diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index f692680..17c4bf6 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -24,8 +24,9 @@ case class DataCacheConfig(cacheSize : Int, earlyDataMux : Boolean = false, tagSizeShift : Int = 0, //Used to force infering ram withLrSc : Boolean = false, - withAmo : Boolean = false){ - + withAmo : Boolean = false, + mergeExecuteMemory : Boolean = false){ + assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) @@ -446,7 +447,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } val stageA = new Area{ - def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.memory.isStuck) + def stagePipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.memory.isStuck) val request = stagePipe(io.cpu.execute.args) val mask = stagePipe(stage0.mask) io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid @@ -457,16 +458,22 @@ class DataCache(p : DataCacheConfig) extends Component{ val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) - val colisions = stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + val colisions = if(mergeExecuteMemory){ + stagePipe(stage0.colisions) + } else { + //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) + } } val stageB = new Area { def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.writeBack.isStuck) + def ramPipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.writeBack.isStuck) val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) val mmuRspFreeze = False val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) - val tagsReadRsp = ways.map(w => stagePipe(w.tagsReadRsp)) - val dataReadRsp = !earlyDataMux generate ways.map(w => stagePipe(w.dataReadRsp)) + val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) + val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHit = waysHits.orR val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 10e4550..9102a72 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -148,7 +148,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) if(catchSomething) - exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) + exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack) if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) @@ -162,7 +162,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBus = master(DataCacheMemBus(this.config)).setName("dBus") - val cache = new DataCache(this.config) + val cache = new DataCache(this.config.copy( + mergeExecuteMemory = writeBack == null + )) //Interconnect the plugin dBus with the cache dBus with some optional pipelining def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on @@ -226,19 +228,22 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address } - memory plug new Area{ - import memory._ + val mmuAndBufferStage = if(writeBack != null) memory else execute + mmuAndBufferStage plug new Area { + import mmuAndBufferStage._ + cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA))) + cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else if(mmuAndBufferStage == execute) cache.io.cpu.execute.address else U(input(REGFILE_WRITE_DATA))) cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) } - writeBack plug new Area{ - import writeBack._ + val managementStage = stages.last + managementStage plug new Area{ + import managementStage._ cache.io.cpu.writeBack.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.writeBack.isStuck := arbitration.isStuck cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) @@ -323,10 +328,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire - mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) - dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) + mmuBus.cmd.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)) + if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))) + cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING)) + dBusAccess.rsp.valid := managementStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo @@ -334,10 +339,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } - memory.input(IS_DBUS_SHARING) init(False) - writeBack.input(IS_DBUS_SHARING) init(False) + if(mmuAndBufferStage != execute) mmuAndBufferStage.input(IS_DBUS_SHARING) init(False) + managementStage.input(IS_DBUS_SHARING) init(False) when(dBusAccess.rsp.valid){ - writeBack.input(IS_DBUS_SHARING).getDrivingReg := False + managementStage.input(IS_DBUS_SHARING).getDrivingReg := False } } } diff --git a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala index f674ae8..1ed1d83 100644 --- a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala @@ -95,7 +95,7 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, } if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null) - if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE) + if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE) if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index f366854..1bd8fb4 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -31,7 +31,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), BYPASSABLE_MEMORY_STAGE -> True, RS1_USE -> True, RS2_USE -> True @@ -69,8 +69,9 @@ class MulDivIterativePlugin(genMul : Boolean = true, import pipeline.config._ if(!genMul && !genDiv) return - memory plug new Area { - import memory._ + val flushStage = if(memory != null) memory else execute + flushStage plug new Area { + import flushStage._ //Shared ressources val rs1 = Reg(UInt(33 bits)) diff --git a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala index 41ed391..3b407e1 100644 --- a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala @@ -19,8 +19,8 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, - BYPASSABLE_MEMORY_STAGE -> False, + BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), + BYPASSABLE_MEMORY_STAGE -> Bool(pipeline.stages.last == pipeline.memory), RS1_USE -> True, RS2_USE -> True, IS_MUL -> True @@ -66,14 +66,16 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt } - memory plug new Area { - import memory._ + val injectionStage = if(pipeline.memory != null) pipeline.memory else pipeline.execute + injectionStage plug new Area { + import injectionStage._ insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits } - writeBack plug new Area { - import writeBack._ + val memStage = stages.last + memStage plug new Area { + import memStage._ when(arbitration.isValid && input(IS_MUL)){ switch(input(INSTRUCTION)(13 downto 12)){ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 33e4aa6..efa975c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -99,6 +99,22 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) var l = List[VexRiscvPosition]() + + + + new VexRiscvPosition("MulDivFpgaSimple") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulSimplePlugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + if(!noMemory) { l = new VexRiscvPosition("MulDivAsic") { override def testParam = "MUL=yes DIV=yes" @@ -376,7 +392,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { - if(r.nextDouble() < 0.4 || noMemory || noWriteBack){ + if(r.nextDouble() < 0.4 || noMemory){ val withLrSc = catchAll val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { @@ -396,7 +412,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusRspSlavePipe, relaxedMemoryTranslationRegister, earlyWaysHits = r.nextBoolean() + val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val earlyWaysHits = r.nextBoolean() && !noWriteBack val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ @@ -600,11 +617,11 @@ class TestIndividualFeatures extends FunSuite { val testId : Option[mutable.HashSet[Int]] = None val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong - +// // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(24, 43, 49)) -// val testId = Some(mutable.HashSet(11)) -// val seed = -8309068850561113754l +// val testId = Some(mutable.HashSet(22)) +// val testId = Some(mutable.HashSet(22, 33 , 38, 47, 48)) +// val seed = 5426556825163943143l val rand = new Random(seed) @@ -622,11 +639,16 @@ class TestIndividualFeatures extends FunSuite { universe += VexRiscvUniverse.MMU universe += VexRiscvUniverse.FORCE_MULDIV universe += VexRiscvUniverse.SUPERVISOR + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } else { if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } - var tmp = rand.nextDouble() if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){ }else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK