diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index e8194ab..ed95756 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -17,9 +17,12 @@ case class InstructionCacheConfig( cacheSize : Int, catchAccessFault : Boolean, catchMemoryTranslationMiss : Boolean, asyncTagMemory : Boolean, + twoCycleCache : Boolean = false, twoCycleRam : Boolean = false, preResetFlush : Boolean = false){ + assert(!(twoCycleRam && !twoCycleCache)) + def dataOnDecode = twoCycleRam && wayCount > 1 def burstSize = bytePerLine*8/memDataWidth def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess @@ -63,10 +66,12 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val pc = UInt(p.addressWidth bits) val data = Bits(p.cpuDataWidth bits) val mmuBus = MemoryTranslatorBus() + val cacheMiss, error, mmuMiss, illegalAccess,isUser = ifGen(!p.twoCycleCache)(Bool) override def asMaster(): Unit = { out(isValid, isStuck, pc) - inWithNull(data) + inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss) + outWithNull(isUser) slaveWithNull(mmuBus) } } @@ -74,19 +79,15 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave { val isValid = Bool - val isUser = Bool val isStuck = Bool val pc = UInt(p.addressWidth bits) - val cacheMiss = Bool val data = ifGen(p.dataOnDecode) (Bits(p.cpuDataWidth bits)) - val error = Bool - val mmuMiss = Bool - val illegalAccess = Bool + val cacheMiss, error, mmuMiss, illegalAccess, isUser = ifGen(p.twoCycleCache)(Bool) override def asMaster(): Unit = { - out(isValid, isUser, isStuck, pc) - in(cacheMiss) - inWithNull(error,mmuMiss,illegalAccess,data) + out(isValid, isStuck, pc) + outWithNull(isUser) + inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss) } } @@ -94,9 +95,10 @@ case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle wit val prefetch = InstructionCacheCpuPrefetch(p) val fetch = InstructionCacheCpuFetch(p) val decode = InstructionCacheCpuDecode(p) + val fill = Flow(UInt(p.addressWidth bits)) override def asMaster(): Unit = { - master(prefetch, fetch, decode) + master(prefetch, fetch, decode, fill) } } @@ -218,6 +220,11 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val address = Reg(UInt(addressWidth bits)) val hadError = RegInit(False) clearWhen(fire) + when(io.cpu.fill.valid){ + valid := True + address := io.cpu.fill.payload + } + io.cpu.prefetch.haltIt setWhen(valid) val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(if(preResetFlush) wayLineCount else 0) @@ -311,10 +318,21 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.pc io.cpu.fetch.mmuBus.cmd.bypassTranslation := False + + val resolution = ifGen(!twoCycleCache)( new Area{ + def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck) + val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp) + + io.cpu.fetch.cacheMiss := !hit.valid + io.cpu.fetch.error := hit.error + io.cpu.fetch.mmuMiss := mmuRsp.miss + io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser) + }) } - val decodeStage = new Area{ + + val decodeStage = ifGen(twoCycleCache) (new Area{ def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck) val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp) @@ -335,16 +353,16 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } io.cpu.decode.cacheMiss := !hit.valid - when( io.cpu.decode.isValid && io.cpu.decode.cacheMiss){ - io.cpu.prefetch.haltIt := True - lineLoader.valid := True - lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used - } +// when( io.cpu.decode.isValid && io.cpu.decode.cacheMiss){ +// io.cpu.prefetch.haltIt := True +// lineLoader.valid := True +// lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used +// } // when(io.cpu) io.cpu.decode.error := hit.error io.cpu.decode.mmuMiss := mmuRsp.miss io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser) - } + }) } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index a2d5c11..559e485 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -44,12 +44,12 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, } - var decodeExceptionPort : Flow[ExceptionCause] = null +// var decodeExceptionPort : Flow[ExceptionCause] = null override def setup(pipeline: VexRiscv): Unit = { fetcherHalt = False if(catchAccessFault || catchAddressMisaligned) { val exceptionService = pipeline.service(classOf[ExceptionService]) - decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1).setName("iBusErrorExceptionnPort") +// decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1).setName("iBusErrorExceptionnPort") } pipeline(RVC_GEN) = compressedGen @@ -200,8 +200,10 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, // ... + val readyForError = True val outputBeforeStage = Stream(FetchRsp()) val output = if(rspStageGen) outputBeforeStage.m2sPipeWithFlush(flush) else outputBeforeStage + if(rspStageGen) readyForError.clearWhen(output.valid) } val decompressor = ifGen(decodePcGen)(new Area{ @@ -209,7 +211,6 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, val output = Stream(FetchRsp()) val bufferValid = RegInit(False) - val bufferError = Reg(Bool) val bufferData = Reg(Bits(16 bits)) val raw = Mux( @@ -219,11 +220,10 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, ) val isRvc = raw(1 downto 0) =/= 3 val decompressed = RvcDecompressor(raw(15 downto 0)) - output.valid := isRvc ? (bufferValid || input.valid) | (input.valid && (bufferValid || !input.pc(1))) + output.valid := (isRvc ? (bufferValid || input.valid) | (input.valid && (bufferValid || !input.pc(1)))) output.pc := input.pc output.isRvc := isRvc output.rsp.inst := isRvc ? decompressed | raw - output.rsp.error := (bufferValid && bufferError) || (input.valid && input.rsp.error && (!isRvc || (isRvc && !bufferValid))) input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready)) @@ -231,19 +231,21 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, when(input.ready){ when(input.valid) { bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1)) - bufferError := input.rsp.error bufferData := input.rsp.inst(31 downto 16) } } bufferValid.clearWhen(flush) + iBusRsp.readyForError.clearWhen(bufferValid && isRvc) }) def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that val injector = new Area { val inputBeforeHalt = condApply(if(decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush)) + if(injectorReadyCutGen) iBusRsp.readyForError.clearWhen(inputBeforeHalt.valid) val decodeInput = if(injectorStage){ val decodeInput = inputBeforeHalt.m2sPipeWithFlush(killLastStage) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeHalt.rsp.inst) + iBusRsp.readyForError.clearWhen(decodeInput.valid) decodeInput } else { inputBeforeHalt @@ -273,11 +275,11 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, decode.insert(INSTRUCTION_READY) := True if(compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc - if(catchAccessFault){ - decodeExceptionPort.valid := decode.arbitration.isValid && decodeInput.rsp.error - decodeExceptionPort.code := 1 - decodeExceptionPort.badAddr := decode.input(PC) - } +// if(catchAccessFault){ +// decodeExceptionPort.valid := decode.arbitration.isValid && decodeInput.rsp.error +// decodeExceptionPort.code := 1 +// decodeExceptionPort.badAddr := decode.input(PC) +// } } prediction match { diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index a3a72cf..7cfa72e 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -50,10 +50,10 @@ class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConf redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor - if(catchSomething) { - val exceptionService = pipeline.service(classOf[ExceptionService]) - decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1) - } +// if(catchSomething) { +// val exceptionService = pipeline.service(classOf[ExceptionService]) +// decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1) +// } // if(pipeline.serviceExist(classOf[MemoryTranslator])) // ??? //TODO @@ -114,43 +114,52 @@ class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConf cache.io.cpu.fetch.mmuBus.rsp.miss := False } - 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 - } + val missHalt = cache.io.cpu.fetch.isValid && cache.io.cpu.fetch.cacheMiss + iBusRsp.outputBeforeStage.arbitrationFrom(iBusRsp.inputPipeline(0).haltWhen(missHalt)) + 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 + cache.io.cpu.fill.valid := missHalt && iBusRsp.readyForError + cache.io.cpu.fill.payload := cache.io.cpu.fetch.pc + redoBranch.valid := (RegNext(cache.io.cpu.fill.valid && !flush) init(False)) redoBranch.payload := decode.input(PC) - when(redoBranch.valid) { - decode.arbitration.redoIt := True - decode.arbitration.flushAll := True - } +// 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 +// 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) - } +// decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess) +// decodeExceptionPort.code := mmuMiss ? U(14) | 1 +// decodeExceptionPort.badAddr := decode.input(PC) +// } memory plug new Area {