From b21a26f94776242b2b3ddb8f1a615d50e5c63ad1 Mon Sep 17 00:00:00 2001 From: Liphen Date: Fri, 29 Dec 2023 11:14:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(cache):=20=E5=AE=9E=E7=8E=B0=E4=BA=86fence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chisel/playground/src/cache/DCache.scala | 75 ++++++++++++------------ chisel/playground/src/cache/ICache.scala | 19 +++--- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/chisel/playground/src/cache/DCache.scala b/chisel/playground/src/cache/DCache.scala index bcdecc9..3f23fd4 100644 --- a/chisel/playground/src/cache/DCache.scala +++ b/chisel/playground/src/cache/DCache.scala @@ -103,15 +103,16 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul // * valid dirty * // // 每行有一个有效位和一个脏位 - val valid = RegInit(VecInit(Seq.fill(nindex)(VecInit(Seq.fill(nway)(false.B))))) + val valid = RegInit(VecInit(Seq.fill(nindex)(VecInit(Seq.fill(nway)(false.B))))) // FIXME:nway放前面会导致栈溢出错误 val dirty = RegInit(VecInit(Seq.fill(nindex)(VecInit(Seq.fill(nway)(false.B))))) val lru = RegInit(VecInit(Seq.fill(nindex)(false.B))) // TODO:支持更多路数,目前只支持2路 - val dirty_table = Wire(Vec(nindex, UInt(nway.W))) // 0:第0路脏位为真,1:第1路脏位为真,2:两路都为假 - val dirty_index = Wire(UInt(indexWidth.W)) - val dirty_way = dirty_table(dirty_index) // 用于指示哪个路的脏位为真 - val writeback_index = RegInit(0.U(indexWidth.W)) - val writeback_tag = RegInit(0.U(tagWidth.W)) + // 0:第0路脏位为真,1:第1路脏位为真,2:两路都为假 + val dirty_table = Wire(Vec(nindex, UInt(log2Ceil(nway + 1).W))) + // 用于指示哪个行的脏位为真 + val dirty_index = Wire(UInt(indexWidth.W)) + // 用于指示哪个路的脏位为真 + val dirty_way = dirty_table(dirty_index) for (i <- 0 until nindex) { dirty_table(i) := MuxCase( @@ -125,7 +126,9 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul dirty_index := PriorityEncoder(dirty_table.map(w => w =/= 2.U)) - val fence = RegInit(false.B) + // 表示进入fence的写回状态 + val fence = RegInit(false.B) + // 表示准备好了fence的写回数据,因为bank读数据要两拍 val fence_data_ready = RegInit(false.B) // 对于uncached段使用writeFifo进行写回 @@ -143,7 +146,7 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul })) // 用于解决在replace时读写时序不一致的问题 - val bank_woffset = RegInit(0.U((offsetWidth - log2Ceil(XLEN / 8)).W)) + val bank_windex = RegInit(0.U((offsetWidth - log2Ceil(XLEN / 8)).W)) val bank_replication = RegInit(VecInit(Seq.fill(nbank)(0.U(XLEN.W)))) // 是否使用exe的地址进行提前访存 @@ -318,7 +321,7 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul }.otherwise { when(!cache_hit) { state := s_replace - bank_woffset := 0.U + bank_windex := 0.U burst.wstrb(replace_way) := 1.U // 先写入第一块bank when(replace_dirty) { // cache行的脏位为真时需要写回,备份一下cache行,便于处理读写时序问题 @@ -370,15 +373,15 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul when(w.last) { wvalid := false.B }.otherwise { - bank_woffset := bank_woffset + 1.U - w.data := data(bank_woffset + 1.U)(dirty_way) - when(bank_woffset + 1.U === (cached_len).U) { + bank_windex := bank_windex + 1.U + w.data := data(bank_windex + 1.U)(dirty_way) + when(bank_windex + 1.U === (cached_len).U) { w.last := true.B } } } when(io.axi.b.valid) { - // TODO: 增加此处的错误处理 + // TODO: 增加此处的acc_err错误处理 // acc_err := io.axi.b.bits.resp =/= RESP_OKEY.U dirty(dirty_index)(dirty_way) := false.B // 写回完成,清除脏位 fence_data_ready := false.B @@ -386,23 +389,21 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul } }.elsewhen(dirty.asUInt.orR) { when(fence_data_ready) { - writeback_index := dirty_index // 方便debug - writeback_tag := Mux(dirty_way === 0.U, tagRam(0).io.rdata, tagRam(1).io.rdata) // 方便debug // for axi write aw.addr := Cat( Mux(dirty_way === 0.U, tagRam(0).io.rdata, tagRam(1).io.rdata), dirty_index, 0.U(offsetWidth.W) ) - aw.len := cached_len.U - aw.size := cached_size.U - awvalid := true.B - w.data := data(0)(dirty_way) // 从第零块bank开始写回 - w.strb := ~0.U(AXI_STRB_WID.W) - w.last := false.B - wvalid := true.B - bank_woffset := 0.U - fence := true.B + aw.len := cached_len.U + aw.size := cached_size.U + awvalid := true.B + w.data := data(0)(dirty_way) // 从第零块bank开始写回 + w.strb := ~0.U(AXI_STRB_WID.W) + w.last := false.B + wvalid := true.B + bank_windex := 0.U + fence := true.B }.otherwise { fence_data_ready := true.B } @@ -422,15 +423,15 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul when(w.last) { wvalid := false.B }.otherwise { - bank_woffset := bank_woffset + 1.U - w.data := bank_replication(bank_woffset + 1.U) - when(bank_woffset + 1.U === (cached_len).U) { + bank_windex := bank_windex + 1.U + w.data := bank_replication(bank_windex + 1.U) + when(bank_windex + 1.U === (cached_len).U) { w.last := true.B } } } when(io.axi.b.valid) { - // TODO: 增加此处的错误处理 + // TODO: 增加此处的acc_err错误处理 // acc_err := io.axi.b.bits.resp =/= RESP_OKEY.U replace_dirty := false.B // 写回完成,清除脏位 } @@ -469,15 +470,15 @@ class DCache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul tag_wstrb(replace_way) := true.B tag_wdata := io.cpu.tlb.ptag when(replace_dirty) { - aw.addr := Cat(tag(replace_way), replace_index, 0.U(offsetWidth.W)) - aw.len := cached_len.U - aw.size := cached_size.U - awvalid := true.B - w.data := data(0)(replace_way) - w.strb := ~0.U(AXI_STRB_WID.W) - w.last := false.B - wvalid := true.B - bank_woffset := 0.U + aw.addr := Cat(tag(replace_way), replace_index, 0.U(offsetWidth.W)) + aw.len := cached_len.U + aw.size := cached_size.U + awvalid := true.B + w.data := data(0)(replace_way) + w.strb := ~0.U(AXI_STRB_WID.W) + w.last := false.B + wvalid := true.B + bank_windex := 0.U } } } diff --git a/chisel/playground/src/cache/ICache.scala b/chisel/playground/src/cache/ICache.scala index d85363b..adb078f 100644 --- a/chisel/playground/src/cache/ICache.scala +++ b/chisel/playground/src/cache/ICache.scala @@ -99,14 +99,6 @@ class ICache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul when(tlb_fill) { tlb_fill := false.B } io.cpu.tlb.fill := tlb_fill - // * fence * // - // fence指令时清空cache,等同于将所有valid位置0 - when(io.cpu.fence_i) { - // TODO:还要考虑更复杂的情况,比如说打断了读 - valid := 0.U.asTypeOf(valid) - state := s_fence - } - // * lru * //// TODO:检查lru的正确性,增加可拓展性,目前只支持两路的cache val lru = RegInit(VecInit(Seq.fill(nindex)(false.B))) @@ -306,13 +298,20 @@ class ICache(cacheConfig: CacheConfig)(implicit config: CpuConfig) extends Modul } } is(s_fence) { - // 等待dcache完成写回操作 - when(io.cpu.complete_single_request && !io.cpu.dcache_stall) { + // 等待dcache完成写回操作,且等待axi总线完成读取操作,因为icache发生状态转移时可能正在读取数据 + when(!io.cpu.dcache_stall && !io.axi.r.valid) { state := s_idle } } } + // * fence * // + // 不论icache在什么状态,fence指令优先度最高,会强制将icache状态转移为s_fence + when(io.cpu.fence_i) { + valid := 0.U.asTypeOf(valid) // fence.i指令需要icache,等同于将所有valid位置0 + state := s_fence + } + println("----------------------------------------") println("ICache: ") println("nindex: " + nindex)