gem5/src/mem/protocol/MOESI_CMP_token-L2cache.sm
Brad Beckmann 12a05c23b7 ruby: automate permission setting
This patch integrates permissions with cache and memory states, and then
automates the setting of permissions within the generated code.  No longer
does one need to manually set the permissions within the setState funciton.
This patch will faciliate easier functional access support by always correctly
setting permissions for both cache and memory states.

--HG--
rename : src/mem/slicc/ast/EnumDeclAST.py => src/mem/slicc/ast/StateDeclAST.py
rename : src/mem/slicc/ast/TypeFieldEnumAST.py => src/mem/slicc/ast/TypeFieldStateAST.py
2011-02-23 16:41:59 -08:00

1477 lines
48 KiB
Text

/*
* 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")
: CacheMemory * L2cacheMemory,
int N_tokens,
int l2_request_latency = 5,
int l2_response_latency = 5,
bool filtering_enabled = true
{
// L2 BANK QUEUES
// From local bank of L2 cache TO the network
// this L2 bank -> a local L1 || mod-directory
MessageBuffer responseFromL2Cache, network="To", virtual_network="4", ordered="false";
// this L2 bank -> mod-directory
MessageBuffer GlobalRequestFromL2Cache, network="To", virtual_network="2", ordered="false";
// this L2 bank -> a local L1
MessageBuffer L1RequestFromL2Cache, network="To", virtual_network="1", ordered="false";
// FROM the network to this local bank of L2 cache
// a local L1 || mod-directory -> this L2 bank
MessageBuffer responseToL2Cache, network="From", virtual_network="4", ordered="false";
MessageBuffer persistentToL2Cache, network="From", virtual_network="3", ordered="true";
// mod-directory -> this L2 bank
MessageBuffer GlobalRequestToL2Cache, network="From", virtual_network="2", ordered="false";
// a local L1 -> this L2 bank
MessageBuffer L1RequestToL2Cache, network="From", virtual_network="1", ordered="false";
// STATES
state_declaration(State, desc="L2 Cache states", default="L2Cache_State_I") {
// Base states
NP, AccessPermission:Invalid, desc="Not Present";
I, AccessPermission:Invalid, desc="Idle";
S, AccessPermission:Read_Only, desc="Shared, not present in any local L1s";
O, AccessPermission:Read_Only, desc="Owned, not present in any L1s";
M, AccessPermission:Read_Write, desc="Modified, not present in any L1s";
// Locked states
I_L, AccessPermission:Busy, "I^L", desc="Invalid, Locked";
S_L, AccessPermission:Busy, "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";
Persistent_GETS_Last_Token, 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(PerfectCacheMemory) {
void allocate(Address);
void deallocate(Address);
DirEntry lookup(Address);
bool isTagPresent(Address);
}
external_type(PersistentTable) {
void persistentRequestLock(Address, MachineID, AccessType);
void persistentRequestUnlock(Address, MachineID);
MachineID findSmallest(Address);
AccessType typeOfSmallest(Address);
void markEntries(Address);
bool isLocked(Address);
int countStarvingForAddress(Address);
int countReadStarvingForAddress(Address);
}
PersistentTable persistentTable;
PerfectCacheMemory localDirectory, template_hack="<L2Cache_DirEntry>";
void set_cache_entry(AbstractCacheEntry b);
void unset_cache_entry();
Entry getCacheEntry(Address address), return_by_pointer="yes" {
Entry cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address));
return cache_entry;
}
int getTokens(Entry cache_entry) {
if (is_valid(cache_entry)) {
return cache_entry.Tokens;
} else {
return 0;
}
}
State getState(Entry cache_entry, Address addr) {
if (is_valid(cache_entry)) {
return cache_entry.CacheState;
} else if (persistentTable.isLocked(addr) == true) {
return State:I_L;
} else {
return State:NP;
}
}
void setState(Entry cache_entry, Address addr, State state) {
if (is_valid(cache_entry)) {
// Make sure the token count is in range
assert(cache_entry.Tokens >= 0);
assert(cache_entry.Tokens <= max_tokens());
assert(cache_entry.Tokens != (max_tokens() / 2));
// Make sure we have no tokens in L
if ((state == State:I_L) ) {
assert(cache_entry.Tokens == 0);
}
// in M and E you have all the tokens
if (state == State:M ) {
assert(cache_entry.Tokens == max_tokens());
}
// in NP you have no tokens
if (state == State:NP) {
assert(cache_entry.Tokens == 0);
}
// You have at least one token in S-like states
if (state == State:S ) {
assert(cache_entry.Tokens > 0);
}
// You have at least half the token in O-like states
if (state == State:O ) {
assert(cache_entry.Tokens > (max_tokens() / 2));
}
cache_entry.CacheState := state;
}
}
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;
}
}
GenericRequestType convertToGenericType(CoherenceRequestType type) {
if(type == CoherenceRequestType:GETS) {
return GenericRequestType:GETS;
} else if(type == CoherenceRequestType:GETX) {
return GenericRequestType:GETX;
} else {
DPRINTF(RubySlicc, "%s\n", type);
error("invalid CoherenceRequestType");
}
}
// ** 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");
}
Entry cache_entry := getCacheEntry(in_msg.Address);
// 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) {
if (getTokens(cache_entry) == 1 ||
getTokens(cache_entry) == (max_tokens() / 2) + 1) {
trigger(Event:Persistent_GETS_Last_Token, in_msg.Address,
cache_entry);
} else {
trigger(Event:Persistent_GETS, in_msg.Address, cache_entry);
}
} else {
trigger(Event:Persistent_GETX, in_msg.Address, cache_entry);
}
}
else {
trigger(Event:Own_Lock_or_Unlock, in_msg.Address, cache_entry);
}
}
}
}
// Request Network
in_port(requestNetwork_in, RequestMsg, GlobalRequestToL2Cache) {
if (requestNetwork_in.isReady()) {
peek(requestNetwork_in, RequestMsg) {
assert(in_msg.Destination.isElement(machineID));
Entry cache_entry := getCacheEntry(in_msg.Address);
if (in_msg.Type == CoherenceRequestType:GETX) {
trigger(Event:Transient_GETX, in_msg.Address, cache_entry);
} else if (in_msg.Type == CoherenceRequestType:GETS) {
if (getTokens(cache_entry) == 1) {
trigger(Event:Transient_GETS_Last_Token, in_msg.Address,
cache_entry);
}
else {
trigger(Event:Transient_GETS, in_msg.Address, cache_entry);
}
} else {
error("Unexpected message");
}
}
}
}
in_port(L1requestNetwork_in, RequestMsg, L1RequestToL2Cache) {
if (L1requestNetwork_in.isReady()) {
peek(L1requestNetwork_in, RequestMsg) {
assert(in_msg.Destination.isElement(machineID));
Entry cache_entry := getCacheEntry(in_msg.Address);
if (in_msg.Type == CoherenceRequestType:GETX) {
trigger(Event:L1_GETX, in_msg.Address, cache_entry);
} else if (in_msg.Type == CoherenceRequestType:GETS) {
if (getTokens(cache_entry) == 1 ||
getTokens(cache_entry) == (max_tokens() / 2) + 1) {
trigger(Event:L1_GETS_Last_Token, in_msg.Address, cache_entry);
}
else {
trigger(Event:L1_GETS, in_msg.Address, cache_entry);
}
} 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));
Entry cache_entry := getCacheEntry(in_msg.Address);
if (getTokens(cache_entry) + in_msg.Tokens != max_tokens()) {
if (in_msg.Type == CoherenceResponseType:ACK) {
assert(in_msg.Tokens < (max_tokens() / 2));
trigger(Event:Ack, in_msg.Address, cache_entry);
} else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
trigger(Event:Data_Owner, in_msg.Address, cache_entry);
} else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
trigger(Event:Data_Shared, in_msg.Address, cache_entry);
} 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) || is_valid(cache_entry)) {
// 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, cache_entry);
} else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
assert(in_msg.Dirty == false);
trigger(Event:Writeback_Shared_Data, in_msg.Address, cache_entry);
}
else if (in_msg.Type == CoherenceResponseType:WB_OWNED) {
//assert(in_msg.Dirty == false);
trigger(Event:Writeback_Owned, in_msg.Address, cache_entry);
}
}
else {
trigger(Event:L2_Replacement,
L2cacheMemory.cacheProbe(in_msg.Address),
getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address)));
}
} else if (in_msg.Type == CoherenceResponseType:INV) {
trigger(Event:L1_INV, in_msg.Address, cache_entry);
} else {
error("Unexpected message");
}
} else {
if (in_msg.Type == CoherenceResponseType:ACK) {
assert(in_msg.Tokens < (max_tokens() / 2));
trigger(Event:Ack_All_Tokens, in_msg.Address, cache_entry);
} else if (in_msg.Type == CoherenceResponseType:DATA_OWNER ||
in_msg.Type == CoherenceResponseType:DATA_SHARED) {
trigger(Event:Data_All_Tokens, in_msg.Address, cache_entry);
} 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) || is_valid(cache_entry)) {
// either room is available or the block is already present
if (in_msg.Type == CoherenceResponseType:WB_TOKENS) {
assert(in_msg.Dirty == false);
assert( (getState(cache_entry, in_msg.Address) != State:NP)
&& (getState(cache_entry, in_msg.Address) != State:I) );
trigger(Event:Writeback_All_Tokens, in_msg.Address, cache_entry);
} else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
assert(in_msg.Dirty == false);
trigger(Event:Writeback_All_Tokens, in_msg.Address, cache_entry);
}
else if (in_msg.Type == CoherenceResponseType:WB_OWNED) {
trigger(Event:Writeback_All_Tokens, in_msg.Address, cache_entry);
}
}
else {
trigger(Event:L2_Replacement,
L2cacheMemory.cacheProbe(in_msg.Address),
getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address)));
}
} else if (in_msg.Type == CoherenceResponseType:INV) {
trigger(Event:L1_INV, in_msg.Address, cache_entry);
} else {
DPRINTF(RubySlicc, "%s\n", 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.RetryNum := in_msg.RetryNum;
//
// If a statically shared L2 cache, then no other L2 caches can
// store the block
//
//out_msg.Destination.broadcast(MachineType:L2Cache);
//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="1") {
out_msg.Address := address;
out_msg.Type := in_msg.Type;
out_msg.Sender := machineID;
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") {
assert(is_valid(cache_entry));
if (cache_entry.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.Destination.add(map_Address_to_Directory(address));
out_msg.Tokens := cache_entry.Tokens;
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
cache_entry.Tokens := 0;
}
}
action(cc_dirtyReplacement, "\c", desc="Issue dirty writeback") {
assert(is_valid(cache_entry));
enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) {
out_msg.Address := address;
out_msg.Sender := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.Tokens := cache_entry.Tokens;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
if (cache_entry.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;
}
}
cache_entry.Tokens := 0;
}
action(d_sendDataWithTokens, "d", desc="Send data and a token from cache to requestor") {
peek(requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA_SHARED;
out_msg.Sender := machineID;
out_msg.Destination.add(in_msg.Requestor);
out_msg.Tokens := N_tokens;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
cache_entry.Tokens := cache_entry.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.Destination.add(in_msg.Requestor);
out_msg.Tokens := 1;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
cache_entry.Tokens := cache_entry.Tokens - 1;
}
}
}
action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") {
assert(is_valid(cache_entry));
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.Destination.add(in_msg.Requestor);
assert(cache_entry.Tokens >= 1);
out_msg.Tokens := cache_entry.Tokens;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
cache_entry.Tokens := 0;
}
action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") {
assert(is_valid(cache_entry));
if (cache_entry.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.Destination.add(persistentTable.findSmallest(address));
assert(cache_entry.Tokens >= 1);
out_msg.Tokens := cache_entry.Tokens;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
cache_entry.Tokens := 0;
}
action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") {
assert(is_valid(cache_entry));
enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA_OWNER;
out_msg.Sender := machineID;
out_msg.Destination.add(persistentTable.findSmallest(address));
assert(cache_entry.Tokens >= 1);
out_msg.Tokens := cache_entry.Tokens;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
cache_entry.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(is_valid(cache_entry));
assert(cache_entry.Tokens > 0);
if (cache_entry.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.Destination.add(persistentTable.findSmallest(address));
assert(cache_entry.Tokens >= 1);
out_msg.Tokens := cache_entry.Tokens - 1;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
cache_entry.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(is_valid(cache_entry));
assert(cache_entry.Tokens > (max_tokens() / 2) + 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.Destination.add(persistentTable.findSmallest(address));
out_msg.Tokens := cache_entry.Tokens - 1;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
cache_entry.Tokens := 1;
}
action(fa_sendDataWithAllTokens, "fa", desc="Send data and out tokens but one to starver") {
//assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
assert(is_valid(cache_entry));
assert(cache_entry.Tokens == (max_tokens() / 2) + 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.Destination.add(persistentTable.findSmallest(address));
out_msg.Tokens := cache_entry.Tokens;
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
cache_entry.Tokens := 0;
}
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="1") {
out_msg.Address := address;
out_msg.Type := in_msg.Type;
out_msg.Sender := machineID;
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="1") {
out_msg.Address := address;
if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
out_msg.Type := CoherenceResponseType:DATA_SHARED;
} else {
assert(in_msg.Tokens < (max_tokens() / 2));
out_msg.Type := CoherenceResponseType:ACK;
}
out_msg.Sender := machineID;
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="1") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA_OWNER;
out_msg.Sender := machineID;
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 (filtering_enabled == true && in_msg.RetryNum == 0 && sharersExist(in_msg.Address) == false) {
//profile_filter_action(1);
DPRINTF(RubySlicc, "filtered message, Retry Num: %d\n",
in_msg.RetryNum);
}
else {
enqueue(localRequestNetwork_out, RequestMsg, latency=l2_response_latency ) {
out_msg.Address := in_msg.Address;
out_msg.Requestor := in_msg.Requestor;
//
// Currently assuming only one chip so all L1s are local
//
//out_msg.Destination := getLocalL1IDs(machineID);
out_msg.Destination.broadcast(MachineType:L1Cache);
out_msg.Destination.remove(in_msg.Requestor);
out_msg.Type := in_msg.Type;
out_msg.isLocal := false;
out_msg.MessageSize := MessageSizeType:Broadcast_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(is_valid(cache_entry));
assert(cache_entry.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.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
out_msg.Tokens := 1;
}
cache_entry.Tokens := cache_entry.Tokens - 1;
}
}
action(k_dataOwnerFromL2CacheToL1Requestor, "\k", desc="Send data and a token from cache to L1 requestor") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
assert(cache_entry.Tokens == (max_tokens() / 2) + 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.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
out_msg.Tokens := cache_entry.Tokens;
}
cache_entry.Tokens := 0;
}
}
action(k_dataAndAllTokensFromL2CacheToL1Requestor, "\kk", desc="Send data and a token from cache to L1 requestor") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
// assert(cache_entry.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.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
//out_msg.Tokens := max_tokens();
out_msg.Tokens := cache_entry.Tokens;
}
cache_entry.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(is_valid(cache_entry));
assert(in_msg.Tokens != 0);
cache_entry.Tokens := cache_entry.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) {
cache_entry.Dirty := true;
}
}
}
action(r_markNewSharer, "r", desc="Mark the new local sharer from local request message") {
peek(L1requestNetwork_in, RequestMsg) {
if (machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache) {
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" ) {
peek(L1requestNetwork_in, RequestMsg) {
if ((machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache) &&
(is_valid(cache_entry))) {
L2cacheMemory.setMRU(address);
}
}
}
action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") {
assert(is_valid(cache_entry));
if (cache_entry.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.Destination.add(in_msg.Requestor);
assert(cache_entry.Tokens >= 1);
out_msg.Tokens := cache_entry.Tokens;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
}
cache_entry.Tokens := 0;
}
action(tt_sendLocalAckWithCollectedTokens, "tt", desc="Send ack with the tokens we've collected thus far.") {
assert(is_valid(cache_entry));
if (cache_entry.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.Destination.add(in_msg.Requestor);
assert(cache_entry.Tokens >= 1);
out_msg.Tokens := cache_entry.Tokens;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
}
cache_entry.Tokens := 0;
}
action(u_writeDataToCache, "u", desc="Write data to cache") {
peek(responseNetwork_in, ResponseMsg) {
assert(is_valid(cache_entry));
cache_entry.DataBlk := in_msg.DataBlk;
if ((cache_entry.Dirty == false) && in_msg.Dirty) {
cache_entry.Dirty := in_msg.Dirty;
}
}
}
action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
set_cache_entry(L2cacheMemory.allocate(address, new Entry));
}
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);
unset_cache_entry();
}
action(uu_profileMiss, "\u", desc="Profile the demand miss") {
peek(L1requestNetwork_in, RequestMsg) {
L2cacheMemory.profileGenericRequest(convertToGenericType(in_msg.Type),
in_msg.AccessMode,
in_msg.Prefetch);
}
}
action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") {
peek(responseNetwork_in, ResponseMsg) {
if (in_msg.Type != CoherenceResponseType:ACK &&
in_msg.Type != CoherenceResponseType:WB_TOKENS) {
assert(is_valid(cache_entry));
assert(cache_entry.DataBlk == in_msg.DataBlk);
}
}
}
//*****************************************************
// 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, Persistent_GETS_Last_Token},
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, Persistent_GETS_Last_Token},
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, Persistent_GETS_Last_Token}, 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, Persistent_GETS_Last_Token, I_L) {
fa_sendDataWithAllTokens;
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, Persistent_GETS_Last_Token}) {
l_popPersistentQueue;
}
transition(I_L, {Persistent_GETX, Persistent_GETS}) {
l_popPersistentQueue;
}
}