From c94d8f1c6c1896fd35e1e5779f69566a9f09bb28 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 28 Feb 2020 17:23:44 +0100 Subject: [PATCH] Fetcher and IBusSimplePlugin flush reworked --- src/main/scala/vexriscv/plugin/Fetcher.scala | 21 +++-- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 88 +++++++++---------- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 8463238..1de5021 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -93,10 +93,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, class FetchArea(pipeline : VexRiscv) extends Area { import pipeline._ import pipeline.config._ - val fetcherflushIt = stages.map(_.arbitration.flushNext).orR + val externalFlush = stages.map(_.arbitration.flushNext).orR def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { - if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else fetcherflushIt + if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else externalFlush } //Arbitrate jump requests into pcLoad @@ -208,7 +208,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val input = Stream(UInt(32 bits)) val output = Stream(UInt(32 bits)) val halt = Bool() - val flush = Bool() }) stages(0).input << fetchPc.output @@ -222,16 +221,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, fetchPc.redo.payload := stages.last.input.payload } - stages.head.flush := False //getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush + val flush = (if(isDrivingDecode(IBUS_RSP)) pipeline.decode.arbitration.isRemoved || decode.arbitration.flushNext && !decode.arbitration.isStuck else externalFlush) || redoFetch for((s,sNext) <- (stages, stages.tail).zipped) { - val discardInputOnFlush = s != stages.head - sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || redoFetch + val sFlushed = if(s != stages.head) flush else False + val sNextFlushed = flush if(s == stages.head && pcRegReusedForSecondStage) { - sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush)) + sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed)) sNext.input.payload := fetchPc.pcReg fetchPc.pcRegPropagate setWhen(sNext.input.ready) } else { - sNext.input << s.output.m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush) + sNext.input << s.output.m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed) } } @@ -294,14 +293,14 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that val injector = new Area { - val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(fetcherflushIt)) + val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(externalFlush)) if (injectorReadyCutGen) { iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe incomingInstruction setWhen (inputBeforeStage.valid) } val decodeInput = (if (injectorStage) { val flushStage = getFlushAt(INJECTOR_M2S) - val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = fetcherflushIt) + val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = externalFlush) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst) iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer incomingInstruction setWhen (decodeInput.valid) @@ -458,7 +457,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } val fetchContext = DynamicContext() fetchContext.hazard := hazard - fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) + fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || externalFlush) object PREDICTION_CONTEXT extends Stageable(DynamicContext()) decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._3 diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 1f59a33..642fcbb 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -156,7 +156,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt) - cache.io.cpu.fetch.isRemoved := fetcherflushIt + cache.io.cpu.fetch.isRemoved := externalFlush } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index ed5cbb4..b8bc978 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -255,7 +255,9 @@ class IBusSimplePlugin( resetVector : BigInt, val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault var mmuBus : MemoryTranslatorBus = null - if(rspHoldValue) assert(busLatencyMin <= 1) +// if(rspHoldValue) assert(busLatencyMin <= 1) + assert(!rspHoldValue, "rspHoldValue not supported yet") + assert(!singleInstructionPipeline) override def setup(pipeline: VexRiscv): Unit = { super.setup(pipeline) @@ -283,9 +285,12 @@ class IBusSimplePlugin( resetVector : BigInt, iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd) //Avoid sending to many iBus cmd - val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) - val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt - pendingCmd := pendingCmdNext + val pending = new Area{ + val inc, dec = Bool() + val value = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) + val next = value + U(inc) - U(dec) + value := next + } val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) @@ -293,29 +298,30 @@ class IBusSimplePlugin( resetVector : BigInt, val cmdFork = if(!secondStagePersistence) new Area { //This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed def stage = cmdForkStage - stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready)) - if(singleInstructionPipeline) { - cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR - assert(injectorStage == false) - assert(iBusRsp.stages.dropWhile(_ != stage).length <= 2) - }else { - cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax - } + val canEmit = stage.output.ready && pending.value =/= pendingMax + stage.halt setWhen(stage.input.valid && (!canEmit || !cmd.ready)) + cmd.valid := stage.input.valid && canEmit + pending.inc := cmd.fire } else new Area{ //This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed def stage = cmdForkStage - val pendingFull = pendingCmd === pendingMax - val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready) + val pendingFull = pending.value === pendingMax + val enterTheMarket = Bool() + val cmdKeep = RegInit(False) setWhen(enterTheMarket) clearWhen(cmd.ready) val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready) - stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) - cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired + enterTheMarket := stage.input.valid && !pendingFull && !cmdFired && !cmdKeep +// stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) //(cmd.isStall) + stage.halt setWhen(pendingFull && !cmdFired && !cmdKeep) + stage.halt setWhen(!cmd.ready && !cmdFired) + cmd.valid := enterTheMarket || cmdKeep + pending.inc := enterTheMarket } val mmu = (mmuBus != null) generate new Area { mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False - mmuBus.end := cmdForkStage.output.fire || fetcherflushIt + mmuBus.end := cmdForkStage.output.fire || externalFlush cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00" @@ -341,43 +347,37 @@ class IBusSimplePlugin( resetVector : BigInt, val rspJoin = new Area { import iBusRsp._ //Manage flush for iBus transactions in flight - val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) - discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt - when(iBusRsp.stages.last.flush) { - if(secondStagePersistence) - discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt - else - discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt) - } - - val rspBufferOutput = Stream(IBusSimpleRsp()) - - val rspBuffer = if(!rspHoldValue) new Area{ + val rspBuffer = new Area { + val output = Stream(IBusSimpleRsp()) val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0)) - c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream - c.io.flush := iBusRsp.stages.last.flush - if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent) - if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready) - rspBufferOutput << c.io.pop - } else new Area{ - val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream - val validReg = RegInit(False) setWhen(rspStream.valid) clearWhen(rspBufferOutput.ready) - rspBufferOutput << rspStream - rspBufferOutput.valid setWhen(validReg) + val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) + discardCounter := discardCounter - (c.io.pop.valid && discardCounter =/= 0).asUInt + when(iBusRsp.flush) { + discardCounter := (if(cmdForkOnSecondStage) pending.next else pending.value - U(pending.dec)) + } + + c.io.push << iBus.rsp.toStream +// if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent) +// if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready) + val flush = discardCounter =/= 0 || iBusRsp.flush + output.valid := c.io.pop.valid && discardCounter === 0 + output.payload := c.io.pop.payload + c.io.pop.ready := output.ready || flush + + pending.dec := c.io.pop.fire // iBus.rsp.valid && flush || c.io.pop.valid && output.ready instead to avoid unecessary dependancies ? } val fetchRsp = FetchRsp() fetchRsp.pc := stages.last.output.payload - fetchRsp.rsp := rspBufferOutput.payload - fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin - + fetchRsp.rsp := rspBuffer.output.payload + fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin val join = Stream(FetchRsp()) val exceptionDetected = False - join.valid := stages.last.output.valid && rspBufferOutput.valid + join.valid := stages.last.output.valid && rspBuffer.output.valid join.payload := fetchRsp stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready - rspBufferOutput.ready := join.fire + rspBuffer.output.ready := join.fire output << join.haltWhen(exceptionDetected) if(memoryTranslatorPortConfig != null){