summaryrefslogtreecommitdiff
path: root/src/mem/protocol/MOESI_CMP_token-L2cache.sm
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/protocol/MOESI_CMP_token-L2cache.sm')
-rw-r--r--src/mem/protocol/MOESI_CMP_token-L2cache.sm1424
1 files changed, 1424 insertions, 0 deletions
diff --git a/src/mem/protocol/MOESI_CMP_token-L2cache.sm b/src/mem/protocol/MOESI_CMP_token-L2cache.sm
new file mode 100644
index 000000000..21fbf0b95
--- /dev/null
+++ b/src/mem/protocol/MOESI_CMP_token-L2cache.sm
@@ -0,0 +1,1424 @@
+
+/*
+ * 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$
+ *
+ */
+
+machine(L2Cache, "Token protocol") {
+
+ // L2 BANK QUEUES
+ // From local bank of L2 cache TO the network
+ MessageBuffer L1RequestFromL2Cache, network="To", virtual_network="0", ordered="false"; // this L2 bank -> a local L1
+ MessageBuffer GlobalRequestFromL2Cache, network="To", virtual_network="1", ordered="false"; // this L2 bank -> mod-directory
+ MessageBuffer responseFromL2Cache, network="To", virtual_network="2", ordered="false"; // this L2 bank -> a local L1 || mod-directory
+
+
+ // FROM the network to this local bank of L2 cache
+ MessageBuffer L1RequestToL2Cache, network="From", virtual_network="0", ordered="false"; // a local L1 -> this L2 bank
+ MessageBuffer GlobalRequestToL2Cache, network="From", virtual_network="1", ordered="false"; // mod-directory -> this L2 bank
+ MessageBuffer responseToL2Cache, network="From", virtual_network="2", ordered="false"; // a local L1 || mod-directory -> this L2 bank
+ MessageBuffer persistentToL2Cache, network="From", virtual_network="3", ordered="true";
+
+ // STATES
+ enumeration(State, desc="L2 Cache states", default="L2Cache_State_I") {
+ // Base states
+ NP, desc="Not Present";
+ I, desc="Idle";
+ S, desc="Shared, not present in any local L1s";
+ O, desc="Owned, not present in any L1s";
+ M, desc="Modified, not present in any L1s";
+
+ // Locked states
+ I_L, "I^L", desc="Invalid, Locked";
+ S_L, "S^L", desc="Shared, Locked";
+ }
+
+ // EVENTS
+ enumeration(Event, desc="Cache events") {
+
+ // Requests
+ L1_GETS, desc="local L1 GETS request";
+ L1_GETS_Last_Token, desc="local L1 GETS request";
+ L1_GETX, desc="local L1 GETX request";
+ L1_INV, desc="L1 no longer has tokens";
+ Transient_GETX, desc="A GetX from another processor";
+ Transient_GETS, desc="A GetS from another processor";
+ Transient_GETS_Last_Token, desc="A GetS from another processor";
+
+ // events initiated by this L2
+ L2_Replacement, desc="L2 Replacement", format="!r";
+
+ // events of external L2 responses
+
+ // Responses
+ Writeback_Tokens, desc="Received a writeback from L1 with only tokens (no data)";
+ Writeback_Shared_Data, desc="Received a writeback from L1 that includes clean data";
+ Writeback_All_Tokens, desc="Received a writeback from L1";
+ Writeback_Owned, desc="Received a writeback from L1";
+
+
+ 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";
+
+ // Lock/Unlock
+ 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";
+ }
+
+ // TYPES
+
+ // 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";
+ }
+
+
+
+ structure(DirEntry, desc="...") {
+ Set Sharers, desc="Set of the internal processors that want the block in shared state";
+ bool exclusive, default="false", desc="if local exclusive is likely";
+ }
+
+ 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);
+ void setMRU(Address);
+ }
+
+ external_type(PerfectCacheMemory) {
+ void allocate(Address);
+ void deallocate(Address);
+ DirEntry lookup(Address);
+ bool isTagPresent(Address);
+ }
+
+
+ CacheMemory L2cacheMemory, template_hack="<L2Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L2Cache,int_to_string(i)+"_L2"';
+
+ PersistentTable persistentTable, constructor_hack="i";
+ PerfectCacheMemory localDirectory, template_hack="<L2Cache_DirEntry>";
+
+
+ bool getFilteringEnabled();
+
+ Entry getL2CacheEntry(Address addr), return_by_ref="yes" {
+ if (L2cacheMemory.isTagPresent(addr)) {
+ return L2cacheMemory[addr];
+ }
+ }
+
+ int getTokens(Address addr) {
+ if (L2cacheMemory.isTagPresent(addr)) {
+ return L2cacheMemory[addr].Tokens;
+ } else {
+ return 0;
+ }
+ }
+
+ void changePermission(Address addr, AccessPermission permission) {
+ if (L2cacheMemory.isTagPresent(addr)) {
+ return L2cacheMemory.changePermission(addr, permission);
+ }
+ }
+
+ bool isCacheTagPresent(Address addr) {
+ return (L2cacheMemory.isTagPresent(addr) );
+ }
+
+ State getState(Address addr) {
+ if (isCacheTagPresent(addr)) {
+ return getL2CacheEntry(addr).CacheState;
+ } else if (persistentTable.isLocked(addr) == true) {
+ return State:I_L;
+ } else {
+ return State:NP;
+ }
+ }
+
+ string getStateStr(Address addr) {
+ return L2Cache_State_to_string(getState(addr));
+ }
+
+ void setState(Address addr, State state) {
+
+
+ if (isCacheTagPresent(addr)) {
+ // Make sure the token count is in range
+ assert(getL2CacheEntry(addr).Tokens >= 0);
+ assert(getL2CacheEntry(addr).Tokens <= max_tokens());
+
+ // Make sure we have no tokens in L
+ if ((state == State:I_L) ) {
+ if (isCacheTagPresent(addr)) {
+ assert(getL2CacheEntry(addr).Tokens == 0);
+ }
+ }
+
+ // in M and E you have all the tokens
+ if (state == State:M ) {
+ assert(getL2CacheEntry(addr).Tokens == max_tokens());
+ }
+
+ // in NP you have no tokens
+ if (state == State:NP) {
+ assert(getL2CacheEntry(addr).Tokens == 0);
+ }
+
+ // You have at least one token in S-like states
+ if (state == State:S ) {
+ assert(getL2CacheEntry(addr).Tokens > 0);
+ }
+
+ // You have at least half the token in O-like states
+ if (state == State:O ) {
+ assert(getL2CacheEntry(addr).Tokens >= 1); // Must have at least one token
+ // assert(getL2CacheEntry(addr).Tokens >= (max_tokens() / 2)); // Only mostly true; this might not always hold
+ }
+
+ getL2CacheEntry(addr).CacheState := state;
+
+ // Set permission
+ if (state == State:I) {
+ changePermission(addr, AccessPermission:Invalid);
+ } else if (state == State:S || state == State:O ) {
+ changePermission(addr, AccessPermission:Read_Only);
+ } else if (state == State:M ) {
+ changePermission(addr, AccessPermission:Read_Write);
+ } else {
+ changePermission(addr, AccessPermission:Invalid);
+ }
+ }
+ }
+
+ void removeSharer(Address addr, NodeID id) {
+
+ if (localDirectory.isTagPresent(addr)) {
+ localDirectory[addr].Sharers.remove(id);
+ if (localDirectory[addr].Sharers.count() == 0) {
+ localDirectory.deallocate(addr);
+ }
+ }
+ }
+
+ bool sharersExist(Address addr) {
+ if (localDirectory.isTagPresent(addr)) {
+ if (localDirectory[addr].Sharers.count() > 0) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ bool exclusiveExists(Address addr) {
+ if (localDirectory.isTagPresent(addr)) {
+ if (localDirectory[addr].exclusive == true) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ // assumes that caller will check to make sure tag is present
+ Set getSharers(Address addr) {
+ return localDirectory[addr].Sharers;
+ }
+
+ void setNewWriter(Address addr, NodeID id) {
+ if (localDirectory.isTagPresent(addr) == false) {
+ localDirectory.allocate(addr);
+ }
+ localDirectory[addr].Sharers.clear();
+ localDirectory[addr].Sharers.add(id);
+ localDirectory[addr].exclusive := true;
+ }
+
+ void addNewSharer(Address addr, NodeID id) {
+ if (localDirectory.isTagPresent(addr) == false) {
+ localDirectory.allocate(addr);
+ }
+ localDirectory[addr].Sharers.add(id);
+ // localDirectory[addr].exclusive := false;
+ }
+
+ void clearExclusiveBitIfExists(Address addr) {
+ if (localDirectory.isTagPresent(addr) == true) {
+ localDirectory[addr].exclusive := false;
+ }
+ }
+
+ // ** OUT_PORTS **
+ out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache);
+ out_port(localRequestNetwork_out, RequestMsg, L1RequestFromL2Cache);
+ out_port(responseNetwork_out, ResponseMsg, responseFromL2Cache);
+
+
+
+ // ** IN_PORTS **
+
+ // Persistent Network
+ in_port(persistentNetwork_in, PersistentMsg, persistentToL2Cache) {
+ if (persistentNetwork_in.isReady()) {
+ peek(persistentNetwork_in, PersistentMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+
+ 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.typeOfSmallest(in_msg.Address) == AccessType:Read) {
+ trigger(Event:Persistent_GETS, in_msg.Address);
+ } else {
+ trigger(Event:Persistent_GETX, in_msg.Address);
+ }
+ }
+ else {
+ trigger(Event:Own_Lock_or_Unlock, in_msg.Address);
+ }
+ }
+ }
+ }
+
+
+ // Request Network
+ in_port(requestNetwork_in, RequestMsg, GlobalRequestToL2Cache) {
+ if (requestNetwork_in.isReady()) {
+ peek(requestNetwork_in, RequestMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+
+ if (in_msg.Type == CoherenceRequestType:GETX) {
+ trigger(Event:Transient_GETX, in_msg.Address);
+ } else if (in_msg.Type == CoherenceRequestType:GETS) {
+ if (L2cacheMemory.isTagPresent(in_msg.Address) && getL2CacheEntry(in_msg.Address).Tokens == 1) {
+ trigger(Event:Transient_GETS_Last_Token, in_msg.Address);
+ }
+ else {
+ trigger(Event:Transient_GETS, in_msg.Address);
+ }
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+
+ in_port(L1requestNetwork_in, RequestMsg, L1RequestToL2Cache) {
+ if (L1requestNetwork_in.isReady()) {
+ peek(L1requestNetwork_in, RequestMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+ if (in_msg.Type == CoherenceRequestType:GETX) {
+ trigger(Event:L1_GETX, in_msg.Address);
+ } else if (in_msg.Type == CoherenceRequestType:GETS) {
+ if (L2cacheMemory.isTagPresent(in_msg.Address) && getL2CacheEntry(in_msg.Address).Tokens == 1) {
+ trigger(Event:L1_GETS_Last_Token, in_msg.Address);
+ }
+ else {
+ trigger(Event:L1_GETS, in_msg.Address);
+ }
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+
+
+ // Response Network
+ in_port(responseNetwork_in, ResponseMsg, responseToL2Cache) {
+ if (responseNetwork_in.isReady()) {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(in_msg.Destination.isElement(machineID));
+ 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 if (in_msg.Type == CoherenceResponseType:WB_TOKENS || in_msg.Type == CoherenceResponseType:WB_OWNED || in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
+
+ if (L2cacheMemory.cacheAvail(in_msg.Address) || L2cacheMemory.isTagPresent(in_msg.Address)) {
+
+ // either room is available or the block is already present
+
+ if (in_msg.Type == CoherenceResponseType:WB_TOKENS) {
+ assert(in_msg.Dirty == false);
+ trigger(Event:Writeback_Tokens, in_msg.Address);
+ } else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
+ assert(in_msg.Dirty == false);
+ trigger(Event:Writeback_Shared_Data, in_msg.Address);
+ }
+ else if (in_msg.Type == CoherenceResponseType:WB_OWNED) {
+ //assert(in_msg.Dirty == false);
+ trigger(Event:Writeback_Owned, in_msg.Address);
+ }
+ }
+ else {
+ trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
+ }
+ } else if (in_msg.Type == CoherenceResponseType:INV) {
+ trigger(Event:L1_INV, 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 if (in_msg.Type == CoherenceResponseType:WB_TOKENS || in_msg.Type == CoherenceResponseType:WB_OWNED || in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
+ if (L2cacheMemory.cacheAvail(in_msg.Address) || L2cacheMemory.isTagPresent(in_msg.Address)) {
+
+ // either room is available or the block is already present
+
+ if (in_msg.Type == CoherenceResponseType:WB_TOKENS) {
+ assert(in_msg.Dirty == false);
+ assert( (getState(in_msg.Address) != State:NP) && (getState(in_msg.Address) != State:I) );
+ trigger(Event:Writeback_All_Tokens, in_msg.Address);
+ } else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
+ assert(in_msg.Dirty == false);
+ trigger(Event:Writeback_All_Tokens, in_msg.Address);
+ }
+ else if (in_msg.Type == CoherenceResponseType:WB_OWNED) {
+ trigger(Event:Writeback_All_Tokens, in_msg.Address);
+ }
+ }
+ else {
+ trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
+ }
+ } else if (in_msg.Type == CoherenceResponseType:INV) {
+ trigger(Event:L1_INV, in_msg.Address);
+ } else {
+ DEBUG_EXPR(in_msg.Type);
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+ }
+
+
+ // ACTIONS
+
+ action(a_broadcastLocalRequest, "a", desc="broadcast local request globally") {
+
+ peek(L1requestNetwork_in, RequestMsg) {
+
+ // if this is a retry or no local sharers, broadcast normally
+
+ // if (in_msg.RetryNum > 0 || (in_msg.Type == CoherenceRequestType:GETX && exclusiveExists(in_msg.Address) == false) || (in_msg.Type == CoherenceRequestType:GETS && sharersExist(in_msg.Address) == false)) {
+ enqueue(globalRequestNetwork_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
+ out_msg.Address := in_msg.Address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.RequestorMachine := in_msg.RequestorMachine;
+ //out_msg.Destination.broadcast(MachineType:L2Cache);
+ out_msg.RetryNum := in_msg.RetryNum;
+ out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
+ out_msg.Destination.remove(map_L1CacheMachId_to_L2Cache(address, in_msg.Requestor));
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ out_msg.AccessMode := in_msg.AccessMode;
+ out_msg.Prefetch := in_msg.Prefetch;
+ } //enqueue
+ // } // if
+
+ //profile_filter_action(0);
+ } // peek
+ } //action
+
+
+ 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:L2Cache;
+ 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_cleanReplacement, "c", desc="Issue clean writeback") {
+ if (getL2CacheEntry(address).Tokens > 0) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+ }
+
+ action(cc_dirtyReplacement, "\c", desc="Issue dirty writeback") {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := getL2CacheEntry(address).Dirty;
+
+ if (getL2CacheEntry(address).Dirty) {
+ out_msg.MessageSize := MessageSizeType:Writeback_Data;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ } else {
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ out_msg.Type := CoherenceResponseType:ACK_OWNER;
+ }
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+
+ action(d_sendDataWithTokens, "d", desc="Send data and a token from cache to requestor") {
+ peek(requestNetwork_in, RequestMsg) {
+ if (getL2CacheEntry(address).Tokens > N_tokens()) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.Tokens := N_tokens();
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := false;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens - N_tokens();
+ }
+ else {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.Tokens := 1;
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := false;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ getL2CacheEntry(address).Tokens := getL2CacheEntry(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="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := getL2CacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+
+ action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") {
+ if (getL2CacheEntry(address).Tokens > 0) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+
+ action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := getL2CacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+
+ action(f_sendAckWithAllButOneTokens, "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(getL2CacheEntry(address).Tokens > 0);
+ if (getL2CacheEntry(address).Tokens > 1) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens - 1;
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ getL2CacheEntry(address).Tokens := 1;
+ }
+
+ action(ff_sendDataWithAllButOneTokens, "\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(getL2CacheEntry(address).Tokens > 0);
+ if (getL2CacheEntry(address).Tokens > 1) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(persistentTable.findSmallest(address));
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens - 1;
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := getL2CacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ getL2CacheEntry(address).Tokens := 1;
+ }
+ }
+
+
+
+ action(gg_bounceResponseToStarver, "\g", desc="Redirect response to starving processor") {
+ // assert(persistentTable.isLocked(address));
+ peek(responseNetwork_in, ResponseMsg) {
+ // 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:L2Cache;
+ 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(gg_bounceWBSharedToStarver, "\gg", desc="Redirect response to starving processor") {
+ //assert(persistentTable.isLocked(address));
+ peek(responseNetwork_in, ResponseMsg) {
+ // FIXME, should use a 3rd vnet in some cases
+ enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
+ out_msg.Address := address;
+ if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ } else {
+ out_msg.Type := CoherenceResponseType:ACK;
+ }
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ 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(gg_bounceWBOwnedToStarver, "\ggg", desc="Redirect response to starving processor") {
+ // assert(persistentTable.isLocked(address));
+ peek(responseNetwork_in, ResponseMsg) {
+ // FIXME, should use a 3rd vnet in some cases
+ enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ 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_updateFilterFromL1HintOrWB, "h", desc="update filter from received writeback") {
+ peek(responseNetwork_in, ResponseMsg) {
+ removeSharer(in_msg.Address, machineIDToNodeID(in_msg.Sender));
+ }
+ }
+
+ action(j_forwardTransientRequestToLocalSharers, "j", desc="Forward external transient request to local sharers") {
+ peek(requestNetwork_in, RequestMsg) {
+ if (getFilteringEnabled() == true && in_msg.RetryNum == 0 && sharersExist(in_msg.Address) == false) {
+ profile_filter_action(1);
+ DEBUG_EXPR("filtered message");
+ DEBUG_EXPR(in_msg.RetryNum);
+ }
+ else {
+ enqueue( localRequestNetwork_out, RequestMsg, latency="L2_RESPONSE_LATENCY" ) {
+ out_msg.Address := in_msg.Address;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.RequestorMachine := in_msg.RequestorMachine;
+ out_msg.Destination := getLocalL1IDs(machineID);
+ out_msg.Type := in_msg.Type;
+ out_msg.isLocal := false;
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ out_msg.AccessMode := in_msg.AccessMode;
+ out_msg.Prefetch := in_msg.Prefetch;
+ }
+ profile_filter_action(0);
+ }
+ }
+ }
+
+
+ action(k_dataFromL2CacheToL1Requestor, "k", desc="Send data and a token from cache to L1 requestor") {
+ peek(L1requestNetwork_in, RequestMsg) {
+ assert(getL2CacheEntry(address).Tokens > 0);
+ //enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_to_L1_RESPONSE_LATENCY") {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_SHARED;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := false;
+ out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
+ out_msg.Tokens := 1;
+ }
+ getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens - 1;
+ }
+ }
+
+ action(k_dataOwnerFromL2CacheToL1Requestor, "\k", desc="Send data and a token from cache to L1 requestor") {
+ peek(L1requestNetwork_in, RequestMsg) {
+ assert(getL2CacheEntry(address).Tokens > 0);
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := getL2CacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
+ out_msg.Tokens := 1;
+ }
+ getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens - 1;
+ }
+ }
+
+ action(k_dataAndAllTokensFromL2CacheToL1Requestor, "\kk", desc="Send data and a token from cache to L1 requestor") {
+ peek(L1requestNetwork_in, RequestMsg) {
+// assert(getL2CacheEntry(address).Tokens == max_tokens());
+ //enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_to_L1_RESPONSE_LATENCY") {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:DATA_OWNER;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
+ out_msg.Dirty := getL2CacheEntry(address).Dirty;
+ out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
+ //out_msg.Tokens := max_tokens();
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+ }
+
+ 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_popL1RequestQueue, "o", desc="Pop L1 request queue.") {
+ L1requestNetwork_in.dequeue();
+ }
+
+
+ action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(in_msg.Tokens != 0);
+ getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens + in_msg.Tokens;
+
+ // this should ideally be in u_writeDataToCache, but Writeback_All_Tokens
+ // may not trigger this action.
+ if ( (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:WB_OWNED) && in_msg.Dirty) {
+ getL2CacheEntry(address).Dirty := true;
+ }
+ }
+ }
+
+ action(r_markNewSharer, "r", desc="Mark the new local sharer from local request message") {
+
+ peek(L1requestNetwork_in, RequestMsg) {
+ if (in_msg.Type == CoherenceRequestType:GETX) {
+ setNewWriter(in_msg.Address, machineIDToNodeID(in_msg.Requestor));
+ } else if (in_msg.Type == CoherenceRequestType:GETS) {
+ addNewSharer(in_msg.Address, machineIDToNodeID(in_msg.Requestor));
+ }
+ }
+ }
+
+ action(r_clearExclusive, "\rrr", desc="clear exclusive bit") {
+ clearExclusiveBitIfExists(address);
+ }
+
+ action( r_setMRU, "\rr", desc="manually set the MRU bit for cache line" ) {
+ if(isCacheTagPresent(address)) {
+ L2cacheMemory.setMRU(address);
+ }
+ }
+
+ action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") {
+ if (getL2CacheEntry(address).Tokens > 0) {
+ peek(requestNetwork_in, RequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+
+ action(tt_sendLocalAckWithCollectedTokens, "tt", desc="Send ack with the tokens we've collected thus far.") {
+ if (getL2CacheEntry(address).Tokens > 0) {
+ peek(L1requestNetwork_in, RequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.SenderMachine := MachineType:L2Cache;
+ out_msg.Destination.add(in_msg.Requestor);
+ assert(getL2CacheEntry(address).Tokens >= 1);
+ out_msg.Tokens := getL2CacheEntry(address).Tokens;
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ }
+ getL2CacheEntry(address).Tokens := 0;
+ }
+
+ action(u_writeDataToCache, "u", desc="Write data to cache") {
+ peek(responseNetwork_in, ResponseMsg) {
+ getL2CacheEntry(address).DataBlk := in_msg.DataBlk;
+ if ((getL2CacheEntry(address).Dirty == false) && in_msg.Dirty) {
+ getL2CacheEntry(address).Dirty := in_msg.Dirty;
+ }
+ }
+ }
+
+ action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
+ L2cacheMemory.allocate(address);
+ }
+
+ action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
+ L2cacheMemory.deallocate(address);
+ }
+
+ action(uu_profileMiss, "\u", desc="Profile the demand miss") {
+ peek(L1requestNetwork_in, RequestMsg) {
+ // AccessModeType not implemented
+ profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, machineIDToNodeID(in_msg.Requestor));
+ }
+ }
+
+
+ action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(getL2CacheEntry(address).DataBlk == in_msg.DataBlk);
+ }
+ }
+
+ action(z_stall, "z", desc="Stall") {
+ }
+
+
+
+
+ //*****************************************************
+ // TRANSITIONS
+ //*****************************************************
+
+ transition({NP, I, S, O, M, I_L, S_L}, L1_INV) {
+
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition({NP, I, S, O, M}, Own_Lock_or_Unlock) {
+ l_popPersistentQueue;
+ }
+
+
+ // Transitions from NP
+
+ transition(NP, {Transient_GETX, Transient_GETS}) {
+ // forward message to local sharers
+ r_clearExclusive;
+ j_forwardTransientRequestToLocalSharers;
+ m_popRequestQueue;
+ }
+
+
+ transition(NP, {L1_GETS, L1_GETX}) {
+ a_broadcastLocalRequest;
+ r_markNewSharer;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+ transition(NP, {Ack, Data_Shared, Data_Owner, Data_All_Tokens}) {
+ bb_bounceResponse;
+ n_popResponseQueue;
+ }
+
+ transition(NP, Writeback_Shared_Data, S) {
+ vv_allocateL2CacheBlock;
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(NP, Writeback_Tokens, I) {
+ vv_allocateL2CacheBlock;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(NP, Writeback_All_Tokens, M) {
+ vv_allocateL2CacheBlock;
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(NP, Writeback_Owned, O) {
+ vv_allocateL2CacheBlock;
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+
+ transition(NP, {Persistent_GETX, Persistent_GETS}, I_L) {
+ l_popPersistentQueue;
+ }
+
+ // Transitions from Idle
+
+ transition(I, {L1_GETS, L1_GETS_Last_Token}) {
+ a_broadcastLocalRequest;
+ tt_sendLocalAckWithCollectedTokens; // send any tokens we have collected
+ r_markNewSharer;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+ transition(I, L1_GETX) {
+ a_broadcastLocalRequest;
+ tt_sendLocalAckWithCollectedTokens; // send any tokens we have collected
+ r_markNewSharer;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+ transition(I, L2_Replacement) {
+ c_cleanReplacement; // Only needed in some cases
+ rr_deallocateL2CacheBlock;
+ }
+
+ transition(I, {Transient_GETX, Transient_GETS, Transient_GETS_Last_Token}) {
+ r_clearExclusive;
+ t_sendAckWithCollectedTokens;
+ j_forwardTransientRequestToLocalSharers;
+ m_popRequestQueue;
+ }
+
+ transition(I, {Persistent_GETX, Persistent_GETS}, I_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+
+ transition(I, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(I, Data_Shared, S) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(I, Writeback_Shared_Data, S) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(I, Writeback_Tokens) {
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(I, Data_Owner, O) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(I, Writeback_Owned, O) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(I, Data_All_Tokens, M) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+
+ transition(I, Writeback_All_Tokens, M) {
+ u_writeDataToCache;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ // Transitions from Shared
+
+ transition(S, L2_Replacement, I) {
+ c_cleanReplacement;
+ rr_deallocateL2CacheBlock;
+ }
+
+ transition(S, Transient_GETX, I) {
+ r_clearExclusive;
+ t_sendAckWithCollectedTokens;
+ j_forwardTransientRequestToLocalSharers;
+ m_popRequestQueue;
+ }
+
+ transition(S, {Transient_GETS, Transient_GETS_Last_Token}) {
+ j_forwardTransientRequestToLocalSharers;
+ r_clearExclusive;
+ m_popRequestQueue;
+ }
+
+ transition(S, Persistent_GETX, I_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+
+ transition(S, Persistent_GETS, S_L) {
+ f_sendAckWithAllButOneTokens;
+ l_popPersistentQueue;
+ }
+
+
+ transition(S, Ack) {
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Data_Shared) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Writeback_Tokens) {
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(S, Writeback_Shared_Data) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+
+ transition(S, Data_Owner, O) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Writeback_Owned, O) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(S, Data_All_Tokens, M) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(S, Writeback_All_Tokens, M) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(S, L1_GETX, I) {
+ a_broadcastLocalRequest;
+ tt_sendLocalAckWithCollectedTokens;
+ r_markNewSharer;
+ r_setMRU;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+
+ transition(S, L1_GETS) {
+ k_dataFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ transition(S, L1_GETS_Last_Token, I) {
+
+ k_dataFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ // Transitions from Owned
+
+ transition(O, L2_Replacement, I) {
+ cc_dirtyReplacement;
+ rr_deallocateL2CacheBlock;
+ }
+
+ transition(O, Transient_GETX, I) {
+ r_clearExclusive;
+ dd_sendDataWithAllTokens;
+ j_forwardTransientRequestToLocalSharers;
+ m_popRequestQueue;
+ }
+
+ transition(O, Persistent_GETX, I_L) {
+ ee_sendDataWithAllTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(O, Persistent_GETS, S_L) {
+ ff_sendDataWithAllButOneTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(O, Transient_GETS) {
+ // send multiple tokens
+ r_clearExclusive;
+ d_sendDataWithTokens;
+ m_popRequestQueue;
+ }
+
+ transition(O, Transient_GETS_Last_Token) {
+ // WAIT FOR IT TO GO PERSISTENT
+ r_clearExclusive;
+ 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, {Writeback_Tokens, Writeback_Shared_Data}) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(O, Data_All_Tokens, M) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ n_popResponseQueue;
+ }
+
+ transition(O, Writeback_All_Tokens, M) {
+ w_assertIncomingDataAndCacheDataMatch;
+ q_updateTokensFromResponse;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(O, L1_GETS) {
+ k_dataFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ transition(O, L1_GETS_Last_Token, I) {
+ k_dataOwnerFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ transition(O, L1_GETX, I) {
+ a_broadcastLocalRequest;
+ k_dataAndAllTokensFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+ // Transitions from M
+
+ transition(M, L2_Replacement, I) {
+ cc_dirtyReplacement;
+ rr_deallocateL2CacheBlock;
+ }
+
+ // MRM_DEBUG: Give up all tokens even for GETS? ???
+ transition(M, {Transient_GETX, Transient_GETS}, I) {
+ r_clearExclusive;
+ dd_sendDataWithAllTokens;
+ m_popRequestQueue;
+ }
+
+ transition(M, {Persistent_GETS, Persistent_GETX}, I_L) {
+ ee_sendDataWithAllTokens;
+ l_popPersistentQueue;
+ }
+
+
+ transition(M, L1_GETS, O) {
+ k_dataFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ transition(M, L1_GETX, I) {
+ k_dataAndAllTokensFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+
+ //Transitions from locked states
+
+ transition({I_L, S_L}, Ack) {
+ gg_bounceResponseToStarver;
+ n_popResponseQueue;
+ }
+
+ transition({I_L, S_L}, {Data_Shared, Data_Owner, Data_All_Tokens}) {
+ gg_bounceResponseToStarver;
+ n_popResponseQueue;
+ }
+
+ transition({I_L, S_L}, {Writeback_Tokens, Writeback_Shared_Data}) {
+ gg_bounceWBSharedToStarver;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition({I_L, S_L}, {Writeback_Owned, Writeback_All_Tokens}) {
+ gg_bounceWBOwnedToStarver;
+ h_updateFilterFromL1HintOrWB;
+ n_popResponseQueue;
+ }
+
+ transition(S_L, L2_Replacement, I) {
+ c_cleanReplacement;
+ rr_deallocateL2CacheBlock;
+ }
+
+ transition(I_L, L2_Replacement, I) {
+ rr_deallocateL2CacheBlock;
+ }
+
+ transition(I_L, Own_Lock_or_Unlock, I) {
+ l_popPersistentQueue;
+ }
+
+ transition(S_L, Own_Lock_or_Unlock, S) {
+ l_popPersistentQueue;
+ }
+
+ transition({I_L, S_L}, {Transient_GETS_Last_Token, Transient_GETS, Transient_GETX}) {
+ r_clearExclusive;
+ m_popRequestQueue;
+ }
+
+ transition(I_L, {L1_GETX, L1_GETS}) {
+ a_broadcastLocalRequest;
+ r_markNewSharer;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+ transition(S_L, L1_GETX, I_L) {
+ a_broadcastLocalRequest;
+ tt_sendLocalAckWithCollectedTokens;
+ r_markNewSharer;
+ r_setMRU;
+ uu_profileMiss;
+ o_popL1RequestQueue;
+ }
+
+ transition(S_L, L1_GETS) {
+ k_dataFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ transition(S_L, L1_GETS_Last_Token, I_L) {
+ k_dataFromL2CacheToL1Requestor;
+ r_markNewSharer;
+ r_setMRU;
+ o_popL1RequestQueue;
+ }
+
+ transition(S_L, Persistent_GETX, I_L) {
+ e_sendAckWithCollectedTokens;
+ l_popPersistentQueue;
+ }
+
+ transition(S_L, Persistent_GETS) {
+ l_popPersistentQueue;
+ }
+
+ transition(I_L, {Persistent_GETX, Persistent_GETS}) {
+ l_popPersistentQueue;
+ }
+}