summaryrefslogtreecommitdiff
path: root/src/mem/protocol/MOESI_CMP_token-L1cache.sm
diff options
context:
space:
mode:
authorNathan Binkert <nate@binkert.org>2009-05-11 10:38:43 -0700
committerNathan Binkert <nate@binkert.org>2009-05-11 10:38:43 -0700
commit2f30950143cc70bc42a3c8a4111d7cf8198ec881 (patch)
tree708f6c22edb3c6feb31dd82866c26623a5329580 /src/mem/protocol/MOESI_CMP_token-L1cache.sm
parentc70241810d4e4f523f173c1646b008dc40faad8e (diff)
downloadgem5-2f30950143cc70bc42a3c8a4111d7cf8198ec881.tar.xz
ruby: Import ruby and slicc from GEMS
We eventually plan to replace the m5 cache hierarchy with the GEMS hierarchy, but for now we will make both live alongside eachother.
Diffstat (limited to 'src/mem/protocol/MOESI_CMP_token-L1cache.sm')
-rw-r--r--src/mem/protocol/MOESI_CMP_token-L1cache.sm2041
1 files changed, 2041 insertions, 0 deletions
diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm
new file mode 100644
index 000000000..ab58c5c00
--- /dev/null
+++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm
@@ -0,0 +1,2041 @@
+
+/*
+ * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * $Id: MOESI_CMP_token-L1cache.sm 1.22 05/01/19 15:55:39-06:00 beckmann@s0-28.cs.wisc.edu $
+ *
+ */
+
+machine(L1Cache, "Token protocol") {
+
+ // From this node's L1 cache TO the network
+ // a local L1 -> this L2 bank, currently ordered with directory forwarded requests
+ MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="false";
+ // a local L1 -> this L2 bank
+ MessageBuffer responseFromL1Cache, network="To", virtual_network="2", ordered="false";
+ MessageBuffer persistentFromL1Cache, network="To", virtual_network="3", ordered="true";
+
+ // To this node's L1 cache FROM the network
+ // a L2 bank -> this L1
+ MessageBuffer requestToL1Cache, network="From", virtual_network="0", ordered="false";
+ // a L2 bank -> this L1
+ MessageBuffer responseToL1Cache, network="From", virtual_network="2", ordered="false";
+ MessageBuffer persistentToL1Cache, network="From", virtual_network="3", ordered="true";
+
+ // STATES
+ enumeration(State, desc="Cache states", default="L1Cache_State_I") {
+ // Base states
+ NP, "NP", desc="Not Present";
+ I, "I", desc="Idle";
+ S, "S", desc="Shared";
+ O, "O", desc="Owned";
+ M, "M", desc="Modified (dirty)";
+ MM, "MM", desc="Modified (dirty and locally modified)";
+ M_W, "M^W", desc="Modified (dirty), waiting";
+ MM_W, "MM^W", desc="Modified (dirty and locally modified), waiting";
+
+ // Transient States
+ IM, "IM", desc="Issued GetX";
+ SM, "SM", desc="Issued GetX, we still have an old copy of the line";
+ OM, "OM", desc="Issued GetX, received data";
+ IS, "IS", desc="Issued GetS";
+
+ // Locked states
+ I_L, "I^L", desc="Invalid, Locked";
+ S_L, "S^L", desc="Shared, Locked";
+ IM_L, "IM^L", desc="Invalid, Locked, trying to go to Modified";
+ SM_L, "SM^L", desc="Shared, Locked, trying to go to Modified";
+ IS_L, "IS^L", desc="Invalid, Locked, trying to go to Shared";
+ }
+
+ // EVENTS
+ enumeration(Event, desc="Cache events") {
+ Load, desc="Load request from the processor";
+ Ifetch, desc="I-fetch request from the processor";
+ Store, desc="Store request from the processor";
+ L1_Replacement, desc="L1 Replacement";
+
+ // Responses
+ Data_Shared, desc="Received a data message, we are now a sharer";
+ Data_Owner, desc="Received a data message, we are now the owner";
+ Data_All_Tokens, desc="Received a data message, we are now the owner, we now have all the tokens";
+ Ack, desc="Received an ack message";
+ Ack_All_Tokens, desc="Received an ack message, we now have all the tokens";
+
+ // Requests
+ Transient_GETX, desc="A GetX from another processor";
+ Transient_Local_GETX, desc="A GetX from another processor";
+ Transient_GETS, desc="A GetS from another processor";
+ Transient_Local_GETS, desc="A GetS from another processor";
+ Transient_GETS_Last_Token, desc="A GetS from another processor";
+ Transient_Local_GETS_Last_Token, desc="A GetS from another processor";
+
+ // Lock/Unlock for distributed
+ Persistent_GETX, desc="Another processor has priority to read/write";
+ Persistent_GETS, desc="Another processor has priority to read";
+ Own_Lock_or_Unlock, desc="This processor now has priority";
+
+ // Triggers
+ Request_Timeout, desc="Timeout";
+ Use_TimeoutStarverX, desc="Timeout";
+ Use_TimeoutStarverS, desc="Timeout";
+ Use_TimeoutNoStarvers, desc="Timeout";
+
+ }
+
+ // TYPES
+
+ int getRetryThreshold();
+ int getFixedTimeoutLatency();
+ bool getDynamicTimeoutEnabled();
+
+ // CacheEntry
+ structure(Entry, desc="...", interface="AbstractCacheEntry") {
+ State CacheState, desc="cache state";
+ bool Dirty, desc="Is the data dirty (different than memory)?";
+ int Tokens, desc="The number of tokens we're holding for the line";
+ DataBlock DataBlk, desc="data for the block";
+ }
+
+
+ // TBE fields
+ structure(TBE, desc="...") {
+ Address Address, desc="Physical address for this TBE";
+ State TBEState, desc="Transient state";
+ int IssueCount, default="0", desc="The number of times we've issued a request for this line.";
+ Address PC, desc="Program counter of request";
+
+ bool WentPersistent, default="false", desc="Request went persistent";
+ bool ExternalResponse, default="false", desc="Response came from an external controller";
+
+ AccessType AccessType, desc="Type of request (used for profiling)";
+ Time IssueTime, desc="Time the request was issued";
+ AccessModeType AccessMode, desc="user/supervisor access type";
+ PrefetchBit Prefetch, desc="Is this a prefetch request";
+ }
+
+ external_type(CacheMemory) {
+ bool cacheAvail(Address);
+ Address cacheProbe(Address);
+ void allocate(Address);
+ void deallocate(Address);
+ Entry lookup(Address);
+ void changePermission(Address, AccessPermission);
+ bool isTagPresent(Address);
+ }
+
+ external_type(TBETable) {
+ TBE lookup(Address);
+ void allocate(Address);
+ void deallocate(Address);
+ bool isPresent(Address);
+ }
+
+
+ TBETable L1_TBEs, template_hack="<L1Cache_TBE>";
+ CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
+ CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
+
+ MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
+ Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
+
+ bool starving, default="false";
+
+ PersistentTable persistentTable, constructor_hack="i";
+ TimerTable useTimerTable;
+ TimerTable reissueTimerTable;
+
+ int outstandingRequests, default="0";
+ int outstandingPersistentRequests, default="0";
+
+ int averageLatencyHysteresis, default="(8)"; // Constant that provides hysteresis for calculated the estimated average
+ int averageLatencyCounter, default="(500 << (*m_L1Cache_averageLatencyHysteresis_vec[i]))";
+
+ int averageLatencyEstimate() {
+ DEBUG_EXPR( (averageLatencyCounter >> averageLatencyHysteresis) );
+ profile_average_latency_estimate( (averageLatencyCounter >> averageLatencyHysteresis) );
+ return averageLatencyCounter >> averageLatencyHysteresis;
+ }
+
+ void updateAverageLatencyEstimate(int latency) {
+ DEBUG_EXPR( latency );
+ assert(latency >= 0);
+
+ // By subtracting the current average and then adding the most
+ // recent sample, we calculate an estimate of the recent average.
+ // If we simply used a running sum and divided by the total number
+ // of entries, the estimate of the average would adapt very slowly
+ // after the execution has run for a long time.
+ // averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency;
+
+ averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency;
+ }
+
+
+ Entry getCacheEntry(Address addr), return_by_ref="yes" {
+ if (L1DcacheMemory.isTagPresent(addr)) {
+ return L1DcacheMemory[addr];
+ } else {
+ return L1IcacheMemory[addr];
+ }
+ }
+
+ int getTokens(Address addr) {
+ if (L1DcacheMemory.isTagPresent(addr)) {
+ return L1DcacheMemory[addr].Tokens;
+ } else if (L1IcacheMemory.isTagPresent(addr)) {
+ return L1IcacheMemory[addr].Tokens;
+ } else {
+ return 0;
+ }
+ }
+
+ void changePermission(Address addr, AccessPermission permission) {
+ if (L1DcacheMemory.isTagPresent(addr)) {
+ return L1DcacheMemory.changePermission(addr, permission);
+ } else {
+ return L1IcacheMemory.changePermission(addr, permission);
+ }
+ }
+
+ bool isCacheTagPresent(Address addr) {
+ return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
+ }
+
+ State getState(Address addr) {
+ assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
+
+ if (L1_TBEs.isPresent(addr)) {
+ return L1_TBEs[addr].TBEState;
+ } else if (isCacheTagPresent(addr)) {
+ return getCacheEntry(addr).CacheState;
+ } else {
+ if ((persistentTable.isLocked(addr) == true) && (persistentTable.findSmallest(addr) != machineID)) {
+ // Not in cache, in persistent table, but this processor isn't highest priority
+ return State:I_L;
+ } else {
+ return State:NP;
+ }
+ }
+ }
+
+ void setState(Address addr, State state) {
+ assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
+
+ if (L1_TBEs.isPresent(addr)) {
+ assert(state != State:I);
+ assert(state != State:S);
+ assert(state != State:O);
+ assert(state != State:MM);
+ assert(state != State:M);
+ L1_TBEs[addr].TBEState := state;
+ }
+
+ if (isCacheTagPresent(addr)) {
+ // Make sure the token count is in range
+ assert(getCacheEntry(addr).Tokens >= 0);
+ assert(getCacheEntry(addr).Tokens <= max_tokens());
+
+ if ((state == State:I_L) ||
+ (state == State:IM_L) ||
+ (state == State:IS_L)) {
+ // Make sure we have no tokens in the "Invalid, locked" states
+ if (isCacheTagPresent(addr)) {
+ assert(getCacheEntry(addr).Tokens == 0);
+ }
+
+ // Make sure the line is locked
+ // assert(persistentTable.isLocked(addr));
+
+ // But we shouldn't have highest priority for it
+ // assert(persistentTable.findSmallest(addr) != id);
+
+ } else if ((state == State:S_L) ||
+ (state == State:SM_L)) {
+ assert(getCacheEntry(addr).Tokens >= 1);
+
+ // Make sure the line is locked...
+ // assert(persistentTable.isLocked(addr));
+
+ // ...But we shouldn't have highest priority for it...
+ // assert(persistentTable.findSmallest(addr) != id);
+
+ // ...And it must be a GETS request
+ // assert(persistentTable.typeOfSmallest(addr) == AccessType:Read);
+
+ } else {
+
+ // If there is an entry in the persistent table of this block,
+ // this processor needs to have an entry in the table for this
+ // block, and that entry better be the smallest (highest
+ // priority). Otherwise, the state should have been one of
+ // locked states
+
+ //if (persistentTable.isLocked(addr)) {
+ // assert(persistentTable.findSmallest(addr) == id);
+ //}
+ }
+
+ // in M and E you have all the tokens
+ if (state == State:MM || state == State:M || state == State:MM_W || state == State:M_W) {
+ assert(getCacheEntry(addr).Tokens == max_tokens());
+ }
+
+ // in NP you have no tokens
+ if (state == State:NP) {
+ assert(getCacheEntry(addr).Tokens == 0);
+ }
+
+ // You have at least one token in S-like states
+ if (state == State:S || state == State:SM) {
+ assert(getCacheEntry(addr).Tokens > 0);
+ }
+
+ // You have at least half the token in O-like states
+ if (state == State:O && state == State:OM) {
+ assert(getCacheEntry(addr).Tokens >= 1); // Must have at least one token
+ assert(getCacheEntry(addr).Tokens >= (max_tokens() / 2)); // Only mostly true; this might not always hold
+ }
+
+ getCacheEntry(addr).CacheState := state;
+
+ // Set permission
+ if (state == State:MM ||
+ state == State:MM_W) {
+ changePermission(addr, AccessPermission:Read_Write);
+ } else if ((state == State:S) ||
+ (state == State:O) ||
+ (state == State:M) ||
+ (state == State:M_W) ||
+ (state == State:SM) ||
+ (state == State:S_L) ||
+ (state == State:SM_L) ||
+ (state == State:OM)) {
+ changePermission(addr, AccessPermission:Read_Only);
+ } else {
+ changePermission(addr, AccessPermission:Invalid);
+ }
+ }
+ }
+
+ Event mandatory_request_type_to_event(CacheRequestType type) {
+ if (type == CacheRequestType:LD) {
+ return Event:Load;
+ } else if (type == CacheRequestType:IFETCH) {
+ return Event:Ifetch;
+ } else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
+ return Event:Store;
+ } else {
+ error("Invalid CacheRequestType");
+ }
+ }
+
+ AccessType cache_request_type_to_access_type(CacheRequestType type) {
+ if ((type == CacheRequestType:LD) || (type == CacheRequestType:IFETCH)) {
+ return AccessType:Read;
+ } else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
+ return AccessType:Write;
+ } else {
+ error("Invalid CacheRequestType");
+ }
+ }
+
+ GenericMachineType getNondirectHitMachType(Address addr, MachineID sender) {
+ if (machineIDToMachineType(sender) == MachineType:L1Cache) {
+ return GenericMachineType:L1Cache_wCC; // NOTE direct L1 hits should not call this
+ } else if (machineIDToMachineType(sender) == MachineType:L2Cache) {
+ if ( sender == (map_L1CacheMachId_to_L2Cache(addr,machineID))) {
+ return GenericMachineType:L2Cache;
+ } else {
+ return GenericMachineType:L2Cache_wCC;
+ }
+ } else {
+ return ConvertMachToGenericMach(machineIDToMachineType(sender));
+ }
+ }
+
+ bool okToIssueStarving(Address addr) {
+ return persistentTable.okToIssueStarving(addr);
+ }
+
+ void markPersistentEntries(Address addr) {
+ persistentTable.markEntries(addr);
+ }
+
+ MessageBuffer triggerQueue, ordered="false", random="false";
+
+ // ** OUT_PORTS **
+ out_port(persistentNetwork_out, PersistentMsg, persistentFromL1Cache);
+ out_port(requestNetwork_out, RequestMsg, requestFromL1Cache);
+ out_port(responseNetwork_out, ResponseMsg, responseFromL1Cache);
+ out_port(requestRecycle_out, RequestMsg, requestToL1Cache);
+
+ // ** IN_PORTS **
+
+ // Use Timer
+ in_port(useTimerTable_in, Address, useTimerTable) {
+ if (useTimerTable_in.isReady()) {
+ if (persistentTable.isLocked(useTimerTable.readyAddress()) && (persistentTable.findSmallest(useTimerTable.readyAddress()) != machineID)) {
+ if (persistentTable.typeOfSmallest(useTimerTable.readyAddress()) == AccessType:Write) {
+ trigger(Event:Use_TimeoutStarverX, useTimerTable.readyAddress());
+ }
+ else {
+ trigger(Event:Use_TimeoutStarverS, useTimerTable.readyAddress());
+ }
+ }
+ else {
+ trigger(Event:Use_TimeoutNoStarvers, useTimerTable.readyAddress());
+ }
+ }
+ }
+
+ // Reissue Timer
+ in_port(reissueTimerTable_in, Address, reissueTimerTable) {
+ if (reissueTimerTable_in.isReady()) {
+ trigger(Event:Request_Timeout, reissueTimerTable.readyAddress());
+ }
+ }
+
+
+
+ // Persistent Network
+ in_port(persistentNetwork_in, PersistentMsg, persistentToL1Cache) {
+ if (persistentNetwork_in.isReady()) {
+ peek(persistentNetwork_in, PersistentMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+
+ // Apply the lockdown or unlockdown message to the table
+ if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
+ persistentTable.persistentRequestLock(in_msg.Address, in_msg.Requestor, AccessType:Write);
+ } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
+ persistentTable.persistentRequestLock(in_msg.Address, in_msg.Requestor, AccessType:Read);
+ } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
+ persistentTable.persistentRequestUnlock(in_msg.Address, in_msg.Requestor);
+ } else {
+ error("Unexpected message");
+ }
+
+ // React to the message based on the current state of the table
+ if (persistentTable.isLocked(in_msg.Address)) {
+ if (persistentTable.findSmallest(in_msg.Address) == machineID) {
+ // Our Own Lock - this processor is highest priority
+ trigger(Event:Own_Lock_or_Unlock, in_msg.Address);
+ } else {
+ if (persistentTable.typeOfSmallest(in_msg.Address) == AccessType:Read) {
+ trigger(Event:Persistent_GETS, in_msg.Address);
+ } else {
+ trigger(Event:Persistent_GETX, in_msg.Address);
+ }
+ }
+ } else {
+ // Unlock case - no entries in the table
+ trigger(Event:Own_Lock_or_Unlock, in_msg.Address);
+ }
+ }
+ }
+ }
+
+
+ // Request Network
+ in_port(requestNetwork_in, RequestMsg, requestToL1Cache) {
+ if (requestNetwork_in.isReady()) {
+ peek(requestNetwork_in, RequestMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+ if (in_msg.Type == CoherenceRequestType:GETX) {
+ if (in_msg.isLocal) {
+ trigger(Event:Transient_Local_GETX, in_msg.Address);
+ }
+ else {
+ trigger(Event:Transient_GETX, in_msg.Address);
+ }
+ } else if (in_msg.Type == CoherenceRequestType:GETS) {
+ if ( (L1DcacheMemory.isTagPresent(in_msg.Address) || L1IcacheMemory.isTagPresent(in_msg.Address)) && getCacheEntry(in_msg.Address).Tokens == 1) {
+ if (in_msg.isLocal) {
+ trigger(Event:Transient_Local_GETS_Last_Token, in_msg.Address);
+ }
+ else {
+ trigger(Event:Transient_GETS_Last_Token, in_msg.Address);
+ }
+ }
+ else {
+ if (in_msg.isLocal) {
+ trigger(Event:Transient_Local_GETS, in_msg.Address);
+ }
+ else {
+ trigger(Event:Transient_GETS, in_msg.Address);
+ }
+ }
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+
+ // Response Network
+ in_port(responseNetwork_in, ResponseMsg, responseToL1Cache) {
+ if (responseNetwork_in.isReady()) {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+
+ // Mark TBE flag if response received off-chip. Use this to update average latency estimate
+ if ( in_msg.SenderMachine == MachineType:L2Cache ) {
+
+ if (in_msg.Sender == map_L1CacheMachId_to_L2Cache(in_msg.Address, machineID)) {
+ // came from an off-chip L2 cache
+ if (L1_TBEs.isPresent(in_msg.Address)) {
+ // L1_TBEs[in_msg.Address].ExternalResponse := true;
+ // profile_offchipL2_response(in_msg.Address);
+ }
+ }
+ else {
+ // profile_onchipL2_response(in_msg.Address );
+ }
+ } else if ( in_msg.SenderMachine == MachineType:Directory ) {
+ if (L1_TBEs.isPresent(in_msg.Address)) {
+ L1_TBEs[in_msg.Address].ExternalResponse := true;
+ // profile_memory_response( in_msg.Address);
+ }
+ } else if ( in_msg.SenderMachine == MachineType:L1Cache) {
+ if (isLocalProcessor(machineID, in_msg.Sender) == false) {
+ if (L1_TBEs.isPresent(in_msg.Address)) {
+ // L1_TBEs[in_msg.Address].ExternalResponse := true;
+ // profile_offchipL1_response(in_msg.Address );
+ }
+ }
+ else {
+ // profile_onchipL1_response(in_msg.Address );
+ }
+ } else {
+ error("unexpected SenderMachine");
+ }
+
+
+ if (getTokens(in_msg.Address) + in_msg.Tokens != max_tokens()) {
+ if (in_msg.Type == CoherenceResponseType:ACK) {
+ trigger(Event:Ack, in_msg.Address);
+ } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
+ trigger(Event:Data_Owner, in_msg.Address);
+ } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
+ trigger(Event:Data_Shared, in_msg.Address);
+ } else {
+ error("Unexpected message");
+ }
+ } else {
+ if (in_msg.Type == CoherenceResponseType:ACK) {
+ trigger(Event:Ack_All_Tokens, in_msg.Address);
+ } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:DATA_SHARED) {
+ trigger(Event:Data_All_Tokens, in_msg.Address);
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+ }
+
+ // Mandatory Queue
+ in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
+ if (mandatoryQueue_in.isReady()) {
+ peek(mandatoryQueue_in, CacheMsg) {
+ // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
+
+ if (in_msg.Type == CacheRequestType:IFETCH) {
+ // ** INSTRUCTION ACCESS ***
+
+ // Check to see if it is in the OTHER L1
+ if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
+ // The block is in the wrong L1, try to write it to the L2
+ trigger(Event:L1_Replacement, in_msg.Address);
+ }
+
+ if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
+ // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ } else {
+ if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
+ // L1 does't have the line, but we have space for it in the L1
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ } else {
+ // No room in the L1, so we need to make room
+ trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address));
+ }
+ }
+ } else {
+ // *** DATA ACCESS ***
+
+ // Check to see if it is in the OTHER L1
+ if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
+ // The block is in the wrong L1, try to write it to the L2
+ trigger(Event:L1_Replacement, in_msg.Address);
+ }
+
+ if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
+ // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ } else {
+ if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
+ // L1 does't have the line, but we have space for it in the L1
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ } else {
+ // No room in the L1, so we need to make room
+ trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // ACTIONS
+
+ action(a_issueReadRequest, "a", desc="Issue GETS") {
+ if (L1_TBEs[address].IssueCount == 0) {
+ // Update outstanding requests
+ profile_outstanding_request(outstandingRequests);
+ outstandingRequests := outstandingRequests + 1;
+ }
+
+ if (L1_TBEs[address].IssueCount >= getRetryThreshold() ) {
+ // Issue a persistent request if possible
+ if (okToIssueStarving(address) && (starving == false)) {
+ enqueue(persistentNetwork_out, PersistentMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := PersistentRequestType:GETS_PERSISTENT;
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Persistent_Control;
+ out_msg.Prefetch := L1_TBEs[address].Prefetch;
+ out_msg.AccessMode := L1_TBEs[address].AccessMode;
+ }
+ markPersistentEntries(address);
+ starving := true;
+
+ if (L1_TBEs[address].IssueCount == 0) {
+ profile_persistent_prediction(address, L1_TBEs[address].AccessType);
+ }
+
+ // Update outstanding requests
+ profile_outstanding_persistent_request(outstandingPersistentRequests);
+ outstandingPersistentRequests := outstandingPersistentRequests + 1;
+
+ // Increment IssueCount
+ L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1;
+
+ L1_TBEs[address].WentPersistent := true;
+
+ // Do not schedule a wakeup, a persistent requests will always complete
+ }
+ else {
+
+ // We'd like to issue a persistent request, but are not allowed
+ // to issue a P.R. right now. This, we do not increment the
+ // IssueCount.
+
+ // Set a wakeup timer
+ reissueTimerTable.set(address, 10);
+
+ }
+ } else {
+ // Make a normal request
+ enqueue(requestNetwork_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GETS;
+ out_msg.Requestor := machineID;
+ out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address,machineID));
+ out_msg.RetryNum := L1_TBEs[address].IssueCount;
+ if (L1_TBEs[address].IssueCount == 0) {
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Reissue_Control;
+ }
+ out_msg.Prefetch := L1_TBEs[address].Prefetch;
+ out_msg.AccessMode := L1_TBEs[address].AccessMode;
+ }
+
+ // send to other local L1s, with local bit set
+ enqueue(requestNetwork_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GETS;
+ out_msg.Requestor := machineID;
+ out_msg.Destination := getOtherLocalL1IDs(machineID);
+ out_msg.RetryNum := L1_TBEs[address].IssueCount;
+ out_msg.isLocal := true;
+ if (L1_TBEs[address].IssueCount == 0) {
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Reissue_Control;
+ }
+ out_msg.Prefetch := L1_TBEs[address].Prefetch;
+ out_msg.AccessMode := L1_TBEs[address].AccessMode;
+ }
+
+ // Increment IssueCount
+ L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1;
+
+ // Set a wakeup timer
+
+ if (getDynamicTimeoutEnabled()) {
+ reissueTimerTable.set(address, 1.25 * averageLatencyEstimate());
+ } else {
+ reissueTimerTable.set(address, getFixedTimeoutLatency());
+ }
+
+ }
+ }
+
+ action(b_issueWriteRequest, "b", desc="Issue GETX") {
+
+ if (L1_TBEs[address].IssueCount == 0) {
+ // Update outstanding requests
+ profile_outstanding_request(outstandingRequests);
+ outstandingRequests := outstandingRequests + 1;
+ }
+
+ if (L1_TBEs[address].IssueCount >= getRetryThreshold() ) {
+ // Issue a persistent request if possible
+ if ( okToIssueStarving(address) && (starving == false)) {
+ enqueue(persistentNetwork_out, PersistentMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := PersistentRequestType:GETX_PERSISTENT;
+ out_msg.Requestor := machineID;
+ out_msg.RequestorMachine := MachineType:L1Cache;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Persistent_Control;
+ out_msg.Prefetch := L1_TBEs[address].Prefetch;
+ out_msg.AccessMode := L1_TBEs[address].AccessMode;
+ }
+ markPersistentEntries(address);
+ starving := true;
+
+ // Update outstanding requests
+ profile_outstanding_persistent_request(outstandingPersistentRequests);
+ outstandingPersistentRequests := outstandingPersistentRequests + 1;
+
+ if (L1_TBEs[address].IssueCount == 0) {
+ profile_persistent_prediction(address, L1_TBEs[address].AccessType);
+ }
+
+ // Increment IssueCount
+ L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1;
+
+ L1_TBEs[address].WentPersistent := true;
+
+ // Do not schedule a wakeup, a persistent requests will always complete
+ }
+ else {
+
+ // We'd like to issue a persistent request, but are not allowed
+ // to issue a P.R. right now. This, we do not increment the
+ // IssueCount.
+
+ // Set a wakeup timer
+ reissueTimerTable.set(address, 10);
+ }
+
+
+ } else {
+ // Make a normal request
+ enqueue(requestNetwork_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GETX;
+ out_msg.Requestor := machineID;
+ out_msg.RequestorMachine := MachineType:L1Cache;
+ out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address,machineID));
+ out_msg.RetryNum := L1_TBEs[address].IssueCount;
+
+ if (L1_TBEs[address].IssueCount == 0) {
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Reissue_Control;
+ }
+ out_msg.Prefetch := L1_TBEs[address].Prefetch;
+ out_msg.AccessMode := L1_TBEs[address].AccessMode;
+ }
+
+ // send to other local L1s too
+ enqueue(requestNetwork_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GETX;
+ out_msg.Requestor := machineID;
+ out_msg.isLocal := true;
+ out_msg.Destination := getOtherLocalL1IDs(machineID);
+ out_msg.RetryNum := L1_TBEs[address].IssueCount;
+ if (L1_TBEs[address].IssueCount == 0) {
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Reissue_Control;
+ }
+ out_msg.Prefetch := L1_TBEs[address].Prefetch;
+ out_msg.AccessMode := L1_TBEs[address].AccessMode;
+ }
+
+ // Increment IssueCount
+ L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1;
+
+ DEBUG_EXPR("incremented issue count");
+ DEBUG_EXPR(L1_TBEs[address].IssueCount);
+
+ // Set a wakeup timer
+ if (getDynamicTimeoutEnabled()) {
+ reissueTimerTable.set(address, 1.25 * averageLatencyEstimate());
+ } else {
+ reissueTimerTable.set(address, getFixedTimeoutLatency());
+ }
+ }
+ }
+
+ action(bb_bounceResponse, "\b", desc="Bounce tokens and data to memory") {
+ peek(responseNetwork_in, ResponseMsg) {
+ // FIXME, should use a 3rd vnet
+ enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.Tokens := in_msg.Tokens;
+ out_msg.MessageSize := in_msg.MessageSize;
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.Dirty := in_msg.Dirty;
+ }
+ }
+ }
+
+ action(c_ownedReplacement, "c", desc="Issue writeback") {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address,machineID));
+ out_msg.Tokens := getCacheEntry(address).Tokens;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.Dirty := getCacheEntry(address).Dirty;
+ out_msg.Type := CoherenceResponseType:WB_OWNED;
+
+ // always send the data?
+ out_msg.MessageSize := MessageSizeType:Writeback_Data;
+ }
+ getCacheEntry(address).Tokens := 0;
+ }
+
+ action(cc_sharedReplacement, "\c", desc="Issue dirty writeback") {
+
+ // don't send writeback if replacing block with no tokens
+ if (getCacheEntry(address).Tokens != 0) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address,machineID));
+ out_msg.Tokens := getCacheEntry(address).Tokens;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ // assert(getCacheEntry(address).Dirty == false);
+ out_msg.Dirty := false;
+
+ // always send the data?
+ if (getCacheEntry(address).Tokens > 1) {
+ out_msg.MessageSize := MessageSizeType:Writeback_Data;
+ out_msg.Type := CoherenceResponseType:WB_SHARED_DATA;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ out_msg.Type := CoherenceResponseType:WB_TOKENS;
+ }
+ }
+ getCacheEntry(address).Tokens := 0;
+ }
+ }
+
+
+ action(d_sendDataWithToken, "d", desc="Send data and a token from cache to requestor") {
+ peek(requestNetwork_in, RequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.Tokens := 1;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ // out_msg.Dirty := getCacheEntry(address).Dirty;
+ out_msg.Dirty := false;
+ if (in_msg.isLocal) {
+ out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
+ getCacheEntry(address).Tokens := getCacheEntry(address).Tokens - 1;
+ assert(getCacheEntry(address).Tokens >= 1);
+ }
+
+ action(d_sendDataWithNTokenIfAvail, "\dd", desc="Send data and a token from cache to requestor") {
+ peek(requestNetwork_in, RequestMsg) {
+ if (getCacheEntry(address).Tokens > N_tokens()) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.Tokens := N_tokens();
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ // out_msg.Dirty := getCacheEntry(address).Dirty;
+ out_msg.Dirty := false;
+ if (in_msg.isLocal) {
+ out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ getCacheEntry(address).Tokens := getCacheEntry(address).Tokens - N_tokens();
+ }
+ else if (getCacheEntry(address).Tokens > 1) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.Tokens := 1;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ // out_msg.Dirty := getCacheEntry(address).Dirty;
+ out_msg.Dirty := false;
+ if (in_msg.isLocal) {
+ out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ getCacheEntry(address).Tokens := getCacheEntry(address).Tokens - 1;
+ }
+ }
+// assert(getCacheEntry(address).Tokens >= 1);
+ }
+
+ action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") {
+ peek(requestNetwork_in, RequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ assert(getCacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getCacheEntry(address).Tokens;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.Dirty := getCacheEntry(address).Dirty;
+ if (in_msg.isLocal) {
+ out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
+ getCacheEntry(address).Tokens := 0;
+ }
+
+ action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") {
+ // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
+ if (getCacheEntry(address).Tokens > 0) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getCacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getCacheEntry(address).Tokens;
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ getCacheEntry(address).Tokens := 0;
+ }
+
+ action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") {
+ //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
+ assert(getCacheEntry(address).Tokens > 0);
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getCacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getCacheEntry(address).Tokens;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.Dirty := getCacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ getCacheEntry(address).Tokens := 0;
+ }
+
+ action(f_sendAckWithAllButNorOneTokens, "f", desc="Send ack with all our tokens but one to starver.") {
+ //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
+ assert(getCacheEntry(address).Tokens > 0);
+ if (getCacheEntry(address).Tokens > 1) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getCacheEntry(address).Tokens >= 1);
+ if (getCacheEntry(address).Tokens > N_tokens()) {
+ out_msg.Tokens := getCacheEntry(address).Tokens - N_tokens();
+ } else {
+ out_msg.Tokens := getCacheEntry(address).Tokens - 1;
+ }
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ if (getCacheEntry(address).Tokens > N_tokens()) {
+ getCacheEntry(address).Tokens := N_tokens();
+ } else {
+ getCacheEntry(address).Tokens := 1;
+ }
+ }
+
+ action(ff_sendDataWithAllButNorOneTokens, "\f", desc="Send data and out tokens but one to starver") {
+ //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
+ assert(getCacheEntry(address).Tokens > 0);
+ if (getCacheEntry(address).Tokens > 1) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getCacheEntry(address).Tokens >= 1);
+ if (getCacheEntry(address).Tokens > N_tokens()) {
+ out_msg.Tokens := getCacheEntry(address).Tokens - N_tokens();
+ } else {
+ out_msg.Tokens := getCacheEntry(address).Tokens - 1;
+ }
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.Dirty := getCacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ if (getCacheEntry(address).Tokens > N_tokens()) {
+ getCacheEntry(address).Tokens := N_tokens();
+ } else {
+ getCacheEntry(address).Tokens := 1;
+ }
+ }
+ }
+
+ action(g_bounceResponseToStarver, "g", desc="Redirect response to starving processor") {
+ // assert(persistentTable.isLocked(address));
+
+ peek(responseNetwork_in, ResponseMsg) {
+ // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
+ // FIXME, should use a 3rd vnet in some cases
+ enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ out_msg.Tokens := in_msg.Tokens;
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.Dirty := in_msg.Dirty;
+ out_msg.MessageSize := in_msg.MessageSize;
+ }
+ }
+ }
+
+
+ action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
+ DEBUG_EXPR(address);
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ sequencer.readCallback(address, getCacheEntry(address).DataBlk, GenericMachineType:L1Cache, PrefetchBit:No);
+ }
+
+ action(x_external_load_hit, "x", desc="Notify sequencer the load completed.") {
+ DEBUG_EXPR(address);
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ peek(responseNetwork_in, ResponseMsg) {
+
+ sequencer.readCallback(address, getCacheEntry(address).DataBlk, getNondirectHitMachType(in_msg.Address, in_msg.Sender), PrefetchBit:No);
+ }
+ }
+
+ action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
+ DEBUG_EXPR(address);
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ sequencer.writeCallback(address, getCacheEntry(address).DataBlk, GenericMachineType:L1Cache, PrefetchBit:No);
+ getCacheEntry(address).Dirty := true;
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ }
+
+ action(xx_external_store_hit, "\x", desc="Notify sequencer that store completed.") {
+ DEBUG_EXPR(address);
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ peek(responseNetwork_in, ResponseMsg) {
+ sequencer.writeCallback(address, getCacheEntry(address).DataBlk, getNondirectHitMachType(in_msg.Address, in_msg.Sender), PrefetchBit:No);
+ }
+ getCacheEntry(address).Dirty := true;
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ }
+
+ action(i_allocateTBE, "i", desc="Allocate TBE") {
+ check_allocate(L1_TBEs);
+ L1_TBEs.allocate(address);
+ L1_TBEs[address].IssueCount := 0;
+ peek(mandatoryQueue_in, CacheMsg) {
+ L1_TBEs[address].PC := in_msg.ProgramCounter;
+ L1_TBEs[address].AccessType := cache_request_type_to_access_type(in_msg.Type);
+ L1_TBEs[address].Prefetch := in_msg.Prefetch;
+ L1_TBEs[address].AccessMode := in_msg.AccessMode;
+ }
+ L1_TBEs[address].IssueTime := get_time();
+ }
+
+
+ action(j_unsetReissueTimer, "j", desc="Unset reissue timer.") {
+ if (reissueTimerTable.isSet(address)) {
+ reissueTimerTable.unset(address);
+ }
+ }
+
+ action(jj_unsetUseTimer, "\j", desc="Unset use timer.") {
+ useTimerTable.unset(address);
+ }
+
+
+
+ action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
+ mandatoryQueue_in.dequeue();
+ }
+
+ action(l_popPersistentQueue, "l", desc="Pop persistent queue.") {
+ persistentNetwork_in.dequeue();
+ }
+
+ action(m_popRequestQueue, "m", desc="Pop request queue.") {
+ requestNetwork_in.dequeue();
+ }
+
+ action(n_popResponseQueue, "n", desc="Pop response queue") {
+ responseNetwork_in.dequeue();
+ }
+
+ action(o_scheduleUseTimeout, "o", desc="Schedule a use timeout.") {
+ useTimerTable.set(address, 50);
+ }
+
+ action(p_informL2AboutTokenLoss, "p", desc="Inform L2 about loss of all tokens") {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:INV;
+ out_msg.Tokens := 0;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.DestMachine := MachineType:L2Cache;
+ out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address,machineID));
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+
+
+ action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(in_msg.Tokens != 0);
+ DEBUG_EXPR("MRM_DEBUG L1 received tokens");
+ DEBUG_EXPR(in_msg.Address);
+ DEBUG_EXPR(in_msg.Tokens);
+ getCacheEntry(address).Tokens := getCacheEntry(address).Tokens + in_msg.Tokens;
+ DEBUG_EXPR(getCacheEntry(address).Tokens);
+
+ if (getCacheEntry(address).Dirty == false && in_msg.Dirty) {
+ getCacheEntry(address).Dirty := true;
+ }
+ }
+ }
+
+ action(s_deallocateTBE, "s", desc="Deallocate TBE") {
+
+ if (L1_TBEs[address].WentPersistent) {
+ // assert(starving == true);
+ outstandingRequests := outstandingRequests - 1;
+ enqueue(persistentNetwork_out, PersistentMsg, latency="L1_REQUEST_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := PersistentRequestType:DEACTIVATE_PERSISTENT;
+ out_msg.Requestor := machineID;
+ out_msg.RequestorMachine := MachineType:L1Cache;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Persistent_Control;
+ }
+ starving := false;
+ }
+
+ // Update average latency
+ if (L1_TBEs[address].IssueCount <= 1) {
+ if (L1_TBEs[address].ExternalResponse == true) {
+ updateAverageLatencyEstimate(time_to_int(get_time()) - time_to_int(L1_TBEs[address].IssueTime));
+ }
+ }
+
+ // Profile
+ //if (L1_TBEs[address].WentPersistent) {
+ // profile_token_retry(address, L1_TBEs[address].AccessType, 2);
+ //}
+ //else {
+ // profile_token_retry(address, L1_TBEs[address].AccessType, 1);
+ //}
+
+ profile_token_retry(address, L1_TBEs[address].AccessType, L1_TBEs[address].IssueCount);
+ L1_TBEs.deallocate(address);
+ }
+
+ action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") {
+ if (getCacheEntry(address).Tokens > 0) {
+ peek(requestNetwork_in, RequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L1Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ assert(getCacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getCacheEntry(address).Tokens;
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ }
+ getCacheEntry(address).Tokens := 0;
+ }
+
+ action(u_writeDataToCache, "u", desc="Write data to cache") {
+ peek(responseNetwork_in, ResponseMsg) {
+ getCacheEntry(address).DataBlk := in_msg.DataBlk;
+ if (getCacheEntry(address).Dirty == false && in_msg.Dirty) {
+ getCacheEntry(address).Dirty := in_msg.Dirty;
+ }
+
+ }
+ }
+
+ action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
+ if (L1DcacheMemory.isTagPresent(address)) {
+ L1DcacheMemory.deallocate(address);
+ } else {
+ L1IcacheMemory.deallocate(address);
+ }
+ }
+
+ action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
+ if (L1DcacheMemory.isTagPresent(address) == false) {
+ L1DcacheMemory.allocate(address);
+ }
+ }
+
+ action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
+ if (L1IcacheMemory.isTagPresent(address) == false) {
+ L1IcacheMemory.allocate(address);
+ }
+ }
+
+ action(uu_profileMiss, "\u", desc="Profile the demand miss") {
+ peek(mandatoryQueue_in, CacheMsg) {
+ // profile_miss(in_msg, id);
+ }
+ }
+
+ action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(getCacheEntry(address).DataBlk == in_msg.DataBlk);
+ }
+ }
+
+
+ action(z_stall, "z", desc="Stall") {
+
+ }
+
+ action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
+ mandatoryQueue_in.recycle();
+ }
+
+ //*****************************************************
+ // TRANSITIONS
+ //*****************************************************
+
+ // Transitions for Load/Store/L2_Replacement from transient states
+ transition({IM, SM, OM, IS, IM_L, IS_L, I_L, S_L, SM_L, M_W, MM_W}, L1_Replacement) {
+ zz_recycleMandatoryQueue;
+ }
+
+ transition({IM, SM, OM, IS, IM_L, IS_L, SM_L}, Store) {
+ zz_recycleMandatoryQueue;
+ }
+
+ transition({IM, IS, IM_L, IS_L}, {Load, Ifetch}) {
+ zz_recycleMandatoryQueue;
+ }
+
+
+ // Lockdowns
+ transition({NP, I, S, O, M, MM, M_W, MM_W, IM, SM, OM, IS}, Own_Lock_or_Unlock) {
+ l_popPersistentQueue;
+ }
+
+ // Transitions from NP
+ transition(NP, Load, IS) {
+ ii_allocateL1DCacheBlock;
+ i_allocateTBE;
+ a_issueReadRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(NP, Ifetch, IS) {
+ pp_allocateL1ICacheBlock;
+ i_allocateTBE;
+ a_issueReadRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(NP, Store, IM) {
+ ii_allocateL1DCacheBlock;
+ i_allocateTBE;
+ b_issueWriteRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(NP, {Ack, Data_Shared, Data_Owner, Data_All_Tokens}) {
+ bb_bounceResponse;
+ n_popResponseQueue;
+ }
+
+ transition(NP, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) {
+ m_popRequestQueue;
+ }
+
+ transition(NP, {Persistent_GETX, Persistent_GETS}, I_L) {
+ l_popPersistentQueue;
+ }
+
+ // Transitions from Idle
+ transition(I, Load, IS) {
+ i_allocateTBE;
+ a_issueReadRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(I, Ifetch, IS) {
+ i_allocateTBE;
+ a_issueReadRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(I, Store, IM) {
+ i_allocateTBE;
+ b_issueWriteRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(I, L1_Replacement) {
+ cc_sharedReplacement;
+ gg_deallocateL1CacheBlock;
+ }
+
+ transition(I, {Transient_GETX, Transient_Local_GETX}) {
+ t_sendAckWithCollectedTokens;
+ m_popRequestQueue;
+ }
+
+ transition(I, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
+ m_popRequestQueue;
+ }
+
+ transition(I, {Persistent_GETX, Persistent_GETS}, I_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(I_L, {Persistent_GETX, Persistent_GETS}) {
+ l_popPersistentQueue;
+ }
+
+ transition(I, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(I, Data_Shared, S) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(I, Data_Owner, O) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(I, Data_All_Tokens, M) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ // Transitions from Shared
+ transition({S, SM, S_L, SM_L}, {Load, Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(S, Store, SM) {
+ i_allocateTBE;
+ b_issueWriteRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(S, L1_Replacement, I) {
+ cc_sharedReplacement; // Only needed in some cases
+ gg_deallocateL1CacheBlock;
+ }
+
+ transition(S, {Transient_GETX, Transient_Local_GETX}, I) {
+ t_sendAckWithCollectedTokens;
+ p_informL2AboutTokenLoss;
+ m_popRequestQueue;
+ }
+
+ // only owner responds to non-local requests
+ transition(S, Transient_GETS) {
+ m_popRequestQueue;
+ }
+
+ transition(S, Transient_Local_GETS) {
+ d_sendDataWithToken;
+ m_popRequestQueue;
+ }
+
+ transition(S, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) {
+ m_popRequestQueue;
+ }
+
+ transition({S, S_L}, Persistent_GETX, I_L) {
+ e_sendAckWithCollectedTokens;
+ p_informL2AboutTokenLoss;
+ l_popPersistentQueue;
+ }
+
+ transition(S, Persistent_GETS, S_L) {
+ f_sendAckWithAllButNorOneTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(S_L, Persistent_GETS) {
+ l_popPersistentQueue;
+ }
+
+ transition(S, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Data_Shared) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Data_Owner, O) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Data_All_Tokens, M) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ // Transitions from Owned
+ transition({O, OM}, {Load, Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(O, Store, OM) {
+ i_allocateTBE;
+ b_issueWriteRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(O, L1_Replacement, I) {
+ c_ownedReplacement;
+ gg_deallocateL1CacheBlock;
+ }
+
+ transition(O, {Transient_GETX, Transient_Local_GETX}, I) {
+ dd_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ m_popRequestQueue;
+ }
+
+ transition(O, Persistent_GETX, I_L) {
+ ee_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ l_popPersistentQueue;
+ }
+
+ transition(O, Persistent_GETS, S_L) {
+ ff_sendDataWithAllButNorOneTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(O, Transient_GETS) {
+ d_sendDataWithToken;
+ m_popRequestQueue;
+ }
+
+ transition(O, Transient_Local_GETS) {
+ d_sendDataWithToken;
+ m_popRequestQueue;
+ }
+
+ // ran out of tokens, wait for it to go persistent
+ transition(O, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) {
+ m_popRequestQueue;
+ }
+
+ transition(O, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(O, Ack_All_Tokens, M) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(O, Data_Shared) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(O, Data_All_Tokens, M) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ // Transitions from Modified
+ transition({MM, MM_W}, {Load, Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition({MM, MM_W}, Store) {
+ hh_store_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(MM, L1_Replacement, I) {
+ c_ownedReplacement;
+ gg_deallocateL1CacheBlock;
+ }
+
+ transition(MM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}, I) {
+ dd_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ m_popRequestQueue;
+ }
+
+ transition({MM_W}, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request
+ m_popRequestQueue;
+ }
+
+ // Implement the migratory sharing optimization, even for persistent requests
+ transition(MM, {Persistent_GETX, Persistent_GETS}, I_L) {
+ ee_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ l_popPersistentQueue;
+ }
+
+ // ignore persistent requests in lockout period
+ transition(MM_W, {Persistent_GETX, Persistent_GETS}) {
+ l_popPersistentQueue;
+ }
+
+
+ transition(MM_W, Use_TimeoutNoStarvers, MM) {
+ s_deallocateTBE;
+ jj_unsetUseTimer;
+ }
+
+ // Transitions from Dirty Exclusive
+ transition({M, M_W}, {Load, Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(M, Store, MM) {
+ hh_store_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(M_W, Store, MM_W) {
+ hh_store_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(M, L1_Replacement, I) {
+ c_ownedReplacement;
+ gg_deallocateL1CacheBlock;
+ }
+
+ transition(M, {Transient_GETX, Transient_Local_GETX}, I) {
+ dd_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ m_popRequestQueue;
+ }
+
+ transition(M, Transient_Local_GETS, O) {
+ d_sendDataWithToken;
+ m_popRequestQueue;
+ }
+
+ transition(M, Transient_GETS, O) {
+ d_sendDataWithNTokenIfAvail;
+ m_popRequestQueue;
+ }
+
+ transition(M_W, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request
+ m_popRequestQueue;
+ }
+
+ transition(M, Persistent_GETX, I_L) {
+ ee_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ l_popPersistentQueue;
+ }
+
+ transition(M, Persistent_GETS, S_L) {
+ ff_sendDataWithAllButNorOneTokens;
+ l_popPersistentQueue;
+ }
+
+ // ignore persistent requests in lockout period
+ transition(M_W, {Persistent_GETX, Persistent_GETS}) {
+ l_popPersistentQueue;
+ }
+
+ transition(M_W, Use_TimeoutStarverS, S_L) {
+ s_deallocateTBE;
+ ff_sendDataWithAllButNorOneTokens;
+ jj_unsetUseTimer;
+ }
+
+ // someone unlocked during timeout
+ transition(M_W, Use_TimeoutNoStarvers, M) {
+ s_deallocateTBE;
+ jj_unsetUseTimer;
+ }
+
+ transition(M_W, Use_TimeoutStarverX, I_L) {
+ s_deallocateTBE;
+ ee_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ jj_unsetUseTimer;
+ }
+
+
+
+ // migratory
+ transition(MM_W, {Use_TimeoutStarverX, Use_TimeoutStarverS}, I_L) {
+ s_deallocateTBE;
+ ee_sendDataWithAllTokens;
+ p_informL2AboutTokenLoss;
+ jj_unsetUseTimer;
+
+ }
+
+
+ // Transient_GETX and Transient_GETS in transient states
+ transition(OM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
+ m_popRequestQueue; // Even if we have the data, we can pretend we don't have it yet.
+ }
+
+ transition(IS, {Transient_GETX, Transient_Local_GETX}) {
+ t_sendAckWithCollectedTokens;
+ m_popRequestQueue;
+ }
+
+ transition(IS, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
+ m_popRequestQueue;
+ }
+
+ transition(IS, {Persistent_GETX, Persistent_GETS}, IS_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(IS_L, {Persistent_GETX, Persistent_GETS}) {
+ l_popPersistentQueue;
+ }
+
+ transition(IM, {Persistent_GETX, Persistent_GETS}, IM_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(IM_L, {Persistent_GETX, Persistent_GETS}) {
+ l_popPersistentQueue;
+ }
+
+ transition({SM, SM_L}, Persistent_GETX, IM_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(SM, Persistent_GETS, SM_L) {
+ f_sendAckWithAllButNorOneTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(SM_L, Persistent_GETS) {
+ l_popPersistentQueue;
+ }
+
+ transition(OM, Persistent_GETX, IM_L) {
+ ee_sendDataWithAllTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(OM, Persistent_GETS, SM_L) {
+ ff_sendDataWithAllButNorOneTokens;
+ l_popPersistentQueue;
+ }
+
+ // Transitions from IM/SM
+
+ transition({IM, SM}, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(IM, Data_Shared, SM) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(IM, Data_Owner, OM) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(IM, Data_All_Tokens, MM_W) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ xx_external_store_hit;
+ o_scheduleUseTimeout;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(SM, Data_Shared) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(SM, Data_Owner, OM) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(SM, Data_All_Tokens, MM_W) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ xx_external_store_hit;
+ o_scheduleUseTimeout;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition({IM, SM}, {Transient_GETX, Transient_Local_GETX}, IM) { // We don't have the data yet, but we might have collected some tokens. We give them up here to avoid livelock
+ t_sendAckWithCollectedTokens;
+ m_popRequestQueue;
+ }
+
+ transition({IM, SM}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
+ m_popRequestQueue;
+ }
+
+ transition({IM, SM}, Request_Timeout) {
+ j_unsetReissueTimer;
+ b_issueWriteRequest;
+ }
+
+ // Transitions from OM
+
+ transition(OM, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(OM, Ack_All_Tokens, MM_W) {
+ q_updateTokensFromResponse;
+ xx_external_store_hit;
+ o_scheduleUseTimeout;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(OM, Data_Shared) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(OM, Data_All_Tokens, MM_W) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ xx_external_store_hit;
+ o_scheduleUseTimeout;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(OM, Request_Timeout) {
+ j_unsetReissueTimer;
+ b_issueWriteRequest;
+ }
+
+ // Transitions from IS
+
+ transition(IS, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(IS, Data_Shared, S) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ x_external_load_hit;
+ s_deallocateTBE;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(IS, Data_Owner, O) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ x_external_load_hit;
+ s_deallocateTBE;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(IS, Data_All_Tokens, M_W) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ x_external_load_hit;
+ o_scheduleUseTimeout;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(IS, Request_Timeout) {
+ j_unsetReissueTimer;
+ a_issueReadRequest;
+ }
+
+ // Transitions from I_L
+
+ transition(I_L, Load, IS_L) {
+ ii_allocateL1DCacheBlock;
+ i_allocateTBE;
+ a_issueReadRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(I_L, Ifetch, IS_L) {
+ pp_allocateL1ICacheBlock;
+ i_allocateTBE;
+ a_issueReadRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(I_L, Store, IM_L) {
+ ii_allocateL1DCacheBlock;
+ i_allocateTBE;
+ b_issueWriteRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+
+ // Transitions from S_L
+
+ transition(S_L, Store, SM_L) {
+ i_allocateTBE;
+ b_issueWriteRequest;
+ uu_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ // Other transitions from *_L states
+
+ transition({I_L, IM_L, IS_L, S_L, SM_L}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS, Transient_GETX, Transient_Local_GETX}) {
+ m_popRequestQueue;
+ }
+
+ transition({I_L, IM_L, IS_L, S_L, SM_L}, Ack) {
+ g_bounceResponseToStarver;
+ n_popResponseQueue;
+ }
+
+ transition({I_L, IM_L, S_L, SM_L}, {Data_Shared, Data_Owner}) {
+ g_bounceResponseToStarver;
+ n_popResponseQueue;
+ }
+
+ transition({I_L, S_L}, Data_All_Tokens) {
+ g_bounceResponseToStarver;
+ n_popResponseQueue;
+ }
+
+ transition(IS_L, Request_Timeout) {
+ j_unsetReissueTimer;
+ a_issueReadRequest;
+ }
+
+ transition({IM_L, SM_L}, Request_Timeout) {
+ j_unsetReissueTimer;
+ b_issueWriteRequest;
+ }
+
+ // Opportunisticly Complete the memory operation in the following
+ // cases. Note: these transitions could just use
+ // g_bounceResponseToStarver, but if we have the data and tokens, we
+ // might as well complete the memory request while we have the
+ // chance (and then immediately forward on the data)
+
+ transition(IM_L, Data_All_Tokens, MM_W) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ xx_external_store_hit;
+ j_unsetReissueTimer;
+ o_scheduleUseTimeout;
+ n_popResponseQueue;
+ }
+
+ transition(SM_L, Data_All_Tokens, S_L) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ xx_external_store_hit;
+ ff_sendDataWithAllButNorOneTokens;
+ s_deallocateTBE;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(IS_L, Data_Shared, I_L) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ x_external_load_hit;
+ s_deallocateTBE;
+ e_sendAckWithCollectedTokens;
+ p_informL2AboutTokenLoss;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(IS_L, Data_Owner, I_L) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ x_external_load_hit;
+ ee_sendDataWithAllTokens;
+ s_deallocateTBE;
+ p_informL2AboutTokenLoss;
+ j_unsetReissueTimer;
+ n_popResponseQueue;
+ }
+
+ transition(IS_L, Data_All_Tokens, M_W) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ x_external_load_hit;
+ j_unsetReissueTimer;
+ o_scheduleUseTimeout;
+ n_popResponseQueue;
+ }
+
+
+ // Own_Lock_or_Unlock
+
+ transition(I_L, Own_Lock_or_Unlock, I) {
+ l_popPersistentQueue;
+ }
+
+ transition(S_L, Own_Lock_or_Unlock, S) {
+ l_popPersistentQueue;
+ }
+
+ transition(IM_L, Own_Lock_or_Unlock, IM) {
+ l_popPersistentQueue;
+ }
+
+ transition(IS_L, Own_Lock_or_Unlock, IS) {
+ l_popPersistentQueue;
+ }
+
+ transition(SM_L, Own_Lock_or_Unlock, SM) {
+ l_popPersistentQueue;
+ }
+}
+