This repository contains a 32-bit RISC-V CPU implementing the RV32I base integer ISA. The design follows a classic 5-stage pipeline:
- IF – Instruction Fetch
- ID – Instruction Decode / Register Read
- EX – Execute / Address Calculation
- MEM – Data Memory Access
- WB – Write Back
The implementation was built in two steps:
Lucrarea 2: Front-end implementation (IF + ID)Lucrarea 3: Back-end implementation (EX + MEM + WB) plus forwarding and hazard detection, resulting in a complete pipelined CPU.
Scope notes:
- Integer-only execution (no floating-point unit).
- No hardware multiply/divide extension (no RV32M).
- Pipeline control supports stalling and forwarding for correctness.
Below are the key module definitions and responsibilities, listed in pipeline order.
Fetches the instruction at the current PC and computes the next PC.
Key behaviors:
- Next PC is selected by a mux between PC + 4 and branch target PC (PC_Branch), using PcSrc.
- PC update can be stalled using PC_Write.
- IF/ID pipeline register write can be stalled using IF_ID_Write.
Important modules:
- 2:1 PC mux
module mux2_1(
input [31:0] ina, inb,
input sel,
output [31:0] out
);- PC register (D flip-flop register)
- Global clk and reset
- Updates only when PC_Write = 1
- Instruction memory
- Asynchronous read
- Contents loaded using $readmemh
- Addressing is word-based via PC >> 2 (since PC counts bytes and instructions are 4 bytes)
- Adder
- Computes PC + 4
- IF/ID pipeline register
- Holds PC_ID and INSTRUCTION_ID
- Writes only when IF_ID_Write = 1
Decodes the fetched instruction, reads source registers, and generates immediates.
Decoded/extracted fields:
- OPCODE, FUNCT3, FUNCT7
- RS1, RS2, RD
- Immediate IMM (depending on instruction format)
Important modules:
- Register file (32 × 32-bit, 2 async reads, 1 sync write)
module registers(
input clk, reg_write,
input [4:0] read_reg1, read_reg2, write_reg,
input [31:0] write_data,
output [31:0] read_data1, read_data2
);Notes:
-
x0 is always 0.
-
Writes occur on clock when reg_write = 1.
-
Reads are asynchronous.
-
Immediate generator
module imm_gen(
input [31:0] in,
output reg [31:0] out
);Generates immediate values for instruction formats I, S, B, U, J.
- ID wrapper (connects registers + imm_gen + field extraction)
module ID(
input clk,
input [31:0] PC_ID, INSTRUCTION_ID,
input RegWrite_WB,
input [31:0] ALU_DATA_WB,
input [4:0] RD_WB,
output [31:0] IMM_ID,
output [31:0] REG_DATA1_ID, REG_DATA2_ID,
output [2:0] FUNCT3_ID,
output [6:0] FUNCT7_ID,
output [6:0] OPCODE_ID,
output [4:0] RD_ID, RS1_ID, RS2_ID
);Control and hazard-related units (in the complete CPU):
- Control unit (control_path)
- Generates control signals such as RegWrite, MemRead, MemWrite, MemtoReg, ALUSrc, ALUop, Branch, etc.
- Hazard detection unit
- Detects load-use hazards that cannot be solved by forwarding
- Produces PC_Write (stall PC), IF_ID_Write (stall IF/ID), and control_sel (zero/disable control signals to insert a bubble)
Pipeline registers:
- ID/EX pipeline register carries decoded fields, register operands, immediate, PC, and control signals into EX.
Performs ALU operations, selects operands, applies forwarding, and computes branch target address.
Key behaviors:
- ALU operation chosen from ALUop + funct3 + funct7
- Operand2 selected via ALUSrc:
- Register operand (REG_DATA2_EX) or immediate (IMM_EX)
- Forwarding resolves RAW hazards by bypassing values from later pipeline stages.
- Branch target computed with a separate adder:
- PC_Branch_EX = PC_EX + IMM_EX
Important modules:
- ALU control
module ALUcontrol(
input [1:0] ALUop,
input [6:0] funct7,
input [2:0] funct3,
output reg [3:0] ALUinput
);ALUinput encodings used:
-
ld/sd (lw/sw) : 0010
-
add/addi : 0010
-
sub : 0110
-
and/andi : 0000
-
or/ori : 0001
-
xor/xori : 0011
-
srl/srli : 0101
-
sll/slli : 0100
-
sra/srai : 1001
-
slt : 1000
-
sltu : 0111 Branch compare encodings:
-
beq/bne : 0110
-
blt/bge : 1000
-
bltu/bgeu : 0111
-
ALU
module ALU(
input [3:0] ALUop,
input [31:0] ina, inb,
output zero,
output reg [31:0] out
);- Forwarding unit
module forwarding(
input [4:0] rs1, rs2,
input [4:0] ex_mem_rd,
input [4:0] mem_wb_rd,
input ex_mem_regwrite,
input mem_wb_regwrite,
output reg [1:0] forwardA, forwardB
);- EX wrapper
module EX(
input [31:0] IMM_EX,
input [31:0] REG_DATA1_EX,
input [31:0] REG_DATA2_EX,
input [31:0] PC_EX,
input [2:0] FUNCT3_EX,
input [6:0] FUNCT7_EX,
input [4:0] RD_EX,
input [4:0] RS1_EX,
input [4:0] RS2_EX,
input RegWrite_EX,
input MemtoReg_EX,
input MemRead_EX,
input MemWrite_EX,
input [1:0] ALUop_EX,
input ALUSrc_EX,
input Branch_EX,
input [1:0] forwardA, forwardB,
input [31:0] ALU_DATA_WB,
input [31:0] ALU_OUT_MEM,
output ZERO_EX,
output [31:0] ALU_OUT_EX,
output [31:0] PC_Branch_EX,
output [31:0] ALU_B_in,
output [31:0] REG_DATA2_EX_FINAL
);Pipeline register:
- EX/MEM pipeline register carries ALU result, branch target, zero flag, store data, RD, and control signals into MEM.
Performs data memory operations and branch decision handling.
Key behaviors:
- Data memory supports:
- Asynchronous read (mem_read)
- Synchronous write (mem_write) on clock
- PcSrc is computed in a Branch Control block when BRANCH_MEM = 1, supporting:
- beq, bne, blt, bge, bltu, bgeu
Important modules:
- Data memory (4 KB)
module data_memory(
input clk,
input mem_read,
input mem_write,
input [31:0] address,
input [31:0] write_data,
output reg [31:0] read_data
);Pipeline register:
- MEM/WB pipeline register carries memory read data, ALU result, RD, and write-back control into WB.
Writes the final result back into the register file.
Key behaviors:
- MemtoReg selects what is written back:
- Memory read value (for loads)
- ALU result (for ALU/immediate ops)
- RegWrite enables writing to the destination register RD.
Conceptual write-back mux:
- ALU_DATA_WB = (MemtoReg) ? DATA_MEMORY_MEM : ALU_OUT_MEM
Based on the lab requirements and implemented immediate/control coverage, the CPU supports the following RV32I instructions:
Arithmetic / Logic (Register-Register):
- add
- sub
- and
- or
- xor
- sll
- srl
- sra
- slt
- sltu
Arithmetic / Logic (Immediate):
- addi
- andi
- ori
- xori
- slli
- srli
- srai
- slti
- sltiu
Loads / Stores:
- lw
- sw
Branches:
- beq
- bne
- blt
- bge
- bltu
- bgeu
Forwarding (RAW hazards):
- Bypasses results from EX/MEM and MEM/WB to the EX stage inputs when required.
Load-use hazard stalling:
- Detects hazards where a load in EX is followed by an instruction in ID that consumes the loaded RD.
- When stalling:
- PC_Write = 0
- IF_ID_Write = 0
- control_sel forces control signals to 0 to insert a bubble
- Instruction memory is initialized from a .mem file via $readmemh.
- PC addresses are byte-based; instruction memory indexing uses PC >> 2.
- For debugging, it is useful to add the internal register file array and data memory array to the waveform view.
- David A. Patterson, John L. Hennessy, Computer Organization and Design: RISC-V Edition
- The RISC-V Instruction Set Manual, Volume I: User-Level ISA (RV32I base spec)
- Lab handouts: Lucrarea 2 and Lucrarea 3 - Rares Ifrim