diff options
Diffstat (limited to 'VexRiscv/src/main/scala/vexriscv/plugin/Fetcher.scala')
-rw-r--r-- | VexRiscv/src/main/scala/vexriscv/plugin/Fetcher.scala | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/VexRiscv/src/main/scala/vexriscv/plugin/Fetcher.scala b/VexRiscv/src/main/scala/vexriscv/plugin/Fetcher.scala new file mode 100644 index 0000000..14450a1 --- /dev/null +++ b/VexRiscv/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -0,0 +1,637 @@ +package vexriscv.plugin + +import vexriscv._ +import spinal.core._ +import spinal.lib._ +import vexriscv.Riscv.IMM +import StreamVexPimper._ +import scala.collection.mutable.ArrayBuffer + + +//TODO val killLastStage = jump.pcLoad.valid || decode.arbitration.isRemoved +// DBUSSimple check memory halt execute optimization + +abstract class IBusFetcherImpl(val resetVector : BigInt, + val keepPcPlus4 : Boolean, + val decodePcGen : Boolean, + val compressedGen : Boolean, + val cmdToRspStageCount : Int, + val allowPcRegReusedForSecondStage : Boolean, + val injectorReadyCutGen : Boolean, + val prediction : BranchPrediction, + val historyRamSizeLog2 : Int, + val injectorStage : Boolean, + val relaxPredictorAddress : Boolean, + val fetchRedoGen : Boolean, + val predictionBuffer : Boolean = true) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ + var prefetchExceptionPort : Flow[ExceptionCause] = null + var decodePrediction : DecodePredictionBus = null + var fetchPrediction : FetchPredictionBus = null + var dynamicTargetFailureCorrection : Flow[UInt] = null + var externalResetVector : UInt = null + assert(cmdToRspStageCount >= 1) +// assert(!(cmdToRspStageCount == 1 && !injectorStage)) + assert(!(compressedGen && !decodePcGen)) + var fetcherHalt : Bool = null + var forceNoDecodeCond : Bool = null + var pcValids : Vec[Bool] = null + def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage)) + var incomingInstruction : Bool = null + override def incoming() = incomingInstruction + + + override def withRvc(): Boolean = compressedGen + + var injectionPort : Stream[Bits] = null + override def getInjectionPort() = { + injectionPort = Stream(Bits(32 bits)) + injectionPort + } + def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET //TODO might not be required for DYNAMIC_TARGET + var predictionJumpInterface : Flow[UInt] = null + + override def haltIt(): Unit = fetcherHalt := True + override def forceNoDecode(): Unit = forceNoDecodeCond := True + case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int) + val jumpInfos = ArrayBuffer[JumpInfo]() + override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = { + assert(stage != null) + val interface = Flow(UInt(32 bits)) + jumpInfos += JumpInfo(interface,stage, priority) + interface + } + + +// var decodeExceptionPort : Flow[ExceptionCause] = null + override def setup(pipeline: VexRiscv): Unit = { + fetcherHalt = False + forceNoDecodeCond = False + incomingInstruction = False + if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector")) + + prediction match { + case NONE => + case STATIC | DYNAMIC => { + predictionJumpInterface = createJumpInterface(pipeline.decode) + decodePrediction = pipeline.service(classOf[PredictionInterface]).askDecodePrediction() + } + case DYNAMIC_TARGET => { + fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() + } + } + + pcValids = Vec(Bool, pipeline.stages.size) + } + + object IBUS_RSP + object DECOMPRESSOR + object INJECTOR_M2S + + def isDrivingDecode(s : Any): Boolean = { + if(injectorStage) return s == INJECTOR_M2S + s == IBUS_RSP || s == DECOMPRESSOR + } + + + + class FetchArea(pipeline : VexRiscv) extends Area { + import pipeline._ + import pipeline.config._ + val externalFlush = stages.map(_.arbitration.flushNext).orR + + def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { + if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else externalFlush + } + + //Arbitrate jump requests into pcLoad + val jump = new Area { + val sortedByStage = jumpInfos.sortWith((a, b) => { + (pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) || + (pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority) + }) + val valids = sortedByStage.map(_.interface.valid) + val pcs = sortedByStage.map(_.interface.payload) + + val pcLoad = Flow(UInt(32 bits)) + pcLoad.valid := jumpInfos.map(_.interface.valid).orR + pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs) + } + + + + //The fetchPC pcReg can also be use for the second stage of the fetch + //When the fetcherHalt is set and the pipeline isn't stalled,, the pc is propagated to to the pcReg, which allow + //using the pc pipeline to get the next PC value for interrupts + val fetchPc = new Area{ + //PC calculation without Jump + val output = Stream(UInt(32 bits)) + val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) + val correction = False + val correctionReg = RegInit(False) setWhen(correction) clearWhen(output.fire) + val corrected = correction || correctionReg + val pcRegPropagate = False + val booted = RegNext(True) init (False) + val inc = RegInit(False) clearWhen(correction || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) + val pc = pcReg + (inc ## B"00").asUInt + val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) + val redo = (fetchRedoGen || prediction == DYNAMIC_TARGET) generate Flow(UInt(32 bits)) + val flushed = False + + if(compressedGen) when(inc) { + pc(1) := False + } + + if(predictionPcLoad != null) { + when(predictionPcLoad.valid) { + correction := True + pc := predictionPcLoad.payload + } + } + if(redo != null) when(redo.valid){ + correction := True + pc := redo.payload + flushed := True + } + when(jump.pcLoad.valid) { + correction := True + pc := jump.pcLoad.payload + flushed := True + } + + when(booted && (output.ready || correction || pcRegPropagate)){ + pcReg := pc + } + + pc(0) := False + if(!compressedGen) pc(1) := False + + output.valid := !fetcherHalt && booted + output.payload := pc + } + + val decodePc = ifGen(decodePcGen)(new Area { + //PC calculation without Jump + val flushed = False + val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) + val pcPlus = if(compressedGen) + pcReg + ((decode.input(IS_RVC)) ? U(2) | U(4)) + else + pcReg + 4 + + if (keepPcPlus4) KeepAttribute(pcPlus) + val injectedDecode = False + when(decode.arbitration.isFiring && !injectedDecode) { + pcReg := pcPlus + } + + val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) + if(prediction == DYNAMIC_TARGET) { + when(predictionPcLoad.valid && !forceNoDecodeCond) { + pcReg := predictionPcLoad.payload + } + } + + //application of the selected jump request + when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) { + pcReg := jump.pcLoad.payload + flushed := True + } + }) + + + case class FetchRsp() extends Bundle { + val pc = UInt(32 bits) + val rsp = IBusSimpleRsp() + val isRvc = Bool() + } + + + val iBusRsp = new Area { + val redoFetch = False + val stages = Array.fill(cmdToRspStageCount + 1)(new Bundle { + val input = Stream(UInt(32 bits)) + val output = Stream(UInt(32 bits)) + val halt = Bool() + }) + + stages(0).input << fetchPc.output + for(s <- stages) { + s.halt := False + s.output << s.input.haltWhen(s.halt) + } + + if(fetchPc.redo != null) { + fetchPc.redo.valid := redoFetch + fetchPc.redo.payload := stages.last.input.payload + } + + 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 sFlushed = if(s != stages.head) flush else False + val sNextFlushed = flush + if(s == stages.head && pcRegReusedForSecondStage) { + 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(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed) + } + } + + val readyForError = True + val output = Stream(FetchRsp()) + incomingInstruction setWhen(stages.tail.map(_.input.valid).reduce(_ || _)) + } + + val decompressor = ifGen(decodePcGen)(new Area{ + val input = iBusRsp.output.clearValidWhen(iBusRsp.redoFetch) + val output = Stream(FetchRsp()) + val flush = getFlushAt(DECOMPRESSOR) + val flushNext = if(isDrivingDecode(DECOMPRESSOR)) decode.arbitration.flushNext else False + val consumeCurrent = if(isDrivingDecode(DECOMPRESSOR)) flushNext && output.ready else False + + val bufferValid = RegInit(False) + val bufferData = Reg(Bits(16 bits)) + + val isInputLowRvc = input.rsp.inst(1 downto 0) =/= 3 + val isInputHighRvc = input.rsp.inst(17 downto 16) =/= 3 + val throw2BytesReg = RegInit(False) + val throw2Bytes = throw2BytesReg || input.pc(1) + val unaligned = throw2Bytes || bufferValid + def aligned = !unaligned + + //Latch and patches are there to ensure that the decoded instruction do not mutate while being halted and unscheduled to ensure FpuPlugin cmd fork from consistancy + val bufferValidLatch = RegNextWhen(bufferValid, input.valid) + val throw2BytesLatch = RegNextWhen(throw2Bytes, input.valid) + val bufferValidPatched = input.valid ? bufferValid | bufferValidLatch + val throw2BytesPatched = input.valid ? throw2Bytes | throw2BytesLatch + + val raw = Mux( + sel = bufferValidPatched, + whenTrue = input.rsp.inst(15 downto 0) ## bufferData, + whenFalse = input.rsp.inst(31 downto 16) ## (throw2BytesPatched ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) + ) + val isRvc = raw(1 downto 0) =/= 3 + val decompressed = RvcDecompressor(raw(15 downto 0), pipeline.config.withRvf, pipeline.config.withRvd) + output.valid := input.valid && !(throw2Bytes && !bufferValid && !isInputHighRvc) + output.pc := input.pc + output.isRvc := isRvc + output.rsp.inst := isRvc ? decompressed | raw + input.ready := output.ready && (!iBusRsp.stages.last.input.valid || flushNext || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc))) + + when(output.fire){ + throw2BytesReg := (aligned && isInputLowRvc && isInputHighRvc) || (bufferValid && isInputHighRvc) + } + val bufferFill = (aligned && isInputLowRvc && !isInputHighRvc) || (bufferValid && !isInputHighRvc) || (throw2Bytes && !isRvc && !isInputHighRvc) + when(output.ready && input.valid){ + bufferValid := False + } + when(output.ready && input.valid){ + bufferData := input.rsp.inst(31 downto 16) + bufferValid setWhen(bufferFill) + } + + when(flush || consumeCurrent){ + throw2BytesReg := False + bufferValid := False + } + + if(fetchPc.redo != null) { + fetchPc.redo.payload(1) setWhen(throw2BytesReg) + } + }) + + + 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(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 = 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) + decodeInput + } else { + inputBeforeStage + }) + + if(!decodePcGen) iBusRsp.readyForError.clearWhen(!pcValid(decode)) //Need to wait a valid PC on the decode stage, as it is use to fill CSR xEPC + + + def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean, flush : Bool) : Seq[Bool] = { + stucks.scanLeft(input)((i, stuck) => { + val reg = RegInit(False) + if(!relaxedInput) when(flush) { + reg := False + } + when(!stuck) { + reg := i + } + if(relaxedInput || i != input) when(flush) { + reg := False + } + reg + }).tail + } + + val stagesFromExecute = stages.dropWhile(_ != execute).toList + val nextPcCalc = if (decodePcGen) new Area{ + val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true, decodePc.flushed) + pcValids := Vec(valids.takeRight(stages.size)) + } else new Area{ + val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false, fetchPc.flushed) + pcValids := Vec(valids.takeRight(stages.size)) + } + + decodeInput.ready := !decode.arbitration.isStuck + decode.arbitration.isValid := decodeInput.valid + decode.insert(PC) := (if (decodePcGen) decodePc.pcReg else decodeInput.pc) + decode.insert(INSTRUCTION) := decodeInput.rsp.inst + if (compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc + + if (injectionPort != null) { + Component.current.addPrePopTask(() => { + val state = RegInit(U"000") + + injectionPort.ready := False + if(decodePcGen){ + decodePc.injectedDecode setWhen(state =/= 0) + } + switch(state) { + is(0) { //request pipelining + when(injectionPort.valid) { + state := 1 + } + } + is(1) { //Give time to propagate the payload + state := 2 + } + is(2){ //read regfile delay + decode.arbitration.isValid := True + decode.arbitration.haltItself := True + state := 3 + } + is(3){ //Do instruction + decode.arbitration.isValid := True + when(!decode.arbitration.isStuck) { + state := 4 + } + } + is(4){ //request pipelining + injectionPort.ready := True + state := 0 + } + } + + //Check if the decode instruction is driven by a register + val instructionDriver = try { + decode.input(INSTRUCTION).getDrivingReg + } catch { + case _: Throwable => null + } + if (instructionDriver != null) { //If yes => + //Insert the instruction by writing the "fetch to decode instruction register", + // Work even if it need to cross some hierarchy (caches) + instructionDriver.component.rework { + when(state.pull() =/= 0) { + instructionDriver := injectionPort.payload.pull() + } + } + } else { + //Insert the instruction via a mux in the decode stage + when(state =/= 0) { + decode.input(INSTRUCTION) := RegNext(injectionPort.payload) + } + } + }) + } + + Component.current.addPrePopTask(() => { + decode.arbitration.isValid clearWhen(forceNoDecodeCond) + }) + + //Formal verification signals generation, miss prediction stuff ? + val formal = new Area { + val raw = if(compressedGen) decompressor.raw else inputBeforeStage.rsp.inst + val rawInDecode = Delay(raw, if(injectorStage) 1 else 0, when = decodeInput.ready) + decode.insert(FORMAL_INSTRUCTION) := rawInDecode + + decode.insert(FORMAL_PC_NEXT) := (if (compressedGen) + decode.input(PC) + ((decode.input(IS_RVC)) ? U(2) | U(4)) + else + decode.input(PC) + 4) + + if(decodePc != null && decodePc.predictionPcLoad != null){ + when(decodePc.predictionPcLoad.valid){ + decode.insert(FORMAL_PC_NEXT) := decodePc.predictionPcLoad.payload + } + } + + jumpInfos.foreach(info => { + when(info.interface.valid) { + info.stage.output(FORMAL_PC_NEXT) := info.interface.payload + } + }) + } + } + + def stage1ToInjectorPipe[T <: Data](input : T): (T, T, T) ={ + val iBusRspContext = iBusRsp.stages.drop(1).dropRight(1).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) + + val iBusRspContextOutput = cloneOf(input) + iBusRspContextOutput := iBusRspContext + val injectorContext = Delay(iBusRspContextOutput, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) + val injectorContextWire = cloneOf(input) //Allow combinatorial override + injectorContextWire := injectorContext + (iBusRspContext, iBusRspContextOutput, injectorContextWire) + } + + val predictor = prediction match { + case NONE => + case STATIC | DYNAMIC => { + def historyWidth = 2 + val dynamic = ifGen(prediction == DYNAMIC) (new Area { + case class BranchPredictorLine() extends Bundle{ + val history = SInt(historyWidth bits) + } + + val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) + val historyWrite = historyCache.writePort + 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 + val line = BranchPredictorLine() + } + val fetchContext = DynamicContext() + fetchContext.hazard := hazard + 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 + val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb + + val branchStage = decodePrediction.stage + val branchContext = branchStage.input(PREDICTION_CONTEXT) + val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb + + historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline.config.withRvc) + ((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0)) + else + U(0)) + + historyWrite.data.history := branchContext.line.history + (moreJump ? S(-1) | S(1)) + val sat = (branchContext.line.history === (moreJump ? S(branchContext.line.history.minValue) | S(branchContext.line.history.maxValue))) + historyWrite.valid := !branchContext.hazard && branchStage.arbitration.isFiring && branchStage.input(BRANCH_CTRL) === BranchCtrlEnum.B && !sat + }) + + + val imm = IMM(decode.input(INSTRUCTION)) + + val conditionalBranchPrediction = prediction match { + case STATIC => imm.b_sext.msb + case DYNAMIC => dynamic.decodeContextPrediction + } + + decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) + + val noPredictionOnMissaligned = (!pipeline.config.withRvc) generate new Area{ + val missaligned = decode.input(BRANCH_CTRL).mux( + BranchCtrlEnum.JAL -> imm.j_sext(1), + default -> imm.b_sext(1) + ) + decodePrediction.cmd.hadBranch clearWhen(missaligned) + } + + //TODO no more fireing depedancies + predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch + predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt + decode.arbitration.flushNext setWhen(predictionJumpInterface.valid) + + if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) + } + case DYNAMIC_TARGET => new Area{ +// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") + + case class BranchPredictorLine() extends Bundle{ + val source = Bits(30 - historyRamSizeLog2 bits) + val branchWish = UInt(2 bits) + val last2Bytes = ifGen(compressedGen)(Bool) + val target = UInt(32 bits) + } + + val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) + val historyWriteDelayPatched = history.writePort + val historyWrite = cloneOf(historyWriteDelayPatched) + historyWriteDelayPatched.valid := historyWrite.valid + historyWriteDelayPatched.address := (if(predictionBuffer) historyWrite.address - 1 else historyWrite.address) + historyWriteDelayPatched.data := historyWrite.data + + + val writeLast = RegNextWhen(historyWriteDelayPatched, iBusRsp.stages(0).output.ready) + + //Avoid write to read hazard + val buffer = predictionBuffer generate new Area{ + val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready) + val pcCorrected = RegNextWhen(fetchPc.corrected, iBusRsp.stages(0).input.ready) + val hazard = (writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized) + } + + val (line, hazard) = predictionBuffer match { + case true => + (RegNextWhen(buffer.line, iBusRsp.stages(0).output.ready), + RegNextWhen(buffer.hazard, iBusRsp.stages(0).output.ready) || buffer.pcCorrected) + case false => + (history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, + iBusRsp.stages(0).output.ready), writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized) + } + + val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) + if(compressedGen) hit clearWhen(!line.last2Bytes && iBusRsp.stages(1).input.payload(1)) + + fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).input.valid + fetchPc.predictionPcLoad.payload := line.target + + case class PredictionResult() extends Bundle{ + val hazard = Bool + val hit = Bool + val line = BranchPredictorLine() + } + + val fetchContext = PredictionResult() + fetchContext.hazard := hazard + fetchContext.hit := hit + fetchContext.line := line + + val (iBusRspContext, iBusRspContextOutput, injectorContext) = stage1ToInjectorPipe(fetchContext) + + object PREDICTION_CONTEXT extends Stageable(PredictionResult()) + pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext + val branchStage = fetchPrediction.stage + val branchContext = branchStage.input(PREDICTION_CONTEXT) + + fetchPrediction.cmd.hadBranch := branchContext.hit && !branchContext.hazard && branchContext.line.branchWish.msb + fetchPrediction.cmd.targetPc := branchContext.line.target + + + historyWrite.valid := False + historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits) + historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2 + historyWrite.data.target := fetchPrediction.rsp.finalPc + if(compressedGen) historyWrite.data.last2Bytes := fetchPrediction.stage.input(PC)(1) && fetchPrediction.stage.input(IS_RVC) + + when(fetchPrediction.rsp.wasRight) { + historyWrite.valid := branchContext.hit + historyWrite.data.branchWish := branchContext.line.branchWish + (branchContext.line.branchWish === 2).asUInt - (branchContext.line.branchWish === 1).asUInt + } otherwise { + when(branchContext.hit) { + historyWrite.valid := True + historyWrite.data.branchWish := branchContext.line.branchWish - (branchContext.line.branchWish.msb).asUInt + (!branchContext.line.branchWish.msb).asUInt + } otherwise { + historyWrite.valid := True + historyWrite.data.branchWish := "10" + } + } + + historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) + + val compressor = compressedGen generate new Area{ + val predictionBranch = iBusRspContext.hit && !iBusRspContext.hazard && iBusRspContext.line.branchWish(1) + val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && iBusRspContext.line.last2Bytes && Mux(decompressor.unaligned, !decompressor.isInputHighRvc, decompressor.isInputLowRvc && !decompressor.isInputHighRvc) + + when(unalignedWordIssue){ + historyWrite.valid := True + historyWrite.address := (iBusRsp.stages(1).input.payload >> 2).resized + historyWrite.data.branchWish := 0 + + iBusRsp.redoFetch := True + } + + //Do not trigger prediction hit when it is one for the upper RVC word and we aren't there yet + iBusRspContextOutput.hit clearWhen(iBusRspContext.line.last2Bytes && (decompressor.bufferValid || (!decompressor.throw2Bytes && decompressor.isInputLowRvc))) + + decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire + decodePc.predictionPcLoad.payload := injectorContext.line.target + + //Clean the RVC buffer when a prediction was made + when(iBusRspContext.line.branchWish.msb && iBusRspContextOutput.hit && !iBusRspContext.hazard && decompressor.output.fire){ + decompressor.bufferValid := False + decompressor.throw2BytesReg := False + decompressor.input.ready := True //Drop the remaining byte if any + } + } + } + } + + def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={ + iBusRsp.stages.dropWhile(_ != stage).tail.foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) + } + + } +}
\ No newline at end of file |