diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 450b745..dddbf8c 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -95,19 +95,13 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ } -//Allow to avoid instruction cache plugin to be confused by new instruction poping in the pipeline -trait InstructionInjector{ - def isInjecting(stage : Stage) : Bool -} -class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] with InstructionInjector { +class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { var io : DebugExtensionIo = null val injectionAsks = ArrayBuffer[(Stage, Bool)]() - var isInjectingOnDecode : Bool = null var injectionPort : Stream[Bits] = null - override def isInjecting(stage: Stage) : Bool = if(stage == pipeline.decode) isInjectingOnDecode else False object IS_EBREAK extends Stageable(Bool) override def setup(pipeline: VexRiscv): Unit = { @@ -127,7 +121,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg )) - isInjectingOnDecode = Bool() injectionPort = pipeline.service(classOf[IBusFetcher]).getInjectionPort() } @@ -138,7 +131,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w val logic = debugClockDomain {pipeline plug new Area{ val iBusFetcher = service(classOf[IBusFetcher]) - val insertDecodeInstruction = False val firstCycle = RegNext(False) setWhen (io.bus.cmd.ready) val secondCycle = RegNext(firstCycle) val resetIt = RegInit(False) @@ -164,6 +156,9 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w io.bus.rsp.data(4) := stepIt } + injectionPort.valid := False + injectionPort.payload := io.bus.cmd.data + when(io.bus.cmd.valid) { switch(io.bus.cmd.address(2 downto 2)) { is(0) { @@ -176,18 +171,14 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w } is(1) { when(io.bus.cmd.wr) { - insertDecodeInstruction := True -// decode.arbitration.isValid.getDrivingReg setWhen (firstCycle) -// decode.arbitration.haltItself setWhen (secondCycle) -// io.bus.cmd.ready := !firstCycle && !secondCycle && execute.arbitration.isValid - io.bus.cmd.ready := injectionPort.fire + injectionPort.valid := True + io.bus.cmd.ready := injectionPort.ready } } } } - injectionPort.valid := RegNext(insertDecodeInstruction) init(False) clearWhen(injectionPort.fire) - injectionPort.payload := RegNext(io.bus.cmd.data) + // Component.current.addPrePopTask(() => { @@ -232,9 +223,17 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w haltIt := True } } + when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) { haltIt := False } + + //Avoid having two C instruction executed in a single step + if(pipeline(RVC_GEN)){ + val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) + decode.arbitration.removeIt setWhen(cleanStep) + } + io.resetOut := RegNext(resetIt) if(serviceExist(classOf[InterruptionInhibitor])) { @@ -248,8 +247,5 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w } } }} - - - isInjectingOnDecode := RegNext(logic.insertDecodeInstruction) init(False) } } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 1b91a62..4e4781e 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -171,7 +171,8 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, pcReg + 4 if (keepPcPlus4) KeepAttribute(pcPlus) - when(decode.arbitration.isFiring) { + val injectedDecode = False + when(decode.arbitration.isFiring && !injectedDecode) { pcReg := pcPlus } @@ -250,31 +251,31 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3) }) - //TODO never colalpse buble of the last stage + def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that val injector = new Area { - val inputBeforeHalt = condApply(if(decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush)) - if(injectorReadyCutGen) { + val inputBeforeHalt = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush)) + if (injectorReadyCutGen) { iBusRsp.readyForError.clearWhen(inputBeforeHalt.valid) - incomingInstruction setWhen(inputBeforeHalt.valid) + incomingInstruction setWhen (inputBeforeHalt.valid) } - val decodeInput = (if(injectorStage){ + val decodeInput = (if (injectorStage) { val decodeInput = inputBeforeHalt.m2sPipeWithFlush(killLastStage, collapsBubble = false) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeHalt.rsp.inst) iBusRsp.readyForError.clearWhen(decodeInput.valid) - incomingInstruction setWhen(decodeInput.valid) + incomingInstruction setWhen (decodeInput.valid) decodeInput } else { inputBeforeHalt }) - if(decodePcGen){ + if (decodePcGen) { decodeNextPcValid := True decodeNextPc := decodePc.pcReg - }else { - val lastStageStream = if(injectorStage) inputBeforeHalt - else if(rspStageGen) iBusRsp.outputBeforeStage - else if(cmdToRspStageCount > 1)iBusRsp.inputPipeline(cmdToRspStageCount-2) + } else { + val lastStageStream = if (injectorStage) inputBeforeHalt + else if (rspStageGen) iBusRsp.outputBeforeStage + else if (cmdToRspStageCount > 1) iBusRsp.inputPipeline(cmdToRspStageCount - 2) else throw new Exception("Fetch should at least have two stages") // when(fetcherHalt){ @@ -287,25 +288,72 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, decodeInput.ready := !decode.arbitration.isStuck decode.arbitration.isValid := decodeInput.valid - decode.insert(PC) := (if(decodePcGen) decodePc.pcReg else decodeInput.pc) + decode.insert(PC) := (if (decodePcGen) decodePc.pcReg else decodeInput.pc) decode.insert(INSTRUCTION) := decodeInput.rsp.inst decode.insert(INSTRUCTION_READY) := True - if(compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc + if (compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc -// if(catchAccessFault){ -// decodeExceptionPort.valid := decode.arbitration.isValid && decodeInput.rsp.error -// decodeExceptionPort.code := 1 -// decodeExceptionPort.badAddr := decode.input(PC) -// } + // if(catchAccessFault){ + // decodeExceptionPort.valid := decode.arbitration.isValid && decodeInput.rsp.error + // decodeExceptionPort.code := 1 + // decodeExceptionPort.badAddr := decode.input(PC) + // } - if(injectionPort != null){ - val state = RegNext(injectionPort.valid) init(False) clearWhen(injectionPort.ready) - injectionPort.ready := !decode.arbitration.isStuck && state - when(injectionPort.valid) { - decode.arbitration.isValid := True - decode.arbitration.haltItself setWhen(!state) - decode.insert(INSTRUCTION) := injectionPort.payload - } + if (injectionPort != null) { + Component.current.addPrePopTask(() => { + val state = RegInit(U"000") + + injectionPort.ready := False + if(decodePcGen){ + decodePc.injectedDecode setWhen(state =/= 0) + } + switch(state) { + is(0) { //request pipelining + when(injectionPort.valid) { + state := 1 + } + } + is(1) { //Give time to propagate the payload + state := 2 + } + is(2){ //read regfile delay + decode.arbitration.isValid := True + decode.arbitration.haltItself := True + state := 3 + } + is(3){ //Do instruction + decode.arbitration.isValid := True + when(!decode.arbitration.isStuck) { + state := 4 + } + } + is(4){ //request pipelining + injectionPort.ready := True + state := 0 + } + } + + //Check if the decode instruction is driven by a register + val instructionDriver = try { + decode.input(INSTRUCTION).getDrivingReg + } catch { + case _: Throwable => null + } + if (instructionDriver != null) { //If yes => + //Insert the instruction by writing the "fetch to decode instruction register", + // Work even if it need to cross some hierarchy (caches) + instructionDriver.component.rework { + when(state.pull() =/= 0) { + instructionDriver := injectionPort.payload.pull() + } + } + } else { + //Insert the instruction via a mux in the decode stage + when(state =/= 0) { + decode.input(INSTRUCTION) := RegNext(injectionPort.payload) + } + } + }) } } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index d149bf7..8612c25 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -109,8 +109,8 @@ class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean, catchAccessFault = catchAccessFault, resetVector = BigInt(0x80000000l), keepPcPlus4 = false, - decodePcGen = false, - compressedGen = false, + decodePcGen = true, + compressedGen = true, cmdToRspStageCount = 1, rspStageGen = false, injectorReadyCutGen = false, diff --git a/src/test/python/tool/.gitignore b/src/test/python/tool/.gitignore new file mode 100644 index 0000000..f5d70ab --- /dev/null +++ b/src/test/python/tool/.gitignore @@ -0,0 +1 @@ +/disasm.s diff --git a/src/test/python/tool/disasm.s b/src/test/python/tool/disasm.s index 4e1f43f..70a1827 100644 --- a/src/test/python/tool/disasm.s +++ b/src/test/python/tool/disasm.s @@ -1 +1 @@ -.word 0x8067 +.word 0x812e23