diff --git a/bench/tests/op/beq.s b/bench/tests/op/beq.s new file mode 100644 index 0000000..05f73e9 --- /dev/null +++ b/bench/tests/op/beq.s @@ -0,0 +1,15 @@ +# expected: 000001BC, 000002BC + .text +_start: + add x1, x0, 0x00A + add x2, x0, 0x00B + beq x1, x2, finish # Should not jump + add x31, x0, 0x1BC + + add x1, x0, 0x1BC + add x2, x0, 0x1BC + beq x1, x2, finish # Should jump to finish + add x31, x0, 0x3BC + +finish: + add x31, x0, 0x2BC diff --git a/bench/tests/op/bge.s b/bench/tests/op/bge.s new file mode 100644 index 0000000..aa5d6b3 --- /dev/null +++ b/bench/tests/op/bge.s @@ -0,0 +1,15 @@ +# expected: 000001BC, 000002BC + .text +_start: + add x1, x0, -29 + add x2, x0, -28 + bge x1, x2, finish # Should not jump + add x31, x0, 0x1BC + + add x1, x0, 12 + add x2, x0, 12 + bge x1, x2, finish # Should jump to finish + add x31, x0, 0x3BC + +finish: + add x31, x0, 0x2BC diff --git a/bench/tests/op/bgeu.s b/bench/tests/op/bgeu.s new file mode 100644 index 0000000..c4cc110 --- /dev/null +++ b/bench/tests/op/bgeu.s @@ -0,0 +1,15 @@ +# expected: 000001BC, 000002BC + .text +_start: + add x1, x0, 21 + add x2, x0, 22 + bgeu x1, x2, finish # Should not jump + add x31, x0, 0x1BC + + add x1, x0, 12 + add x2, x0, 12 + bgeu x1, x2, finish # Should jump to finish + add x31, x0, 0x3BC + +finish: + add x31, x0, 0x2BC diff --git a/bench/tests/op/blt.s b/bench/tests/op/blt.s new file mode 100644 index 0000000..3b34264 --- /dev/null +++ b/bench/tests/op/blt.s @@ -0,0 +1,15 @@ +# expected: 000001BC, 000002BC + .text +_start: + add x1, x0, -28 + add x2, x0, -28 + blt x1, x2, finish # Should not jump + add x31, x0, 0x1BC + + add x1, x0, -28 + add x2, x0, 12 + blt x1, x2, finish # Should jump to finish + add x31, x0, 0x3BC + +finish: + add x31, x0, 0x2BC diff --git a/bench/tests/op/bltu.s b/bench/tests/op/bltu.s new file mode 100644 index 0000000..e17e957 --- /dev/null +++ b/bench/tests/op/bltu.s @@ -0,0 +1,15 @@ +# expected: 000001BC, 000002BC + .text +_start: + add x1, x0, 28 + add x2, x0, 28 + bltu x1, x2, finish # Should not jump + add x31, x0, 0x1BC + + add x1, x0, 12 + add x2, x0, 24 + bltu x1, x2, finish # Should jump to finish + add x31, x0, 0x3BC + +finish: + add x31, x0, 0x2BC diff --git a/bench/tests/op/bne.s b/bench/tests/op/bne.s new file mode 100644 index 0000000..d42aaf1 --- /dev/null +++ b/bench/tests/op/bne.s @@ -0,0 +1,15 @@ +# expected: 000001BC, 000002BC + .text +_start: + add x1, x0, 0x00B + add x2, x0, 0x00B + bne x1, x2, finish # Should not jump + add x31, x0, 0x1BC + + add x1, x0, 0x1BA + add x2, x0, 0x1BC + bne x1, x2, finish # Should jump to finish + add x31, x0, 0x3BC + +finish: + add x31, x0, 0x2BC diff --git a/src/main/scala/projet/Alu.scala b/src/main/scala/projet/Alu.scala index 560e6e9..88fb81c 100644 --- a/src/main/scala/projet/Alu.scala +++ b/src/main/scala/projet/Alu.scala @@ -6,8 +6,8 @@ import chisel3.util.is object AluOpCode extends ChiselEnum { val Add, And, Or, Xor, ShiftLeft, ShiftRight, ShiftArithmeticRight, - LessThanSigned, LessThanUnsigned, GreaterEqualSigned, GreaterEqualUnsigned, - Equal = Value + LessThanSigned, LessThanUnsigned, GreaterEqualSigned, + GreaterEqualUnsigned, Equal = Value } class Alu extends Module { @@ -22,7 +22,7 @@ class Alu extends Module { }) io.out := 0.U; - io.flags := false.B; + io.comp_result := false.B; switch(io.opcode) { is(Add) { io.out := io.a + io.b; @@ -60,25 +60,25 @@ class Alu extends Module { } is(LessThanSigned) { - val less_than := io.a.asSInt < io.b.asSInt + val less_than = io.a.asSInt < io.b.asSInt io.out := less_than io.comp_result := less_than; } - + is(GreaterEqualUnsigned) { - val geq_than = io.a >== io.b; + val geq_than = io.a >= io.b; io.out := geq_than io.comp_result := geq_than; } is(GreaterEqualSigned) { - val geq_than := io.a.asSInt >== io.b.asSInt + val geq_than = io.a.asSInt >= io.b.asSInt io.out := geq_than io.comp_result := geq_than; } is(Equal) { - io.comp_result := io.& === io.b; + io.comp_result := io.a === io.b; } } diff --git a/src/main/scala/projet/ControlUnit.scala b/src/main/scala/projet/ControlUnit.scala index 841d2b5..bb8fbaf 100644 --- a/src/main/scala/projet/ControlUnit.scala +++ b/src/main/scala/projet/ControlUnit.scala @@ -8,6 +8,9 @@ class CUInterface extends Bundle { val instruction = Input(UInt(32.W)) val reg_file_we = Output(Bool()) val alu_opcode = Output(AluOpCode()) + // Alu comparison result + val alu_comp_result = Input(Bool()) + val optype = Output(OpType()) // True if the decoded instruction is a jump @@ -40,7 +43,7 @@ class CUInterface extends Bundle { } object OpType extends ChiselEnum { - val U, I, IR, J = Value + val U, I, IR, J, B = Value } object OpCode extends ChiselEnum { @@ -72,6 +75,9 @@ object OpCode extends ChiselEnum { // Type I val JALR = "b1100111".U + + // Type B + val OpBranch = "b1100011".U } class ControlUnit() extends Module { @@ -153,6 +159,11 @@ class ControlUnit() extends Module { io.mux_pcadder_writeback := false.B; // Set pc to writeback dest io.optype := OpType.I } + + is(OpCode.OpBranch) { + io.optype := OpType.B; + opBranch(funct3, io); + } } // Implements functions for all instruction of the opImm kind @@ -304,4 +315,78 @@ class ControlUnit() extends Module { } } } + + // Implements functions for all instruction of the branch kind + def opBranch(funct3: UInt, io: CUInterface) = { + // Meaning of Funct3 in the context of an OpBranch instruction + object Funct3 extends ChiselEnum { + val BEQ = "b000".U + val BNE = "b001".U + val BLT = "b100".U + val BGE = "b101".U + val BLTU = "b110".U + val BGEU = "b111".U + } + + val branch = WireInit(false.B); + switch(funct3) { + is(Funct3.BEQ) { + // Send operands from registers to alu + io.alu_opcode := AluOpCode.Equal + io.mux_rega_pc := true.B; + io.mux_regb_imm := true.B; + branch := io.alu_comp_result + } + + is(Funct3.BNE) { + // Send operands from registers to alu + io.alu_opcode := AluOpCode.Equal + io.mux_rega_pc := true.B; + io.mux_regb_imm := true.B; + branch := ~io.alu_comp_result + } + + // Signed comparison + is(Funct3.BLT) { + // Send operands from registers to alu + io.alu_opcode := AluOpCode.LessThanSigned + io.mux_rega_pc := true.B; + io.mux_regb_imm := true.B; + branch := io.alu_comp_result + } + + is(Funct3.BGE) { + // Send operands from registers to alu + io.alu_opcode := AluOpCode.LessThanSigned + io.mux_rega_pc := true.B; + io.mux_regb_imm := true.B; + branch := ~io.alu_comp_result + } + + // Signed comparison + is(Funct3.BLTU) { + // Send operands from registers to alu + io.alu_opcode := AluOpCode.LessThanUnsigned + io.mux_rega_pc := true.B; + io.mux_regb_imm := true.B; + branch := io.alu_comp_result + } + + is(Funct3.BGEU) { + // Send operands from registers to alu + io.alu_opcode := AluOpCode.LessThanUnsigned + io.mux_rega_pc := true.B; + io.mux_regb_imm := true.B; + branch := ~io.alu_comp_result + } + } + + // Branch if comparison is successful + when(branch) { + io.mux_pcadder_writeback := true.B; + io.mux_incrpc4_imm := false.B; + io.mux_regpc_executepc := false.B; + io.is_jump := true.B; + } + } } diff --git a/src/main/scala/projet/ImmediateDecoder.scala b/src/main/scala/projet/ImmediateDecoder.scala index 132690b..354c7a3 100644 --- a/src/main/scala/projet/ImmediateDecoder.scala +++ b/src/main/scala/projet/ImmediateDecoder.scala @@ -28,6 +28,14 @@ class ImmediateDecoder extends Module { io.instruction(30, 21), 0.U ); + val imm_b = Cat( + Fill(19, io.instruction(31)), + io.instruction(31), + io.instruction(7), + io.instruction(30, 25), + io.instruction(11, 8), + 0.U + ) switch(io.op_type) { is(OpType.U) { @@ -42,5 +50,8 @@ class ImmediateDecoder extends Module { is(OpType.J) { io.immediate := imm_j } + is(OpType.B) { + io.immediate := imm_b + } } } diff --git a/src/main/scala/projet/Rv32i.scala b/src/main/scala/projet/Rv32i.scala index cd1083b..1c38f33 100644 --- a/src/main/scala/projet/Rv32i.scala +++ b/src/main/scala/projet/Rv32i.scala @@ -23,6 +23,8 @@ class Rv32i(sim: Boolean = true) extends Module { val immediate_decoder = Module(new ImmediateDecoder()); val control_unit = Module(new ControlUnit()); + control_unit.io.alu_comp_result := alu.io.comp_result + // PC delayed to execute stage for auipc op val execute_pc = Delay.Delay(reg_pc, 1, 0.U); // True if the instruction in the execute stage is a jump