From 86efb75f6aac3a50bbfcd2749c7721e0d6b1fc3f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 23 Sep 2018 22:05:53 +0200 Subject: [PATCH] rework fetcher --- src/main/scala/vexriscv/plugin/Fetcher.scala | 116 ++++++++---------- .../vexriscv/plugin/IBusCachedPlugin.scala | 73 +++-------- .../vexriscv/plugin/IBusSimplePlugin.scala | 53 ++++---- .../vexriscv/TestIndividualFeatures.scala | 4 +- 4 files changed, 104 insertions(+), 142 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 5584ab2..986502e 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -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{ diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 187e95c..405c277 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -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 { diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 523a2ef..6e415c0 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -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){ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 3474e7b..d7eae7e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -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)