#60 Got the new instruction cache design passing the standard regressions
This commit is contained in:
parent
bc0af02c97
commit
fd4da77084
|
@ -21,7 +21,7 @@ trait Pipeline {
|
||||||
|
|
||||||
def service[T](clazz : Class[T]) = {
|
def service[T](clazz : Class[T]) = {
|
||||||
val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass))
|
val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass))
|
||||||
assert(filtered.length == 1)
|
assert(filtered.length == 1, s"??? ${clazz.getName}")
|
||||||
filtered.head.asInstanceOf[T]
|
filtered.head.asInstanceOf[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,6 @@ object TestsWorkspace {
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true,
|
||||||
catchMemoryTranslationMiss = true,
|
|
||||||
atomicEntriesCount = 2
|
atomicEntriesCount = 2
|
||||||
),
|
),
|
||||||
// memoryTranslatorPortConfig = null
|
// memoryTranslatorPortConfig = null
|
||||||
|
|
|
@ -88,8 +88,7 @@ object BrieyConfig{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = null
|
memoryTranslatorPortConfig = null
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -41,8 +41,7 @@ object GenFull extends App{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
portTlbSize = 6
|
portTlbSize = 6
|
||||||
|
|
|
@ -42,8 +42,7 @@ object GenFullNoMmu extends App{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new StaticMemoryTranslatorPlugin(
|
new StaticMemoryTranslatorPlugin(
|
||||||
|
|
|
@ -43,8 +43,7 @@ object GenFullNoMmuMaxPerf extends App{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = false
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new StaticMemoryTranslatorPlugin(
|
new StaticMemoryTranslatorPlugin(
|
||||||
|
|
|
@ -96,76 +96,77 @@ object LinuxGen {
|
||||||
new DummyFencePlugin(), //TODO should be removed for design with caches
|
new DummyFencePlugin(), //TODO should be removed for design with caches
|
||||||
|
|
||||||
//Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config
|
//Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config
|
||||||
// new IBusSimplePlugin(
|
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(
|
||||||
// resetVector = 0x80000000l,
|
// resetVector = 0x80000000l,
|
||||||
// cmdForkOnSecondStage = false,
|
|
||||||
// cmdForkPersistence = false,
|
|
||||||
// prediction = NONE,
|
|
||||||
// historyRamSizeLog2 = 10,
|
|
||||||
// catchAccessFault = true,
|
|
||||||
// compressedGen = true,
|
// compressedGen = true,
|
||||||
// busLatencyMin = 1,
|
// prediction = NONE,
|
||||||
// injectorStage = true,
|
// 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(
|
// memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
|
||||||
// portTlbSize = 4
|
// portTlbSize = 4
|
||||||
// )
|
// )
|
||||||
// ),
|
// ),
|
||||||
|
new DBusCachedPlugin(
|
||||||
//Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config
|
config = new DataCacheConfig(
|
||||||
new IBusCachedPlugin(
|
|
||||||
resetVector = 0x80000000l,
|
|
||||||
compressedGen = true,
|
|
||||||
prediction = NONE,
|
|
||||||
injectorStage = true,
|
|
||||||
config = InstructionCacheConfig(
|
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine = 32,
|
bytePerLine = 32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchIllegalAccess = true,
|
catchAccessError = true,
|
||||||
catchAccessFault = true,
|
catchIllegal = true,
|
||||||
asyncTagMemory = false,
|
catchUnaligned = true,
|
||||||
twoCycleRam = false,
|
atomicEntriesCount = 2
|
||||||
twoCycleCache = true
|
|
||||||
),
|
|
||||||
memoryTranslatorPortConfig = MmuPortConfig(
|
|
||||||
portTlbSize = 4
|
|
||||||
)
|
)
|
||||||
|
// ),
|
||||||
|
// memoryTranslatorPortConfig = null
|
||||||
|
// memoryTranslatorPortConfig = MmuPortConfig(
|
||||||
|
// portTlbSize = 4
|
||||||
|
// )
|
||||||
),
|
),
|
||||||
// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))),
|
new StaticMemoryTranslatorPlugin(
|
||||||
new DBusSimplePlugin(
|
ioRange = _(31 downto 28) === 0xF
|
||||||
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,
|
|
||||||
// catchMemoryTranslationMiss = true,
|
|
||||||
// atomicEntriesCount = 2
|
|
||||||
// ),
|
|
||||||
// // memoryTranslatorPortConfig = null
|
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
|
||||||
// portTlbSize = 6
|
|
||||||
// )
|
|
||||||
// ),
|
|
||||||
// new StaticMemoryTranslatorPlugin(
|
|
||||||
// ioRange = _(31 downto 28) === 0xF
|
|
||||||
// ),
|
|
||||||
// new MemoryTranslatorPlugin(
|
// new MemoryTranslatorPlugin(
|
||||||
// tlbSize = 32,
|
// tlbSize = 32,
|
||||||
// virtualRange = _(31 downto 28) === 0xC,
|
// virtualRange = _(31 downto 28) === 0xC,
|
||||||
|
@ -237,12 +238,12 @@ object LinuxGen {
|
||||||
new YamlPlugin("cpu0.yaml")
|
new YamlPlugin("cpu0.yaml")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if(withMmu) config.plugins += new MmuPlugin(
|
// if(withMmu) config.plugins += new MmuPlugin(
|
||||||
virtualRange = a => True,
|
// virtualRange = a => True,
|
||||||
// virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround)
|
// // 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),
|
// 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
|
// allowUserIo = true
|
||||||
)
|
// )
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +266,7 @@ object LinuxGen {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
SpinalConfig(mergeAsyncProcess = true).generateVerilog {
|
SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "zz").generateVerilog {
|
||||||
|
|
||||||
|
|
||||||
val toplevel = new VexRiscv(configFull(
|
val toplevel = new VexRiscv(configFull(
|
||||||
|
|
|
@ -66,8 +66,7 @@ object VexRiscvAvalonForSim{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = null
|
memoryTranslatorPortConfig = null
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -63,8 +63,7 @@ object VexRiscvAvalonWithIntegratedJtag{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = null
|
memoryTranslatorPortConfig = null
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -64,8 +64,7 @@ object VexRiscvAxi4WithIntegratedJtag{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = null
|
memoryTranslatorPortConfig = null
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -62,8 +62,7 @@ object VexRiscvCachedWishboneForSim{
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
catchAccessError = true,
|
catchAccessError = true,
|
||||||
catchIllegal = true,
|
catchIllegal = true,
|
||||||
catchUnaligned = true,
|
catchUnaligned = true
|
||||||
catchMemoryTranslationMiss = true
|
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = null
|
memoryTranslatorPortConfig = null
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -8,7 +8,7 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||||
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
||||||
import spinal.lib.bus.simple._
|
import spinal.lib.bus.simple._
|
||||||
|
|
||||||
case class DataCacheConfig( cacheSize : Int,
|
case class DataCacheConfig(cacheSize : Int,
|
||||||
bytePerLine : Int,
|
bytePerLine : Int,
|
||||||
wayCount : Int,
|
wayCount : Int,
|
||||||
addressWidth : Int,
|
addressWidth : Int,
|
||||||
|
@ -17,14 +17,15 @@ case class DataCacheConfig( cacheSize : Int,
|
||||||
catchAccessError : Boolean,
|
catchAccessError : Boolean,
|
||||||
catchIllegal : Boolean,
|
catchIllegal : Boolean,
|
||||||
catchUnaligned : Boolean,
|
catchUnaligned : Boolean,
|
||||||
catchMemoryTranslationMiss : Boolean,
|
earlyWaysHits : Boolean = true,
|
||||||
clearTagsAfterReset : Boolean = true,
|
earlyDataMux : Boolean = false,
|
||||||
waysHitRetime : Boolean = true,
|
|
||||||
tagSizeShift : Int = 0, //Used to force infering ram
|
tagSizeShift : Int = 0, //Used to force infering ram
|
||||||
atomicEntriesCount : Int = 0){
|
atomicEntriesCount : Int = 0){
|
||||||
|
|
||||||
|
assert(!(earlyDataMux && !earlyWaysHits))
|
||||||
def burstSize = bytePerLine*8/memDataWidth
|
def burstSize = bytePerLine*8/memDataWidth
|
||||||
val burstLength = bytePerLine/(memDataWidth/8)
|
val burstLength = bytePerLine/(memDataWidth/8)
|
||||||
def catchSomething = catchUnaligned || catchMemoryTranslationMiss || catchIllegal || catchAccessError
|
def catchSomething = catchUnaligned || catchIllegal || catchAccessError
|
||||||
def genAtomic = atomicEntriesCount != 0
|
def genAtomic = atomicEntriesCount != 0
|
||||||
|
|
||||||
def getAxi4SharedConfig() = Axi4Config(
|
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{
|
object DataCacheCpuExecute{
|
||||||
implicit def implArgs(that : DataCacheCpuExecute) = that.args
|
implicit def implArgs(that : DataCacheCpuExecute) = that.args
|
||||||
}
|
}
|
||||||
|
@ -148,23 +72,22 @@ object DataCacheCpuExecute{
|
||||||
case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||||
val isValid = Bool
|
val isValid = Bool
|
||||||
val isStuck = Bool
|
val isStuck = Bool
|
||||||
|
val address = UInt(p.addressWidth bit)
|
||||||
// val haltIt = Bool
|
// val haltIt = Bool
|
||||||
val args = DataCacheCpuExecuteArgs(p)
|
val args = DataCacheCpuExecuteArgs(p)
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid, isStuck, args)
|
out(isValid, isStuck, args, address)
|
||||||
// in(haltIt)
|
// in(haltIt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{
|
case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{
|
||||||
val kind = DataCacheCpuCmdKind()
|
|
||||||
val wr = Bool
|
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 data = Bits(p.cpuDataWidth bit)
|
||||||
val size = UInt(2 bits)
|
val size = UInt(2 bits)
|
||||||
val forceUncachedAccess = Bool
|
val forceUncachedAccess = Bool
|
||||||
val clean, invalidate, way = Bool
|
|
||||||
val isAtomic = ifGen(p.genAtomic){Bool}
|
val isAtomic = ifGen(p.genAtomic){Bool}
|
||||||
// val all = Bool //Address should be zero when "all" is used
|
// 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 isValid = Bool
|
||||||
val isStuck = Bool
|
val isStuck = Bool
|
||||||
val isRemoved = Bool
|
val isRemoved = Bool
|
||||||
val haltIt = Bool
|
val address = UInt(p.addressWidth bit)
|
||||||
val mmuBus = MemoryTranslatorBus()
|
val mmuBus = MemoryTranslatorBus()
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid, isStuck, isRemoved)
|
out(isValid, isStuck, isRemoved, address)
|
||||||
in(haltIt)
|
|
||||||
slave(mmuBus)
|
slave(mmuBus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,14 +112,15 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste
|
||||||
val isUser = Bool
|
val isUser = Bool
|
||||||
val haltIt = Bool
|
val haltIt = Bool
|
||||||
val data = Bits(p.cpuDataWidth bit)
|
val data = Bits(p.cpuDataWidth bit)
|
||||||
val mmuMiss, illegalAccess, unalignedAccess , accessError = Bool
|
val address = UInt(p.addressWidth bit)
|
||||||
val badAddr = UInt(32 bits)
|
val mmuException, unalignedAccess , accessError = Bool
|
||||||
val clearAtomicEntries = ifGen(p.genAtomic) {Bool}
|
val clearAtomicEntries = ifGen(p.genAtomic) {Bool}
|
||||||
|
|
||||||
// val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null
|
// val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid,isStuck,isUser)
|
out(isValid,isStuck,isUser, address)
|
||||||
in(haltIt, data, mmuMiss,illegalAccess , unalignedAccess, accessError, badAddr)
|
in(haltIt, data, mmuException, unalignedAccess, accessError)
|
||||||
outWithNull(clearAtomicEntries)
|
outWithNull(clearAtomicEntries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,10 +130,13 @@ case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave
|
||||||
val memory = DataCacheCpuMemory(p)
|
val memory = DataCacheCpuMemory(p)
|
||||||
val writeBack = DataCacheCpuWriteBack(p)
|
val writeBack = DataCacheCpuWriteBack(p)
|
||||||
|
|
||||||
|
val redo = Bool()
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
master(execute)
|
master(execute)
|
||||||
master(memory)
|
master(memory)
|
||||||
master(writeBack)
|
master(writeBack)
|
||||||
|
in(redo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +296,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
|
||||||
|
|
||||||
class DataCache(p : DataCacheConfig) extends Component{
|
class DataCache(p : DataCacheConfig) extends Component{
|
||||||
import p._
|
import p._
|
||||||
import DataCacheCpuCmdKind._
|
|
||||||
assert(wayCount == 1)
|
assert(wayCount == 1)
|
||||||
assert(cpuDataWidth == memDataWidth)
|
assert(cpuDataWidth == memDataWidth)
|
||||||
|
|
||||||
|
@ -379,6 +304,7 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val mem = master(DataCacheMemBus(p))
|
val mem = master(DataCacheMemBus(p))
|
||||||
// val flushDone = out Bool //It pulse at the same time than the manager.request.fire
|
// val flushDone = out Bool //It pulse at the same time than the manager.request.fire
|
||||||
}
|
}
|
||||||
|
|
||||||
val haltCpu = False
|
val haltCpu = False
|
||||||
val lineWidth = bytePerLine*8
|
val lineWidth = bytePerLine*8
|
||||||
val lineCount = cacheSize/bytePerLine
|
val lineCount = cacheSize/bytePerLine
|
||||||
|
@ -397,14 +323,13 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
|
|
||||||
|
|
||||||
class LineInfo() extends Bundle{
|
class LineInfo() extends Bundle{
|
||||||
val used = Bool
|
val valid, error = Bool()
|
||||||
val dirty = Bool
|
|
||||||
val address = UInt(tagRange.length bit)
|
val address = UInt(tagRange.length bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
val tagsReadCmd = Flow(UInt(log2Up(wayLineCount) bits))
|
val tagsReadCmd = Flow(UInt(log2Up(wayLineCount) bits))
|
||||||
val tagsWriteCmd = Flow(new Bundle{
|
val tagsWriteCmd = Flow(new Bundle{
|
||||||
// val way = UInt(log2Up(wayCount) bits)
|
val way = Bits(wayCount bits)
|
||||||
val address = UInt(log2Up(wayLineCount) bits)
|
val address = UInt(log2Up(wayLineCount) bits)
|
||||||
val data = new LineInfo()
|
val data = new LineInfo()
|
||||||
})
|
})
|
||||||
|
@ -413,13 +338,39 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
|
|
||||||
val dataReadCmd = Flow(UInt(log2Up(wayWordCount) bits))
|
val dataReadCmd = Flow(UInt(log2Up(wayWordCount) bits))
|
||||||
val dataWriteCmd = Flow(new Bundle{
|
val dataWriteCmd = Flow(new Bundle{
|
||||||
// val way = UInt(log2Up(wayCount) bits)
|
val way = Bits(wayCount bits)
|
||||||
val address = UInt(log2Up(wayWordCount) bits)
|
val address = UInt(log2Up(wayWordCount) bits)
|
||||||
val data = Bits(wordWidth bits)
|
val data = Bits(wordWidth bits)
|
||||||
val mask = Bits(wordWidth/8 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.valid := False
|
||||||
tagsReadCmd.payload.assignDontCare()
|
tagsReadCmd.payload.assignDontCare()
|
||||||
dataReadCmd.valid := False
|
dataReadCmd.valid := False
|
||||||
|
@ -428,219 +379,74 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
tagsWriteCmd.payload.assignDontCare()
|
tagsWriteCmd.payload.assignDontCare()
|
||||||
dataWriteCmd.valid := False
|
dataWriteCmd.valid := False
|
||||||
dataWriteCmd.payload.assignDontCare()
|
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){
|
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)
|
tagsReadCmd.payload := io.cpu.execute.address(lineRange)
|
||||||
|
dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low)
|
||||||
dataReadCmd.valid := True
|
|
||||||
dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) //TODO FMAX maybe critical path could be default
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def collisionProcess(readAddress : UInt, readMask : Bits): Bits ={
|
||||||
val cpuMemoryStageNeedReadData = Bool()
|
val ret = Bits(wayCount bits)
|
||||||
|
for(i <- 0 until wayCount){
|
||||||
val victim = new Area{
|
ret(i) := dataWriteCmd.valid && dataWriteCmd.way(i) && dataWriteCmd.address === readAddress && (readMask & dataWriteCmd.mask) =/= 0
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
dataReadRestored clearWhen(request.ready)
|
val stage0 = new Area{
|
||||||
io.cpu.memory.haltIt := cpuMemoryStageNeedReadData && request.valid && !dataReadRestored
|
val mask = io.cpu.execute.size.mux (
|
||||||
|
|
||||||
//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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 (
|
|
||||||
U(0) -> B"0001",
|
U(0) -> B"0001",
|
||||||
U(1) -> B"0011",
|
U(1) -> B"0011",
|
||||||
default -> B"1111"
|
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.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
|
//Evict the cache after reset logics
|
||||||
val bootEvicts = if(clearTagsAfterReset) new Area {
|
val flusher = new Area {
|
||||||
val valid = RegInit(True)
|
val valid = RegInit(True)
|
||||||
mmuRsp.physicalAddress init (0)
|
mmuRsp.physicalAddress init (0)
|
||||||
when(valid) {
|
when(valid) {
|
||||||
tagsWriteCmd.valid := valid
|
tagsWriteCmd.valid := valid
|
||||||
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
||||||
tagsWriteCmd.data.used := False
|
tagsWriteCmd.way.setAll()
|
||||||
|
tagsWriteCmd.data.valid := False
|
||||||
when(mmuRsp.physicalAddress(lineRange) =/= lineCount - 1) {
|
when(mmuRsp.physicalAddress(lineRange) =/= lineCount - 1) {
|
||||||
mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1
|
mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1
|
||||||
io.cpu.writeBack.haltIt := True
|
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{
|
case class AtomicEntry() extends Bundle{
|
||||||
val valid = Bool()
|
val valid = Bool()
|
||||||
val size = UInt(2 bits)
|
val size = UInt(2 bits)
|
||||||
|
@ -664,11 +470,11 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
}
|
}
|
||||||
val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount)
|
val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount)
|
||||||
val entriesAllocCounter = Counter(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){
|
when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){
|
||||||
entries(entriesAllocCounter).valid := True
|
entries(entriesAllocCounter).valid := True
|
||||||
entries(entriesAllocCounter).size := request.size
|
entries(entriesAllocCounter).size := request.size //TODO remove size stuff
|
||||||
entries(entriesAllocCounter).address := request.address
|
entries(entriesAllocCounter).address := io.cpu.writeBack.address
|
||||||
when(!io.cpu.writeBack.isStuck){
|
when(!io.cpu.writeBack.isStuck){
|
||||||
entriesAllocCounter.increment()
|
entriesAllocCounter.increment()
|
||||||
}
|
}
|
||||||
|
@ -676,128 +482,127 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
when(io.cpu.writeBack.clearAtomicEntries){
|
when(io.cpu.writeBack.clearAtomicEntries){
|
||||||
entries.foreach(_.valid := False)
|
entries.foreach(_.valid := False)
|
||||||
}
|
}
|
||||||
|
|
||||||
when(request.isAtomic && ! entriesHit){
|
|
||||||
writeMask := 0
|
|
||||||
}
|
}
|
||||||
} else null
|
|
||||||
|
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(io.cpu.writeBack.isValid) {
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
when(request.forceUncachedAccess || mmuRsp.isIoAccess) {
|
||||||
val memCmdSent = RegInit(False)
|
io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid)
|
||||||
when(!victim.request.valid) {
|
|
||||||
//Avoid mixing memory request while victim is pending
|
io.mem.cmd.valid := !memCmdSent
|
||||||
io.mem.cmd.wr := request.wr
|
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.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit)
|
||||||
io.mem.cmd.mask := writeMask
|
io.mem.cmd.mask := mask
|
||||||
io.mem.cmd.data := request.data
|
io.mem.cmd.data := request.data
|
||||||
io.mem.cmd.length := 0
|
io.mem.cmd.length := 0
|
||||||
io.mem.cmd.last := True
|
io.mem.cmd.last := True
|
||||||
|
|
||||||
when(!memCmdSent) {
|
|
||||||
io.mem.cmd.valid := True
|
|
||||||
memCmdSent setWhen (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 {
|
} otherwise {
|
||||||
when(waysHit || !loadingNotDone) {
|
when(waysHit || request.wr) { //Do not require a cache refill ?
|
||||||
io.cpu.writeBack.haltIt := False
|
//Data cache update
|
||||||
dataWriteCmd.valid := request.wr
|
dataWriteCmd.valid setWhen(request.wr && waysHit)
|
||||||
dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low)
|
dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low)
|
||||||
dataWriteCmd.data := request.data
|
dataWriteCmd.data := request.data
|
||||||
dataWriteCmd.mask := writeMask
|
dataWriteCmd.mask := mask
|
||||||
|
dataWriteCmd.way := waysHits
|
||||||
|
|
||||||
tagsWriteCmd.valid := (!loadingNotDone) || request.wr
|
//Write through
|
||||||
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
io.mem.cmd.valid setWhen(request.wr)
|
||||||
tagsWriteCmd.data.used := True
|
io.mem.cmd.wr := True
|
||||||
tagsWriteCmd.data.dirty := request.wr
|
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit)
|
||||||
tagsWriteCmd.data.address := mmuRsp.physicalAddress(tagRange)
|
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)
|
||||||
|
|
||||||
|
//On write to read colisions
|
||||||
|
io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0
|
||||||
|
} otherwise { //Do refill
|
||||||
|
|
||||||
|
//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 {
|
} otherwise {
|
||||||
val victimRequired = way.tagReadRspTwo.used && way.tagReadRspTwo.dirty
|
io.cpu.writeBack.data := dataMux
|
||||||
loaderValid := loadingNotDone && !(victimNotSent && victim.request.isStall) //Additional condition used to be sure of that all previous victim are written into the RAM
|
if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0
|
||||||
victim.requestIn.valid := victimRequired && victimNotSent
|
|
||||||
victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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")
|
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){
|
if(genAtomic){
|
||||||
when(request.isAtomic && request.wr){
|
when(request.isAtomic && request.wr){
|
||||||
io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized
|
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 loader = new Area{
|
||||||
val valid = RegNext(stageB.loaderValid) init(False)
|
val valid = RegInit(False) setWhen(stageB.loaderValid)
|
||||||
val baseAddress = stageB.mmuRsp.physicalAddress
|
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 counter = Counter(memTransactionPerLine)
|
||||||
|
val waysAllocator = Reg(Bits(wayCount bits)) init(1)
|
||||||
|
val error = RegInit(False)
|
||||||
|
|
||||||
when(valid && io.mem.rsp.valid){
|
when(valid && io.mem.rsp.valid){
|
||||||
dataWriteCmd.valid := True
|
dataWriteCmd.valid := True
|
||||||
dataWriteCmd.address := baseAddress(lineRange) @@ counter
|
dataWriteCmd.address := baseAddress(lineRange) @@ counter
|
||||||
dataWriteCmd.data := io.mem.rsp.data
|
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()
|
counter.increment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
when(counter.willOverflow){
|
when(counter.willOverflow){
|
||||||
memCmdSent := False
|
|
||||||
valid := 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
var mmuBus : MemoryTranslatorBus = null
|
var mmuBus : MemoryTranslatorBus = null
|
||||||
var exceptionBus : Flow[ExceptionCause] = null
|
var exceptionBus : Flow[ExceptionCause] = null
|
||||||
var privilegeService : PrivilegeService = null
|
var privilegeService : PrivilegeService = null
|
||||||
|
var redoBranch : Flow[UInt] = null
|
||||||
|
|
||||||
object MEMORY_ENABLE extends Stageable(Bool)
|
object MEMORY_ENABLE extends Stageable(Bool)
|
||||||
object MEMORY_MANAGMENT extends Stageable(Bool)
|
object MEMORY_MANAGMENT extends Stageable(Bool)
|
||||||
|
@ -44,7 +45,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
SRC_USE_SUB_LESS -> False,
|
SRC_USE_SUB_LESS -> False,
|
||||||
MEMORY_ENABLE -> True,
|
MEMORY_ENABLE -> True,
|
||||||
RS1_USE -> 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(
|
val loadActions = stdActions ++ List(
|
||||||
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
SRC2_CTRL -> Src2CtrlEnum.IMI,
|
||||||
|
@ -75,13 +76,14 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
decoderService.add(
|
decoderService.add(
|
||||||
key = LR,
|
key = LR,
|
||||||
values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq(
|
values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq(
|
||||||
SRC2_CTRL -> Src2CtrlEnum.RS,
|
SRC_ADD_ZERO -> True,
|
||||||
MEMORY_ATOMIC -> True
|
MEMORY_ATOMIC -> True
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
decoderService.add(
|
decoderService.add(
|
||||||
key = SC,
|
key = SC,
|
||||||
values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq(
|
values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq(
|
||||||
|
SRC_ADD_ZERO -> True,
|
||||||
REGFILE_WRITE_VALID -> True,
|
REGFILE_WRITE_VALID -> True,
|
||||||
BYPASSABLE_EXECUTE_STAGE -> False,
|
BYPASSABLE_EXECUTE_STAGE -> False,
|
||||||
BYPASSABLE_MEMORY_STAGE -> False,
|
BYPASSABLE_MEMORY_STAGE -> False,
|
||||||
|
@ -98,6 +100,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
))
|
))
|
||||||
|
|
||||||
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig)
|
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig)
|
||||||
|
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.writeBack)
|
||||||
|
|
||||||
if(catchSomething)
|
if(catchSomething)
|
||||||
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack)
|
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack)
|
||||||
|
@ -141,8 +144,8 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
val size = input(INSTRUCTION)(13 downto 12).asUInt
|
val size = input(INSTRUCTION)(13 downto 12).asUInt
|
||||||
cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||||
cache.io.cpu.execute.isStuck := arbitration.isStuck
|
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.wr := input(MEMORY_WR)
|
||||||
cache.io.cpu.execute.args.address := input(SRC_ADD).asUInt
|
|
||||||
cache.io.cpu.execute.args.data := size.mux(
|
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(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),
|
U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0),
|
||||||
|
@ -150,19 +153,18 @@ class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
)
|
)
|
||||||
cache.io.cpu.execute.args.size := size
|
cache.io.cpu.execute.args.size := size
|
||||||
cache.io.cpu.execute.args.forceUncachedAccess := False
|
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)
|
|
||||||
if(genAtomic) {
|
if(genAtomic) {
|
||||||
cache.io.cpu.execute.args.isAtomic := False
|
cache.io.cpu.execute.args.isAtomic := False
|
||||||
when(input(MEMORY_ATOMIC)){
|
when(input(MEMORY_ATOMIC)){
|
||||||
cache.io.cpu.execute.args.isAtomic := True
|
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{
|
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.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||||
cache.io.cpu.memory.isStuck := arbitration.isStuck
|
cache.io.cpu.memory.isStuck := arbitration.isStuck
|
||||||
cache.io.cpu.memory.isRemoved := arbitration.removeIt
|
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
|
cache.io.cpu.memory.mmuBus <> mmuBus
|
||||||
arbitration.haltItself setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeBack plug new Area{
|
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.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||||
cache.io.cpu.writeBack.isStuck := arbitration.isStuck
|
cache.io.cpu.writeBack.isStuck := arbitration.isStuck
|
||||||
cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False)
|
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(genAtomic) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching
|
||||||
|
|
||||||
if(catchSomething) {
|
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.valid := False //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.badAddr := U(input(REGFILE_WRITE_DATA))
|
||||||
exceptionBus.code.assignDontCare()
|
exceptionBus.code.assignDontCare()
|
||||||
when(cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError){
|
|
||||||
|
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
|
exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized
|
||||||
}
|
}
|
||||||
when(cache.io.cpu.writeBack.unalignedAccess){
|
|
||||||
|
if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) {
|
||||||
|
exceptionBus.valid := True
|
||||||
exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized
|
exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized
|
||||||
}
|
}
|
||||||
when(cache.io.cpu.writeBack.mmuMiss){
|
when (cache.io.cpu.writeBack.mmuException) {
|
||||||
exceptionBus.code := 13
|
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)
|
arbitration.haltItself.setWhen(cache.io.cpu.writeBack.haltIt)
|
||||||
|
|
|
@ -33,9 +33,8 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
|
||||||
port.bus.rsp.allowExecute := True
|
port.bus.rsp.allowExecute := True
|
||||||
port.bus.rsp.allowUser := True
|
port.bus.rsp.allowUser := True
|
||||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||||
???
|
port.bus.rsp.exception := False
|
||||||
// port.bus.rsp.miss := False
|
port.bus.rsp.refilling := False
|
||||||
// port.bus.rsp.hit := True
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
[*]
|
[*]
|
||||||
[*] GTKWave Analyzer v3.3.100 (w)1999-2019 BSI
|
[*] 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] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/rv32ui-p-lw.vcd"
|
||||||
[dumpfile_mtime] "Sat Mar 30 09:16:30 2019"
|
[dumpfile_mtime] "Mon Apr 1 21:52:20 2019"
|
||||||
[dumpfile_size] 249834424
|
[dumpfile_size] 1974526
|
||||||
[savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw"
|
[savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw"
|
||||||
[timestart] 106663042
|
[timestart] 348
|
||||||
[size] 1920 1030
|
[size] 1920 1030
|
||||||
[pos] -458 -215
|
[pos] -1 -1
|
||||||
*-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
|
*-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.
|
||||||
[treeopen] TOP.VexRiscv.
|
[treeopen] TOP.VexRiscv.
|
||||||
[sst_width] 287
|
[sst_width] 287
|
||||||
[signals_width] 465
|
[signals_width] 563
|
||||||
[sst_expanded] 1
|
[sst_expanded] 1
|
||||||
[sst_vpaned_height] 279
|
[sst_vpaned_height] 279
|
||||||
@28
|
@28
|
||||||
|
@ -21,43 +21,37 @@ TOP.VexRiscv.writeBack_arbitration_isFiring
|
||||||
@22
|
@22
|
||||||
TOP.VexRiscv.writeBack_PC[31:0]
|
TOP.VexRiscv.writeBack_PC[31:0]
|
||||||
TOP.VexRiscv.writeBack_INSTRUCTION[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
|
@28
|
||||||
TOP.VexRiscv.CsrPlugin_exception
|
TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_valid
|
||||||
TOP.VexRiscv.CsrPlugin_privilege[1:0]
|
[color] 1
|
||||||
|
TOP.VexRiscv.dataCache_1_.io_mem_cmd_valid
|
||||||
|
[color] 1
|
||||||
|
TOP.VexRiscv.dataCache_1_.io_mem_cmd_ready
|
||||||
@22
|
@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
|
@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
|
@22
|
||||||
TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_payload[31:0]
|
[color] 1
|
||||||
|
TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_mask[3:0]
|
||||||
@28
|
@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
|
@22
|
||||||
TOP.VexRiscv.CsrPlugin_mepc[31:0]
|
[color] 1
|
||||||
TOP.VexRiscv.CsrPlugin_sepc[31:0]
|
TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_data[31:0]
|
||||||
@28
|
@28
|
||||||
TOP.VexRiscv.decode_IS_RVC
|
[color] 1
|
||||||
@24
|
TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_error
|
||||||
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
|
|
||||||
[pattern_trace] 1
|
[pattern_trace] 1
|
||||||
[pattern_trace] 0
|
[pattern_trace] 0
|
||||||
|
|
|
@ -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););
|
// redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
|
||||||
// return 0;
|
// return 0;
|
||||||
|
|
||||||
|
|
||||||
for(int idx = 0;idx < 1;idx++){
|
for(int idx = 0;idx < 1;idx++){
|
||||||
|
|
||||||
#if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX)
|
#if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX)
|
||||||
|
|
|
@ -366,7 +366,6 @@ class DBusDimension extends VexRiscvDimension("DBus") {
|
||||||
catchAccessError = catchAll,
|
catchAccessError = catchAll,
|
||||||
catchIllegal = catchAll,
|
catchIllegal = catchAll,
|
||||||
catchUnaligned = catchAll,
|
catchUnaligned = catchAll,
|
||||||
catchMemoryTranslationMiss = catchAll,
|
|
||||||
atomicEntriesCount = 0
|
atomicEntriesCount = 0
|
||||||
),
|
),
|
||||||
memoryTranslatorPortConfig = null
|
memoryTranslatorPortConfig = null
|
||||||
|
|
Loading…
Reference in New Issue