柳嘉祐
IF:Fetch the instruction and update the program counter.
ID:Decode the instruction and read the registers.
EX:Execute the operation or compute the address.
MEM:Access memory (such as loading or storing data).
WB:Write the result back to the register.
IF_ID reg:Store the data from the IF stage and pass it to the ID stage.
ID_EX reg:Store the data from the ID stage and pass it to the EX stage.
EX_MEM reg:Store the data from the EX stage and pass it to the MEM stage.
MEM_WB reg:Store the data from the MEM stage and pass it to the WB stage.
// R type instructions (e.g., add, sub)
is(51.U) {
io.mem_write := 0.B
io.branch := 0.B
io.mem_read := 0.B
io.reg_write := 1.B
io.men_to_reg := 0.B
io.alu_operation := 0.U
io.operand_A := 0.U
io.operand_B := 0.B
io.extend := 0.U
io.next_pc_sel := 0.U
}
// I type instructions (e.g., immediate operations)
is(19.U) {
io.mem_write := 0.B
io.branch := 0.B
io.mem_read := 0.B
io.reg_write := 1.B
io.men_to_reg := 0.B
io.alu_operation := 1.U
io.operand_A := 0.U
io.operand_B := 1.B
io.extend := 0.U
io.next_pc_sel := 0.U
}
Classify instructions based on opcode and funct.
add x1, x2, x3 # instruction 1
sub x4, x1, x5 # instruction 2 (depend on x1)
add x1, x2, x3 # instruction 1
add x4, x5, x6 # instruction 2
sub x7, x1, x9 # instruction 3 (depend on x1)
If the add instruction has not yet completed writing back to x1, and the sub instruction already requires the value of x1, a data hazard will occur.
Forwarding allows the sub instruction to directly obtain the result from the ALU output of the add instruction during the EX stage or from MEM stage, instead of waiting for the add instruction to complete the WB stage and then reading from the register.
when(io.EXMEM_regWr === "b1".U && io.EXMEM_rd =/= "b00000".U &&
(io.EXMEM_rd === io.IDEX_rs1.asUInt) && (io.EXMEM_rd === io.IDEX_rs2)) {
io.forward_a := "b10".U
io.forward_b := "b10".U
}.elsewhen(io.EXMEM_regWr === "b1".U && io.EXMEM_rd =/= "b00000".U &&
(io.EXMEM_rd === io.IDEX_rs2)) {
io.forward_b := "b10".U
}.elsewhen(io.EXMEM_regWr === "b1".U && io.EXMEM_rd =/= "b00000".U &&
(io.EXMEM_rd === io.IDEX_rs1)) {
io.forward_a := "b10".U
}
If it is certain that the value will be written back to the register, and the rd register is not zero and the MEM rd equals EX rs (1 or 2), the forwarding bit is set to 2'b10.
when((io.MEMWB_regWr === "b1".U) && (io.MEMWB_rd =/= "b00000".U) && (io.MEMWB_rd === io.IDEX_rs1) && (io.MEMWB_rd === io.IDEX_rs2) &&
~(io.EXMEM_regWr === "b1".U && io.EXMEM_rd =/= "b00000".U && (io.EXMEM_rd === io.IDEX_rs1) && (io.EXMEM_rd === io.IDEX_rs2))) {
io.forward_a := "b01".U
io.forward_b := "b01".U
}.elsewhen((io.MEMWB_regWr === "b1".U) && (io.MEMWB_rd =/= "b00000".U) && (io.MEMWB_rd === io.IDEX_rs2) &&
~(io.EXMEM_regWr === "b1".U && io.EXMEM_rd =/= "b00000".U && (io.EXMEM_rd === io.IDEX_rs2))){
io.forward_b := "b01".U
}.elsewhen((io.MEMWB_regWr === "b1".U) && (io.MEMWB_rd =/= "b00000".U) && (io.MEMWB_rd === io.IDEX_rs1) &&
~(io.EXMEM_regWr === "b1".U && io.EXMEM_rd =/= "b00000".U && (io.EXMEM_rd === io.IDEX_rs1))){
io.forward_a := "b01".U
}
If it is certain that the value will be written back to the register, the rd register is not zero, the WB rd equals EX rs (1 or 2), and it is confirmed that there is no forwarding from MEM, the forwarding bit is set to 2'b01.
forwarding bit | forwarding from | forwarding to |
---|---|---|
2'b00 | non | non |
2'b10 | mem | ex |
2'b01 | wb | ex |
switch(io.alu_Op) {
is(ALU_ADD, ALU_ADDI, ALU_SW, ALU_LW, ALU_LUI, ALU_AUIPC) {
result := io.in_A + io.in_B
}
is(ALU_SLL, ALU_SLLI) {
result := (io.in_A.asUInt << io.in_B(4, 0)).asSInt
}
is(ALU_SLT, ALU_SLTI) {
result := Mux(io.in_A < io.in_B, 1.S, 0.S)
}
is(ALU_SLTU, ALU_SLTUI) {
result := Mux(io.in_A.asUInt < io.in_B.asUInt, 1.S, 0.S)
}
is(ALU_XOR, ALU_XORI) {
result := io.in_A ^ io.in_B
}
is(ALU_SRL, ALU_SRLI) {
result := (io.in_A.asUInt >> io.in_B(4, 0)).asSInt
}
is(ALU_OR, ALU_ORI) {
result := io.in_A | io.in_B
}
is(ALU_AND, ALU_ANDI) {
result := io.in_A & io.in_B
}
is(ALU_SUB) {
result := io.in_A - io.in_B
}
is(ALU_SRA, ALU_SRAI) {
result := (io.in_A >> io.in_B(4, 0)).asSInt
}
is(ALU_JAL, ALU_JALR) {
result := io.in_A
}
}
Perform calculations for each category using the ALU based on the classification.
val Rs1 = io.IF_ID_inst(19, 15)
val Rs2 = io.IF_ID_inst(24, 20)
when(io.ID_EX_memRead === 1.B && ((io.ID_EX_rd === Rs1) || (io.ID_EX_rd === Rs2))) {
io.inst_forward := true.B
io.pc_forward := true.B
io.ctrl_forward := true.B
}.otherwise {
io.inst_forward := false.B
io.pc_forward := false.B
io.ctrl_forward := false.B
}
io.inst_out := io.IF_ID_inst
io.pc_out := io.pc_in
io.current_pc_out := io.current_pc
This code implements Load-Use Hazard detection. When a memory load instruction has not completed its write-back and the next instruction depends on its result, it activates Forwarding or Stalling control signals to ensure data consistency and prevent instruction execution errors.
git clone https://github.com/sysprog21/rv32emu.git
sudo apt install libsdl2-dev libsdl2-mixer-dev
sudo apt-get install llvm-18
make ENABLE_JIT=1
result
gcc -march=rv32i_zicsr_zifencei -mabi=ilp32 -O2 -Wall -c -o getcycles.o getcycles.S
gcc: error: unrecognized argument in option ‘-mabi=ilp32’
gcc: note: valid arguments to ‘-mabi=’ are: ms sysv
make: *** [Makefile:15: getcycles.o] Error 1
1.Unsupported Compiler
You might be using the standard GCC for x86 or another platform to compile RISC-V code, but this GCC does not recognize the -march and -mabi options because these options are specific to the RISC-V target.
2.Compiler Prefix Error
The compile command might be using gcc instead of the cross-compiler, such as riscv32-unknown-elf-gcc.
environment
sudo apt update
sudo apt install gawk
sudo apt install bison flex texinfo
set
cd 5-Stage-RV32I/
git clone https://github.com/riscv/riscv-gnu-toolchain
./configure --prefix=/media/disk2/uuuwei0504/rv32emu --with-arch=rv32i_zicsr_zifencei --with-abi=ilp32cat
make
But encounter space-related issues
../.././gcc/gcc/config/riscv/thead-peephole.md:77:1: fatal error: error writing to /tmp/ccD30nlN.s: No space left on device
compilation terminated.
make[2]: *** [Makefile:1198: insn-recog.o] Error 1
make[2]: Leaving directory '/home/liu/5-stage-RV32I/riscv-gnu-toolchain/build-gcc-newlib-stage1/gcc'
make[1]: *** [Makefile:4702: all-gcc] Error 2
make[1]: Leaving directory '/home/liu/5-stage-RV32I/riscv-gnu-toolchain/build-gcc-newlib-stage1'
make: *** [Makefile:651: stamps/build-gcc-newlib-stage1] Error 2
git clone --recurse-submodules https://github.com/riscv/riscv-b.git
build
cd ./riscv-b && make build