Stage 11: Passing tests
This commit is contained in:
12
bench/tests/op/lb.s
Normal file
12
bench/tests/op/lb.s
Normal 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
12
bench/tests/op/lbu.s
Normal 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
16
bench/tests/op/lh.s
Normal 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
16
bench/tests/op/lhu.s
Normal 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
9
bench/tests/op/lw.s
Normal 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)
|
||||||
@@ -20,6 +20,9 @@ class CUInterface extends Bundle {
|
|||||||
val memory_size = Output(DMemSize())
|
val memory_size = Output(DMemSize())
|
||||||
val memory_en = Output(Bool())
|
val memory_en = Output(Bool())
|
||||||
val memory_we = 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
|
// Muxers
|
||||||
// The naming convention is as follows : mux_xxx_yyy.
|
// 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
|
// Selects pc or write back for register write
|
||||||
val mux_writeback_pc = Output(Bool())
|
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 {
|
object OpType extends ChiselEnum {
|
||||||
@@ -101,6 +107,7 @@ class ControlUnit() extends Module {
|
|||||||
io.memory_size := DMemSize.Word
|
io.memory_size := DMemSize.Word
|
||||||
io.memory_en := false.B
|
io.memory_en := false.B
|
||||||
io.memory_we := false.B
|
io.memory_we := false.B
|
||||||
|
io.memory_sign_extend := false.B;
|
||||||
io.mux_alu_imm := true.B;
|
io.mux_alu_imm := true.B;
|
||||||
io.mux_rega_pc := true.B;
|
io.mux_rega_pc := true.B;
|
||||||
io.mux_regb_imm := true.B;
|
io.mux_regb_imm := true.B;
|
||||||
@@ -108,6 +115,7 @@ class ControlUnit() extends Module {
|
|||||||
io.mux_regpc_executepc := true.B;
|
io.mux_regpc_executepc := true.B;
|
||||||
io.mux_writeback_pc := true.B;
|
io.mux_writeback_pc := true.B;
|
||||||
io.mux_pcadder_writeback := true.B;
|
io.mux_pcadder_writeback := true.B;
|
||||||
|
io.mux_executeout_dout := true.B;
|
||||||
|
|
||||||
// Decode instruction
|
// Decode instruction
|
||||||
val opcode = io.instruction(6, 0);
|
val opcode = io.instruction(6, 0);
|
||||||
@@ -447,21 +455,39 @@ class ControlUnit() extends Module {
|
|||||||
val LB = "b000".U
|
val LB = "b000".U
|
||||||
val LH = "b001".U
|
val LH = "b001".U
|
||||||
val LW = "b010".U
|
val LW = "b010".U
|
||||||
|
val LBU = "b100".U
|
||||||
|
val LHU = "b101".U
|
||||||
}
|
}
|
||||||
|
|
||||||
io.alu_opcode := AluOpCode.Add
|
io.alu_opcode := AluOpCode.Add
|
||||||
io.mux_alu_imm := true.B
|
io.mux_alu_imm := true.B
|
||||||
io.mux_rega_pc := true.B
|
io.mux_rega_pc := true.B
|
||||||
io.mux_regb_imm := false.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.reg_file_we := true.B
|
||||||
io.memory_en := true.B
|
io.memory_en := true.B
|
||||||
|
io.memory_we := false.B
|
||||||
switch(funct3) {
|
switch(funct3) {
|
||||||
|
// Byte load
|
||||||
is(Funct3.LB) {
|
is(Funct3.LB) {
|
||||||
io.memory_size := DMemSize.Byte
|
io.memory_size := DMemSize.Byte
|
||||||
|
io.memory_sign_extend := true.B;
|
||||||
}
|
}
|
||||||
|
is(Funct3.LBU) {
|
||||||
|
io.memory_size := DMemSize.Byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Half load
|
||||||
is(Funct3.LH) {
|
is(Funct3.LH) {
|
||||||
io.memory_size := DMemSize.Half
|
io.memory_size := DMemSize.Half
|
||||||
|
io.memory_sign_extend := true.B;
|
||||||
}
|
}
|
||||||
|
is(Funct3.LHU) {
|
||||||
|
io.memory_size := DMemSize.Half
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word load
|
||||||
is(Funct3.LW) {
|
is(Funct3.LW) {
|
||||||
io.memory_size := DMemSize.Word
|
io.memory_size := DMemSize.Word
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import chisel3._
|
|||||||
import chisel3.util.switch
|
import chisel3.util.switch
|
||||||
import chisel3.util.is
|
import chisel3.util.is
|
||||||
import chisel3.util.Cat
|
import chisel3.util.Cat
|
||||||
|
import chisel3.util.Fill
|
||||||
|
|
||||||
object DMemSize extends ChiselEnum {
|
object DMemSize extends ChiselEnum {
|
||||||
val Byte, Half, Word = Value
|
val Byte, Half, Word = Value
|
||||||
@@ -20,14 +21,16 @@ class DMem extends Module {
|
|||||||
val data_in = Input(UInt(32.W))
|
val data_in = Input(UInt(32.W))
|
||||||
|
|
||||||
val data_out = Output(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.addr := Cat(io.addr(31, 2), 0.U(2.W));
|
||||||
io.dbus.en := io.en;
|
io.dbus.en := io.en;
|
||||||
|
io.data_out := 0.U
|
||||||
|
|
||||||
val bytes_enabled = VecInit(false.B, false.B, false.B, false.B)
|
val bytes_enabled = VecInit(false.B, false.B, false.B, false.B)
|
||||||
val data = WireInit(0.U(32.W))
|
val data = WireInit(0.U(32.W))
|
||||||
|
|
||||||
when(io.we) {
|
when(io.we && io.en) {
|
||||||
switch(io.size) {
|
switch(io.size) {
|
||||||
is(DMemSize.Byte) {
|
is(DMemSize.Byte) {
|
||||||
bytes_enabled(io.addr(1, 0)) := true.B
|
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.be := bytes_enabled
|
||||||
|
|
||||||
io.dbus.wdata := data
|
io.dbus.wdata := data
|
||||||
|
|
||||||
io.data_out := 0.U
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class Rv32i(sim: Boolean = true) extends Module {
|
|||||||
dmem.io.en := control_unit.io.memory_en
|
dmem.io.en := control_unit.io.memory_en
|
||||||
dmem.io.we := control_unit.io.memory_we
|
dmem.io.we := control_unit.io.memory_we
|
||||||
dmem.io.size := control_unit.io.memory_size
|
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
|
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
|
// True if the instruction in the execute stage is a jump
|
||||||
val is_jump = Delay.Delay(control_unit.io.is_jump, 1, false.B);
|
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
|
// 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.instruction := instruction
|
||||||
immediate_decoder.io.op_type := control_unit.io.optype
|
immediate_decoder.io.op_type := control_unit.io.optype
|
||||||
alu.io.opcode := control_unit.io.alu_opcode;
|
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
|
// Increment PC each clock
|
||||||
val pc_adder_out = Mux(
|
val pc_adder_out = Mux(
|
||||||
@@ -54,7 +65,6 @@ class Rv32i(sim: Boolean = true) extends Module {
|
|||||||
immediate_decoder.io.immediate
|
immediate_decoder.io.immediate
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Fetch instruction
|
// Fetch instruction
|
||||||
io.ibus.en := true.B;
|
io.ibus.en := true.B;
|
||||||
io.ibus.addr := reg_pc;
|
io.ibus.addr := reg_pc;
|
||||||
@@ -62,14 +72,15 @@ class Rv32i(sim: Boolean = true) extends Module {
|
|||||||
control_unit.io.instruction := instruction;
|
control_unit.io.instruction := instruction;
|
||||||
|
|
||||||
// Decode rs1 index
|
// Decode rs1 index
|
||||||
val rs1 = instruction(19, 15)
|
val rs1_index = instruction(19, 15)
|
||||||
reg_file.io.rs1_addr := rs1
|
reg_file.io.rs1_addr := rs1_index
|
||||||
// Decode rs2 index
|
// Decode rs2 index
|
||||||
val rs2 = instruction(24, 20)
|
val rs2_index = instruction(24, 20)
|
||||||
reg_file.io.rs2_addr := rs2
|
reg_file.io.rs2_addr := rs2_index
|
||||||
// Decode rd index
|
// Decode rd index
|
||||||
val rd = instruction(11, 7)
|
val rd_index = instruction(11, 7)
|
||||||
reg_file.io.rd_addr := rd
|
reg_rd_index := rd_index;
|
||||||
|
reg_file.io.rd_addr := reg_rd_index;
|
||||||
|
|
||||||
// EXECUTE
|
// 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);
|
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
|
||||||
reg_file.io.rd_data :=
|
val execute_out = Mux(control_unit.io.mux_alu_imm, alu.io.out, imm);
|
||||||
Mux(
|
reg_execute_out := execute_out;
|
||||||
control_unit.io.mux_writeback_pc,
|
|
||||||
writeback_line,
|
|
||||||
reg_pc
|
|
||||||
);
|
|
||||||
|
|
||||||
reg_pc := Mux(control_unit.io.mux_pcadder_writeback,
|
reg_mux_executeout_dout := control_unit.io.mux_executeout_dout;
|
||||||
pc_adder_out,
|
val writeback_line = Mux(
|
||||||
writeback_line
|
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.data_in := reg_file.io.rs2_data
|
||||||
dmem.io.addr := writeback_line
|
dmem.io.addr := execute_out
|
||||||
|
|
||||||
io.ibus.wdata := 0.U;
|
io.ibus.wdata := 0.U;
|
||||||
io.ibus.be := VecInit(false.B, false.B, false.B, false.B)
|
io.ibus.be := VecInit(false.B, false.B, false.B, false.B)
|
||||||
|
|||||||
Reference in New Issue
Block a user