diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index 6123a6c70d..5d614dcc24 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -401,6 +401,12 @@ action(Initiate_Replacement, desc="") { } copyCacheAndDir(cache_entry, getDirEntry(address), tbe, initial); + // UD_RU line needs to be written back because the upstream may be in UC state. + if (initial == State:UD_RU) { + tbe.dataBlk := cache_entry.DataBlk; + tbe.dataBlkValid.fillMask(); + } + // model the initial tag array read tbe.actions.pushNB(Event:TagArrayRead); @@ -1553,7 +1559,8 @@ action(Send_InvSnpResp, desc="") { action(Send_WriteBackOrWriteEvict, desc="") { assert(is_valid(tbe)); assert(tbe.dataBlkValid.isFull()); - assert(tbe.dataValid); + assert(tbe.dataValid || + (tbe.dir_ownerIsExcl && tbe.dataUnique && tbe.dataDirty)); assert(is_HN == false); assert(tbe.dataUnique || tbe.dataDirty); @@ -1576,7 +1583,9 @@ action(Send_WriteBackOrWriteEvict, desc="") { action(Send_WriteCleanFull, desc="") { assert(is_valid(tbe)); assert(tbe.dataBlkValid.isFull()); - assert(tbe.dataValid); + // Data must be valid or the line was in UD_RU state. + assert(tbe.dataValid || + (tbe.dir_ownerIsExcl && tbe.dataUnique && tbe.dataDirty)); assert(is_HN == false); assert(tbe.dataDirty); @@ -2654,14 +2663,20 @@ action(Send_WBData, desc="") { if (is_HN) { assert(tbe.dataBlkValid.isFull()); assert(tbe.dataDirty); - assert(tbe.dataValid); + assert(tbe.dataValid || + (tbe.dir_ownerIsExcl && tbe.dataUnique && tbe.dataDirty)); tbe.snd_msgType := CHIDataType:NCBWrData; } else { if (tbe.dataValid == false) { - // only possible when the WB was made stale by a snoop - assert(tbe.is_stale); - tbe.dataBlkValid.fillMask(); - tbe.snd_msgType := CHIDataType:CBWrData_I; + // only possible when the WB was made stale by a snoop or + // Writeback on UD_RU line. + if (tbe.dir_ownerIsExcl && tbe.dataUnique && tbe.dataDirty) { + tbe.snd_msgType := CHIDataType:CBWrData_UD_PD; + } else { + assert(tbe.is_stale); + tbe.dataBlkValid.fillMask(); + tbe.snd_msgType := CHIDataType:CBWrData_I; + } } else if (tbe.dataUnique) { assert(tbe.dataBlkValid.isFull()); if (tbe.dataDirty) { diff --git a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm index 9aaee236ac..9ced9d1826 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm @@ -713,7 +713,7 @@ transition({UD_RSC, UC_RSC, SC_RSC, SD_RSC, UD, RU, RSD, RUSD, RUSC, UD_RSD, SD_ // When in UD_RU,UC_RU,UD_RSD,SD_RSD we also just drop the line since an upstream // cache has an up-to-data line that it will either WriteBack or WriteEvict transition({SC,UC,SC_RSC,UC_RSC, - UD_RU,UC_RU,UD_RSD,SD_RSD}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { + UC_RU,UD_RSD,SD_RSD}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_JustDrop; Profile_Eviction; @@ -722,7 +722,7 @@ transition({SC,UC,SC_RSC,UC_RSC, ProcessNextState; } -transition({UD,SD,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD,SD,UD_RU,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_WB; Profile_Eviction; @@ -749,7 +749,7 @@ transition({UD,SD,UC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { ProcessNextState; } -transition({UD_RU,UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_JustDrop; Profile_Eviction; @@ -758,7 +758,7 @@ transition({UD_RU,UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) ProcessNextState; } -transition({UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { +transition({UD_RU, UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { Initiate_Replacement; Initiate_Replacement_WB; Profile_Eviction;