Fetcher and IBusSimplePlugin flush reworked
This commit is contained in:
parent
492310e6fa
commit
c94d8f1c6c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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){
|
||||
|
|
Loading…
Reference in New Issue