A small, header-only RV32I CPU emulator with a mock UART instruction queue.
This project is meant to be easy to drop into other code and simple to experiment with.
- Include
emulator.hppin your project. - Create a
CPUand aUARTMockinstance. - Encode each instruction as a
uint32_t, then queue it withuart.send(inst). - Run one instruction at a time with
cpu.step_from_uart(uart), or execute the whole queue withcpu.run_from_uart(uart). - Check register and PC state with
cpu.read_reg(index)andcpu.read_pc().
demo.cpp is a full end-to-end example if you want something concrete to copy from.
Current RV32I coverage is listed below.
| Group | Instruction | Opcode | funct3 | funct7 |
|---|---|---|---|---|
| Register-register ALU | add |
0x33 |
0x0 |
0x00 |
| Register-register ALU | sub |
0x33 |
0x0 |
0x20 |
| Register-register ALU | sll |
0x33 |
0x1 |
0x00 |
| Register-register ALU | slt |
0x33 |
0x2 |
0x00 |
| Register-register ALU | sltu |
0x33 |
0x3 |
0x00 |
| Register-register ALU | xor |
0x33 |
0x4 |
0x00 |
| Register-register ALU | srl |
0x33 |
0x5 |
0x00 |
| Register-register ALU | sra |
0x33 |
0x5 |
0x20 |
| Register-register ALU | or |
0x33 |
0x6 |
0x00 |
| Register-register ALU | and |
0x33 |
0x7 |
0x00 |
| Register-immediate ALU | addi |
0x13 |
0x0 |
- |
| Register-immediate ALU | slli |
0x13 |
0x1 |
0x00 |
| Register-immediate ALU | slti |
0x13 |
0x2 |
- |
| Register-immediate ALU | sltiu |
0x13 |
0x3 |
- |
| Register-immediate ALU | xori |
0x13 |
0x4 |
- |
| Register-immediate ALU | srli |
0x13 |
0x5 |
0x00 |
| Register-immediate ALU | srai |
0x13 |
0x5 |
0x20 |
| Register-immediate ALU | ori |
0x13 |
0x6 |
- |
| Register-immediate ALU | andi |
0x13 |
0x7 |
- |
| Loads | lb |
0x03 |
0x0 |
- |
| Loads | lh |
0x03 |
0x1 |
- |
| Loads | lw |
0x03 |
0x2 |
- |
| Loads | lbu |
0x03 |
0x4 |
- |
| Loads | lhu |
0x03 |
0x5 |
- |
| Stores | sb |
0x23 |
0x0 |
- |
| Stores | sh |
0x23 |
0x1 |
- |
| Stores | sw |
0x23 |
0x2 |
- |
| Upper-immediate | auipc |
0x17 |
- |
- |
| Upper-immediate | lui |
0x37 |
- |
- |
| Branches | beq |
0x63 |
0x0 |
- |
| Branches | bne |
0x63 |
0x1 |
- |
| Branches | blt |
0x63 |
0x4 |
- |
| Branches | bge |
0x63 |
0x5 |
- |
| Branches | bltu |
0x63 |
0x6 |
- |
| Branches | bgeu |
0x63 |
0x7 |
- |
| System | ecall |
0x73 |
- |
- |
If your program only uses the instructions above, it should run as-is in this emulator.
jal/jalr- fence and CSR instructions
- pseudoinstructions in decode (these should be expanded by your assembler)
makeOr build and run directly:
g++ -std=c++23 -Wall -Wextra -pedantic demo.cpp -o demo
./demoIssues and pull requests are welcome.