summaryrefslogtreecommitdiff
path: root/src/mem/protocol/MOESI_CMP_token-L2cache.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-L2cache.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-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;
+ }
+}