diff --git a/bench/tests/op/addiw.s b/bench/tests/op/addiw.s new file mode 100644 index 0000000..5943844 --- /dev/null +++ b/bench/tests/op/addiw.s @@ -0,0 +1,14 @@ +# expected: 0000000000000000, FFFFFFFFFFFFFFFF, 0000000000000010 + .text +_start: + # This test CANNOT use li as it uses addiw under the hood + + # 0 addition + addiw x31, x0, 0 + + # all bits addition + sign extension to 32 bits then 64 bits + addiw x31, x0, (-1) + + # simple addition + addi x1, x0, 8 + addiw x31, x1, 8 diff --git a/src/main/scala/projet/Alu.scala b/src/main/scala/projet/Alu.scala index 2639ac4..9f8b633 100644 --- a/src/main/scala/projet/Alu.scala +++ b/src/main/scala/projet/Alu.scala @@ -5,9 +5,9 @@ import chisel3.util.switch import chisel3.util.is object AluOpCode extends ChiselEnum { - val Add, AddW, Sub, And, Or, Xor, ShiftLeft, ShiftRight, - ShiftArithmeticRight, LessThanSigned, LessThanUnsigned, - GreaterEqualSigned, GreaterEqualUnsigned, Equal = Value + val Add, Sub, And, Or, Xor, ShiftLeft, ShiftRight, ShiftArithmeticRight, + LessThanSigned, LessThanUnsigned, GreaterEqualSigned, + GreaterEqualUnsigned, Equal = Value } class Alu extends Module { @@ -19,65 +19,87 @@ class Alu extends Module { val out = Output(UInt(64.W)) val opcode = Input(AluOpCode()) val comp_result = Output(Bool()) + + // ~~ Rv64i ~~ + // If word_mode is enabled, operations are performed + // on 32-bit-truncated inputs and then sign extended to 64bits + val word_mode = Input(Bool()) }) io.out := 0.U; io.comp_result := false.B; + val out = WireInit(0.U(64.W)) + val op_a = WireInit(0.U(64.W)) + val op_b = WireInit(0.U(64.W)) + + // Defaults + op_a := io.a + op_b := io.b + io.out := out + + // Truncate operands, sext result + when(io.word_mode) { + op_a := io.a(31, 0) + op_b := io.b(31, 0) + + io.out := SignExtend.Sext(out(31, 0), 64) + } + switch(io.opcode) { is(Add) { - io.out := io.a + io.b; + out := io.a + io.b; } is(Sub) { - io.out := io.a - io.b; + out := io.a - io.b; } is(And) { - io.out := io.a & io.b; + out := io.a & io.b; } is(Or) { - io.out := io.a | io.b; + out := io.a | io.b; } is(Xor) { - io.out := io.a ^ io.b; + out := io.a ^ io.b; } is(ShiftLeft) { - io.out := io.a << io.b(5, 0); + out := io.a << io.b(5, 0); } is(ShiftRight) { - io.out := io.a >> io.b(5, 0); + out := io.a >> io.b(5, 0); } is(ShiftArithmeticRight) { // >> means arithmetic shift for SInts - io.out := (io.a.asSInt >> io.b(5, 0)).asUInt; + out := (io.a.asSInt >> io.b(5, 0)).asUInt; } is(LessThanUnsigned) { val less_than = io.a < io.b; - io.out := less_than; + out := less_than; io.comp_result := less_than; } is(LessThanSigned) { val less_than = io.a.asSInt < io.b.asSInt - io.out := less_than + out := less_than io.comp_result := less_than; } is(GreaterEqualUnsigned) { val geq_than = io.a >= io.b; - io.out := geq_than + out := geq_than io.comp_result := geq_than; } is(GreaterEqualSigned) { val geq_than = io.a.asSInt >= io.b.asSInt - io.out := geq_than + out := geq_than io.comp_result := geq_than; } diff --git a/src/main/scala/projet/ControlUnit.scala b/src/main/scala/projet/ControlUnit.scala index 9fc7560..291c624 100644 --- a/src/main/scala/projet/ControlUnit.scala +++ b/src/main/scala/projet/ControlUnit.scala @@ -8,8 +8,11 @@ class CUInterface extends Bundle { val instruction = Input(UInt(32.W)) val reg_file_we = Output(Bool()) val alu_opcode = Output(AluOpCode()) + + // TODO: Maybe bundle alu <> cu // Alu comparison result val alu_comp_result = Input(Bool()) + val alu_word_mode = Output(Bool()) val optype = Output(OpType()) @@ -95,6 +98,9 @@ object OpCode extends ChiselEnum { // Type I val OpLoad = "b0000011".U + + // ~~ Rv64i ~~ + val OpImmW = "b0011011".U } class ControlUnit() extends Module { @@ -102,6 +108,7 @@ class ControlUnit() extends Module { io.reg_file_we := false.B io.alu_opcode := AluOpCode.Add + io.alu_word_mode := false.B io.optype := OpType.U io.is_jump := false.B; io.memory_size := DMemSize.Word @@ -196,6 +203,12 @@ class ControlUnit() extends Module { io.optype := OpType.I opLoad(funct3, io); } + + is(OpCode.OpImmW) { + io.reg_file_we := true.B // Write to regfile + io.optype := OpType.I + opImmW(funct3, funct7, io); + } } // Implements functions for all instruction of the opImm kind @@ -224,6 +237,7 @@ class ControlUnit() extends Module { io.mux_regb_imm := false.B; // OpImm are operations with imm, so send imm to ALU io.mux_alu_imm := true.B; io.mux_rega_pc := true.B; + io.alu_word_mode := false.B; switch(funct3) { // Type I is(Funct3.ADDI) { @@ -505,4 +519,40 @@ class ControlUnit() extends Module { } } } + + // ~~~ EXTENSIONS ~~~ + + // ~~ Rv64i ~~ + + // Implements functions for all instruction of the opImm, w kind + def opImmW(funct3: UInt, funct7: UInt, io: CUInterface) = { + // Meaning of Funct3 in the context of an OpImm instruction + val _ = funct7; + object Funct3 extends ChiselEnum { + // Type I + val ADDIW = "b000".U + val SLLIW = "b001".U + + // Unimplemented + val SRLIW_SRAIW = "b101".U // Right shifts + } + + // Meaning of Funct7 in the context of SHIFTR IR instructions + // object IRFunct7 extends ChiselEnum { + // val SRLI = "b0000000".U + // val SRAI = "b0100000".U + // } + + io.mux_regb_imm := false.B; // OpImm are operations with imm, so send imm to ALU + io.mux_alu_imm := true.B; + io.mux_rega_pc := true.B; + switch(funct3) { + // Type I + is(Funct3.ADDIW) { + io.alu_word_mode := true.B + io.alu_opcode := AluOpCode.Add + io.optype := OpType.I + } + } + } } diff --git a/src/main/scala/projet/Rv64i.scala b/src/main/scala/projet/Rv64i.scala index b6b8c6b..3237248 100644 --- a/src/main/scala/projet/Rv64i.scala +++ b/src/main/scala/projet/Rv64i.scala @@ -30,6 +30,7 @@ class Rv64i(sim: Boolean = true) extends Module { dmem.io.sign_extend := control_unit.io.memory_sign_extend control_unit.io.alu_comp_result := alu.io.comp_result + alu.io.word_mode := control_unit.io.alu_word_mode // PC delayed to execute stage for auipc op val execute_pc = Delay.Delay(reg_pc, 1, 0.U); diff --git a/src/main/scala/projet/SignExtend.scala b/src/main/scala/projet/SignExtend.scala new file mode 100644 index 0000000..9f7e09f --- /dev/null +++ b/src/main/scala/projet/SignExtend.scala @@ -0,0 +1,11 @@ +package projet + +import chisel3.UInt +import chisel3.util.Fill + +// Utility function to sign extend number to higher amount of bits +object SignExtend { + def Sext(x: UInt, n: Int): UInt = { + Fill(n - x.getWidth, x(x.getWidth - 1)) ## x + } +}