Github: http://github.com/ultraembedded/riscv_soc
A basic RISC-V test SoC with Timer, UART, SPI and GPIO peripherals...
# Clone repository and submodules
git clone https://github.com/ultraembedded/riscv_soc.git --recursive
Name
Contents
core
RISC-V core (http://github.com/ultraembedded/riscv )
fpga/arty
Digilent Artix-7 Arty FPGA Dev Board project
soc
Verilog for peripherals, interconnect, etc
tb
System-C testbench for the project
The top (riscv_soc in riscv_soc.v) contains;
RISC-V core (RV32IM instructions supported).
16KB (8KB x 2-way) instruction cache.
Timer, UART, SPI and interrupt controller peripherals.
AXI4-Lite slave port for external bus master/debug access to peripherals / main memory.
AXI4 master port for access to main memory, e.g. SDRAM (external to the design).
Name
Description
clk_i
Clock input
rst_i
Async reset, active-high. Reset SoC (excluding CPU core).
rst_cpu_i
Async reset, active-high. Reset CPU core.
reset_vector_i
Initial boot address.
inport_*
AXI4-Lite slave interface for access to SoC / memory.
mem_*
AXI4 master interface to main memory.
spi_*
SPI interface
gpio_*
GPIO interface
uart_rxd_o
UART Tx (connect to remote receiver)
uart_txd_i
UART Rx (connect to remote transmitter)
A basic System-C / Verilator based testbench for the design is provided.
Dependancies;
gcc
make
libelf
System-C (specify path using SYSTEMC_HOME)
Verilator (specify path using VERILATOR_SRC)
To build the testbench;
To run the provided test executable;
This project is ready to run on the 'Digilent Artix-7 Arty' FPGA dev board;
A pre-cooked bitstream for this board is located in 'fpga/arty/top.bit'.
The test project for FPGA uses the UART to AXI dbg bridge to allow code to be loaded into DDR prior to de-asserting the CPU's reset.
The 'rv32imsu' core (as used in the provided bitstream) is capable of booting Linux;
cd fpga/arty
# Load bitstream onto target
vivado -mode tcl -source program.tcl
# Load test app into DDR and release reset (change ttyUSB2 as appropriate)
./run.py -d /dev/ttyUSB2 -f ../../images/linux_riscv_soc.elf
ELF: Loading 0x80000000 - size 7KB
|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| 100.0%
ELF: Loading 0x80400000 - size 5368KB
|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| 100.0%
ELF: Loading 0x81f00000 - size 2KB
|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| 100.0%
[Console]: Enter UART mode
Booting...
OF: fdt: Ignoring memory range 0x80000000 - 0x80400000
Linux version 4.19.0-29706-g1479c35-dirty (build@vm) (gcc version 7.2.0 (GCC)) #531 Sat Mar 16 22:07:04 GMT 2019
bootconsole [early0] enabled
initrd not found or empty - disabling initrd
Zone ranges:
Normal [mem 0x0000000080400000-0x0000081effffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000080400000-0x0000000081efffff]
Initmem setup node 0 [mem 0x0000000080400000-0x0000000081efffff]
On node 0 totalpages: 6912
Normal zone: 54 pages used for memmap
Normal zone: 0 pages reserved
Normal zone: 6912 pages, LIFO batch:0
elf_hwcap is 0x1101
pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
pcpu-alloc: [0] 0
Built 1 zonelists, mobility grouping on. Total pages: 6858
Kernel command line: console=ttyUL0,1000000 debug
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
Sorting __ex_table...
Memory: 21992K/27648K available (3664K kernel code, 138K rwdata, 547K rodata, 792K init, 220K bss, 5656K reserved, 0K cma-reserved)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
irq-xilinx: /soc/interrupt-controller@90000000: num_irq=9, edge=0x100
clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 76450417870 ns
Console: colour dummy device 80x25
Calibrating delay loop (skipped), value calculated using timer frequency.. 50.00 BogoMIPS (lpj=100000)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
devtmpfs: initialized
random: get_random_u32 called from bucket_table_alloc.isra.7+0xa0/0x208 with crng_init=0
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
futex hash table entries: 256 (order: -1, 3072 bytes)
NET: Registered protocol family 16
random: fast init done
clocksource: Switched to clocksource timer
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes)
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
workingset: timestamp_bits=30 max_order=13 bucket_order=0
NET: Registered protocol family 38
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
io scheduler mq-deadline registered
io scheduler kyber registered
92000000.serial: ttyUL0 at MMIO 0x92000000 (irq = 2, base_baud = 0) is a uartlite
console [ttyUL0] enabled
console [ttyUL0] enabled
bootconsole [early0] disabled
bootconsole [early0] disabled
loop: module loaded
NET: Registered protocol family 10
Segment Routing with IPv6
sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
NET: Registered protocol family 17
Freeing unused kernel memory: 792K
This architecture does not have kernel memory protection.
Run /init as init process
init started: BusyBox v1.29.3 (2018-11-13 23:09:48 GMT)
Please press Enter to activate this console.
BusyBox v1.29.3 (2018-11-13 23:09:48 GMT) built-in shell (ash)
# ls
bin dev etc init lib mnt proc sbin sys test
#
SoC + Small Core (core/rv32i_spartan6)
Xilinx Vivado (for XC7)
Used
Slice LUTs
3654
Slice Registers
1468
SoC + Larger Core (core/rv32imsu)
Xilinx Vivado (for XC7)
Used
Slice LUTs
7046
Slice Registers
3170
Range
Description
0x8000_0000 - 0x8fff_ffff
Main memory (external to the design)
0x9000_0000 - 0x90ff_ffff
Peripheral - IRQ controller
0x9100_0000 - 0x91ff_ffff
Peripheral - Timer
0x9200_0000 - 0x92ff_ffff
Peripheral - UART
0x9300_0000 - 0x93ff_ffff
Peripheral - SPI
0x9400_0000 - 0x94ff_ffff
Peripheral - GPIO
Index
Source
0
Peripheral - Timer
1
Peripheral - UART
2
Peripheral - SPI
3
Peripheral - GPIO
Offset
Name
Description
0x9000_0000
IRQ_ISR
[RW] Interrupt Status Register
0x9000_0004
IRQ_IPR
[R] Interrupt Pending Register
0x9000_0008
IRQ_IER
[RW] Interrupt Enable Register
0x9000_000c
IRQ_IAR
[W] Interrupt Acknowledge Register
0x9000_0010
IRQ_SIE
[W] Set Interrupt Enable bits
0x9000_0014
IRQ_CIE
[W] Clear Interrupt Enable bits
0x9000_0018
IRQ_IVR
[RW] Interrupt Vector Register
0x9000_001c
IRQ_MER
[RW] Master Enable Register
0x9100_0008
TIMER_CTRL0
[RW] Control
0x9100_000c
TIMER_CMP0
[RW] Compare value (interrupt on match)
0x9100_0010
TIMER_VAL0
[RW] Current Value
0x9100_0014
TIMER_CTRL1
[RW] Control
0x9100_0018
TIMER_CMP1
[RW] Compare value (interrupt on match)
0x9100_001c
TIMER_VAL1
[RW] Current Value
0x9200_0000
ULITE_RX
[R] UART Data Register
0x9200_0004
ULITE_TX
[W] UART Data Register
0x9200_0008
ULITE_STATUS
[R] UART Status Register
0x9200_000c
ULITE_CONTROL
[RW] UART Configuration Register
0x9300_001c
SPI_DGIER
[RW] Device Global Interrupt Enable Register
0x9300_0020
SPI_IPISR
[RW] IP Interrupt Status Register
0x9300_0028
SPI_IPIER
[RW] IP Interrupt Enable Register
0x9300_0040
SPI_SRR
[RW] Software Reset Register
0x9300_0060
SPI_CR
[RW] SPI Control Register
0x9300_0064
SPI_SR
[R] SPI Status Register
0x9300_0068
SPI_DTR
[W] SPI Data Transmit Register
0x9300_006c
SPI_DRR
[R] SPI Data Receive Register
0x9300_0070
SPI_SSR
[RW] SPI Slave Select Register
0x9400_0000
GPIO_DIRECTION
[RW] Configuration Register
0x9400_0004
GPIO_INPUT
[R] GPIO Input Status
0x9400_0008
GPIO_OUTPUT
[RW] GPIO Output Control
0x9400_000c
GPIO_OUTPUT_SET
[W] GPIO Output Control Set Alias
0x9400_0010
GPIO_OUTPUT_CLR
[W] GPIO Output Control Clr Alias
0x9400_0014
GPIO_INT_MASK
[RW] GPIO Interrupt Enable Mask
0x9400_0018
GPIO_INT_SET
[W] GPIO Interrupt Set
0x9400_001c
GPIO_INT_CLR
[W] GPIO Interrupt Clear
0x9400_0020
GPIO_INT_STATUS
[R] GPIO Interrupt Raw Status
0x9400_0024
GPIO_INT_LEVEL
[RW] GPIO Interrupt Level
0x9400_0028
GPIO_INT_MODE
[RW] GPIO Interrupt Mode
Peripheral Register Fields
Bits
Name
Description
3:0
STATUS
Pending interrupt (unmasked) bitmap.
Bits
Name
Description
3:0
PENDING
Pending interrupts (masked) bitmap.
Bits
Name
Description
3:0
ENABLE
Interrupt enable mask.
Bits
Name
Description
3:0
ACK
Bitmap of interrupts to acknowledge.
Bits
Name
Description
3:0
SET
Bitmap of interrupts to enable.
Bits
Name
Description
3:0
CLR
Bitmap of interrupts to disable.
Bits
Name
Description
31:0
VECTOR
Highest priority active interrupt number.
Bits
Name
Description
0
ME
Master Enable
Timer Register: TIMER_CTRLx
Bits
Name
Description
1
INTERRUPT
Interrupt enable.
2
ENABLE
Timer enable.
Timer Register: TIMER_CMPx
Bits
Name
Description
31:0
VALUE
Match value.
Timer Register: TIMER_VALx
Bits
Name
Description
31:0
CURRENT
Current timer value.
Bits
Name
Description
7:0
DATA
Date byte
Bits
Name
Description
7:0
DATA
Date byte
UART Register: ULITE_STATUS
Bits
Name
Description
4
IE
Interrupt enabled
3
TXFULL
Transmit buffer full
2
TXEMPTY
Transmit buffer empty
1
RXFULL
Receive buffer full
0
RXVALID
Receive buffer not empty
UART Register: ULITE_CONTROL
Bits
Name
Description
4
IE
Interrupt enable
1
RST_RX
Flush Rx Buffer
0
RST_TX
Flush Tx Buffer
Bits
Name
Description
31
GIE
Global interrupt enable.
Bits
Name
Description
2
TX_EMPTY
Tx FIFO empty interrupt status.
Bits
Name
Description
2
TX_EMPTY
Tx FIFO interrupt enable.
Bits
Name
Description
31:0
RESET
Software FIFO reset.
Bits
Name
Description
0
LOOP
Loopback enable (MOSI to MISO).
1
SPE
SPI Enable.
2
MASTER
Master mode (slave mode not currently supported).
3
CPOL
Clock polarity.
4
CPHA
Clock phase.
5
TXFIFO_RST
Tx FIFO reset.
6
RXFIFO_RST
Rx FIFO reset.
7
MANUAL_SS
Manual chip select mode (auto mode not supported).
8
TRANS_INHIBIT
Transfer inhibit.
9
LSB_FIRST
Data LSB first (1) or MSB first (0).
Bits
Name
Description
0
RX_EMPTY
Rx FIFO empty.
1
RX_FULL
Rx FIFO full.
2
TX_EMPTY
Tx FIFO empty.
3
TX_FULL
Tx FIFO full.
Bits
Name
Description
7:0
DATA
Date byte
Bits
Name
Description
7:0
DATA
Date byte
Bits
Name
Description
0
VALUE
Chip select value
GPIO Register: GPIO_DIRECTION
Bits
Name
Description
31:0
OUTPUT
0 = Input, 1 = Output
GPIO Register: GPIO_INPUT
Bits
Name
Description
31:0
VALUE
Raw input status
GPIO Register: GPIO_OUTPUT
Bits
Name
Description
31:0
DATA
GPIO output value
GPIO Register: GPIO_OUTPUT_SET
Bits
Name
Description
31:0
DATA
GPIO output mask - set for high
GPIO Register: GPIO_OUTPUT_CLR
Bits
Name
Description
31:0
DATA
GPIO output mask - set for low
GPIO Register: GPIO_INT_MASK
Bits
Name
Description
31:0
ENABLE
GPIO Interrupt Enable Mask
GPIO Register: GPIO_INT_SET
Bits
Name
Description
31:0
SW_IRQ
Write 1 to assert an interrupt
GPIO Register: GPIO_INT_CLR
Bits
Name
Description
31:0
ACK
Write 1 to clear an interrupt
GPIO Register: GPIO_INT_STATUS
Bits
Name
Description
31:0
RAW
Set if interrupt active (regardless of INT_MASK)
GPIO Register: GPIO_INT_LEVEL
Bits
Name
Description
31:0
ACTIVE_HIGH
GPIO Interrupt Level - 1 = active high / rising edge, 0 = active low / falling edge
GPIO Register: GPIO_INT_MODE
Bits
Name
Description
31:0
EDGE
GPIO Interrupt Mode - 1 = edge triggered, 0 = level