diff --git a/Makefile b/Makefile index fa63653..7d58825 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ OBJCOPY := $(PREFIX)objcopy OBTOMEM := common/objtomem.awk ## Flags -ASFLAGS :=-march=rv64i -mabi=lp64 -ffreestanding -nostdlib -T $(BENCH_DIR)/link.ld +ASFLAGS :=-march=rv64im -mabi=lp64 -ffreestanding -nostdlib -T $(BENCH_DIR)/link.ld CFLAGS :=$(ASFLAGS) ELFFLAGS :=$(ASFLAGS) $(MEM_DIR)/crt.o -Os -fno-unroll-loops ODFLAGS :=-j .text -j .rodata -j .data -s diff --git a/bench/tests/op/mul.s b/bench/tests/op/mul.s new file mode 100644 index 0000000..429aab2 --- /dev/null +++ b/bench/tests/op/mul.s @@ -0,0 +1,18 @@ +# expected: 0000000000000000, ffffffffdead0000, 045680e900000000, 0000000021530000 + .text +_start: + lui x2, 0xdead0 + lui x3, 0x0 + addi x4, x0, 0x1 + addi x5, x0, (-1) + lui x6, 0xdead0 + + # Mul 0 + mul x31, x2, x3 + + # Basic multiplications + mul x31, x2, x4 + mul x31, x2, x6 + + # Overflow + mul x31, x5, x2 diff --git a/bench/tests/op/mulh.s b/bench/tests/op/mulh.s new file mode 100644 index 0000000..8fd593a --- /dev/null +++ b/bench/tests/op/mulh.s @@ -0,0 +1,18 @@ +# expected: 0000000000000000, 0000000000000000, ffffffffbd5a0000, ffffffffdeacffff + .text +_start: + lui x2, 0xdead0 + lui x3, 0x0 + addi x4, x0, 0x1 + addi x5, x0, (-1) + lui x6, 0xdead0 + + # Mul 0 + mulh x31, x2, x3 + + # Basic multiplications + mulh x31, x2, x4 + mulh x31, x2, x6 + + # Overflow + mulh x31, x5, x2 diff --git a/bench/tests/op/mulhsu.s b/bench/tests/op/mulhsu.s new file mode 100644 index 0000000..5cb8e1e --- /dev/null +++ b/bench/tests/op/mulhsu.s @@ -0,0 +1,18 @@ +# expected: 0000000000000000, 0000000000000000, ffffffffbd5a0000, ffffffffdeacffff + .text +_start: + lui x2, 0xdead0 + lui x3, 0x0 + addi x4, x0, 0x1 + addi x5, x0, (-1) + lui x6, 0xdead0 + + # Mul 0 + mulhsu x31, x2, x3 + + # Basic multiplications + mulhsu x31, x2, x4 + mulhsu x31, x2, x6 + + # Overflow + mulhsu x31, x5, x2 diff --git a/src/main/scala/projet/Alu.scala b/src/main/scala/projet/Alu.scala index 2639ac4..a53ac8b 100644 --- a/src/main/scala/projet/Alu.scala +++ b/src/main/scala/projet/Alu.scala @@ -3,11 +3,15 @@ package projet import chisel3._ import chisel3.util.switch import chisel3.util.is +import chisel3.util.Cat +import chisel3.util.Fill object AluOpCode extends ChiselEnum { - val Add, AddW, Sub, And, Or, Xor, ShiftLeft, ShiftRight, + val Add, AddW, Sub, Mul, Mulh, Mulhsu, Mulhu, Div, Divu, Rem, Remu, Mulw, + Divw, Divuw, Remw, Remuw, And, Or, Xor, ShiftLeft, ShiftRight, ShiftArithmeticRight, LessThanSigned, LessThanUnsigned, - GreaterEqualSigned, GreaterEqualUnsigned, Equal = Value + GreaterEqualSigned, GreaterEqualUnsigned, Equal = + Value } class Alu extends Module { @@ -32,6 +36,63 @@ class Alu extends Module { io.out := io.a - io.b; } + is(Mul) { + io.out := (io.a.asSInt * io.b.asSInt).asUInt; + } + + is(Mulh) { + io.out := ((io.a.asSInt * io.b.asSInt) >> 64.U).asUInt; + } + + is(Mulhsu) { + io.out := ((io.a.asSInt * io.b).asSInt >> 64.U).asUInt; + } + + is(Mulhu) { + io.out := (io.a * io.b) >> 64.U; + } + + is(Div) { + io.out := (io.a.asSInt / io.b.asSInt).asUInt; + } + + is(Divu) { + io.out := io.a / io.b; + } + + is(Rem) { + io.out := (io.a.asSInt % io.b.asSInt).asUInt; + } + + is(Remu) { + io.out := io.a % io.b; + } + + is(Mulw) { + val res = (io.a.asSInt * io.b.asSInt).asUInt + io.out := Cat(Fill(32, res(31)), res(31, 0)) + } + + is(Divw) { + val res = (io.a(31, 0).asSInt / io.b(31, 0).asSInt).asUInt; + io.out := Cat(Fill(32, res(31)), res(31, 0)); + } + + is(Divuw) { + val res = io.a(31, 0) / io.b(31, 0); + io.out := Cat(Fill(32, res(31)), res(31, 0)); + } + + is(Remw) { + val res = (io.a(31, 0).asSInt % io.b(31, 0).asSInt).asUInt; + io.out := Cat(Fill(32, res(31)), res(31, 0)); + } + + is(Remuw) { + val res = io.a(31, 0) % io.b(31, 0); + io.out := Cat(Fill(32, res(31)), res(31, 0)); + } + is(And) { io.out := io.a & io.b; } diff --git a/src/main/scala/projet/ControlUnit.scala b/src/main/scala/projet/ControlUnit.scala index 9fc7560..6c27655 100644 --- a/src/main/scala/projet/ControlUnit.scala +++ b/src/main/scala/projet/ControlUnit.scala @@ -78,9 +78,12 @@ object OpCode extends ChiselEnum { // Perfomrs some operation with rs1 and rd2 // and writes back to a register - // add, and, or, xor, sll, srl, sra, slt, stlu + // add, and, or, xor, sll, srl, sra, slt, stlu, mul, mulh, mulhsu, mulhu, div, divu, rem, remu val OpR = "b0110011".U; + // mulw, divw, remw + val OpMw = "b0111011".U; + // Type J val JAL = "b1101111".U @@ -150,6 +153,12 @@ class ControlUnit() extends Module { opR(funct3, funct7, io); } + // OpMw instructions + is(OpCode.OpMw) { + io.reg_file_we := true.B // Write to regfile + opMw(funct3, io); + } + // J instructions is(OpCode.JAL) { io.alu_opcode := AluOpCode.Add // ALU is unused @@ -305,7 +314,7 @@ class ControlUnit() extends Module { val SUB = "b0100000".U } - io.mux_regb_imm := true.B; // OpImm are operations with imm, so send imm to ALU + io.mux_regb_imm := true.B; io.mux_rega_pc := true.B; io.mux_alu_imm := true.B; switch(funct3) { @@ -358,6 +367,12 @@ class ControlUnit() extends Module { } } } + + // Switch to mul extension + val RV32M_FUNCT7 = "b0000001".U + when(funct7 === RV32M_FUNCT7) { + opM(funct3, io); + } } // Implements functions for all instruction of the branch kind @@ -505,4 +520,74 @@ class ControlUnit() extends Module { } } } + // Implements functions for instructions of the M extension of type R + def opM(funct3: UInt, io: CUInterface) = { + // Meaning of Funct3 in the context of an OpM instruction + object Funct3 extends ChiselEnum { + val MUL = "b000".U + val MULH = "b001".U + val MULHSU = "b010".U + val MULHU = "b011".U + val DIV = "b100".U + val DIVU = "b101".U + val REM = "b110".U + val REMU = "b111".U + } + + switch(funct3) { + is(Funct3.MUL) { + io.alu_opcode := AluOpCode.Mul + } + is(Funct3.MULH) { + io.alu_opcode := AluOpCode.Mulh + } + is(Funct3.MULHSU) { + io.alu_opcode := AluOpCode.Mulhsu + } + is(Funct3.MULHU) { + io.alu_opcode := AluOpCode.Mulhu + } + is(Funct3.DIV) { + io.alu_opcode := AluOpCode.Div + } + is(Funct3.DIVU) { + io.alu_opcode := AluOpCode.Divu + } + is(Funct3.REM) { + io.alu_opcode := AluOpCode.Rem + } + is(Funct3.REMU) { + io.alu_opcode := AluOpCode.Remu + } + } + } + // Implements functions for instructions of the M extension with word size + def opMw(funct3: UInt, io: CUInterface) = { + // Meaning of Funct3 in the context of an OpMw instruction + object Funct3 extends ChiselEnum { + val MULW = "b000".U + val DIVW = "b100".U + val DIVUW = "b101".U + val REMW = "b110".U + val REMUW = "b111".U + } + + switch(funct3) { + is(Funct3.MULW) { + io.alu_opcode := AluOpCode.Mulw + } + is(Funct3.DIVW) { + io.alu_opcode := AluOpCode.Divw + } + is(Funct3.DIVUW) { + io.alu_opcode := AluOpCode.Divuw + } + is(Funct3.REMW) { + io.alu_opcode := AluOpCode.Remw + } + is(Funct3.REMUW) { + io.alu_opcode := AluOpCode.Remuw + } + } + } }