diff --git a/src/main/scala/Barriers.scala b/src/main/scala/Barriers.scala index d2ebc56..ec99bc1 100644 --- a/src/main/scala/Barriers.scala +++ b/src/main/scala/Barriers.scala @@ -4,42 +4,60 @@ import chisel3._ import chisel3.experimental.MultiIOModule -object BarrierReg { - def apply[T <: Data](in: T)(implicit freeze: Bool): Data = { - val reg = RegNext(in) - val old = RegNext(reg) +class Barrier[B <: Bundle](b: B) extends MultiIOModule { + implicit val freeze = IO(Input(Bool())) + implicit val clear = IO(Input(Bool())) + val in = IO(Input(b)) + val out = IO(Output(b)) + + def default() { + out := barrier(in) + } - when (freeze) { - reg := old + def barrier[T <: Data](in: T, delay: Boolean = true): Data = { + val clearVal = in match { + case i: Instruction => Instruction.NOP + case _ => 0.U.asTypeOf(in) } - reg - } -} + val t = chiselTypeOf(in) + val data = WireInit(t, Mux(clear, clearVal, in)) + val out = Wire(t) + val reg = RegNext(data) -class Barrier[B <: Bundle](b: B) extends MultiIOModule { - implicit val freeze = IO(Input(Bool())) - val in = IO(Input(b)) - val out = IO(Output(b)) + if (delay) { + when (freeze) { + reg := reg + } - out := BarrierReg(in) + out := reg + } else { + out := Mux(RegNext(freeze), reg, data) + } + + out + } } class IFBundle extends Bundle { - val PC = UInt() + val PC = UInt(32.W) + val next = UInt(32.W) val instruction = new Instruction } class IFBarrier extends Barrier(new IFBundle) { - out.instruction := in.instruction - out.PC := BarrierReg(in.PC) + out.instruction := barrier(in.instruction, false) + out.PC := barrier(in.PC) + out.next := Mux(freeze, RegNext(in.next), in.next) } -class IDBundle extends IFBundle { +class IDBundle extends Bundle { + val PC = UInt(32.W) + val instruction = new Instruction val controlSignals = new ControlSignals val branchType = UInt(3.W) val reg1 = UInt(32.W) @@ -49,10 +67,12 @@ class IDBundle extends IFBundle { } -class IDBarrier extends Barrier(new IDBundle) {} +class IDBarrier extends Barrier(new IDBundle) { default() } -class EXBundle extends IFBundle { +class EXBundle extends Bundle { + val PC = UInt(32.W) + val instruction = new Instruction val controlSignals = new ControlSignals val reg2 = UInt(32.W) val result = UInt(32.W) @@ -60,20 +80,31 @@ class EXBundle extends IFBundle { } -class EXBarrier extends Barrier(new EXBundle) {} +class EXBarrier extends Barrier(new EXBundle) { default() } -class MEMBundle extends IFBundle { +class MEMBundle extends Bundle { + val PC = UInt(32.W) + val instruction = new Instruction val controlSignals = new ControlSignals - val result = UInt(32.W) - val dataOut = UInt(32.W) + val result = UInt(32.W) + val dataOut = UInt(32.W) } class MEMBarrier extends Barrier(new MEMBundle) { - out.PC := BarrierReg(in.PC) - out.instruction := BarrierReg(in.instruction) - out.controlSignals := BarrierReg(in.controlSignals) - out.result := BarrierReg(in.result) - out.dataOut := in.dataOut + out.PC := barrier(in.PC) + out.instruction := barrier(in.instruction) + out.controlSignals := barrier(in.controlSignals) + out.result := barrier(in.result) + out.dataOut := barrier(in.dataOut, false) } + +class WBBundle extends Bundle { + val PC = UInt(32.W) + val instruction = new Instruction + val controlSignals = new ControlSignals + val writeback = UInt(32.W) +} + +class WBBarrier extends Barrier(new WBBundle) { default() } diff --git a/src/main/scala/CPU.scala b/src/main/scala/CPU.scala index 3153281..113b1d5 100644 --- a/src/main/scala/CPU.scala +++ b/src/main/scala/CPU.scala @@ -26,6 +26,7 @@ class CPU extends MultiIOModule { val IDBarrier = Module(new IDBarrier) val EXBarrier = Module(new EXBarrier) val MEMBarrier = Module(new MEMBarrier) + val WBBarrier = Module(new WBBarrier) val ID = Module(new InstructionDecode) val IF = Module(new InstructionFetch) @@ -62,9 +63,22 @@ class CPU extends MultiIOModule { IDBarrier.freeze := freeze EXBarrier.freeze := freeze MEMBarrier.freeze := freeze + WBBarrier.freeze := freeze + + val clear = Wire(Bool()) + clear := false.B + IFBarrier.clear := clear + IDBarrier.clear := clear + EXBarrier.clear := clear + MEMBarrier.clear := clear + WBBarrier.clear := clear + + // The value that is written back to the register + val writeback = Wire(UInt(32.W)) // Stage 1 IFBarrier.in := IF.io + IF.io.addr := IFBarrier.out.next // Stage 2 ID.io.instruction := IFBarrier.out.instruction @@ -82,17 +96,61 @@ class CPU extends MultiIOModule { val exToRs2 = IDBarrier.out.instruction.registerRs2 === EXBarrier.out.instruction.registerRd val memToRs1 = IDBarrier.out.instruction.registerRs1 === MEMBarrier.out.instruction.registerRd val memToRs2 = IDBarrier.out.instruction.registerRs2 === MEMBarrier.out.instruction.registerRd - val ldToRs1 = exToRs1 && EXBarrier.out.controlSignals.memRead - val ldToRs2 = exToRs2 && EXBarrier.out.controlSignals.memRead + val wbToRs1 = IDBarrier.out.instruction.registerRs1 === WBBarrier.out.instruction.registerRd + val wbToRs2 = IDBarrier.out.instruction.registerRs2 === WBBarrier.out.instruction.registerRd + val ldToRs1 = exToRs1 && EXBarrier.out.controlSignals.memToReg + val ldToRs2 = exToRs2 && EXBarrier.out.controlSignals.memToReg + + //printf(p"0x${Hexadecimal(IF.io.PC)}: EX in: ${IDBarrier.out.instruction.registerRs1}, MEM out: ${MEMBarrier.out.instruction.registerRd}\n") when ((ldToRs1 || ldToRs2) && state =/= LOAD_FREEZE) { + //printf(p"0x${Hexadecimal(IF.io.PC)}: Load freeze\n") + // Freeze all barriers (repeating the instruction) until the value is loaded from memory freeze := true.B + + // The MEM and WB carry out their instructions, but MEM is cleared so it doesn't repeat + // the instruction. This carries through to WB next cycle. MEMBarrier.freeze := false.B + WBBarrier.freeze := false.B + EXBarrier.freeze := false.B + EXBarrier.clear := true.B state := LOAD_FREEZE } - val rs1 = Mux(exToRs1, EXBarrier.out.result, Mux(memToRs1, MEMBarrier.out.result, IDBarrier.out.reg1)) - val rs2 = Mux(exToRs2, EXBarrier.out.result, Mux(memToRs2, MEMBarrier.out.result, IDBarrier.out.reg2)) + //printf(p"0x${Hexadecimal(IF.io.PC)}: freeze: $freeze, exR1: ${IDBarrier.out.instruction.registerRs1}, rd: ${IF.io.instruction.registerRd}, IF: ${IFBarrier.out.instruction.opcode}, ID: ${IDBarrier.out.instruction.opcode}, EX: ${EXBarrier.out.instruction.opcode}, MEM: ${MEMBarrier.out.instruction.opcode}, WB: ${WBBarrier.out.instruction.opcode}\n") + + //printf(p"0x${Hexadecimal(IF.io.PC)}: next: 0x${Hexadecimal(IFBarrier.out.next)}, IF: 0x${Hexadecimal(IFBarrier.out.PC)}, ID: 0x${Hexadecimal(IDBarrier.out.PC)}, EX: 0x${Hexadecimal(EXBarrier.out.PC)}, MEM: 0x${Hexadecimal(MEMBarrier.out.PC)}, WB: 0x${Hexadecimal(WBBarrier.out.PC)}, freeze: $freeze\n") + + val rs1 = Wire(UInt(32.W)) + when (ldToRs1) { + rs1 := MEMBarrier.out.dataOut + }.elsewhen (exToRs1) { + rs1 := EXBarrier.out.result + }.elsewhen (memToRs1) { + rs1 := writeback + }.elsewhen (wbToRs1) { + rs1 := WBBarrier.out.writeback + }.otherwise { + rs1 := IDBarrier.out.reg1 + } + + val rs2 = Wire(UInt(32.W)) + when (ldToRs2) { + rs2 := MEMBarrier.out.dataOut + }.elsewhen (exToRs2) { + rs2 := EXBarrier.out.result + }.elsewhen (memToRs2) { + rs2 := writeback + }.elsewhen (wbToRs2) { + rs2 := WBBarrier.out.writeback + }.otherwise { + rs2 := IDBarrier.out.reg2 + } + + //printf(p"0x${Hexadecimal(IF.io.PC)}: Reg write: ${MEMBarrier.out.controlSignals.regWrite}, ExToR1: $exToRs1, MEMToR1: $memToRs1, wbToR1: $wbToRs1, R1: $rs1, EX: ${EXBarrier.out.result}, MEM: ${MEMBarrier.out.dataOut}, WB: ${WBBarrier.out.writeback}}\n") + + //printf(p"0x${Hexadecimal(IF.io.PC)}: Next: 0x${Hexadecimal(IFBarrier.out.next)}, freeze: $freeze, IF: ${IFBarrier.out.instruction}, ID: ${IDBarrier.out.instruction}, EX: ${EXBarrier.out.instruction}, MEM: ${MEMBarrier.out.instruction}\n") + EX.io.PC := IDBarrier.out.PC EX.io.controlSignals := IDBarrier.out.controlSignals @@ -114,8 +172,9 @@ class CPU extends MultiIOModule { MEM.io.writeEnable := EXBarrier.out.controlSignals.memWrite MEM.io.dataAddress := EXBarrier.out.result - IF.io.jumpEnable := EXBarrier.out.branch - IF.io.jumpAddr := EXBarrier.out.result + when (EXBarrier.out.branch) { + //IF.io.addr := EXBarrier.out.result + } MEMBarrier.in.PC := EXBarrier.out.PC MEMBarrier.in.instruction := EXBarrier.out.instruction @@ -124,15 +183,28 @@ class CPU extends MultiIOModule { MEMBarrier.in.dataOut := MEM.io.dataOut // Stage 5 - ID.io.writeEnable := MEMBarrier.out.controlSignals.regWrite - ID.io.writeAddr := MEMBarrier.out.instruction.registerRd - ID.io.writeData := MEMBarrier.out.result + when (freeze) { + ID.io.writeEnable := false.B + ID.io.writeAddr := 0.U + ID.io.writeData := 0.U + }.otherwise { + ID.io.writeEnable := MEMBarrier.out.controlSignals.regWrite + ID.io.writeAddr := MEMBarrier.out.instruction.registerRd + ID.io.writeData := writeback + } + + WBBarrier.in.PC := MEMBarrier.out.PC + WBBarrier.in.instruction := MEMBarrier.out.instruction + WBBarrier.in.controlSignals := MEMBarrier.out.controlSignals + WBBarrier.in.writeback := writeback + + writeback := MEMBarrier.out.result when (MEMBarrier.out.controlSignals.memToReg) { - ID.io.writeData := MEMBarrier.out.dataOut + writeback := MEMBarrier.out.dataOut } when (MEMBarrier.out.controlSignals.jump) { - ID.io.writeData := MEMBarrier.out.PC + 4.U + writeback := MEMBarrier.out.PC + 4.U } } diff --git a/src/main/scala/IF.scala b/src/main/scala/IF.scala index da8d6e7..dec0ded 100644 --- a/src/main/scala/IF.scala +++ b/src/main/scala/IF.scala @@ -17,9 +17,9 @@ class InstructionFetch extends MultiIOModule { new Bundle { val PC = Output(UInt()) val instruction = Output(new Instruction) + val next = Output(UInt(32.W)) - val jumpEnable = Input(Bool()) - val jumpAddr = Input(UInt(32.W)) + val addr = Input(UInt(32.W)) }) val IMEM = Module(new IMEM) @@ -33,16 +33,12 @@ class InstructionFetch extends MultiIOModule { testHarness.PC := IMEM.testHarness.requestedAddress - val addr = Mux(io.jumpEnable, io.jumpAddr, PC + 4.U) - when (io.jumpEnable) { - //printf(p"Jump to ${Hexadecimal(addr)}\n") - } - IMEM.io.instructionAddress := PC - PC := addr + PC := io.addr io.PC := PC + io.next := PC + 4.U io.instruction := IMEM.io.instruction.asTypeOf(new Instruction) diff --git a/src/test/resources/tests/basic/load.s b/src/test/resources/tests/basic/load.s index c4cb55d..541d053 100644 --- a/src/test/resources/tests/basic/load.s +++ b/src/test/resources/tests/basic/load.s @@ -1,8 +1,8 @@ main: addi x1, zero, 4 addi x2, zero, 4 - addi x3, zero, 4 - addi x4, zero, 4 + addi x3, zero, 4 + addi x4, zero, 4 lw x3, 0(x3) nop nop diff --git a/src/test/scala/chiselTestRunner.scala b/src/test/scala/chiselTestRunner.scala index cdd83a8..786c736 100644 --- a/src/test/scala/chiselTestRunner.scala +++ b/src/test/scala/chiselTestRunner.scala @@ -142,7 +142,7 @@ private class ChiselTestRunner ( // After finishing, let the circuit run until all updates can be committed. private def flush: List[CircuitTrace] = - (0 to 3).map(_ => stepOne).reverse.toList + (0 to 5).map(_ => stepOne).reverse.toList /** * Run the entire shebang