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;
cd tb
make
To run the provided test executable;
cd tb
make run
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
#
Xilinx Vivado (for XC7) | Used |
---|---|
Slice LUTs | 3654 |
Slice Registers | 1468 |
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 |
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 |
Bits | Name | Description |
---|---|---|
1 | INTERRUPT | Interrupt enable. |
2 | ENABLE | Timer enable. |
Bits | Name | Description |
---|---|---|
31:0 | VALUE | Match value. |
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 |
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 |
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 |
Bits | Name | Description |
---|---|---|
31:0 | OUTPUT | 0 = Input, 1 = Output |
Bits | Name | Description |
---|---|---|
31:0 | VALUE | Raw input status |
Bits | Name | Description |
---|---|---|
31:0 | DATA | GPIO output value |
Bits | Name | Description |
---|---|---|
31:0 | DATA | GPIO output mask - set for high |
Bits | Name | Description |
---|---|---|
31:0 | DATA | GPIO output mask - set for low |
Bits | Name | Description |
---|---|---|
31:0 | ENABLE | GPIO Interrupt Enable Mask |
Bits | Name | Description |
---|---|---|
31:0 | SW_IRQ | Write 1 to assert an interrupt |
Bits | Name | Description |
---|---|---|
31:0 | ACK | Write 1 to clear an interrupt |
Bits | Name | Description |
---|---|---|
31:0 | RAW | Set if interrupt active (regardless of INT_MASK) |
Bits | Name | Description |
---|---|---|
31:0 | ACTIVE_HIGH | GPIO Interrupt Level - 1 = active high / rising edge, 0 = active low / falling edge |
Bits | Name | Description |
---|---|---|
31:0 | EDGE | GPIO Interrupt Mode - 1 = edge triggered, 0 = level |