gem5/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm

2192 lines
78 KiB
Text
Raw Normal View History

/*
* 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, "MOSI Directory L2 Cache CMP") {
// L2 BANK QUEUES
// From local bank of L2 cache TO the network
MessageBuffer dummyFrom0, network="To", virtual_network="0", ordered="false"; // dummy buffer that shouldn't be used
MessageBuffer DirRequestFromL2Cache, network="To", virtual_network="1", ordered="false"; // this L2 bank -> mod-directory
MessageBuffer L1RequestFromL2Cache, network="To", virtual_network="2", ordered="true"; // this L2 bank -> a local L1
MessageBuffer responseFromL2Cache, network="To", virtual_network="3", ordered="false"; // this L2 bank -> a local L1 || mod-directory
MessageBuffer finalAckFromL2Cache, network="To", virtual_network="4", ordered="false"; // this L2 bank -> mod-directory
// FROM the network to this local bank of L2 cache
//MessageBuffer L1RequestToL2Cache, network="From", virtual_network="1", ordered="true"; // a local L1 -> this L2 bank
MessageBuffer L1RequestToL2Cache, network="From", virtual_network="0", ordered="true"; // a local L1 -> this L2 bank
MessageBuffer dummyTo1, network="From", virtual_network="1", ordered="false"; // dummy buffer that shouldn't be used
MessageBuffer forwardedRequestToL2Cache, network="From", virtual_network="2", ordered="true"; // mod-directory -> this L2 bank
MessageBuffer responseToL2Cache, network="From", virtual_network="3", ordered="false"; // a local L1 || mod-directory -> this L2 bank
MessageBuffer dummyTo4, network="From", virtual_network="4", ordered="false"; // dummy buffer that shouldn't be used
// STATES
enumeration(State, desc="L2 Cache states", default="L2Cache_State_L2_NP") {
// Base states
L2_NP, desc="Not present in either cache";
L2_I, desc="L2 cache entry Idle";
L2_S, desc="L2 cache entry Shared, not present in any local L1s";
L2_O, desc="L2 cache entry Owned, not present in any local L1s";
L2_M, desc="L2 cache entry Modified, not present in any L1s", format="!b";
L2_SS, desc="L2 cache entry Shared, also present in one or more L1s";
L2_SO, desc="L2 cache entry Owned, also present in one or more L1s or ext L2s";
L2_MT, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
// Transient States
// Transient States from I
L2_IS, desc="L2 idle, issued GETS, have not seen response yet";
L2_ISZ, desc="L2 idle, issued GETS, saw a L1_GETX, have not seen data for GETS yet", format="!b";
L2_ISI, desc="L2 idle, issued GETS, saw INV, have not seen data for GETS yet", format="!b";
L2_IMV, desc="L2 idle, issued GETX, valid int L1, have not seen response(s) yet";
L2_MV, desc="L2 modified, a valid old L1 copy exist, external world gave write permission";
L2_IM, desc="L2 idle, issued GETX, no valid int L1, have not seen response(s) yet";
L2_IMO, desc="L2 idle, issued GETX, saw forwarded GETS";
L2_IMI, desc="L2 idle, issued GETX, saw forwarded GETX";
L2_IMZ, desc="L2 idle, issued GETX, saw another L1_GETX";
L2_IMOI, desc="L2 idle, issued GETX, saw GETS, saw forwarded GETX";
L2_IMOZ, desc="L2 idle, issued GETX, saw GETS, then a L1_GETX";
// Invalidation steps for S -> I
L2_SIC, desc="L2 shared, L2_INV, valid L1 copies exist, issued invalidates, have not seen responses yet";
L2_SIV, desc="L2 shared, L2_Replacement, valid L1 copies exist, issued invalidates, have not seen responses yet";
// Invalidation steps for M -> I for L2 Repalcement
L2_MIV, desc="L2 modified, a valid L1 copy exist, issued forced writeback, have not seen the response yet";
L2_MIN, desc="L2 modified, no valid L1 copies, issued PUTX, have not seen response yet";
// Invalidation steps for M -> I for a Forwarded GetX
L2_MIC, desc="L2 modified, a valid L1 copy exist, issued forced writeback, have not seen the response yet";
// In MT state and see another L1_GETX request
L2_MIT, desc="L2 modified, a valid L1 copy exist, saw L1_GETX, issued INV, have not seen the response yet";
// Downgrade steps for M -> SO
L2_MO, desc="L2 modified, a valid L1 copy exist, issued downgrade request, have not seen response yet";
L2_MOIC, desc="L2 modified, a valid L1 copy exist, issued downgrade request, saw INV, have not seen response yet";
L2_MOICR, desc="L2 modified, a valid L1 copy exist, issued invalidate request, saw INV, have not seen response yet";
L2_MOZ, desc="L2 modified, a valid L1 copy exist, issued downgrade request, saw L1_GETX, have not seen response yet";
// Invalidation steps for O/SO -> I for L2 Replacement
L2_OIV, desc="L2 owned, valid L1 copies exist, issued invalidates, have not seen responses yet from L1s";
L2_OIN, desc="L2 owned, no valid L1 copies, issued PUTX, have not seen response yet from dir";
// Invalidation steps for SO -> I for a Forwarded GetX
L2_OIC, desc="L2 owned, valid L1 copies exist, issued invalidates, have not seen responses yet from L1s";
// Strange OM states
// Note: strange states, because it is waiting for the line
// to be stolen away, or look like it has been stolen away. The
// common case is that we see a forward from the directory that is
// really from us, we forwarded the data to our dataqueue, and
// everythings works fine.
L2_OMV, desc="L2 owned and valid L1 copies, issued GETX and invalidates, have not seen responses yet";
L2_OM, desc="L2 owned and no valid L1 copies, issued GETX, have not seen response yet";
}
// EVENTS
enumeration(Event, desc="L2 Cache events") {
// L2 events
// events initiated by the local L1s
L1_GET_INSTR, desc="a L1I GET INSTR request for a block maped to us";
L1_GETS, desc="a L1D GETS request for a block maped to us";
L1_GETX, desc="a L1D GETX request for a block maped to us";
L1_UPGRADE, desc="a L1D UPGRADE request for a block maped to us";
L1_UPGRADE_no_others, desc="a L1D UPGRADE request for a block maped to us, requestor is the only on-chip sharer";
L1_PUTX, desc="a L1D PUTX request for a block maped to us (L1 replacement of a modified block)";
L1_PUTX_last, desc="a L1D PUTX request for a block maped to us (L1 replacement of a modified block) last sharer";
L1_PUTX_old, desc="an old L1D PUTX request for a block maped to us (L1 replacement of a modified block)";
L1_PUTS, desc="a L1 replacement of a shared block", format="!r";
L1_PUTS_last, desc="a L1 replacement of the last local L1 shared block", format="!r";
L1_PUTS_old, desc="an old L1 replacement of a shared block", format="!r";
// events of local L1 responses
Proc_int_ack, "Proc on-chip L1 Cache ack", desc="Ack from on-chip L1 Cache";
Proc_last_int_ack, "Proc last on-chip L1 Cache ack", desc="Last on-chip L1 Cache ack", format="!r";
Data_int_ack, "Data int ack", desc="Received modified data from L1 now proceed in handling miss";
// events initiated by the external L2s
Forwarded_GETS, "Forwarded GETS", desc="Directory forwards Inter-chip GETS to us";
Forwarded_GET_INSTR, "Forwarded GETINSTR", desc="Inter-chip Forwarded GETINSTR";
Forwarded_GETX, "Forwarded GETX", desc="Directory forwards Inter-chip GETX to us";
L2_INV, "L2_INV", desc="L2 Invalidation initiated from other L2", format="!r";
// events initiated by this L2
L2_Replacement, desc="L2 Replacement", format="!r";
// events of external L2 responses
Proc_ext_ack, "Proc off-chip ack", desc="Ack from off-chip";
Proc_last_ext_ack, "Proc last off-chip ack", desc="Last off-chip ack", format="!r";
Data_ext_ack_0, "Data ack 0", desc="Data with ack count = 0";
Data_ext_ack_not_0, "Data ack not 0", desc="Data with ack count != 0 (but haven't seen all acks first";
// Data_ext_ack_not_0_last: is when the requestor has seen all acks but the directory has not, therefore
// the directory must be told that we now have the data
Data_ext_ack_not_0_last, "Data ack not 0 last", desc="Data with ack count != 0 after having received all acks";
Dir_WB_ack, "WB ack", desc="Writeback ack from dir";
Dir_exe_ack, "Only copy", desc="Directory tells us we already have exclusive permission, go directly to MT state";
}
// TYPES
// CacheEntry
structure(Entry, desc="...", interface="AbstractCacheEntry") {
State CacheState, desc="cache state";
NetDest Sharers, desc="tracks the L1 shares on-chip";
DataBlock DataBlk, desc="data for the block";
}
// TBE fields
structure(TBE, desc="...") {
Address Address, desc="Physical address for this TBE";
State TBEState, desc="Transient state";
DataBlock DataBlk, desc="Buffer for the data block";
int NumPendingExtAcks, desc="Number of ext acks that this L2 bank is waiting for";
int NumPendingIntAcks, desc="Number of int acks that this L2 bank is waiting for";
NetDest Forward_GetS_IDs, desc="Set of the external processors to forward the block";
NetDest L1_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
MachineID Forward_GetX_ID, desc="ID of the L2 cache to forward the block";
MachineID L1_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
MachineID InvalidatorID, desc="ID of the L2 cache (needed for L2_SS -> L2_I)";
int ForwardGetX_AckCount, desc="Number of acks the GetX we are forwarded needs";
bool isPrefetch, desc="Set if this was caused by a prefetch";
bool isThreeHop, desc="is this request a three hop";
bool validForwardedGetXId, desc="Indicate whether a forwarded GetX ID is valid";
bool validInvalidator, desc="Indicate whether an invalidator is valid";
bool isInternalRequestOnly, desc="Is internal request only, i.e. only L1s";
}
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(TBETable) {
TBE lookup(Address);
void allocate(Address);
void deallocate(Address);
bool isPresent(Address);
}
TBETable L2_TBEs, template_hack="<L2Cache_TBE>";
CacheMemory L2cacheMemory, template_hack="<L2Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L2Cache,int_to_string(i)';
// inclusive cache, returns L2 entries only
Entry getL2CacheEntry(Address addr), return_by_ref="yes" {
return L2cacheMemory[addr];
}
void changeL2Permission(Address addr, AccessPermission permission) {
if (L2cacheMemory.isTagPresent(addr)) {
return L2cacheMemory.changePermission(addr, permission);
}
}
string getCoherenceRequestTypeStr(CoherenceRequestType type) {
return CoherenceRequestType_to_string(type);
}
bool isL2CacheTagPresent(Address addr) {
return (L2cacheMemory.isTagPresent(addr));
}
bool isOneSharerLeft(Address addr, MachineID requestor) {
assert(L2cacheMemory[addr].Sharers.isElement(requestor));
return (L2cacheMemory[addr].Sharers.count() == 1);
}
bool isSharer(Address addr, MachineID requestor) {
if (L2cacheMemory.isTagPresent(addr)) {
return L2cacheMemory[addr].Sharers.isElement(requestor);
} else {
return false;
}
}
void addSharer(Address addr, MachineID requestor) {
DEBUG_EXPR(machineID);
DEBUG_EXPR(requestor);
DEBUG_EXPR(addr);
assert(map_L1CacheMachId_to_L2Cache(addr, requestor) == machineID);
L2cacheMemory[addr].Sharers.add(requestor);
}
State getState(Address addr) {
if(L2_TBEs.isPresent(addr)) {
return L2_TBEs[addr].TBEState;
} else if (isL2CacheTagPresent(addr)) {
return getL2CacheEntry(addr).CacheState;
}
return State:L2_NP;
}
string getStateStr(Address addr) {
return L2Cache_State_to_string(getState(addr));
}
// when is this called
void setState(Address addr, State state) {
// MUST CHANGE
if (L2_TBEs.isPresent(addr)) {
L2_TBEs[addr].TBEState := state;
}
if (isL2CacheTagPresent(addr)) {
getL2CacheEntry(addr).CacheState := state;
// Set permission
if (state == State:L2_I ||
state == State:L2_SIC || state == State:L2_SIV ||
state == State:L2_MIV || state == State:L2_MIN || state == State:L2_MIC || state == State:L2_MIT ||
state == State:L2_OIV || state == State:L2_OIN || state == State:L2_OIC) {
changeL2Permission(addr, AccessPermission:Invalid);
} else if (state == State:L2_S || state == State:L2_O || state == State:L2_SS || state == State:L2_SO) {
changeL2Permission(addr, AccessPermission:Read_Only);
} else if (state == State:L2_OM || state == State:L2_OMV) {
changeL2Permission(addr, AccessPermission:ReadUpgradingToWrite);
} else if (state == State:L2_M) {
changeL2Permission(addr, AccessPermission:Read_Write);
} else if (state == State:L2_MT) {
changeL2Permission(addr, AccessPermission:Stale);
} else {
changeL2Permission(addr, AccessPermission:Busy);
}
}
}
Event L1Cache_request_type_to_event(CoherenceRequestType type, Address addr, MachineID requestor) {
if(type == CoherenceRequestType:GETS) {
return Event:L1_GETS;
} else if(type == CoherenceRequestType:GET_INSTR) {
return Event:L1_GET_INSTR;
} else if (type == CoherenceRequestType:GETX) {
return Event:L1_GETX;
} else if (type == CoherenceRequestType:UPGRADE) {
if (isSharer(addr, requestor)) {
if (isOneSharerLeft(addr, requestor)) {
return Event:L1_UPGRADE_no_others;
} else {
return Event:L1_UPGRADE;
}
} else { // possible that we removed the line from the L2 before we could process the UPGRADE request
return Event:L1_GETX;
}
} else if (type == CoherenceRequestType:PUTX) {
if (isSharer(addr, requestor)) {
if (isOneSharerLeft(addr, requestor)) {
return Event:L1_PUTX_last;
} else {
return Event:L1_PUTX;
}
} else {
return Event:L1_PUTX_old;
}
} else if (type == CoherenceRequestType:PUTS) {
if (isSharer(addr, requestor)) {
if (isOneSharerLeft(addr, requestor)) {
return Event:L1_PUTS_last;
} else {
return Event:L1_PUTS;
}
} else { // possible that we removed the line from the L2 before we could process the L1_PUTS request
return Event:L1_PUTS_old;
}
} else {
DEBUG_EXPR(addr);
DEBUG_EXPR(type);
error("Invalid L1 forwarded request type");
}
}
// ** OUT_PORTS **
// All ports output to the same CMP network, NI determines where to route msg
out_port(L1RequestIntraChipL2Network_out, RequestMsg, L1RequestFromL2Cache);
out_port(DirRequestIntraChipL2Network_out, RequestMsg, DirRequestFromL2Cache);
out_port(responseIntraChipL2Network_out, ResponseMsg, responseFromL2Cache);
out_port(finalAckIntraChipL2Network_out, ResponseMsg, finalAckFromL2Cache);
// ** IN_PORTS **
in_port(dummyTo1_in, RequestMsg, dummyTo1) {
if (dummyTo1_in.isReady()) {
peek(dummyTo1_in, RequestMsg) {
DEBUG_EXPR(in_msg.Address);
DEBUG_EXPR(id);
DEBUG_EXPR(in_msg.Type);
DEBUG_EXPR(getState(in_msg.Address));
DEBUG_EXPR(in_msg.RequestorMachId);
}
error("dummyTo1 port should not be used");
}
}
in_port(dummyTo4_in, ResponseMsg, dummyTo4) {
if (dummyTo4_in.isReady()) {
peek(dummyTo4_in, ResponseMsg) {
DEBUG_EXPR(in_msg.Address);
DEBUG_EXPR(id);
DEBUG_EXPR(in_msg.Type);
DEBUG_EXPR(getState(in_msg.Address));
DEBUG_EXPR(in_msg.SenderMachId);
}
error("dummyTo4 port should not be used");
}
}
// Response IntraChip L2 Network - response msg to this particular L2 bank
in_port(responseIntraChipL2Network_in, ResponseMsg, responseToL2Cache) {
if (responseIntraChipL2Network_in.isReady()) {
peek(responseIntraChipL2Network_in, ResponseMsg) {
DEBUG_EXPR(in_msg.Address);
DEBUG_EXPR(id);
DEBUG_EXPR(getState(in_msg.Address));
DEBUG_EXPR(in_msg.SenderMachId);
DEBUG_EXPR(in_msg.Type);
DEBUG_EXPR(in_msg.NumPendingExtAcks);
// test wether it's from a local L1 or an off chip source
assert(in_msg.Destination.isElement(machineID));
if(machineIDToMachineType(in_msg.SenderMachId) == MachineType:L1Cache) {
if(in_msg.Type == CoherenceResponseType:DATA) {
if(L2_TBEs[in_msg.Address].NumPendingIntAcks == 1) {
trigger(Event:Data_int_ack, in_msg.Address); // L1 now has data and all on-chip acks
} else {
DEBUG_EXPR(in_msg.Address);
DEBUG_EXPR(L2_TBEs[in_msg.Address].NumPendingIntAcks);
error("Invalid L1 sent data when L2 wasn't expecting it");
}
} else if(in_msg.Type == CoherenceResponseType:INV_ACK) {
if(L2_TBEs.isPresent(in_msg.Address)) { // FIXME - possible to get a L1 ack after the transaction is completed
if(L2_TBEs[in_msg.Address].NumPendingIntAcks == 1) {
trigger(Event:Proc_last_int_ack, in_msg.Address); // L1 now has all on-chip acks
} else {
trigger(Event:Proc_int_ack, in_msg.Address); // process on-chip ack
}
}
}
} else { // external message
if(in_msg.Type == CoherenceResponseType:DATA) {
if(in_msg.NumPendingExtAcks == 0) {
trigger(Event:Data_ext_ack_0, in_msg.Address); // L2 now has data and all off-chip acks
} else {
if(in_msg.NumPendingExtAcks + L2_TBEs[in_msg.Address].NumPendingExtAcks != 0) {
trigger(Event:Data_ext_ack_not_0, in_msg.Address);
} else {
trigger(Event:Data_ext_ack_not_0_last, in_msg.Address);
}
}
} else if(in_msg.Type == CoherenceResponseType:ACK) {
if(L2_TBEs[in_msg.Address].NumPendingExtAcks != 1){
trigger(Event:Proc_ext_ack, in_msg.Address);
} else {
trigger(Event:Proc_last_ext_ack, in_msg.Address);
}
}
}
}
} // if not ready, do nothing
}
// Forwarded Request from Directory
in_port(forwardedRequestIntraChipL2Network_in, RequestMsg, forwardedRequestToL2Cache) {
if(forwardedRequestIntraChipL2Network_in.isReady()) {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
DEBUG_EXPR(in_msg.Address);
DEBUG_EXPR(id);
DEBUG_EXPR(getState(in_msg.Address));
DEBUG_EXPR(in_msg.RequestorMachId);
DEBUG_EXPR(in_msg.Type);
assert(in_msg.Destination.isElement(machineID));
if(in_msg.Type == CoherenceRequestType:GETS) {
trigger(Event:Forwarded_GETS, in_msg.Address); // L2
} else if(in_msg.Type == CoherenceRequestType:GET_INSTR) {
trigger(Event:Forwarded_GET_INSTR, in_msg.Address); // L2
} else if (in_msg.Type == CoherenceRequestType:GETX) {
trigger(Event:Forwarded_GETX, in_msg.Address); // L2
} else if (in_msg.Type == CoherenceRequestType:INV) {
trigger(Event:L2_INV, in_msg.Address); // L2
} else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
trigger(Event:Dir_WB_ack, in_msg.Address); // L2
} else if (in_msg.Type == CoherenceRequestType:EXE_ACK) {
trigger(Event:Dir_exe_ack, in_msg.Address); // L2
} else {
error("Invalid L2 forwarded request type");
}
}
}
}
// L1 Request
in_port(L1RequestIntraChipL2Network_in, RequestMsg, L1RequestToL2Cache) {
if(L1RequestIntraChipL2Network_in.isReady()) {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
DEBUG_EXPR(in_msg.Address);
DEBUG_EXPR(id);
DEBUG_EXPR(version);
DEBUG_EXPR(getState(in_msg.Address));
DEBUG_EXPR(in_msg.RequestorMachId);
DEBUG_EXPR(in_msg.Type);
DEBUG_EXPR(in_msg.Destination);
assert(machineIDToMachineType(in_msg.RequestorMachId) == MachineType:L1Cache);
assert(in_msg.Destination.isElement(machineID));
if (L2cacheMemory.isTagPresent(in_msg.Address)) {
// The L2 contains the block, so proceeded with handling the request
trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address, in_msg.RequestorMachId), in_msg.Address);
} else {
if (L2cacheMemory.cacheAvail(in_msg.Address)) {
// L2 does't have the line, but we have space for it in the L2
trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address, in_msg.RequestorMachId), in_msg.Address);
} else {
// No room in the L2, so we need to make room before handling the request
trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
}
}
}
}
}
// ACTIONS
action(a_issueGETS, "a", desc="Issue GETS") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:GETS;
out_msg.RequestorMachId := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.MessageSize := MessageSizeType:Control;
out_msg.L1CacheStateStr := in_msg.L1CacheStateStr;
out_msg.L2CacheStateStr := getStateStr(address);
}
}
}
action(b_issueGETX, "b", desc="Issue GETX") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:GETX;
out_msg.RequestorMachId := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.MessageSize := MessageSizeType:Control;
out_msg.L1CacheStateStr := in_msg.L1CacheStateStr;
out_msg.L2CacheStateStr := getStateStr(address);
}
}
}
// finalAck issued from the response queue
action(c_finalAckToDirIfNeeded, "c", desc="Send FinalAck to dir if this is response to 3-hop xfer") {
peek(responseIntraChipL2Network_in, ResponseMsg) {
DEBUG_EXPR(in_msg);
if(machineIDToMachineType(in_msg.SenderMachId) == MachineType:L2Cache) {
enqueue(finalAckIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY"){
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:FINALACK;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.MessageSize := MessageSizeType:Control;
DEBUG_EXPR(out_msg);
}
}
}
}
// finalAck issued from TBE
action(n_sendFinalAckIfThreeHop, "n", desc=""){
peek(responseIntraChipL2Network_in, ResponseMsg){
DEBUG_EXPR(in_msg);
if(L2_TBEs[address].isThreeHop == true){
enqueue(finalAckIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY"){
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:FINALACK;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.MessageSize := MessageSizeType:Control;
DEBUG_EXPR(out_msg);
}
}
}
}
action(mm_rememberIfFinalAckNeeded, "\m", desc=""){
peek(responseIntraChipL2Network_in, ResponseMsg){
if(machineIDToMachineType(in_msg.SenderMachId) == MachineType:L2Cache){
L2_TBEs[address].isThreeHop := true;
}
}
}
action(d_issuePUTX, "d", desc="Issue PUTX") {
enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:PUTX;
out_msg.RequestorMachId := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
DEBUG_EXPR(out_msg.Address);
DEBUG_EXPR(out_msg.Destination);
DEBUG_EXPR(out_msg.DataBlk);
out_msg.MessageSize := MessageSizeType:Data;
out_msg.L1CacheStateStr := "NA";
out_msg.L2CacheStateStr := getStateStr(address);
}
}
action(f_issueGETINSTR, "f", desc="Issue GETINSTR") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:GET_INSTR;
out_msg.RequestorMachId := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.MessageSize := MessageSizeType:Control;
out_msg.L1CacheStateStr := in_msg.L1CacheStateStr;
out_msg.L2CacheStateStr := getStateStr(address);
}
}
}
// DELAYED RESPONSES - Sorced from a TBE entry
// TBE -> L1
action(h_issueLoadHit, "h", desc="If not prefetch, notify sequencer the load completed.") {
DEBUG_EXPR(getL2CacheEntry(address).DataBlk);
if((L2_TBEs.isPresent(address) == false) || (L2_TBEs[address].isPrefetch == false)) {
// Non-prefetch
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination := L2_TBEs[address].L1_GetS_IDs; // could be multiple internal nodes
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
} else {
// Prefetch - don't issue hit msg
}
}
action(oo_issueLoadHitInv, "\o", desc="If not prefetch, notify sequencer the load completed.") {
DEBUG_EXPR(getL2CacheEntry(address).DataBlk);
if((L2_TBEs.isPresent(address) == false) || (L2_TBEs[address].isPrefetch == false)) {
// Non-prefetch
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA_I;
out_msg.SenderMachId := machineID;
out_msg.Destination := L2_TBEs[address].L1_GetS_IDs; // could be multiple internal nodes
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
} else {
// Prefetch - don't issue hit msg
}
}
action(hh_issueStoreHit, "\h", desc="If not prefetch, issue store hit message to local L1 requestor") {
DEBUG_EXPR(getL2CacheEntry(address).DataBlk);
if((L2_TBEs.isPresent(address) == false) || (L2_TBEs[address].isPrefetch == false)) {
// Non-prefetch
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(L2_TBEs[address].L1_GetX_ID); // a single node
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
} else {
// Prefetch - don't issue hit msg
}
}
action(pp_issueStoreHitInv, "\p", desc="If not prefetch, issue store hit message to local L1 requestor") {
DEBUG_EXPR(getL2CacheEntry(address).DataBlk);
if((L2_TBEs.isPresent(address) == false) || (L2_TBEs[address].isPrefetch == false)) {
// Non-prefetch
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA_I;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(L2_TBEs[address].L1_GetX_ID); // a single node
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
} else {
// Prefetch - don't issue hit msg
}
}
action(cc_issueStoreHitDG, "\c", desc="If not prefetch, issue store hit message to local L1 requestor") {
DEBUG_EXPR(getL2CacheEntry(address).DataBlk);
if((L2_TBEs.isPresent(address) == false) || (L2_TBEs[address].isPrefetch == false)) {
// Non-prefetch
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA_S;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(L2_TBEs[address].L1_GetX_ID); // a single node
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
} else {
// Prefetch - don't issue hit msg
}
}
action(w_sendPutAckToL1Cache, "w", desc="send acknowledgement of an L1 replacement") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:ACK;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(in_msg.RequestorMachId); // a single node
DEBUG_EXPR(out_msg.Destination);
out_msg.MessageSize := MessageSizeType:Control;
}
}
}
// TBE -> L1s and L2s
action(ee_dataFromL2CacheToGetSIDs, "\e", desc="Send data from cache to all GetS IDs") {
// FIXME - In some cases this should be from the TBE, not the cache.
// may send to other mod-L2s
if (L2_TBEs[address].Forward_GetS_IDs.count() > 0) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination := L2_TBEs[address].Forward_GetS_IDs; // external nodes
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.NumPendingExtAcks := 0;
DEBUG_EXPR(out_msg.Address);
DEBUG_EXPR(out_msg.Destination);
DEBUG_EXPR(out_msg.DataBlk);
out_msg.MessageSize := MessageSizeType:Data;
}
}
// may send to local L1s
if (L2_TBEs[address].L1_GetS_IDs.count() > 0) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination := L2_TBEs[address].L1_GetS_IDs; // internal nodes
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
}
}
// TBE -> L2s only
action(bb_dataFromL2CacheToGetSForwardIDs, "\b", desc="Send data from cache to GetS ForwardIDs") {
// FIXME - In some cases this should be from the TBE, not the cache.
if ((L2_TBEs[address].Forward_GetS_IDs.count() > 0) || (L2_TBEs[address].L1_GetS_IDs.count() > 0)) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination := L2_TBEs[address].Forward_GetS_IDs; // external nodes
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.NumPendingExtAcks := 0;
out_msg.MessageSize := MessageSizeType:Data;
}
}
}
// TBE -> L2 only
action(gg_dataFromL2CacheToGetXForwardID, "\g", desc="Send data from cache to GetX ForwardID") {
// FIXME - In some cases this should be from the TBE, not the cache.
if (L2_TBEs[address].validForwardedGetXId) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(L2_TBEs[address].Forward_GetX_ID);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.NumPendingExtAcks := L2_TBEs[address].ForwardGetX_AckCount;
DEBUG_EXPR(out_msg.Address);
DEBUG_EXPR(out_msg.Destination);
DEBUG_EXPR(out_msg.DataBlk);
DEBUG_EXPR(out_msg.NumPendingExtAcks);
out_msg.MessageSize := MessageSizeType:Data;
}
}
}
// IMMEDIATE RESPONSES directly from the ForwardRequest queue
// ForwardRequest -> L2
action(e_dataFromL2CacheToL2Requestor, "e", desc="Send data from cache to requestor") {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.NumPendingExtAcks := in_msg.NumPendingExtAcks; // Needed when in state O and we see a GetX
out_msg.Destination.add(in_msg.RequestorMachId);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
DEBUG_EXPR(out_msg.Address);
DEBUG_EXPR(out_msg.Destination);
DEBUG_EXPR(out_msg.DataBlk);
DEBUG_EXPR(out_msg.NumPendingExtAcks);
out_msg.MessageSize := MessageSizeType:Data;
}
}
}
// ForwardRequest -> L1
action(k_dataFromL2CacheToL1Requestor, "k", desc="Send data from cache to L1 requestor") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(in_msg.RequestorMachId);
DEBUG_EXPR(out_msg.Destination);
out_msg.DataBlk := getL2CacheEntry(address).DataBlk;
out_msg.MessageSize := MessageSizeType:Data;
}
}
}
// OTHER ACTIONS
action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") {
check_allocate(L2_TBEs);
L2_TBEs.allocate(address);
L2_TBEs[address].NumPendingIntAcks := 0; // default value
L2_TBEs[address].NumPendingExtAcks := 0; // default value
L2_TBEs[address].isPrefetch := false;
L2_TBEs[address].isThreeHop := false;
L2_TBEs[address].Forward_GetS_IDs.clear();
L2_TBEs[address].L1_GetS_IDs.clear();
L2_TBEs[address].validInvalidator := false;
L2_TBEs[address].validForwardedGetXId := false;
L2_TBEs[address].isInternalRequestOnly := false;
}
action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
L2_TBEs.deallocate(address);
}
action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
profileMsgDelay(0, L1RequestIntraChipL2Network_in.dequeue_getDelayCycles());
}
action(l_popForwardedRequestQueue, "l", desc="Pop incoming forwarded request queue") {
profileMsgDelay(2, forwardedRequestIntraChipL2Network_in.dequeue_getDelayCycles());
}
action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
profileMsgDelay(3, responseIntraChipL2Network_in.dequeue_getDelayCycles());
}
action(p_addNumberOfPendingExtAcks, "p", desc="Add number of pending acks to TBE") {
peek(responseIntraChipL2Network_in, ResponseMsg) {
DEBUG_EXPR(L2_TBEs[address].NumPendingExtAcks);
L2_TBEs[address].NumPendingExtAcks := L2_TBEs[address].NumPendingExtAcks + in_msg.NumPendingExtAcks;
DEBUG_EXPR(in_msg.NumPendingExtAcks);
DEBUG_EXPR(L2_TBEs[address].NumPendingExtAcks);
}
}
action(q_decrementNumberOfPendingExtAcks, "q", desc="Decrement number of pending ext invalidations by one") {
DEBUG_EXPR(L2_TBEs[address].NumPendingExtAcks);
L2_TBEs[address].NumPendingExtAcks := L2_TBEs[address].NumPendingExtAcks - 1;
DEBUG_EXPR(L2_TBEs[address].NumPendingExtAcks);
}
action(r_decrementNumberOfPendingIntAcks, "r", desc="Decrement number of pending int invalidations by one") {
DEBUG_EXPR(L2_TBEs[address].NumPendingExtAcks);
L2_TBEs[address].NumPendingIntAcks := L2_TBEs[address].NumPendingIntAcks - 1;
DEBUG_EXPR(L2_TBEs[address].NumPendingExtAcks);
}
action(t_sendAckToInvalidator, "t", desc="Send ack to invalidator") {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:ACK;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(in_msg.RequestorMachId);
DEBUG_EXPR(out_msg.Destination);
out_msg.NumPendingExtAcks := 0;
out_msg.MessageSize := MessageSizeType:Control;
}
}
}
action(u_writeDataFromResponseQueueToL2Cache, "u", desc="Write data from response queue to cache") {
peek(responseIntraChipL2Network_in, ResponseMsg) {
getL2CacheEntry(address).DataBlk := in_msg.DataBlk;
}
}
// FIXME - probably need to change this to a seperate low priority request queue
action(m_writeDataFromRequestQueueToL2Cache, "m", desc="Write data from response queue to cache") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
getL2CacheEntry(address).DataBlk := in_msg.DataBlk;
}
}
action(x_copyDataFromL2CacheToTBE, "x", desc="Copy data from cache to TBE") {
L2_TBEs[address].DataBlk := getL2CacheEntry(address).DataBlk;
}
action(y_dataFromTBEToRequestor, "y", desc="Send data from TBE to requestor") {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.SenderMachId := machineID;
out_msg.NumPendingExtAcks := in_msg.NumPendingExtAcks;
out_msg.Destination.add(in_msg.RequestorMachId);
out_msg.DataBlk := L2_TBEs[address].DataBlk;
DEBUG_EXPR(out_msg.Address);
DEBUG_EXPR(out_msg.Destination);
DEBUG_EXPR(out_msg.DataBlk);
DEBUG_EXPR(out_msg.NumPendingExtAcks);
out_msg.MessageSize := MessageSizeType:Data;
}
}
}
action(zz_sendAckToQueuedInvalidator, "\z", desc="Send ack to invalidator") {
if (L2_TBEs[address].validInvalidator) {
enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:ACK;
out_msg.SenderMachId := machineID;
out_msg.Destination.add(L2_TBEs[address].InvalidatorID);
DEBUG_EXPR(out_msg.Destination);
out_msg.NumPendingExtAcks := 0;
out_msg.MessageSize := MessageSizeType:Control;
}
}
}
action(z_stall, "z", desc="Stall") {
}
action(yy_recordInvalidatorID, "\y", desc="Record Invalidator for future response") {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
L2_TBEs[address].InvalidatorID := in_msg.RequestorMachId;
L2_TBEs[address].validInvalidator := true;
}
}
action(dd_recordGetSForwardID, "\d", desc="Record forwarded GetS for future forwarding") {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
L2_TBEs[address].Forward_GetS_IDs.add(in_msg.RequestorMachId);
}
}
action(ss_recordGetSL1ID, "\s", desc="Record forwarded L1 GetS for load response") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
L2_TBEs[address].L1_GetS_IDs.add(in_msg.RequestorMachId);
}
}
action(ii_recordGetXForwardID, "\i", desc="Record forwarded GetX and ack count for future forwarding") {
peek(forwardedRequestIntraChipL2Network_in, RequestMsg) {
L2_TBEs[address].Forward_GetX_ID := in_msg.RequestorMachId;
L2_TBEs[address].ForwardGetX_AckCount := in_msg.NumPendingExtAcks;
L2_TBEs[address].validForwardedGetXId := true;
}
}
action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
L2_TBEs[address].L1_GetX_ID := in_msg.RequestorMachId;
}
}
action(set_setMRU, "\set", desc="set the MRU entry") {
L2cacheMemory.setMRU(address);
}
action(bbb_setPendingIntAcksToSharers, "\bb", desc="Set number of pending acks equal to number of sharers") {
L2_TBEs[address].NumPendingIntAcks := L2cacheMemory[address].Sharers.count();
}
action(ddd_setPendingIntAcksToOne, "\dd", desc="Set number of pending acks equal to one") {
L2_TBEs[address].NumPendingIntAcks := 1;
}
action(ccc_setPendingIntAcksMinusOne, "\cc", desc="Set number of pending acks equal to number of sharers minus one") {
L2_TBEs[address].NumPendingIntAcks := L2cacheMemory[address].Sharers.count() - 1;
}
action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
if (L2cacheMemory.isTagPresent(address) == false) {
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(L1RequestIntraChipL2Network_in, RequestMsg) {
//profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, L1CacheMachIDToProcessorNum(in_msg.RequestorMachId));
}
}
action(ww_profileMissNoDir, "\w", desc="Profile this transition at the L2 because Dir won't see the request") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
profile_request(in_msg.L1CacheStateStr, getStateStr(address), "NA", getCoherenceRequestTypeStr(in_msg.Type));
}
}
action(v_issueInvalidateIntL1copyRequest, "v", desc="invalidate the L1 M copy") {
enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:INV;
out_msg.RequestorMachId := machineID;
out_msg.Destination := L2cacheMemory[address].Sharers;
out_msg.MessageSize := MessageSizeType:Control;
}
}
action(tt_issueSharedInvalidateIntL1copiesRequest, "\t", desc="invalidate all L1 S copies") {
enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:INV_S;
out_msg.RequestorMachId := machineID;
out_msg.Destination := L2cacheMemory[address].Sharers;
out_msg.MessageSize := MessageSizeType:Control;
}
}
action(vv_issueInvalidateOtherIntL1copiesRequest, "\v", desc="invalidate other L1 copies not the local requestor") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
if ((L2cacheMemory[address].Sharers.count() > 1) || (L2cacheMemory[address].Sharers.isElement(in_msg.RequestorMachId) != true)) {
enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:INV_S;
out_msg.RequestorMachId := machineID;
out_msg.Destination := L2cacheMemory[address].Sharers;
out_msg.Destination.remove(in_msg.RequestorMachId);
out_msg.MessageSize := MessageSizeType:Control;
}
}
}
}
action(g_issueDownGradeIntL1copiesRequest, "g", desc="DownGrade L1 copy") {
enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency="L2_REQUEST_LATENCY") {
out_msg.Address := address;
out_msg.Type := CoherenceRequestType:L1_DG;
out_msg.RequestorMachId := machineID;
out_msg.Destination := L2cacheMemory[address].Sharers;
out_msg.MessageSize := MessageSizeType:Control;
}
}
action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
addSharer(address, in_msg.RequestorMachId);
}
}
action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
L2cacheMemory[address].Sharers.remove(in_msg.RequestorMachId);
}
}
action(aa_removeResponseSharer, "\a", desc="Remove L1 Response sharer from list") {
peek(responseIntraChipL2Network_in, ResponseMsg) {
L2cacheMemory[address].Sharers.remove(in_msg.SenderMachId);
}
}
action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
peek(L1RequestIntraChipL2Network_in, RequestMsg) {
L2cacheMemory[address].Sharers.clear();
}
}
//*****************************************************
// TRANSITIONS
//*****************************************************
//===============================================
// STALLS
// Stalls L2 Replacement and L1 PUT for all transient states
transition({L2_IS, L2_ISZ, L2_ISI, L2_IMV, L2_MV, L2_IM, L2_IMO, L2_IMI, L2_IMZ, L2_IMOI, L2_IMOZ,
L2_SIV, L2_SIC,
L2_MIV, L2_MIN, L2_MIC, L2_MIT, L2_MO, L2_MOIC, L2_MOICR, L2_MOZ,
L2_OIV, L2_OIN, L2_OIC, L2_OMV, L2_OM},
{L2_Replacement, L1_PUTX, L1_PUTX_last, L1_PUTS, L1_PUTS_last, L1_PUTX_old, L1_PUTS_old, }) {
z_stall;
}
//===============================================
// old L1_PUT requests
transition({L2_NP, L2_I, L2_S, L2_SS, L2_M, L2_MT, L2_O, L2_SO}, {L1_PUTX_old, L1_PUTS_old}) {
w_sendPutAckToL1Cache;
jj_popL1RequestQueue;
}
//===============================================
// BASE STATE - I
// Transitions from I (Idle)
transition({L2_NP,L2_I}, L2_Replacement) {
rr_deallocateL2CacheBlock;
}
transition({L2_NP,L2_I}, L2_INV) { // could see an invalidate from the directory, but not Forwards
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition({L2_NP,L2_I}, L1_GETS, L2_IS) {
qq_allocateL2CacheBlock;
ll_clearSharers;
nn_addSharer;
i_allocateTBE;
ss_recordGetSL1ID;
a_issueGETS;
uu_profileMiss;
jj_popL1RequestQueue;
}
transition({L2_NP,L2_I}, L1_GET_INSTR, L2_IS) {
qq_allocateL2CacheBlock;
ll_clearSharers;
nn_addSharer;
i_allocateTBE;
ss_recordGetSL1ID;
f_issueGETINSTR;
uu_profileMiss;
jj_popL1RequestQueue;
}
transition({L2_NP,L2_I}, {L1_GETX, L1_UPGRADE, L1_UPGRADE_no_others}, L2_IM) { // UPGRADE possible because L2_Replacement have higher priority
qq_allocateL2CacheBlock;
ll_clearSharers;
nn_addSharer;
i_allocateTBE;
xx_recordGetXL1ID;
b_issueGETX;
uu_profileMiss;
jj_popL1RequestQueue;
}
// Transitions from L2_IS
// could see L2_INVs or more L1 requests
transition(L2_IS, L2_INV, L2_ISI) { // could see an invalidate from the directory, but not Forwards
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_IS, Data_ext_ack_0, L2_SS) {
u_writeDataFromResponseQueueToL2Cache;
h_issueLoadHit;
c_finalAckToDirIfNeeded;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_IS, {L1_GETS,L1_GET_INSTR}) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
ss_recordGetSL1ID;
jj_popL1RequestQueue;
}
transition(L2_IS, L1_GETX, L2_ISZ) { // don't go there, just go to stall state
z_stall;
}
// Transitions from L2_ISZ
// could see L2_INVs or more L1 requests
// stall all L1 requests, wait for data
transition(L2_ISZ, L2_INV, L2_ISI) { // could see an invalidate from the directory, but not Forwards
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_ISZ, Data_ext_ack_0, L2_SS) {
u_writeDataFromResponseQueueToL2Cache;
h_issueLoadHit;
c_finalAckToDirIfNeeded;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_ISZ, {L1_GETS, L1_GET_INSTR, L1_GETX}) {
z_stall;
}
// Transitions from L2_ISI, already sent the invalidate ack so can imediately go to I
// - in ISI, could get data from the Proc whose GETX caused INV to go from IS to ISI
// or, could get data from Dir if Dir's data lost race to Dir's INV
// or, could get data from Dir, if my GETS took forever to get to Dir, and the GETX
// processor already wrote it back
transition(L2_ISI, Data_ext_ack_0, L2_I) {
u_writeDataFromResponseQueueToL2Cache;
oo_issueLoadHitInv;
c_finalAckToDirIfNeeded;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_ISI, L2_INV) { // could see an invalidate from the directory, but not Forwards
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_ISI, {L1_GETS, L1_GET_INSTR, L1_GETX}) { // stall all L1 requests
z_stall;
}
// Transitions from L2_IMV, waiting for int_acks
// currently stall all request
// could see forwards and/or more L1 requests
transition(L2_IMV, L2_INV) { // could see an invalidate for SS
yy_recordInvalidatorID;
l_popForwardedRequestQueue;
}
// stall all Forwarded request
transition(L2_IMV, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX}) {
z_stall;
}
// stall all L1 request
transition(L2_IMV, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE, L1_UPGRADE_no_others}) {
z_stall;
}
transition(L2_IMV, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MV) {
u_writeDataFromResponseQueueToL2Cache;
c_finalAckToDirIfNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMV, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMV, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMV, Proc_last_ext_ack, L2_MV) {
n_sendFinalAckIfThreeHop;
o_popIncomingResponseQueue;
}
transition(L2_IMV, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMV, Proc_last_int_ack, L2_IM) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
zz_sendAckToQueuedInvalidator;
}
// Transitions from L2_MV, waiting for int_acks
// external world gave us write permission
// stall all Forwarded request
transition(L2_MV, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX}) {
z_stall;
}
// stall all L1 request
transition(L2_MV, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE, L1_UPGRADE_no_others}) {
z_stall;
}
transition(L2_MV, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
}
transition(L2_MV, Proc_last_int_ack, L2_MT) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
hh_issueStoreHit;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
// Transitions from L2_IM, waiting for external data before going to MT state
// could see forwards and/or more L1 requests
transition(L2_IM, L2_INV) { // could see an invalidate from the directory (earlier epoch)
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_IM, {Forwarded_GETS,Forwarded_GET_INSTR}, L2_IMO) { // could see Forwards, if directory responses get out-of-order
dd_recordGetSForwardID;
l_popForwardedRequestQueue;
}
transition(L2_IM, {L1_GETS,L1_GET_INSTR}, L2_IMO) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
ss_recordGetSL1ID;
jj_popL1RequestQueue;
}
transition(L2_IM, Forwarded_GETX, L2_IMI) { // could see Forwards, if directory requests get ahead of responses
ii_recordGetXForwardID;
l_popForwardedRequestQueue;
}
transition(L2_IM, L1_GETX, L2_IMZ) { // don't go there, just go to stall state
z_stall;
}
transition(L2_IM, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MT) {
u_writeDataFromResponseQueueToL2Cache;
hh_issueStoreHit;
c_finalAckToDirIfNeeded;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_IM, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IM, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IM, Proc_last_ext_ack, L2_MT) {
hh_issueStoreHit;
n_sendFinalAckIfThreeHop;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
// transitions from L2_IMO
transition(L2_IMO, L2_INV) { // could see an invalidate from the directory (earlier epoch)
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_IMO, {Forwarded_GETS,Forwarded_GET_INSTR}) { // could see Forwards
dd_recordGetSForwardID;
l_popForwardedRequestQueue;
}
transition(L2_IMO, Forwarded_GETX, L2_IMOI) { // could see Forwards
ii_recordGetXForwardID;
l_popForwardedRequestQueue;
}
transition(L2_IMO, {L1_GETS,L1_GET_INSTR}) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
ss_recordGetSL1ID;
jj_popL1RequestQueue;
}
transition(L2_IMO, L1_GETX, L2_IMOZ) {
z_stall;
}
transition(L2_IMO, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MO) {
u_writeDataFromResponseQueueToL2Cache;
cc_issueStoreHitDG;
ddd_setPendingIntAcksToOne;
c_finalAckToDirIfNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMO, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMO, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMO, Proc_last_ext_ack, L2_MO) {
n_sendFinalAckIfThreeHop;
cc_issueStoreHitDG;
ddd_setPendingIntAcksToOne;
o_popIncomingResponseQueue;
}
// transitions from L2_IMI
// the directory put us in this state so it should tell us nothing (i.e. don't worry about INV or Forwards)
// stall all L1 request
transition(L2_IMI, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MIC) {
u_writeDataFromResponseQueueToL2Cache;
pp_issueStoreHitInv;
ddd_setPendingIntAcksToOne;
c_finalAckToDirIfNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMI, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMI, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMI, Proc_last_ext_ack, L2_MIC) {
n_sendFinalAckIfThreeHop;
pp_issueStoreHitInv;
ddd_setPendingIntAcksToOne;
o_popIncomingResponseQueue;
}
transition(L2_IMI, {L1_GETS, L1_GET_INSTR, L1_GETX}) { // stall all L1 requests
z_stall;
}
// transistions from L2_IMZ
// just wait for all acks and data
// stall on all requests
// NOTE: A performance option might be possible to go into M state instead of MT
transition(L2_IMZ, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MT) {
u_writeDataFromResponseQueueToL2Cache;
hh_issueStoreHit;
c_finalAckToDirIfNeeded;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_IMZ, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMZ, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMZ, Proc_last_ext_ack, L2_MT) {
hh_issueStoreHit;
n_sendFinalAckIfThreeHop;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_IMZ, L2_INV) { // could see an invalidate from the directory (earlier epoch)
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_IMZ, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX, L1_GETS, L1_GET_INSTR, L1_GETX}) {
z_stall;
}
// transitions from L2_IMOI
// the directory put us in this state so it should tell us nothing (i.e. don't worry about INV or Forwards)
// stall all L1 requests
transition(L2_IMOI, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MOICR) {
u_writeDataFromResponseQueueToL2Cache;
pp_issueStoreHitInv;
ddd_setPendingIntAcksToOne;
c_finalAckToDirIfNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMOI, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMOI, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMOI, Proc_last_ext_ack, L2_MOICR) {
n_sendFinalAckIfThreeHop;
pp_issueStoreHitInv;
ddd_setPendingIntAcksToOne;
o_popIncomingResponseQueue;
}
transition(L2_IMOI, {L1_GETS, L1_GET_INSTR, L1_GETX}) { // stall all L1 requests
z_stall;
}
// transitions from L2_IMOZ
// just wait for all acks and data
// stall on all requests
transition(L2_IMOZ, L2_INV) { // could see an invalidate from the directory (earlier epoch)
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_IMOZ, {Data_ext_ack_0, Data_ext_ack_not_0_last}, L2_MOZ) {
u_writeDataFromResponseQueueToL2Cache;
cc_issueStoreHitDG;
ddd_setPendingIntAcksToOne;
c_finalAckToDirIfNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMOZ, Data_ext_ack_not_0) {
u_writeDataFromResponseQueueToL2Cache;
p_addNumberOfPendingExtAcks;
mm_rememberIfFinalAckNeeded;
o_popIncomingResponseQueue;
}
transition(L2_IMOZ, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_IMOZ, Proc_last_ext_ack, L2_MOZ) {
cc_issueStoreHitDG;
ddd_setPendingIntAcksToOne;
n_sendFinalAckIfThreeHop;
o_popIncomingResponseQueue;
}
// stall on all requests
transition(L2_IMOZ, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX, L1_GETS, L1_GET_INSTR, L1_GETX}) {
z_stall;
}
// ===============================================
// BASE STATE - S
// Transitions from S, no L1 copies
transition(L2_S, L2_Replacement, L2_I) {
rr_deallocateL2CacheBlock;
}
transition(L2_S, L2_INV, L2_I) { // could see an invalidate from the directory, but not Forwards
t_sendAckToInvalidator;
l_popForwardedRequestQueue;
}
transition(L2_S, {L1_GETS, L1_GET_INSTR}, L2_SS) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
k_dataFromL2CacheToL1Requestor;
jj_popL1RequestQueue;
}
transition(L2_S, L1_GETX, L2_IM) {
set_setMRU;
nn_addSharer;
i_allocateTBE;
xx_recordGetXL1ID;
b_issueGETX;
uu_profileMiss;
jj_popL1RequestQueue;
}
// BASE STATE - SS
// Transitions from SS, L1 copies
transition(L2_SS, L2_Replacement, L2_SIV) {
i_allocateTBE; // for internal request
bbb_setPendingIntAcksToSharers;
tt_issueSharedInvalidateIntL1copiesRequest;
}
transition(L2_SS, L2_INV, L2_SIC) {
i_allocateTBE; // for internal request
yy_recordInvalidatorID;
bbb_setPendingIntAcksToSharers;
tt_issueSharedInvalidateIntL1copiesRequest;
l_popForwardedRequestQueue;
}
transition(L2_SS, {L1_GETS, L1_GET_INSTR}) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
k_dataFromL2CacheToL1Requestor;
jj_popL1RequestQueue;
}
transition(L2_SS, L1_UPGRADE_no_others, L2_IM) {
set_setMRU;
i_allocateTBE; // for both ext. and int.
xx_recordGetXL1ID;
b_issueGETX; // for external
uu_profileMiss;
jj_popL1RequestQueue;
}
transition(L2_SS, L1_UPGRADE, L2_IMV) {
set_setMRU;
i_allocateTBE; // for both ext. and int.
xx_recordGetXL1ID;
ccc_setPendingIntAcksMinusOne;
vv_issueInvalidateOtherIntL1copiesRequest; // for internal
b_issueGETX; // for external
uu_profileMiss;
jj_popL1RequestQueue;
}
transition(L2_SS, L1_GETX, L2_IMV) {
set_setMRU;
i_allocateTBE; // for both ext. and int.
xx_recordGetXL1ID;
bbb_setPendingIntAcksToSharers;
vv_issueInvalidateOtherIntL1copiesRequest; // for internal
nn_addSharer;
b_issueGETX; // for external
uu_profileMiss;
jj_popL1RequestQueue;
}
transition(L2_SS, L1_PUTS) {
ww_profileMissNoDir;
w_sendPutAckToL1Cache;
kk_removeRequestSharer;
jj_popL1RequestQueue;
}
transition(L2_SS, L1_PUTS_last, L2_S) {
ww_profileMissNoDir;
w_sendPutAckToL1Cache;
kk_removeRequestSharer;
jj_popL1RequestQueue;
}
// Transitions from SIC - Initiated by an invalidate
transition(L2_SIC, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
}
transition(L2_SIC, Proc_last_int_ack, L2_I) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
zz_sendAckToQueuedInvalidator;
s_deallocateTBE;
}
transition(L2_SIC, L2_INV) { // could see an invalidate from the directory, but not Forwards
l_popForwardedRequestQueue; // ignore: already know an ack must be sent to the directory
}
transition(L2_SIC, {L1_GETS, L1_GET_INSTR, L1_UPGRADE, L1_UPGRADE_no_others, L1_GETX}) { // stall on all L1 requests
z_stall;
}
// Transitions from SIV - initiated by a L2_Replacement
transition(L2_SIV, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
}
transition(L2_SIV, Proc_last_int_ack, L2_I) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
s_deallocateTBE;
rr_deallocateL2CacheBlock;
}
transition(L2_SIV, L2_INV) { // could see an invalidate from the directory, but not Forwards
z_stall; // guarenteed to receive all acks thus moving the state to I where the L2_INV can be handled
}
transition(L2_SIV, {L1_GETS, L1_GET_INSTR, L1_UPGRADE, L1_UPGRADE_no_others, L1_GETX}) { // stall on all L1 requests
z_stall;
}
// ===============================================
// BASE STATE - M
// Transitions from M, no L1 copies
transition(L2_M, L2_Replacement, L2_MIN) {
i_allocateTBE;
d_issuePUTX;
x_copyDataFromL2CacheToTBE;
rr_deallocateL2CacheBlock;
}
transition(L2_M, {Forwarded_GETS,Forwarded_GET_INSTR}, L2_O) { // can see forwards, not inv
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_M, Forwarded_GETX, L2_I) { // can see forwards, not inv
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_M, {L1_GETS, L1_GET_INSTR}, L2_SO) { // FIXME FOR BETTER PERFORMANCE - an E state would be nice here
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
k_dataFromL2CacheToL1Requestor;
jj_popL1RequestQueue;
}
transition(L2_M, L1_GETX, L2_MT) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
k_dataFromL2CacheToL1Requestor;
jj_popL1RequestQueue;
}
// BASE STATE - MT
// Transitions from MT, M L1 copy
transition(L2_MT, L2_Replacement, L2_MIV) {
i_allocateTBE;
bbb_setPendingIntAcksToSharers;
v_issueInvalidateIntL1copyRequest;
}
transition(L2_MT, {Forwarded_GETS, Forwarded_GET_INSTR}, L2_MO) { // can see forwards, not inv
i_allocateTBE;
bbb_setPendingIntAcksToSharers;
g_issueDownGradeIntL1copiesRequest;
dd_recordGetSForwardID;
l_popForwardedRequestQueue;
}
transition(L2_MT, {L1_GETS, L1_GET_INSTR}, L2_MO) {
set_setMRU;
ww_profileMissNoDir;
i_allocateTBE;
bbb_setPendingIntAcksToSharers;
g_issueDownGradeIntL1copiesRequest;
ss_recordGetSL1ID;
nn_addSharer;
jj_popL1RequestQueue;
}
transition(L2_MT, Forwarded_GETX, L2_MIC) { // can see forwards, not inv
i_allocateTBE;
bbb_setPendingIntAcksToSharers;
v_issueInvalidateIntL1copyRequest;
ii_recordGetXForwardID;
l_popForwardedRequestQueue;
}
transition(L2_MT, L1_GETX, L2_MIT) {
set_setMRU;
ww_profileMissNoDir;
i_allocateTBE;
bbb_setPendingIntAcksToSharers;
v_issueInvalidateIntL1copyRequest;
nn_addSharer;
xx_recordGetXL1ID;
jj_popL1RequestQueue;
}
transition(L2_MT, L1_PUTX_last, L2_M) {
ww_profileMissNoDir;
w_sendPutAckToL1Cache;
kk_removeRequestSharer;
m_writeDataFromRequestQueueToL2Cache;
jj_popL1RequestQueue;
}
// Transitions from L2_MIV, waiting for local L1 response
transition(L2_MIV, Data_int_ack, L2_MIN) {
aa_removeResponseSharer;
u_writeDataFromResponseQueueToL2Cache;
bb_dataFromL2CacheToGetSForwardIDs; // likely won't send any messages
gg_dataFromL2CacheToGetXForwardID; // likely won't send any messages
d_issuePUTX;
x_copyDataFromL2CacheToTBE;
rr_deallocateL2CacheBlock;
o_popIncomingResponseQueue;
}
transition(L2_MIV, {Forwarded_GETS,Forwarded_GET_INSTR}) { // could see Forwards
dd_recordGetSForwardID;
l_popForwardedRequestQueue;
}
transition(L2_MIV, Forwarded_GETX) { // could see Forwards
ii_recordGetXForwardID;
l_popForwardedRequestQueue;
}
transition(L2_MIV, {L1_GETS, L1_GET_INSTR, L1_GETX}) { // stall on all L1 requests
z_stall;
}
// Transitions from L2_MIN, waiting for directory ack
transition(L2_MIN, {Forwarded_GETS,Forwarded_GET_INSTR}) { // could see Forwards
y_dataFromTBEToRequestor;
l_popForwardedRequestQueue;
}
transition(L2_MIN, Forwarded_GETX) { // could see Forwards
y_dataFromTBEToRequestor;
l_popForwardedRequestQueue;
}
transition(L2_MIN, Dir_WB_ack, L2_I) {
s_deallocateTBE;
l_popForwardedRequestQueue;
}
transition(L2_MIN, {L1_GETS, L1_GET_INSTR, L1_GETX}) { // stall all L1 requests
z_stall;
}
// Transitions from L2_MIC, waiting for local L1 response
// Directory put us in this state with a forwarded GetX
// therefore we shouldn't see anymore forwards
// we stall on all L1 requests
transition(L2_MIC, Data_int_ack, L2_I) {
aa_removeResponseSharer;
u_writeDataFromResponseQueueToL2Cache;
gg_dataFromL2CacheToGetXForwardID;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_MIC, {L1_GETS, L1_GET_INSTR, L1_GETX}) { // stall all L1 requests
z_stall;
}
// Transitions from L2_MIT, waiting for local L1 response
// A local L1 request put us in this state, so any request are possible
// we currently stall all requests because of the ugly recursive path it could lead us on
// removing some of the blocking here could have major performance benefits
// however one must be careful not to violate cache coherence
transition(L2_MIT, Data_int_ack, L2_MT) {
aa_removeResponseSharer;
u_writeDataFromResponseQueueToL2Cache;
hh_issueStoreHit; // internal requestor
s_deallocateTBE;
o_popIncomingResponseQueue;
}
// stall all requests
transition(L2_MIT, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX, L1_GETS, L1_GET_INSTR, L1_GETX}) {
z_stall;
}
// Transistion from L2_MO, waiting for local L1 data response
// a GetS request put us in this state
// stall must stall if we get a GETX request
transition(L2_MO, Data_int_ack, L2_SO) {
u_writeDataFromResponseQueueToL2Cache;
ee_dataFromL2CacheToGetSIDs; // could be an internal or external requestor
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_MO, {Forwarded_GETS, Forwarded_GET_INSTR}) { // can see forwards, not inv
dd_recordGetSForwardID;
l_popForwardedRequestQueue;
}
transition(L2_MO, {L1_GETS, L1_GET_INSTR}) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
ss_recordGetSL1ID;
jj_popL1RequestQueue;
}
transition(L2_MO, Forwarded_GETX, L2_MOIC) { // can see forwards, not inv
ii_recordGetXForwardID;
l_popForwardedRequestQueue;
}
transition(L2_MO, {L1_GETX, L1_UPGRADE, L1_UPGRADE_no_others}, L2_MOZ) { // don't go there, just go to a stall state
z_stall;
}
// Transistion from L2_MOIC
// a Forwarded_GETX put us here so we should not see any more forwards
// stall on all L1 requests, once data is received send new data to all queued up L1 shares
// then immediately send invalidate request to those new L1 shared copies
//
// KEY DIFFERENCE: L2_MOICR assumes the L1 data responder moved to I state and removes the sharer,
// while L2_MOIC assumes the L1 data responder moved to S state and doesn't remove the sharer
transition(L2_MOIC, Data_int_ack, L2_OIC) { // need only one ack
u_writeDataFromResponseQueueToL2Cache;
ee_dataFromL2CacheToGetSIDs;
bbb_setPendingIntAcksToSharers;
tt_issueSharedInvalidateIntL1copiesRequest;
o_popIncomingResponseQueue;
}
transition(L2_MOIC, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE, L1_UPGRADE_no_others}) {
z_stall;
}
// Transistion from L2_MOICR
// a Forwarded_GETX put us here so we should not see any more forwards
// stall on all L1 requests, once data is received send new data to all queued up L1 shares
// then immediately send invalidate request to those new L1 shared copies
//
// KEY DIFFERENCE: L2_MOICR assumes the L1 data responder moved to I state and removes the sharer,
// while L2_MOIC assumes the L1 data responder moved to S state and doesn't remove the sharer
transition(L2_MOICR, Data_int_ack, L2_OIC) { // need only one ack
aa_removeResponseSharer;
u_writeDataFromResponseQueueToL2Cache;
ee_dataFromL2CacheToGetSIDs;
bbb_setPendingIntAcksToSharers;
tt_issueSharedInvalidateIntL1copiesRequest;
o_popIncomingResponseQueue;
}
transition(L2_MOICR, {L1_GETS, L1_GET_INSTR, L1_GETX}) {
z_stall;
}
// L2_MOZ
// simply wait on data
// stall on everything
transition(L2_MOZ, Data_int_ack, L2_SO) {
u_writeDataFromResponseQueueToL2Cache;
ee_dataFromL2CacheToGetSIDs; // could be an internal or external requestor
s_deallocateTBE;
o_popIncomingResponseQueue;
}
// stall everything
transition(L2_MOZ, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX, L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE, L1_UPGRADE_no_others}) {
z_stall;
}
// ===============================================
// BASE STATE - O
// Transitions from L2_O, only block cached on the chip
transition(L2_O, L2_Replacement, L2_OIN){
i_allocateTBE;
x_copyDataFromL2CacheToTBE;
d_issuePUTX;
rr_deallocateL2CacheBlock;
}
transition(L2_O, {Forwarded_GETS,Forwarded_GET_INSTR}) {
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_O, Forwarded_GETX, L2_I) {
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_O, {L1_GETS, L1_GET_INSTR}, L2_SO) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
k_dataFromL2CacheToL1Requestor;
jj_popL1RequestQueue;
}
transition(L2_O, L1_GETX, L2_OM) {
set_setMRU;
nn_addSharer;
i_allocateTBE;
xx_recordGetXL1ID;
b_issueGETX;
uu_profileMiss;
jj_popL1RequestQueue;
}
// BASE STATE - SO
// Transitions from L2_SO, other valid L1 cached copies
transition(L2_SO, L2_Replacement, L2_OIV){
i_allocateTBE;
x_copyDataFromL2CacheToTBE;
bbb_setPendingIntAcksToSharers;
tt_issueSharedInvalidateIntL1copiesRequest;
}
transition(L2_SO, {Forwarded_GETS,Forwarded_GET_INSTR}) {
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_SO, Forwarded_GETX, L2_OIC) {
i_allocateTBE;
bbb_setPendingIntAcksToSharers;
ii_recordGetXForwardID;
tt_issueSharedInvalidateIntL1copiesRequest;
l_popForwardedRequestQueue;
}
transition(L2_SO, {L1_GETS, L1_GET_INSTR}) {
set_setMRU;
ww_profileMissNoDir;
nn_addSharer;
k_dataFromL2CacheToL1Requestor;
jj_popL1RequestQueue;
}
transition(L2_SO, L1_UPGRADE, L2_OMV) {
set_setMRU;
nn_addSharer;
i_allocateTBE;
xx_recordGetXL1ID;
ccc_setPendingIntAcksMinusOne;
vv_issueInvalidateOtherIntL1copiesRequest; // for internal
b_issueGETX; // for external
uu_profileMiss;
jj_popL1RequestQueue;
}
transition(L2_SO, L1_UPGRADE_no_others, L2_OM) {
set_setMRU;
i_allocateTBE;
xx_recordGetXL1ID;
b_issueGETX; // for external
uu_profileMiss;
jj_popL1RequestQueue;
}
transition(L2_SO, L1_GETX, L2_OMV) {
set_setMRU;
i_allocateTBE;
xx_recordGetXL1ID;
bbb_setPendingIntAcksToSharers;
vv_issueInvalidateOtherIntL1copiesRequest;
nn_addSharer;
b_issueGETX; // for external
uu_profileMiss;
jj_popL1RequestQueue;
}
transition(L2_SO, {L1_PUTS, L1_PUTX}) { // PUTX possible because L2 downgraded before seeing PUTX
ww_profileMissNoDir;
w_sendPutAckToL1Cache;
kk_removeRequestSharer;
jj_popL1RequestQueue;
}
transition(L2_SO, {L1_PUTS_last, L1_PUTX_last}, L2_O) { // PUTX possible because L2 downgraded before seeing PUTX
ww_profileMissNoDir;
w_sendPutAckToL1Cache;
kk_removeRequestSharer;
jj_popL1RequestQueue;
}
// Transitions from L2_OIV
// L2 replacement put us here, we must stall all L1 requests
transition(L2_OIV, {Forwarded_GETS, Forwarded_GET_INSTR}) {
y_dataFromTBEToRequestor;
l_popForwardedRequestQueue;
}
transition(L2_OIV, Forwarded_GETX) {
z_stall;
}
transition(L2_OIV, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks
o_popIncomingResponseQueue;
}
transition(L2_OIV, Proc_last_int_ack, L2_OIN) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks
o_popIncomingResponseQueue;
d_issuePUTX;
rr_deallocateL2CacheBlock;
}
transition(L2_OIV, {L1_UPGRADE, L1_UPGRADE_no_others, L1_GETX, L1_GETS, L1_GET_INSTR}) { // stall L1 requests
z_stall;
}
// transitions from L2_OIN
// L2 replacement put us here, we must stall all L1 requests
transition(L2_OIN, {Forwarded_GETS, Forwarded_GET_INSTR, Forwarded_GETX}) {
y_dataFromTBEToRequestor;
l_popForwardedRequestQueue;
}
transition(L2_OIN, Dir_WB_ack, L2_I) {
s_deallocateTBE;
l_popForwardedRequestQueue;
}
transition(L2_OIN, {L1_UPGRADE, L1_UPGRADE_no_others, L1_GETX, L1_GETS, L1_GET_INSTR}) { // stall L1 requests
z_stall;
}
// transitions from L2_OIC
// directory put us in this state, should not see any forwards
// we must stall all L1 requests
transition(L2_OIC, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks
o_popIncomingResponseQueue;
}
transition(L2_OIC, Proc_last_int_ack, L2_I) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks
gg_dataFromL2CacheToGetXForwardID;
s_deallocateTBE;
o_popIncomingResponseQueue;
}
transition(L2_OIC, {L1_UPGRADE, L1_UPGRADE_no_others, L1_GETX, L1_GETS, L1_GET_INSTR}) { // stall L1 requests
z_stall;
}
// Transitions from L2_OMV,
// int_acks needed
// waiting to see our Forwarded GETX from the directory
// if we see the Forwarded GETX before all invalidates received, stall
// stall all L1 requests
transition(L2_OMV, Proc_int_ack) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
}
transition(L2_OMV, Proc_last_int_ack, L2_OM) {
aa_removeResponseSharer;
r_decrementNumberOfPendingIntAcks;
o_popIncomingResponseQueue;
}
transition(L2_OMV, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_OMV, {Forwarded_GETS, Forwarded_GET_INSTR}) { // these are GetS that beat us to the directory
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_OMV, Dir_exe_ack, L2_MV) {
l_popForwardedRequestQueue;
}
transition(L2_OMV, Forwarded_GETX) { // the Forwarded GetX may or may not be ours, we can't respond until int_acks received
z_stall;
}
transition(L2_OMV, {L1_UPGRADE, L1_UPGRADE_no_others, L1_GETS, L1_GET_INSTR, L1_GETX}) { // must stall all L1 requests
z_stall;
}
// Transitions from L2_OM,
// all L1 copies invalid, no int_acks needed
// waiting to see our Forwarded GETX from the directory
// once we see the Forwarded GETX, we can move to IM and wait for the data_ack
// stall all L1 requests
transition(L2_OM, Proc_ext_ack) {
q_decrementNumberOfPendingExtAcks;
o_popIncomingResponseQueue;
}
transition(L2_OM, {Forwarded_GETS, Forwarded_GET_INSTR}) { // these are GetS that beat us to the directory
e_dataFromL2CacheToL2Requestor;
l_popForwardedRequestQueue;
}
transition(L2_OM, Forwarded_GETX, L2_IM) { // the Forwarded GetX may or may not be ours
e_dataFromL2CacheToL2Requestor; // we're probably sending a message to ourselves here, but not guarenteed
l_popForwardedRequestQueue;
}
transition(L2_OM, Dir_exe_ack, L2_MT) { // Directory tells us we already have an exclusive copy
hh_issueStoreHit;
s_deallocateTBE;
l_popForwardedRequestQueue;
}
transition(L2_OM, {L1_UPGRADE, L1_UPGRADE_no_others, L1_GETS, L1_GET_INSTR, L1_GETX}) { // must stall all L1 requests
z_stall;
}
}