summaryrefslogtreecommitdiff
path: root/src/mem/protocol/MOESI_AMD_Base-probeFilter.sm
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/protocol/MOESI_AMD_Base-probeFilter.sm')
-rw-r--r--src/mem/protocol/MOESI_AMD_Base-probeFilter.sm1408
1 files changed, 1408 insertions, 0 deletions
diff --git a/src/mem/protocol/MOESI_AMD_Base-probeFilter.sm b/src/mem/protocol/MOESI_AMD_Base-probeFilter.sm
new file mode 100644
index 000000000..f545c2fa7
--- /dev/null
+++ b/src/mem/protocol/MOESI_AMD_Base-probeFilter.sm
@@ -0,0 +1,1408 @@
+/*
+ * Copyright (c) 2013-2015 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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 HOLDER 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.
+ *
+ * Author: Lisa Hsu, Sooraj Puthoor
+ */
+
+/*
+ * This file is based on MOESI_AMD_Base.sm
+ * Differences with AMD base protocol
+ * -- Uses a probe filter memory to track sharers.
+ * -- The probe filter can be inclusive or non-inclusive
+ * -- Only two sharers tracked. Sharers are a) GPU or/and b) CPU
+ * -- If sharer information available, the sharer is probed
+ * -- If sharer information not available, probes are broadcasted
+ */
+
+machine(MachineType:Directory, "AMD Baseline protocol")
+: DirectoryMemory * directory;
+ CacheMemory * L3CacheMemory;
+ CacheMemory * ProbeFilterMemory;
+ Cycles response_latency := 5;
+ Cycles l3_hit_latency := 50;
+ bool noTCCdir := "False";
+ bool CAB_TCC := "False";
+ int TCC_select_num_bits:=1;
+ bool useL3OnWT := "False";
+ bool inclusiveDir := "True";
+ Cycles to_memory_controller_latency := 1;
+
+ // From the Cores
+ MessageBuffer * requestFromCores, network="From", virtual_network="0", ordered="false", vnet_type="request";
+ MessageBuffer * responseFromCores, network="From", virtual_network="2", ordered="false", vnet_type="response";
+ MessageBuffer * unblockFromCores, network="From", virtual_network="4", ordered="false", vnet_type="unblock";
+
+ MessageBuffer * probeToCore, network="To", virtual_network="0", ordered="false", vnet_type="request";
+ MessageBuffer * responseToCore, network="To", virtual_network="2", ordered="false", vnet_type="response";
+
+ MessageBuffer * triggerQueue, ordered="true";
+ MessageBuffer * L3triggerQueue, ordered="true";
+ MessageBuffer * responseFromMemory;
+{
+ // STATES
+ state_declaration(State, desc="Directory states", default="Directory_State_U") {
+ U, AccessPermission:Backing_Store, desc="unblocked";
+ BL, AccessPermission:Busy, desc="got L3 WB request";
+ // BL is Busy because it is busy waiting for the data
+ // which is possibly in the network. The cache which evicted the data
+ // might have moved to some other state after doing the eviction
+ // BS==> Received a read request; has not requested ownership
+ // B==> Received a read request; has requested ownership
+ // BM==> Received a modification request
+ B_P, AccessPermission:Backing_Store, desc="Back invalidation, waiting for probes";
+ BS_M, AccessPermission:Backing_Store, desc="blocked waiting for memory";
+ BM_M, AccessPermission:Backing_Store, desc="blocked waiting for memory";
+ B_M, AccessPermission:Backing_Store, desc="blocked waiting for memory";
+ BP, AccessPermission:Backing_Store, desc="blocked waiting for probes, no need for memory";
+ BS_PM, AccessPermission:Backing_Store, desc="blocked waiting for probes and Memory";
+ BM_PM, AccessPermission:Backing_Store, desc="blocked waiting for probes and Memory";
+ B_PM, AccessPermission:Backing_Store, desc="blocked waiting for probes and Memory";
+ BS_Pm, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory";
+ BM_Pm, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory";
+ B_Pm, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory";
+ B, AccessPermission:Backing_Store, desc="sent response, Blocked til ack";
+ }
+
+ // Events
+ enumeration(Event, desc="Directory events") {
+ // CPU requests
+ RdBlkS, desc="...";
+ RdBlkM, desc="...";
+ RdBlk, desc="...";
+ CtoD, desc="...";
+ WriteThrough, desc="WriteThrough Message";
+ Atomic, desc="Atomic Message";
+
+ // writebacks
+ VicDirty, desc="...";
+ VicClean, desc="...";
+ CPUData, desc="WB data from CPU";
+ StaleWB, desc="Notification that WB has been superceded by a probe";
+
+ // probe responses
+ CPUPrbResp, desc="Probe Response Msg";
+
+ ProbeAcksComplete, desc="Probe Acks Complete";
+
+ L3Hit, desc="Hit in L3 return data to core";
+
+ // Replacement
+ PF_Repl, desc="Replace address from probe filter";
+
+ // Memory Controller
+ MemData, desc="Fetched data from memory arrives";
+ WBAck, desc="Writeback Ack from memory arrives";
+
+ CoreUnblock, desc="Core received data, unblock";
+ UnblockWriteThrough, desc="Unblock because of writethrough request finishing";
+
+ StaleVicDirty, desc="Core invalidated before VicDirty processed";
+ }
+
+ enumeration(RequestType, desc="To communicate stats from transitions to recordStats") {
+ L3DataArrayRead, desc="Read the data array";
+ L3DataArrayWrite, desc="Write the data array";
+ L3TagArrayRead, desc="Read the data array";
+ L3TagArrayWrite, desc="Write the data array";
+
+ PFTagArrayRead, desc="Read the data array";
+ PFTagArrayWrite, desc="Write the data array";
+ }
+
+ // TYPES
+
+ enumeration(ProbeFilterState, desc="") {
+ T, desc="Tracked";
+ NT, desc="Not tracked";
+ B, desc="Blocked, This entry is being replaced";
+ }
+
+ // DirectoryEntry
+ structure(Entry, desc="...", interface="AbstractEntry") {
+ State DirectoryState, desc="Directory state";
+ DataBlock DataBlk, desc="data for the block";
+ NetDest VicDirtyIgnore, desc="VicDirty coming from whom to ignore";
+ }
+
+ structure(CacheEntry, desc="...", interface="AbstractCacheEntry") {
+ DataBlock DataBlk, desc="data for the block";
+ MachineID LastSender, desc="Mach which this block came from";
+ ProbeFilterState pfState, desc="ProbeFilter state",default="Directory_ProbeFilterState_NT";
+ bool isOnCPU, desc="Block valid in the CPU complex",default="false";
+ bool isOnGPU, desc="Block valid in the GPU complex",default="false";
+ }
+
+ structure(TBE, desc="...") {
+ State TBEState, desc="Transient state";
+ DataBlock DataBlk, desc="data for the block";
+ bool Dirty, desc="Is the data dirty?";
+ int NumPendingAcks, desc="num acks expected";
+ MachineID OriginalRequestor, desc="Original Requestor";
+ MachineID WTRequestor, desc="WT Requestor";
+ bool Cached, desc="data hit in Cache";
+ bool MemData, desc="Got MemData?",default="false";
+ bool wtData, desc="Got write through data?",default="false";
+ bool atomicData, desc="Got Atomic op?",default="false";
+ Cycles InitialRequestTime, desc="...";
+ Cycles ForwardRequestTime, desc="...";
+ Cycles ProbeRequestStartTime, desc="...";
+ MachineID LastSender, desc="Mach which this block came from";
+ bool L3Hit, default="false", desc="Was this an L3 hit?";
+ uint64_t probe_id, desc="probe id for lifetime profiling";
+ WriteMask writeMask, desc="outstanding write through mask";
+ Addr demandAddress, desc="Address of demand request which caused probe filter eviction";
+ }
+
+ structure(TBETable, external="yes") {
+ TBE lookup(Addr);
+ void allocate(Addr);
+ void deallocate(Addr);
+ bool isPresent(Addr);
+ }
+
+ TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
+
+ int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()";
+
+ Tick clockEdge();
+ Tick cyclesToTicks(Cycles c);
+
+ void set_tbe(TBE a);
+ void unset_tbe();
+ void wakeUpAllBuffers();
+ void wakeUpBuffers(Addr a);
+ Cycles curCycle();
+
+ Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
+ Entry dir_entry := static_cast(Entry, "pointer", directory.lookup(addr));
+
+ if (is_valid(dir_entry)) {
+ //DPRINTF(RubySlicc, "Getting entry %s: %s\n", addr, dir_entry.DataBlk);
+ return dir_entry;
+ }
+
+ dir_entry := static_cast(Entry, "pointer",
+ directory.allocate(addr, new Entry));
+ return dir_entry;
+ }
+
+ DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
+ TBE tbe := TBEs.lookup(addr);
+ if (is_valid(tbe) && tbe.MemData) {
+ DPRINTF(RubySlicc, "Returning DataBlk from TBE %s:%s\n", addr, tbe);
+ return tbe.DataBlk;
+ }
+ DPRINTF(RubySlicc, "Returning DataBlk from Dir %s:%s\n", addr, getDirectoryEntry(addr));
+ return getDirectoryEntry(addr).DataBlk;
+ }
+
+ State getState(TBE tbe, CacheEntry entry, Addr addr) {
+ CacheEntry probeFilterEntry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.lookup(addr));
+ if (inclusiveDir) {
+ if (is_valid(probeFilterEntry) && probeFilterEntry.pfState == ProbeFilterState:B) {
+ return State:B_P;
+ }
+ }
+ return getDirectoryEntry(addr).DirectoryState;
+ }
+
+ void setState(TBE tbe, CacheEntry entry, Addr addr, State state) {
+ getDirectoryEntry(addr).DirectoryState := state;
+ }
+
+ void functionalRead(Addr addr, Packet *pkt) {
+ TBE tbe := TBEs.lookup(addr);
+ if(is_valid(tbe)) {
+ testAndRead(addr, tbe.DataBlk, pkt);
+ } else {
+ functionalMemoryRead(pkt);
+ }
+ }
+
+ int functionalWrite(Addr addr, Packet *pkt) {
+ int num_functional_writes := 0;
+
+ TBE tbe := TBEs.lookup(addr);
+ if(is_valid(tbe)) {
+ num_functional_writes := num_functional_writes +
+ testAndWrite(addr, tbe.DataBlk, pkt);
+ }
+
+ num_functional_writes := num_functional_writes +
+ functionalMemoryWrite(pkt);
+ return num_functional_writes;
+ }
+
+ AccessPermission getAccessPermission(Addr addr) {
+ // For this Directory, all permissions are just tracked in Directory, since
+ // it's not possible to have something in TBE but not Dir, just keep track
+ // of state all in one place.
+ if (directory.isPresent(addr)) {
+ return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+ }
+
+ return AccessPermission:NotPresent;
+ }
+
+ void setAccessPermission(CacheEntry entry, Addr addr, State state) {
+ getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
+ }
+
+ void recordRequestType(RequestType request_type, Addr addr) {
+ if (request_type == RequestType:L3DataArrayRead) {
+ L3CacheMemory.recordRequestType(CacheRequestType:DataArrayRead, addr);
+ } else if (request_type == RequestType:L3DataArrayWrite) {
+ L3CacheMemory.recordRequestType(CacheRequestType:DataArrayWrite, addr);
+ } else if (request_type == RequestType:L3TagArrayRead) {
+ L3CacheMemory.recordRequestType(CacheRequestType:TagArrayRead, addr);
+ } else if (request_type == RequestType:L3TagArrayWrite) {
+ L3CacheMemory.recordRequestType(CacheRequestType:TagArrayWrite, addr);
+ } else if (request_type == RequestType:PFTagArrayRead) {
+ ProbeFilterMemory.recordRequestType(CacheRequestType:TagArrayRead, addr);
+ } else if (request_type == RequestType:PFTagArrayWrite) {
+ ProbeFilterMemory.recordRequestType(CacheRequestType:TagArrayWrite, addr);
+ }
+ }
+
+ bool checkResourceAvailable(RequestType request_type, Addr addr) {
+ if (request_type == RequestType:L3DataArrayRead) {
+ return L3CacheMemory.checkResourceAvailable(CacheResourceType:DataArray, addr);
+ } else if (request_type == RequestType:L3DataArrayWrite) {
+ return L3CacheMemory.checkResourceAvailable(CacheResourceType:DataArray, addr);
+ } else if (request_type == RequestType:L3TagArrayRead) {
+ return L3CacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr);
+ } else if (request_type == RequestType:L3TagArrayWrite) {
+ return L3CacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr);
+ } else if (request_type == RequestType:PFTagArrayRead) {
+ return ProbeFilterMemory.checkResourceAvailable(CacheResourceType:TagArray, addr);
+ } else if (request_type == RequestType:PFTagArrayWrite) {
+ return ProbeFilterMemory.checkResourceAvailable(CacheResourceType:TagArray, addr);
+ } else {
+ error("Invalid RequestType type in checkResourceAvailable");
+ return true;
+ }
+ }
+
+ bool isNotPresentProbeFilter(Addr address) {
+ if (ProbeFilterMemory.isTagPresent(address) ||
+ ProbeFilterMemory.cacheAvail(address)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool isGPUSharer(Addr address) {
+ assert(ProbeFilterMemory.isTagPresent(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.lookup(address));
+ if (entry.pfState == ProbeFilterState:NT) {
+ return true;
+ } else if (entry.isOnGPU){
+ return true;
+ }
+ return false;
+ }
+
+ bool isCPUSharer(Addr address) {
+ assert(ProbeFilterMemory.isTagPresent(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.lookup(address));
+ if (entry.pfState == ProbeFilterState:NT) {
+ return true;
+ } else if (entry.isOnCPU){
+ return true;
+ }
+ return false;
+ }
+
+
+ // ** OUT_PORTS **
+ out_port(probeNetwork_out, NBProbeRequestMsg, probeToCore);
+ out_port(responseNetwork_out, ResponseMsg, responseToCore);
+
+ out_port(triggerQueue_out, TriggerMsg, triggerQueue);
+ out_port(L3TriggerQueue_out, TriggerMsg, L3triggerQueue);
+
+ // ** IN_PORTS **
+
+ // Trigger Queue
+ in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=5) {
+ if (triggerQueue_in.isReady(clockEdge())) {
+ peek(triggerQueue_in, TriggerMsg) {
+ TBE tbe := TBEs.lookup(in_msg.addr);
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
+ if (in_msg.Type == TriggerType:AcksComplete) {
+ trigger(Event:ProbeAcksComplete, in_msg.addr, entry, tbe);
+ }else if (in_msg.Type == TriggerType:UnblockWriteThrough) {
+ trigger(Event:UnblockWriteThrough, in_msg.addr, entry, tbe);
+ } else {
+ error("Unknown trigger msg");
+ }
+ }
+ }
+ }
+
+ in_port(L3TriggerQueue_in, TriggerMsg, L3triggerQueue, rank=4) {
+ if (L3TriggerQueue_in.isReady(clockEdge())) {
+ peek(L3TriggerQueue_in, TriggerMsg) {
+ TBE tbe := TBEs.lookup(in_msg.addr);
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
+ if (in_msg.Type == TriggerType:L3Hit) {
+ trigger(Event:L3Hit, in_msg.addr, entry, tbe);
+ } else {
+ error("Unknown trigger msg");
+ }
+ }
+ }
+ }
+
+ // Unblock Network
+ in_port(unblockNetwork_in, UnblockMsg, unblockFromCores, rank=3) {
+ if (unblockNetwork_in.isReady(clockEdge())) {
+ peek(unblockNetwork_in, UnblockMsg) {
+ TBE tbe := TBEs.lookup(in_msg.addr);
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
+ trigger(Event:CoreUnblock, in_msg.addr, entry, tbe);
+ }
+ }
+ }
+
+ // Core response network
+ in_port(responseNetwork_in, ResponseMsg, responseFromCores, rank=2) {
+ if (responseNetwork_in.isReady(clockEdge())) {
+ peek(responseNetwork_in, ResponseMsg) {
+ TBE tbe := TBEs.lookup(in_msg.addr);
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
+ if (in_msg.Type == CoherenceResponseType:CPUPrbResp) {
+ trigger(Event:CPUPrbResp, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:CPUData) {
+ trigger(Event:CPUData, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:StaleNotif) {
+ trigger(Event:StaleWB, in_msg.addr, entry, tbe);
+ } else {
+ error("Unexpected response type");
+ }
+ }
+ }
+ }
+
+ // off-chip memory request/response is done
+ in_port(memQueue_in, MemoryMsg, responseFromMemory, rank=1) {
+ if (memQueue_in.isReady(clockEdge())) {
+ peek(memQueue_in, MemoryMsg) {
+ TBE tbe := TBEs.lookup(in_msg.addr);
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
+ if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
+ trigger(Event:MemData, in_msg.addr, entry, tbe);
+ DPRINTF(RubySlicc, "%s\n", in_msg);
+ } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
+ trigger(Event:WBAck, in_msg.addr, entry, tbe); // ignore WBAcks, don't care about them.
+ } else {
+ DPRINTF(RubySlicc, "%s\n", in_msg.Type);
+ error("Invalid message");
+ }
+ }
+ }
+ }
+
+ in_port(requestNetwork_in, CPURequestMsg, requestFromCores, rank=0) {
+ if (requestNetwork_in.isReady(clockEdge())) {
+ peek(requestNetwork_in, CPURequestMsg) {
+ TBE tbe := TBEs.lookup(in_msg.addr);
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
+ if (inclusiveDir && isNotPresentProbeFilter(in_msg.addr)) {
+ Addr victim := ProbeFilterMemory.cacheProbe(in_msg.addr);
+ tbe := TBEs.lookup(victim);
+ entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(victim));
+ trigger(Event:PF_Repl, victim, entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:RdBlk) {
+ trigger(Event:RdBlk, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:RdBlkS) {
+ trigger(Event:RdBlkS, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:RdBlkM) {
+ trigger(Event:RdBlkM, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:WriteThrough) {
+ trigger(Event:WriteThrough, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:Atomic) {
+ trigger(Event:Atomic, in_msg.addr, entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:VicDirty) {
+ if (getDirectoryEntry(in_msg.addr).VicDirtyIgnore.isElement(in_msg.Requestor)) {
+ DPRINTF(RubySlicc, "Dropping VicDirty for address %s\n", in_msg.addr);
+ trigger(Event:StaleVicDirty, in_msg.addr, entry, tbe);
+ } else {
+ DPRINTF(RubySlicc, "Got VicDirty from %s on %s\n", in_msg.Requestor, in_msg.addr);
+ trigger(Event:VicDirty, in_msg.addr, entry, tbe);
+ }
+ } else if (in_msg.Type == CoherenceRequestType:VicClean) {
+ if (getDirectoryEntry(in_msg.addr).VicDirtyIgnore.isElement(in_msg.Requestor)) {
+ DPRINTF(RubySlicc, "Dropping VicClean for address %s\n", in_msg.addr);
+ trigger(Event:StaleVicDirty, in_msg.addr, entry, tbe);
+ } else {
+ DPRINTF(RubySlicc, "Got VicClean from %s on %s\n", in_msg.Requestor, in_msg.addr);
+ trigger(Event:VicClean, in_msg.addr, entry, tbe);
+ }
+ } else {
+ error("Bad request message type");
+ }
+ }
+ }
+ }
+
+ // Actions
+ action(s_sendResponseS, "s", desc="send Shared response") {
+ enqueue(responseNetwork_out, ResponseMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceResponseType:NBSysResp;
+ if (tbe.L3Hit) {
+ out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0));
+ } else {
+ out_msg.Sender := machineID;
+ }
+ out_msg.Destination.add(tbe.OriginalRequestor);
+ out_msg.DataBlk := tbe.DataBlk;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ out_msg.Dirty := false;
+ out_msg.State := CoherenceState:Shared;
+ out_msg.InitialRequestTime := tbe.InitialRequestTime;
+ out_msg.ForwardRequestTime := tbe.ForwardRequestTime;
+ out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
+ out_msg.OriginalResponder := tbe.LastSender;
+ out_msg.L3Hit := tbe.L3Hit;
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ }
+ }
+
+ action(es_sendResponseES, "es", desc="send Exclusive or Shared response") {
+ enqueue(responseNetwork_out, ResponseMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceResponseType:NBSysResp;
+ if (tbe.L3Hit) {
+ out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0));
+ } else {
+ out_msg.Sender := machineID;
+ }
+ out_msg.Destination.add(tbe.OriginalRequestor);
+ out_msg.DataBlk := tbe.DataBlk;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ out_msg.Dirty := tbe.Dirty;
+ if (tbe.Cached) {
+ out_msg.State := CoherenceState:Shared;
+ } else {
+ out_msg.State := CoherenceState:Exclusive;
+ }
+ out_msg.InitialRequestTime := tbe.InitialRequestTime;
+ out_msg.ForwardRequestTime := tbe.ForwardRequestTime;
+ out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
+ out_msg.OriginalResponder := tbe.LastSender;
+ out_msg.L3Hit := tbe.L3Hit;
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ }
+ }
+
+ // write-through and atomics do not send an unblock ack back to the
+ // directory. Hence, directory has to generate a self unblocking
+ // message. Additionally, write through's does not require data
+ // in its response. Hence, write through is treated seperately from
+ // write-back and atomics
+ action(m_sendResponseM, "m", desc="send Modified response") {
+ if (tbe.wtData) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:UnblockWriteThrough;
+ }
+ }else{
+ enqueue(responseNetwork_out, ResponseMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceResponseType:NBSysResp;
+ if (tbe.L3Hit) {
+ out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0));
+ } else {
+ out_msg.Sender := machineID;
+ }
+ out_msg.Destination.add(tbe.OriginalRequestor);
+ out_msg.DataBlk := tbe.DataBlk;
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ out_msg.Dirty := tbe.Dirty;
+ out_msg.State := CoherenceState:Modified;
+ out_msg.CtoD := false;
+ out_msg.InitialRequestTime := tbe.InitialRequestTime;
+ out_msg.ForwardRequestTime := tbe.ForwardRequestTime;
+ out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
+ out_msg.OriginalResponder := tbe.LastSender;
+ if(tbe.atomicData){
+ out_msg.WTRequestor := tbe.WTRequestor;
+ }
+ out_msg.L3Hit := tbe.L3Hit;
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ }
+ if (tbe.atomicData) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:UnblockWriteThrough;
+ }
+ }
+ }
+ }
+
+ action(c_sendResponseCtoD, "c", desc="send CtoD Ack") {
+ enqueue(responseNetwork_out, ResponseMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceResponseType:NBSysResp;
+ out_msg.Sender := machineID;
+ out_msg.Destination.add(tbe.OriginalRequestor);
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ out_msg.Dirty := false;
+ out_msg.State := CoherenceState:Modified;
+ out_msg.CtoD := true;
+ out_msg.InitialRequestTime := tbe.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ }
+ }
+
+ action(w_sendResponseWBAck, "w", desc="send WB Ack") {
+ peek(requestNetwork_in, CPURequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceResponseType:NBSysWBAck;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.WTRequestor := in_msg.WTRequestor;
+ out_msg.Sender := machineID;
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ out_msg.ProbeRequestStartTime := curCycle();
+ }
+ }
+ }
+
+ action(l_queueMemWBReq, "lq", desc="Write WB data to memory") {
+ peek(responseNetwork_in, ResponseMsg) {
+ queueMemoryWrite(machineID, address, to_memory_controller_latency,
+ in_msg.DataBlk);
+ }
+ }
+
+ action(l_queueMemRdReq, "lr", desc="Read data from memory") {
+ peek(requestNetwork_in, CPURequestMsg) {
+ if (L3CacheMemory.isTagPresent(address)) {
+ enqueue(L3TriggerQueue_out, TriggerMsg, l3_hit_latency) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:L3Hit;
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ }
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address));
+ tbe.DataBlk := entry.DataBlk;
+ tbe.LastSender := entry.LastSender;
+ tbe.L3Hit := true;
+ tbe.MemData := true;
+ L3CacheMemory.deallocate(address);
+ } else {
+ queueMemoryRead(machineID, address, to_memory_controller_latency);
+ }
+ }
+ }
+
+ action(dc_probeInvCoreData, "dc", desc="probe inv cores, return data") {
+ peek(requestNetwork_in, CPURequestMsg) {
+ enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := ProbeRequestType:PrbInv;
+ out_msg.ReturnData := true;
+ out_msg.MessageSize := MessageSizeType:Control;
+ if(isCPUSharer(address)) {
+ out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket
+ }
+
+ // add relevant TCC node to list. This replaces all TCPs and SQCs
+ if(isGPUSharer(address)) {
+ if ((in_msg.Type == CoherenceRequestType:WriteThrough ||
+ in_msg.Type == CoherenceRequestType:Atomic) &&
+ in_msg.NoWriteConflict) {
+ // Don't Include TCCs unless there was write-CAB conflict in the TCC
+ } else if(noTCCdir) {
+ out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
+ TCC_select_low_bit, TCC_select_num_bits));
+ } else {
+ out_msg.Destination.add(map_Address_to_TCCdir(address));
+ }
+ }
+ out_msg.Destination.remove(in_msg.Requestor);
+ tbe.NumPendingAcks := out_msg.Destination.count();
+ if (tbe.NumPendingAcks == 0) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:AcksComplete;
+ }
+ }
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ APPEND_TRANSITION_COMMENT(" dc: Acks remaining: ");
+ APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
+ tbe.ProbeRequestStartTime := curCycle();
+ }
+ }
+ }
+
+ action(bp_backProbe, "bp", desc="back probe") {
+ enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := ProbeRequestType:PrbInv;
+ out_msg.ReturnData := true;
+ out_msg.MessageSize := MessageSizeType:Control;
+ if(isCPUSharer(address)) {
+ // won't be realistic for multisocket
+ out_msg.Destination.broadcast(MachineType:CorePair);
+ }
+ // add relevant TCC node to the list. This replaces all TCPs and SQCs
+ if(isGPUSharer(address)) {
+ if (noTCCdir) {
+ //Don't need to notify TCC about reads
+ } else {
+ out_msg.Destination.add(map_Address_to_TCCdir(address));
+ tbe.NumPendingAcks := tbe.NumPendingAcks + 1;
+ }
+ if (noTCCdir && CAB_TCC) {
+ out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
+ TCC_select_low_bit, TCC_select_num_bits));
+ }
+ }
+ tbe.NumPendingAcks := out_msg.Destination.count();
+ if (tbe.NumPendingAcks == 0) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:AcksComplete;
+ }
+ }
+ DPRINTF(RubySlicc, "%s\n", (out_msg));
+ APPEND_TRANSITION_COMMENT(" sc: Acks remaining: ");
+ APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
+ APPEND_TRANSITION_COMMENT(" - back probe");
+ tbe.ProbeRequestStartTime := curCycle();
+ }
+ }
+
+ action(sc_probeShrCoreData, "sc", desc="probe shared cores, return data") {
+ peek(requestNetwork_in, CPURequestMsg) { // not the right network?
+ enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := ProbeRequestType:PrbDowngrade;
+ out_msg.ReturnData := true;
+ out_msg.MessageSize := MessageSizeType:Control;
+ if(isCPUSharer(address)) {
+ out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket
+ }
+ // add relevant TCC node to the list. This replaces all TCPs and SQCs
+ if(isGPUSharer(address)) {
+ if (noTCCdir) {
+ //Don't need to notify TCC about reads
+ } else {
+ out_msg.Destination.add(map_Address_to_TCCdir(address));
+ tbe.NumPendingAcks := tbe.NumPendingAcks + 1;
+ }
+ if (noTCCdir && CAB_TCC) {
+ out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
+ TCC_select_low_bit, TCC_select_num_bits));
+ }
+ }
+ out_msg.Destination.remove(in_msg.Requestor);
+ tbe.NumPendingAcks := out_msg.Destination.count();
+ if (tbe.NumPendingAcks == 0) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:AcksComplete;
+ }
+ }
+ DPRINTF(RubySlicc, "%s\n", (out_msg));
+ APPEND_TRANSITION_COMMENT(" sc: Acks remaining: ");
+ APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
+ tbe.ProbeRequestStartTime := curCycle();
+ }
+ }
+ }
+
+ action(ic_probeInvCore, "ic", desc="probe invalidate core, no return data needed") {
+ peek(requestNetwork_in, CPURequestMsg) { // not the right network?
+ enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
+ out_msg.addr := address;
+ out_msg.Type := ProbeRequestType:PrbInv;
+ out_msg.ReturnData := false;
+ out_msg.MessageSize := MessageSizeType:Control;
+ if(isCPUSharer(address)) {
+ out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket
+ }
+
+ // add relevant TCC node to the list. This replaces all TCPs and SQCs
+ if(isGPUSharer(address)) {
+ if (noTCCdir) {
+ out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
+ TCC_select_low_bit, TCC_select_num_bits));
+ } else {
+ out_msg.Destination.add(map_Address_to_TCCdir(address));
+ }
+ }
+ out_msg.Destination.remove(in_msg.Requestor);
+ tbe.NumPendingAcks := out_msg.Destination.count();
+ if (tbe.NumPendingAcks == 0) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:AcksComplete;
+ }
+ }
+ APPEND_TRANSITION_COMMENT(" ic: Acks remaining: ");
+ APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
+ DPRINTF(RubySlicc, "%s\n", out_msg);
+ tbe.ProbeRequestStartTime := curCycle();
+ }
+ }
+ }
+
+ action(sm_setMRU, "sm", desc="set probe filter entry as MRU") {
+ ProbeFilterMemory.setMRU(address);
+ }
+
+ action(d_writeDataToMemory, "d", desc="Write data to memory") {
+ peek(responseNetwork_in, ResponseMsg) {
+ getDirectoryEntry(address).DataBlk := in_msg.DataBlk;
+ DPRINTF(RubySlicc, "Writing Data: %s to address %s\n", in_msg.DataBlk,
+ in_msg.addr);
+ }
+ }
+
+ action(te_allocateTBEForEviction, "te", desc="allocate TBE Entry") {
+ check_allocate(TBEs);
+ TBEs.allocate(address);
+ set_tbe(TBEs.lookup(address));
+ tbe.writeMask.clear();
+ tbe.wtData := false;
+ tbe.atomicData := false;
+ tbe.DataBlk := getDirectoryEntry(address).DataBlk; // Data only for WBs
+ tbe.Dirty := false;
+ tbe.NumPendingAcks := 0;
+ }
+
+ action(t_allocateTBE, "t", desc="allocate TBE Entry") {
+ check_allocate(TBEs);
+ peek(requestNetwork_in, CPURequestMsg) {
+ TBEs.allocate(address);
+ set_tbe(TBEs.lookup(address));
+ if (in_msg.Type == CoherenceRequestType:WriteThrough) {
+ tbe.writeMask.clear();
+ tbe.writeMask.orMask(in_msg.writeMask);
+ tbe.wtData := true;
+ tbe.WTRequestor := in_msg.WTRequestor;
+ tbe.LastSender := in_msg.Requestor;
+ }
+ if (in_msg.Type == CoherenceRequestType:Atomic) {
+ tbe.writeMask.clear();
+ tbe.writeMask.orMask(in_msg.writeMask);
+ tbe.atomicData := true;
+ tbe.WTRequestor := in_msg.WTRequestor;
+ tbe.LastSender := in_msg.Requestor;
+ }
+ tbe.DataBlk := getDirectoryEntry(address).DataBlk; // Data only for WBs
+ tbe.Dirty := false;
+ if (in_msg.Type == CoherenceRequestType:WriteThrough) {
+ tbe.DataBlk.copyPartial(in_msg.DataBlk,tbe.writeMask);
+ tbe.Dirty := false;
+ }
+ tbe.OriginalRequestor := in_msg.Requestor;
+ tbe.NumPendingAcks := 0;
+ tbe.Cached := in_msg.ForceShared;
+ tbe.InitialRequestTime := in_msg.InitialRequestTime;
+ }
+ }
+
+ action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") {
+ if (tbe.Dirty == false) {
+ getDirectoryEntry(address).DataBlk := tbe.DataBlk;
+ }
+ TBEs.deallocate(address);
+ unset_tbe();
+ }
+
+ action(wd_writeBackData, "wd", desc="Write back data if needed") {
+ if (tbe.wtData) {
+ DataBlock tmp := getDirectoryEntry(address).DataBlk;
+ tmp.copyPartial(tbe.DataBlk,tbe.writeMask);
+ tbe.DataBlk := tmp;
+ getDirectoryEntry(address).DataBlk := tbe.DataBlk;
+ } else if (tbe.atomicData) {
+ tbe.DataBlk.atomicPartial(getDirectoryEntry(address).DataBlk,
+ tbe.writeMask);
+ getDirectoryEntry(address).DataBlk := tbe.DataBlk;
+ } else if (tbe.Dirty == false) {
+ getDirectoryEntry(address).DataBlk := tbe.DataBlk;
+ }
+ }
+
+ action(mt_writeMemDataToTBE, "mt", desc="write Mem data to TBE") {
+ peek(memQueue_in, MemoryMsg) {
+ if (tbe.wtData == true) {
+ // DO Nothing (already have the directory data)
+ } else if (tbe.Dirty == false) {
+ tbe.DataBlk := getDirectoryEntry(address).DataBlk;
+ }
+ tbe.MemData := true;
+ }
+ }
+
+ action(y_writeProbeDataToTBE, "y", desc="write Probe Data to TBE") {
+ peek(responseNetwork_in, ResponseMsg) {
+ if (in_msg.Dirty) {
+ DPRINTF(RubySlicc, "Got dirty data for %s from %s\n", address, in_msg.Sender);
+ DPRINTF(RubySlicc, "Data is %s\n", in_msg.DataBlk);
+ if (tbe.wtData) {
+ DataBlock tmp := in_msg.DataBlk;
+ tmp.copyPartial(tbe.DataBlk,tbe.writeMask);
+ tbe.DataBlk := tmp;
+ } else if (tbe.Dirty) {
+ if(tbe.atomicData == false && tbe.wtData == false) {
+ DPRINTF(RubySlicc, "Got double data for %s from %s\n", address, in_msg.Sender);
+ assert(tbe.DataBlk == in_msg.DataBlk); // in case of double data
+ }
+ } else {
+ tbe.DataBlk := in_msg.DataBlk;
+ tbe.Dirty := in_msg.Dirty;
+ tbe.LastSender := in_msg.Sender;
+ }
+ }
+ if (in_msg.Hit) {
+ tbe.Cached := true;
+ }
+ }
+ }
+
+ action(mwc_markSinkWriteCancel, "mwc", desc="Mark to sink impending VicDirty") {
+ peek(responseNetwork_in, ResponseMsg) {
+ DPRINTF(RubySlicc, "Write cancel bit set on address %s\n", address);
+ getDirectoryEntry(address).VicDirtyIgnore.add(in_msg.Sender);
+ APPEND_TRANSITION_COMMENT(" setting bit to sink VicDirty ");
+ }
+ }
+
+ action(x_decrementAcks, "x", desc="decrement Acks pending") {
+ tbe.NumPendingAcks := tbe.NumPendingAcks - 1;
+ APPEND_TRANSITION_COMMENT(" Acks remaining: ");
+ APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
+ }
+
+ action(o_checkForCompletion, "o", desc="check for ack completion") {
+ if (tbe.NumPendingAcks == 0) {
+ enqueue(triggerQueue_out, TriggerMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:AcksComplete;
+ }
+ }
+ APPEND_TRANSITION_COMMENT(" Check: Acks remaining: ");
+ APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
+ }
+
+ action(rv_removeVicDirtyIgnore, "rv", desc="Remove ignored core") {
+ peek(requestNetwork_in, CPURequestMsg) {
+ getDirectoryEntry(address).VicDirtyIgnore.remove(in_msg.Requestor);
+ }
+ }
+
+ action(al_allocateL3Block, "al", desc="allocate the L3 block on WB") {
+ peek(responseNetwork_in, ResponseMsg) {
+ if (L3CacheMemory.isTagPresent(address)) {
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address));
+ APPEND_TRANSITION_COMMENT(" al wrote data to L3 (hit) ");
+ entry.DataBlk := in_msg.DataBlk;
+ entry.LastSender := in_msg.Sender;
+ } else {
+ if (L3CacheMemory.cacheAvail(address) == false) {
+ Addr victim := L3CacheMemory.cacheProbe(address);
+ CacheEntry victim_entry := static_cast(CacheEntry, "pointer",
+ L3CacheMemory.lookup(victim));
+ queueMemoryWrite(machineID, victim, to_memory_controller_latency,
+ victim_entry.DataBlk);
+ L3CacheMemory.deallocate(victim);
+ }
+ assert(L3CacheMemory.cacheAvail(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.allocate(address, new CacheEntry));
+ APPEND_TRANSITION_COMMENT(" al wrote data to L3 ");
+ entry.DataBlk := in_msg.DataBlk;
+
+ entry.LastSender := in_msg.Sender;
+ }
+ }
+ }
+
+ action(alwt_allocateL3BlockOnWT, "alwt", desc="allocate the L3 block on WT") {
+ if ((tbe.wtData || tbe.atomicData) && useL3OnWT) {
+ if (L3CacheMemory.isTagPresent(address)) {
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address));
+ APPEND_TRANSITION_COMMENT(" al wrote data to L3 (hit) ");
+ entry.DataBlk := tbe.DataBlk;
+ entry.LastSender := tbe.LastSender;
+ } else {
+ if (L3CacheMemory.cacheAvail(address) == false) {
+ Addr victim := L3CacheMemory.cacheProbe(address);
+ CacheEntry victim_entry := static_cast(CacheEntry, "pointer",
+ L3CacheMemory.lookup(victim));
+ queueMemoryWrite(machineID, victim, to_memory_controller_latency,
+ victim_entry.DataBlk);
+ L3CacheMemory.deallocate(victim);
+ }
+ assert(L3CacheMemory.cacheAvail(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.allocate(address, new CacheEntry));
+ APPEND_TRANSITION_COMMENT(" al wrote data to L3 ");
+ entry.DataBlk := tbe.DataBlk;
+ entry.LastSender := tbe.LastSender;
+ }
+ }
+ }
+
+ action(apf_allocateProbeFilterEntry, "apf", desc="Allocate probe filte entry") {
+ if (!ProbeFilterMemory.isTagPresent(address)) {
+ if (inclusiveDir) {
+ assert(ProbeFilterMemory.cacheAvail(address));
+ } else if (ProbeFilterMemory.cacheAvail(address) == false) {
+ Addr victim := ProbeFilterMemory.cacheProbe(address);
+ ProbeFilterMemory.deallocate(victim);
+ }
+ assert(ProbeFilterMemory.cacheAvail(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.allocate(address, new CacheEntry));
+ APPEND_TRANSITION_COMMENT(" allocating a new probe filter entry");
+ entry.pfState := ProbeFilterState:NT;
+ if (inclusiveDir) {
+ entry.pfState := ProbeFilterState:T;
+ }
+ entry.isOnCPU := false;
+ entry.isOnGPU := false;
+ }
+ }
+
+ action(mpfe_markPFEntryForEviction, "mpfe", desc="Mark this PF entry is being evicted") {
+ assert(ProbeFilterMemory.isTagPresent(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.lookup(address));
+ entry.pfState := ProbeFilterState:B;
+ peek(requestNetwork_in, CPURequestMsg) {
+ tbe.demandAddress := in_msg.addr;
+ }
+ }
+
+ action(we_wakeUpEvictionDependents, "we", desc="Wake up requests waiting for demand address and victim address") {
+ wakeUpBuffers(address);
+ wakeUpBuffers(tbe.demandAddress);
+ }
+
+ action(dpf_deallocateProbeFilter, "dpf", desc="deallocate PF entry") {
+ assert(ProbeFilterMemory.isTagPresent(address));
+ ProbeFilterMemory.deallocate(address);
+ }
+
+ action(upf_updateProbeFilter, "upf", desc="") {
+ peek(requestNetwork_in, CPURequestMsg) {
+ assert(ProbeFilterMemory.isTagPresent(address));
+ CacheEntry entry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.lookup(address));
+ if (in_msg.Type == CoherenceRequestType:WriteThrough) {
+ entry.pfState := ProbeFilterState:T;
+ entry.isOnCPU := false;
+ entry.isOnGPU := false;
+ } else if (in_msg.Type == CoherenceRequestType:Atomic) {
+ entry.pfState := ProbeFilterState:T;
+ entry.isOnCPU := false;
+ entry.isOnGPU := false;
+ } else if (in_msg.Type == CoherenceRequestType:RdBlkM) {
+ entry.pfState := ProbeFilterState:T;
+ entry.isOnCPU := false;
+ entry.isOnGPU := false;
+ } else if (in_msg.Type == CoherenceRequestType:CtoD) {
+ entry.pfState := ProbeFilterState:T;
+ entry.isOnCPU := false;
+ entry.isOnGPU := false;
+ }
+ if(machineIDToMachineType(in_msg.Requestor) == MachineType:CorePair) {
+ entry.isOnCPU := true;
+ } else {
+ entry.isOnGPU := true;
+ }
+ }
+ }
+
+ action(rmcd_removeSharerConditional, "rmcd", desc="remove sharer from probe Filter, conditional") {
+ peek(requestNetwork_in, CPURequestMsg) {
+ if (ProbeFilterMemory.isTagPresent(address)) {
+ CacheEntry entry := static_cast(CacheEntry, "pointer", ProbeFilterMemory.lookup(address));
+ if(machineIDToMachineType(in_msg.Requestor) == MachineType:CorePair) {//CorePair has inclusive L2
+ if (in_msg.Type == CoherenceRequestType:VicDirty) {
+ entry.isOnCPU := false;
+ } else if (in_msg.Type == CoherenceRequestType:VicClean) {
+ entry.isOnCPU := false;
+ }
+ }
+ }
+ }
+ }
+
+ action(sf_setForwardReqTime, "sf", desc="...") {
+ tbe.ForwardRequestTime := curCycle();
+ }
+
+ action(dl_deallocateL3, "dl", desc="deallocate the L3 block") {
+ L3CacheMemory.deallocate(address);
+ }
+
+ action(p_popRequestQueue, "p", desc="pop request queue") {
+ requestNetwork_in.dequeue(clockEdge());
+ }
+
+ action(pr_popResponseQueue, "pr", desc="pop response queue") {
+ responseNetwork_in.dequeue(clockEdge());
+ }
+
+ action(pm_popMemQueue, "pm", desc="pop mem queue") {
+ memQueue_in.dequeue(clockEdge());
+ }
+
+ action(pt_popTriggerQueue, "pt", desc="pop trigger queue") {
+ triggerQueue_in.dequeue(clockEdge());
+ }
+
+ action(ptl_popTriggerQueue, "ptl", desc="pop L3 trigger queue") {
+ L3TriggerQueue_in.dequeue(clockEdge());
+ }
+
+ action(pu_popUnblockQueue, "pu", desc="pop unblock queue") {
+ unblockNetwork_in.dequeue(clockEdge());
+ }
+
+ action(zz_recycleRequestQueue, "zz", desc="recycle request queue") {
+ requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
+ }
+
+ action(yy_recycleResponseQueue, "yy", desc="recycle response queue") {
+ responseNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
+ }
+
+ action(st_stallAndWaitRequest, "st", desc="Stall and wait on the address") {
+ stall_and_wait(requestNetwork_in, address);
+ }
+
+ action(wa_wakeUpDependents, "wa", desc="Wake up any requests waiting for this address") {
+ wakeUpBuffers(address);
+ }
+
+ action(wa_wakeUpAllDependents, "waa", desc="Wake up any requests waiting for this region") {
+ wakeUpAllBuffers();
+ }
+
+ action(z_stall, "z", desc="...") {
+ }
+
+ // TRANSITIONS
+ transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P, B}, {RdBlkS, RdBlkM, RdBlk, CtoD}) {
+ st_stallAndWaitRequest;
+ }
+
+ // It may be possible to save multiple invalidations here!
+ transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P, B}, {Atomic, WriteThrough}) {
+ st_stallAndWaitRequest;
+ }
+
+
+ // transitions from U
+ transition(U, PF_Repl, B_P) {PFTagArrayRead, PFTagArrayWrite}{
+ te_allocateTBEForEviction;
+ apf_allocateProbeFilterEntry;
+ bp_backProbe;
+ sm_setMRU;
+ mpfe_markPFEntryForEviction;
+ }
+
+ transition(U, {RdBlkS}, BS_PM) {L3TagArrayRead, PFTagArrayRead, PFTagArrayWrite} {
+ t_allocateTBE;
+ apf_allocateProbeFilterEntry;
+ l_queueMemRdReq;
+ sc_probeShrCoreData;
+ sm_setMRU;
+ upf_updateProbeFilter;
+ p_popRequestQueue;
+ }
+
+ transition(U, WriteThrough, BM_PM) {L3TagArrayRead, L3TagArrayWrite, PFTagArrayRead, PFTagArrayWrite} {
+ t_allocateTBE;
+ apf_allocateProbeFilterEntry;
+ w_sendResponseWBAck;
+ l_queueMemRdReq;
+ dc_probeInvCoreData;
+ sm_setMRU;
+ upf_updateProbeFilter;
+ p_popRequestQueue;
+ }
+
+ transition(U, Atomic, BM_PM) {L3TagArrayRead, L3TagArrayWrite, PFTagArrayRead, PFTagArrayWrite} {
+ t_allocateTBE;
+ apf_allocateProbeFilterEntry;
+ l_queueMemRdReq;
+ dc_probeInvCoreData;
+ sm_setMRU;
+ upf_updateProbeFilter;
+ p_popRequestQueue;
+ }
+
+ transition(U, {RdBlkM}, BM_PM) {L3TagArrayRead, PFTagArrayRead, PFTagArrayWrite} {
+ t_allocateTBE;
+ apf_allocateProbeFilterEntry;
+ l_queueMemRdReq;
+ dc_probeInvCoreData;
+ sm_setMRU;
+ upf_updateProbeFilter;
+ p_popRequestQueue;
+ }
+
+ transition(U, RdBlk, B_PM) {L3TagArrayRead, PFTagArrayRead, PFTagArrayWrite}{
+ t_allocateTBE;
+ apf_allocateProbeFilterEntry;
+ l_queueMemRdReq;
+ sc_probeShrCoreData;
+ sm_setMRU;
+ upf_updateProbeFilter;
+ p_popRequestQueue;
+ }
+
+ transition(U, CtoD, BP) {L3TagArrayRead, PFTagArrayRead, PFTagArrayWrite} {
+ t_allocateTBE;
+ apf_allocateProbeFilterEntry;
+ ic_probeInvCore;
+ sm_setMRU;
+ upf_updateProbeFilter;
+ p_popRequestQueue;
+ }
+
+ transition(U, VicDirty, BL) {L3TagArrayRead} {
+ t_allocateTBE;
+ w_sendResponseWBAck;
+ rmcd_removeSharerConditional;
+ p_popRequestQueue;
+ }
+
+ transition(U, VicClean, BL) {L3TagArrayRead} {
+ t_allocateTBE;
+ w_sendResponseWBAck;
+ rmcd_removeSharerConditional;
+ p_popRequestQueue;
+ }
+
+ transition(BL, {VicDirty, VicClean}) {
+ zz_recycleRequestQueue;
+ }
+
+ transition(BL, CPUData, U) {L3TagArrayWrite, L3DataArrayWrite} {
+ d_writeDataToMemory;
+ al_allocateL3Block;
+ wa_wakeUpDependents;
+ dt_deallocateTBE;
+ //l_queueMemWBReq; // why need an ack? esp. with DRAMSim, just put it in queue no ack needed
+ pr_popResponseQueue;
+ }
+
+ transition(BL, StaleWB, U) {L3TagArrayWrite} {
+ dt_deallocateTBE;
+ wa_wakeUpAllDependents;
+ pr_popResponseQueue;
+ }
+
+ transition({B, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P}, {VicDirty, VicClean}) {
+ z_stall;
+ }
+
+ transition({U, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P, B}, WBAck) {
+ pm_popMemQueue;
+ }
+
+ transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P, B}, PF_Repl) {
+ zz_recycleRequestQueue;
+ }
+
+ transition({U, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P, B}, StaleVicDirty) {
+ rv_removeVicDirtyIgnore;
+ w_sendResponseWBAck;
+ p_popRequestQueue;
+ }
+
+ transition({B}, CoreUnblock, U) {
+ wa_wakeUpDependents;
+ pu_popUnblockQueue;
+ }
+
+ transition(B, UnblockWriteThrough, U) {
+ wa_wakeUpDependents;
+ pt_popTriggerQueue;
+ }
+
+ transition(BS_PM, MemData, BS_Pm) {} {
+ mt_writeMemDataToTBE;
+ pm_popMemQueue;
+ }
+
+ transition(BM_PM, MemData, BM_Pm){} {
+ mt_writeMemDataToTBE;
+ pm_popMemQueue;
+ }
+
+ transition(B_PM, MemData, B_Pm){} {
+ mt_writeMemDataToTBE;
+ pm_popMemQueue;
+ }
+
+ transition(BS_PM, L3Hit, BS_Pm) {} {
+ ptl_popTriggerQueue;
+ }
+
+ transition(BM_PM, L3Hit, BM_Pm) {} {
+ ptl_popTriggerQueue;
+ }
+
+ transition(B_PM, L3Hit, B_Pm) {} {
+ ptl_popTriggerQueue;
+ }
+
+ transition(BS_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} {
+ mt_writeMemDataToTBE;
+ s_sendResponseS;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pm_popMemQueue;
+ }
+
+ transition(BM_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} {
+ mt_writeMemDataToTBE;
+ m_sendResponseM;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pm_popMemQueue;
+ }
+
+ transition(B_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} {
+ mt_writeMemDataToTBE;
+ es_sendResponseES;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pm_popMemQueue;
+ }
+
+ transition(BS_M, L3Hit, B) {L3TagArrayWrite, L3DataArrayWrite} {
+ s_sendResponseS;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ ptl_popTriggerQueue;
+ }
+
+ transition(BM_M, L3Hit, B) {L3DataArrayWrite, L3TagArrayWrite} {
+ m_sendResponseM;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ ptl_popTriggerQueue;
+ }
+
+ transition(B_M, L3Hit, B) {L3DataArrayWrite, L3TagArrayWrite} {
+ es_sendResponseES;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ ptl_popTriggerQueue;
+ }
+
+ transition({BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B_P, BP}, CPUPrbResp) {
+ y_writeProbeDataToTBE;
+ x_decrementAcks;
+ o_checkForCompletion;
+ pr_popResponseQueue;
+ }
+
+ transition(BS_PM, ProbeAcksComplete, BS_M) {} {
+ sf_setForwardReqTime;
+ pt_popTriggerQueue;
+ }
+
+ transition(BM_PM, ProbeAcksComplete, BM_M) {} {
+ sf_setForwardReqTime;
+ pt_popTriggerQueue;
+ }
+
+ transition(B_PM, ProbeAcksComplete, B_M){} {
+ sf_setForwardReqTime;
+ pt_popTriggerQueue;
+ }
+
+ transition(BS_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} {
+ sf_setForwardReqTime;
+ s_sendResponseS;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pt_popTriggerQueue;
+ }
+
+ transition(BM_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} {
+ sf_setForwardReqTime;
+ m_sendResponseM;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pt_popTriggerQueue;
+ }
+
+ transition(B_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} {
+ sf_setForwardReqTime;
+ es_sendResponseES;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pt_popTriggerQueue;
+ }
+
+ transition(B_P, ProbeAcksComplete, U) {
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ we_wakeUpEvictionDependents;
+ dpf_deallocateProbeFilter;
+ dt_deallocateTBE;
+ pt_popTriggerQueue;
+ }
+
+ transition(BP, ProbeAcksComplete, B){L3TagArrayWrite, L3TagArrayWrite} {
+ sf_setForwardReqTime;
+ c_sendResponseCtoD;
+ wd_writeBackData;
+ alwt_allocateL3BlockOnWT;
+ dt_deallocateTBE;
+ pt_popTriggerQueue;
+ }
+}