Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/maikmerten/spu32
Small Processing Unit 32: A compact RV32I CPU written in Verilog
https://github.com/maikmerten/spu32
fpga ice40 icestorm risc-processor risc-v rv32i system-on-chip verilog
Last synced: about 5 hours ago
JSON representation
Small Processing Unit 32: A compact RV32I CPU written in Verilog
- Host: GitHub
- URL: https://github.com/maikmerten/spu32
- Owner: maikmerten
- License: mit
- Created: 2018-02-09T16:29:23.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2022-05-30T16:01:53.000Z (over 2 years ago)
- Last Synced: 2023-03-31T13:30:35.781Z (almost 2 years ago)
- Topics: fpga, ice40, icestorm, risc-processor, risc-v, rv32i, system-on-chip, verilog
- Language: C
- Homepage:
- Size: 714 KB
- Stars: 52
- Watchers: 13
- Forks: 12
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SPU32
This is SPU32 ("Small Processing Unit 32"), a compact RISC-V processor implementing the RV32I instruction set.
A demo-SoC is also included, featuring some peripherals.
The project ist writting in Verilog and is designed to be synthesizable using the open-source [Yosys open synthesis suite](https://github.com/YosysHQ/yosys).
An example SoC:
```mermaidgraph TD;
CPU[CPU
RISC-V, 32 bit] --- WB[Wishbone bus
8 or 32 bit, pipelined]
WB --- BROM[Boot ROM]
WB --- RAM[RAM]
WB --- UART[UART
115200 baud]
WB --- SPI[SPI bus]
SPI --- SDCARD[SD card]
WB --- TIMER[Timer
Interrupt-capable]
WB --- PRNG[PRNG
32 bit predictable
random numbers]
WB --- LEDS[LEDs
blinky board LEDs]
WB --- IR[IR decoder
NEC protocol]
IR --- IRREC[IR receiver
38 kHz carrier]
WB --- VGA[VGA graphics
text and bitmaps]```
## Building a fitting 32-bit RISC-V toolchain
For Linux, in a nutshell (adapt paths as desired):
```
mkdir riscv-gcc
cd riscv-gcc
git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv32 --with-arch=rv32i --with-abi=ilp32
make -j$(nproc)
```## CPU
### Vectors
Following vectors are used by the CPU and can be configured via parameters when instantiating the CPU module:
* `VECTOR_RESET`: The memory address where the CPU will start execution after reset. By default set to `0x00000000`
* `VECTOR_EXCEPTION`: The memory address where the CPU will jump to to handle interrupts (for example, external interrupts or software interrupts) and exceptions (for example, illegal instructions). By default set to `0x00000010`.### Interrupts and exceptions
The CPU supports following types of interrupts and exceptions:
* software interrupts using the `ecall` and `ebreak` instructions
* external interrupts raised, e.g., by a peripheral device
* illegal/unknown instructionsIf an interrupt of any type occurs, the CPU will jump to `VECTOR_EXCEPTION`, where a handling routine should be present.
The mode of interrupt/exception-handling is inspired by the privileged RISC-V specification, but much simplified for sake of implementation compactness. It therefore does not conform to an official specification, but should feel somewhat similar.
Interrupt- and exception-handling is controlled using machine-status registers that can be accessed using the `csrrw` instruction (the other csr-instructions are not supported in hardware and will raise an illegal-instruction exception, which can be handled in software if so desired). All status-registers have a read-write address (to allow swapping values with normal registers) and read-only address (to allow reading status-registers without changing their contents).
Following machine-status registers (MSRs) are used to control interrupt/exception-handling:
#### MSR_STATUS
* read-only address: `0xFC0`
* read-write address: `0x7C0`Following information is encoded:
* `MSR_STATUS[31-3]`: reserved, always reads zero
* `MSR_STATUS[2]`: status of external interrupt line, i.e., `1` if an external interrupt is currently requested
* `MSR_STATUS[1]`: previous state of the external interrupt enable flag (`meie_prev`)
* `MSR_STATUS[0]`: current state of the external interrupt enable flag (`meie`)When an interrupt/exception occurs, the value of `meie` is saved to `meie_prev`. The `meie`-flag is set to zero, which ensures that external interrupts are ignored until the current interrupt is handled or the `meie`-flag is reinstated.
The `mret`-instruction is used to return from an interrupt/exception. `meie` is set to the value of `meie_prev` and execution is resumed at the address stored in `MSR_EPC`.
On reset, `meie` is set to zero, which means that external interrupts will be ignored. To enable external interrupts, `meie` needs to be set to `1`.
Software-interrupts are always processed.
#### MSR_CAUSE
* read-only address: `0xFC1`
* read-write address: `0x7C1`This status-register encodes the cause of of the raised interrupt/exception:
| `MSR_CAUSE[31]` | `MSR_CAUSE[3-0]` | type of exception |
| --- | --- | --- |
| 1 | 1011 | external interrupt |
| 0 | 0010 | invalid instruction |
| 0 | 0011 | `ebreak`-instruction |
| 0 | 1011 | `ecall`-instruction |`MSR_CAUSE[30]` to `MSR_CAUSE[4]` are reserved and always read as zero.
Note that `MSR_CAUSE[31]` can be used to easily distinguish external interrupts from software-interrupts. A neat effect of this encoding is that external interrupt and software-interrupts can be distinguished by signed comparison with zero, e.g., by using the `bltz` (branch if less than zero) instruction.
#### MSR_EPC
* read-only address: `0xFC2`
* read-write address: `0x7C2`This status-register contains the address of the instruction where the last interrupt/exception occurred. The `mret`-instruction will jump to the address stored in this status-register.
**Please note**: In case of software interrupts/exceptions, this status-register will point to the instruction that caused the interrupt/exception. When directly issuing `mret`, execution will resume at exactly the same instruction, which means that yet another interrupt/exception will be raised immediately. To resume normal program flow, one needs to increment the value of `MSR_EPC` by `4` (i.e., by the length of one instruction) to resume execution a the next instruction. This can be detected by `MSR_CAUSE[31]`.
External interrupts directly resume execution at the address stored in `MSR_EPC`, so no increment is needed prior to `mret`.
#### MSR_EVECT
* read-only address: `0xFC3`
* read-write address: `0x7C3`This status-register specifies the memory address the CPU will jump to when an interrupt/exception occurs. By default initialized to `VECTOR_EXCEPTION`, but may be changed to any memory address where an interrupt service routine is located.