From fd4da77084247c45b9c61cb153ee363405860906 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 2 Apr 2019 00:26:53 +0200 Subject: [PATCH] #60 Got the new instruction cache design passing the standard regressions --- src/main/scala/vexriscv/Pipeline.scala | 2 +- src/main/scala/vexriscv/TestsWorkspace.scala | 1 - src/main/scala/vexriscv/demo/Briey.scala | 3 +- src/main/scala/vexriscv/demo/GenFull.scala | 3 +- .../scala/vexriscv/demo/GenFullNoMmu.scala | 3 +- .../vexriscv/demo/GenFullNoMmuMaxPerf.scala | 3 +- src/main/scala/vexriscv/demo/Linux.scala | 141 ++--- .../vexriscv/demo/VexRiscvAvalonForSim.scala | 3 +- .../VexRiscvAvalonWithIntegratedJtag.scala | 3 +- .../demo/VexRiscvAxi4WithIntegratedJtag.scala | 3 +- .../demo/VexRiscvCachedWishboneForSim.scala | 3 +- src/main/scala/vexriscv/ip/DataCache.scala | 591 ++++++------------ .../vexriscv/plugin/DBusCachedPlugin.scala | 61 +- .../plugin/StaticMemoryTranslatorPlugin.scala | 5 +- src/test/cpp/regression/fail.gtkw | 72 +-- src/test/cpp/regression/main.cpp | 1 + .../vexriscv/TestIndividualFeatures.scala | 1 - 17 files changed, 353 insertions(+), 546 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 6cbf1c7..cde5ae8 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -21,7 +21,7 @@ trait Pipeline { def service[T](clazz : Class[T]) = { val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass)) - assert(filtered.length == 1) + assert(filtered.length == 1, s"??? ${clazz.getName}") filtered.head.asInstanceOf[T] } diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 73576ba..387691a 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -81,7 +81,6 @@ object TestsWorkspace { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - catchMemoryTranslationMiss = true, atomicEntriesCount = 2 ), // memoryTranslatorPortConfig = null diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index d7bb91c..053abf8 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -88,8 +88,7 @@ object BrieyConfig{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/GenFull.scala b/src/main/scala/vexriscv/demo/GenFull.scala index e1df08b..ae75397 100644 --- a/src/main/scala/vexriscv/demo/GenFull.scala +++ b/src/main/scala/vexriscv/demo/GenFull.scala @@ -41,8 +41,7 @@ object GenFull extends App{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = MemoryTranslatorPortConfig( portTlbSize = 6 diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmu.scala b/src/main/scala/vexriscv/demo/GenFullNoMmu.scala index 167735c..00ba8c9 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmu.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmu.scala @@ -42,8 +42,7 @@ object GenFullNoMmu extends App{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ) ), new StaticMemoryTranslatorPlugin( diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala index b15d078..28843d8 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala @@ -43,8 +43,7 @@ object GenFullNoMmuMaxPerf extends App{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = false + catchUnaligned = true ) ), new StaticMemoryTranslatorPlugin( diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index bbd5ecd..cc0c5f7 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -96,76 +96,77 @@ object LinuxGen { new DummyFencePlugin(), //TODO should be removed for design with caches //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config -// new IBusSimplePlugin( -// resetVector = 0x80000000l, -// cmdForkOnSecondStage = false, -// cmdForkPersistence = false, -// prediction = NONE, -// historyRamSizeLog2 = 10, -// catchAccessFault = true, -// compressedGen = true, -// busLatencyMin = 1, -// injectorStage = true, -// memoryTranslatorPortConfig = withMmu generate MmuPortConfig( -// portTlbSize = 4 -// ) -// ), - - //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config - new IBusCachedPlugin( + new IBusSimplePlugin( resetVector = 0x80000000l, - compressedGen = true, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, prediction = NONE, - injectorStage = true, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = false, - twoCycleCache = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 - ) - ), - // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), - new DBusSimplePlugin( - catchAddressMisaligned = true, + historyRamSizeLog2 = 10, catchAccessFault = true, - earlyInjection = false, - atomicEntriesCount = 1, + compressedGen = true, + busLatencyMin = 1, + injectorStage = true, memoryTranslatorPortConfig = withMmu generate MmuPortConfig( portTlbSize = 4 ) ), - // new DBusCachedPlugin( - // config = new DataCacheConfig( - // cacheSize = 4096, - // bytePerLine = 32, - // wayCount = 1, - // addressWidth = 32, - // cpuDataWidth = 32, - // memDataWidth = 32, - // catchAccessError = true, - // catchIllegal = true, - // catchUnaligned = true, - // catchMemoryTranslationMiss = true, - // atomicEntriesCount = 2 - // ), - // // memoryTranslatorPortConfig = null - // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( - // portTlbSize = 6 - // ) - // ), - // new StaticMemoryTranslatorPlugin( - // ioRange = _(31 downto 28) === 0xF - // ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config +// new IBusCachedPlugin( +// resetVector = 0x80000000l, +// compressedGen = true, +// prediction = NONE, +// injectorStage = true, +// config = InstructionCacheConfig( +// cacheSize = 4096, +// bytePerLine = 32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchIllegalAccess = true, +// catchAccessFault = true, +// asyncTagMemory = false, +// twoCycleRam = false, +// twoCycleCache = true +// ) +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4 +// ) +// ), + // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), +// new DBusSimplePlugin( +// catchAddressMisaligned = true, +// catchAccessFault = true, +// earlyInjection = false, +// atomicEntriesCount = 1, +// memoryTranslatorPortConfig = withMmu generate MmuPortConfig( +// portTlbSize = 4 +// ) +// ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + atomicEntriesCount = 2 + ) +// ), + // memoryTranslatorPortConfig = null +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4 +// ) + ), + new StaticMemoryTranslatorPlugin( + ioRange = _(31 downto 28) === 0xF + ), // new MemoryTranslatorPlugin( // tlbSize = 32, // virtualRange = _(31 downto 28) === 0xC, @@ -237,12 +238,12 @@ object LinuxGen { new YamlPlugin("cpu0.yaml") ) ) - if(withMmu) config.plugins += new MmuPlugin( - virtualRange = a => True, - // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) - ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), - allowUserIo = true - ) +// if(withMmu) config.plugins += new MmuPlugin( +// virtualRange = a => True, +// // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) +// ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), +// allowUserIo = true +// ) config } @@ -265,7 +266,7 @@ object LinuxGen { // } // } - SpinalConfig(mergeAsyncProcess = true).generateVerilog { + SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "zz").generateVerilog { val toplevel = new VexRiscv(configFull( diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala index 84f90a4..4245cd1 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala @@ -66,8 +66,7 @@ object VexRiscvAvalonForSim{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala index 5621b2e..bba065e 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala @@ -63,8 +63,7 @@ object VexRiscvAvalonWithIntegratedJtag{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala index 37ad552..b002c06 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala @@ -64,8 +64,7 @@ object VexRiscvAxi4WithIntegratedJtag{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala index 422e819..2a83428 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala @@ -62,8 +62,7 @@ object VexRiscvCachedWishboneForSim{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 21f1c38..96dea4c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -8,23 +8,24 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ -case class DataCacheConfig( cacheSize : Int, - bytePerLine : Int, - wayCount : Int, - addressWidth : Int, - cpuDataWidth : Int, - memDataWidth : Int, - catchAccessError : Boolean, - catchIllegal : Boolean, - catchUnaligned : Boolean, - catchMemoryTranslationMiss : Boolean, - clearTagsAfterReset : Boolean = true, - waysHitRetime : Boolean = true, - tagSizeShift : Int = 0, //Used to force infering ram - atomicEntriesCount : Int = 0){ +case class DataCacheConfig(cacheSize : Int, + bytePerLine : Int, + wayCount : Int, + addressWidth : Int, + cpuDataWidth : Int, + memDataWidth : Int, + catchAccessError : Boolean, + catchIllegal : Boolean, + catchUnaligned : Boolean, + earlyWaysHits : Boolean = true, + earlyDataMux : Boolean = false, + tagSizeShift : Int = 0, //Used to force infering ram + atomicEntriesCount : Int = 0){ + + assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) - def catchSomething = catchUnaligned || catchMemoryTranslationMiss || catchIllegal || catchAccessError + def catchSomething = catchUnaligned || catchIllegal || catchAccessError def genAtomic = atomicEntriesCount != 0 def getAxi4SharedConfig() = Axi4Config( @@ -64,83 +65,6 @@ case class DataCacheConfig( cacheSize : Int, ) } - -object Bypasser{ - - //shot readValid path - def writeFirstMemWrap[T <: Data](readValid : Bool, readLastAddress : UInt, readLastData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = { - val writeSample = readValid || (writeValid && writeAddress === readLastAddress) - val writeValidReg = RegNextWhen(writeValid,writeSample) - val writeAddressReg = RegNextWhen(writeAddress,writeSample) - val writeDataReg = RegNextWhen(writeData,writeSample) - (writeValidReg && writeAddressReg === readLastAddress) ? writeDataReg | readLastData - } - - - //short readValid path - def writeFirstMemWrap(readValid : Bool, readLastAddress : UInt, readLastData : Bits,writeValid : Bool, writeAddress : UInt, writeData : Bits,writeMask : Bits) : Bits = { - val writeHit = writeValid && writeAddress === readLastAddress - val writeSample = readValid || writeHit - val writeValidReg = RegNextWhen(writeValid,writeSample) - val writeAddressReg = RegNextWhen(writeAddress,writeSample) - val writeDataReg = Reg(writeData) - val writeMaskReg = Reg(Bits(widthOf(writeData)/8 bits)) - val writeDataRegBytes = writeDataReg.subdivideIn(8 bits) - val writeDataBytes = writeData.subdivideIn(8 bits) - val ret = cloneOf(readLastData) - val retBytes = ret.subdivideIn(8 bits) - val readLastDataBytes = readLastData.subdivideIn(8 bits) - val writeRegHit = writeValidReg && writeAddressReg === readLastAddress - for(b <- writeMask.range){ - when(writeHit && writeMask(b)){ - writeMaskReg(b) := True - } - when(readValid) { - writeMaskReg(b) := writeMask(b) - } - when(readValid || (writeHit && writeMask(b))){ - writeDataRegBytes(b) := writeDataBytes(b) - } - - retBytes(b) := (writeRegHit && writeMaskReg(b)) ? writeDataRegBytes(b) | readLastDataBytes(b) - } - ret - } - - //Long sample path - // def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,lastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) : (T,T) = { - // val hit = writeValid && (sample ? sampleAddress | lastAddress) === writeAddress - // val bypass = hit ? writeData | readData - // val reg = RegNextWhen(bypass,sample || hit) - // (reg,bypass) - // } - - //Short sample path - def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, sampleData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = { - val bypass = (!sample || (writeValid && sampleAddress === writeAddress)) ? writeData | sampleData - val regEn = sample || (writeValid && sampleLastAddress === writeAddress) - val reg = RegNextWhen(bypass,regEn) - reg - } - - def writeFirstRegWrap(sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, sampleData : Bits, writeValid : Bool, writeAddress : UInt, writeData : Bits,writeMask : Bits) = { - val byteCount = widthOf(writeMask) - val sampleWriteHit = writeValid && sampleAddress === writeAddress - val sampleLastHit = writeValid && sampleLastAddress === writeAddress - val regBytes = Vec(Bits(8 bits),byteCount) - for(b <- writeMask.range){ - val bypass = Mux(!sample || (sampleWriteHit && writeMask(b)), writeData(b*8, 8 bits), sampleData(b*8, 8 bits)) - val regEn = sample || (sampleLastHit && writeMask(b)) - regBytes(b) := RegNextWhen(bypass,regEn) - } - regBytes.asBits - } -} - -object DataCacheCpuCmdKind extends SpinalEnum{ - val MEMORY,MANAGMENT = newElement() -} - object DataCacheCpuExecute{ implicit def implArgs(that : DataCacheCpuExecute) = that.args } @@ -148,23 +72,22 @@ object DataCacheCpuExecute{ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool val isStuck = Bool + val address = UInt(p.addressWidth bit) // val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) override def asMaster(): Unit = { - out(isValid, isStuck, args) + out(isValid, isStuck, args, address) // in(haltIt) } } case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ - val kind = DataCacheCpuCmdKind() val wr = Bool - val address = UInt(p.addressWidth bit) + //val address = UInt(p.addressWidth bit) Given on the side, as it's also part of the main pipeline val data = Bits(p.cpuDataWidth bit) val size = UInt(2 bits) val forceUncachedAccess = Bool - val clean, invalidate, way = Bool val isAtomic = ifGen(p.genAtomic){Bool} // val all = Bool //Address should be zero when "all" is used } @@ -173,12 +96,11 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl val isValid = Bool val isStuck = Bool val isRemoved = Bool - val haltIt = Bool + val address = UInt(p.addressWidth bit) val mmuBus = MemoryTranslatorBus() override def asMaster(): Unit = { - out(isValid, isStuck, isRemoved) - in(haltIt) + out(isValid, isStuck, isRemoved, address) slave(mmuBus) } } @@ -190,14 +112,15 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val isUser = Bool val haltIt = Bool val data = Bits(p.cpuDataWidth bit) - val mmuMiss, illegalAccess, unalignedAccess , accessError = Bool - val badAddr = UInt(32 bits) + val address = UInt(p.addressWidth bit) + val mmuException, unalignedAccess , accessError = Bool val clearAtomicEntries = ifGen(p.genAtomic) {Bool} + // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null override def asMaster(): Unit = { - out(isValid,isStuck,isUser) - in(haltIt, data, mmuMiss,illegalAccess , unalignedAccess, accessError, badAddr) + out(isValid,isStuck,isUser, address) + in(haltIt, data, mmuException, unalignedAccess, accessError) outWithNull(clearAtomicEntries) } } @@ -207,10 +130,13 @@ case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave val memory = DataCacheCpuMemory(p) val writeBack = DataCacheCpuWriteBack(p) + val redo = Bool() + override def asMaster(): Unit = { master(execute) master(memory) master(writeBack) + in(redo) } } @@ -370,7 +296,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave class DataCache(p : DataCacheConfig) extends Component{ import p._ - import DataCacheCpuCmdKind._ assert(wayCount == 1) assert(cpuDataWidth == memDataWidth) @@ -379,6 +304,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val mem = master(DataCacheMemBus(p)) // val flushDone = out Bool //It pulse at the same time than the manager.request.fire } + val haltCpu = False val lineWidth = bytePerLine*8 val lineCount = cacheSize/bytePerLine @@ -397,14 +323,13 @@ class DataCache(p : DataCacheConfig) extends Component{ class LineInfo() extends Bundle{ - val used = Bool - val dirty = Bool + val valid, error = Bool() val address = UInt(tagRange.length bit) } val tagsReadCmd = Flow(UInt(log2Up(wayLineCount) bits)) val tagsWriteCmd = Flow(new Bundle{ - // val way = UInt(log2Up(wayCount) bits) + val way = Bits(wayCount bits) val address = UInt(log2Up(wayLineCount) bits) val data = new LineInfo() }) @@ -413,13 +338,39 @@ class DataCache(p : DataCacheConfig) extends Component{ val dataReadCmd = Flow(UInt(log2Up(wayWordCount) bits)) val dataWriteCmd = Flow(new Bundle{ - // val way = UInt(log2Up(wayCount) bits) + val way = Bits(wayCount bits) val address = UInt(log2Up(wayWordCount) bits) val data = Bits(wordWidth bits) val mask = Bits(wordWidth/8 bits) }) + + io.mem.cmd.valid := False + io.mem.cmd.payload.assignDontCare() + + val ways = for(i <- 0 until wayCount) yield new Area{ + val tags = Mem(new LineInfo(), wayLineCount) + val data = Mem(Bits(wordWidth bit), wayWordCount) + + //Reads + val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.execute.isStuck) + val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.execute.isStuck) + + //Writes + when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ + tags(tagsWriteCmd.address) := tagsWriteCmd.data + } + when(dataWriteCmd.valid && dataWriteCmd.way(i)){ + data.write( + address = dataWriteCmd.address, + data = dataWriteCmd.data, + mask = dataWriteCmd.mask + ) + } + } + + tagsReadCmd.valid := False tagsReadCmd.payload.assignDontCare() dataReadCmd.valid := False @@ -428,219 +379,74 @@ class DataCache(p : DataCacheConfig) extends Component{ tagsWriteCmd.payload.assignDontCare() dataWriteCmd.valid := False dataWriteCmd.payload.assignDontCare() - io.mem.cmd.valid := False - io.mem.cmd.payload.assignDontCare() - - - val way = new Area{ - val tags = Mem(new LineInfo(),wayLineCount) - val data = Mem(Bits(wordWidth bit),wayWordCount) - - when(tagsWriteCmd.valid){ - tags(tagsWriteCmd.address) := tagsWriteCmd.data - } - when(dataWriteCmd.valid){ - data.write( - address = dataWriteCmd.address, - data = dataWriteCmd.data, - mask = dataWriteCmd.mask - ) - } - - val tagReadRspOneAddress = RegNextWhen(tagsReadCmd.payload, tagsReadCmd.valid) - val tagReadRspOne = Bypasser.writeFirstMemWrap( - readValid = tagsReadCmd.valid, - readLastAddress = tagReadRspOneAddress, - readLastData = tags.readSync(tagsReadCmd.payload,enable = tagsReadCmd.valid), - writeValid = tagsWriteCmd.valid, - writeAddress = tagsWriteCmd.address, - writeData = tagsWriteCmd.data - ) - - val dataReadRspOneKeepAddress = False - val dataReadRspOneAddress = RegNextWhen(dataReadCmd.payload, dataReadCmd.valid && !dataReadRspOneKeepAddress) - val dataReadRspOneWithoutBypass = data.readSync(dataReadCmd.payload,enable = dataReadCmd.valid) - val dataReadRspOne = Bypasser.writeFirstMemWrap( - readValid = dataReadCmd.valid, - readLastAddress = dataReadRspOneAddress, - readLastData = dataReadRspOneWithoutBypass, - writeValid = dataWriteCmd.valid, - writeAddress = dataWriteCmd.address, - writeData = dataWriteCmd.data, - writeMask = dataWriteCmd.mask - ) - - val tagReadRspTwoEnable = !io.cpu.writeBack.isStuck - val tagReadRspTwoRegIn = (tagsWriteCmd.valid && tagsWriteCmd.address === tagReadRspOneAddress) ? tagsWriteCmd.data | tagReadRspOne - val tagReadRspTwo = RegNextWhen(tagReadRspTwoRegIn ,tagReadRspTwoEnable) - - - val dataReadRspTwoEnable = !io.cpu.writeBack.isStuck - val dataReadRspTwo = Bypasser.writeFirstRegWrap( - sample = dataReadRspTwoEnable, - sampleAddress = dataReadRspOneAddress, - sampleLastAddress = RegNextWhen(dataReadRspOneAddress, dataReadRspTwoEnable), - sampleData = dataReadRspOne, - writeValid = dataWriteCmd.valid, - writeAddress = dataWriteCmd.address, - writeData = dataWriteCmd.data, - writeMask = dataWriteCmd.mask - ) - } when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){ - tagsReadCmd.valid := True + tagsReadCmd.valid := True + dataReadCmd.valid := True tagsReadCmd.payload := io.cpu.execute.address(lineRange) - - dataReadCmd.valid := True - dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) //TODO FMAX maybe critical path could be default + dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) } - - val cpuMemoryStageNeedReadData = Bool() - - val victim = new Area{ - val requestIn = Stream(cloneable(new Bundle{ - // val way = UInt(log2Up(wayCount) bits) - val address = UInt(p.addressWidth bits) - })) - requestIn.valid := False - requestIn.payload.assignDontCare() - - val request = requestIn.halfPipe() - request.ready := False - - val buffer = Mem(Bits(p.memDataWidth bits),memTransactionPerLine << tagSizeShift) // WARNING << tagSizeShift could resolve cyclone II issue, //.add(new AttributeString("ramstyle","M4K")) - - //Send line read commands to fill the buffer - val readLineCmdCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) - val dataReadCmdOccure = False - val dataReadRestored = RegInit(False) - when(request.valid){ - when(!readLineCmdCounter.msb) { - readLineCmdCounter := readLineCmdCounter + 1 - //dataReadCmd := request.address(lineRange.high downto wordRange.low) Done in the manager - dataReadCmdOccure := True - dataReadCmd.valid := True - dataReadCmd.payload := request.address(lineRange) @@ readLineCmdCounter(readLineCmdCounter.high - 1 downto 0) - way.dataReadRspOneKeepAddress := True - } otherwise { - when(!dataReadRestored && cpuMemoryStageNeedReadData) { - dataReadCmd.valid := True - dataReadCmd.payload := way.dataReadRspOneAddress //Restore stage one readed value - } - dataReadRestored := True - } - } - - dataReadRestored clearWhen(request.ready) - io.cpu.memory.haltIt := cpuMemoryStageNeedReadData && request.valid && !dataReadRestored - - //Fill the buffer with line read responses - val readLineRspCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) - when(Delay(dataReadCmdOccure,1, init=False)){ - buffer(readLineRspCounter.resized) := way.dataReadRspOneWithoutBypass - readLineRspCounter := readLineRspCounter + 1 - } - - //Send buffer read commands - val bufferReadCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) - val bufferReadStream = Stream(buffer.addressType) - bufferReadStream.valid := readLineRspCounter > bufferReadCounter - bufferReadStream.payload := bufferReadCounter.resized - when(bufferReadStream.fire){ - bufferReadCounter := bufferReadCounter + 1 - } - val bufferReaded = buffer.streamReadSync(bufferReadStream).stage - bufferReaded.ready := False - - //Send memory writes from bufffer read responses - val bufferReadedCounter = Reg(UInt(log2Up(memTransactionPerLine) bits)) init(0) - val memCmdAlreadyUsed = False - when(bufferReaded.valid) { - io.mem.cmd.valid := True - io.mem.cmd.wr := True - io.mem.cmd.address := request.address(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) - io.mem.cmd.length := p.burstLength-1 - io.mem.cmd.data := bufferReaded.payload - io.mem.cmd.mask := (1<<(wordWidth/8))-1 - io.mem.cmd.last := bufferReadedCounter === bufferReadedCounter.maxValue - - when(!memCmdAlreadyUsed && io.mem.cmd.ready){ - bufferReaded.ready := True - bufferReadedCounter := bufferReadedCounter + 1 - when(bufferReadedCounter === bufferReadedCounter.maxValue){ - request.ready := True - } - } - } - - - val counter = Counter(memTransactionPerLine) - when(request.ready){ - readLineCmdCounter.msb := False - readLineRspCounter.msb := False - bufferReadCounter.msb := False + def collisionProcess(readAddress : UInt, readMask : Bits): Bits ={ + val ret = Bits(wayCount bits) + for(i <- 0 until wayCount){ + ret(i) := dataWriteCmd.valid && dataWriteCmd.way(i) && dataWriteCmd.address === readAddress && (readMask & dataWriteCmd.mask) =/= 0 } + ret } - - - val stageA = new Area{ - val request = RegNextWhen(io.cpu.execute.args, !io.cpu.memory.isStuck) - io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid && request.kind === MEMORY //TODO filter request kind - io.cpu.memory.mmuBus.cmd.virtualAddress := request.address - io.cpu.memory.mmuBus.cmd.bypassTranslation := request.way - io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved - cpuMemoryStageNeedReadData := io.cpu.memory.isValid && request.kind === MEMORY && !request.wr - } - - val stageB = new Area { - val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) - val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck) - val waysHit = if(waysHitRetime) - RegNextWhen(way.tagReadRspTwoRegIn.used && io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming - else - way.tagReadRspTwo.used && mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwo.address - - - //Loader interface - val loaderValid = False - val loaderReady = False - val loadingDone = RegNext(loaderValid && loaderReady) init(False) //one cycle pulse - - //delayedXX are used to relax logic timings in flush and evict modes - val delayedIsStuck = RegNext(io.cpu.writeBack.isStuck) - val delayedWaysHitValid = RegNext(waysHit) - - val victimNotSent = RegInit(False) clearWhen(victim.requestIn.ready) setWhen(!io.cpu.memory.isStuck) - val loadingNotDone = RegInit(False) clearWhen(loaderReady) setWhen(!io.cpu.memory.isStuck) - - val writeMask = request.size.mux ( + val stage0 = new Area{ + val mask = io.cpu.execute.size.mux ( U(0) -> B"0001", U(1) -> B"0011", default -> B"1111" - ) |<< mmuRsp.physicalAddress(1 downto 0) + ) |<< io.cpu.execute.address(1 downto 0) + val colisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) + } + + val stageA = new Area{ + def stagePipe[T <: Data](that : T) = 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 + io.cpu.memory.mmuBus.cmd.virtualAddress := io.cpu.memory.address + io.cpu.memory.mmuBus.cmd.bypassTranslation := False + io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved + + 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 stageB = new Area { + def stagePipe[T <: Data](that : T) = 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 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) + val mask = stagePipe(stageA.mask) + val colisions = stagePipe(stageA.colisions) + + //Loader interface + val loaderValid = False + - val hadMemRspErrorReg = RegInit(False) - val hadMemRspError = (io.mem.rsp.valid && io.mem.rsp.error) || hadMemRspErrorReg - hadMemRspErrorReg := hadMemRspError && io.cpu.writeBack.haltIt io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid - io.cpu.writeBack.mmuMiss := False - io.cpu.writeBack.illegalAccess := False - io.cpu.writeBack.unalignedAccess := False - io.cpu.writeBack.accessError := (if(catchAccessError) hadMemRspError && !io.cpu.writeBack.haltIt else False) - io.cpu.writeBack.badAddr := request.address //Evict the cache after reset logics - val bootEvicts = if(clearTagsAfterReset) new Area { + val flusher = new Area { val valid = RegInit(True) mmuRsp.physicalAddress init (0) when(valid) { tagsWriteCmd.valid := valid tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) - tagsWriteCmd.data.used := False + tagsWriteCmd.way.setAll() + tagsWriteCmd.data.valid := False when(mmuRsp.physicalAddress(lineRange) =/= lineCount - 1) { mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 io.cpu.writeBack.haltIt := True @@ -651,7 +457,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } - val atomic = if(genAtomic) new Area{ + val atomic = genAtomic generate new Area{ case class AtomicEntry() extends Bundle{ val valid = Bool() val size = UInt(2 bits) @@ -664,11 +470,11 @@ class DataCache(p : DataCacheConfig) extends Component{ } val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount) val entriesAllocCounter = Counter(atomicEntriesCount) - val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === request.address).orR + val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === io.cpu.writeBack.address).orR when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){ entries(entriesAllocCounter).valid := True - entries(entriesAllocCounter).size := request.size - entries(entriesAllocCounter).address := request.address + entries(entriesAllocCounter).size := request.size //TODO remove size stuff + entries(entriesAllocCounter).address := io.cpu.writeBack.address when(!io.cpu.writeBack.isStuck){ entriesAllocCounter.increment() } @@ -676,128 +482,127 @@ class DataCache(p : DataCacheConfig) extends Component{ when(io.cpu.writeBack.clearAtomicEntries){ entries.foreach(_.valid := False) } + } + + val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) + + io.cpu.redo := mmuRsp.refilling + io.cpu.writeBack.accessError := False + io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) || (!mmuRsp.allowUser && io.cpu.writeBack.isUser) else False) + io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) - when(request.isAtomic && ! entriesHit){ - writeMask := 0 - } - } else null when(io.cpu.writeBack.isValid) { - if (catchMemoryTranslationMiss) { - io.cpu.writeBack.mmuMiss := ??? //TODO mmuRsp.miss - } - switch(request.kind) { - is(MANAGMENT) { - when(delayedIsStuck && ???){ //TODO!mmuRsp.miss) { - when(delayedWaysHitValid || (request.way && way.tagReadRspTwo.used)) { - io.cpu.writeBack.haltIt.clearWhen(!(victim.requestIn.valid && !victim.requestIn.ready)) - victim.requestIn.valid := request.clean && way.tagReadRspTwo.dirty - tagsWriteCmd.valid := victim.requestIn.ready - } otherwise{ - io.cpu.writeBack.haltIt := False - } - } + when(request.forceUncachedAccess || mmuRsp.isIoAccess) { + io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid) - victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) - tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) - tagsWriteCmd.data.used := !request.invalidate - tagsWriteCmd.data.dirty := !request.clean - } - is(MEMORY) { - val illegal = if(catchIllegal) (request.wr && !mmuRsp.allowWrite) || (!request.wr && !mmuRsp.allowRead) || (io.cpu.writeBack.isUser && !mmuRsp.allowUser) else False - val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False - io.cpu.writeBack.illegalAccess := illegal - io.cpu.writeBack.unalignedAccess := unaligned - when((Bool(!catchMemoryTranslationMiss) || ???) && !illegal && !unaligned) { //TODO !mmuRsp.miss - when(request.forceUncachedAccess || mmuRsp.isIoAccess) { - val memCmdSent = RegInit(False) - when(!victim.request.valid) { - //Avoid mixing memory request while victim is pending - io.mem.cmd.wr := request.wr - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) - io.mem.cmd.mask := writeMask - io.mem.cmd.data := request.data - io.mem.cmd.length := 0 - io.mem.cmd.last := True + io.mem.cmd.valid := !memCmdSent + io.mem.cmd.wr := request.wr + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.mask := mask + io.mem.cmd.data := request.data + io.mem.cmd.length := 0 + io.mem.cmd.last := True + } otherwise { + when(waysHit || request.wr) { //Do not require a cache refill ? + //Data cache update + dataWriteCmd.valid setWhen(request.wr && waysHit) + dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) + dataWriteCmd.data := request.data + dataWriteCmd.mask := mask + dataWriteCmd.way := waysHits - when(!memCmdSent) { - io.mem.cmd.valid := True - memCmdSent setWhen (io.mem.cmd.ready) - } + //Write through + io.mem.cmd.valid setWhen(request.wr) + io.mem.cmd.wr := True + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.mask := mask + io.mem.cmd.data := request.data + io.mem.cmd.length := 0 + io.mem.cmd.last := True + io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) - io.cpu.writeBack.haltIt.clearWhen(memCmdSent && (io.mem.rsp.fire || request.wr)) //Cut mem.cmd.ready path but insert one cycle stall when write - } - memCmdSent clearWhen (!io.cpu.writeBack.isStuck) - } otherwise { - when(waysHit || !loadingNotDone) { - io.cpu.writeBack.haltIt := False - dataWriteCmd.valid := request.wr - dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) - dataWriteCmd.data := request.data - dataWriteCmd.mask := writeMask + //On write to read colisions + io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0 + } otherwise { //Do refill - tagsWriteCmd.valid := (!loadingNotDone) || request.wr - tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) - tagsWriteCmd.data.used := True - tagsWriteCmd.data.dirty := request.wr - tagsWriteCmd.data.address := mmuRsp.physicalAddress(tagRange) - } otherwise { - val victimRequired = way.tagReadRspTwo.used && way.tagReadRspTwo.dirty - loaderValid := loadingNotDone && !(victimNotSent && victim.request.isStall) //Additional condition used to be sure of that all previous victim are written into the RAM - victim.requestIn.valid := victimRequired && victimNotSent - victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) - } - } - } + //Emit cmd + io.mem.cmd.valid setWhen(!memCmdSent) + io.mem.cmd.wr := False + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) + io.mem.cmd.length := p.burstLength-1 + io.mem.cmd.last := True + + loaderValid setWhen(io.mem.cmd.ready) } } } + when(request.forceUncachedAccess || mmuRsp.isIoAccess){ + io.cpu.writeBack.data := io.mem.rsp.data + if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error + } otherwise { + io.cpu.writeBack.data := dataMux + if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 + } + + //remove side effects on exceptions + when(mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ + io.mem.cmd.valid := False + tagsWriteCmd.valid := False + dataWriteCmd.valid := False + loaderValid := False + io.cpu.writeBack.haltIt := False + } assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") - io.cpu.writeBack.data := (request.forceUncachedAccess || mmuRsp.isIoAccess) ? io.mem.rsp.data | way.dataReadRspTwo //not multi ways + if(genAtomic){ when(request.isAtomic && request.wr){ io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized } + when(request.isAtomic && !atomic.entriesHit){ + io.mem.cmd.mask := 0 + } } } - //The whole life of a loading task, the corresponding manager request is present val loader = new Area{ - val valid = RegNext(stageB.loaderValid) init(False) + val valid = RegInit(False) setWhen(stageB.loaderValid) val baseAddress = stageB.mmuRsp.physicalAddress - val memCmdSent = RegInit(False) - when(valid && !memCmdSent) { - io.mem.cmd.valid := True - io.mem.cmd.wr := False - io.mem.cmd.address := baseAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) - io.mem.cmd.length := p.burstLength-1 - io.mem.cmd.last := True - } - - when(valid && io.mem.cmd.ready){ - memCmdSent := True - } - - when(valid && !memCmdSent) { - victim.memCmdAlreadyUsed := True - } - val counter = Counter(memTransactionPerLine) + val waysAllocator = Reg(Bits(wayCount bits)) init(1) + val error = RegInit(False) + when(valid && io.mem.rsp.valid){ dataWriteCmd.valid := True dataWriteCmd.address := baseAddress(lineRange) @@ counter dataWriteCmd.data := io.mem.rsp.data - dataWriteCmd.mask := (1<<(wordWidth/8))-1 + dataWriteCmd.mask.setAll() + dataWriteCmd.way := waysAllocator + error := error | io.mem.rsp.error counter.increment() } + when(counter.willOverflow){ - memCmdSent := False valid := False - stageB.loaderReady := True + + //Update tags + tagsWriteCmd.valid := True + tagsWriteCmd.address := baseAddress(lineRange) + tagsWriteCmd.data.valid := True + tagsWriteCmd.data.address := baseAddress(tagRange) + tagsWriteCmd.data.error := error || io.mem.rsp.error + tagsWriteCmd.way := waysAllocator + + waysAllocator := (waysAllocator ## waysAllocator.msb).resized + + error := False } + + io.cpu.redo setWhen(valid) + stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid) } } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index b5eca04..c62984a 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -26,6 +26,7 @@ class DBusCachedPlugin(config : DataCacheConfig, var mmuBus : MemoryTranslatorBus = null var exceptionBus : Flow[ExceptionCause] = null var privilegeService : PrivilegeService = null + var redoBranch : Flow[UInt] = null object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_MANAGMENT extends Stageable(Bool) @@ -44,7 +45,7 @@ class DBusCachedPlugin(config : DataCacheConfig, SRC_USE_SUB_LESS -> False, MEMORY_ENABLE -> True, RS1_USE -> True - ) ++ (if (catchUnaligned) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage + ) ++ (if (catchSomething) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage val loadActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMI, @@ -75,13 +76,14 @@ class DBusCachedPlugin(config : DataCacheConfig, decoderService.add( key = LR, values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq( - SRC2_CTRL -> Src2CtrlEnum.RS, + SRC_ADD_ZERO -> True, MEMORY_ATOMIC -> True ) ) decoderService.add( key = SC, values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( + SRC_ADD_ZERO -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, @@ -98,6 +100,7 @@ class DBusCachedPlugin(config : DataCacheConfig, )) mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.writeBack) if(catchSomething) exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) @@ -141,28 +144,27 @@ class DBusCachedPlugin(config : DataCacheConfig, val size = input(INSTRUCTION)(13 downto 12).asUInt cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.execute.isStuck := arbitration.isStuck + cache.io.cpu.execute.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.wr := input(MEMORY_WR) - cache.io.cpu.execute.args.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.data := size.mux( U(0) -> input(RS2)( 7 downto 0) ## input(RS2)( 7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0), U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0), default -> input(RS2)(31 downto 0) ) cache.io.cpu.execute.args.size := size - cache.io.cpu.execute.args.forceUncachedAccess := False - cache.io.cpu.execute.args.kind := input(MEMORY_MANAGMENT) ? DataCacheCpuCmdKind.MANAGMENT | DataCacheCpuCmdKind.MEMORY - cache.io.cpu.execute.args.clean := input(INSTRUCTION)(28) - cache.io.cpu.execute.args.invalidate := input(INSTRUCTION)(29) - cache.io.cpu.execute.args.way := input(INSTRUCTION)(30) + cache.io.cpu.execute.args.forceUncachedAccess := False if(genAtomic) { cache.io.cpu.execute.args.isAtomic := False when(input(MEMORY_ATOMIC)){ cache.io.cpu.execute.args.isAtomic := True - cache.io.cpu.execute.args.address := input(SRC1).asUInt } } - insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.args.address(1 downto 0) + insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.address(1 downto 0) + + when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){ + arbitration.haltItself := True + } } memory plug new Area{ @@ -170,10 +172,9 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt) + cache.io.cpu.memory.address := U(input(REGFILE_WRITE_DATA)) cache.io.cpu.memory.mmuBus <> mmuBus - arbitration.haltItself setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss } writeBack plug new Area{ @@ -181,20 +182,36 @@ class DBusCachedPlugin(config : DataCacheConfig, 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) + cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) if(genAtomic) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching if(catchSomething) { - exceptionBus.valid := cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess - exceptionBus.badAddr := cache.io.cpu.writeBack.badAddr + exceptionBus.valid := False //cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess + exceptionBus.badAddr := U(input(REGFILE_WRITE_DATA)) exceptionBus.code.assignDontCare() - when(cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError){ - exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized - } - when(cache.io.cpu.writeBack.unalignedAccess){ - exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized - } - when(cache.io.cpu.writeBack.mmuMiss){ - exceptionBus.code := 13 + + redoBranch.valid := False + redoBranch.payload := input(PC) + arbitration.flushAll setWhen(redoBranch.valid) + + when(cache.io.cpu.writeBack.isValid) { + if (catchAccessError) when(cache.io.cpu.writeBack.accessError) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized + } + + if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized + } + when (cache.io.cpu.writeBack.mmuException) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized + } + when(cache.io.cpu.redo) { + redoBranch.valid := True + exceptionBus.valid := False + } } } arbitration.haltItself.setWhen(cache.io.cpu.writeBack.haltIt) diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index d190ef0..a2a6bbc 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -33,9 +33,8 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis port.bus.rsp.allowExecute := True port.bus.rsp.allowUser := True port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - ??? -// port.bus.rsp.miss := False -// port.bus.rsp.hit := True + port.bus.rsp.exception := False + port.bus.rsp.refilling := False } } } diff --git a/src/test/cpp/regression/fail.gtkw b/src/test/cpp/regression/fail.gtkw index 788713e..be47402 100644 --- a/src/test/cpp/regression/fail.gtkw +++ b/src/test/cpp/regression/fail.gtkw @@ -1,19 +1,19 @@ [*] [*] GTKWave Analyzer v3.3.100 (w)1999-2019 BSI -[*] Sat Mar 30 09:33:33 2019 +[*] Mon Apr 1 21:53:07 2019 [*] -[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/linux.vcd" -[dumpfile_mtime] "Sat Mar 30 09:16:30 2019" -[dumpfile_size] 249834424 +[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/rv32ui-p-lw.vcd" +[dumpfile_mtime] "Mon Apr 1 21:52:20 2019" +[dumpfile_size] 1974526 [savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw" -[timestart] 106663042 +[timestart] 348 [size] 1920 1030 -[pos] -458 -215 -*-5.000000 106541900 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[pos] -1 -1 +*-2.000000 357 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. [treeopen] TOP.VexRiscv. [sst_width] 287 -[signals_width] 465 +[signals_width] 563 [sst_expanded] 1 [sst_vpaned_height] 279 @28 @@ -21,43 +21,37 @@ TOP.VexRiscv.writeBack_arbitration_isFiring @22 TOP.VexRiscv.writeBack_PC[31:0] TOP.VexRiscv.writeBack_INSTRUCTION[31:0] +TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_address[4:0] +TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_data[31:0] @28 -TOP.VexRiscv.CsrPlugin_exception -TOP.VexRiscv.CsrPlugin_privilege[1:0] +TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_valid +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_valid +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_ready @22 -TOP.VexRiscv.CsrPlugin_scause_exceptionCode[3:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_address[31:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_data[31:0] @28 -TOP.VexRiscv.CsrPlugin_scause_interrupt +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_last +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_length[2:0] @22 -TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_payload[31:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_mask[3:0] @28 -TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_valid +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_wr +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_rsp_valid @22 -TOP.VexRiscv.CsrPlugin_mepc[31:0] -TOP.VexRiscv.CsrPlugin_sepc[31:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_data[31:0] @28 -TOP.VexRiscv.decode_IS_RVC -@24 -TOP.VexRiscv.CsrPlugin_mcycle[63:0] -@28 -TOP.VexRiscv.decode_IS_RVC -TOP.VexRiscv.decode_arbitration_isValid -@22 -TOP.VexRiscv.RegFilePlugin_regFile(10)[31:0] -@28 -TOP.dBus_cmd_valid -TOP.dBus_cmd_ready -@22 -TOP.dBus_cmd_payload_address[31:0] -@28 -TOP.dBus_cmd_payload_wr -@29 -TOP.dBus_cmd_payload_size[1:0] -@22 -TOP.dBus_cmd_payload_data[31:0] -TOP.dBus_rsp_data[31:0] -@28 -TOP.dBus_rsp_error -TOP.dBus_rsp_ready +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_error [pattern_trace] 1 [pattern_trace] 0 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 1101157..82c5429 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3446,6 +3446,7 @@ int main(int argc, char **argv, char **env) { // redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); // return 0; + for(int idx = 0;idx < 1;idx++){ #if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 8e85c60..9be96b4 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -366,7 +366,6 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchAccessError = catchAll, catchIllegal = catchAll, catchUnaligned = catchAll, - catchMemoryTranslationMiss = catchAll, atomicEntriesCount = 0 ), memoryTranslatorPortConfig = null