diff options
author | Nathan Binkert <nate@binkert.org> | 2009-05-11 10:38:43 -0700 |
---|---|---|
committer | Nathan Binkert <nate@binkert.org> | 2009-05-11 10:38:43 -0700 |
commit | 2f30950143cc70bc42a3c8a4111d7cf8198ec881 (patch) | |
tree | 708f6c22edb3c6feb31dd82866c26623a5329580 /src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm | |
parent | c70241810d4e4f523f173c1646b008dc40faad8e (diff) | |
download | gem5-2f30950143cc70bc42a3c8a4111d7cf8198ec881.tar.xz |
ruby: Import ruby and slicc from GEMS
We eventually plan to replace the m5 cache hierarchy with the GEMS
hierarchy, but for now we will make both live alongside eachother.
Diffstat (limited to 'src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm')
-rw-r--r-- | src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm | 2191 |
1 files changed, 2191 insertions, 0 deletions
diff --git a/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm b/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm new file mode 100644 index 000000000..d68efc819 --- /dev/null +++ b/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm @@ -0,0 +1,2191 @@ + +/* + * 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; + } + +} |