Stage 11: Passing tests

This commit is contained in:
2025-11-09 17:48:18 +01:00
parent 4018f69f65
commit 603a1ac54a
8 changed files with 168 additions and 23 deletions

12
bench/tests/op/lb.s Normal file
View File

@@ -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)

12
bench/tests/op/lbu.s Normal file
View File

@@ -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)

16
bench/tests/op/lh.s Normal file
View File

@@ -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)

16
bench/tests/op/lhu.s Normal file
View File

@@ -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)

9
bench/tests/op/lw.s Normal file
View File

@@ -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)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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);
// 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_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(
control_unit.io.mux_writeback_pc,
Delay.Delay(control_unit.io.mux_writeback_pc, 1, true.B),
writeback_line,
reg_pc
);
reg_pc := Mux(control_unit.io.mux_pcadder_writeback,
// 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)