Skip to content

Commit ad488fa

Browse files
fix(MainPipe): unified meta read on snoop nesting release (#369)
1 parent 79dd4bd commit ad488fa

File tree

7 files changed

+98
-106
lines changed

7 files changed

+98
-106
lines changed

src/main/scala/coupledL2/Common.scala

+2-5
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ class TaskBundle(implicit p: Parameters) extends L2Bundle
124124
val snpHitReleaseToClean = Bool()
125125
val snpHitReleaseWithData = Bool()
126126
val snpHitReleaseIdx = UInt(mshrBits.W)
127-
val snpHitReleaseState = UInt(2.W)
128-
val snpHitReleaseDirty = Bool()
127+
val snpHitReleaseMeta = new MetaEntry
129128
// CHI
130129
val tgtID = chiOpt.map(_ => UInt(TGTID_WIDTH.W))
131130
val srcID = chiOpt.map(_ => UInt(SRCID_WIDTH.W))
@@ -204,10 +203,8 @@ class MSHRInfo(implicit p: Parameters) extends L2Bundle with HasTLChannelBits {
204203
// PS: ReleaseTask is also responsible for writing refillData to DS when A miss
205204
val blockRefill = Bool()
206205

206+
val meta = new MetaEntry
207207
val metaTag = UInt(tagBits.W)
208-
val metaState = UInt(stateBits.W)
209-
val metaDirty = Bool()
210-
val probeDirty = Bool()
211208
val dirHit = Bool()
212209

213210
// to drop duplicate prefetch reqs

src/main/scala/coupledL2/tl2chi/MSHR.scala

+9-12
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes {
183183
// *NOTICE: WriteBack/WriteClean(s) with nested snoops that passed dirty were not considered as
184184
// a nested hit here, which would no longer pass latest data to lower tier memories.
185185
val hitDirty = dirResult.hit && meta.dirty || probeDirty
186-
val hitWriteBack = req.snpHitRelease && req.snpHitReleaseWithData && req.snpHitReleaseDirty && req.snpHitReleaseToInval
187-
val hitWriteClean = req.snpHitRelease && req.snpHitReleaseWithData && req.snpHitReleaseDirty && req.snpHitReleaseToClean
188-
val hitWriteEvict = req.snpHitRelease && req.snpHitReleaseWithData && !req.snpHitReleaseDirty
186+
val hitWriteBack = req.snpHitRelease && req.snpHitReleaseWithData && req.snpHitReleaseMeta.dirty && req.snpHitReleaseToInval
187+
val hitWriteClean = req.snpHitRelease && req.snpHitReleaseWithData && req.snpHitReleaseMeta.dirty && req.snpHitReleaseToClean
188+
val hitWriteEvict = req.snpHitRelease && req.snpHitReleaseWithData && !req.snpHitReleaseMeta.dirty
189189

190190
val hitWriteX = hitWriteBack || hitWriteClean || hitWriteEvict
191191
val hitWriteDirty = hitWriteBack || hitWriteClean
@@ -310,9 +310,9 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes {
310310
// *NOTICE: Snp*Fwd would enter MSHR on directory missing
311311
val respCacheState = ParallelPriorityMux(Seq(
312312
snpToN -> I,
313-
snpToB -> Mux(!dirResult.hit, I, SC),
313+
snpToB -> Mux(req.snpHitReleaseToInval, I, SC),
314314
isSnpOnceX(req_chiOpcode) ->
315-
Mux(!dirResult.hit, I, Mux(
315+
Mux(req.snpHitReleaseToInval, I, Mux(
316316
req.snpHitReleaseToClean,
317317
SC,
318318
Mux(probeDirty || meta.dirty, UD, metaChi)
@@ -893,8 +893,7 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes {
893893
mp_dct.snpHitReleaseToClean := req.snpHitReleaseToClean
894894
mp_dct.snpHitReleaseWithData := req.snpHitReleaseWithData
895895
mp_dct.snpHitReleaseIdx := req.snpHitReleaseIdx
896-
mp_dct.snpHitReleaseState := req.snpHitReleaseState
897-
mp_dct.snpHitReleaseDirty := req.snpHitReleaseDirty
896+
mp_dct.snpHitReleaseMeta := req.snpHitReleaseMeta
898897

899898
mp_dct
900899
}
@@ -956,8 +955,7 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes {
956955
mp_cmometaw.snpHitReleaseToClean := req.snpHitReleaseToClean
957956
mp_cmometaw.snpHitReleaseWithData := req.snpHitReleaseWithData
958957
mp_cmometaw.snpHitReleaseIdx := req.snpHitReleaseIdx
959-
mp_cmometaw.snpHitReleaseState := req.snpHitReleaseState
960-
mp_cmometaw.snpHitReleaseDirty := req.snpHitReleaseDirty
958+
mp_cmometaw.snpHitReleaseMeta := req.snpHitReleaseMeta
961959

962960
mp_cmometaw
963961
}
@@ -1313,9 +1311,8 @@ class MSHR(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes {
13131311
io.msInfo.bits.blockRefill := releaseNotSent || RegNext(releaseNotSent, false.B) || RegNext(RegNext(releaseNotSent, false.B), false.B)
13141312
io.msInfo.bits.dirHit := dirResult.hit
13151313
io.msInfo.bits.metaTag := dirResult.tag
1316-
io.msInfo.bits.metaState := meta.state
1317-
io.msInfo.bits.metaDirty := meta.dirty
1318-
io.msInfo.bits.probeDirty := probeDirty
1314+
io.msInfo.bits.meta := meta
1315+
io.msInfo.bits.meta.dirty := meta.dirty || probeDirty
13191316
io.msInfo.bits.willFree := will_free
13201317
io.msInfo.bits.isAcqOrPrefetch := req_acquire || req_prefetch
13211318
io.msInfo.bits.isPrefetch := req_prefetch

src/main/scala/coupledL2/tl2chi/MainPipe.scala

+74-72
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,19 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
194194
val cache_alias = req_acquire_s3 && dirResult_s3.hit && meta_s3.clients(0) &&
195195
meta_s3.alias.getOrElse(0.U) =/= req_s3.alias.getOrElse(0.U)
196196

197+
// *NOTICE: 'nestable_*' must not be used in A Channel related logics.
198+
val nestable_dirResult_s3 = Wire(chiselTypeOf(dirResult_s3))
199+
val nestable_meta_s3 = nestable_dirResult_s3.meta
200+
val nestable_meta_has_clients_s3 = nestable_dirResult_s3.meta.clients.orR
201+
nestable_dirResult_s3 := dirResult_s3
202+
when (req_s3.snpHitRelease) {
203+
// Meta states from MSHRs were considered as directory result here.
204+
// Therefore, meta states were always inferred to be hit when nesting release, no matter the fact that directory
205+
// was always non-hit on cache replacement subsequent release.
206+
nestable_dirResult_s3.hit := true.B
207+
nestable_dirResult_s3.meta := req_s3.snpHitReleaseMeta
208+
}
209+
197210
val tagError_s3 = io.dirResp_s3.error || meta_s3.tagErr
198211
val dataError_s3 = meta_s3.dataErr
199212
val l2Error_s3 = io.dirResp_s3.error || mshr_req_s3 && req_s3.dataCheckErr.getOrElse(false.B)
@@ -206,6 +219,8 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
206219
val need_repl = replResp_valid_hold && io.replResp.bits.meta.state =/= INVALID && req_s3.replTask
207220

208221
/* ======== Interact with MSHR ======== */
222+
// *NOTICE: A Channel requests should be blocked by RequestBuffer when MSHR nestable,
223+
// 'nestable_*' must not be used here.
209224
val acquire_on_miss_s3 = req_acquire_s3 || req_prefetch_s3 || req_get_s3
210225
val acquire_on_hit_s3 = meta_s3.state === BRANCH && req_needT_s3 && !req_prefetch_s3
211226
val need_acquire_s3_a = req_s3.fromA && (Mux(
@@ -244,9 +259,8 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
244259
*/
245260
// whether L2 should do forwarding or not
246261
val expectFwd = isSnpXFwd(req_s3.chiOpcode.get)
247-
val canFwd = dirResult_s3.hit
262+
val canFwd = nestable_dirResult_s3.hit
248263
val doFwd = expectFwd && canFwd
249-
val doFwdHitRelease = expectFwd && req_s3.snpHitRelease && req_s3.snpHitReleaseWithData
250264
val need_pprobe_s3_b_snpStable = req_s3.fromB && (
251265
isSnpOnceX(req_s3.chiOpcode.get) || isSnpQuery(req_s3.chiOpcode.get) || isSnpStashX(req_s3.chiOpcode.get)
252266
) && dirResult_s3.hit && meta_s3.state === TRUNK && meta_has_clients_s3
@@ -260,7 +274,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
260274
isSnpMakeInvalidX(req_s3.chiOpcode.get)
261275
) && dirResult_s3.hit && meta_has_clients_s3
262276
val need_pprobe_s3_b = need_pprobe_s3_b_snpStable || need_pprobe_s3_b_snpToB || need_pprobe_s3_b_snpToN
263-
val need_dct_s3_b = doFwd || doFwdHitRelease // DCT
277+
val need_dct_s3_b = doFwd // DCT
264278
val need_mshr_s3_b = need_pprobe_s3_b || need_dct_s3_b
265279

266280
val need_mshr_s3 = need_mshr_s3_a || need_mshr_s3_b
@@ -269,7 +283,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
269283
val alloc_state = WireInit(0.U.asTypeOf(new FSMState()))
270284
alloc_state.elements.foreach(_._2 := true.B)
271285
io.toMSHRCtl.mshr_alloc_s3.valid := task_s3.valid && !mshr_req_s3 && need_mshr_s3
272-
io.toMSHRCtl.mshr_alloc_s3.bits.dirResult := dirResult_s3
286+
io.toMSHRCtl.mshr_alloc_s3.bits.dirResult := nestable_dirResult_s3
273287
io.toMSHRCtl.mshr_alloc_s3.bits.state := alloc_state
274288
io.toMSHRCtl.mshr_alloc_s3.bits.task match { case task =>
275289
task := req_s3
@@ -291,75 +305,86 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
291305
isSnpQuery(req_s3.chiOpcode.get) ||
292306
req_s3.chiOpcode.get === SnpOnceFwd ||
293307
req_s3.chiOpcode.get === SnpUniqueFwd
294-
val shouldRespData_dirty = dirResult_s3.hit && (meta_s3.state === TIP || meta_s3.state === TRUNK) && meta_s3.dirty
308+
val shouldRespData_dirty = nestable_dirResult_s3.hit &&
309+
(nestable_meta_s3.state === TIP || nestable_meta_s3.state === TRUNK) && nestable_meta_s3.dirty
295310
// For forwarding snoops, if the RetToSrc value is 1, must return a copy is the cache line is Dirty or Clean.
296-
val shouldRespData_retToSrc_fwd = dirResult_s3.hit && retToSrc && isSnpXFwd(req_s3.chiOpcode.get)
311+
val shouldRespData_retToSrc_fwd = nestable_dirResult_s3.hit && retToSrc && isSnpXFwd(req_s3.chiOpcode.get)
297312
// For non-forwarding snoops, ig the RetToSrc value is 1, must return a copy if the cache line is Shared Clean and
298313
// snoopee retains a copy of the cache line.
299-
val shouldRespData_retToSrc_nonFwd = dirResult_s3.hit && retToSrc && meta_s3.state === BRANCH && (
314+
val shouldRespData_retToSrc_nonFwd = nestable_dirResult_s3.hit && retToSrc && nestable_meta_s3.state === BRANCH && (
300315
req_s3.chiOpcode.get === SnpOnce ||
301316
req_s3.chiOpcode.get === SnpUnique ||
302317
isSnpToBNonFwd(req_s3.chiOpcode.get)
303318
)
304319
val shouldRespData = shouldRespData_dirty || shouldRespData_retToSrc_fwd || shouldRespData_retToSrc_nonFwd
305320
val doRespData = shouldRespData && !neverRespData
306-
val doRespDataHitRelease = req_s3.snpHitRelease && req_s3.snpHitReleaseWithData && !neverRespData
307321
dontTouch(doRespData)
308322
dontTouch(shouldRespData)
309323
dontTouch(neverRespData)
310324

325+
// On directory hit under non-invalidating snoop nesting WriteCleanFull,
326+
// excluding SnpStashX and SnpQuery:
327+
// 1. SnpCleanShared[1-sink_resp] : UD -> UC_PD, UC -> UC, SC -> SC
328+
// 2. SnpOnce*[2-sink_resp] : UD -> SC_PD, UC -> SC, SC -> SC
329+
// 3. snpToB : UD -> SC_PD, UC -> SC, SC -> SC
330+
//
331+
// *NOTE[1-sink_resp]:
332+
// UD -> SC transitions were not used on WriteCleanFull without nesting snoop, and
333+
// only UD -> UC update could be observed on directory in this case
334+
// Therefore, it was unnecessary to observe cache state from nested WriteCleanFull MSHRs, while
335+
// extracting PassDirty from MSHRs
336+
//
337+
// *NOTE[2-sink_resp]:
338+
// UD -> UC transitions were not allowed on SnpOnce*, while permitting UD -> UD and UC -> UC
339+
// On SnpOnce*, UD/UC were turned into SC on nested WriteClean, on which directory must hit
340+
// Otherwise, the cache state was fast forwarded to I by default
341+
// Directory might be missing after multiple nesting snoops on WriteClean, indicating losing UD
342+
//
311343
// Resp[2: 0] = {PassDirty, CacheState[1: 0]}
312344
val respCacheState = WireInit(I)
313-
val respPassDirty = dirResult_s3.hit && meta_s3.state === TIP && meta_s3.dirty &&
314-
!(neverRespData || req_s3.chiOpcode.get === SnpOnce) &&
345+
val respPassDirty = doRespData && nestable_dirResult_s3.hit && isT(nestable_meta_s3.state) && nestable_meta_s3.dirty &&
346+
(req_s3.chiOpcode.get =/= SnpOnce || req_s3.snpHitRelease) &&
315347
!(isSnpStashX(req_s3.chiOpcode.get) || isSnpQuery(req_s3.chiOpcode.get))
316348

317-
when (dirResult_s3.hit) {
349+
when (nestable_dirResult_s3.hit) {
318350
when (isSnpToB(req_s3.chiOpcode.get)) {
319-
respCacheState := SC
351+
respCacheState := Mux(req_s3.snpHitReleaseToInval, I, SC)
320352
}
321353
when (isSnpOnceX(req_s3.chiOpcode.get) || isSnpStashX(req_s3.chiOpcode.get) || isSnpQuery(req_s3.chiOpcode.get)) {
354+
/**
355+
* NOTICE: On Stash and Query:
356+
* the cache state must maintain unchanged on nested copy-back writes
357+
*/
322358
respCacheState := Mux(
323-
meta_s3.state === BRANCH,
359+
nestable_meta_s3.state === BRANCH,
324360
SC,
325-
Mux(meta_s3.dirty, UD, UC)
361+
Mux(nestable_meta_s3.dirty, UD, UC)
326362
)
327363
}
328-
when (req_s3.chiOpcode.get === SnpCleanShared) {
329-
respCacheState := Mux(isT(meta_s3.state), UC, SC)
330-
}
331-
332-
when (req_s3.snpHitReleaseToClean) {
364+
when (isSnpOnceX(req_s3.chiOpcode.get)) {
333365
// On SnpOnce/SnpOnceFwd nesting WriteCleanFull, turn UD/UC to SC
334-
when (isSnpOnceX(req_s3.chiOpcode.get)) {
366+
when (req_s3.snpHitReleaseToClean) {
335367
respCacheState := SC
336368
}
369+
// On SnpOnce/SnpOnceFwd nesting WriteBack*/WriteEvict*, turn UD to I
370+
when (req_s3.snpHitReleaseToInval) {
371+
respCacheState := I
372+
}
337373
}
338-
}
339-
340-
when (req_s3.snpHitRelease) {
341-
/**
342-
* NOTICE: On Stash and Query:
343-
* the cache state must maintain unchanged on nested copy-back writes
344-
*/
345-
when (isSnpStashX(req_s3.chiOpcode.get) || isSnpQuery(req_s3.chiOpcode.get)) {
346-
respCacheState := Mux(
347-
req_s3.snpHitReleaseState === BRANCH,
348-
SC,
349-
Mux(req_s3.snpHitReleaseDirty, UD, UC)
350-
)
374+
when (req_s3.chiOpcode.get === SnpCleanShared) {
375+
respCacheState := Mux(isT(nestable_meta_s3.state), UC, SC)
351376
}
352377
}
353378

354379
// FwdState[2: 0] = {PassDirty, CacheState[1: 0]}
355380
val fwdCacheState = WireInit(I)
356381
val fwdPassDirty = WireInit(false.B)
357-
when (dirResult_s3.hit) {
382+
when (nestable_dirResult_s3.hit) {
358383
when (isSnpToBFwd(req_s3.chiOpcode.get)) {
359-
fwdCacheState := SC
384+
fwdCacheState := Mux(req_s3.snpHitReleaseToInval, I, SC)
360385
}
361386
when (req_s3.chiOpcode.get === SnpUniqueFwd) {
362-
when (meta_s3.state === TIP && meta_s3.dirty) {
387+
when (nestable_meta_s3.state === TIP && nestable_meta_s3.dirty) {
363388
fwdCacheState := UD
364389
fwdPassDirty := true.B
365390
}.otherwise {
@@ -392,44 +417,17 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
392417
sink_resp_s3.bits.dbID.foreach(_ := 0.U)
393418
sink_resp_s3.bits.pCrdType.foreach(_ := 0.U) // TODO
394419
sink_resp_s3.bits.chiOpcode.foreach(_ := MuxLookup(
395-
Cat(doFwd || doFwdHitRelease, doRespData || doRespDataHitRelease),
420+
Cat(doFwd, doRespData),
396421
SnpResp
397422
)(Seq(
398423
Cat(false.B, false.B) -> SnpResp,
399424
Cat(true.B, false.B) -> SnpRespFwded,
400425
Cat(false.B, true.B) -> SnpRespData, // ignore SnpRespDataPtl for now
401426
Cat(true.B, true.B) -> SnpRespDataFwded
402427
)))
403-
sink_resp_s3.bits.resp.foreach(_ := Mux(
404-
req_s3.snpHitRelease && !(isSnpStashX(req_s3.chiOpcode.get) || isSnpQuery(req_s3.chiOpcode.get)),
405-
setPD(
406-
// On directory hit under non-invalidating snoop nesting WriteCleanFull,
407-
// excluding SnpStashX and SnpQuery:
408-
// 1. SnpCleanShared[1-sink_resp] : UD -> UC_PD, UC -> UC, SC -> SC
409-
// 2. SnpOnce*[2-sink_resp] : UD -> SC_PD, UC -> SC, SC -> SC
410-
// 3. snpToB : UD -> SC_PD, UC -> SC, SC -> SC
411-
//
412-
// *NOTE[1-sink_resp]:
413-
// UD -> SC transitions were not used on WriteCleanFull without nesting snoop, and
414-
// only UD -> UC update could be observed on directory in this case
415-
// Therefore, it was unnecessary to observe cache state from nested WriteCleanFull MSHRs, while
416-
// extracting PassDirty from MSHRs
417-
//
418-
// *NOTE[2-sink_resp]:
419-
// UD -> UC transitions were not allowed on SnpOnce*, while permitting UD -> UD and UC -> UC
420-
// On SnpOnce*, UD/UC were turned into SC on nested WriteClean, on which directory must hit
421-
// Otherwise, the cache state was fast forwarded to I by default
422-
// Directory might be missing after multiple nesting snoops on WriteClean, indicating losing UD
423-
Mux(req_s3.snpHitReleaseToClean && !isSnpToN(req_s3.chiOpcode.get), respCacheState, I),
424-
req_s3.snpHitReleaseWithData && req_s3.snpHitReleaseDirty && !isSnpMakeInvalidX(req_s3.chiOpcode.get)),
425-
setPD(respCacheState, respPassDirty && (doRespData || doRespDataHitRelease))
426-
))
428+
sink_resp_s3.bits.resp.foreach(_ := setPD(respCacheState, respPassDirty && doRespData))
427429
sink_resp_s3.bits.fwdState.foreach(_ := setPD(fwdCacheState, fwdPassDirty))
428-
sink_resp_s3.bits.txChannel := Cat(
429-
doRespData || doRespDataHitRelease,
430-
!(doRespData || doRespDataHitRelease),
431-
false.B
432-
) // TODO: parameterize this
430+
sink_resp_s3.bits.txChannel := Cat(doRespData, !doRespData, false.B) // TODO: parameterize this
433431
sink_resp_s3.bits.size := log2Ceil(blockBytes).U
434432
sink_resp_s3.bits.meta := sink_resp_s3_b_meta
435433
sink_resp_s3.bits.metaWen := sink_resp_s3_b_metaWen
@@ -451,9 +449,9 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
451449
val hasData_s3 = hasData_s3_tl || hasData_s3_chi
452450

453451
val need_data_a = dirResult_s3.hit && (req_get_s3 || req_acquireBlock_s3)
454-
val need_data_b = sinkB_req_s3 && (doRespData || doFwd || dirResult_s3.hit && meta_s3.state === TRUNK)
452+
val need_data_b = sinkB_req_s3 && (doRespData || doFwd || nestable_dirResult_s3.hit && nestable_meta_s3.state === TRUNK)
455453
val need_data_mshr_repl = mshr_refill_s3 && need_repl && !retry
456-
val need_data_cmo = cmo_cbo_s3 && dirResult_s3.hit && meta_s3.dirty
454+
val need_data_cmo = cmo_cbo_s3 && nestable_dirResult_s3.hit && nestable_meta_s3.dirty
457455
val ren = need_data_a || need_data_b || need_data_mshr_repl || need_data_cmo
458456

459457
val wen_c = sinkC_req_s3 && isParamFromT(req_s3.param) && req_s3.opcode(0) && dirResult_s3.hit
@@ -507,11 +505,13 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
507505
val need_write_refillBuf = false.B
508506

509507
/* ======== Write Directory ======== */
508+
// B, C: Requests from Channel B (RXSNP) and Channel C would only downgrade permission,
509+
// so there is no need to use 'nestable_*'.
510510
val metaW_valid_s3_a = sinkA_req_s3 && !need_mshr_s3_a && !req_get_s3 && !req_prefetch_s3 && !cmo_cbo_s3 // get & prefetch that hit will not write meta
511511
// Also write directory on:
512512
// 1. SnpOnce nesting WriteCleanFull under UD (SnpOnceFwd always needs MSHR) for UD -> SC
513513
val metaW_valid_s3_b = sinkB_req_s3 && !need_mshr_s3_b && dirResult_s3.hit &&
514-
(!isSnpOnce(req_s3.chiOpcode.get) || (req_s3.snpHitReleaseToClean && req_s3.snpHitReleaseDirty)) &&
514+
(!isSnpOnce(req_s3.chiOpcode.get) || (req_s3.snpHitReleaseToClean && req_s3.snpHitReleaseMeta.dirty)) &&
515515
!isSnpStashX(req_s3.chiOpcode.get) && !isSnpQuery(req_s3.chiOpcode.get) && (
516516
meta_s3.state === TIP || meta_s3.state === BRANCH && isSnpToN(req_s3.chiOpcode.get)
517517
)
@@ -623,12 +623,14 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
623623
val isTXDAT_s3 = Mux(
624624
mshr_req_s3,
625625
mshr_snpRespDataX_s3 || mshr_cbWrData_s3 || mshr_dct_s3,
626-
req_s3.fromB && !need_mshr_s3 && (doRespDataHitRelease || doRespData && !data_unready_s3)
626+
req_s3.fromB && !need_mshr_s3 &&
627+
(doRespData && (!data_unready_s3 || req_s3.snpHitRelease && req_s3.snpHitReleaseWithData))
627628
)
628629
val isTXDAT_s3_ready = Mux(
629630
mshr_req_s3,
630631
mshr_snpRespDataX_s3 || mshr_cbWrData_s3 || mshr_dct_s3,
631-
req_s3.fromB && !need_mshr_s3 && (doRespDataHitRelease || doRespData && !data_unready_s3) && !txdat_s3_latch.B
632+
req_s3.fromB && !need_mshr_s3 && !txdat_s3_latch.B &&
633+
(doRespData && (!data_unready_s3 || req_s3.snpHitRelease && req_s3.snpHitReleaseWithData))
632634
)
633635
val isTXREQ_s3 = mshr_req_s3 && (mshr_writeBackFull_s3 || mshr_writeCleanFull_s3 ||
634636
mshr_writeEvictFull_s3 || mshr_writeEvictOrEvict_s3 || mshr_evict_s3)
@@ -897,7 +899,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
897899
// TXDAT
898900
!neverRespData,
899901
// TXRSP
900-
!doRespDataHitRelease,
902+
!(doRespData && req_s3.snpHitRelease),
901903
// TXREQ
902904
task.bits.toTXREQ
903905
)

0 commit comments

Comments
 (0)