Modern 32-bit RISC-V processor implementing the base integer instruction set. Includes both single-cycle and 5-stage pipelined implementations with hazard detection and forwarding.
Instruction fetch, PC+4, branch target
Decode, register read, immediate gen
ALU, branch resolve, forwarding MUX
Data memory read/write
Register write-back
| Parameter | Value |
|---|---|
| ISA | RISC-V RV32I (base integer, 47 instructions) |
| Data width | 32 bits |
| Registers | 32 general-purpose (x0 hardwired to zero) |
| Instruction types | R, I, S, B, U, J formats |
| ALU operations | ADD, SUB, AND, OR, XOR, SLL, SRL, SRA, SLT, SLTU |
| Branch types | BEQ, BNE, BLT, BGE, BLTU, BGEU |
| Memory ops | LB/LH/LW/LBU/LHU (load), SB/SH/SW (store) |
| Pipeline | 5-stage (IF, ID, EX, MEM, WB) with forwarding |
| Hazard handling | Data forwarding, load-use stall, branch flush |
The instruction decoder extracts fields from all six RISC-V instruction formats and generates the immediate value using the sign-extension logic specified by the ISA.
class DecoderRV32I < RHDL::Sim::Component
input :instr, width: 32
output :rs1, width: 5
output :rs2, width: 5
output :rd, width: 5
output :imm, width: 32
output :alu_op, width: 4
output :mem_read, :mem_write
output :reg_write, :branch
behavior do
opcode = instr[6..0]
funct3 = instr[14..12]
funct7 = instr[31..25]
rs1 <= instr[19..15]
rs2 <= instr[24..20]
rd <= instr[11..7]
# Immediate generation
imm <= case_select(opcode, {
0b0010011 => sign_ext(instr[31..20]),
0b0100011 => sign_ext(
{ instr[31..25], instr[11..7] }),
0b1100011 => sign_ext(
{ instr[31], instr[7],
instr[30..25],
instr[11..8], 1'b0' }),
})
end
end
The forwarding unit resolves data hazards by detecting when a source register matches a pending write-back destination and selecting the forwarded value.
class ForwardingUnit < RHDL::Sim::Component
# Source registers (ID/EX stage)
input :rs1, width: 5
input :rs2, width: 5
# EX/MEM stage write-back
input :ex_mem_rd, width: 5
input :ex_mem_wr
# MEM/WB stage write-back
input :mem_wb_rd, width: 5
input :mem_wb_wr
# Forward select (0=reg, 1=EX, 2=MEM)
output :fwd_a, width: 2
output :fwd_b, width: 2
behavior do
# Priority: EX/MEM over MEM/WB
fwd_a <= cond(
ex_mem_wr & ex_mem_rd.neq?(0)
& ex_mem_rd.eq?(rs1),
1,
cond(
mem_wb_wr & mem_wb_rd.neq?(0)
& mem_wb_rd.eq?(rs1),
2, 0))
fwd_b <= cond(
ex_mem_wr & ex_mem_rd.neq?(0)
& ex_mem_rd.eq?(rs2),
1,
cond(
mem_wb_wr & mem_wb_rd.neq?(0)
& mem_wb_rd.eq?(rs2),
2, 0))
end
end
The pipelined processor top-level connects all five stages with pipeline registers, forwarding unit, and hazard detection logic.
class RV32IPipeline < RHDL::Sim::SequentialComponent
input :clk, :rst
output :imem_addr, width: 32
input :imem_data, width: 32
output :dmem_addr, width: 32
output :dmem_wdata, width: 32
output :dmem_wr
input :dmem_rdata, width: 32
# Pipeline stages
subcomponent :fetch, FetchStage
subcomponent :decode, DecodeStage
subcomponent :execute, ExecuteStage
subcomponent :memory, MemoryStage
subcomponent :wb, WriteBackStage
# Hazard handling
subcomponent :fwd, ForwardingUnit
subcomponent :hazard, HazardDetector
subcomponent :regfile, RegisterFile,
depth: 32, width: 32
sequential clock: :clk, reset: :rst do
# Pipeline register updates
# Stall IF/ID on load-use hazard
# Flush IF/ID + ID/EX on branch taken
# Forward EX and MEM results to EX inputs
end
end