Fix target branch prediction for RVC, all default configs pass dhrystone

This commit is contained in:
Charles Papon 2020-02-20 02:27:57 +01:00
parent a684d5e4d1
commit 59508d5b57
1 changed files with 30 additions and 26 deletions

View File

@ -247,36 +247,42 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
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 doubleRvc = iBusRsp.stages.last.input.valid && !bufferValid && isInputLowRvc && isInputHighRvc && !input.pc(1)
val throw2BytesReg = RegInit(False)
val throw2Bytes = throw2BytesReg || input.pc(1)
val unaligned = throw2Bytes || bufferValid
def aligned = !unaligned
val raw = Mux(
sel = bufferValid,
whenTrue = input.rsp.inst(15 downto 0) ## bufferData,
whenFalse = input.rsp.inst(31 downto 16) ## (input.pc(1) ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0))
whenFalse = input.rsp.inst(31 downto 16) ## (throw2Bytes ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0))
)
val isRvc = raw(1 downto 0) =/= 3
val isBufferRvc = bufferData(1 downto 0) =/= 3
val decompressed = RvcDecompressor(raw(15 downto 0))
output.valid := bufferValid ? (isBufferRvc || input.valid) | (input.valid && (!input.pc(1) || input.rsp.inst(17 downto 16) =/= 3))
output.valid := input.valid && !(throw2Bytes && !bufferValid && !isInputHighRvc)
output.pc := input.pc
output.isRvc := isRvc
output.rsp.inst := isRvc ? decompressed | raw
input.ready := output.ready && !(bufferValid && isBufferRvc)
input.ready := output.ready && (!iBusRsp.stages.last.input.valid || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc)))
val bufferFill = False
when(output.ready && (isBufferRvc || input.valid)){
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)
when((!bufferValid && !input.pc(1) && input.rsp.inst(1 downto 0) =/= 3) || (bufferValid && !isBufferRvc) || (input.pc(1) && input.rsp.inst(17 downto 16) === 3)){
bufferFill := True
bufferValid := True
}
bufferValid setWhen(bufferFill)
}
bufferValid.clearWhen(flush)
when(bufferValid && isBufferRvc){
iBusRsp.readyForError := False
incomingInstruction := True
when(flush){
throw2BytesReg := False
bufferValid := False
}
})
@ -504,7 +510,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val source = Bits(30 - historyRamSizeLog2 bits)
val branchWish = UInt(2 bits)
val target = UInt(32 bits)
val unaligned = ifGen(compressedGen)(Bool)
val last2Bytes = ifGen(compressedGen)(Bool)
}
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
@ -515,6 +521,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized
val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready)
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
@ -533,14 +540,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
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))))
decompressorContext.hit clearWhen(decompressorContext.line.last2Bytes && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.throw2Bytes)))
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(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){
decompressor.bufferValid := False
decompressor.input.ready := True
decompressor.throw2BytesReg := False
decompressor.input.ready := True //Drop the remaining byte if any
}
}
@ -557,7 +566,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
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)
if(compressedGen) historyWrite.data.last2Bytes := fetchPrediction.stage.input(PC)(1) && fetchPrediction.stage.input(IS_RVC)
when(fetchPrediction.rsp.wasRight) {
historyWrite.valid := branchContext.hit
@ -574,18 +583,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring)
val predictionFailure = ifGen(compressedGen)(new Area{
val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1)
val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch
val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt)
val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready, init=False)
val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid
val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && decompressor.throw2Bytes && !decompressor.isInputHighRvc
when(injectorFailure || bypassFailure){
when(unalignedWordIssue){
historyWrite.valid := True
historyWrite.address := (decode.input(PC) >> 2).resized
historyWrite.address := (iBusRsp.stages(1).input.payload >> 2).resized
historyWrite.data.branchWish := 0
iBusRsp.redoFetch := True