diff --git a/bench/tests/op/jal.s b/bench/tests/op/jal.s new file mode 100644 index 0000000..d25278a --- /dev/null +++ b/bench/tests/op/jal.s @@ -0,0 +1,12 @@ +# expected: 00000004, 0000008, 0000000C + .text +_start: + jal x31, step1 +step1: + jal x31, step2 +step2: + jal x31, step3 +step3: + nop + + diff --git a/build.sc b/build.sc index 84d50fe..ac748dc 100644 --- a/build.sc +++ b/build.sc @@ -14,28 +14,28 @@ import mill.bsp._ // See: https://github.com/com-lihaoyi/mill/issues/3840 object `TPchisel` extends SbtModule { m => - override def millSourcePath = super.millSourcePath / os.up - override def scalaVersion = "2.13.16" - override def scalacOptions = Seq( - "-language:reflectiveCalls", - "-deprecation", - "-feature", - "-Xcheckinit", - "-Ymacro-annotations", - "-unchecked", - "-Xfatal-warnings", - "-Ywarn-dead-code", - "-Ywarn-unused" - ) - override def ivyDeps = Agg( - ivy"org.chipsalliance::chisel:7.2.0", - ) - override def scalacPluginIvyDeps = Agg( - ivy"org.chipsalliance:::chisel-plugin:7.2.0", - ) - object test extends SbtTests with TestModule.ScalaTest { - override def ivyDeps = m.ivyDeps() ++ Agg( - ivy"org.scalatest::scalatest::3.2.19" + override def millSourcePath = super.millSourcePath / os.up + override def scalaVersion = "2.13.16" + override def scalacOptions = Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + "-Ymacro-annotations", + "-unchecked", + "-Xfatal-warnings", + "-Ywarn-dead-code", + "-Ywarn-unused" ) - } + override def ivyDeps = Agg( + ivy"org.chipsalliance::chisel:7.2.0" + ) + override def scalacPluginIvyDeps = Agg( + ivy"org.chipsalliance:::chisel-plugin:7.2.0" + ) + object test extends SbtTests with TestModule.ScalaTest { + override def ivyDeps = m.ivyDeps() ++ Agg( + ivy"org.scalatest::scalatest::3.2.19" + ) + } } diff --git a/src/main/scala/projet/ControlUnit.scala b/src/main/scala/projet/ControlUnit.scala index b573d86..6ccf36b 100644 --- a/src/main/scala/projet/ControlUnit.scala +++ b/src/main/scala/projet/ControlUnit.scala @@ -10,16 +10,21 @@ class CUInterface extends Bundle { val alu_opcode = Output(AluOpCode()) val optype = Output(OpType()) + // True if the decoded instruction is a jump + val is_jump = Output(Bool()) + // Muxers // The naming convention is as follows : mux_xxx_yyy. // If the signal is hot, xxx is selected otherwise yyy is selected val mux_alu_imm = Output(Bool()) val mux_rega_pc = Output(Bool()) val mux_regb_imm = Output(Bool()) + val mux_incrpc4_imm = Output(Bool()) + val mux_regpc_executepc = Output(Bool()) } object OpType extends ChiselEnum { - val U, I, IR = Value + val U, I, IR, J = Value } object OpCode extends ChiselEnum { @@ -46,6 +51,8 @@ object OpCode extends ChiselEnum { // add, and, or, xor, sll, srl, sra, slt, stlu val OpR = 0b0110011.U; + // Type J + val JAL = 0b1101111.U } @@ -55,9 +62,12 @@ class ControlUnit() extends Module { io.reg_file_we := false.B io.alu_opcode := AluOpCode.Add io.optype := OpType.U + io.is_jump := false.B; io.mux_alu_imm := true.B; io.mux_rega_pc := true.B; io.mux_regb_imm := true.B; + io.mux_incrpc4_imm := true.B; + io.mux_regpc_executepc := true.B; // Decode instruction val opcode = io.instruction(6, 0); @@ -76,21 +86,33 @@ class ControlUnit() extends Module { io.alu_opcode := AluOpCode.Add io.reg_file_we := true.B // Write to regfile io.mux_rega_pc := false.B // Send PC to ALU A - io.mux_alu_imm := false.B; // Send immu to ALU B + io.mux_regb_imm := false.B; // Send immu to ALU B io.optype := OpType.U } // OpImm instructions is(OpCode.OpImm) { - io.reg_file_we := true.B + io.reg_file_we := true.B // Write to regfile opImm(funct3, funct7, io); } // OpR instructions is(OpCode.OpR) { - io.reg_file_we := true.B + io.reg_file_we := true.B // Write to regfile opR(funct3, funct7, io); } + + // J instructions + is(OpCode.JAL) { + io.alu_opcode := AluOpCode.Add + io.reg_file_we := true.B // Write to regfile + io.mux_rega_pc := false.B // Send PC to ALU A + io.mux_regb_imm := false.B; // Send imm to ALU B + io.is_jump := true.B + io.mux_incrpc4_imm := false.B; // Send the immediate in PC + io.mux_regpc_executepc := false.B; // Add the immediate to the previous PC + io.optype := OpType.J + } } diff --git a/src/main/scala/projet/ImmediateDecoder.scala b/src/main/scala/projet/ImmediateDecoder.scala index 8affac9..132690b 100644 --- a/src/main/scala/projet/ImmediateDecoder.scala +++ b/src/main/scala/projet/ImmediateDecoder.scala @@ -20,6 +20,14 @@ class ImmediateDecoder extends Module { val imm_u = Cat(io.instruction(31, 12), 0.U(12.W)); val imm_i = Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)); val imm_ir = io.instruction(24, 20); + val imm_j = Cat( + Fill(11, io.instruction(31)), + io.instruction(31), + io.instruction(19, 12), + io.instruction(20), + io.instruction(30, 21), + 0.U + ); switch(io.op_type) { is(OpType.U) { @@ -31,5 +39,8 @@ class ImmediateDecoder extends Module { is(OpType.IR) { io.immediate := imm_ir } + is(OpType.J) { + io.immediate := imm_j + } } } diff --git a/src/main/scala/projet/Rv32i.scala b/src/main/scala/projet/Rv32i.scala index 1dcf7f6..7c0be1f 100644 --- a/src/main/scala/projet/Rv32i.scala +++ b/src/main/scala/projet/Rv32i.scala @@ -12,32 +12,38 @@ class Rv32i(sim: Boolean = true) extends Module { val reg_pc = RegInit(0.U(32.W)); val reg_file = Module(new RegFile(sim)); - val instruction = io.ibus.rdata; reg_file.io.rd_data := 0.U; io.x31 := reg_file.io.x31 if (sim) { - io.valid_x31.get := reg_file.io.valid_x31.get && Delay.Delay( - !reset.asBool, - 1, - false.B - ) + io.valid_x31.get := reg_file.io.valid_x31.get } val alu = Module(new Alu()); val immediate_decoder = Module(new ImmediateDecoder()); val control_unit = Module(new ControlUnit()); + // 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 + val is_jump = Delay.Delay(control_unit.io.is_jump, 1, false.B); + val instruction = Mux(is_jump, 0b00000000000000000000000000010011.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 // Increment PC each clock - reg_pc := reg_pc + 4.U; - - // PC delayed to execute stage for auipc op - val execute_pc = Delay.Delay(reg_pc, 1, 0.U); + reg_pc := Mux( + control_unit.io.mux_regpc_executepc, + reg_pc, + execute_pc + ) + Mux( + control_unit.io.mux_incrpc4_imm, + 4.U, + immediate_decoder.io.immediate + ); // Fetch instruction io.ibus.en := true.B; diff --git a/src/main/scala/projet/ZzTop.scala b/src/main/scala/projet/ZzTop.scala index ff946ea..14a8d38 100644 --- a/src/main/scala/projet/ZzTop.scala +++ b/src/main/scala/projet/ZzTop.scala @@ -24,7 +24,7 @@ class ZzTop(file: String = "", sim: Boolean = true) extends Module { // clock et reset sont les signaux implicites clkg.io.clk_in1 := clock clkg.io.reset := reset - val rst = (reset.asBool || !clkg.io.locked).asAsyncReset + val rst = reset.asBool || !clkg.io.locked // Ces deux IPs doivent tourner à 125 MHz val vmem = Module(new IDMem(sim, 17)) @@ -34,7 +34,7 @@ class ZzTop(file: String = "", sim: Boolean = true) extends Module { vgad.io.clk := clkg.io.clk_out2 // Clock pixel // Expose core for testing usage - val core = withClockAndReset(clkg.io.clk_out1, rst) { + withClockAndReset(clkg.io.clk_out1, rst) { val interconnect = Module(new BusInterconnect) val core = Module(new Rv32i(sim)) val dmem = Module(new IDMem(sim, 16, file)) @@ -70,7 +70,5 @@ class ZzTop(file: String = "", sim: Boolean = true) extends Module { io.r := vgad.io.r io.g := vgad.io.g io.b := vgad.io.b - - core } }