From 603a1ac54a8a0ee111f252f2bb706eee2610a3c0 Mon Sep 17 00:00:00 2001 From: Albin Chaboissier Date: Sun, 9 Nov 2025 17:48:18 +0100 Subject: [PATCH] Stage 11: Passing tests --- bench/tests/op/lb.s | 12 +++++ bench/tests/op/lbu.s | 12 +++++ bench/tests/op/lh.s | 16 ++++++ bench/tests/op/lhu.s | 16 ++++++ bench/tests/op/lw.s | 9 ++++ src/main/scala/projet/ControlUnit.scala | 26 ++++++++++ src/main/scala/projet/DMem.scala | 35 ++++++++++++- src/main/scala/projet/Rv32i.scala | 65 +++++++++++++++++-------- 8 files changed, 168 insertions(+), 23 deletions(-) create mode 100644 bench/tests/op/lb.s create mode 100644 bench/tests/op/lbu.s create mode 100644 bench/tests/op/lh.s create mode 100644 bench/tests/op/lhu.s create mode 100644 bench/tests/op/lw.s diff --git a/bench/tests/op/lb.s b/bench/tests/op/lb.s new file mode 100644 index 0000000..6a383aa --- /dev/null +++ b/bench/tests/op/lb.s @@ -0,0 +1,12 @@ +# expected: FFFFFFFB, FFFFFFFB + .text +_start: + addi x1, x0, 0x0FB + nop # Next instruction depends on previous register op + sb x1, 100(x0) + lb x31, 100(x0) + + addi x1, x0, 0x0FB + nop # Next instruction depends on previous register op + sb x1, 106(x0) + lb x31, 106(x0) diff --git a/bench/tests/op/lbu.s b/bench/tests/op/lbu.s new file mode 100644 index 0000000..df68222 --- /dev/null +++ b/bench/tests/op/lbu.s @@ -0,0 +1,12 @@ +# expected: 000000FB, 000000FB + .text +_start: + addi x1, x0, 0x0FB + nop # Next instruction depends on previous register op + sb x1, 100(x0) + lbu x31, 100(x0) + + addi x1, x0, 0x0FB + nop # Next instruction depends on previous register op + sb x1, 106(x0) + lbu x31, 106(x0) diff --git a/bench/tests/op/lh.s b/bench/tests/op/lh.s new file mode 100644 index 0000000..98ef006 --- /dev/null +++ b/bench/tests/op/lh.s @@ -0,0 +1,16 @@ +# expected: FFFFF1BC, FFFFF1BC + .text +_start: + lui x1, 0xF + nop # Next instruction depends on previous register op + ori x1, x1, 0x1BC + nop # Next instruction depends on previous register op + sh x1, 100(x0) + lh x31, 100(x0) + + lui x1, 0xF + nop # Next instruction depends on previous register op + ori x1, x1, 0x1BC + nop # Next instruction depends on previous register op + sh x1, 106(x0) + lh x31, 106(x0) diff --git a/bench/tests/op/lhu.s b/bench/tests/op/lhu.s new file mode 100644 index 0000000..d039a95 --- /dev/null +++ b/bench/tests/op/lhu.s @@ -0,0 +1,16 @@ +# expected: 0000F1BC, 0000F1BC + .text +_start: + lui x1, 0xF + nop # Next instruction depends on previous register op + ori x1, x1, 0x1BC + nop # Next instruction depends on previous register op + sh x1, 100(x0) + lhu x31, 100(x0) + + lui x1, 0xF + nop # Next instruction depends on previous register op + ori x1, x1, 0x1BC + nop # Next instruction depends on previous register op + sh x1, 106(x0) + lhu x31, 106(x0) diff --git a/bench/tests/op/lw.s b/bench/tests/op/lw.s new file mode 100644 index 0000000..3558bdd --- /dev/null +++ b/bench/tests/op/lw.s @@ -0,0 +1,9 @@ +# expected: 123451BC + .text +_start: + lui x1, 0x12345 + nop # Next instruction depends on previous register op + ori x1, x1, 0x1BC + nop # Next instruction depends on previous register op + sw x1, 100(x0) + lw x31, 100(x0) diff --git a/src/main/scala/projet/ControlUnit.scala b/src/main/scala/projet/ControlUnit.scala index 6c829a2..c938bce 100644 --- a/src/main/scala/projet/ControlUnit.scala +++ b/src/main/scala/projet/ControlUnit.scala @@ -20,6 +20,9 @@ class CUInterface extends Bundle { val memory_size = Output(DMemSize()) val memory_en = Output(Bool()) val memory_we = Output(Bool()) + val memory_sign_extend = Output( + Bool() + ) // Wether to signe extend the output of the memory for bytes, half loads // Muxers // The naming convention is as follows : mux_xxx_yyy. @@ -45,6 +48,9 @@ class CUInterface extends Bundle { // Selects pc or write back for register write val mux_writeback_pc = Output(Bool()) + + // Selects aluout or memory data out for writeback_line + val mux_executeout_dout = Output(Bool()) } object OpType extends ChiselEnum { @@ -101,6 +107,7 @@ class ControlUnit() extends Module { io.memory_size := DMemSize.Word io.memory_en := false.B io.memory_we := false.B + io.memory_sign_extend := false.B; io.mux_alu_imm := true.B; io.mux_rega_pc := true.B; io.mux_regb_imm := true.B; @@ -108,6 +115,7 @@ class ControlUnit() extends Module { io.mux_regpc_executepc := true.B; io.mux_writeback_pc := true.B; io.mux_pcadder_writeback := true.B; + io.mux_executeout_dout := true.B; // Decode instruction val opcode = io.instruction(6, 0); @@ -447,21 +455,39 @@ class ControlUnit() extends Module { val LB = "b000".U val LH = "b001".U val LW = "b010".U + val LBU = "b100".U + val LHU = "b101".U } io.alu_opcode := AluOpCode.Add io.mux_alu_imm := true.B io.mux_rega_pc := true.B io.mux_regb_imm := false.B + io.mux_writeback_pc := true.B; + io.mux_executeout_dout := false.B; io.reg_file_we := true.B io.memory_en := true.B + io.memory_we := false.B switch(funct3) { + // Byte load is(Funct3.LB) { io.memory_size := DMemSize.Byte + io.memory_sign_extend := true.B; } + is(Funct3.LBU) { + io.memory_size := DMemSize.Byte + } + + // Half load is(Funct3.LH) { io.memory_size := DMemSize.Half + io.memory_sign_extend := true.B; } + is(Funct3.LHU) { + io.memory_size := DMemSize.Half + } + + // Word load is(Funct3.LW) { io.memory_size := DMemSize.Word } diff --git a/src/main/scala/projet/DMem.scala b/src/main/scala/projet/DMem.scala index c7f1928..4924af0 100644 --- a/src/main/scala/projet/DMem.scala +++ b/src/main/scala/projet/DMem.scala @@ -4,6 +4,7 @@ import chisel3._ import chisel3.util.switch import chisel3.util.is import chisel3.util.Cat +import chisel3.util.Fill object DMemSize extends ChiselEnum { val Byte, Half, Word = Value @@ -20,14 +21,16 @@ class DMem extends Module { val data_in = Input(UInt(32.W)) val data_out = Output(UInt(32.W)) + val sign_extend = Input(Bool()) }) io.dbus.addr := Cat(io.addr(31, 2), 0.U(2.W)); io.dbus.en := io.en; + io.data_out := 0.U val bytes_enabled = VecInit(false.B, false.B, false.B, false.B) val data = WireInit(0.U(32.W)) - when(io.we) { + when(io.we && io.en) { switch(io.size) { is(DMemSize.Byte) { bytes_enabled(io.addr(1, 0)) := true.B @@ -47,9 +50,37 @@ class DMem extends Module { } } } + + // Data out is available one cycle after the read request + val read_addr = Delay.Delay(io.addr, 1, 0.U); + val read_sign_extend = Delay.Delay(io.sign_extend, 1, false.B); + when(Delay.Delay(io.en && !io.we, 1, false.B)) { + switch(Delay.Delay(io.size, 1, DMemSize.Byte)) { + is(DMemSize.Byte) { + val dout = (io.dbus.rdata >> + (read_addr(1) * 16.U + read_addr(0) * 8.U)) & 0xff.U; + io.data_out := dout | Mux( + read_sign_extend, + Fill(24, dout(7)) << 8.U, + 0.U + ); + } + is(DMemSize.Half) { + val dout = (io.dbus.rdata >> + (read_addr(1) * 16.U)) & 0xffff.U; + io.data_out := dout | Mux( + read_sign_extend, + Fill(16, dout(15)) << 16.U, + 0.U + ); + } + is(DMemSize.Word) { + io.data_out := io.dbus.rdata + } + } + } io.dbus.be := bytes_enabled io.dbus.wdata := data - io.data_out := 0.U } diff --git a/src/main/scala/projet/Rv32i.scala b/src/main/scala/projet/Rv32i.scala index 3189283..ae24aab 100644 --- a/src/main/scala/projet/Rv32i.scala +++ b/src/main/scala/projet/Rv32i.scala @@ -27,6 +27,7 @@ class Rv32i(sim: Boolean = true) extends Module { dmem.io.en := control_unit.io.memory_en dmem.io.we := control_unit.io.memory_we dmem.io.size := control_unit.io.memory_size + dmem.io.sign_extend := control_unit.io.memory_sign_extend control_unit.io.alu_comp_result := alu.io.comp_result @@ -35,13 +36,23 @@ class Rv32i(sim: Boolean = true) extends Module { // True if the instruction in the execute stage is a jump val is_jump = Delay.Delay(control_unit.io.is_jump, 1, false.B); + // Pipelining registers for mem stage + val reg_rd_index = RegInit(0.U); + val reg_execute_out = RegInit(0.U); + val reg_mux_executeout_dout = RegInit(true.B); + val reg_regile_we = RegInit(false.B); + // Insert no-op if jump - val instruction = Mux(is_jump, 0b00000000000000000000000000010011.U, io.ibus.rdata); + val instruction = + Mux(is_jump, "b00000000000000000000000000010011".U, io.ibus.rdata); immediate_decoder.io.instruction := instruction immediate_decoder.io.op_type := control_unit.io.optype alu.io.opcode := control_unit.io.alu_opcode; - reg_file.io.we := control_unit.io.reg_file_we + + // Reg file write-enable + reg_regile_we := control_unit.io.reg_file_we; + reg_file.io.we := reg_regile_we; // Increment PC each clock val pc_adder_out = Mux( @@ -54,7 +65,6 @@ class Rv32i(sim: Boolean = true) extends Module { immediate_decoder.io.immediate ); - // Fetch instruction io.ibus.en := true.B; io.ibus.addr := reg_pc; @@ -62,14 +72,15 @@ class Rv32i(sim: Boolean = true) extends Module { control_unit.io.instruction := instruction; // Decode rs1 index - val rs1 = instruction(19, 15) - reg_file.io.rs1_addr := rs1 + val rs1_index = instruction(19, 15) + reg_file.io.rs1_addr := rs1_index // Decode rs2 index - val rs2 = instruction(24, 20) - reg_file.io.rs2_addr := rs2 + val rs2_index = instruction(24, 20) + reg_file.io.rs2_addr := rs2_index // Decode rd index - val rd = instruction(11, 7) - reg_file.io.rd_addr := rd + val rd_index = instruction(11, 7) + reg_rd_index := rd_index; + reg_file.io.rd_addr := reg_rd_index; // EXECUTE @@ -82,21 +93,33 @@ class Rv32i(sim: Boolean = true) extends Module { ); alu.io.b := Mux(control_unit.io.mux_regb_imm, reg_file.io.rs2_data, imm); - val writeback_line = Mux(control_unit.io.mux_alu_imm, alu.io.out, imm); - reg_file.io.rd_data := - Mux( - control_unit.io.mux_writeback_pc, - writeback_line, - reg_pc - ); + // Select what to send on writeback line + val execute_out = Mux(control_unit.io.mux_alu_imm, alu.io.out, imm); + reg_execute_out := execute_out; - reg_pc := Mux(control_unit.io.mux_pcadder_writeback, - pc_adder_out, - writeback_line - ); + reg_mux_executeout_dout := control_unit.io.mux_executeout_dout; + val writeback_line = Mux( + reg_mux_executeout_dout, + reg_execute_out, + dmem.io.data_out + ); + + reg_file.io.rd_data := + Mux( + Delay.Delay(control_unit.io.mux_writeback_pc, 1, true.B), + writeback_line, + reg_pc + ); + + // Writeback pipelining registers + reg_pc := Mux( + control_unit.io.mux_pcadder_writeback, + pc_adder_out, + writeback_line + ); dmem.io.data_in := reg_file.io.rs2_data - dmem.io.addr := writeback_line + dmem.io.addr := execute_out io.ibus.wdata := 0.U; io.ibus.be := VecInit(false.B, false.B, false.B, false.B)