| /* |
| * Copyright (c) 2021 ARM Limited |
| * All rights reserved |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // CHI-cache transition definition |
| //////////////////////////////////////////////////////////////////////////// |
| |
| // Allocate resources and move to the ready queue |
| transition({I,SC,UC,SD,UD,RU,RSC,RSD,RUSD,SC_RSC,UC_RSC,SD_RSC,UD_RSC,UC_RU,UD_RU,UD_RSD,SD_RSD,RUSC |
| BUSY_INTR,BUSY_BLKD}, AllocRequest) { |
| AllocateTBE_Request; |
| } |
| |
| transition({I,SC,UC,SD,UD,RU,RSC,RSD,RUSD,SC_RSC,UC_RSC,SD_RSC,UD_RSC,UC_RU,UD_RU,UD_RSD,SD_RSD,RUSC |
| BUSY_INTR,BUSY_BLKD}, AllocRequestWithCredit) { |
| AllocateTBE_Request_WithCredit; |
| } |
| |
| transition({I,SC,UC,SD,UD,RU,RSC,RSD,RUSD,SC_RSC,UC_RSC,SD_RSC,UD_RSC,UC_RU,UD_RU,UD_RSD,SD_RSD,RUSC |
| BUSY_INTR,BUSY_BLKD}, SendRetryAck) { |
| Send_RetryAck; |
| Pop_RetryTriggerQueue; |
| } |
| |
| transition({I,SC,UC,SD,UD,RU,RSC,RSD,RUSD,SC_RSC,UC_RSC,SD_RSC,UD_RSC,UC_RU,UD_RU,UD_RSD,SD_RSD,RUSC |
| BUSY_INTR,BUSY_BLKD}, SendPCrdGrant) { |
| Send_PCrdGrant; |
| Pop_RetryTriggerQueue; |
| } |
| |
| transition({I,SC,UC,SD,UD,UD_T,RU,RSC,RSD,RUSD,SC_RSC,UC_RSC,SD_RSC,UD_RSC,UC_RU,UD_RU,UD_RSD,SD_RSD,RUSC |
| BUSY_INTR,BUSY_BLKD}, AllocSnoop) { |
| AllocateTBE_Snoop; |
| } |
| |
| transition({I}, AllocDvmSnoop) { |
| AllocateTBE_DvmSnoop; |
| } |
| |
| transition({UD,UD_T,SD,UC,SC,I,BUSY_INTR,BUSY_BLKD}, AllocSeqRequest) { |
| AllocateTBE_SeqRequest; |
| } |
| |
| // You can't allocate a DVM request on the same TBE as another DVM request, |
| // so we don't need a long "Transition-from" list and we can change the output state. |
| transition({I}, AllocSeqDvmRequest) { |
| AllocateTBE_SeqDvmRequest; |
| } |
| |
| transition({I,SC,UC,SD,UD,UD_T,RU,RSC,RSD,RUSD,SC_RSC,SD_RSC,SD_RSD,UC_RSC,UC_RU,UD_RU,UD_RSD,UD_RSC,RUSC |
| BUSY_INTR,BUSY_BLKD}, AllocPfRequest) { |
| AllocateTBE_PfRequest; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, TagArrayRead) {TagArrayRead} { |
| Pop_TriggerQueue; |
| TagArrayRead; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, TagArrayWrite) {TagArrayWrite} { |
| Pop_TriggerQueue; |
| TagArrayWrite; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, DataArrayRead) {DataArrayRead} { |
| Pop_TriggerQueue; |
| DataArrayRead; |
| ProcessNextState_ClearPending; |
| } |
| |
| // goes to BUSY_INTR as we may need to accept snoops while waiting |
| // on potential replacement |
| transition({BUSY_INTR,BUSY_BLKD}, CheckCacheFill, BUSY_INTR) { |
| CheckCacheFill; |
| // CheckCacheFill either does Pop_TriggerQueue+ProcessNextState_ClearPending |
| // or a stall depending on block availability |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, DataArrayWrite) {DataArrayWrite} { |
| Pop_TriggerQueue; |
| DataArrayWrite; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, DataArrayWriteOnFill) {DataArrayWrite} { |
| Pop_TriggerQueue; |
| Profile_Fill; |
| DataArrayWrite; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, ReadHitPipe) { |
| Pop_TriggerQueue; |
| ReadHitPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, ReadMissPipe) { |
| Pop_TriggerQueue; |
| ReadMissPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, WriteFEPipe) { |
| Pop_TriggerQueue; |
| WriteFEPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, WriteBEPipe) { |
| Pop_TriggerQueue; |
| WriteBEPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, FillPipe) { |
| Pop_TriggerQueue; |
| FillPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, SnpSharedPipe) { |
| Pop_TriggerQueue; |
| SnpSharedPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, SnpInvPipe) { |
| Pop_TriggerQueue; |
| SnpInvPipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, SnpOncePipe) { |
| Pop_TriggerQueue; |
| SnpOncePipe; |
| ProcessNextState_ClearPending; |
| } |
| |
| // ReadShared / ReadNotSharedDirty |
| |
| transition(I, {ReadShared,ReadNotSharedDirty}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadShared_Miss; |
| Allocate_DirEntry; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({RSC,RUSC}, {ReadShared,ReadNotSharedDirty}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadShared_HitUpstream_NoOwner; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD,SD,UC,SC}, {ReadShared,ReadNotSharedDirty}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadShared_Hit; |
| Allocate_DirEntry; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RSC,SD_RSC,UC_RSC,SC_RSC,UD_RSD,SD_RSD}, {ReadShared,ReadNotSharedDirty}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadShared_Hit; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RU,UC_RU,RU,RSD,RUSD}, {ReadShared,ReadNotSharedDirty}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadShared_HitUpstream; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| // ReadOnce |
| |
| transition(I, ReadOnce, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadOnce_Miss; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD,SD,UC,SC,UD_RSC,SD_RSC,UC_RSC,SC_RSC,UD_RSD,SD_RSD}, ReadOnce, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadOnce_Hit; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RU,UC_RU,RU,RSD,RUSD,RSC,RUSC}, ReadOnce, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadOnce_HitUpstream; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| |
| // ReadUnique |
| |
| transition(I, {ReadUnique,ReadUnique_PoC}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_Miss; |
| Allocate_DirEntry; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD,UC}, {ReadUnique,ReadUnique_PoC}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_Hit; |
| Allocate_DirEntry; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RSC,UC_RSC,UD_RSD}, {ReadUnique,ReadUnique_PoC}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_Hit_InvUpstream; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RU,UC_RU,RU,RUSD,RUSC}, {ReadUnique,ReadUnique_PoC}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_HitUpstream; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SC,SD}, ReadUnique_PoC, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_AutoUpgrade; |
| Initiate_ReadUnique_Hit; |
| Allocate_DirEntry; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SC_RSC, SD_RSC, SD_RSD}, ReadUnique_PoC, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_AutoUpgrade; |
| Initiate_ReadUnique_Hit_InvUpstream; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({RSC,RSD}, ReadUnique_PoC, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_AutoUpgrade; |
| Initiate_ReadUnique_HitUpstream; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| |
| transition({SC,SD}, ReadUnique, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_Upgrade; |
| Allocate_DirEntry; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SC_RSC, SD_RSC, RSC, SD_RSD, RSD}, ReadUnique, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_ReadUnique_Upgrade; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| // CleanUnique |
| |
| transition({I, SC, UC, SD, UD, RU, RSC, RSD, RUSD, RUSC, |
| SC_RSC, SD_RSD, SD_RSC, UC_RSC, UC_RU, UD_RU, UD_RSD, UD_RSC}, CleanUnique, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_CleanUnique; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({I, SC, UC, SD, UD, RU, RSC, RSD, RUSD, RUSC, |
| SC_RSC, SD_RSD, SD_RSC, UC_RSC, UC_RU, UD_RU, UD_RSD, UD_RSC}, |
| CleanUnique_Stale, BUSY_BLKD) { |
| Initiate_Request_Stale; |
| Initiate_CleanUnique_Stale; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| // WriteUniquePtl |
| |
| transition({UD,UD_RSD,UD_RSC,UC,UC_RSC}, |
| {WriteUnique, WriteUniquePtl_PoC, WriteUniqueFull_PoC, WriteUniqueFull_PoC_Alloc}, |
| BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_LocalWrite; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RU,UC_RU}, |
| {WriteUnique, WriteUniquePtl_PoC, WriteUniqueFull_PoC, WriteUniqueFull_PoC_Alloc}, |
| BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_LocalWrite; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SD, SD_RSD, SD_RSC, SC, SC_RSC}, |
| {WriteUniquePtl_PoC, WriteUniqueFull_PoC, WriteUniqueFull_PoC_Alloc}, |
| BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_LocalWrite; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({RSC,RSD,RUSD,RUSC,RU,I}, WriteUniqueFull_PoC_Alloc, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_LocalWrite; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SD, SD_RSD, SD_RSC, SC, SC_RSC}, |
| {WriteUnique}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_LocalWrite_AfterUpgrade; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({RSD,RUSD,RUSC,RU}, {WriteUniquePtl_PoC, WriteUniqueFull_PoC}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_Writeback; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({RSC,I}, {WriteUniquePtl_PoC, WriteUniqueFull_PoC}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_PartialWrite; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({RSC,RSD,RUSD,RUSC,RU,I}, WriteUnique, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_WriteUnique_Forward; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| |
| // Load / Store from sequencer & Prefetch from prefetcher |
| |
| transition({UD,UD_T,SD,UC,SC}, Load, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_LoadHit; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| // Prefetch hits if either this cache or one of its upstream caches has a |
| // valid block. |
| // In some states, using the normal hit path for a prefetch will deallocate |
| // the local cache entry at the end since our data is stale. If the cache is |
| // inclusive for unique data we need to keep the block, so just bypass the |
| // normal path. |
| transition({UD,UD_T,SD,UC,SC,RU,RSC,RSD,RUSD,SC_RSC,SD_RSC,SD_RSD,UC_RSC,UC_RU,UD_RU,UD_RSD,UD_RSC}, Prefetch) { |
| Callback_ExpressPrefetchHit; |
| Pop_ReqRdyQueue; |
| } |
| |
| transition(BUSY_BLKD, LoadHit) { |
| Pop_TriggerQueue; |
| Callback_LoadHit; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({UD,UD_T,UC}, Store, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_StoreHit; |
| Profile_Hit; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_BLKD, StoreHit) { |
| Pop_TriggerQueue; |
| Callback_StoreHit; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(I, {Load,Prefetch}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_LoadMiss; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition(I, Store, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_StoreMiss; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SD,SC}, Store, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_StoreUpgrade; |
| Profile_Miss; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| // write timeout |
| |
| transition(UD_T, UseTimeout, UD) { |
| Unset_Timeout_Cache; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, UseTimeout) { |
| Unset_Timeout_TBE; |
| } |
| |
| // Evict from Upstream |
| |
| transition({UD_RSC,SD_RSC,UC_RSC,SC_RSC,RSC,RSD,RUSD,RUSC,UD_RSD,SD_RSD}, Evict, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_Evict; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD, UD_RSC, SD_RSC, UC_RSC, SC_RSC, UD_RU, UC_RU, UD_RSD, SD_RSD, RU, RSC, RSD, RUSD, RUSC, SD, UC, SC, I}, |
| Evict_Stale) { |
| Initiate_Request_Stale; |
| Send_CompI_Stale; |
| Finalize_DeallocateRequest; |
| Pop_ReqRdyQueue; |
| } |
| |
| // WriteBack from upstream |
| |
| transition({UD_RU, UC_RU, RU, UD_RSD, SD_RSD, RSD, RUSD}, {WriteBackFull, WriteCleanFull}, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_CopyBack; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RU, UC_RU, RU}, WriteEvictFull, BUSY_BLKD) { |
| Initiate_Request; |
| Initiate_CopyBack; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RSC, UC_RSC, SC_RSC, SD_RSC, UD, RU, RSD, RUSD, RUSC, UD_RSD, SD_RSD, RSC, UD_RU, UC_RU, SD, UC, SC, I}, |
| {WriteBackFull_Stale, WriteEvictFull_Stale, WriteCleanFull_Stale}, BUSY_BLKD) { |
| Initiate_Request_Stale; |
| Initiate_CopyBack_Stale; |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| // Cache Replacement |
| |
| // 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} { |
| Initiate_Replacement; |
| Initiate_Replacement_JustDrop; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD,SD,UD_RSC,SD_RSC}, LocalHN_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_WB; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition(SC, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_Evict; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD,SD,UC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_WB; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RU,UC_RU,UD_RSD,SD_RSD,SC_RSC,UC_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_JustDrop; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RSC,SD_RSC}, Local_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_WB; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition({UD_RSC,SD_RSC,UC_RSC,UD_RU,UC_RU,UD_RSD}, Global_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_WB_BackInvalidate; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Deallocate_DirEntry; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| transition(SC_RSC, Global_Eviction, BUSY_BLKD) {ReplTBEAvailable} { |
| Initiate_Replacement; |
| Initiate_Replacement_Evict_BackInvalidte; |
| Profile_Eviction; |
| Deallocate_CacheBlock; |
| Deallocate_DirEntry; |
| Pop_ReplTriggerQueue; |
| ProcessNextState; |
| } |
| |
| // This could happen if enqueued the eviction when the line was busy |
| // or couldn't handle it immediately due to no TBE available |
| transition({RU,RSC,RSD,RUSC,RUSD,I}, {Local_Eviction, LocalHN_Eviction}) { |
| Pop_ReplTriggerQueue; |
| } |
| transition(I, Global_Eviction) { |
| Pop_ReplTriggerQueue; |
| } |
| |
| // Snoops |
| |
| // SnpCleanInvalid/SnpUnique/SnpUniqueFwd |
| // All invalidating snoops have a simular behavior |
| |
| transition({UD,SD,UC,SC,UD_RSC,SD_RSC,UC_RSC,UD_RU,UC_RU,RU,RUSD,RUSC,RSD,UD_RSD,SD_RSD,SC_RSC,RSC}, |
| {SnpUnique,SnpUniqueFwd,SnpCleanInvalid}, BUSY_BLKD) { |
| Initiate_Snoop; |
| Initiate_InvalidationSnoop; |
| Profile_Eviction; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_INTR, {SnpUnique,SnpUniqueFwd,SnpCleanInvalid}, BUSY_BLKD) { |
| Initiate_Snoop_Hazard; |
| Initiate_InvalidationSnoop; |
| Profile_Eviction; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| // SnpShared / SnpNotSharedDirty |
| |
| transition({UD,UD_RSC,SD,SD_RSC,UC,UC_RSC,UD_RU,UC_RU,RU,UD_RSD,SD_RSD,RSD,RUSD,RUSC}, |
| {SnpShared,SnpSharedFwd,SnpNotSharedDirtyFwd}, BUSY_BLKD) { |
| Initiate_Snoop; |
| Initiate_SnpShared; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition({SC, SC_RSC, RSC}, {SnpSharedFwd, SnpNotSharedDirtyFwd}, BUSY_BLKD) { |
| Initiate_Snoop; |
| Initiate_SnpShared; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_INTR, {SnpShared,SnpSharedFwd,SnpNotSharedDirtyFwd}, BUSY_BLKD) { |
| Initiate_Snoop_Hazard; |
| Initiate_SnpShared; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| // SnpOnce |
| transition({UD,UD_T,UD_RSC,UD_RU,UD_RSD,SD,SD_RSC,SD_RSD,UC,UC_RSC,UC_RU,SC,SC_RSC,RU,RSC,RSD,RUSD,RUSC}, |
| {SnpOnce,SnpOnceFwd}, BUSY_BLKD) { |
| Initiate_Snoop; |
| Initiate_SnpOnce; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_INTR, {SnpOnce,SnpOnceFwd}, BUSY_BLKD) { |
| Initiate_Snoop_Hazard; |
| Initiate_SnpOnce; |
| Pop_SnoopRdyQueue; |
| ProcessNextState; |
| } |
| |
| |
| // Stalls |
| |
| transition({BUSY_BLKD,BUSY_INTR}, |
| {ReadShared, ReadNotSharedDirty, ReadUnique, ReadUnique_PoC, |
| ReadOnce, CleanUnique, CleanUnique_Stale, |
| Load, Store, Prefetch, |
| WriteBackFull, WriteBackFull_Stale, |
| WriteEvictFull, WriteEvictFull_Stale, |
| WriteCleanFull, WriteCleanFull_Stale, |
| Evict, Evict_Stale, |
| WriteUnique,WriteUniquePtl_PoC, |
| WriteUniqueFull_PoC,WriteUniqueFull_PoC_Alloc}) { |
| StallRequest; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, |
| {Global_Eviction, Local_Eviction, LocalHN_Eviction}) { |
| StallLocalEviction; |
| } |
| |
| // Kill the timer and try again as a snoop may be pending as well |
| transition(UD_T, {Global_Eviction, Local_Eviction, LocalHN_Eviction}, UD) { |
| Unset_Timeout_Cache; |
| Pop_ReplTriggerQueue; |
| } |
| |
| transition(BUSY_BLKD, |
| {SnpCleanInvalid,SnpShared,SnpUnique,SnpSharedFwd,SnpUniqueFwd, |
| SnpOnce,SnpOnceFwd,SnpNotSharedDirtyFwd}) { |
| StallSnoop; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, SnpStalled) { |
| StallSnoop; |
| } |
| |
| transition(UD_T, {SnpCleanInvalid,SnpShared,SnpUnique,SnpSharedFwd,SnpUniqueFwd, |
| SnpNotSharedDirtyFwd}) { |
| StallSnoop_NoTBE; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, ActionStalledOnHazard) { |
| StallActionOnHazard; |
| } |
| |
| // Trigger-specifc transitions |
| |
| transition(BUSY_BLKD, SendWriteBackOrWriteEvict, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_WriteBackOrWriteEvict; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWriteClean, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_WriteCleanFull; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWriteUnique, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_WriteUnique; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWriteNoSnp, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_WriteNoSnp; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWriteNoSnpPartial, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_WriteNoSnp_Partial; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| |
| transition(BUSY_BLKD, SendEvict, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_Evict; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| // May get here from BUSY_INTR |
| transition({BUSY_BLKD, BUSY_INTR}, SendCompData, BUSY_BLKD) { |
| Pop_TriggerQueue; |
| Send_CompData; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWBData) { |
| Pop_TriggerQueue; |
| Send_WBData; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWUData) { |
| Pop_TriggerQueue; |
| Send_WUData; |
| CheckWUComp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendWUDataCB) { |
| Pop_TriggerQueue; |
| Callback_WriteUnique; |
| Send_WUData; |
| CheckWUComp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendInvSnpResp) { |
| Pop_TriggerQueue; |
| Send_InvSnpResp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpData) { |
| Pop_TriggerQueue; |
| Send_SnpRespData; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpUniqueFwdCompData) { |
| Pop_TriggerQueue; |
| Send_CompData_SnpUniqueFwd; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpSharedFwdCompData) { |
| Pop_TriggerQueue; |
| Send_CompData_SnpSharedFwd; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpNotSharedDirtyFwdCompData) { |
| Pop_TriggerQueue; |
| Send_CompData_SnpNSDFwd; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpOnceFwdCompData) { |
| Pop_TriggerQueue; |
| Send_CompData_SnpOnceFwd; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpFwdedData) { |
| Pop_TriggerQueue; |
| Send_SnpRespDataFwded; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpFwdedResp) { |
| Pop_TriggerQueue; |
| Send_FwdSnpResp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompAck) { |
| Pop_TriggerQueue; |
| Send_CompAck; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpIResp) { |
| Pop_TriggerQueue; |
| Send_SnpRespI; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompIResp) { |
| Pop_TriggerQueue; |
| Send_CompI; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompUCResp) { |
| Pop_TriggerQueue; |
| Send_CompUC; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompUCRespStale) { |
| Pop_TriggerQueue; |
| Send_CompUC_Stale; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendRespSepData) { |
| Pop_TriggerQueue; |
| Send_RespSepData; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_INTR, BUSY_BLKD}, WaitCompAck) { |
| Pop_TriggerQueue; |
| ExpectCompAck; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, RestoreFromHazard, BUSY_INTR) { |
| Pop_TriggerQueue; |
| RestoreFromHazard; |
| } |
| |
| transition(BUSY_BLKD, SendReadShared, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_ReadShared; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendReadOnce, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_ReadOnce; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendReadUnique, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_ReadUnique; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCleanUnique, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_CleanUnique; |
| Profile_OutgoingStart; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendReadNoSnp, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_ReadNoSnp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendReadNoSnpDMT, BUSY_INTR) {DestinationAvailable} { |
| Pop_TriggerQueue; |
| Send_ReadNoSnpDMT; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpShared) { |
| Pop_TriggerQueue; |
| Send_SnpShared; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpSharedFwdToOwner) { |
| Pop_TriggerQueue; |
| Send_SnpSharedFwd_ToOwner; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpSharedFwdToSharer) { |
| Pop_TriggerQueue; |
| Send_SnpSharedFwd_ToSharer; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpOnceFwd) { |
| Pop_TriggerQueue; |
| Send_SnpOnceFwd; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpOnce) { |
| Pop_TriggerQueue; |
| Send_SnpOnce; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpUnique) { |
| Pop_TriggerQueue; |
| Send_SnpUnique; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpUniqueRetToSrc) { |
| Pop_TriggerQueue; |
| Send_SnpUnique_RetToSrc; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpUniqueFwd) { |
| Pop_TriggerQueue; |
| Send_SnpUniqueFwd; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpCleanInvalid) { |
| Pop_TriggerQueue; |
| Send_SnpCleanInvalid; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendSnpCleanInvalidNoReq) { |
| Pop_TriggerQueue; |
| Send_SnpCleanInvalid_NoReq; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompDBIDResp) { |
| Pop_TriggerQueue; |
| Send_CompDBIDResp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompDBIDResp_WU) { |
| Pop_TriggerQueue; |
| ExpectNCBWrData; |
| Send_CompDBIDResp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendDBIDResp_WU) { |
| Pop_TriggerQueue; |
| ExpectNCBWrData; |
| Send_DBIDResp; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, SendComp_WU) { |
| Pop_TriggerQueue; |
| Send_Comp_WU; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, SendCompDBIDRespStale) { |
| Pop_TriggerQueue; |
| Send_CompDBIDResp_Stale; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, MaintainCoherence) { |
| Pop_TriggerQueue; |
| Initiate_MaitainCoherence; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, FinishCleanUnique) { |
| Pop_TriggerQueue; |
| Finish_CleanUnique; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, FinishCopyBack_Stale) { |
| Pop_TriggerQueue; |
| Finish_CopyBack_Stale; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, CheckUpgrade_FromStore) { |
| Pop_TriggerQueue; |
| Callback_Miss; // note: Callback happens only if tbe.dataValid |
| CheckUpgrade_FromStoreOrRU; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, CheckUpgrade_FromCU) { |
| Pop_TriggerQueue; |
| CheckUpgrade_FromCU; |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(BUSY_BLKD, CheckUpgrade_FromRU) { |
| Pop_TriggerQueue; |
| CheckUpgrade_FromStoreOrRU; |
| ProcessNextState_ClearPending; |
| } |
| |
| |
| // Generic send/receive transitions |
| |
| // waiting for data |
| transition(BUSY_BLKD, |
| {CBWrData_I,CBWrData_SC,CBWrData_SD_PD,CBWrData_UC,CBWrData_UD_PD}) { |
| Receive_ReqDataResp; |
| UpdateDirState_FromReqDataResp; |
| UpdateDataState_FromReqDataResp; |
| Pop_DataInQueue; |
| ProcessNextState; |
| } |
| |
| // could be waiting for both data and CompDBIDResp on a WriteUnique |
| transition({BUSY_BLKD,BUSY_INTR}, NCBWrData) { |
| Receive_ReqDataResp; |
| UpdateDataState_FromWUDataResp; |
| Pop_DataInQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_BLKD, |
| {SnpRespData_I_PD,SnpRespData_I,SnpRespData_SC_PD, |
| SnpRespData_SC,SnpRespData_SD,SnpRespData_UC,SnpRespData_UD, |
| SnpRespData_SC_Fwded_SC,SnpRespData_SC_Fwded_SD_PD, |
| SnpRespData_SC_PD_Fwded_SC,SnpRespData_I_Fwded_SD_PD, |
| SnpRespData_I_PD_Fwded_SC,SnpRespData_I_Fwded_SC}) { |
| Receive_SnpDataResp; |
| UpdateDirState_FromSnpDataResp; |
| UpdateDataState_FromSnpDataResp; |
| Pop_DataInQueue; |
| ProcessNextState; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, RespSepData, BUSY_BLKD) { |
| Receive_RespSepData; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, DataSepResp_UC, BUSY_BLKD) { |
| Receive_ReqDataResp; |
| UpdateDataState_FromReqDataResp; |
| Callback_Miss; |
| Profile_OutgoingEnd_DataResp; |
| Pop_DataInQueue; |
| ProcessNextState; |
| } |
| |
| transition({BUSY_BLKD,BUSY_INTR}, |
| {CompData_I,CompData_SC,CompData_SD_PD,CompData_UC,CompData_UD_PD}, |
| BUSY_BLKD) { |
| Receive_RespSepDataFromCompData; |
| Receive_ReqDataResp; |
| UpdateDataState_FromReqDataResp; |
| Callback_Miss; |
| Profile_OutgoingEnd_DataResp; |
| Pop_DataInQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_INTR, ReadReceipt, BUSY_BLKD) { |
| Receive_ReadReceipt; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // Retry handling |
| |
| transition(BUSY_INTR, {RetryAck, RetryAck_PoC}) { |
| Receive_RetryAck; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_INTR, {PCrdGrant, PCrdGrant_PoC}) { |
| Receive_PCrdGrant; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // RetryAck/PCrdGrant on BUSY_BLKD is only expected in a PoC/HN when waiting |
| // for CompAck after sending down a request with DMT enabled. Handle the same |
| // as BUSY_INTR |
| |
| transition(BUSY_BLKD, RetryAck_PoC) { |
| Receive_RetryAck; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_BLKD, PCrdGrant_PoC) { |
| Receive_PCrdGrant; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // RetryAck/PCrdGrant received during a snoop hazard may arrive in both |
| // BUSY_BLKD and BUSY_INTR |
| transition({BUSY_INTR,BUSY_BLKD}, {RetryAck_Hazard, RetryAck_PoC_Hazard}) { |
| Receive_RetryAck_Hazard; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, {PCrdGrant_Hazard, PCrdGrant_PoC_Hazard}) { |
| Receive_PCrdGrant_Hazard; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // Resend the request after RetryAck+PCrdGrant received |
| |
| transition({BUSY_INTR,BUSY_BLKD}, DoRetry) { |
| Send_Retry; |
| Pop_RetryTriggerQueue; |
| } |
| |
| transition({BUSY_INTR,BUSY_BLKD}, DoRetry_Hazard) { |
| Send_Retry_Hazard; |
| Pop_RetryTriggerQueue; |
| } |
| |
| // waiting for completion ack |
| transition({BUSY_BLKD,BUSY_INTR}, CompAck) { |
| Receive_ReqResp; |
| UpdateDirState_FromReqResp; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_BLKD, |
| {SnpResp_I,SnpResp_SC, |
| SnpResp_I_Fwded_UC,SnpResp_I_Fwded_UD_PD, |
| SnpResp_SC_Fwded_SC,SnpResp_SC_Fwded_SD_PD, |
| SnpResp_UC_Fwded_I,SnpResp_UD_Fwded_I, |
| SnpResp_SC_Fwded_I,SnpResp_SD_Fwded_I}) { |
| Receive_SnpResp; |
| UpdateDirState_FromSnpResp; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // waiting for WB or evict ack |
| transition(BUSY_INTR, |
| {CompDBIDResp,Comp_I}, BUSY_BLKD) { |
| Receive_ReqResp; |
| Profile_OutgoingEnd_DatalessResp; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // currently this happens after a CleanUnique |
| transition(BUSY_INTR, Comp_UC, BUSY_BLKD) { |
| Receive_ReqResp; |
| UpdateDataState_FromCUResp; |
| Profile_OutgoingEnd_DatalessResp; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // alternative flow for WU with separate Comp |
| transition(BUSY_INTR, DBIDResp, BUSY_BLKD) { |
| Receive_ReqResp; |
| Receive_ReqResp_WUNeedComp; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| transition(BUSY_BLKD, Comp) { |
| Receive_ReqResp_WUComp; |
| Profile_OutgoingEnd_DatalessResp; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| transition(BUSY_BLKD, TX_Data) { |
| Pop_TriggerQueue; |
| Send_Data; |
| ProcessNextState_ClearPending; |
| } |
| |
| // Finalization transition |
| |
| transition({BUSY_BLKD,BUSY_INTR}, Final, *) { |
| Pop_TriggerQueue; |
| Finalize_UpdateCacheFromTBE; |
| Finalize_UpdateDirectoryFromTBE; |
| Finalize_DeallocateRequest; |
| } |
| |
| //////////////////////////////////////////////////////// |
| // DVM transitions |
| |
| |
| // I, DvmTlbi_Initiate, DvmTlbi_Unconfirmed |
| // I, DvmSync_Initiate, DvmSync_Unconfirmed |
| // Sync should expect only DBIDResp, |
| // but Tlbi could expect both DBIDResp and CompDBIDResp. |
| // Other CompDBIDResp handlers call a "Receive" action twice - is that relevant? |
| transition(I, DvmTlbi_Initiate, DvmTlbi_Unconfirmed) { |
| Initiate_Request_DVM; |
| |
| Send_DvmTlbi; |
| Profile_OutgoingStart_DVM; |
| |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| transition(I, DvmSync_Initiate, DvmSync_Unsent) { |
| Initiate_Request_DVM; |
| |
| Try_Send_DvmSync; |
| Profile_OutgoingStart_DVM; |
| |
| Pop_ReqRdyQueue; |
| ProcessNextState; |
| } |
| |
| transition(DvmSync_Unsent, DvmSync_Send, DvmSync_Unconfirmed) { |
| Pop_TriggerQueue; |
| |
| Send_DvmSync; |
| |
| ProcessNextState_ClearPending; |
| } |
| |
| // {DvmTlbi_Unconfirmed,DvmSync_Unconfirmed}, RetryAck |
| // {DvmTlbi_Unconfirmed,DvmSync_Unconfirmed}, PCrdGrant |
| // See other RetryAck, PCrdGrants |
| transition({DvmTlbi_Unconfirmed,DvmSync_Unconfirmed}, RetryAck) { |
| Receive_RetryAck; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| transition({DvmTlbi_Unconfirmed,DvmSync_Unconfirmed}, PCrdGrant) { |
| Receive_PCrdGrant; |
| Pop_RespInQueue; |
| ProcessNextState; |
| } |
| |
| // Resend the request after RetryAck+PCrdGrant received |
| transition({DvmTlbi_Unconfirmed,DvmSync_Unconfirmed}, DoRetry) { |
| Send_Retry_DVM; |
| Pop_RetryTriggerQueue; |
| ProcessNextState_ClearPending; |
| } |
| |
| // DvmTlbi_Unconfirmed, DBIDResp, DvmTlbi_Waiting |
| // DvmSync_Unconfirmed, DBIDResp, DvmSync_Waiting |
| // Should both send NCBWrData |
| transition(DvmTlbi_Unconfirmed, DBIDResp, DvmTlbi_Waiting) { |
| Receive_ReqResp; |
| Pop_RespInQueue; |
| |
| Send_DvmTlbi_NCBWrData; |
| ExpectComp; |
| |
| ProcessNextState; |
| } |
| transition(DvmSync_Unconfirmed, DBIDResp, DvmSync_Waiting) { |
| Receive_ReqResp; |
| Pop_RespInQueue; |
| |
| Send_DvmSync_NCBWrData; |
| ExpectComp; |
| |
| ProcessNextState; |
| } |
| |
| // DvmTlbi_Unconfirmed, CompDBIDResp, DvmOp_Finished |
| // should call ProcessNextState |
| // {DvmTlbi_Waiting,DvmSync_Waiting}, Comp, DvmOp_Finished |
| // should call ProcessNextState |
| transition(DvmTlbi_Unconfirmed, CompDBIDResp, DvmOp_Finished) { |
| Receive_ReqResp; |
| Pop_RespInQueue; |
| |
| Send_DvmTlbi_NCBWrData; |
| |
| // We got the comp as well, so send the callback |
| DvmTlbi_CompCallback; |
| Profile_OutgoingEnd_DVM; |
| Try_Send_Pending_DvmSync; |
| ProcessNextState; |
| } |
| transition(DvmTlbi_Waiting, Comp, DvmOp_Finished) { |
| Receive_ReqResp; |
| Pop_RespInQueue; |
| |
| DvmTlbi_CompCallback; |
| Profile_OutgoingEnd_DVM; |
| Try_Send_Pending_DvmSync; |
| ProcessNextState; |
| } |
| transition(DvmSync_Waiting, Comp, DvmOp_Finished) { |
| Receive_ReqResp; |
| Pop_RespInQueue; |
| |
| DvmSync_CompCallback; |
| Profile_OutgoingEnd_DVM; |
| ProcessNextState; |
| } |
| |
| // DvmOp_Finished, Final, I |
| // Should deallocate DvmOp |
| transition(DvmOp_Finished, Final, I) { |
| Pop_TriggerQueue; // "Final" is triggered from Trigger queue, so pop that |
| Finalize_DeallocateDvmRequest; |
| } |
| |
| ///////////////////////////////////////////////// |
| // DVM snoops |
| |
| transition(I, {SnpDvmOpNonSync_P1,SnpDvmOpNonSync_P2}, DvmExtTlbi_Partial) { |
| // First message has arrived, could be P1 or P2 because either order is allowed |
| Initiate_DvmSnoop; |
| Pop_SnoopRdyQueue; |
| } |
| |
| transition(I, {SnpDvmOpSync_P1,SnpDvmOpSync_P2}, DvmExtSync_Partial) { |
| // First message has arrived, could be P1 or P2 because either order is allowed |
| Initiate_DvmSnoop; |
| Pop_SnoopRdyQueue; |
| } |
| |
| transition(DvmExtTlbi_Partial, {SnpDvmOpNonSync_P1,SnpDvmOpNonSync_P2}, DvmExtTlbi_Executing) { |
| // TODO - some check that we didn't receive a {P1,P1} or {P2,P2} pair? |
| // We receive this event directly from the SnpInPort, so pop it |
| Pop_SnpInPort; |
| |
| // Triggers SnpResp_I from inside Ruby with a delay |
| DvmExtTlbi_EnqueueSnpResp; |
| ProcessNextState; |
| } |
| |
| transition(DvmExtSync_Partial, {SnpDvmOpSync_P1,SnpDvmOpSync_P2}, DvmExtSync_Executing) { |
| // TODO - some check that we didn't receive a {P1,P1} or {P2,P2} pair? |
| // We receive this event directly from the SnpInPort, so pop it |
| Pop_SnpInPort; |
| |
| // Tell the CPU model to perform a Sync |
| // e.g. flush load-store-queue |
| DvmExtSync_TriggerCallback; |
| |
| // We just wait for the CPU to finish |
| } |
| |
| transition(DvmExtTlbi_Executing, SendSnpIResp, DvmExtOp_Finished) { |
| // TLBI snoop response has been triggered after the delay |
| Pop_TriggerQueue; |
| |
| // Send the snoop response to the MN |
| Send_SnpRespI; |
| |
| // Should trigger Final state |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(DvmExtSync_Executing, DvmSync_ExternCompleted, DvmExtOp_Finished) { |
| Pop_SeqInPort; |
| |
| // The CPU model has declared that the Sync is complete |
| // => send the snoop response to the MN |
| Send_SnpRespI; |
| |
| // Should trigger Final state |
| ProcessNextState_ClearPending; |
| } |
| |
| transition(DvmExtOp_Finished, Final, I) { |
| Pop_TriggerQueue; |
| Finalize_DeallocateDvmSnoop; |
| } |