rework fetcher

This commit is contained in:
Dolu1990 2018-09-23 22:05:53 +02:00
parent 56fd73fbbc
commit 86efb75f6a
4 changed files with 104 additions and 142 deletions

View File

@ -18,7 +18,6 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val compressedGen : Boolean,
val cmdToRspStageCount : Int,
val injectorReadyCutGen : Boolean,
val relaxedPcCalculation : Boolean,
val prediction : BranchPrediction,
val historyRamSizeLog2 : Int,
val injectorStage : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
@ -111,39 +110,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits)))
}
val fetchPc = if(relaxedPcCalculation) new PcFetch {
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val pcPlus4 = pcReg + 4
if (keepPcPlus4) KeepAttribute(pcPlus4)
when(preOutput.fire) {
pcReg := pcPlus4
}
//Realign
if(compressedGen){
when(preOutput.fire){
pcReg(1 downto 0) := 0
}
}
preOutput.valid := RegNext(True) init (False) // && !jump.pcLoad.valid
preOutput.payload := pcReg
//application of the selected jump request
if(predictionPcLoad != null) {
when(predictionPcLoad.valid) {
pcReg := predictionPcLoad.payload
preOutput.valid := False
}
}
when(jump.pcLoad.valid) {
pcReg := jump.pcLoad.payload
}
} else new PcFetch{
val fetchPc = new PcFetch{
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val inc = RegInit(False)
@ -216,14 +183,6 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
})
// val iBusCmd = new Area {
// def input = fetchPc.output
//
// // ...
//
// val output = Stream(UInt(32 bits))
// }
case class FetchRsp() extends Bundle {
val pc = UInt(32 bits)
val rsp = IBusSimpleRsp()
@ -232,22 +191,51 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val iBusRsp = new Area {
val input = Stream(UInt(32 bits))
val inputPipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount)
val inputPipelineHalt = Vec(False, cmdToRspStageCount-1)
for(i <- 0 until cmdToRspStageCount) {
// val doFlush = if(i == cmdToRspStageCount- 1 && ???) killLastStage else flush
inputPipeline(i) << {i match {
case 0 => input.m2sPipeWithFlush(flush, relaxedPcCalculation, collapsBubble = false)
case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
}}
// val input = Stream(UInt(32 bits))
// val inputPipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount)
// val inputPipelineHalt = Vec(False, cmdToRspStageCount-1)
// for(i <- 0 until cmdToRspStageCount) {
// inputPipeline(i) << {i match {
// case 0 => input.m2sPipeWithFlush(flush, false, collapsBubble = false)
// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
// }}
// }
// val stages = Array.fill(cmdToRspStageCount)(Stream(UInt(32 bits)))
val stages = Array.fill(cmdToRspStageCount + 1)(new Bundle {
val input = Stream(UInt(32 bits))
val output = Stream(UInt(32 bits))
val halt = Bool
val inputSample = Bool
})
stages(0).input << fetchPc.output
stages(0).inputSample := True
for(s <- stages) {
s.halt := False
s.output << s.input.haltWhen(s.halt)
}
for((s,sNext) <- (stages, stages.tail).zipped) {
sNext.input << s.output.m2sPipeWithFlush(flush, s != stages.head, collapsBubble = false)
}
//
// val pipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount + 1)
// val halts = Vec(False, cmdToRspStageCount)
// for(i <- 0 until cmdToRspStageCount + 1) {
// pipeline(i) << {i match {
// case 0 => pipeline(0) << fetchPc.output.haltWhen(halts(i))
// case 1 => pipeline(1).m2sPipeWithFlush(flush, false, collapsBubble = false)
// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
// }}
// }
// ...
val readyForError = True
val output = Stream(FetchRsp())
incomingInstruction setWhen(inputPipeline.map(_.valid).orR)
incomingInstruction setWhen(stages.tail.map(_.input.valid).reduce(_ || _))
}
val decompressor = ifGen(decodePcGen)(new Area{
@ -326,10 +314,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val valids = pcUpdatedGen(True, False :: List(execute, memory, writeBack).map(_.arbitration.isStuck), true)
pcValids := Vec(valids.takeRight(4))
} else new Area{
val valids = pcUpdatedGen(True, iBusRsp.inputPipeline.map(!_.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ List(execute, memory, writeBack).map(_.arbitration.isStuck), relaxedPcCalculation)
if(relaxedPcCalculation && fetchPrediction != null) when(fetchPc.predictionPcLoad.valid){
valids(0).getDrivingReg := False
}
val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ List(execute, memory, writeBack).map(_.arbitration.isStuck), false)
pcValids := Vec(valids.takeRight(4))
}
@ -426,7 +411,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
}
def stage1ToInjectorPipe[T <: Data](input : T): (T,T) ={
val iBusRspContext = iBusRsp.inputPipeline.tail.foldLeft(input)((data,stream) => RegNextWhen(data, stream.ready))
val iBusRspContext = iBusRsp.stages.drop(1).dropRight(1).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready))
// val decompressorContext = ifGen(compressedGen)(new Area{
// val lastContext = RegNextWhen(iBusRspContext, decompressor.input.fire)
// val output = decompressor.bufferValid ? lastContext | iBusRspContext
@ -450,8 +435,8 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
val historyWrite = historyCache.writePort
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.inputPipeline(0).ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.inputPipeline(0).payload >> 2).resized
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(0).input.payload >> 2).resized
case class DynamicContext() extends Bundle{
val hazard = Bool
@ -459,7 +444,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
}
val fetchContext = DynamicContext()
fetchContext.hazard := hazard
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.inputPipeline(0).ready || flush)
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || flush)
object PREDICTION_CONTEXT extends Stageable(DynamicContext())
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2
@ -509,8 +494,8 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
val historyWrite = history.writePort
val line = history.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.inputPipeline(0).ready || flush)
val hit = line.source === (iBusRsp.inputPipeline(0).payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))) else True)
val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || flush)
val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True)
//Avoid stoping instruction fetch in the middle patch
if(compressedGen && cmdToRspStageCount == 1){
@ -518,9 +503,10 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
}
//Avoid write to read hazard
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.inputPipeline(0).ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.inputPipeline(0).payload >> 2).resized
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.inputPipeline(0).fire //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized
//TODO improve predictionPcLoad way of doing things
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.fire //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))
fetchPc.predictionPcLoad.payload := line.target
case class PredictionResult() extends Bundle{

View File

@ -23,14 +23,14 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
compressedGen = compressedGen,
cmdToRspStageCount = (if(config.twoCycleCache) 2 else 1),
cmdToRspStageCount = (if(config.twoCycleCache) 2 else 1) + (if(relaxedPcCalculation) 1 else 0),
injectorReadyCutGen = false,
relaxedPcCalculation = relaxedPcCalculation,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = !config.twoCycleCache || injectorStage){
import config._
var iBus : InstructionCacheMemBus = null
var mmuBus : MemoryTranslatorBus = null
var privilegeService : PrivilegeService = null
@ -99,18 +99,20 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus")
iBus <> cache.io.mem
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset
val stageOffset = if(relaxedPcCalculation) 1 else 0
def stages = iBusRsp.stages.drop(stageOffset)
//Connect prefetch cache side
cache.io.cpu.prefetch.isValid := fetchPc.output.valid
cache.io.cpu.prefetch.pc := fetchPc.output.payload
iBusRsp.input << fetchPc.output.haltWhen(cache.io.cpu.prefetch.haltIt)
cache.io.cpu.prefetch.isValid := stages(0).input.valid
cache.io.cpu.prefetch.pc := stages(0).input.payload
stages(0).halt setWhen(cache.io.cpu.prefetch.haltIt)
cache.io.cpu.fetch.isRemoved := flush
val iBusRspOutputHalt = False
if (mmuBus != null) {
cache.io.cpu.fetch.mmuBus <> mmuBus
(if(twoCycleCache) iBusRsp.inputPipelineHalt(0) else iBusRspOutputHalt) setWhen(mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
(if(twoCycleCache) stages(1).halt else iBusRspOutputHalt) setWhen(mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
} else {
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
@ -123,15 +125,15 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
}
//Connect fetch cache side
cache.io.cpu.fetch.isValid := iBusRsp.inputPipeline(0).valid
cache.io.cpu.fetch.isStuck := !iBusRsp.inputPipeline(0).ready
cache.io.cpu.fetch.pc := iBusRsp.inputPipeline(0).payload
cache.io.cpu.fetch.isValid := stages(1).input.valid
cache.io.cpu.fetch.isStuck := !stages(1).input.ready
cache.io.cpu.fetch.pc := stages(1).input.payload
if(twoCycleCache){
cache.io.cpu.decode.isValid := iBusRsp.inputPipeline(1).valid
cache.io.cpu.decode.isStuck := !iBusRsp.inputPipeline(1).ready
cache.io.cpu.decode.pc := iBusRsp.inputPipeline(1).payload
cache.io.cpu.decode.isValid := stages(2).input.valid
cache.io.cpu.decode.isStuck := !stages(2).input.ready
cache.io.cpu.decode.pc := stages(2).input.payload
cache.io.cpu.decode.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False)
if((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage){
@ -145,7 +147,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
// val missHalt = cache.io.cpu.fetch.isValid && cache.io.cpu.fetch.cacheMiss
val cacheRsp = if(twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch
val cacheRspArbitration = iBusRsp.inputPipeline(if(twoCycleCache) 1 else 0)
val cacheRspArbitration = stages(if(twoCycleCache) 2 else 1)
var issueDetected = False
val redoFetch = False //RegNext(False) init(False)
when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected){
@ -174,49 +176,12 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
}
}
iBusRsp.output.arbitrationFrom(cacheRspArbitration.haltWhen(issueDetected || iBusRspOutputHalt))
cacheRspArbitration.halt setWhen(issueDetected || iBusRspOutputHalt)
iBusRsp.output.arbitrationFrom(cacheRspArbitration.output)
iBusRsp.output.rsp.inst := cacheRsp.data
iBusRsp.output.pc := cacheRspArbitration.payload
iBusRsp.output.pc := cacheRspArbitration.output.payload
// if (dataOnDecode) {
// decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
// } else {
// iBusRsp.outputBeforeStage.arbitrationFrom(iBusRsp.inputPipeline(0))
// iBusRsp.outputBeforeStage.rsp.inst := cache.io.cpu.fetch.data
// iBusRsp.outputBeforeStage.pc := iBusRsp.inputPipeline(0).payload
// }
//
// cache.io.cpu.decode.pc := injector.inputBeforeHalt.pc
//
// val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode))
// cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode
// cache.io.cpu.decode.isStuck := !injector.inputBeforeHalt.ready
// cache.io.cpu.decode.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False)
// // cache.io.cpu.decode.pc := decode.input(PC)
//
// redoBranch.valid := decode.arbitration.isValid && ownDecode && cache.io.cpu.decode.cacheMiss && !cache.io.cpu.decode.mmuMiss && !cache.io.cpu.decode.illegalAccess
// redoBranch.payload := decode.input(PC)
// when(redoBranch.valid) {
// decode.arbitration.redoIt := True
// decode.arbitration.flushAll := True
// }
// val redo = RegInit(False) clearWhen(decode.arbitration.isValid) setWhen(redoBranch.valid)
// when(redoBranch.valid || redo){
// service(classOf[InterruptionInhibitor]).inhibateInterrupts()
// }
// if (catchSomething) {
// val accessFault = if (catchAccessFault) cache.io.cpu.decode.error else False
// val mmuMiss = if (catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
// val illegalAccess = if (catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False
// decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess)
// decodeExceptionPort.code := mmuMiss ? U(14) | 1
// decodeExceptionPort.badAddr := decode.input(PC)
// }
memory plug new Area {

View File

@ -159,9 +159,8 @@ class IBusSimplePlugin(resetVector : BigInt,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
compressedGen = compressedGen,
cmdToRspStageCount = busLatencyMin,
cmdToRspStageCount = busLatencyMin + (if(relaxedPcCalculation) 1 else 0),
injectorReadyCutGen = false,
relaxedPcCalculation = relaxedPcCalculation,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = injectorStage){
@ -187,36 +186,49 @@ class IBusSimplePlugin(resetVector : BigInt,
pipeline plug new FetchArea(pipeline) {
//Avoid sending to many iBus cmd
val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
val pendingCmdNext = pendingCmd + iBus.cmd.fire.asUInt - iBus.rsp.fire.asUInt
pendingCmd := pendingCmdNext
val cmd = if(relaxedBusCmdValid) new Area {
assert(relaxedPcCalculation, "relaxedBusCmdValid can only be used with relaxedPcCalculation")
def input = fetchPc.output
def output = iBusRsp.input
???
/* def inputStage = iBusRsp.stages(0)
val busFork = Stream(UInt(32 bits))
val busForkedReg = RegInit(False)
if(!relaxedPcCalculation) busForkedReg clearWhen(flush)
busForkedReg setWhen(iBus.cmd.fire)
busForkedReg clearWhen(inputStage.output.ready)
if(relaxedPcCalculation) busForkedReg clearWhen(flush)
val busForked = Bool
busForked := (if(!relaxedPcCalculation) (busForkedReg && !flush) else (busForkedReg))
busFork.valid := inputStage.input.valid && !busForkedReg
busFork.payload := inputStage.input.payload
inputStage.halt setWhen()
output.valid := (inputStage.input.valid && iBus.cmd.fire) || busForked
output.payload := input.payload
input.ready := output.fire
val fork = StreamForkVex(input, 2, flush)
val busFork = fork(0)
val pipFork = fork(1)
output << pipFork
val okBus = pendingCmd =/= pendingMax
iBus.cmd.valid := busFork.valid && okBus
iBus.cmd.pc := busFork.payload(31 downto 2) @@ "00"
busFork.ready := iBus.cmd.ready && okBus
busFork.ready := iBus.cmd.ready && okBus*/
} else new Area {
def input = fetchPc.output
def output = iBusRsp.input
def stage = iBusRsp.stages(if(relaxedPcCalculation) 1 else 0)
stage.halt setWhen(stage.input.valid && (!iBus.cmd.valid || !iBus.cmd.ready))
output << input.continueWhen(iBus.cmd.fire)
iBus.cmd.valid := input.valid && output.ready && pendingCmd =/= pendingMax
iBus.cmd.pc := input.payload(31 downto 2) @@ "00"
iBus.cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
iBus.cmd.pc := stage.input.payload(31 downto 2) @@ "00"
}
val rsp = new Area {
import iBusRsp._
//Manage flush for iBus transactions in flight
@ -226,20 +238,19 @@ class IBusSimplePlugin(resetVector : BigInt,
discardCounter := (if(relaxedPcCalculation) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt)
}
val rspBuffer = StreamFifoLowLatency(IBusSimpleRsp(), cmdToRspStageCount + (if(relaxedBusCmdValid) 1 else 0))
val rspBuffer = StreamFifoLowLatency(IBusSimpleRsp(), cmdToRspStageCount - (if(relaxedPcCalculation) 0 else 0))
rspBuffer.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream
rspBuffer.io.flush := flush
val fetchRsp = FetchRsp()
fetchRsp.pc := inputPipeline.last.payload
fetchRsp.pc := stages.last.output.payload
fetchRsp.rsp := rspBuffer.io.pop.payload
fetchRsp.rsp.error.clearWhen(!rspBuffer.io.pop.valid) //Avoid interference with instruction injection from the debug plugin
var issueDetected = False
val join = StreamJoin(Seq(inputPipeline.last, rspBuffer.io.pop), fetchRsp)
inputPipeline.last.ready setWhen(!inputPipeline.last.valid)
val join = StreamJoin(Seq(stages.last.output, rspBuffer.io.pop), fetchRsp)
stages.last.output.ready setWhen(!stages.last.output.valid)
output << join.haltWhen(issueDetected)
if(catchAccessFault){

View File

@ -522,8 +522,8 @@ class TestIndividualFeatures extends FunSuite {
// val seed = -2412372746600605141l
// val testId = Some(mutable.HashSet[Int](15))
// val seed = -8861778219266506530l
// val testId = Some(mutable.HashSet[Int](1,6,11,17,23,24))
// val seed = -7309275932954927463l
val rand = new Random(seed)