Create RISC-V Core using Verilog HDL (2) “create a core that can execute add.”

Yoshi's Tech Blog
2 min readMay 24, 2021

--

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.

--

--

Yoshi's Tech Blog

I’m a master’s student at the University of Tokyo. My major is Computer Science. Webpage: yoshi-ki.github.io