I'm building a simple 32-bit RISC-V processor in SystemVerilog as a way to get more practical experience with computer architecture and RTL design.
I had studied processor architecture and digital logic before, but I wanted to actually build the things I was learning about instead of only working with block diagrams. So I decided to start with a small RISC-V core and build it piece by piece.
This project is still a work in progress.
So far, I've built and tested the main building blocks of the processor:
- ALU
- Register file
- Program counter
- Instruction memory
- Instruction fetch
- Instruction decoder
- Immediate generator
- Control unit
- ALU input multiplexer
- Data memory
- Basic integrated CPU datapath
The ALU supports:
- ADD
- SUB
- AND
- OR
- XOR
- SLL
- SRL
- SRA
- SLT
- SLTU
I've also implemented and tested several RISC-V immediate instructions, including:
- ADDI
- ANDI
- ORI
- XORI
- SLTI
- SLTIU
The individual modules are tested separately before being connected to the CPU. I've also started testing multiple instructions together at the CPU level.
For example, the current CPU test gives:
ADDI: PASS
ANDI: PASS
ORI: PASS
XORI: PASS
SLTI: PASS
SLTIU: PASS
I-TYPE ALU TEST COMPLETE
Load and store instructions are the next part I'm working on.
I'm not trying to write the whole processor in one go.
I started with the ALU, tested it, then moved on to the register file, decoder, immediate generation, control logic, memory, and so on. Once the individual pieces worked, I started connecting them together.
This has been useful because some of the problems aren't really visible when you're just looking at a processor diagram. For example, I've had to deal with clock edges, register write timing, reset behavior, instruction encoding, and figuring out why something that looks correct on paper isn't behaving correctly in simulation.
That's probably been one of the most useful parts of the project so far.
At the moment, the basic flow is:
Program Counter
│
▼
Instruction Memory
│
▼
Instruction Decoder
│
┌──────┴──────┐
▼ ▼
Register File Control Unit
│
▼
ALU
│
▼
Data Memory
The design is written as separate SystemVerilog modules rather than one large CPU module. I'm doing this partly to keep the design manageable and partly so that I can test each block on its own.
Each major module has its own testbench.
I'm using Icarus Verilog to compile and simulate the SystemVerilog RTL.
So far I've tested things such as:
- ALU operations
- Register reads and writes
x0staying at zero- Immediate generation
- Instruction decoding
- Program counter operation
- Instruction fetch
- Data memory reads and writes
- ALU input selection
- Integrated CPU instruction execution
There is still a lot more verification to do as the processor grows.
rv32i_project/
│
├── rtl/
│ ├── alu.sv
│ ├── alu_input_mux.sv
│ ├── control_unit.sv
│ ├── data_memory.sv
│ ├── immediate_generator.sv
│ ├── instruction_decoder.sv
│ ├── instruction_fetch.sv
│ ├── instruction_memory.sv
│ ├── program_counter.sv
│ ├── register_file.sv
│ └── rv32i_cpu.sv
│
├── tb/
│ ├── alu_tb.sv
│ ├── alu_input_mux_tb.sv
│ ├── control_unit_tb.sv
│ ├── data_memory_tb.sv
│ ├── immediate_generator_tb.sv
│ ├── instruction_decoder_tb.sv
│ ├── instruction_fetch_tb.sv
│ ├── instruction_memory_tb.sv
│ ├── program_counter_tb.sv
│ ├── register_file_tb.sv
│ └── rv32i_cpu_tb.sv
│
├── README.md
└── .gitignore
I'm planning to keep extending the processor as I learn more.
The next things I want to work on are:
- Finish
LWandSW - Add branches such as
BEQandBNE - Add
JALandJALR - Expand the supported RV32I instructions
- Run small RISC-V assembly programs
- Improve the CPU-level testbench
- Experiment with a fixed-point datapath
- Learn more about caches and memory hierarchies
- Eventually try synthesizing the RTL and looking at timing
I chose RISC-V because the ISA is open and relatively easy to understand compared with many commercial processor architectures.
It also gives me something real to work toward. Instead of designing an arbitrary CPU with instructions I made up myself, I can gradually work toward implementing an actual instruction set and eventually run real RISC-V code on it.
- SystemVerilog
- Icarus Verilog
- VS Code
- Git
- GitHub
Majid Khan B.S. Electrical Engineering, UET Peshawar