Create RISC-V Core using Verilog HDL (2) “create a core that can execute add.”
About this project
Hi, I’m currently implementing a RISC-V core using Verilog HDL to deeper understand the CPU. Here is the GitHub of this project. If you are interested, please give me a star.
Today’s version is written in the following link.
https://github.com/yoshi-ki/RISC-V-core/tree/main/practice-files/ver1
Design Plan
The first thing I had to do was to create a plan for the whole design. Implementing some additional functions, such as pipelining and branch predictions, would be tough for the first step; thus, I decided to implement the simple core without pipelining, which contains four stages: fetch, decode, execute, and write. The stage transition is defined by the clock as follows.
always @(posedge CLK) begin
case(cpu_state)
s_fetch: begin
cpu_state <= s_decode;
end
s_decode: begin
cpu_state <= s_execute;
end
s_execute: begin
cpu_state <= s_write;
end
s_write: begin
cpu_state <= s_fetch;
end
endcase
end
File directory
Next, I created several files for each component.
cpu.sv: The top file of this design.
decoder.sv: The file that describes the circuit for the decoder. This circuit takes the instruction code as its input and outputs the decoded information.
alu.sv: The file that describes the circuit for ALU. The ALU is responsible for the rv32-i instructions.
executer.sv: The execution stage includes ALU and other components, such as FPU and PC update; thus, I create executer.sv in addition to alu.sv.
For simplicity
This time, I only implemented the whole design flow; thus, the decoder and ALU are very simple. These components only execute add instructions. Besides, the instruction memory is implemented as the registers as follows.
reg [31:0] inst_mem [0:11] = '{ 32'b00000000001000011000000110110011, // ADD 3(rs1) + 2(rs2) = 3(rd) ...
...
32'b00000000001000011000001010110011 // ADD 3(rs1) + 2(rs2) = 5(rd) };
Implementation
After that, I implemented all files like the above. For more concrete implementations, I would like you to see the GitHub link.
Test Code
After the implementation, I had to implement another code for testing. Since Verilog is just the circuit design, we have to give them input and verify the movement of them. To verify my circuit, I created a file named “test_cpu.sv.”
Compilation and Run Test
The compilation is divided into three steps.
The first step:
xvlog --sv test_cpu.sv cpu.sv alu.sv decoder.sv executer.sv
In this step, Verilog parser named “xvlog” parses the Verilog source files and stores the parsed dump into a HDL library. Watch out the order of files. We have to set the test file first.
The second step:
xelab -debug typical test_cpu -s test_cpu.sim
In this step, the simulator compiler named “xelab” compiles our HDL model into a snapshot, which is a representation of the model in a form that the simulator can execute.
The third step:
xsim --runall test_cpu.sim
In this step, the simulator loads and executes the snapshot made by xelab to simulate the model.
After the simulation, I found the whole design works well! Great!
Next Plan
I will implement other rv32i instructions.