This project is a single cycle RISC-V processor (32-bit) implementation in (System)Verilog solely for educational purposes. Only 11 instructions were implemented (see RV32I), making it a good reference for those looking for a simple CPU implementation.
It served as an exercise to learn more about how digital circuits (at RTL level) are designed and it was an attempts to familiarize myself with the lower levels of computer science.
The development of this project was done on a MacBook (arm) using the following tools.
- Install Icarus Verilog from source
- Install GTKWave from source
- Test your setup using the Icarus Verilog examples
NYCU's Computer Organization course's slides and code templates were used as a reference during the implementation.
- Write an assembler in any programming language (e.g. Python) that reads assembly instructions from a text file and turns them into machine code (a .mem file)
- Write unit tests for the assembler checking the machine code
- Use
$readmemb
to read the .mem file in your Verilog testbench and store the instructions in program memory
The example assembly file contains the following code, which should result in alu_mux_out_wire holding the value 6 after 50 time units.
lw r1, 1
addi r2, r1, 2
sw r2, 1
lw r3, 1
addi r4, r3, 3
CPU Core - [code]
The CPU core implementation in Verilog.
File | Description |
---|---|
[program_memory.sv] | Stores the instructions (in machine code)loaded from the memory file. |
[program_counter.sv] | Forwards the next instruction address to program memory on the positive edge of clock. |
[register_file.sv] | A 32x32 CPU register file, also read RISC-V ISA Specification for more details. |
[control.sv] | Takes care of the selects and enables of other modules in the circuit based on the instruction's opcode. Use the RISC-V ISA Specification as a reference, especially the RV32/64G Instruction Set Listings. |
[alu_control.sv] | Tells ALU which operation to perform |
[alu.sv] | Contains the actual circuitry to do the operations. |
[imm_generator.sv] | Handles the immediates based (incl. sign extension) on the opcode. Use the Immediate Encoding Variants section in the spec as a reference. |
[data_memory.sv] | Stores data (not the instructions) and can be used with the lw and sw, i.e. load and store, instructions. |
[core.sv] | Connects all other modules together and allows you to configure what you want to output to GTKWave. |
Verification & Testing - [code]
Run the compile.sh
script to use the assembler, compile your Verilog implementation, and run GTKWave to see the results of your testbench.
# from verification dir
./compile.sh
Mnemonic | Type | Example .asm |
---|---|---|
add | R-type | add r3, r2, r1 |
sub | R-type | sub r3, r2, r1 |
and | R-type | and r3, r2, r1 |
or | R-type | or r3, r2, r1 |
slt | R-type | slt r3, r2, r1 |
addi | I-type | addi r3, r2, 5 |
andi | I-type | andi r3, r2, 5 |
ori | I-type | ori r3, r2, 5 |
slti | I-type | slti r3, r2, 5 |
lw | I-type | lw r1, 1 |
sw | S-type | sw r1, 1 |