DataCache add invalidate/clean/invalidateClean on a virtual address/way
This commit is contained in:
parent
48a5dc8e79
commit
5ba8ab7947
|
@ -63,7 +63,7 @@ class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean
|
||||||
List(SB, SH, SW).map(_ -> storeActions)
|
List(SB, SH, SW).map(_ -> storeActions)
|
||||||
)
|
)
|
||||||
|
|
||||||
if(askMemoryTranslation != null)
|
if(askMemoryTranslation)
|
||||||
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.memory,memoryTranslatorPortConfig)
|
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.memory,memoryTranslatorPortConfig)
|
||||||
|
|
||||||
if(catchSomething)
|
if(catchSomething)
|
||||||
|
@ -100,8 +100,10 @@ class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean
|
||||||
default -> B"1111"
|
default -> B"1111"
|
||||||
) << cache.io.cpu.execute.args.address(1 downto 0)).resized
|
) << cache.io.cpu.execute.args.address(1 downto 0)).resized
|
||||||
cache.io.cpu.execute.args.bypass := cache.io.cpu.execute.args.address(31 downto 28) === 0xF
|
cache.io.cpu.execute.args.bypass := cache.io.cpu.execute.args.address(31 downto 28) === 0xF
|
||||||
cache.io.cpu.execute.args.all := False
|
|
||||||
cache.io.cpu.execute.args.kind := DataCacheCpuCmdKind.MEMORY
|
cache.io.cpu.execute.args.kind := DataCacheCpuCmdKind.MEMORY
|
||||||
|
cache.io.cpu.execute.args.clean := False
|
||||||
|
cache.io.cpu.execute.args.invalidate := False
|
||||||
|
cache.io.cpu.execute.args.way := False
|
||||||
|
|
||||||
insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.args.address(1 downto 0)
|
insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.args.address(1 downto 0)
|
||||||
}
|
}
|
||||||
|
@ -228,7 +230,7 @@ object Bypasser{
|
||||||
}
|
}
|
||||||
|
|
||||||
object DataCacheCpuCmdKind extends SpinalEnum{
|
object DataCacheCpuCmdKind extends SpinalEnum{
|
||||||
val MEMORY,FLUSH,EVICT = newElement()
|
val MEMORY,LINE = newElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
object DataCacheCpuExecute{
|
object DataCacheCpuExecute{
|
||||||
|
@ -254,7 +256,8 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{
|
||||||
val data = Bits(p.cpuDataWidth bit)
|
val data = Bits(p.cpuDataWidth bit)
|
||||||
val mask = Bits(p.cpuDataWidth/8 bit)
|
val mask = Bits(p.cpuDataWidth/8 bit)
|
||||||
val bypass = Bool
|
val bypass = Bool
|
||||||
val all = Bool //Address should be zero when "all" is used
|
val clean, invalidate, way = Bool
|
||||||
|
// val all = Bool //Address should be zero when "all" is used
|
||||||
}
|
}
|
||||||
|
|
||||||
case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{
|
||||||
|
@ -330,7 +333,7 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val io = new Bundle{
|
val io = new Bundle{
|
||||||
val cpu = slave(DataCacheCpuBus(p))
|
val cpu = slave(DataCacheCpuBus(p))
|
||||||
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
|
||||||
|
@ -385,8 +388,6 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
io.mem.cmd.payload.assignDontCare()
|
io.mem.cmd.payload.assignDontCare()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val way = new Area{
|
val way = new Area{
|
||||||
val tags = Mem(new LineInfo(),wayLineCount)
|
val tags = Mem(new LineInfo(),wayLineCount)
|
||||||
val data = Mem(Bits(wordWidth bit),wayWordCount)
|
val data = Mem(Bits(wordWidth bit),wayWordCount)
|
||||||
|
@ -430,7 +431,6 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val tagReadRspTwo = RegNextWhen(tagReadRspTwoRegIn ,tagReadRspTwoEnable)
|
val tagReadRspTwo = RegNextWhen(tagReadRspTwoRegIn ,tagReadRspTwoEnable)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val dataReadRspTwoEnable = !io.cpu.writeBack.isStuck
|
val dataReadRspTwoEnable = !io.cpu.writeBack.isStuck
|
||||||
val dataReadRspTwo = Bypasser.writeFirstRegWrap(
|
val dataReadRspTwo = Bypasser.writeFirstRegWrap(
|
||||||
sample = dataReadRspTwoEnable,
|
sample = dataReadRspTwoEnable,
|
||||||
|
@ -444,9 +444,6 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// val dataReadedValue = Vec(id => RegNext(ways(id).dataReadRsp),ways.length)
|
|
||||||
|
|
||||||
|
|
||||||
when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){
|
when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){
|
||||||
tagsReadCmd.valid := True
|
tagsReadCmd.valid := True
|
||||||
tagsReadCmd.payload := io.cpu.execute.address(lineRange)
|
tagsReadCmd.payload := io.cpu.execute.address(lineRange)
|
||||||
|
@ -458,7 +455,7 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
|
|
||||||
val victim = new Area{
|
val victim = new Area{
|
||||||
val requestIn = Stream(cloneable(new Bundle{
|
val requestIn = Stream(cloneable(new Bundle{
|
||||||
val way = UInt(log2Up(wayCount) bits)
|
// val way = UInt(log2Up(wayCount) bits)
|
||||||
val address = UInt(p.addressWidth bits)
|
val address = UInt(p.addressWidth bits)
|
||||||
}))
|
}))
|
||||||
requestIn.valid := False
|
requestIn.valid := False
|
||||||
|
@ -547,107 +544,70 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
val request = RegNextWhen(io.cpu.execute.args, !io.cpu.memory.isStuck)
|
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.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.virtualAddress := request.address
|
||||||
|
io.cpu.memory.mmuBus.cmd.bypass := request.way
|
||||||
}
|
}
|
||||||
|
|
||||||
val stageB = new Area {
|
val stageB = new Area {
|
||||||
io.flushDone := False
|
|
||||||
|
|
||||||
val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck)
|
val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck)
|
||||||
val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck)
|
val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck)
|
||||||
// val waysHit = RegNextWhen(way.tagReadRspTwoRegIn.used && stageA.mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming
|
// val waysHit = RegNextWhen(way.tagReadRspTwoRegIn.used && stageA.mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming
|
||||||
val waysHit = way.tagReadRspTwo.used && mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwo.address
|
val waysHit = way.tagReadRspTwo.used && mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwo.address
|
||||||
|
|
||||||
//Evict the cache after reset
|
|
||||||
val requestValid = io.cpu.writeBack.isValid || RegNextWhen(False, !io.cpu.writeBack.isStuck, True)
|
|
||||||
request.kind init(DataCacheCpuCmdKind.EVICT)
|
|
||||||
request.all init(True)
|
|
||||||
mmuRsp.physicalAddress init(0)
|
|
||||||
|
|
||||||
io.cpu.writeBack.haltIt := requestValid
|
|
||||||
|
|
||||||
|
|
||||||
//Loader interface
|
//Loader interface
|
||||||
val loaderValid = False
|
val loaderValid = False
|
||||||
val loaderReady = False
|
val loaderReady = False
|
||||||
val loadingDone = RegNext(loaderValid && loaderReady) init(False) //one cycle pulse
|
val loadingDone = RegNext(loaderValid && loaderReady) init(False) //one cycle pulse
|
||||||
|
|
||||||
|
//delayedXX are used to relax logic timings in flush and evict modes
|
||||||
// val flushAllState = RegInit(False) //Used to keep logic timings fast
|
val delayedIsStuck = RegNext(io.cpu.writeBack.isStuck)
|
||||||
// val flushAllDone = RegNext(False) init(False)
|
val delayedWaysHitValid = RegNext(waysHit)
|
||||||
|
|
||||||
|
|
||||||
val victimNotSent = RegInit(False) clearWhen(victim.requestIn.ready) setWhen(!io.cpu.memory.isStuck)
|
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 loadingNotDone = RegInit(False) clearWhen(loaderReady) setWhen(!io.cpu.memory.isStuck)
|
||||||
|
|
||||||
|
io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid
|
||||||
io.cpu.writeBack.mmuMiss := False
|
io.cpu.writeBack.mmuMiss := False
|
||||||
io.cpu.writeBack.badAddr := request.address
|
io.cpu.writeBack.badAddr := request.address
|
||||||
|
|
||||||
|
//Evict the cache after reset logics
|
||||||
when(requestValid) {
|
val bootEvicts = new Area {
|
||||||
switch(request.kind) {
|
val valid = RegInit(True)
|
||||||
is(EVICT){
|
mmuRsp.physicalAddress init (0)
|
||||||
when(request.all){
|
when(valid) {
|
||||||
tagsWriteCmd.valid := True
|
tagsWriteCmd.valid := valid
|
||||||
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
||||||
tagsWriteCmd.data.used := False
|
tagsWriteCmd.data.used := 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
|
||||||
|
} otherwise {
|
||||||
|
valid := False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when(io.cpu.writeBack.isValid) {
|
||||||
|
switch(request.kind) {
|
||||||
|
is(LINE) {
|
||||||
|
if (catchMemoryTranslationMiss) {
|
||||||
|
io.cpu.writeBack.mmuMiss := mmuRsp.miss
|
||||||
|
}
|
||||||
|
when(delayedIsStuck && !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{
|
} otherwise{
|
||||||
io.cpu.writeBack.haltIt := False
|
io.cpu.writeBack.haltIt := False
|
||||||
}
|
}
|
||||||
}otherwise{
|
}
|
||||||
when(waysHit) {
|
|
||||||
tagsWriteCmd.valid := True
|
victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
||||||
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
||||||
tagsWriteCmd.data.used := False
|
tagsWriteCmd.data.used := !request.invalidate
|
||||||
|
tagsWriteCmd.data.dirty := !request.clean
|
||||||
}
|
}
|
||||||
io.cpu.writeBack.haltIt := False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// is(FLUSH) { //TODO!
|
|
||||||
// when(request.all) {
|
|
||||||
// when(!flushAllState){
|
|
||||||
// victim.requestIn.valid := waysRead(0).tag.used && waysRead(0).tag.dirty
|
|
||||||
// victim.requestIn.way := writebackWayId
|
|
||||||
// victim.requestIn.address := writebackWayInfo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
|
||||||
//
|
|
||||||
// tagsWriteCmd.way := writebackWayId
|
|
||||||
// tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
|
||||||
// tagsWriteCmd.data.used := False
|
|
||||||
//
|
|
||||||
// when(!victim.requestIn.isStall) {
|
|
||||||
// mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1
|
|
||||||
// flushAllDone := mmuRsp.physicalAddress(lineRange) === lineCount-1
|
|
||||||
// flushAllState := True
|
|
||||||
// tagsWriteCmd.valid := True
|
|
||||||
// }
|
|
||||||
// } otherwise{
|
|
||||||
// //Wait tag read
|
|
||||||
// flushAllState := False
|
|
||||||
// io.cpu.memory.haltIt.clearWhen(flushAllDone)
|
|
||||||
// io.flushDone := flushAllDone
|
|
||||||
// }
|
|
||||||
// } otherwise {
|
|
||||||
// when(delayedValid) {
|
|
||||||
// when(delayedWaysHitValid) {
|
|
||||||
// io.cpu.memory.haltIt.clearWhen(victim.requestIn.ready)
|
|
||||||
//
|
|
||||||
// victim.requestIn.valid := True
|
|
||||||
// victim.requestIn.way := writebackWayId
|
|
||||||
// victim.requestIn.address := writebackWayInfo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
|
|
||||||
//
|
|
||||||
// tagsWriteCmd.valid := victim.requestIn.ready
|
|
||||||
// tagsWriteCmd.way := writebackWayId
|
|
||||||
// tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
|
|
||||||
// tagsWriteCmd.data.used := False
|
|
||||||
// } otherwise{
|
|
||||||
// io.cpu.memory.haltIt := False
|
|
||||||
// io.flushDone := True
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
is(MEMORY) {
|
is(MEMORY) {
|
||||||
if (catchMemoryTranslationMiss) {
|
if (catchMemoryTranslationMiss) {
|
||||||
io.cpu.writeBack.mmuMiss := mmuRsp.miss
|
io.cpu.writeBack.mmuMiss := mmuRsp.miss
|
||||||
|
@ -738,29 +698,3 @@ class DataCache(p : DataCacheConfig) extends Component{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DataCacheMain{
|
|
||||||
def main(args: Array[String]) {
|
|
||||||
//
|
|
||||||
// SpinalVhdl({
|
|
||||||
// implicit val p = DataCacheConfig(
|
|
||||||
// cacheSize =4096,
|
|
||||||
// bytePerLine =32,
|
|
||||||
// wayCount = 1,
|
|
||||||
// addressWidth = 32,
|
|
||||||
// cpuDataWidth = 32,
|
|
||||||
// memDataWidth = 32)
|
|
||||||
// new WrapWithReg.Wrapper(new DataCache(p)).setDefinitionName("TopLevel")
|
|
||||||
// })
|
|
||||||
// SpinalVhdl({
|
|
||||||
// implicit val p = DataCacheConfig(
|
|
||||||
// cacheSize =512,
|
|
||||||
// bytePerLine =16,
|
|
||||||
// wayCount = 1,
|
|
||||||
// addressWidth = 12,
|
|
||||||
// cpuDataWidth = 16,
|
|
||||||
// memDataWidth = 16)
|
|
||||||
// new DataCache(p)
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,7 +41,7 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
||||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(askMemoryTranslation != null)
|
if(askMemoryTranslation)
|
||||||
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.fetch, memoryTranslatorPortConfig)
|
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.fetch, memoryTranslatorPortConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,18 +172,6 @@ case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle wit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class InstructionCacheTranslationBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
|
||||||
val virtualAddress = UInt(32 bits)
|
|
||||||
val physicalAddress = UInt(32 bits)
|
|
||||||
val error = if(p.catchAccessFault) Bool else null
|
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
|
||||||
out(virtualAddress)
|
|
||||||
in(physicalAddress)
|
|
||||||
if(p.catchAccessFault) in(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
|
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
|
||||||
val address = UInt(p.addressWidth bit)
|
val address = UInt(p.addressWidth bit)
|
||||||
}
|
}
|
||||||
|
@ -470,6 +458,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
|
|
||||||
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
|
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
|
||||||
io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.address
|
io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.address
|
||||||
|
io.cpu.fetch.mmuBus.cmd.bypass := False
|
||||||
val mmuRsp = RegNextWhen(io.cpu.fetch.mmuBus.rsp,!io.cpu.decode.isStuck)
|
val mmuRsp = RegNextWhen(io.cpu.fetch.mmuBus.rsp,!io.cpu.decode.isStuck)
|
||||||
|
|
||||||
val hit = tag.valid && tag.address === mmuRsp.physicalAddress(tagRange) && !(tag.loading && !lineLoader.loadedWords(mmuRsp.physicalAddress(wordRange)))
|
val hit = tag.valid && tag.address === mmuRsp.physicalAddress(tagRange) && !(tag.loading && !lineLoader.loadedWords(mmuRsp.physicalAddress(wordRange)))
|
||||||
|
|
|
@ -66,7 +66,7 @@ class MemoryTranslatorPlugin(tlbSize : Int, mmuRange : UInt => Bool) extends Plu
|
||||||
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12))
|
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12))
|
||||||
val cacheHit = cacheHits.asBits.orR
|
val cacheHit = cacheHits.asBits.orR
|
||||||
val cacheLine = MuxOH(cacheHits, cache)
|
val cacheLine = MuxOH(cacheHits, cache)
|
||||||
val isInMmuRange = mmuRange(port.bus.cmd.virtualAddress)
|
val isInMmuRange = mmuRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypass
|
||||||
|
|
||||||
val sharedMiss = RegInit(False)
|
val sharedMiss = RegInit(False)
|
||||||
val sharedIterator = Reg(UInt(log2Up(tlbSize + 1) bits))
|
val sharedIterator = Reg(UInt(log2Up(tlbSize + 1) bits))
|
||||||
|
|
|
@ -25,6 +25,7 @@ trait ExceptionService{
|
||||||
case class MemoryTranslatorCmd() extends Bundle{
|
case class MemoryTranslatorCmd() extends Bundle{
|
||||||
val isValid = Bool
|
val isValid = Bool
|
||||||
val virtualAddress = UInt(32 bits)
|
val virtualAddress = UInt(32 bits)
|
||||||
|
val bypass = Bool
|
||||||
}
|
}
|
||||||
case class MemoryTranslatorRsp() extends Bundle{
|
case class MemoryTranslatorRsp() extends Bundle{
|
||||||
val physicalAddress = UInt(32 bits)
|
val physicalAddress = UInt(32 bits)
|
||||||
|
|
Loading…
Reference in New Issue