In Ruby CHI protocol UD_RU state means the line is in UD state in the local cache and the upstream may have it in UD or UC state. In the previous implementation UD_RU line was just dropped without WriteBack which can cause loss of dirty data when the upstream has it in UC state. This commit fixes it by performing WriteBack when evciting UD_RU line. Change-Id: I1db9b4f95cc576e71dcef38b01de24775df514ba
1710 lines
41 KiB
Plaintext
1710 lines
41 KiB
Plaintext
/*
|
|
* Copyright (c) 2021-2023 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}, DelayAtomic) {
|
|
Pop_TriggerQueue;
|
|
DelayAtomic;
|
|
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;
|
|
}
|
|
|
|
// WriteUniqueZero cacheline not present
|
|
transition({I,RU,RSC,RSD,RUSD,RUSC},
|
|
WriteUniqueZero,
|
|
BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_WriteUnique_Zero;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
// WriteUniqueZero cacheline available
|
|
transition({SC,UC,SD,UD,SC_RSC,UC_RSC,SD_RSC,UD_RSC,UC_RU,UD_RU,UD_RSD,SD_RSD},
|
|
WriteUniqueZero,
|
|
BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_WriteUnique_Zero;
|
|
Profile_Hit;
|
|
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;
|
|
}
|
|
|
|
// AtomicReturn and AtomicNoReturn
|
|
|
|
transition({I,SC,SC_RSC,SD,SD_RSD,SD_RSC,RSD,RUSD,
|
|
UD,UD_RSC,UD_RSD,UD_RU,UC,UC_RSC,UC_RU,RSC,RU}, AtomicReturn, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_Forward;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition({I,SC,SC_RSC,SD,SD_RSD,SD_RSC,RSD,RUSD,
|
|
UD,UD_RSC,UD_RSD,UD_RU,UC,UC_RSC,UC_RU,RSC,RU}, AtomicNoReturn, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_Forward;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition({UD,UD_RU,UD_RSD,UD_RSC,UC,UC_RU,UC_RSC},
|
|
AtomicReturn_PoC, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_LocalWrite;
|
|
Profile_Hit;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition({UD,UD_RU,UD_RSD,UD_RSC,UC,UC_RU,UC_RSC},
|
|
AtomicNoReturn_PoC, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_LocalWrite;
|
|
Profile_Hit;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition({SD, SD_RSD, SD_RSC, SC, SC_RSC, RSC, RSD, RUSC, RUSD, RU},
|
|
AtomicReturn_PoC, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_LocalWrite;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition({SD, SD_RSD, SD_RSC, SC, SC_RSC, RSC, RSD, RUSC, RUSD, RU},
|
|
AtomicNoReturn_PoC, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_LocalWrite;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(I, AtomicReturn_PoC, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_Miss;
|
|
Allocate_DirEntry;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(I, AtomicNoReturn_PoC, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_Miss;
|
|
Allocate_DirEntry;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
|
|
// Load / Store / Atomic 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,RUSC,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(UC, {AtomicLoad,AtomicStore}, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_Atomic_UC;
|
|
Profile_Hit;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition({UD,UD_T}, {AtomicLoad,AtomicStore}, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_Atomic_UD;
|
|
Profile_Hit;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(BUSY_BLKD, AtomicHit) {
|
|
Pop_TriggerQueue;
|
|
Callback_AtomicHit;
|
|
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;
|
|
}
|
|
|
|
transition(I, AtomicLoad, BUSY_BLKD){
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_I;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(I, AtomicStore, BUSY_BLKD){
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_I;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(SD, AtomicLoad, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_SD;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(SC, AtomicLoad, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicReturn_SC;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(SD, AtomicStore, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_SD;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
transition(SC, AtomicStore, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Initiate_AtomicNoReturn_SC;
|
|
Profile_Miss;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
|
|
// 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 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,
|
|
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_RU,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({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_RU,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;
|
|
}
|
|
|
|
// Stash
|
|
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},
|
|
{StashOnceShared,StashOnceUnique}, BUSY_BLKD) {
|
|
Initiate_Request;
|
|
Send_CompI;
|
|
Pop_ReqRdyQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
// Stalls
|
|
|
|
transition({BUSY_BLKD,BUSY_INTR},
|
|
{ReadShared, ReadNotSharedDirty, ReadUnique, ReadUnique_PoC,
|
|
ReadOnce, CleanUnique, CleanUnique_Stale,
|
|
Load, Store, AtomicLoad, AtomicStore, Prefetch,
|
|
WriteBackFull, WriteBackFull_Stale,
|
|
WriteEvictFull, WriteEvictFull_Stale,
|
|
WriteCleanFull, WriteCleanFull_Stale,
|
|
Evict, Evict_Stale,
|
|
WriteUnique,WriteUniquePtl_PoC,
|
|
WriteUniqueFull_PoC,WriteUniqueFull_PoC_Alloc,
|
|
WriteUniqueZero,
|
|
AtomicReturn,AtomicReturn_PoC,
|
|
AtomicNoReturn,AtomicNoReturn_PoC,
|
|
StashOnceShared,StashOnceUnique}) {
|
|
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, SendAtomicReturn, BUSY_INTR) {DestinationAvailable} {
|
|
Pop_TriggerQueue;
|
|
Send_AtomicReturn;
|
|
CheckARComp;
|
|
Profile_OutgoingStart;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition(BUSY_BLKD, SendAtomicReturn_NoWait, BUSY_INTR) {
|
|
Pop_TriggerQueue;
|
|
Send_AtomicReturn_NoWait;
|
|
CheckARComp;
|
|
Profile_OutgoingStart;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition(BUSY_BLKD, SendAtomicNoReturn, BUSY_INTR) {DestinationAvailable} {
|
|
Pop_TriggerQueue;
|
|
Send_AtomicNoReturn;
|
|
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,BUSY_INTR}, SendARData) {
|
|
Pop_TriggerQueue;
|
|
Send_ARData;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition({BUSY_BLKD,BUSY_INTR}, SendANRData) {
|
|
Pop_TriggerQueue;
|
|
Callback_AtomicNoReturn;
|
|
Send_ANRData;
|
|
CheckANRComp;
|
|
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_WUZ) {
|
|
Pop_TriggerQueue;
|
|
Send_DBIDResp;
|
|
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, SendCompDBIDResp_ANR) {
|
|
Pop_TriggerQueue;
|
|
ExpectNCBWrData_A;
|
|
Send_CompDBIDResp;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition(BUSY_BLKD, SendDBIDResp_AR) {
|
|
Pop_TriggerQueue;
|
|
ExpectNCBWrData_A;
|
|
Send_DBIDResp;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition({BUSY_BLKD,BUSY_INTR}, SendCompData_AR) {
|
|
Pop_TriggerQueue;
|
|
Send_CompData_AR;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition(BUSY_BLKD, SendCompDBIDRespStale) {
|
|
Pop_TriggerQueue;
|
|
Send_CompDBIDResp_Stale;
|
|
ProcessNextState_ClearPending;
|
|
}
|
|
|
|
transition(BUSY_BLKD, MaintainCoherence) {
|
|
Pop_TriggerQueue;
|
|
Initiate_MaintainCoherence;
|
|
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;
|
|
UpdateDataState_FromADataResp;
|
|
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, 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;
|
|
}
|
|
|
|
// waiting for WB or evict ack
|
|
transition(BUSY_INTR, CompDBIDResp, BUSY_BLKD) {
|
|
Receive_ReqResp;
|
|
Receive_ReqResp_CopyDBID;
|
|
Profile_OutgoingEnd_DatalessResp;
|
|
Pop_RespInQueue;
|
|
ProcessNextState;
|
|
}
|
|
|
|
// alternative flow for WU with separate Comp
|
|
transition({BUSY_INTR,BUSY_BLKD}, DBIDResp, BUSY_BLKD) {
|
|
Receive_ReqResp;
|
|
Receive_ReqResp_CopyDBID;
|
|
Receive_ReqResp_WUNeedComp;
|
|
Receive_ReqResp_AR;
|
|
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;
|
|
}
|
|
|
|
transition(BUSY_INTR, WriteZero) {
|
|
Pop_TriggerQueue;
|
|
WriteZero;
|
|
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;
|
|
}
|