From 74add651411eb2d9a33a25d4036c109a9789c192 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Tue, 9 Sep 2025 10:44:28 +0800 Subject: [PATCH 01/19] feat(MSHR): signaling replace nested release from MSHR --- src/main/scala/coupledL2/Common.scala | 19 +++++++++++-------- src/main/scala/coupledL2/tl2chi/MSHR.scala | 4 +++- src/main/scala/coupledL2/tl2chi/MSHRCtl.scala | 15 +++++++++++++-- .../scala/coupledL2/tl2chi/MainPipe.scala | 4 +++- src/main/scala/coupledL2/tl2chi/Slice.scala | 2 +- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/main/scala/coupledL2/Common.scala b/src/main/scala/coupledL2/Common.scala index ac2c21679..8a148a89c 100644 --- a/src/main/scala/coupledL2/Common.scala +++ b/src/main/scala/coupledL2/Common.scala @@ -326,18 +326,21 @@ class BlockInfo(implicit p: Parameters) extends L2Bundle { // used for nested C Release class NestedWriteback(implicit p: Parameters) extends L2Bundle { - val set = UInt(setBits.W) - val tag = UInt(tagBits.W) + val set = Input(UInt(setBits.W)) + val tag = Input(UInt(tagBits.W)) // Nested ReleaseData sets block dirty - val c_set_dirty = Bool() + val c_set_dirty = Input(Bool()) // Nested Release sets block TIP - val c_set_tip = Bool() + val c_set_tip = Input(Bool()) // Nested Snoop invalidates block - val b_inv_dirty = Bool() + val b_inv_dirty = Input(Bool()) + + val b_toB = chiOpt.map(_ => Input(Bool())) + val b_toN = chiOpt.map(_ => Input(Bool())) + val b_toClean = chiOpt.map(_ => Input(Bool())) - val b_toB = chiOpt.map(_ => Bool()) - val b_toN = chiOpt.map(_ => Bool()) - val b_toClean = chiOpt.map(_ => Bool()) + // Nested Release hit replace + val replaceMatch = Output(Bool()) } class PrefetchCtrlFromCore extends Bundle { diff --git a/src/main/scala/coupledL2/tl2chi/MSHR.scala b/src/main/scala/coupledL2/tl2chi/MSHR.scala index c175cd3cc..f6a02879c 100644 --- a/src/main/scala/coupledL2/tl2chi/MSHR.scala +++ b/src/main/scala/coupledL2/tl2chi/MSHR.scala @@ -56,7 +56,7 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes { val alloc = Flipped(ValidIO(new MSHRRequest)) val tasks = new MSHRTasks() val resps = new MSHRResps() - val nestedwb = Input(new NestedWriteback) + val nestedwb = new NestedWriteback() val nestedwbData = Output(Bool()) val aMergeTask = Flipped(ValidIO(new TaskBundle)) val replResp = Flipped(ValidIO(new ReplacerResult)) @@ -1366,6 +1366,8 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes { dirResult.set === io.nestedwb.set && dirResult.tag === io.nestedwb.tag + io.nestedwb.replaceMatch := nestedwb_match + when (nestedwb_match) { when (io.nestedwb.c_set_dirty) { meta.dirty := true.B diff --git a/src/main/scala/coupledL2/tl2chi/MSHRCtl.scala b/src/main/scala/coupledL2/tl2chi/MSHRCtl.scala index ec9172dbc..bc69b4964 100644 --- a/src/main/scala/coupledL2/tl2chi/MSHRCtl.scala +++ b/src/main/scala/coupledL2/tl2chi/MSHRCtl.scala @@ -68,7 +68,7 @@ class MSHRCtl(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val releaseBufWriteId = Output(UInt(mshrBits.W)) /* nested writeback */ - val nestedwb = Input(new NestedWriteback) + val nestedwb = new NestedWriteback() val nestedwbDataId = Output(ValidIO(UInt(mshrBits.W))) /* MSHR info to Sinks */ @@ -146,13 +146,24 @@ class MSHRCtl(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes m.io.replResp.bits := io.replResp.bits io.msInfo(i) := m.io.msInfo - m.io.nestedwb := io.nestedwb + + m.io.nestedwb.set := io.nestedwb.set + m.io.nestedwb.tag := io.nestedwb.tag + m.io.nestedwb.c_set_dirty := io.nestedwb.c_set_dirty + m.io.nestedwb.c_set_tip := io.nestedwb.c_set_tip + m.io.nestedwb.b_inv_dirty := io.nestedwb.b_inv_dirty + m.io.nestedwb.b_toB.foreach(_ := io.nestedwb.b_toB.getOrElse(false.B)) + m.io.nestedwb.b_toN.foreach(_ := io.nestedwb.b_toN.getOrElse(false.B)) + m.io.nestedwb.b_toClean.foreach(_ := io.nestedwb.b_toClean.getOrElse(false.B)) + m.io.aMergeTask.valid := io.aMergeTask.valid && io.aMergeTask.bits.id === i.U m.io.aMergeTask.bits := io.aMergeTask.bits.task io.pCrd(i) <> m.io.pCrd } + io.nestedwb.replaceMatch := ParallelOR(mshrs.map(_.io.nestedwb.replaceMatch)) + /* Reserve 1 entry for SinkB */ io.toReqArb.blockC_s1 := false.B io.toReqArb.blockB_s1 := mshrFull // conflict logic in SinkB diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index 9636189bf..cc961bf64 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -96,7 +96,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val releaseBufWrite = ValidIO(new MSHRBufWrite()) /* nested writeback */ - val nestedwb = Output(new NestedWriteback()) + val nestedwb = Flipped(new NestedWriteback()) val nestedwbData = Output(new DSBlock()) /* l2 refill hint */ @@ -199,6 +199,8 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val cache_alias = req_acquire_s3 && dirResult_s3.hit && meta_s3.clients(0) && meta_s3.alias.getOrElse(0.U) =/= req_s3.alias.getOrElse(0.U) + val replaceNestedRelease_s3 = task_s3.valid && task_s3.bits.fromC && io.nestedwb.replaceMatch + // *NOTICE: 'nestable_*' must not be used in A Channel related logics. val nestable_dirResult_s3 = Wire(chiselTypeOf(dirResult_s3)) val nestable_meta_s3 = nestable_dirResult_s3.meta diff --git a/src/main/scala/coupledL2/tl2chi/Slice.scala b/src/main/scala/coupledL2/tl2chi/Slice.scala index 79b6d8c46..af169d132 100644 --- a/src/main/scala/coupledL2/tl2chi/Slice.scala +++ b/src/main/scala/coupledL2/tl2chi/Slice.scala @@ -134,7 +134,7 @@ class Slice()(implicit p: Parameters) extends BaseSlice[OuterBundle] mshrCtl.io.resps.sinkC := sinkC.io.resp mshrCtl.io.resps.rxrsp := rxrsp.io.in mshrCtl.io.resps.rxdat := rxdat.io.in - mshrCtl.io.nestedwb := mainPipe.io.nestedwb + mshrCtl.io.nestedwb <> mainPipe.io.nestedwb mshrCtl.io.replResp := directory.io.replResp mshrCtl.io.aMergeTask := reqBuf.io.aMergeTask // TODO: This is ugly From f9fbbd903a0f1e3001851ba77719a29198253baa Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Tue, 9 Sep 2025 10:46:31 +0800 Subject: [PATCH 02/19] feat(Directory, MainPipe): partial meta write on non-nested release --- src/main/scala/coupledL2/Directory.scala | 18 +++++++++++++++-- .../scala/coupledL2/tl2chi/MainPipe.scala | 20 +++++++++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/main/scala/coupledL2/Directory.scala b/src/main/scala/coupledL2/Directory.scala index cbe3e2efa..ec843e81a 100644 --- a/src/main/scala/coupledL2/Directory.scala +++ b/src/main/scala/coupledL2/Directory.scala @@ -104,6 +104,11 @@ class MetaWrite(implicit p: Parameters) extends L2Bundle { val set = UInt(setBits.W) val wayOH = UInt(cacheParams.ways.W) val wmeta = new MetaEntry + val release = Valid(new Bundle() { // Release-only mode, write mask bundle + val dirty = Bool() + val clients = Bool() + val state = Bool() + }) } class TagWrite(implicit p: Parameters) extends L2Bundle { @@ -171,7 +176,7 @@ class Directory(implicit p: Parameters) extends L2Module { )) } - val metaArray = Module(new SRAMTemplate(new MetaEntry, sets, ways, singlePort = true, hasMbist = mbist, hasSramCtl = hasSramCtl)) + val metaArray = Module(new SRAMTemplate(new MetaEntry, sets, ways, singlePort = true, useBitmask = true, hasMbist = mbist, hasSramCtl = hasSramCtl)) val tagRead_s3 = Wire(Vec(ways, UInt(tagBits.W))) val metaRead = Wire(Vec(ways, new MetaEntry())) @@ -234,12 +239,21 @@ class Directory(implicit p: Parameters) extends L2Module { errorRead := bankTagError // Meta R/W + val metaMaskNone = Fill(io.metaWReq.bits.wmeta.getWidth, 0.U) + val metaMaskAll = Fill(io.metaWReq.bits.wmeta.getWidth, 1.U) + + val metaMaskRelease = WireInit(metaMaskNone.asTypeOf(new MetaEntry)) + metaMaskRelease.dirty := Fill(metaMaskRelease.dirty.getWidth, io.metaWReq.bits.release.bits.dirty) // masking 'dirty' + metaMaskRelease.clients := Fill(metaMaskRelease.clients.getWidth, io.metaWReq.bits.release.bits.clients) // masking 'clients' + metaMaskRelease.state := Fill(metaMaskRelease.state.getWidth, io.metaWReq.bits.release.bits.state) // masking 'state' + metaRead := metaArray.io.r(io.read.fire, io.read.bits.set).resp.data metaArray.io.w( metaWen, io.metaWReq.bits.wmeta, io.metaWReq.bits.set, - io.metaWReq.bits.wayOH + io.metaWReq.bits.wayOH, + Mux(io.metaWReq.bits.release.valid, metaMaskRelease.asUInt, metaMaskAll) ) val metaAll_s3 = RegEnable(metaRead, 0.U.asTypeOf(metaRead), reqValid_s2) diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index cc961bf64..880dc3e92 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -534,7 +534,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes !isSnpStashX(req_s3.chiOpcode.get) && !isSnpQuery(req_s3.chiOpcode.get) && ( meta_s3.state === TIP || meta_s3.state === BRANCH && isSnpToN(req_s3.chiOpcode.get) ) - val metaW_valid_s3_c = sinkC_req_s3 && dirResult_s3.hit + val metaW_valid_s3_c = sinkC_req_s3 && !replaceNestedRelease_s3 val metaW_valid_s3_mshr = mshr_req_s3 && req_s3.metaWen && !(mshr_refill_s3 && retry) val metaW_valid_s3_cmo = req_cbo_inval_s3 && dirResult_s3.hit require(clientBits == 1) @@ -565,13 +565,13 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes ) ) val metaW_s3_c = MetaEntry( - dirty = meta_s3.dirty || wen_c, - state = Mux(isParamFromT(req_s3.param), TIP, meta_s3.state), - clients = Fill(clientBits, !isToN(req_s3.param)), - alias = meta_s3.alias, - accessed = meta_s3.accessed, - tagErr = Mux(wen_c, req_s3.denied, meta_s3.tagErr), - dataErr = Mux(wen_c, req_s3.corrupt, meta_s3.dataErr) // update error when write DS + dirty = true.B, + state = TIP, + clients = Fill(clientBits, 0.U), + alias = Some(0.U), + accessed = false.B, + tagErr = false.B, + dataErr = false.B // update error when write DS ) // use merge_meta if mergeA val metaW_s3_mshr = WireInit(Mux(req_s3.mergeA, req_s3.aMergeTask.meta, req_s3.meta)) @@ -598,6 +598,10 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes ), MetaEntry() ) + io.metaWReq.bits.release.valid := metaW_valid_s3_c + io.metaWReq.bits.release.bits.clients := isToN(req_s3.param) + io.metaWReq.bits.release.bits.dirty := req_s3.opcode === ReleaseData + io.metaWReq.bits.release.bits.state := isParamFromT(req_s3.param) io.tagWReq.valid := task_s3.valid && req_s3.tagWen && mshr_refill_s3 && !retry io.tagWReq.bits.set := req_s3.set From 744a48ea697a48c3d2ab21e103b9e55bb38edccc Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Tue, 9 Sep 2025 10:47:01 +0800 Subject: [PATCH 03/19] feat(RequestArb): exclude Release (without data) from MCP2 stall --- src/main/scala/coupledL2/RequestArb.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 6e7c05628..78c5a0b5d 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -198,8 +198,12 @@ class RequestArb(implicit p: Parameters) extends L2Module /* ======== Stage 2 ======== */ val s1_AHint_fire = io.sinkA.fire && io.sinkA.bits.opcode === Hint - // any req except AHint might access DS, and continuous DS accesses are prohibited - val ds_mcp2_stall = RegNext(s1_fire && !s1_AHint_fire) + val s1_CRelease_fire = io.sinkC.fire && io.sinkC.bits.opcode === Release + // any req except: + // 1. (A) Hint + // 2. (C) Release + // might access DS, and continuous DS accesses are prohibited + val ds_mcp2_stall = RegNext(s1_fire && !s1_AHint_fire && !s1_CRelease_fire) s2_ready := !ds_mcp2_stall From 706127815722e929c0f244342e33b006fe3e33fe Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Tue, 9 Sep 2025 12:36:56 +0800 Subject: [PATCH 04/19] feat(SinkC): extract way info from SinkC on release --- src/main/scala/coupledL2/GrantBuffer.scala | 1 + src/main/scala/coupledL2/L2Param.scala | 12 +++++++++--- src/main/scala/coupledL2/SinkC.scala | 4 +++- src/main/scala/coupledL2/tl2chi/MainPipe.scala | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/scala/coupledL2/GrantBuffer.scala b/src/main/scala/coupledL2/GrantBuffer.scala index 0d9d1b23e..89689e874 100644 --- a/src/main/scala/coupledL2/GrantBuffer.scala +++ b/src/main/scala/coupledL2/GrantBuffer.scala @@ -94,6 +94,7 @@ class GrantBuffer(implicit p: Parameters) extends L2Module { d.data := data d.corrupt := task.corrupt || task.denied d.echo.lift(IsKeywordKey).foreach(_ := false.B) + d.user.lift(WayKey).foreach(_ := task.way) d } diff --git a/src/main/scala/coupledL2/L2Param.scala b/src/main/scala/coupledL2/L2Param.scala index 63d073006..3298e2bda 100644 --- a/src/main/scala/coupledL2/L2Param.scala +++ b/src/main/scala/coupledL2/L2Param.scala @@ -46,6 +46,10 @@ case class L1Param val needResolveAlias = aliasBitsOpt.nonEmpty } +// Pass way in [ L2 -> D -> L1 ] and [ L1 -> C -> L2 ] +case object WayKey extends ControlKey[UInt]("way") +case class WayField() extends BundleField[UInt](WayKey, Output(UInt(4.W)), _ := 0.U(4.W)) + // Pass PMA and uncached memory attribute from PBMT to MMIOBridge case object MemBackTypeMM extends ControlKey[Bool]("memBackType_MM") case class MemBackTypeMMField() extends BundleField[Bool](MemBackTypeMM, Output(Bool()), _ := false.B) @@ -82,10 +86,10 @@ case class L2Param( // Client echoField: Seq[BundleFieldBase] = Nil, reqField: Seq[BundleFieldBase] = Nil, - respKey: Seq[BundleKeyBase] = Seq(IsHitKey), + respKey: Seq[BundleKeyBase] = Seq(IsHitKey, WayKey), // Manager - reqKey: Seq[BundleKeyBase] = Seq(AliasKey, VaddrKey, PrefetchKey, ReqSourceKey), - respField: Seq[BundleFieldBase] = Nil, + reqKey: Seq[BundleKeyBase] = Seq(AliasKey, VaddrKey, PrefetchKey, ReqSourceKey, WayKey), + respField: Seq[BundleFieldBase] = Seq(WayField()), innerBuf: TLBufferParams = TLBufferParams(), outerBuf: TLBufferParams = TLBufferParams( @@ -134,6 +138,8 @@ case class L2Param( // Enable new clint EnablePrivateClint: Boolean = false ) { + require(ways <= 16, "L1 way record for L2: only support up to 16 ways") + def toCacheParams: CacheParameters = CacheParameters( name = name, sets = sets, diff --git a/src/main/scala/coupledL2/SinkC.scala b/src/main/scala/coupledL2/SinkC.scala index 81961860b..0e6b249db 100644 --- a/src/main/scala/coupledL2/SinkC.scala +++ b/src/main/scala/coupledL2/SinkC.scala @@ -65,6 +65,8 @@ class SinkC(implicit p: Parameters) extends L2Module { val nextPtrReg = RegEnable(nextPtr, 0.U.asTypeOf(nextPtr), io.c.fire && isRelease && first && hasData) def toTaskBundle(c: TLBundleC): TaskBundle = { + require(!c.user.lift(WayKey).isEmpty, "Way field is not present in L2 TLBundleC" + + " (L1 is required to accept and store way info from L2)") val task = Wire(new TaskBundle) task := 0.U.asTypeOf(new TaskBundle) task.channel := "b100".U @@ -91,7 +93,7 @@ class SinkC(implicit p: Parameters) extends L2Module { task.fromL2pft.foreach(_ := false.B) task.needHint.foreach(_ := false.B) task.dirty := false.B - task.way := 0.U(wayBits.W) + task.way := c.user.lift(WayKey).getOrElse(0.U) task.meta := 0.U.asTypeOf(new MetaEntry) task.metaWen := false.B task.tagWen := false.B diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index 880dc3e92..0b8d93aec 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -582,7 +582,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val metaW_way = Mux( mshr_refill_s3 && req_s3.replTask, io.replResp.bits.way, // grant always use replResp way - Mux(mshr_req_s3, req_s3.way, dirResult_s3.way) + Mux(mshr_req_s3 || sinkC_req_s3, req_s3.way, dirResult_s3.way) // use way info from SinkC on Release/ReleaseData ) io.metaWReq.valid := !resetFinish || task_s3.valid && ( From eca0fa13c37679b4a382ca3de11068d908075abc Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Tue, 9 Sep 2025 12:42:10 +0800 Subject: [PATCH 05/19] chore(TestTop): expose 'way' fields on TestTop ports --- src/test/scala/chi/TestTop.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/chi/TestTop.scala b/src/test/scala/chi/TestTop.scala index 3aefb1ed8..c88164d6b 100644 --- a/src/test/scala/chi/TestTop.scala +++ b/src/test/scala/chi/TestTop.scala @@ -49,7 +49,7 @@ class TestTop_CHIL2(numCores: Int = 1, numULAgents: Int = 0, banks: Int = 1, ext channelBytes = TLChannelBeatBytes(cacheParams.blockBytes), minLatency = 1, echoFields = Nil, - requestFields = Seq(AliasField(2), VaddrField(36), PrefetchField()), + requestFields = Seq(AliasField(2), VaddrField(36), PrefetchField(), WayField()), responseKeys = cacheParams.respKey ) )) From f42149255f5f4b604cc8519de419c8eeec51f0f2 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 10 Sep 2025 10:01:49 +0800 Subject: [PATCH 06/19] feat(MainPipe): dispose directory result on release --- src/main/scala/coupledL2/tl2chi/MainPipe.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index 0b8d93aec..8d2fac3f2 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -473,7 +473,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val need_data_cmo = cmo_cbo_s3 && nestable_dirResult_s3.hit && nestable_meta_s3.dirty val ren = need_data_a || need_data_b || need_data_mshr_repl || need_data_cmo - val wen_c = sinkC_req_s3 && isParamFromT(req_s3.param) && req_s3.opcode(0) && dirResult_s3.hit + val wen_c = sinkC_req_s3 && !replaceNestedRelease_s3 && req_s3.opcode === ReleaseData && isParamFromT(req_s3.param) val wen_mshr = req_s3.dsWen && ( mshr_snpRespX_s3 || mshr_snpRespDataX_s3 || mshr_writeCleanFull_s3 || mshr_writeBackFull_s3 || @@ -495,9 +495,9 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes io.toDS.req_s3.bits.way := Mux( mshr_refill_s3 && req_s3.replTask, io.replResp.bits.way, - Mux(mshr_req_s3, req_s3.way, dirResult_s3.way) + Mux(mshr_req_s3 || sinkC_req_s3, req_s3.way, dirResult_s3.way) ) - io.toDS.req_s3.bits.set := Mux(mshr_req_s3, req_s3.set, dirResult_s3.set) + io.toDS.req_s3.bits.set := Mux(mshr_req_s3 || sinkC_req_s3, req_s3.set, dirResult_s3.set) io.toDS.req_s3.bits.wen := wen io.toDS.wdata_s3.data := Mux( !mshr_req_s3, From e5c7e97bb05de0d88a41da5896b070cee81f314b Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 10 Sep 2025 10:02:26 +0800 Subject: [PATCH 07/19] fix(MainPipe): use replacer way result on replacing task --- src/main/scala/coupledL2/tl2chi/MainPipe.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index 8d2fac3f2..b5e80b953 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -667,6 +667,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes txdat_s3.bits.task := source_req_s3 txdat_s3.bits.data.data := data_s3 d_s3.bits.task := source_req_s3 + d_s3.bits.task.way := Mux(source_req_s3.replTask, io.replResp.bits.way, source_req_s3.way) d_s3.bits.data.data := data_s3 when (task_s3.valid) { From 37281faddbaf01b470c8f3ad69d5971c0948c78e Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 10 Sep 2025 10:07:14 +0800 Subject: [PATCH 08/19] fix(MainPipe): update error meta on release --- src/main/scala/coupledL2/Directory.scala | 4 ++++ src/main/scala/coupledL2/tl2chi/MainPipe.scala | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/scala/coupledL2/Directory.scala b/src/main/scala/coupledL2/Directory.scala index ec843e81a..4d5d8fd89 100644 --- a/src/main/scala/coupledL2/Directory.scala +++ b/src/main/scala/coupledL2/Directory.scala @@ -108,6 +108,8 @@ class MetaWrite(implicit p: Parameters) extends L2Bundle { val dirty = Bool() val clients = Bool() val state = Bool() + val tagErr = Bool() + val dataErr = Bool() }) } @@ -246,6 +248,8 @@ class Directory(implicit p: Parameters) extends L2Module { metaMaskRelease.dirty := Fill(metaMaskRelease.dirty.getWidth, io.metaWReq.bits.release.bits.dirty) // masking 'dirty' metaMaskRelease.clients := Fill(metaMaskRelease.clients.getWidth, io.metaWReq.bits.release.bits.clients) // masking 'clients' metaMaskRelease.state := Fill(metaMaskRelease.state.getWidth, io.metaWReq.bits.release.bits.state) // masking 'state' + metaMaskRelease.tagErr := Fill(metaMaskRelease.tagErr.getWidth, io.metaWReq.bits.release.bits.tagErr) // masking 'tagErr' + metaMaskRelease.dataErr := Fill(metaMaskRelease.dataErr.getWidth, io.metaWReq.bits.release.bits.dataErr) // masking 'dataErr' metaRead := metaArray.io.r(io.read.fire, io.read.bits.set).resp.data metaArray.io.w( diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index b5e80b953..e62dc24c7 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -570,8 +570,8 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes clients = Fill(clientBits, 0.U), alias = Some(0.U), accessed = false.B, - tagErr = false.B, - dataErr = false.B // update error when write DS + tagErr = req_s3.denied, + dataErr = req_s3.corrupt // update error when write DS ) // use merge_meta if mergeA val metaW_s3_mshr = WireInit(Mux(req_s3.mergeA, req_s3.aMergeTask.meta, req_s3.meta)) @@ -602,6 +602,8 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes io.metaWReq.bits.release.bits.clients := isToN(req_s3.param) io.metaWReq.bits.release.bits.dirty := req_s3.opcode === ReleaseData io.metaWReq.bits.release.bits.state := isParamFromT(req_s3.param) + io.metaWReq.bits.release.bits.tagErr := wen_c + io.metaWReq.bits.release.bits.dataErr := wen_c io.tagWReq.valid := task_s3.valid && req_s3.tagWen && mshr_refill_s3 && !retry io.tagWReq.bits.set := req_s3.set From 4c0ea32fc92db397f98f565fb303b404d852f834 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 10 Sep 2025 10:10:06 +0800 Subject: [PATCH 09/19] feat(TL2TLCoupledL2): dummy implementation of release bypass * Not bypassing directory read * Partial directory write implemented * Port compatibility with L2-L1 way escalation --- src/main/scala/coupledL2/RequestArb.scala | 6 +++-- src/main/scala/coupledL2/debug/Monitor.scala | 8 ++++--- src/main/scala/coupledL2/tl2tl/MSHR.scala | 4 +++- src/main/scala/coupledL2/tl2tl/MSHRCtl.scala | 15 ++++++++++-- src/main/scala/coupledL2/tl2tl/MainPipe.scala | 24 +++++++++++++------ src/main/scala/coupledL2/tl2tl/Slice.scala | 2 +- 6 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 78c5a0b5d..7fb866bb4 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -172,8 +172,10 @@ class RequestArb(implicit p: Parameters) extends L2Module io.taskInfo_s1.bits := task_s1.bits /* Meta read request */ - // ^ only sinkA/B/C tasks need to read directory - io.dirRead_s1.valid := s2_ready && (chnl_task_s1.valid && !mshr_task_s1.valid || s1_needs_replRead && !io.fromMainPipe.blockG_s1) + // ^ only sinkA/B tasks need to read directory, and sinkC under full-TileLink + io.dirRead_s1.valid := s2_ready && + (if (enableCHI) !io.sinkC.fire else true.B) && + (chnl_task_s1.valid && !mshr_task_s1.valid || s1_needs_replRead && !io.fromMainPipe.blockG_s1) io.dirRead_s1.bits.set := task_s1.bits.set io.dirRead_s1.bits.tag := task_s1.bits.tag // invalid way which causes mshr_retry diff --git a/src/main/scala/coupledL2/debug/Monitor.scala b/src/main/scala/coupledL2/debug/Monitor.scala index ae8dec8ff..f2142fab7 100644 --- a/src/main/scala/coupledL2/debug/Monitor.scala +++ b/src/main/scala/coupledL2/debug/Monitor.scala @@ -18,6 +18,7 @@ class MainpipeMoni(implicit p: Parameters) extends L2Bundle { val dirResult_s3 = new DirResult val allocMSHR_s3 = ValidIO(UInt(mshrBits.W)) val metaW_s3 = ValidIO(new MetaWrite) + val replaceNestedRelease_s3 = Bool() } class CPL2S3Info(implicit p: Parameters) extends L2Bundle { @@ -52,6 +53,7 @@ class Monitor(implicit p: Parameters) extends L2Module { val mshr_req_s3 = req_s3.mshrTask val dirResult_s3 = mp.dirResult_s3 val meta_s3 = mp.dirResult_s3.meta + val replaceHitRelease_s3 = mp.replaceNestedRelease_s3 /* ======== MainPipe Assertions ======== */ // ! Release w/o data will not trigger nestedWBValid, either @@ -66,9 +68,9 @@ class Monitor(implicit p: Parameters) extends L2Module { meta_s3.state === TRUNK && !meta_s3.clients.orR)), "Trunk should have some client hit") - assert(RegNext(!(s3_valid && req_s3.fromC && dirResult_s3.hit && - !meta_s3.clients.orR)), - "Invalid Client should not send Release") +//assert(RegNext(!(s3_valid && req_s3.fromC && dirResult_s3.hit && +// !meta_s3.clients.orR)), +// "Invalid Client should not send Release") // assertion for set blocking // A channel task @s1 never have same-set task @s2/s3 diff --git a/src/main/scala/coupledL2/tl2tl/MSHR.scala b/src/main/scala/coupledL2/tl2tl/MSHR.scala index 048584588..70f1cecd6 100644 --- a/src/main/scala/coupledL2/tl2tl/MSHR.scala +++ b/src/main/scala/coupledL2/tl2tl/MSHR.scala @@ -52,7 +52,7 @@ class MSHR(implicit p: Parameters) extends L2Module { val alloc = Flipped(ValidIO(new MSHRRequest)) val tasks = new MSHRTasks() val resps = new MSHRResps() - val nestedwb = Input(new NestedWriteback) + val nestedwb = new NestedWriteback val nestedwbData = Output(Bool()) val aMergeTask = Flipped(ValidIO(new TaskBundle)) val replResp = Flipped(ValidIO(new ReplacerResult)) @@ -587,6 +587,8 @@ class MSHR(implicit p: Parameters) extends L2Module { dirResult.tag === io.nestedwb.tag && state.w_replResp + io.nestedwb.replaceMatch := nestedwb_match + when (nestedwb_match) { when (io.nestedwb.c_set_dirty) { meta.dirty := true.B diff --git a/src/main/scala/coupledL2/tl2tl/MSHRCtl.scala b/src/main/scala/coupledL2/tl2tl/MSHRCtl.scala index eba04a110..d71abaaf0 100644 --- a/src/main/scala/coupledL2/tl2tl/MSHRCtl.scala +++ b/src/main/scala/coupledL2/tl2tl/MSHRCtl.scala @@ -73,7 +73,7 @@ class MSHRCtl(implicit p: Parameters) extends L2Module with HasPerfEvents { val releaseBufWriteId = Output(UInt(mshrBits.W)) /* nested writeback */ - val nestedwb = Input(new NestedWriteback) + val nestedwb = new NestedWriteback val nestedwbDataId = Output(ValidIO(UInt(mshrBits.W))) /* status of s2 and s3 */ @@ -136,11 +136,22 @@ class MSHRCtl(implicit p: Parameters) extends L2Module with HasPerfEvents { m.io.replResp.bits := io.replResp.bits io.msInfo(i) := m.io.msInfo - m.io.nestedwb := io.nestedwb + + m.io.nestedwb.set := io.nestedwb.set + m.io.nestedwb.tag := io.nestedwb.tag + m.io.nestedwb.c_set_dirty := io.nestedwb.c_set_dirty + m.io.nestedwb.c_set_tip := io.nestedwb.c_set_tip + m.io.nestedwb.b_inv_dirty := io.nestedwb.b_inv_dirty + m.io.nestedwb.b_toB.foreach(_ := io.nestedwb.b_toB.getOrElse(false.B)) + m.io.nestedwb.b_toN.foreach(_ := io.nestedwb.b_toN.getOrElse(false.B)) + m.io.nestedwb.b_toClean.foreach(_ := io.nestedwb.b_toClean.getOrElse(false.B)) + m.io.aMergeTask.valid := io.aMergeTask.valid && io.aMergeTask.bits.id === i.U m.io.aMergeTask.bits := io.aMergeTask.bits.task } + io.nestedwb.replaceMatch := ParallelOR(mshrs.map(_.io.nestedwb.replaceMatch)) + io.toReqArb.blockC_s1 := false.B io.toReqArb.blockB_s1 := mshrFull // conflict logic in SinkB io.toReqArb.blockA_s1 := a_mshrFull // conflict logic in ReqBuf diff --git a/src/main/scala/coupledL2/tl2tl/MainPipe.scala b/src/main/scala/coupledL2/tl2tl/MainPipe.scala index 605ca022b..41154c62f 100644 --- a/src/main/scala/coupledL2/tl2tl/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2tl/MainPipe.scala @@ -92,7 +92,7 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents { /* read DS and write data into ReleaseBuf when the task needs to replace */ val releaseBufWrite = ValidIO(new MSHRBufWrite()) - val nestedwb = Output(new NestedWriteback) + val nestedwb = Flipped(new NestedWriteback) val nestedwbData = Output(new DSBlock) /* send Hint to L1 */ @@ -171,6 +171,8 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents { val cache_alias = req_acquire_s3 && dirResult_s3.hit && meta_s3.clients(0) && meta_s3.alias.getOrElse(0.U) =/= req_s3.alias.getOrElse(0.U) + val replaceNestedRelease_s3 = task_s3.valid && task_s3.bits.fromC && io.nestedwb.replaceMatch + val mshr_refill_s3 = (mshr_accessackdata_s3 || mshr_hintack_s3 || mshr_grant_s3) // needs refill to L2 DS val retry = io.replResp.bits.retry val need_repl = io.replResp.bits.meta.state =/= INVALID && req_s3.replTask // Grant needs replacement @@ -374,13 +376,13 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents { ) val metaW_s3_c = MetaEntry( - dirty = meta_s3.dirty || wen_c, - state = Mux(isParamFromT(req_s3.param), TIP, meta_s3.state), + dirty = true.B, + state = TIP, clients = Fill(clientBits, !isToN(req_s3.param)), - alias = meta_s3.alias, - accessed = meta_s3.accessed, - tagErr = Mux(wen_c, req_s3.denied, meta_s3.tagErr), - dataErr = Mux(wen_c, req_s3.corrupt, meta_s3.dataErr) // update error when write DS + alias = Some(0.U), + accessed = false.B, + tagErr = req_s3.denied, + dataErr = req_s3.corrupt // update error when write DS ) // use merge_meta if mergeA val metaW_s3_mshr = WireInit(Mux(req_s3.mergeA, req_s3.aMergeTask.meta, req_s3.meta)) @@ -401,6 +403,12 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents { ), MetaEntry() ) + io.metaWReq.bits.release.valid := metaW_valid_s3_c + io.metaWReq.bits.release.bits.clients := isToN(req_s3.param) + io.metaWReq.bits.release.bits.dirty := req_s3.opcode === ReleaseData + io.metaWReq.bits.release.bits.state := isParamFromT(req_s3.param) + io.metaWReq.bits.release.bits.tagErr := wen_c + io.metaWReq.bits.release.bits.dataErr := wen_c io.tagWReq.valid := task_s3.valid && req_s3.tagWen && mshr_refill_s3 && !retry io.tagWReq.bits.set := req_s3.set @@ -430,6 +438,7 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents { c_s3.bits.task := source_req_s3 c_s3.bits.data.data := data_s3 d_s3.bits.task := source_req_s3 + d_s3.bits.task.way := Mux(req_s3.replTask, io.replResp.bits.way, source_req_s3.way) d_s3.bits.data.data := data_s3 /* ======== nested & prefetch ======== */ @@ -755,6 +764,7 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents { io.toMonitor.allocMSHR_s3.valid := io.toMSHRCtl.mshr_alloc_s3.valid io.toMonitor.allocMSHR_s3.bits := io.fromMSHRCtl.mshr_alloc_ptr io.toMonitor.metaW_s3 := io.metaWReq + io.toMonitor.replaceNestedRelease_s3 := replaceNestedRelease_s3 /* ===== Hardware Performance Monitor ===== */ val perfEvents = Seq( diff --git a/src/main/scala/coupledL2/tl2tl/Slice.scala b/src/main/scala/coupledL2/tl2tl/Slice.scala index 3b51c48b9..2990d3bb8 100644 --- a/src/main/scala/coupledL2/tl2tl/Slice.scala +++ b/src/main/scala/coupledL2/tl2tl/Slice.scala @@ -85,7 +85,7 @@ class Slice()(implicit p: Parameters) extends BaseSlice[OuterBundle] { mshrCtl.io.resps.sinkC := sinkC.io.resp mshrCtl.io.resps.sinkD := refillUnit.io.resp mshrCtl.io.resps.sourceC := sourceC.io.resp - mshrCtl.io.nestedwb := mainPipe.io.nestedwb + mshrCtl.io.nestedwb <> mainPipe.io.nestedwb mshrCtl.io.aMergeTask := a_reqBuf.io.aMergeTask mshrCtl.io.replResp <> directory.io.replResp mainPipe.io.replResp <> directory.io.replResp From ba285397a7804955fa90bdc78b1e806e502b1534 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 10 Sep 2025 10:23:45 +0800 Subject: [PATCH 10/19] feat(TestTop): expose 'way' field in TileLink TestTop --- src/test/scala/TestTop.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/scala/TestTop.scala b/src/test/scala/TestTop.scala index 3dd6eba05..0cc985821 100644 --- a/src/test/scala/TestTop.scala +++ b/src/test/scala/TestTop.scala @@ -48,7 +48,7 @@ class TestTop_L2()(implicit p: Parameters) extends LazyModule { channelBytes = TLChannelBeatBytes(cacheParams.blockBytes), minLatency = 1, echoFields = Nil, - requestFields = Seq(AliasField(2)), + requestFields = Seq(AliasField(2), WayField()), responseKeys = cacheParams.respKey ) )) @@ -135,7 +135,7 @@ class TestTop_L2L3()(implicit p: Parameters) extends LazyModule { channelBytes = TLChannelBeatBytes(cacheParams.blockBytes), minLatency = 1, echoFields = Nil, - requestFields = Seq(AliasField(2), PrefetchField()), + requestFields = Seq(AliasField(2), PrefetchField(), WayField()), responseKeys = cacheParams.respKey ) )) @@ -281,7 +281,7 @@ class TestTop_L2_Standalone()(implicit p: Parameters) extends LazyModule { channelBytes = TLChannelBeatBytes(cacheParams.blockBytes), minLatency = 1, echoFields = Nil, - requestFields = Seq(AliasField(2)), + requestFields = Seq(AliasField(2), WayField()), responseKeys = cacheParams.respKey ) )) @@ -391,7 +391,7 @@ class TestTop_L2L3L2()(implicit p: Parameters) extends LazyModule { channelBytes = TLChannelBeatBytes(cacheParams.blockBytes), minLatency = 1, echoFields = Nil, - requestFields = Seq(AliasField(2)), + requestFields = Seq(AliasField(2), WayField()), responseKeys = cacheParams.respKey ) )) @@ -541,7 +541,7 @@ class TestTop_fullSys()(implicit p: Parameters) extends LazyModule { channelBytes = TLChannelBeatBytes(cacheParams.blockBytes), minLatency = 1, echoFields = Nil, - requestFields = Seq(AliasField(2)), + requestFields = Seq(AliasField(2), WayField()), responseKeys = cacheParams.respKey ) )) From adf6cec7223ebe74a5d9cd8e9bf968a0bc299951 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 17 Sep 2025 12:13:36 +0800 Subject: [PATCH 11/19] fix(MainPipe): pass 'way' on MainPipe-only task --- src/main/scala/coupledL2/tl2chi/MainPipe.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index e62dc24c7..ddedb49e8 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -418,6 +418,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes sink_resp_s3.valid := task_s3.valid && !mshr_req_s3 && !need_mshr_s3 sink_resp_s3.bits := task_s3.bits sink_resp_s3.bits.mshrId := (1 << (mshrBits-1)).U + sink_resp_s3.bits.sourceId + sink_resp_s3.bits.way := io.dirResp_s3.way when (req_s3.fromA) { sink_resp_s3.bits.opcode := odOpGen(req_s3.opcode) sink_resp_s3.bits.param := Mux ( From 366eebed75784f28c9394e457662cce0a95430ee Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 17 Sep 2025 17:44:22 +0800 Subject: [PATCH 12/19] fix(MainPipe): replacer 'way' alternative for source tasks --- src/main/scala/coupledL2/tl2chi/MainPipe.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index ddedb49e8..d975fb7b0 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -460,6 +460,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val source_req_s3 = Wire(new TaskBundle) source_req_s3 := Mux(sink_resp_s3.valid, sink_resp_s3.bits, req_s3) source_req_s3.isKeyword.foreach(_ := req_s3.isKeyword.getOrElse(false.B)) + source_req_s3.way := Mux(req_s3.replTask, io.replResp.bits.way, req_s3.way) /* ======== Interact with DS ======== */ val data_s3 = Mux(io.releaseBufResp_s3.valid, io.releaseBufResp_s3.bits.data, io.refillBufResp_s3.bits.data) @@ -670,7 +671,6 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes txdat_s3.bits.task := source_req_s3 txdat_s3.bits.data.data := data_s3 d_s3.bits.task := source_req_s3 - d_s3.bits.task.way := Mux(source_req_s3.replTask, io.replResp.bits.way, source_req_s3.way) d_s3.bits.data.data := data_s3 when (task_s3.valid) { From c456451b3770f79f5b600588cf19994564d87840 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Thu, 18 Sep 2025 15:18:53 +0800 Subject: [PATCH 13/19] fix(MainPipe): directory result alternative on non-MSHR task --- src/main/scala/coupledL2/tl2chi/MainPipe.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/coupledL2/tl2chi/MainPipe.scala b/src/main/scala/coupledL2/tl2chi/MainPipe.scala index d975fb7b0..8bbdbd451 100644 --- a/src/main/scala/coupledL2/tl2chi/MainPipe.scala +++ b/src/main/scala/coupledL2/tl2chi/MainPipe.scala @@ -460,7 +460,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes val source_req_s3 = Wire(new TaskBundle) source_req_s3 := Mux(sink_resp_s3.valid, sink_resp_s3.bits, req_s3) source_req_s3.isKeyword.foreach(_ := req_s3.isKeyword.getOrElse(false.B)) - source_req_s3.way := Mux(req_s3.replTask, io.replResp.bits.way, req_s3.way) + source_req_s3.way := Mux(req_s3.replTask, io.replResp.bits.way, Mux(req_s3.mshrTask, req_s3.way, dirResult_s3.way)) /* ======== Interact with DS ======== */ val data_s3 = Mux(io.releaseBufResp_s3.valid, io.releaseBufResp_s3.bits.data, io.refillBufResp_s3.bits.data) From d542c66646ef51390b3edfb2d9a762b83869a00f Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 24 Sep 2025 15:40:02 +0800 Subject: [PATCH 14/19] feat(RequestArb): loosen stall condition for releases * Release & ReleaseData would be no more blocked by Directory at s1 * Release would be no more blocked by MCP2 stall at s1 --- src/main/scala/coupledL2/RequestArb.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 7fb866bb4..028f9d7d0 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -150,11 +150,12 @@ class RequestArb(implicit p: Parameters) extends L2Module // TODO: A Hint is allowed to enter if !s2_ready for mcp2_stall - val sink_ready_basic = io.dirRead_s1.ready && resetFinish && !mshr_task_s1.valid && s2_ready + val sink_ready_nodir = resetFinish && !mshr_task_s1.valid && s2_ready + val sink_ready_basic = io.dirRead_s1.ready && sink_ready_nodir io.sinkA.ready := sink_ready_basic && !block_A && !sinkValids(1) && !sinkValids(0) // SinkC prior to SinkA & SinkB io.sinkB.ready := sink_ready_basic && !block_B && !sinkValids(0) // SinkB prior to SinkA - io.sinkC.ready := sink_ready_basic && !block_C + io.sinkC.ready := sink_ready_nodir && !block_C val chnl_task_s1 = Wire(Valid(new TaskBundle())) chnl_task_s1.valid := io.dirRead_s1.ready && sinkValids.orR && resetFinish @@ -207,7 +208,10 @@ class RequestArb(implicit p: Parameters) extends L2Module // might access DS, and continuous DS accesses are prohibited val ds_mcp2_stall = RegNext(s1_fire && !s1_AHint_fire && !s1_CRelease_fire) - s2_ready := !ds_mcp2_stall + // let Release go through even if MCP2 stall active + val s1_CRelease_letgo = !mshr_task_s1.valid && io.sinkC.valid && io.sinkC.bits.opcode === Release + + s2_ready := !ds_mcp2_stall || s1_CRelease_letgo val task_s2 = RegInit(0.U.asTypeOf(task_s1)) task_s2.valid := s1_fire From 4d363d4c3abfcbcd14da37eae90412a27f9c2704 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Sun, 28 Sep 2025 16:23:56 +0800 Subject: [PATCH 15/19] fix(RequestArb): remove directory ready condition on channel C --- src/main/scala/coupledL2/RequestArb.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 028f9d7d0..12bb9a904 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -158,7 +158,7 @@ class RequestArb(implicit p: Parameters) extends L2Module io.sinkC.ready := sink_ready_nodir && !block_C val chnl_task_s1 = Wire(Valid(new TaskBundle())) - chnl_task_s1.valid := io.dirRead_s1.ready && sinkValids.orR && resetFinish + chnl_task_s1.valid := (io.sinkC.valid && !io.mshrTask.valid || io.dirRead_s1.ready) && sinkValids.orR && resetFinish chnl_task_s1.bits := ParallelPriorityMux(sinkValids, Seq(C_task, B_task, A_task)) // mshr_task_s1 is s1_[reg] @@ -208,10 +208,10 @@ class RequestArb(implicit p: Parameters) extends L2Module // might access DS, and continuous DS accesses are prohibited val ds_mcp2_stall = RegNext(s1_fire && !s1_AHint_fire && !s1_CRelease_fire) - // let Release go through even if MCP2 stall active + // let Release go through even if MCP2 stall active (not supported by MainPipe) val s1_CRelease_letgo = !mshr_task_s1.valid && io.sinkC.valid && io.sinkC.bits.opcode === Release - s2_ready := !ds_mcp2_stall || s1_CRelease_letgo + s2_ready := !ds_mcp2_stall /*|| s1_CRelease_letgo*/ val task_s2 = RegInit(0.U.asTypeOf(task_s1)) task_s2.valid := s1_fire From e06f207476d3cc063181de82e61c20d53294ea32 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Mon, 29 Sep 2025 17:53:32 +0800 Subject: [PATCH 16/19] fix(RequestArb): eliminated sink C stall by directory --- src/main/scala/coupledL2/RequestArb.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 12bb9a904..56135fe40 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -158,15 +158,15 @@ class RequestArb(implicit p: Parameters) extends L2Module io.sinkC.ready := sink_ready_nodir && !block_C val chnl_task_s1 = Wire(Valid(new TaskBundle())) - chnl_task_s1.valid := (io.sinkC.valid && !io.mshrTask.valid || io.dirRead_s1.ready) && sinkValids.orR && resetFinish + chnl_task_s1.valid := (io.sinkC.valid && !mshr_task_s1.valid || io.dirRead_s1.ready) && sinkValids.orR && resetFinish chnl_task_s1.bits := ParallelPriorityMux(sinkValids, Seq(C_task, B_task, A_task)) // mshr_task_s1 is s1_[reg] // task_s1 is [wire] to s2_reg val task_s1 = Mux(mshr_task_s1.valid, mshr_task_s1, chnl_task_s1) - val s1_to_s2_valid = task_s1.valid && !mshr_replRead_stall + val s1_to_s2_valid = task_s1.valid && (!mshr_replRead_stall || task_s1.bits.fromC) - s1_cango := task_s1.valid && !mshr_replRead_stall + s1_cango := s1_to_s2_valid s1_fire := s1_cango && s2_ready io.taskInfo_s1.valid := s1_fire From a5f20a43d713bd13ef242aa64fc1c73185b7fcd2 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Mon, 29 Sep 2025 18:20:14 +0800 Subject: [PATCH 17/19] fix(RequestArb): disable Release/ReleaseData stall relax for TL2TL --- src/main/scala/coupledL2/RequestArb.scala | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 56135fe40..3137c3e54 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -155,16 +155,29 @@ class RequestArb(implicit p: Parameters) extends L2Module io.sinkA.ready := sink_ready_basic && !block_A && !sinkValids(1) && !sinkValids(0) // SinkC prior to SinkA & SinkB io.sinkB.ready := sink_ready_basic && !block_B && !sinkValids(0) // SinkB prior to SinkA - io.sinkC.ready := sink_ready_nodir && !block_C + + if (enableCHI) + io.sinkC.ready := sink_ready_nodir && !block_C + else + io.sinkC.ready := sink_ready_basic && !block_C val chnl_task_s1 = Wire(Valid(new TaskBundle())) - chnl_task_s1.valid := (io.sinkC.valid && !mshr_task_s1.valid || io.dirRead_s1.ready) && sinkValids.orR && resetFinish chnl_task_s1.bits := ParallelPriorityMux(sinkValids, Seq(C_task, B_task, A_task)) + if (enableCHI) + chnl_task_s1.valid := (io.sinkC.valid && !mshr_task_s1.valid || io.dirRead_s1.ready) && sinkValids.orR && resetFinish + else + chnl_task_s1.valid := io.dirRead_s1.ready && sinkValids.orR && resetFinish + // mshr_task_s1 is s1_[reg] // task_s1 is [wire] to s2_reg val task_s1 = Mux(mshr_task_s1.valid, mshr_task_s1, chnl_task_s1) - val s1_to_s2_valid = task_s1.valid && (!mshr_replRead_stall || task_s1.bits.fromC) + val s1_to_s2_valid = Wire(Bool()) + + if (enableCHI) + s1_to_s2_valid := task_s1.valid && (!mshr_replRead_stall || task_s1.bits.fromC) + else + s1_to_s2_valid := task_s1.valid && !mshr_replRead_stall s1_cango := s1_to_s2_valid s1_fire := s1_cango && s2_ready From 71974cdbf15f6899db131f002674edf61a1f2fd9 Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Tue, 4 Nov 2025 17:08:12 +0800 Subject: [PATCH 18/19] fix(RequestArb): inequal fire condition for RequestBuf and MainPipe s1 --- src/main/scala/coupledL2/RequestArb.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 3137c3e54..32374d139 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -165,7 +165,7 @@ class RequestArb(implicit p: Parameters) extends L2Module chnl_task_s1.bits := ParallelPriorityMux(sinkValids, Seq(C_task, B_task, A_task)) if (enableCHI) - chnl_task_s1.valid := (io.sinkC.valid && !mshr_task_s1.valid || io.dirRead_s1.ready) && sinkValids.orR && resetFinish + chnl_task_s1.valid := (io.sinkC.fire || io.dirRead_s1.ready) && sinkValids.orR && resetFinish else chnl_task_s1.valid := io.dirRead_s1.ready && sinkValids.orR && resetFinish @@ -175,7 +175,7 @@ class RequestArb(implicit p: Parameters) extends L2Module val s1_to_s2_valid = Wire(Bool()) if (enableCHI) - s1_to_s2_valid := task_s1.valid && (!mshr_replRead_stall || task_s1.bits.fromC) + s1_to_s2_valid := task_s1.valid && (!mshr_replRead_stall || io.sinkC.fire) else s1_to_s2_valid := task_s1.valid && !mshr_replRead_stall From 78ae1a88a3e37172f31e5422a950796c7bcc8a4e Mon Sep 17 00:00:00 2001 From: Kumonda221 Date: Wed, 26 Nov 2025 22:06:36 +0800 Subject: [PATCH 19/19] fix(RequestArb): unified condition for Release MCP2 skipping --- src/main/scala/coupledL2/RequestArb.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/coupledL2/RequestArb.scala b/src/main/scala/coupledL2/RequestArb.scala index 32374d139..0db5ae877 100644 --- a/src/main/scala/coupledL2/RequestArb.scala +++ b/src/main/scala/coupledL2/RequestArb.scala @@ -222,7 +222,7 @@ class RequestArb(implicit p: Parameters) extends L2Module val ds_mcp2_stall = RegNext(s1_fire && !s1_AHint_fire && !s1_CRelease_fire) // let Release go through even if MCP2 stall active (not supported by MainPipe) - val s1_CRelease_letgo = !mshr_task_s1.valid && io.sinkC.valid && io.sinkC.bits.opcode === Release + val s1_CRelease_letgo = s1_CRelease_fire s2_ready := !ds_mcp2_stall /*|| s1_CRelease_letgo*/