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 {
|
class FetchArea(pipeline : VexRiscv) extends Area {
|
||||||
import pipeline._
|
import pipeline._
|
||||||
import pipeline.config._
|
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 = {
|
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
|
//Arbitrate jump requests into pcLoad
|
||||||
|
@ -208,7 +208,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
||||||
val input = Stream(UInt(32 bits))
|
val input = Stream(UInt(32 bits))
|
||||||
val output = Stream(UInt(32 bits))
|
val output = Stream(UInt(32 bits))
|
||||||
val halt = Bool()
|
val halt = Bool()
|
||||||
val flush = Bool()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
stages(0).input << fetchPc.output
|
stages(0).input << fetchPc.output
|
||||||
|
@ -222,16 +221,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
||||||
fetchPc.redo.payload := stages.last.input.payload
|
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) {
|
for((s,sNext) <- (stages, stages.tail).zipped) {
|
||||||
val discardInputOnFlush = s != stages.head
|
val sFlushed = if(s != stages.head) flush else False
|
||||||
sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || redoFetch
|
val sNextFlushed = flush
|
||||||
if(s == stages.head && pcRegReusedForSecondStage) {
|
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
|
sNext.input.payload := fetchPc.pcReg
|
||||||
fetchPc.pcRegPropagate setWhen(sNext.input.ready)
|
fetchPc.pcRegPropagate setWhen(sNext.input.ready)
|
||||||
} else {
|
} 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
|
def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that
|
||||||
val injector = new Area {
|
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) {
|
if (injectorReadyCutGen) {
|
||||||
iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe
|
iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe
|
||||||
incomingInstruction setWhen (inputBeforeStage.valid)
|
incomingInstruction setWhen (inputBeforeStage.valid)
|
||||||
}
|
}
|
||||||
val decodeInput = (if (injectorStage) {
|
val decodeInput = (if (injectorStage) {
|
||||||
val flushStage = getFlushAt(INJECTOR_M2S)
|
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)
|
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
|
iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer
|
||||||
incomingInstruction setWhen (decodeInput.valid)
|
incomingInstruction setWhen (decodeInput.valid)
|
||||||
|
@ -458,7 +457,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
||||||
}
|
}
|
||||||
val fetchContext = DynamicContext()
|
val fetchContext = DynamicContext()
|
||||||
fetchContext.hazard := hazard
|
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())
|
object PREDICTION_CONTEXT extends Stageable(DynamicContext())
|
||||||
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._3
|
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)
|
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
|
val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault
|
||||||
var mmuBus : MemoryTranslatorBus = null
|
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 = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
super.setup(pipeline)
|
super.setup(pipeline)
|
||||||
|
@ -283,9 +285,12 @@ class IBusSimplePlugin( resetVector : BigInt,
|
||||||
iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd)
|
iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd)
|
||||||
|
|
||||||
//Avoid sending to many iBus cmd
|
//Avoid sending to many iBus cmd
|
||||||
val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
val pending = new Area{
|
||||||
val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt
|
val inc, dec = Bool()
|
||||||
pendingCmd := pendingCmdNext
|
val value = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||||
|
val next = value + U(inc) - U(dec)
|
||||||
|
value := next
|
||||||
|
}
|
||||||
|
|
||||||
val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe
|
val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe
|
||||||
def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1)
|
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 {
|
val cmdFork = if(!secondStagePersistence) new Area {
|
||||||
//This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed
|
//This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed
|
||||||
def stage = cmdForkStage
|
def stage = cmdForkStage
|
||||||
stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready))
|
val canEmit = stage.output.ready && pending.value =/= pendingMax
|
||||||
if(singleInstructionPipeline) {
|
stage.halt setWhen(stage.input.valid && (!canEmit || !cmd.ready))
|
||||||
cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR
|
cmd.valid := stage.input.valid && canEmit
|
||||||
assert(injectorStage == false)
|
pending.inc := cmd.fire
|
||||||
assert(iBusRsp.stages.dropWhile(_ != stage).length <= 2)
|
|
||||||
}else {
|
|
||||||
cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
|
|
||||||
}
|
|
||||||
} else new Area{
|
} else new Area{
|
||||||
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
|
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
|
||||||
def stage = cmdForkStage
|
def stage = cmdForkStage
|
||||||
val pendingFull = pendingCmd === pendingMax
|
val pendingFull = pending.value === pendingMax
|
||||||
val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready)
|
val enterTheMarket = Bool()
|
||||||
|
val cmdKeep = RegInit(False) setWhen(enterTheMarket) clearWhen(cmd.ready)
|
||||||
val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready)
|
val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready)
|
||||||
stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired))
|
enterTheMarket := stage.input.valid && !pendingFull && !cmdFired && !cmdKeep
|
||||||
cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired
|
// 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 {
|
val mmu = (mmuBus != null) generate new Area {
|
||||||
mmuBus.cmd.isValid := cmdForkStage.input.valid
|
mmuBus.cmd.isValid := cmdForkStage.input.valid
|
||||||
mmuBus.cmd.virtualAddress := cmdForkStage.input.payload
|
mmuBus.cmd.virtualAddress := cmdForkStage.input.payload
|
||||||
mmuBus.cmd.bypassTranslation := False
|
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"
|
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00"
|
||||||
|
|
||||||
|
@ -341,43 +347,37 @@ class IBusSimplePlugin( resetVector : BigInt,
|
||||||
val rspJoin = new Area {
|
val rspJoin = new Area {
|
||||||
import iBusRsp._
|
import iBusRsp._
|
||||||
//Manage flush for iBus transactions in flight
|
//Manage flush for iBus transactions in flight
|
||||||
|
val rspBuffer = new Area {
|
||||||
|
val output = Stream(IBusSimpleRsp())
|
||||||
|
val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0))
|
||||||
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||||
discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt
|
discardCounter := discardCounter - (c.io.pop.valid && discardCounter =/= 0).asUInt
|
||||||
when(iBusRsp.stages.last.flush) {
|
when(iBusRsp.flush) {
|
||||||
if(secondStagePersistence)
|
discardCounter := (if(cmdForkOnSecondStage) pending.next else pending.value - U(pending.dec))
|
||||||
discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt
|
|
||||||
else
|
|
||||||
discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val rspBufferOutput = Stream(IBusSimpleRsp())
|
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
|
||||||
|
|
||||||
val rspBuffer = if(!rspHoldValue) new Area{
|
pending.dec := c.io.pop.fire // iBus.rsp.valid && flush || c.io.pop.valid && output.ready instead to avoid unecessary dependancies ?
|
||||||
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 fetchRsp = FetchRsp()
|
val fetchRsp = FetchRsp()
|
||||||
fetchRsp.pc := stages.last.output.payload
|
fetchRsp.pc := stages.last.output.payload
|
||||||
fetchRsp.rsp := rspBufferOutput.payload
|
fetchRsp.rsp := rspBuffer.output.payload
|
||||||
fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin
|
fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin
|
||||||
|
|
||||||
|
|
||||||
val join = Stream(FetchRsp())
|
val join = Stream(FetchRsp())
|
||||||
val exceptionDetected = False
|
val exceptionDetected = False
|
||||||
join.valid := stages.last.output.valid && rspBufferOutput.valid
|
join.valid := stages.last.output.valid && rspBuffer.output.valid
|
||||||
join.payload := fetchRsp
|
join.payload := fetchRsp
|
||||||
stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready
|
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)
|
output << join.haltWhen(exceptionDetected)
|
||||||
|
|
||||||
if(memoryTranslatorPortConfig != null){
|
if(memoryTranslatorPortConfig != null){
|
||||||
|
|
Loading…
Reference in New Issue