blob: faea79fec24df58856cd3badc8df42503ef78884 [file] [log] [blame]
/*
* Copyright (c) 2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 1999-2013 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.
*/
machine(MachineType:L2Cache, "Token protocol")
: CacheMemory * L2cache;
Cycles response_latency := 1;
Cycles request_latency := 1;
// L2 BANK QUEUES
// From local bank of L2 cache TO the network
MessageBuffer * L1RequestFromL2Cache, network="To", virtual_network="0",
vnet_type="request"; // this L2 bank -> a local L1
MessageBuffer * GlobalRequestFromL2Cache, network="To", virtual_network="1",
vnet_type="request"; // this L2 bank -> mod-directory
MessageBuffer * responseFromL2Cache, network="To", virtual_network="2",
vnet_type="response"; // this L2 bank -> a local L1 || mod-directory
// FROM the network to this local bank of L2 cache
MessageBuffer * L1RequestToL2Cache, network="From", virtual_network="0",
vnet_type="request"; // a local L1 -> this L2 bank, Lets try this???
MessageBuffer * GlobalRequestToL2Cache, network="From", virtual_network="1",
vnet_type="request"; // mod-directory -> this L2 bank
MessageBuffer * responseToL2Cache, network="From", virtual_network="2",
vnet_type="response"; // a local L1 || mod-directory -> this L2 bank
MessageBuffer * triggerQueue;
{
// STATES
state_declaration(State, desc="L2 Cache states", default="L2Cache_State_I") {
// Stable states
NP, AccessPermission:Invalid, desc="Not Present";
I, AccessPermission:Invalid, desc="Invalid";
ILS, AccessPermission:Invalid, desc="Idle/NP, but local sharers exist";
ILX, AccessPermission:Invalid, desc="Idle/NP, but local exclusive exists";
ILO, AccessPermission:Invalid, desc="Idle/NP, but local owner exists";
ILOX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and chip is exclusive";
ILOS, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and local sharers as well";
ILOSX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists, local sharers exist, chip is exclusive ";
S, AccessPermission:Read_Only, desc="Shared, no local sharers";
O, AccessPermission:Read_Only, desc="Owned, no local sharers";
OLS, AccessPermission:Read_Only, desc="Owned with local sharers";
OLSX, AccessPermission:Read_Only, desc="Owned with local sharers, chip is exclusive";
SLS, AccessPermission:Read_Only, desc="Shared with local sharers";
M, AccessPermission:Read_Write, desc="Modified";
// Transient States
IFGX, AccessPermission:Busy, desc="Blocked, forwarded global GETX to local owner/exclusive. No other on-chip invs needed";
IFGS, AccessPermission:Busy, desc="Blocked, forwarded global GETS to local owner";
ISFGS, AccessPermission:Busy, desc="Blocked, forwarded global GETS to local owner, local sharers exist";
IFGXX, AccessPermission:Busy, desc="Blocked, forwarded global GETX to local owner but may need acks from other sharers";
OLSF, AccessPermission:Busy, desc="Blocked, got Fwd_GETX with local sharers, waiting for local inv acks";
// writebacks
ILOW, AccessPermission:Busy, desc="local WB request, was ILO";
ILOXW, AccessPermission:Busy, desc="local WB request, was ILOX";
ILOSW, AccessPermission:Busy, desc="local WB request, was ILOS";
ILOSXW, AccessPermission:Busy, desc="local WB request, was ILOSX";
SLSW, AccessPermission:Busy, desc="local WB request, was SLS";
OLSW, AccessPermission:Busy, desc="local WB request, was OLS";
ILSW, AccessPermission:Busy, desc="local WB request, was ILS";
IW, AccessPermission:Busy, desc="local WB request from only sharer, was ILS";
OW, AccessPermission:Busy, desc="local WB request from only sharer, was OLS";
SW, AccessPermission:Busy, desc="local WB request from only sharer, was SLS";
OXW, AccessPermission:Busy, desc="local WB request from only sharer, was OLSX";
OLSXW, AccessPermission:Busy, desc="local WB request from sharer, was OLSX";
ILXW, AccessPermission:Busy, desc="local WB request, was ILX";
IFLS, AccessPermission:Busy, desc="Blocked, forwarded local GETS to _some_ local sharer";
IFLO, AccessPermission:Busy, desc="Blocked, forwarded local GETS to local owner";
IFLOX, AccessPermission:Busy, desc="Blocked, forwarded local GETS to local owner but chip is exclusive";
IFLOXX, AccessPermission:Busy, desc="Blocked, forwarded local GETX to local owner/exclusive, chip is exclusive";
IFLOSX, AccessPermission:Busy, desc="Blocked, forwarded local GETS to local owner w/ other sharers, chip is exclusive";
IFLXO, AccessPermission:Busy, desc="Blocked, forwarded local GETX to local owner with other sharers, chip is exclusive";
IGS, AccessPermission:Busy, desc="Semi-blocked, issued local GETS to directory";
IGM, AccessPermission:Busy, desc="Blocked, issued local GETX to directory. Need global acks and data";
IGMLS, AccessPermission:Busy, desc="Blocked, issued local GETX to directory but may need to INV local sharers";
IGMO, AccessPermission:Busy, desc="Blocked, have data for local GETX but need all acks";
IGMIO, AccessPermission:Busy, desc="Blocked, issued local GETX, local owner with possible local sharer, may need to INV";
OGMIO, AccessPermission:Busy, desc="Blocked, issued local GETX, was owner, may need to INV";
IGMIOF, AccessPermission:Busy, desc="Blocked, issued local GETX, local owner, waiting for global acks, got Fwd_GETX";
IGMIOFS, AccessPermission:Busy, desc="Blocked, issued local GETX, local owner, waiting for global acks, got Fwd_GETS";
OGMIOF, AccessPermission:Busy, desc="Blocked, issued local GETX, was owner, waiting for global acks, got Fwd_GETX";
II, AccessPermission:Busy, desc="Blocked, handling invalidations";
MM, AccessPermission:Busy, desc="Blocked, was M satisfying local GETX";
SS, AccessPermission:Busy, desc="Blocked, was S satisfying local GETS";
OO, AccessPermission:Busy, desc="Blocked, was O satisfying local GETS";
OLSS, AccessPermission:Busy, desc="Blocked, satisfying local GETS";
OLSXS, AccessPermission:Busy, desc="Blocked, satisfying local GETS";
SLSS, AccessPermission:Busy, desc="Blocked, satisfying local GETS";
OI, AccessPermission:Busy, desc="Blocked, doing writeback, was O";
MI, AccessPermission:Busy, desc="Blocked, doing writeback, was M";
MII, AccessPermission:Busy, desc="Blocked, doing writeback, was M, got Fwd_GETX";
OLSI, AccessPermission:Busy, desc="Blocked, doing writeback, was OLS";
ILSI, AccessPermission:Busy, desc="Blocked, doing writeback, was OLS got Fwd_GETX";
// DMA blocking states
ILOSD, AccessPermission:Busy, desc="Blocked, waiting for DMA ack";
ILOSXD, AccessPermission:Busy, desc="Blocked, waiting for DMA ack";
ILOD, AccessPermission:Busy, desc="Blocked, waiting for DMA ack";
ILXD, AccessPermission:Busy, desc="Blocked, waiting for DMA ack";
ILOXD, AccessPermission:Busy, desc="Blocked, waiting for DMA ack";
}
// EVENTS
enumeration(Event, desc="Cache events") {
// Requests
L1_GETS, desc="local L1 GETS request";
L1_GETX, desc="local L1 GETX request";
L1_PUTO, desc="local owner wants to writeback";
L1_PUTX, desc="local exclusive wants to writeback";
L1_PUTS_only, desc="only local sharer wants to writeback";
L1_PUTS, desc="local sharer wants to writeback";
Fwd_GETX, desc="A GetX from another processor";
Fwd_GETS, desc="A GetS from another processor";
Fwd_DMA, desc="A request from DMA";
Own_GETX, desc="A GetX from this node";
Inv, desc="Invalidations from the directory";
// Responses
IntAck, desc="Received an ack message";
ExtAck, desc="Received an ack message";
All_Acks, desc="Received all ack messages";
Data, desc="Received a data message, responder has a shared copy";
Data_Exclusive, desc="Received a data message";
L1_WBCLEANDATA, desc="Writeback from L1, with data";
L1_WBDIRTYDATA, desc="Writeback from L1, with data";
Writeback_Ack, desc="Writeback O.K. from directory";
Writeback_Nack, desc="Writeback not O.K. from directory";
Unblock, desc="Local L1 is telling L2 dir to unblock";
Exclusive_Unblock, desc="Local L1 is telling L2 dir to unblock";
DmaAck, desc="DMA ack from local L1";
// events initiated by this L2
L2_Replacement, desc="L2 Replacement", format="!r";
}
// TYPES
// CacheEntry
structure(Entry, desc="...", interface="AbstractCacheEntry") {
State CacheState, desc="cache state";
NetDest Sharers, desc="Set of the internal processors that want the block in shared state";
MachineID Owner, desc="ID of the L1 cache to forward the block to once we get a response";
bool OwnerValid, default="false", desc="true if Owner means something";
bool Dirty, desc="Is the data dirty (different than memory)?";
DataBlock DataBlk, desc="data for the block";
}
structure(DirEntry, desc="...", interface="AbstractEntry") {
NetDest Sharers, desc="Set of the internal processors that want the block in shared state";
MachineID Owner, desc="ID of the L1 cache to forward the block to once we get a response";
bool OwnerValid, default="false", desc="true if Owner means something";
State DirState, desc="directory state";
}
// TBE fields
structure(TBE, desc="...") {
Addr addr, desc="Physical address for this TBE";
State TBEState, desc="Transient state";
Addr PC, desc="Program counter of request";
DataBlock DataBlk, desc="Buffer for the data block";
bool Dirty, desc="Is the data dirty (different than memory)?";
int NumExtPendingAcks, default="0", desc="Number of global acks/data messages waiting for";
int NumIntPendingAcks, default="0", desc="Number of global acks/data messages waiting for";
int Fwd_GETX_ExtAcks, default="0", desc="Number of acks that requestor will need";
int Local_GETX_IntAcks, default="0", desc="Number of acks that requestor will need";
NetDest L1_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
MachineID L1_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
NetDest Fwd_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
MachineID Fwd_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
}
structure(TBETable, external = "yes") {
TBE lookup(Addr);
void allocate(Addr);
void deallocate(Addr);
bool isPresent(Addr);
}
structure(PerfectCacheMemory, external = "yes") {
void allocate(Addr);
void deallocate(Addr);
DirEntry lookup(Addr);
bool isTagPresent(Addr);
}
TBETable TBEs, template="<L2Cache_TBE>", constructor="m_number_of_TBEs";
PerfectCacheMemory localDirectory, template="<L2Cache_DirEntry>";
Tick clockEdge();
Tick cyclesToTicks(Cycles c);
void set_cache_entry(AbstractCacheEntry b);
void unset_cache_entry();
void set_tbe(TBE b);
void unset_tbe();
MachineID mapAddressToMachine(Addr addr, MachineType mtype);
void wakeUpAllBuffers(Addr a);
// Latency for responses that fetch data from cache
Cycles cacheResponseLatency() {
if (L2cache.getTagLatency() > response_latency) {
return L2cache.getTagLatency();
}
else {
return response_latency;
}
}
Entry getCacheEntry(Addr address), return_by_pointer="yes" {
return static_cast(Entry, "pointer", L2cache[address]);
}
bool isDirTagPresent(Addr addr) {
return (localDirectory.isTagPresent(addr) );
}
DirEntry getDirEntry(Addr address), return_by_pointer="yes" {
return localDirectory.lookup(address);
}
bool isOnlySharer(Entry cache_entry, Addr addr, MachineID shar_id) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
if (cache_entry.Sharers.count() > 1) {
return false;
}
else if (cache_entry.Sharers.count() == 1) {
if (cache_entry.Sharers.isElement(shar_id)) {
return true;
}
else {
return false; // something happened which should cause this PUTS to be nacked
}
return true;
}
else {
return false;
}
}
else if (localDirectory.isTagPresent(addr)){
DirEntry dir_entry := getDirEntry(addr);
if (dir_entry.Sharers.count() > 1) {
return false;
}
else if (dir_entry.Sharers.count() == 1) {
if (dir_entry.Sharers.isElement(shar_id)) {
return true;
}
else {
return false; // something happened which should cause this PUTS to be nacked
}
}
else {
return false;
}
}
else {
// shouldn't happen unless L1 issues PUTS before unblock received
return false;
}
}
void copyCacheStateToDir(Entry cache_entry, Addr addr) {
assert(localDirectory.isTagPresent(addr) == false);
assert(is_valid(cache_entry));
localDirectory.allocate(addr);
DirEntry dir_entry := getDirEntry(addr);
dir_entry.DirState := cache_entry.CacheState;
dir_entry.Sharers := cache_entry.Sharers;
dir_entry.Owner := cache_entry.Owner;
dir_entry.OwnerValid := cache_entry.OwnerValid;
}
void copyDirToCache(Entry cache_entry, Addr addr) {
assert(is_valid(cache_entry));
DirEntry dir_entry := getDirEntry(addr);
cache_entry.Sharers := dir_entry.Sharers;
cache_entry.Owner := dir_entry.Owner;
cache_entry.OwnerValid := dir_entry.OwnerValid;
}
void recordLocalSharerInDir(Entry cache_entry, Addr addr, MachineID shar_id) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
cache_entry.Sharers.add(shar_id);
}
else {
if (localDirectory.isTagPresent(addr) == false) {
localDirectory.allocate(addr);
DirEntry dir_entry := getDirEntry(addr);
dir_entry.Sharers.clear();
dir_entry.OwnerValid := false;
}
DirEntry dir_entry := getDirEntry(addr);
dir_entry.Sharers.add(shar_id);
}
}
void recordNewLocalExclusiveInDir(Entry cache_entry, Addr addr, MachineID exc_id) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
cache_entry.Sharers.clear();
cache_entry.OwnerValid := true;
cache_entry.Owner := exc_id;
}
else {
if (localDirectory.isTagPresent(addr) == false) {
localDirectory.allocate(addr);
}
DirEntry dir_entry := getDirEntry(addr);
dir_entry.Sharers.clear();
dir_entry.OwnerValid := true;
dir_entry.Owner := exc_id;
}
}
void removeAllLocalSharersFromDir(Entry cache_entry, Addr addr) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
cache_entry.Sharers.clear();
cache_entry.OwnerValid := false;
}
else {
DirEntry dir_entry := getDirEntry(addr);
dir_entry.Sharers.clear();
dir_entry.OwnerValid := false;
}
}
void removeSharerFromDir(Entry cache_entry, Addr addr, MachineID sender) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
cache_entry.Sharers.remove(sender);
}
else {
DirEntry dir_entry := getDirEntry(addr);
dir_entry.Sharers.remove(sender);
}
}
void removeOwnerFromDir(Entry cache_entry, Addr addr, MachineID sender) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
cache_entry.OwnerValid := false;
}
else {
DirEntry dir_entry := getDirEntry(addr);
dir_entry.OwnerValid := false;
}
}
bool isLocalSharer(Entry cache_entry, Addr addr, MachineID shar_id) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
return cache_entry.Sharers.isElement(shar_id);
}
else {
DirEntry dir_entry := getDirEntry(addr);
return dir_entry.Sharers.isElement(shar_id);
}
}
NetDest getLocalSharers(Entry cache_entry, Addr addr) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
return cache_entry.Sharers;
}
else {
DirEntry dir_entry := getDirEntry(addr);
return dir_entry.Sharers;
}
}
MachineID getLocalOwner(Entry cache_entry, Addr addr) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
return cache_entry.Owner;
}
else {
DirEntry dir_entry := getDirEntry(addr);
return dir_entry.Owner;
}
}
int countLocalSharers(Entry cache_entry, Addr addr) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
return cache_entry.Sharers.count();
}
else {
DirEntry dir_entry := getDirEntry(addr);
return dir_entry.Sharers.count();
}
}
bool isLocalOwnerValid(Entry cache_entry, Addr addr) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
return cache_entry.OwnerValid;
}
else {
DirEntry dir_entry := getDirEntry(addr);
return dir_entry.OwnerValid;
}
}
int countLocalSharersExceptRequestor(Entry cache_entry, Addr addr, MachineID requestor) {
if (is_valid(cache_entry)) {
assert (localDirectory.isTagPresent(addr) == false);
if (cache_entry.Sharers.isElement(requestor)) {
return ( cache_entry.Sharers.count() - 1 );
}
else {
return cache_entry.Sharers.count();
}
}
else {
DirEntry dir_entry := getDirEntry(addr);
if (dir_entry.Sharers.isElement(requestor)) {
return ( dir_entry.Sharers.count() - 1 );
}
else {
return dir_entry.Sharers.count();
}
}
}
State getState(TBE tbe, Entry cache_entry, Addr addr) {
if (is_valid(tbe)) {
return tbe.TBEState;
} else if (is_valid(cache_entry)) {
return cache_entry.CacheState;
} else if (isDirTagPresent(addr)) {
DirEntry dir_entry := getDirEntry(addr);
return dir_entry.DirState;
} else {
return State:NP;
}
}
std::string getCoherenceRequestTypeStr(CoherenceRequestType type) {
return CoherenceRequestType_to_string(type);
}
void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
assert((localDirectory.isTagPresent(addr) && L2cache.isTagPresent(addr)) == false);
if (is_valid(tbe)) {
tbe.TBEState := state;
}
if (
(state == State:M) ||
(state == State:O) ||
(state == State:S) ||
(state == State:OLS) ||
(state == State:SLS) ||
(state == State:OLSX) ||
(state == State:SLS)
) {
assert(is_valid(cache_entry));
}
else if (
(state == State:ILS) ||
(state == State:ILX) ||
(state == State:ILO) ||
(state == State:ILOX) ||
(state == State:ILOS) ||
(state == State:ILOSX)
) {
// assert(isCacheTagPresent(addr) == false);
}
if (is_valid(cache_entry)) {
if ( ((cache_entry.CacheState != State:M) && (state == State:M)) ||
((cache_entry.CacheState != State:S) && (state == State:S)) ||
((cache_entry.CacheState != State:O) && (state == State:O)) ) {
cache_entry.CacheState := state;
// disable Coherence Checker for now
// sequencer.checkCoherence(addr);
}
else {
cache_entry.CacheState := state;
}
}
else if (localDirectory.isTagPresent(addr)) {
DirEntry dir_entry := getDirEntry(addr);
dir_entry.DirState := state;
}
}
AccessPermission getAccessPermission(Addr addr) {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
return L2Cache_State_to_permission(tbe.TBEState);
}
Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
return L2Cache_State_to_permission(cache_entry.CacheState);
}
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
return AccessPermission:NotPresent;
}
void setAccessPermission(Entry cache_entry, Addr addr, State state) {
if (is_valid(cache_entry)) {
cache_entry.changePermission(L2Cache_State_to_permission(state));
}
}
void functionalRead(Addr addr, Packet *pkt) {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
testAndRead(addr, tbe.DataBlk, pkt);
} else {
testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
}
}
int functionalWrite(Addr addr, Packet *pkt) {
int num_functional_writes := 0;
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
num_functional_writes := num_functional_writes +
testAndWrite(addr, tbe.DataBlk, pkt);
return num_functional_writes;
}
num_functional_writes := num_functional_writes +
testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
return num_functional_writes;
}
out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache);
out_port(localRequestNetwork_out, RequestMsg, L1RequestFromL2Cache);
out_port(responseNetwork_out, ResponseMsg, responseFromL2Cache);
out_port(triggerQueue_out, TriggerMsg, triggerQueue);
// ** IN_PORTS **
// Trigger Queue
in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=3) {
if (triggerQueue_in.isReady(clockEdge())) {
peek(triggerQueue_in, TriggerMsg) {
if (in_msg.Type == TriggerType:ALL_ACKS) {
trigger(Event:All_Acks, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else {
error("Unexpected message");
}
}
}
}
// Response Network
in_port(responseNetwork_in, ResponseMsg, responseToL2Cache, rank=2) {
if (responseNetwork_in.isReady(clockEdge())) {
peek(responseNetwork_in, ResponseMsg) {
assert(in_msg.Destination.isElement(machineID));
if (in_msg.Type == CoherenceResponseType:ACK) {
if (in_msg.SenderMachine == MachineType:L2Cache) {
trigger(Event:ExtAck, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
}
else {
trigger(Event:IntAck, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
}
} else if (in_msg.Type == CoherenceResponseType:DATA) {
trigger(Event:Data, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
trigger(Event:Data_Exclusive, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
DPRINTF(RubySlicc, "Received Unblock from L1 addr: %x\n", in_msg.addr);
trigger(Event:Unblock, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
trigger(Event:Exclusive_Unblock, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
trigger(Event:Writeback_Ack, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceResponseType:WB_NACK) {
trigger(Event:Writeback_Nack, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceResponseType:DMA_ACK) {
trigger(Event:DmaAck, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else {
error("Unexpected message");
}
}
}
}
// Request Network
in_port(requestNetwork_in, RequestMsg, GlobalRequestToL2Cache, rank=1) {
if (requestNetwork_in.isReady(clockEdge())) {
peek(requestNetwork_in, RequestMsg) {
if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:DMA_WRITE) {
if (in_msg.Requestor == machineID) {
trigger(Event:Own_GETX, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else {
trigger(Event:Fwd_GETX, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
}
} else if (in_msg.Type == CoherenceRequestType:GETS) {
trigger(Event:Fwd_GETS, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if(in_msg.Type == CoherenceRequestType:DMA_READ) {
trigger(Event:Fwd_DMA, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceRequestType:INV) {
trigger(Event:Inv, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else {
error("Unexpected message");
}
}
}
}
in_port(L1requestNetwork_in, RequestMsg, L1RequestToL2Cache, rank=0) {
if (L1requestNetwork_in.isReady(clockEdge())) {
peek(L1requestNetwork_in, RequestMsg) {
assert(in_msg.Destination.isElement(machineID));
if (in_msg.Type == CoherenceRequestType:GETX) {
trigger(Event:L1_GETX, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceRequestType:GETS) {
trigger(Event:L1_GETS, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceRequestType:PUTO) {
trigger(Event:L1_PUTO, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
trigger(Event:L1_PUTX, in_msg.addr,
getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
} else if (in_msg.Type == CoherenceRequestType:PUTS) {
Entry cache_entry := getCacheEntry(in_msg.addr);
if (isOnlySharer(cache_entry, in_msg.addr, in_msg.Requestor)) {
trigger(Event:L1_PUTS_only, in_msg.addr,
cache_entry, TBEs[in_msg.addr]);
}
else {
trigger(Event:L1_PUTS, in_msg.addr,
cache_entry, TBEs[in_msg.addr]);
}
} else if (in_msg.Type == CoherenceRequestType:WRITEBACK_DIRTY_DATA) {
Entry cache_entry := getCacheEntry(in_msg.addr);
if (is_invalid(cache_entry) &&
L2cache.cacheAvail(in_msg.addr) == false) {
trigger(Event:L2_Replacement, L2cache.cacheProbe(in_msg.addr),
getCacheEntry(L2cache.cacheProbe(in_msg.addr)),
TBEs[L2cache.cacheProbe(in_msg.addr)]);
}
else {
trigger(Event:L1_WBDIRTYDATA, in_msg.addr,
cache_entry, TBEs[in_msg.addr]);
}
} else if (in_msg.Type == CoherenceRequestType:WRITEBACK_CLEAN_DATA) {
Entry cache_entry := getCacheEntry(in_msg.addr);
if (is_invalid(cache_entry) &&
L2cache.cacheAvail(in_msg.addr) == false) {
trigger(Event:L2_Replacement, L2cache.cacheProbe(in_msg.addr),
getCacheEntry(L2cache.cacheProbe(in_msg.addr)),
TBEs[L2cache.cacheProbe(in_msg.addr)]);
}
else {
trigger(Event:L1_WBCLEANDATA, in_msg.addr,
cache_entry, TBEs[in_msg.addr]);
}
} else {
error("Unexpected message");
}
}
}
}
// ACTIONS
action(a_issueGETS, "a", desc="issue local request globally") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue(globalRequestNetwork_out, RequestMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:GETS;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Requestor := machineID;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.MessageSize := MessageSizeType:Request_Control;
}
}
}
action(a_issueGETX, "\a", desc="issue local request globally") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue(globalRequestNetwork_out, RequestMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:GETX;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Requestor := machineID;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.MessageSize := MessageSizeType:Request_Control;
}
}
}
action(b_issuePUTX, "b", desc="Issue PUTX") {
enqueue(globalRequestNetwork_out, RequestMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:PUTX;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Requestor := machineID;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
action(b_issuePUTO, "\b", desc="Issue PUTO") {
enqueue(globalRequestNetwork_out, RequestMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:PUTO;
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
/* PUTO, but local sharers exist */
action(b_issuePUTO_ls, "\bb", desc="Issue PUTO") {
enqueue(globalRequestNetwork_out, RequestMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:PUTO_SHARERS;
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
action(c_sendDataFromTBEToL1GETS, "c", desc="Send data from TBE to L1 requestors in TBE") {
assert(is_valid(tbe));
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.addNetDest(tbe.L1_GetS_IDs);
out_msg.DataBlk := tbe.DataBlk;
// out_msg.Dirty := tbe.Dirty;
// shared data should be clean
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, tbe.DataBlk);
}
action(c_sendDataFromTBEToL1GETX, "\c", desc="Send data from TBE to L1 requestors in TBE") {
assert(is_valid(tbe));
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(tbe.L1_GetX_ID);
out_msg.DataBlk := tbe.DataBlk;
out_msg.Dirty := tbe.Dirty;
out_msg.Acks := tbe.Local_GETX_IntAcks;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, tbe.DataBlk);
}
action(c_sendExclusiveDataFromTBEToL1GETS, "\cc", desc="Send data from TBE to L1 requestors in TBE") {
assert(is_valid(tbe));
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.addNetDest(tbe.L1_GetS_IDs);
out_msg.DataBlk := tbe.DataBlk;
out_msg.Dirty := tbe.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
action(c_sendDataFromTBEToFwdGETX, "cc", desc="Send data from TBE to external GETX") {
assert(is_valid(tbe));
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(tbe.Fwd_GetX_ID);
out_msg.DataBlk := tbe.DataBlk;
out_msg.Dirty := tbe.Dirty;
out_msg.Acks := tbe.Fwd_GETX_ExtAcks;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
action(cd_sendDataFromTBEToFwdDma, "cd", desc="Send data from TBE to external GETX") {
assert(is_valid(tbe));
peek(requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := tbe.DataBlk;
// out_msg.Dirty := tbe.Dirty;
// shared data should be clean
out_msg.Dirty := false;
out_msg.Acks := tbe.Fwd_GETX_ExtAcks;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, tbe.DataBlk);
}
action(c_sendDataFromTBEToFwdGETS, "ccc", desc="Send data from TBE to external GETX") {
assert(is_valid(tbe));
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.addNetDest(tbe.Fwd_GetS_IDs);
out_msg.DataBlk := tbe.DataBlk;
// out_msg.Dirty := tbe.Dirty;
// shared data should be clean
out_msg.Dirty := false;
out_msg.Acks := tbe.Fwd_GETX_ExtAcks;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, tbe.DataBlk);
}
action(c_sendExclusiveDataFromTBEToFwdGETS, "\ccc", desc="Send data from TBE to external GETX") {
assert(is_valid(tbe));
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.addNetDest(tbe.Fwd_GetS_IDs);
out_msg.DataBlk := tbe.DataBlk;
out_msg.Dirty := tbe.Dirty;
out_msg.Acks := tbe.Fwd_GETX_ExtAcks;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, tbe.DataBlk);
}
action(d_sendDataToL1GETS, "d", desc="Send data directly to L1 requestor") {
assert(is_valid(cache_entry));
peek(L1requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
// out_msg.Dirty := cache_entry.Dirty;
// shared data should be clean
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
}
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, cache_entry.DataBlk);
}
action(d_sendDataToL1GETX, "\d", desc="Send data and a token from TBE to L1 requestor") {
assert(is_valid(cache_entry));
peek(L1requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
assert(is_valid(tbe));
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
out_msg.Acks := tbe.Local_GETX_IntAcks;
}
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, cache_entry.DataBlk);
}
action(dd_sendDataToFwdGETX, "dd", desc="send data") {
assert(is_valid(cache_entry));
peek(requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
out_msg.Acks := in_msg.Acks;
}
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, cache_entry.DataBlk);
}
action(dd_sendDataToFwdGETS, "\dd", desc="send data") {
assert(is_valid(cache_entry));
peek(requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
// out_msg.Dirty := cache_entry.Dirty;
// shared data should be clean
out_msg.Dirty := false;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, cache_entry.DataBlk);
}
action(dd_sendExclusiveDataToFwdGETS, "\d\d", desc="send data") {
assert(is_valid(cache_entry));
peek(requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
}
}
action(e_sendAck, "e", desc="Send ack with the tokens we've collected thus far.") {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
assert(is_valid(tbe));
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:ACK;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add( tbe.Fwd_GetX_ID);
out_msg.Acks := 0 - 1;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
action(e_sendAckToL1Requestor, "\e", desc="Send ack with the tokens we've collected thus far.") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:ACK;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.Acks := 0 - 1;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
}
action(e_sendAckToL1RequestorFromTBE, "eee", desc="Send ack with the tokens we've collected thus far.") {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
assert(is_valid(tbe));
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:ACK;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(tbe.L1_GetX_ID);
out_msg.Acks := 0 - 1;
out_msg.MessageSize := MessageSizeType:Response_Control;
}
}
action(ee_sendLocalInv, "\ee", desc="Send local invalidates") {
assert(is_valid(tbe));
tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address);
DPRINTF(RubySlicc, "Address: %#x, Local Sharers: %s, Pending Acks: %d\n",
address, getLocalSharers(cache_entry, address),
tbe.NumIntPendingAcks);
if (isLocalOwnerValid(cache_entry, address)) {
tbe.NumIntPendingAcks := tbe.NumIntPendingAcks + 1;
DPRINTF(RubySlicc, "%s\n", getLocalOwner(cache_entry, address));
}
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:INV;
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address));
if (isLocalOwnerValid(cache_entry, address))
{
out_msg.Destination.add(getLocalOwner(cache_entry, address));
}
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
}
}
action(ee_sendLocalInvSharersOnly, "\eee", desc="Send local invalidates to sharers if they exist") {
// assert(countLocalSharers(address) > 0);
assert(is_valid(tbe));
tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address);
if (countLocalSharers(cache_entry, address) > 0) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:INV;
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address));
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
}
}
}
action(ee_addLocalIntAck, "e\ee", desc="add a local ack to wait for") {
assert(is_valid(tbe));
tbe.NumIntPendingAcks := tbe.NumIntPendingAcks + 1;
}
action(ee_issueLocalInvExceptL1Requestor, "\eeee", desc="Send local invalidates to sharers if they exist") {
peek(L1requestNetwork_in, RequestMsg) {
// assert(countLocalSharers(address) > 0);
if (countLocalSharers(cache_entry, address) == 0) {
tbe.NumIntPendingAcks := 0;
}
else {
if (isLocalSharer(cache_entry, address, in_msg.Requestor)) {
tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address) - 1;
}
else {
tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address);
}
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:INV;
out_msg.Requestor := in_msg.Requestor;
out_msg.RequestorMachine := MachineType:L1Cache;
out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address));
out_msg.Destination.remove(in_msg.Requestor);
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
}
}
}
}
action(ee_issueLocalInvExceptL1RequestorInTBE, "\eeeeee", desc="Send local invalidates to sharers if they exist") {
assert(is_valid(tbe));
if (countLocalSharers(cache_entry, address) == 0) {
tbe.NumIntPendingAcks := 0;
}
else {
if (isLocalSharer(cache_entry, address, tbe.L1_GetX_ID)) {
tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address) - 1;
}
else {
tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address);
}
}
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:INV;
out_msg.Requestor := tbe.L1_GetX_ID;
out_msg.RequestorMachine := MachineType:L1Cache;
out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address));
out_msg.Destination.remove(tbe.L1_GetX_ID);
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
}
}
action(f_sendUnblock, "f", desc="Send unblock to global directory") {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:UNBLOCK;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.MessageSize := MessageSizeType:Unblock_Control;
}
}
action(f_sendExclusiveUnblock, "\f", desc="Send unblock to global directory") {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.MessageSize := MessageSizeType:Unblock_Control;
}
}
action(g_recordLocalSharer, "g", desc="Record new local sharer from unblock message") {
peek(responseNetwork_in, ResponseMsg) {
recordLocalSharerInDir(cache_entry, in_msg.addr, in_msg.Sender);
}
}
action(g_recordLocalExclusive, "\g", desc="Record new local exclusive sharer from unblock message") {
peek(responseNetwork_in, ResponseMsg) {
recordNewLocalExclusiveInDir(cache_entry, address, in_msg.Sender);
}
}
action(gg_clearLocalSharers, "gg", desc="Clear local sharers") {
removeAllLocalSharersFromDir(cache_entry, address);
}
action(gg_clearSharerFromL1Response, "\gg", desc="Clear sharer from L1 response queue") {
peek(responseNetwork_in, ResponseMsg) {
removeSharerFromDir(cache_entry, in_msg.addr, in_msg.Sender);
}
}
action(gg_clearSharerFromL1Request, "clsl1r", desc="Clear sharer from L1 request queue") {
peek(L1requestNetwork_in, RequestMsg) {
removeSharerFromDir(cache_entry, in_msg.addr, in_msg.Requestor);
}
}
action(gg_clearOwnerFromL1Request, "clol1r", desc="Clear owner from L1 request queue") {
peek(L1requestNetwork_in, RequestMsg) {
removeOwnerFromDir(cache_entry, in_msg.addr, in_msg.Requestor);
}
}
action(h_countLocalSharersExceptRequestor, "h", desc="counts number of acks needed for L1 GETX") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(tbe));
tbe.Local_GETX_IntAcks := countLocalSharersExceptRequestor(cache_entry, address, in_msg.Requestor);
}
}
action(h_clearIntAcks, "\h", desc="clear IntAcks") {
assert(is_valid(tbe));
tbe.Local_GETX_IntAcks := 0;
}
action(hh_countLocalSharersExceptL1GETXRequestorInTBE, "hh", desc="counts number of acks needed for L1 GETX") {
assert(is_valid(tbe));
tbe.Local_GETX_IntAcks := countLocalSharersExceptRequestor(cache_entry, address, tbe.L1_GetX_ID);
}
action(i_copyDataToTBE, "\i", desc="Copy data from response queue to TBE") {
peek(responseNetwork_in, ResponseMsg) {
assert(is_valid(tbe));
tbe.DataBlk := in_msg.DataBlk;
tbe.Dirty := in_msg.Dirty;
APPEND_TRANSITION_COMMENT(in_msg.Sender);
}
}
action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") {
check_allocate(TBEs);
TBEs.allocate(address);
set_tbe(TBEs[address]);
if(is_valid(cache_entry)) {
tbe.DataBlk := cache_entry.DataBlk;
tbe.Dirty := cache_entry.Dirty;
}
tbe.NumIntPendingAcks := 0; // default value
tbe.NumExtPendingAcks := 0; // default value
tbe.Fwd_GetS_IDs.clear();
tbe.L1_GetS_IDs.clear();
}
action(j_forwardGlobalRequestToLocalOwner, "j", desc="Forward external request to local owner") {
peek(requestNetwork_in, RequestMsg) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := in_msg.Type;
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.addr));
out_msg.Type := in_msg.Type;
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
out_msg.Acks := 0 - 1;
}
}
}
action(jd_forwardDmaRequestToLocalOwner, "jd", desc="Forward dma request to local owner") {
peek(requestNetwork_in, RequestMsg) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := in_msg.Type;
out_msg.Requestor := in_msg.Requestor;
out_msg.RequestorMachine := in_msg.RequestorMachine;
out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.addr));
out_msg.Type := in_msg.Type;
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
out_msg.Acks := 0 - 1;
}
}
}
action(k_forwardLocalGETSToLocalSharer, "k", desc="Forward local request to local sharer/owner") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := CoherenceRequestType:GETS;
out_msg.Requestor := in_msg.Requestor;
out_msg.RequestorMachine := MachineType:L1Cache;
// should randomize this so one node doesn't get abused more than others
DirEntry dir_entry := getDirEntry(in_msg.addr);
out_msg.Destination.add(dir_entry.Sharers.smallestElement(MachineType:L1Cache));
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
}
}
}
action(k_forwardLocalGETXToLocalOwner, "\k", desc="Forward local request to local owner") {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
assert(is_valid(tbe));
out_msg.addr := address;
out_msg.Type := CoherenceRequestType:GETX;
out_msg.Requestor := tbe.L1_GetX_ID;
out_msg.RequestorMachine := MachineType:L1Cache;
DirEntry dir_entry := getDirEntry(address);
out_msg.Destination.add(dir_entry.Owner);
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
out_msg.Acks := 1 + tbe.Local_GETX_IntAcks;
}
}
// same as previous except that it assumes to TBE is present to get number of acks
action(kk_forwardLocalGETXToLocalExclusive, "kk", desc="Forward local request to local owner") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := CoherenceRequestType:GETX;
out_msg.Requestor := in_msg.Requestor;
out_msg.RequestorMachine := MachineType:L1Cache;
out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.addr));
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
out_msg.Acks := 1;
}
}
}
action(kk_forwardLocalGETSToLocalOwner, "\kk", desc="Forward local request to local owner") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := CoherenceRequestType:GETS;
out_msg.Requestor := in_msg.Requestor;
out_msg.RequestorMachine := MachineType:L1Cache;
out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.addr));
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
}
}
}
action(l_writebackAckNeedData, "l", desc="Send writeback ack to L1 requesting data") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue( responseNetwork_out, ResponseMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := CoherenceResponseType:WB_ACK_DATA;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
action(l_writebackAckDropData, "\l", desc="Send writeback ack to L1 indicating to drop data") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue( responseNetwork_out, ResponseMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := CoherenceResponseType:WB_ACK;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
action(ll_writebackNack, "\ll", desc="Send writeback nack to L1") {
peek(L1requestNetwork_in, RequestMsg) {
enqueue( responseNetwork_out, ResponseMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := CoherenceResponseType:WB_NACK;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
action(m_popRequestQueue, "m", desc="Pop request queue.") {
requestNetwork_in.dequeue(clockEdge());
}
action(m_decrementNumberOfMessagesInt, "\m", desc="Decrement the number of messages for which we're waiting") {
peek(responseNetwork_in, ResponseMsg) {
assert(is_valid(tbe));
tbe.NumIntPendingAcks := tbe.NumIntPendingAcks + in_msg.Acks;
}
}
action(m_decrementNumberOfMessagesExt, "\mmm", desc="Decrement the number of messages for which we're waiting") {
peek(responseNetwork_in, ResponseMsg) {
assert(is_valid(tbe));
tbe.NumExtPendingAcks := tbe.NumExtPendingAcks - in_msg.Acks;
}
}
action(mm_decrementNumberOfMessagesExt, "\mm", desc="Decrement the number of messages for which we're waiting") {
peek(requestNetwork_in, RequestMsg) {
assert(is_valid(tbe));
tbe.NumExtPendingAcks := tbe.NumExtPendingAcks - in_msg.Acks;
}
}
action(n_popResponseQueue, "n", desc="Pop response queue") {
responseNetwork_in.dequeue(clockEdge());
}
action(n_popTriggerQueue, "\n", desc="Pop trigger queue.") {
triggerQueue_in.dequeue(clockEdge());
}
action(o_popL1RequestQueue, "o", desc="Pop L1 request queue.") {
L1requestNetwork_in.dequeue(clockEdge());
}
action(o_checkForIntCompletion, "\o", desc="Check if we have received all the messages required for completion") {
assert(is_valid(tbe));
if (tbe.NumIntPendingAcks == 0) {
enqueue(triggerQueue_out, TriggerMsg) {
out_msg.addr := address;
out_msg.Type := TriggerType:ALL_ACKS;
}
}
}
action(o_checkForExtCompletion, "\oo", desc="Check if we have received all the messages required for completion") {
assert(is_valid(tbe));
if (tbe.NumExtPendingAcks == 0) {
enqueue(triggerQueue_out, TriggerMsg) {
out_msg.addr := address;
out_msg.Type := TriggerType:ALL_ACKS;
}
}
}
action( qq_sendDataFromTBEToMemory, "qq", desc="Send data from TBE to directory") {
enqueue(globalRequestNetwork_out, RequestMsg, response_latency) {
assert(is_valid(tbe));
out_msg.addr := address;
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
if (tbe.Dirty) {
out_msg.Type := CoherenceRequestType:WRITEBACK_DIRTY_DATA;
out_msg.DataBlk := tbe.DataBlk;
out_msg.MessageSize := MessageSizeType:Writeback_Data;
} else {
out_msg.Type := CoherenceRequestType:WRITEBACK_CLEAN_ACK;
// NOTE: in a real system this would not send data. We send
// data here only so we can check it at the memory
out_msg.DataBlk := tbe.DataBlk;
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
action( r_setMRU, "\rrr", desc="manually set the MRU bit for cache line" ) {
if(is_valid(cache_entry)) {
L2cache.setMRU(address);
}
}
action( s_recordGetXL1ID, "ss", desc="record local GETX requestor") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(tbe));
tbe.L1_GetX_ID := in_msg.Requestor;
}
}
action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
TBEs.deallocate(address);
unset_tbe();
}
action( s_recordGetSL1ID, "\ss", desc="record local GETS requestor") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(tbe));
tbe.L1_GetS_IDs.add(in_msg.Requestor);
}
}
action(t_recordFwdXID, "t", desc="record global GETX requestor") {
peek(requestNetwork_in, RequestMsg) {
assert(is_valid(tbe));
tbe.Fwd_GetX_ID := in_msg.Requestor;
tbe.Fwd_GETX_ExtAcks := in_msg.Acks;
}
}
action(t_recordFwdSID, "\t", desc="record global GETS requestor") {
peek(requestNetwork_in, RequestMsg) {
assert(is_valid(tbe));
tbe.Fwd_GetS_IDs.clear();
tbe.Fwd_GetS_IDs.add(in_msg.Requestor);
}
}
action(u_writeCleanDataToCache, "wCd", desc="Write clean data to cache") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
cache_entry.DataBlk := in_msg.DataBlk;
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, cache_entry.DataBlk);
assert(cache_entry.Dirty == false);
}
}
action(u_writeDirtyDataToCache, "wDd", desc="Write dirty data to cache") {
peek(L1requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
cache_entry.DataBlk := in_msg.DataBlk;
DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
address, cache_entry.DataBlk);
cache_entry.Dirty := true;
}
}
action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
set_cache_entry(L2cache.allocate(address, new Entry));
}
action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
L2cache.deallocate(address);
unset_cache_entry();
}
action(uu_profileMiss, "\um", desc="Profile the demand miss") {
++L2cache.demand_misses;
}
action(uu_profileHit, "\uh", desc="Profile the demand hit") {
++L2cache.demand_hits;
}
action(y_copyCacheStateToDir, "y", desc="Copy cache state to directory state") {
copyCacheStateToDir(cache_entry, address);
}
action(y_copyDirToCacheAndRemove, "/y", desc="Copy dir state to cache and remove") {
copyDirToCache(cache_entry, address);
localDirectory.deallocate(address);
}
action(zz_recycleGlobalRequestQueue, "\zglb", desc="Send the head of the mandatory queue to the back of the queue.") {
peek(requestNetwork_in, RequestMsg) {
APPEND_TRANSITION_COMMENT(in_msg.Requestor);
}
requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
}
action(zz_recycleL1RequestQueue, "\zl1", desc="Send the head of the mandatory queue to the back of the queue.") {
peek(L1requestNetwork_in, RequestMsg) {
APPEND_TRANSITION_COMMENT(in_msg.Requestor);
}
L1requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
}
action(st_stallAndWaitL1RequestQueue, "st", desc="Stall and wait on the address") {
stall_and_wait(L1requestNetwork_in, address);
}
action(wa_wakeUpDependents, "wa", desc="Wake up any requests waiting for this address") {
wakeUpAllBuffers(address);
}
action(da_sendDmaAckUnblock, "da", desc="Send dma ack to global directory") {
enqueue(responseNetwork_out, ResponseMsg, response_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DMA_ACK;
out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L2Cache;
out_msg.MessageSize := MessageSizeType:Unblock_Control;
}
}
//*****************************************************
// TRANSITIONS
//*****************************************************
transition({II, IFGX, IFGS, ISFGS, IFGXX, IFLXO, ILOW, ILOXW, ILOSW, ILOSXW, SLSW, OLSW, ILSW, IW, OW, SW, OXW, OLSXW, ILXW, IFLS, IFLO, IFLOX, IFLOXX, IFLOSX, OLSXS, IGS, IGM, IGMLS, IGMO, IGMIO, OGMIO, IGMIOF, OGMIOF, MM, SS, OO, OI, MI, MII, OLSI, ILSI, SLSS, OLSS, OLSF, IGMIOFS, ILOSD, ILOSXD, ILOD, ILXD, ILOXD}, {L1_PUTO, L1_PUTS, L1_PUTS_only, L1_PUTX}) {
st_stallAndWaitL1RequestQueue;
}
transition({II, IFGX, IFGS, ISFGS, IFGXX, IFLXO, ILOW, ILOXW, ILOSW, ILOSXW, SLSW, OLSW, ILSW, IW, OW, SW, OXW, OLSXW, ILXW, IFLS, IFLO, IFLOX, IFLOXX, IFLOSX, OLSXS, IGS, IGM, IGMLS, IGMO, IGMIO, OGMIO, IGMIOF, OGMIOF, MM, SS, OO, OI, MI, MII, OLSI, ILSI, SLSS, OLSS, OLSF, IGMIOFS, ILOSD, ILOSXD, ILOD, ILXD, ILOXD}, {L1_GETX, L1_GETS}) {
st_stallAndWaitL1RequestQueue;
}
transition({IFGX, IFGS, ISFGS, IFGXX, IFLXO, ILOW, ILOXW, ILOSW, ILOSXW, SLSW, OLSW, ILSW, IW, ILXW, OW, SW, OXW, OLSXW, IFLS, IFLO, IFLOX, IFLOXX, IFLOSX,OLSXS, IGS, IGM, IGMLS, IGMO, MM, SS, OO, OI, MI, MII, OLSI, ILSI, SLSS, OLSS, OLSF, IGMIOFS, ILOSD, ILOSXD, ILOD, ILXD, ILOXD}, L2_Replacement) {
zz_recycleL1RequestQueue;
}
transition({IFGX, IFGS, ISFGS, IFGXX, IFLXO, ILOW, ILOXW, ILOSW, ILOSXW, SLSW, OLSW, ILSW, IW, OW, SW, OXW, OLSXW, ILXW, IFLS, IFLO, IFLOX, IFLOXX, IFLOSX,OLSXS, IGS, IGM, MM, SS, OO, SLSS, OLSS, OLSF, IGMIOFS, ILOSD, ILOSXD, ILOD, ILXD, ILOXD}, {Fwd_GETX, Fwd_GETS, Fwd_DMA}) {
zz_recycleGlobalRequestQueue;
}
transition({OGMIO, IGMIO, IGMO}, Fwd_DMA) {
zz_recycleGlobalRequestQueue;
}
transition({IFGX, IFGS, ISFGS, IFGXX, IFLXO, ILOW, ILOXW, ILOSW, ILOSXW, SLSW, OLSW, ILSW, IW, OW, SW, OXW, OLSXW, ILXW, IFLS, IFLO, IFLOX, IFLOXX, IFLOSX,OLSXS, MM, SS, OO, SLSS, OLSS, OLSF, IGMIOFS, ILOSD, ILOSXD, ILOD, ILXD, ILOXD}, {Inv}) {
zz_recycleGlobalRequestQueue;
}
transition({IGM, IGS, ILOSD, ILOSXD, ILOD, ILXD, ILOXD}, {Own_GETX}) {
zz_recycleGlobalRequestQueue;
}
// must happened because we forwarded GETX to local exclusive trying to do wb
transition({I, M, O, ILS, ILOX, OLS, OLSX, SLS, S}, L1_PUTX) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition({M}, {L1_PUTS, L1_PUTO} ) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition({ILS, OLSX}, L1_PUTO){
ll_writebackNack;
o_popL1RequestQueue;
}
// happened if we forwarded GETS to exclusive who tried to do writeback
// ?? should we just Nack these instead? Could be a bugs here
transition(ILO, L1_PUTX, ILOW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
// this can happen if we forwarded a L1_GETX to exclusiver after it issued a PUTX
transition(ILOS, L1_PUTX, ILOSW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
transition(ILOSX, L1_PUTX, ILOSXW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
// must happened because we got Inv when L1 attempted PUTS
transition(I, L1_PUTS) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition(I, L1_PUTO) {
ll_writebackNack;
o_popL1RequestQueue;
}
// FORWARDED REQUESTS
transition({ILO, ILX, ILOX}, Fwd_GETS, IFGS) {
i_allocateTBE;
t_recordFwdSID;
j_forwardGlobalRequestToLocalOwner;
m_popRequestQueue;
}
transition({ILOS, ILOSX}, Fwd_GETS, ISFGS) {
i_allocateTBE;
t_recordFwdSID;
j_forwardGlobalRequestToLocalOwner;
m_popRequestQueue;
}
transition(ILOS, Fwd_DMA, ILOSD) {
i_allocateTBE;
jd_forwardDmaRequestToLocalOwner;
m_popRequestQueue;
}
transition(ILOSD, DmaAck, ILOS) {
s_deallocateTBE;
da_sendDmaAckUnblock;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILOSX, Fwd_DMA, ILOSXD) {
i_allocateTBE;
t_recordFwdSID;
jd_forwardDmaRequestToLocalOwner;
m_popRequestQueue;
}
transition(ILOSXD, DmaAck, ILOSX) {
s_deallocateTBE;
da_sendDmaAckUnblock;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILO, Fwd_DMA, ILOD) {
i_allocateTBE;
t_recordFwdSID;
jd_forwardDmaRequestToLocalOwner;
m_popRequestQueue;
}
transition(ILOD, DmaAck, ILO) {
s_deallocateTBE;
da_sendDmaAckUnblock;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILX, Fwd_DMA, ILXD) {
i_allocateTBE;
t_recordFwdSID;
jd_forwardDmaRequestToLocalOwner;
m_popRequestQueue;
}
transition(ILXD, DmaAck, ILX) {
s_deallocateTBE;
da_sendDmaAckUnblock;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILOX, Fwd_DMA, ILOXD) {
i_allocateTBE;
t_recordFwdSID;
jd_forwardDmaRequestToLocalOwner;
m_popRequestQueue;
}
transition(ILOXD, DmaAck, ILOX) {
s_deallocateTBE;
da_sendDmaAckUnblock;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition({ILOS, ILOSX, ILO, ILX, ILOX, ILXW}, Data) {
i_copyDataToTBE;
c_sendDataFromTBEToFwdGETS;
s_deallocateTBE;
n_popResponseQueue;
}
transition(IFGS, Data, ILO) {
i_copyDataToTBE;
c_sendDataFromTBEToFwdGETS;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ISFGS, Data, ILOS) {
i_copyDataToTBE;
c_sendDataFromTBEToFwdGETS;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IFGS, Data_Exclusive, I) {
i_copyDataToTBE;
c_sendExclusiveDataFromTBEToFwdGETS;
gg_clearLocalSharers;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition({ILX, ILO, ILOX}, Fwd_GETX, IFGX) {
i_allocateTBE;
t_recordFwdXID;
j_forwardGlobalRequestToLocalOwner;
m_popRequestQueue;
}
transition(IFGX, {Data_Exclusive, Data}, I) {
i_copyDataToTBE;
c_sendDataFromTBEToFwdGETX;
gg_clearLocalSharers;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition({ILOSX, ILOS}, Fwd_GETX, IFGXX) {
i_allocateTBE;
t_recordFwdXID;
j_forwardGlobalRequestToLocalOwner;
ee_sendLocalInvSharersOnly;
ee_addLocalIntAck;
m_popRequestQueue;
}
transition(IFGXX, IntAck) {
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(IFGXX, Data_Exclusive) {
i_copyDataToTBE;
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(IFGXX, All_Acks, I) {
c_sendDataFromTBEToFwdGETX;
gg_clearLocalSharers;
s_deallocateTBE;
n_popTriggerQueue;
wa_wakeUpDependents;
}
// transition({O, OX}, Fwd_GETX, I) {
transition(O, Fwd_GETX, I) {
dd_sendDataToFwdGETX;
y_copyCacheStateToDir;
rr_deallocateL2CacheBlock;
m_popRequestQueue;
}
transition({O, OLS}, Fwd_GETS) {
dd_sendDataToFwdGETS;
m_popRequestQueue;
}
transition({O, OLS}, Fwd_DMA) {
dd_sendDataToFwdGETS;
da_sendDmaAckUnblock;
m_popRequestQueue;
}
// transition({OLSX, OX}, Fwd_GETS, O) {
transition(OLSX, Fwd_GETS, OLS) {
dd_sendDataToFwdGETS;
m_popRequestQueue;
}
transition(OLSX, Fwd_DMA) {
dd_sendDataToFwdGETS;
da_sendDmaAckUnblock;
m_popRequestQueue;
}
transition(M, Fwd_GETX, I) {
dd_sendDataToFwdGETX;
rr_deallocateL2CacheBlock;
m_popRequestQueue;
}
// MAKE THIS THE SAME POLICY FOR NOW
// transition(M, Fwd_GETS, O) {
// dd_sendDataToFwdGETS;
// m_popRequestQueue;
// }
transition(M, Fwd_GETS, I) {
dd_sendExclusiveDataToFwdGETS;
rr_deallocateL2CacheBlock;
m_popRequestQueue;
}
transition(M, Fwd_DMA) {
dd_sendExclusiveDataToFwdGETS;
da_sendDmaAckUnblock;
m_popRequestQueue;
}
transition({OLS, OLSX}, Fwd_GETX, OLSF) {
i_allocateTBE;
t_recordFwdXID;
ee_sendLocalInv;
m_popRequestQueue;
}
transition(OLSF, IntAck) {
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(OLSF, All_Acks, I) {
c_sendDataFromTBEToFwdGETX;
gg_clearLocalSharers;
s_deallocateTBE;
rr_deallocateL2CacheBlock;
n_popTriggerQueue;
wa_wakeUpDependents;
}
// INVALIDATIONS FROM GLOBAL DIRECTORY
transition({IGM, IGS}, Inv) {
t_recordFwdXID;
e_sendAck;
m_popRequestQueue;
}
transition({I,NP}, Inv) {
i_allocateTBE;
t_recordFwdXID;
e_sendAck;
s_deallocateTBE;
m_popRequestQueue;
}
// NEED INV for S state
transition({ILS, ILO, ILX}, Inv, II) {
i_allocateTBE;
t_recordFwdXID;
ee_sendLocalInv;
gg_clearLocalSharers;
m_popRequestQueue;
}
transition(SLS, Inv, II) {
i_allocateTBE;
t_recordFwdXID;
ee_sendLocalInv;
rr_deallocateL2CacheBlock;
m_popRequestQueue;
}
transition(II, IntAck) {
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(II, All_Acks, I) {
e_sendAck;
s_deallocateTBE;
n_popTriggerQueue;
wa_wakeUpDependents;
}
transition(S, Inv, I) {
i_allocateTBE;
t_recordFwdXID;
e_sendAck;
s_deallocateTBE;
rr_deallocateL2CacheBlock;
m_popRequestQueue;
}
// LOCAL REQUESTS SATISFIED LOCALLY
transition(OLSX, L1_GETX, IFLOX) {
i_allocateTBE;
s_recordGetXL1ID;
// count number of INVs needed that doesn't include requestor
h_countLocalSharersExceptRequestor;
// issue INVs to everyone except requestor
ee_issueLocalInvExceptL1Requestor;
d_sendDataToL1GETX
y_copyCacheStateToDir;
r_setMRU;
rr_deallocateL2CacheBlock;
uu_profileHit;
o_popL1RequestQueue;
}
transition(IFLOX, Exclusive_Unblock, ILX) {
g_recordLocalExclusive;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(OLSX, L1_GETS, OLSXS) {
d_sendDataToL1GETS;
r_setMRU;
uu_profileHit;
o_popL1RequestQueue;
}
transition(OLSXS, Unblock, OLSX) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
// after this, can't get Fwd_GETX
transition(IGMO, Own_GETX) {
mm_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
m_popRequestQueue;
}
transition(ILX, L1_GETS, IFLOXX) {
kk_forwardLocalGETSToLocalOwner;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(ILOSX, L1_GETS, IFLOSX) {
kk_forwardLocalGETSToLocalOwner;
uu_profileMiss;
o_popL1RequestQueue;
}
transition({ILOS, ILO}, L1_GETS, IFLO) {
kk_forwardLocalGETSToLocalOwner;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(ILS, L1_GETS, IFLS) {
k_forwardLocalGETSToLocalSharer;
uu_profileMiss;
o_popL1RequestQueue;
}
transition({ILX, ILOX}, L1_GETX, IFLOXX) {
kk_forwardLocalGETXToLocalExclusive;
e_sendAckToL1Requestor;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(ILOX, L1_GETS, IFLOX) {
kk_forwardLocalGETSToLocalOwner;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(IFLOX, Unblock, ILOSX) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IFLS, Unblock, ILS) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IFLOXX, Unblock, ILOSX) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IFLOSX, Unblock, ILOSX) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition({IFLOSX, IFLOXX}, Exclusive_Unblock, ILX) {
g_recordLocalExclusive;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IFLO, Unblock, ILOS) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILOSX, L1_GETX, IFLXO) {
i_allocateTBE;
s_recordGetXL1ID;
h_countLocalSharersExceptRequestor;
ee_issueLocalInvExceptL1Requestor;
k_forwardLocalGETXToLocalOwner;
e_sendAckToL1RequestorFromTBE;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(IFLXO, Exclusive_Unblock, ILX) {
g_recordLocalExclusive;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
// LOCAL REQUESTS THAT MUST ISSUE
transition(NP, {L1_PUTS, L1_PUTX, L1_PUTO}) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition({NP, I}, L1_GETS, IGS) {
i_allocateTBE;
s_recordGetSL1ID;
a_issueGETS;
uu_profileMiss;
o_popL1RequestQueue;
}
transition({NP, I}, L1_GETX, IGM) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(S, L1_GETX, IGM) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
y_copyCacheStateToDir;
r_setMRU;
rr_deallocateL2CacheBlock;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(ILS, L1_GETX, IGMLS) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
// count number of INVs (just sharers?) needed that doesn't include requestor
h_countLocalSharersExceptRequestor;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(IGMLS, Inv) {
t_recordFwdXID;
ee_sendLocalInv;
m_popRequestQueue;
}
transition(IGMLS, IntAck) {
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(IGMLS, All_Acks, IGM) {
gg_clearLocalSharers;
h_clearIntAcks;
e_sendAck;
n_popTriggerQueue;
}
// transition(IGMLS, ExtAck, IGMO) {
transition(IGMLS, ExtAck) {
m_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
n_popResponseQueue;
}
transition(IGMLS, {Data, Data_Exclusive}, IGMO) {
ee_issueLocalInvExceptL1RequestorInTBE;
i_copyDataToTBE;
m_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
n_popResponseQueue;
}
transition(ILOS, L1_GETX, IGMIO) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
uu_profileMiss;
o_popL1RequestQueue;
}
// new exclusive happened while sharer attempted writeback
transition(ILX, {L1_PUTS, L1_PUTS_only, L1_PUTO}) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition(S, L1_PUTS) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition(OLS, L1_GETX, OGMIO) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
h_countLocalSharersExceptRequestor;
// COPY DATA FROM CACHE TO TBE (happens during i_allocateTBE)
y_copyCacheStateToDir;
rr_deallocateL2CacheBlock;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(OGMIO, Fwd_GETS) {
t_recordFwdSID;
c_sendDataFromTBEToFwdGETS;
m_popRequestQueue;
}
transition(ILO, L1_GETX, IGMIO) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
// the following, of course, returns 0 sharers but do anyways for consistency
h_countLocalSharersExceptRequestor;
uu_profileMiss;
o_popL1RequestQueue;
}
transition({ILO, ILOX}, L1_PUTS) {
ll_writebackNack;
o_popL1RequestQueue;
}
transition(IGMIO, Fwd_GETX, IGMIOF) {
t_recordFwdXID;
j_forwardGlobalRequestToLocalOwner;
ee_sendLocalInvSharersOnly;
ee_addLocalIntAck;
m_popRequestQueue;
}
transition(IGMIO, Fwd_GETS, IGMIOFS) {
t_recordFwdSID;
j_forwardGlobalRequestToLocalOwner;
m_popRequestQueue;
}
transition(IGMIOFS, Data, IGMIO) {
i_copyDataToTBE;
c_sendDataFromTBEToFwdGETS;
n_popResponseQueue;
}
transition(OGMIO, Fwd_GETX, OGMIOF) {
t_recordFwdXID;
ee_sendLocalInvSharersOnly;
m_popRequestQueue;
}
transition(OGMIOF, IntAck) {
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(OGMIOF, All_Acks, IGM) {
gg_clearLocalSharers;
hh_countLocalSharersExceptL1GETXRequestorInTBE;
c_sendDataFromTBEToFwdGETX;
n_popTriggerQueue;
}
transition(IGMIOF, IntAck) {
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(IGMIOF, Data_Exclusive) {
i_copyDataToTBE;
m_decrementNumberOfMessagesInt;
o_checkForIntCompletion;
n_popResponseQueue;
}
transition(IGMIOF, All_Acks, IGM) {
gg_clearLocalSharers;
c_sendDataFromTBEToFwdGETX;
n_popTriggerQueue;
}
transition(IGMIO, All_Acks, IGMO) {
hh_countLocalSharersExceptL1GETXRequestorInTBE;
ee_issueLocalInvExceptL1RequestorInTBE;
k_forwardLocalGETXToLocalOwner;
e_sendAckToL1RequestorFromTBE;
n_popTriggerQueue;
}
transition(OGMIO, All_Acks, IGMO) {
ee_issueLocalInvExceptL1RequestorInTBE;
c_sendDataFromTBEToL1GETX;
n_popTriggerQueue;
}
transition({IGMIO, OGMIO}, Own_GETX) {
mm_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
m_popRequestQueue;
}
transition(IGM, {Data, Data_Exclusive}, IGMO) {
i_copyDataToTBE;
m_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
n_popResponseQueue;
}
transition({IGM, IGMIO, OGMIO}, ExtAck) {
m_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
n_popResponseQueue;
}
transition(IGMO, ExtAck) {
m_decrementNumberOfMessagesExt;
o_checkForExtCompletion;
n_popResponseQueue;
}
transition(IGS, Data) {
i_copyDataToTBE;
m_decrementNumberOfMessagesExt;
c_sendDataFromTBEToL1GETS;
n_popResponseQueue;
}
transition(IGS, Data_Exclusive) {
i_copyDataToTBE;
m_decrementNumberOfMessagesExt;
c_sendExclusiveDataFromTBEToL1GETS;
n_popResponseQueue;
}
transition(IGS, Unblock, ILS) {
g_recordLocalSharer;
f_sendUnblock;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IGS, Exclusive_Unblock, ILX) {
g_recordLocalExclusive;
f_sendExclusiveUnblock;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IGMO, All_Acks) {
c_sendDataFromTBEToL1GETX;
n_popTriggerQueue;
}
transition(IGMO, Exclusive_Unblock, ILX) {
g_recordLocalExclusive;
f_sendExclusiveUnblock;
s_deallocateTBE;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(SLS, L1_GETX, IGMLS) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
// count number of INVs needed that doesn't include requestor
h_countLocalSharersExceptRequestor;
// issue INVs to everyone except requestor
y_copyCacheStateToDir;
rr_deallocateL2CacheBlock;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(SLS, L1_GETS, SLSS ) {
d_sendDataToL1GETS;
r_setMRU;
uu_profileHit;
o_popL1RequestQueue;
}
transition(SLSS, Unblock, SLS) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(O, L1_GETX, IGMO) {
i_allocateTBE;
s_recordGetXL1ID;
a_issueGETX;
y_copyCacheStateToDir;
rr_deallocateL2CacheBlock;
uu_profileMiss;
o_popL1RequestQueue;
}
transition(OLS, L1_GETS, OLSS) {
d_sendDataToL1GETS;
r_setMRU;
uu_profileHit;
o_popL1RequestQueue;
}
transition(OLSS, Unblock, OLS) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(IGMO, Fwd_GETX, IGM) {
t_recordFwdXID;
c_sendDataFromTBEToFwdGETX;
m_popRequestQueue;
}
transition(IGMO, Fwd_GETS) {
t_recordFwdSID;
c_sendDataFromTBEToFwdGETS;
m_popRequestQueue;
}
// LOCAL REQUESTS SATISFIED DIRECTLY BY L2
transition(M, L1_GETX, MM) {
i_allocateTBE;
// should count 0 of course
h_countLocalSharersExceptRequestor;
d_sendDataToL1GETX;
y_copyCacheStateToDir;
rr_deallocateL2CacheBlock;
s_deallocateTBE;
uu_profileHit;
o_popL1RequestQueue;
}
transition(MM, Exclusive_Unblock, ILX) {
g_recordLocalExclusive;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(M, L1_GETS, OO) {
i_allocateTBE;
// should count 0 of course
h_countLocalSharersExceptRequestor;
d_sendDataToL1GETX;
r_setMRU;
s_deallocateTBE;
uu_profileHit;
o_popL1RequestQueue;
}
transition(S, L1_GETS, SS) {
d_sendDataToL1GETS;
r_setMRU;
uu_profileHit;
o_popL1RequestQueue;
}
transition(SS, Unblock, SLS) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(O, L1_GETS, OO) {
d_sendDataToL1GETS;
r_setMRU;
uu_profileHit;
o_popL1RequestQueue;
}
transition(OO, Unblock, OLS) {
g_recordLocalSharer;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(OO, Exclusive_Unblock, ILX) {
g_recordLocalExclusive
y_copyCacheStateToDir;
rr_deallocateL2CacheBlock;
n_popResponseQueue;
wa_wakeUpDependents;
}
// L1 WRITEBACKS
transition(ILO, L1_PUTO, ILOW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
transition(ILOX, L1_PUTO, ILOXW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
transition(ILOS, L1_PUTO, ILOSW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
transition(ILOSX, L1_PUTO, ILOSXW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
// hmmm...keep data or drop. Just drop for now
transition(ILOS, L1_PUTS_only, ILOW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(ILSW, Unblock, ILS) {
gg_clearSharerFromL1Response;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILOW, Unblock, ILO) {
gg_clearSharerFromL1Response;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILOSX, L1_PUTS_only, ILOXW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(ILOXW, Unblock, ILOX) {
gg_clearSharerFromL1Response;
n_popResponseQueue;
wa_wakeUpDependents;
}
// hmmm...keep data or drop. Just drop for now
transition(ILOS, L1_PUTS, ILOSW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(ILOSX, L1_PUTS, ILOSXW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(ILOSW, Unblock, ILOS) {
gg_clearSharerFromL1Response;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(ILOSXW, Unblock, ILOSX) {
gg_clearSharerFromL1Response;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(SLS, L1_PUTS, SLSW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(SLS, L1_PUTS_only, SW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(SW, {Unblock}, S) {
gg_clearSharerFromL1Response;
n_popResponseQueue;
wa_wakeUpDependents;
}
transition(OLS, L1_PUTS, OLSW) {
l_writebackAckDropData;
o_popL1RequestQueue;
}
transition(ILS, L1_PUTS, ILSW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}
transition(ILS, L1_PUTS_only, IW) {
l_writebackAckNeedData;
o_popL1RequestQueue;
}