diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 51d57d3..b6ffeb8 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -34,7 +34,7 @@ object TestsWorkspace { new IBusSimplePlugin( resetVector = 0x80000000l, relaxedPcCalculation = false, - prediction = DYNAMIC, + prediction = NONE, historyRamSizeLog2 = 8, catchAccessFault = true, compressedGen = true @@ -98,7 +98,7 @@ object TestsWorkspace { ), new RegFilePlugin( regFileReadyKind = plugin.ASYNC, - zeroBoot = false + zeroBoot = true ), new IntAluPlugin, new SrcPlugin( diff --git a/src/main/scala/vexriscv/demo/FormalSimple.scala b/src/main/scala/vexriscv/demo/FormalSimple.scala index 3e8d170..a18672f 100644 --- a/src/main/scala/vexriscv/demo/FormalSimple.scala +++ b/src/main/scala/vexriscv/demo/FormalSimple.scala @@ -16,7 +16,7 @@ object FormalSimple extends App{ new IBusSimplePlugin( resetVector = 0x00000000l, relaxedPcCalculation = false, - prediction = NONE, + prediction = DYNAMIC_TARGET, catchAccessFault = false, compressedGen = true ), diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index cd9faaa..daa837e 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -35,6 +35,7 @@ case class FetchPredictionCmd() extends Bundle{ case class FetchPredictionRsp() extends Bundle{ val wasRight = Bool val finalPc = UInt(32 bits) + val sourceLastWord = UInt(32 bits) } case class FetchPredictionBus(stage : Stage) extends Bundle { val cmd = FetchPredictionCmd() @@ -310,6 +311,12 @@ class BranchPlugin(earlyBranch : Boolean, val predictionMissmatch = fetchPrediction.cmd.hadBranch =/= input(BRANCH_DO) || (input(BRANCH_DO) && fetchPrediction.cmd.targetPc =/= input(BRANCH_CALC)) fetchPrediction.rsp.wasRight := ! predictionMissmatch fetchPrediction.rsp.finalPc := input(BRANCH_CALC) + fetchPrediction.rsp.sourceLastWord := { + if(pipeline(RVC_GEN)) + ((!input(IS_RVC) && input(PC)(1)) ? input(NEXT_PC) | input(PC)) + else + input(PC) + } jumpInterface.valid := arbitration.isFiring && predictionMissmatch //Probably just isValid instead of isFiring is better jumpInterface.payload := (input(BRANCH_DO) ? input(BRANCH_CALC) | input(NEXT_PC)) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index d2f70eb..2606fa0 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -259,10 +259,17 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, output.pc := input.pc output.isRvc := isRvc output.rsp.inst := isRvc ? decompressed | raw - input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready)) +// input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready)) + input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3)) + addPrePopTask(() => { + when(!input.ready && output.fire && !flush /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { + input.pc.getDrivingReg(1) := True + } + }) bufferValid clearWhen(output.fire) when(input.fire){ +// bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready) bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready) bufferData := input.rsp.inst(31 downto 16) } @@ -387,8 +394,13 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, else decode.input(PC) + 4) - jumpInfos - .foreach(info => { + 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 } @@ -398,12 +410,16 @@ 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 decompressorContext = ifGen(compressedGen)(new Area{ - val lastContext = RegNextWhen(iBusRspContext, decompressor.input.fire) - val output = decompressor.bufferValid ? lastContext | iBusRspContext - }) - val injectorContext = Delay(if(compressedGen) decompressorContext.output else iBusRspContext, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) - (ifGen(compressedGen)(decompressorContext.output), injectorContext) +// val decompressorContext = ifGen(compressedGen)(new Area{ +// val lastContext = RegNextWhen(iBusRspContext, decompressor.input.fire) +// val output = decompressor.bufferValid ? lastContext | iBusRspContext +// }) + val decompressorContext = cloneOf(input) + decompressorContext := iBusRspContext + val injectorContext = Delay(if(compressedGen) decompressorContext else iBusRspContext, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) + val injectorContextWire = cloneOf(input) //Allow combinatorial override + injectorContextWire := injectorContext + (ifGen(compressedGen)(decompressorContext), injectorContextWire) } val predictor = prediction match { @@ -461,14 +477,14 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, // } } case DYNAMIC_TARGET => new Area{ - assert(!compressedGen, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") + assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") val historyRamSizeLog2 : Int = 10 case class BranchPredictorLine() extends Bundle{ val source = Bits(30 - historyRamSizeLog2 bits) val branchWish = UInt(2 bits) val target = UInt(32 bits) -// val unaligned = ifGen(compressedGen)(Bool) + val unaligned = ifGen(compressedGen)(Bool) } val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) @@ -477,10 +493,15 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, 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) + //Avoid stoping instruction fetch in the middle patch + if(compressedGen && cmdToRspStageCount == 1){ + hit clearWhen(!decompressor.output.valid) + } + //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 + fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.inputPipeline(0).fire //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1)) fetchPc.predictionPcLoad.payload := line.target case class PredictionResult() extends Bundle{ @@ -496,11 +517,18 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) if(compressedGen) { + //prediction hit on the right instruction into words + decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) + + // if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned) + decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire decodePc.predictionPcLoad.payload := injectorContext.line.target + when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ decompressor.bufferValid := False + decompressor.input.ready := True } } @@ -514,9 +542,10 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, historyWrite.valid := False - historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) - historyWrite.data.source := branchStage.input(PC).asBits >> 2 + historyRamSizeLog2 + 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.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC) when(fetchPrediction.rsp.wasRight) { historyWrite.valid := branchContext.hit diff --git a/src/test/cpp/regression/.gitignore b/src/test/cpp/regression/.gitignore new file mode 100644 index 0000000..df54a57 --- /dev/null +++ b/src/test/cpp/regression/.gitignore @@ -0,0 +1 @@ +*.regTraceRef diff --git a/src/test/python/tool/disasm.s b/src/test/python/tool/disasm.s index 83ac5f3..2c71b28 100644 --- a/src/test/python/tool/disasm.s +++ b/src/test/python/tool/disasm.s @@ -1 +1 @@ -.word 0xfef5f593 +.word 0x7912a23