summaryrefslogtreecommitdiff
path: root/src/mem/ruby/protocol/MOESI_hammer-dir.sm
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/ruby/protocol/MOESI_hammer-dir.sm')
-rw-r--r--src/mem/ruby/protocol/MOESI_hammer-dir.sm1876
1 files changed, 1876 insertions, 0 deletions
diff --git a/src/mem/ruby/protocol/MOESI_hammer-dir.sm b/src/mem/ruby/protocol/MOESI_hammer-dir.sm
new file mode 100644
index 000000000..42522c727
--- /dev/null
+++ b/src/mem/ruby/protocol/MOESI_hammer-dir.sm
@@ -0,0 +1,1876 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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.
+ *
+ * AMD's contributions to the MOESI hammer protocol do not constitute an
+ * endorsement of its similarity to any AMD products.
+ *
+ * Authors: Milo Martin
+ * Brad Beckmann
+ */
+
+machine(MachineType:Directory, "AMD Hammer-like protocol")
+ : DirectoryMemory * directory;
+ CacheMemory * probeFilter;
+ Cycles from_memory_controller_latency := 2;
+ Cycles to_memory_controller_latency := 1;
+ bool probe_filter_enabled := "False";
+ bool full_bit_dir_enabled := "False";
+
+ MessageBuffer * forwardFromDir, network="To", virtual_network="3",
+ vnet_type="forward";
+
+ MessageBuffer * responseFromDir, network="To", virtual_network="4",
+ vnet_type="response";
+
+ // For a finite buffered network, note that the DMA response network only
+ // works at this relatively lower numbered (lower priority) virtual network
+ // because the trigger queue decouples cache responses from DMA responses.
+ MessageBuffer * dmaResponseFromDir, network="To", virtual_network="1",
+ vnet_type="response";
+
+ MessageBuffer * unblockToDir, network="From", virtual_network="5",
+ vnet_type="unblock";
+
+ MessageBuffer * responseToDir, network="From", virtual_network="4",
+ vnet_type="response";
+
+ MessageBuffer * requestToDir, network="From", virtual_network="2",
+ vnet_type="request";
+
+ MessageBuffer * dmaRequestToDir, network="From", virtual_network="0",
+ vnet_type="request";
+
+ MessageBuffer * triggerQueue;
+ MessageBuffer * responseFromMemory;
+{
+ // STATES
+ state_declaration(State, desc="Directory states", default="Directory_State_E") {
+ // Base states
+ NX, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in O at Owner";
+ NO, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in E/M at Owner";
+ S, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists pointing to the current owner";
+ O, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists";
+ E, AccessPermission:Read_Write, desc="Exclusive Owner, no probe filter entry";
+
+ O_R, AccessPermission:Read_Only, desc="Was data Owner, replacing probe filter entry";
+ S_R, AccessPermission:Read_Only, desc="Was Not Owner or Sharer, replacing probe filter entry";
+ NO_R, AccessPermission:Busy, desc="Was Not Owner or Sharer, replacing probe filter entry";
+
+ NO_B, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked";
+ NO_B_X, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETX";
+ NO_B_S, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETS";
+ NO_B_S_W, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses";
+ O_B, AccessPermission:Busy, "O^B", desc="Owner, Blocked";
+ NO_B_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
+ O_B_W, AccessPermission:Busy, desc="Owner, Blocked, waiting for Dram";
+ NO_W, AccessPermission:Busy, desc="Not Owner, waiting for Dram";
+ O_W, AccessPermission:Busy, desc="Owner, waiting for Dram";
+ NO_DW_B_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram and cache responses";
+ NO_DR_B_W, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for Dram and cache responses";
+ NO_DR_B_D, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses including dirty data";
+ NO_DR_B, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses";
+ NO_DW_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram";
+ O_DR_B_W, AccessPermission:Busy, desc="Owner, Dma Read waiting for Dram and cache responses";
+ O_DR_B, AccessPermission:Busy, desc="Owner, Dma Read waiting for cache responses";
+ WB, AccessPermission:Busy, desc="Blocked on a writeback";
+ WB_O_W, AccessPermission:Busy, desc="Blocked on memory write, will go to O";
+ WB_E_W, AccessPermission:Busy, desc="Blocked on memory write, will go to E";
+
+ NO_F, AccessPermission:Busy, desc="Blocked on a flush";
+ NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
+ }
+
+ // Events
+ enumeration(Event, desc="Directory events") {
+ GETX, desc="A GETX arrives";
+ GETS, desc="A GETS arrives";
+ PUT, desc="A PUT arrives";
+ Unblock, desc="An unblock message arrives";
+ UnblockS, desc="An unblock message arrives";
+ UnblockM, desc="An unblock message arrives";
+ Writeback_Clean, desc="The final part of a PutX (no data)";
+ Writeback_Dirty, desc="The final part of a PutX (data)";
+ Writeback_Exclusive_Clean, desc="The final part of a PutX (no data, exclusive)";
+ Writeback_Exclusive_Dirty, desc="The final part of a PutX (data, exclusive)";
+
+ // Probe filter
+ Pf_Replacement, desc="probe filter replacement";
+
+ // DMA requests
+ DMA_READ, desc="A DMA Read memory request";
+ DMA_WRITE, desc="A DMA Write memory request";
+
+ // Memory Controller
+ Memory_Data, desc="Fetched data from memory arrives";
+ Memory_Ack, desc="Writeback Ack from memory arrives";
+
+ // Cache responses required to handle DMA
+ Ack, desc="Received an ack message";
+ Shared_Ack, desc="Received an ack message, responder has a shared copy";
+ Shared_Data, desc="Received a data message, responder has a shared copy";
+ Data, desc="Received a data message, responder had a owner or exclusive copy, they gave it to us";
+ Exclusive_Data, desc="Received a data message, responder had an exclusive copy, they gave it to us";
+
+ // Triggers
+ All_acks_and_shared_data, desc="Received shared data and message acks";
+ All_acks_and_owner_data, desc="Received shared data and message acks";
+ All_acks_and_data_no_sharers, desc="Received all acks and no other processor has a shared copy";
+ All_Unblocks, desc="Received all unblocks for a merged gets request";
+ GETF, desc="A GETF arrives";
+ PUTF, desc="A PUTF arrives";
+ }
+
+ // TYPES
+
+ // DirectoryEntry
+ structure(Entry, desc="...", interface="AbstractEntry") {
+ State DirectoryState, desc="Directory state";
+ }
+
+ // ProbeFilterEntry
+ structure(PfEntry, desc="...", interface="AbstractCacheEntry") {
+ State PfState, desc="Directory state";
+ MachineID Owner, desc="Owner node";
+ Set Sharers, desc="sharing vector for full bit directory";
+ }
+
+ // TBE entries for DMA requests
+ structure(TBE, desc="TBE entries for outstanding DMA requests") {
+ Addr PhysicalAddress, desc="physical address";
+ State TBEState, desc="Transient State";
+ CoherenceResponseType ResponseType, desc="The type for the subsequent response message";
+ int Acks, default="0", desc="The number of acks that the waiting response represents";
+ int SilentAcks, default="0", desc="The number of silent acks associated with this transaction";
+ DataBlock DmaDataBlk, desc="DMA Data to be written. Partial blocks need to merged with system memory";
+ DataBlock DataBlk, desc="The current view of system memory";
+ int Len, desc="...";
+ MachineID DmaRequestor, desc="DMA requestor";
+ NetDest GetSRequestors, desc="GETS merged requestors";
+ int NumPendingMsgs, desc="Number of pending acks/messages";
+ bool CacheDirty, default="false", desc="Indicates whether a cache has responded with dirty data";
+ bool Sharers, default="false", desc="Indicates whether a cache has indicated it is currently a sharer";
+ bool Owned, default="false", desc="Indicates whether a cache has indicated it is currently a sharer";
+ }
+
+ structure(TBETable, external="yes") {
+ TBE lookup(Addr);
+ void allocate(Addr);
+ void deallocate(Addr);
+ bool isPresent(Addr);
+ }
+
+ Tick clockEdge();
+ void set_cache_entry(AbstractCacheEntry b);
+ void unset_cache_entry();
+ void set_tbe(TBE a);
+ void unset_tbe();
+ void wakeUpBuffers(Addr a);
+ Cycles curCycle();
+
+ // ** OBJECTS **
+
+ Set fwd_set;
+
+ TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
+
+ Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
+ Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
+
+ if (is_valid(dir_entry)) {
+ return dir_entry;
+ }
+
+ dir_entry := static_cast(Entry, "pointer",
+ directory.allocate(addr, new Entry));
+ return dir_entry;
+ }
+
+ PfEntry getProbeFilterEntry(Addr addr), return_by_pointer="yes" {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ PfEntry pfEntry := static_cast(PfEntry, "pointer", probeFilter.lookup(addr));
+ return pfEntry;
+ }
+ return OOD;
+ }
+
+ State getState(TBE tbe, PfEntry pf_entry, Addr addr) {
+ if (is_valid(tbe)) {
+ return tbe.TBEState;
+ } else {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ if (is_valid(pf_entry)) {
+ assert(pf_entry.PfState == getDirectoryEntry(addr).DirectoryState);
+ }
+ }
+ return getDirectoryEntry(addr).DirectoryState;
+ }
+ }
+
+ void setState(TBE tbe, PfEntry pf_entry, Addr addr, State state) {
+ if (is_valid(tbe)) {
+ tbe.TBEState := state;
+ }
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ if (is_valid(pf_entry)) {
+ pf_entry.PfState := state;
+ }
+ if (state == State:NX || state == State:NO || state == State:S || state == State:O) {
+ assert(is_valid(pf_entry));
+ }
+ if (state == State:E) {
+ assert(is_valid(pf_entry) == false);
+ }
+ }
+ if (state == State:E || state == State:NX || state == State:NO || state == State:S ||
+ state == State:O) {
+ assert(is_valid(tbe) == false);
+ }
+ getDirectoryEntry(addr).DirectoryState := state;
+ }
+
+ AccessPermission getAccessPermission(Addr addr) {
+ TBE tbe := TBEs[addr];
+ if(is_valid(tbe)) {
+ return Directory_State_to_permission(tbe.TBEState);
+ }
+
+ if(directory.isPresent(addr)) {
+ return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+ }
+
+ return AccessPermission:NotPresent;
+ }
+
+ void setAccessPermission(PfEntry pf_entry, Addr addr, State state) {
+ getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
+ }
+
+ void functionalRead(Addr addr, Packet *pkt) {
+ TBE tbe := TBEs[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[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;
+ }
+
+ Event cache_request_to_event(CoherenceRequestType type) {
+ if (type == CoherenceRequestType:GETS) {
+ return Event:GETS;
+ } else if (type == CoherenceRequestType:GETX) {
+ return Event:GETX;
+ } else if (type == CoherenceRequestType:GETF) {
+ return Event:GETF;
+ } else {
+ error("Invalid CoherenceRequestType");
+ }
+ }
+
+ // ** OUT_PORTS **
+ out_port(requestQueue_out, ResponseMsg, requestToDir); // For recycling requests
+ out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
+ out_port(responseNetwork_out, ResponseMsg, responseFromDir);
+ out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaResponseFromDir);
+ out_port(triggerQueue_out, TriggerMsg, triggerQueue);
+
+ // ** IN_PORTS **
+
+ // Trigger Queue
+ in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=5) {
+ if (triggerQueue_in.isReady(clockEdge())) {
+ peek(triggerQueue_in, TriggerMsg) {
+ PfEntry pf_entry := getProbeFilterEntry(in_msg.addr);
+ TBE tbe := TBEs[in_msg.addr];
+ if (in_msg.Type == TriggerType:ALL_ACKS) {
+ trigger(Event:All_acks_and_owner_data, in_msg.addr,
+ pf_entry, tbe);
+ } else if (in_msg.Type == TriggerType:ALL_ACKS_OWNER_EXISTS) {
+ trigger(Event:All_acks_and_shared_data, in_msg.addr,
+ pf_entry, tbe);
+ } else if (in_msg.Type == TriggerType:ALL_ACKS_NO_SHARERS) {
+ trigger(Event:All_acks_and_data_no_sharers, in_msg.addr,
+ pf_entry, tbe);
+ } else if (in_msg.Type == TriggerType:ALL_UNBLOCKS) {
+ trigger(Event:All_Unblocks, in_msg.addr,
+ pf_entry, tbe);
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+
+ in_port(unblockNetwork_in, ResponseMsg, unblockToDir, rank=4) {
+ if (unblockNetwork_in.isReady(clockEdge())) {
+ peek(unblockNetwork_in, ResponseMsg) {
+ PfEntry pf_entry := getProbeFilterEntry(in_msg.addr);
+ TBE tbe := TBEs[in_msg.addr];
+ if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
+ trigger(Event:Unblock, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:UNBLOCKS) {
+ trigger(Event:UnblockS, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:UNBLOCKM) {
+ trigger(Event:UnblockM, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:WB_CLEAN) {
+ trigger(Event:Writeback_Clean, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:WB_DIRTY) {
+ trigger(Event:Writeback_Dirty, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:WB_EXCLUSIVE_CLEAN) {
+ trigger(Event:Writeback_Exclusive_Clean, in_msg.addr,
+ pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:WB_EXCLUSIVE_DIRTY) {
+ trigger(Event:Writeback_Exclusive_Dirty, in_msg.addr,
+ pf_entry, tbe);
+ } else {
+ error("Invalid message");
+ }
+ }
+ }
+ }
+
+ // Response Network
+ in_port(responseToDir_in, ResponseMsg, responseToDir, rank=3) {
+ if (responseToDir_in.isReady(clockEdge())) {
+ peek(responseToDir_in, ResponseMsg) {
+ PfEntry pf_entry := getProbeFilterEntry(in_msg.addr);
+ TBE tbe := TBEs[in_msg.addr];
+ if (in_msg.Type == CoherenceResponseType:ACK) {
+ trigger(Event:Ack, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:ACK_SHARED) {
+ trigger(Event:Shared_Ack, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
+ trigger(Event:Shared_Data, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:DATA) {
+ trigger(Event:Data, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
+ trigger(Event:Exclusive_Data, in_msg.addr, pf_entry, tbe);
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+
+ // off-chip memory request/response is done
+ in_port(memQueue_in, MemoryMsg, responseFromMemory, rank=2) {
+ if (memQueue_in.isReady(clockEdge())) {
+ peek(memQueue_in, MemoryMsg) {
+ PfEntry pf_entry := getProbeFilterEntry(in_msg.addr);
+ TBE tbe := TBEs[in_msg.addr];
+ if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
+ trigger(Event:Memory_Data, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
+ trigger(Event:Memory_Ack, in_msg.addr, pf_entry, tbe);
+ } else {
+ DPRINTF(RubySlicc, "%d\n", in_msg.Type);
+ error("Invalid message");
+ }
+ }
+ }
+ }
+
+ in_port(requestQueue_in, RequestMsg, requestToDir, rank=1) {
+ if (requestQueue_in.isReady(clockEdge())) {
+ peek(requestQueue_in, RequestMsg) {
+ PfEntry pf_entry := getProbeFilterEntry(in_msg.addr);
+ TBE tbe := TBEs[in_msg.addr];
+ if (in_msg.Type == CoherenceRequestType:PUT) {
+ trigger(Event:PUT, in_msg.addr, pf_entry, tbe);
+ } else if (in_msg.Type == CoherenceRequestType:PUTF) {
+ trigger(Event:PUTF, in_msg.addr, pf_entry, tbe);
+ } else {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ if (is_valid(pf_entry)) {
+ trigger(cache_request_to_event(in_msg.Type), in_msg.addr,
+ pf_entry, tbe);
+ } else {
+ if (probeFilter.cacheAvail(in_msg.addr)) {
+ trigger(cache_request_to_event(in_msg.Type), in_msg.addr,
+ pf_entry, tbe);
+ } else {
+ trigger(Event:Pf_Replacement,
+ probeFilter.cacheProbe(in_msg.addr),
+ getProbeFilterEntry(probeFilter.cacheProbe(in_msg.addr)),
+ TBEs[probeFilter.cacheProbe(in_msg.addr)]);
+ }
+ }
+ } else {
+ trigger(cache_request_to_event(in_msg.Type), in_msg.addr,
+ pf_entry, tbe);
+ }
+ }
+ }
+ }
+ }
+
+ in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir, rank=0) {
+ if (dmaRequestQueue_in.isReady(clockEdge())) {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ PfEntry pf_entry := getProbeFilterEntry(in_msg.LineAddress);
+ TBE tbe := TBEs[in_msg.LineAddress];
+ if (in_msg.Type == DMARequestType:READ) {
+ trigger(Event:DMA_READ, in_msg.LineAddress, pf_entry, tbe);
+ } else if (in_msg.Type == DMARequestType:WRITE) {
+ trigger(Event:DMA_WRITE, in_msg.LineAddress, pf_entry, tbe);
+ } else {
+ error("Invalid message");
+ }
+ }
+ }
+ }
+
+ // Actions
+
+ action(r_setMRU, "\rr", desc="manually set the MRU bit for pf entry" ) {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ assert(is_valid(cache_entry));
+ probeFilter.setMRU(address);
+ }
+ }
+
+ action(auno_assertUnblockerNotOwner, "auno", desc="assert unblocker not owner") {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ assert(is_valid(cache_entry));
+ peek(unblockNetwork_in, ResponseMsg) {
+ assert(cache_entry.Owner != in_msg.Sender);
+ if (full_bit_dir_enabled) {
+ assert(cache_entry.Sharers.isElement(machineIDToNodeID(in_msg.Sender)) == false);
+ }
+ }
+ }
+ }
+
+ action(uo_updateOwnerIfPf, "uo", desc="update owner") {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ assert(is_valid(cache_entry));
+ peek(unblockNetwork_in, ResponseMsg) {
+ cache_entry.Owner := in_msg.Sender;
+ if (full_bit_dir_enabled) {
+ cache_entry.Sharers.clear();
+ cache_entry.Sharers.add(machineIDToNodeID(in_msg.Sender));
+ APPEND_TRANSITION_COMMENT(cache_entry.Sharers);
+ DPRINTF(RubySlicc, "Sharers = %d\n", cache_entry.Sharers);
+ }
+ }
+ }
+ }
+
+ action(us_updateSharerIfFBD, "us", desc="update sharer if full-bit directory") {
+ if (full_bit_dir_enabled) {
+ assert(probeFilter.isTagPresent(address));
+ peek(unblockNetwork_in, ResponseMsg) {
+ cache_entry.Sharers.add(machineIDToNodeID(in_msg.Sender));
+ }
+ }
+ }
+
+ action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:WB_ACK;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
+
+ action(oc_sendBlockAck, "oc", desc="Send block ack to the owner") {
+ peek(requestQueue_in, RequestMsg) {
+ if (((probe_filter_enabled || full_bit_dir_enabled) && (in_msg.Requestor == cache_entry.Owner)) || machineCount(MachineType:L1Cache) == 1) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:BLOCK_ACK;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
+ }
+
+ action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:WB_NACK;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+ }
+
+ action(pfa_probeFilterAllocate, "pfa", desc="Allocate ProbeFilterEntry") {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ peek(requestQueue_in, RequestMsg) {
+ set_cache_entry(probeFilter.allocate(address, new PfEntry));
+ cache_entry.Owner := in_msg.Requestor;
+ cache_entry.Sharers.setSize(machineCount(MachineType:L1Cache));
+ }
+ }
+ }
+
+ action(pfd_probeFilterDeallocate, "pfd", desc="Deallocate ProbeFilterEntry") {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ probeFilter.deallocate(address);
+ unset_cache_entry();
+ }
+ }
+
+ action(ppfd_possibleProbeFilterDeallocate, "ppfd", desc="Deallocate ProbeFilterEntry") {
+ if ((probe_filter_enabled || full_bit_dir_enabled) && is_valid(cache_entry)) {
+ probeFilter.deallocate(address);
+ unset_cache_entry();
+ }
+ }
+
+ action(v_allocateTBE, "v", desc="Allocate TBE") {
+ check_allocate(TBEs);
+ peek(requestQueue_in, RequestMsg) {
+ TBEs.allocate(address);
+ set_tbe(TBEs[address]);
+ tbe.PhysicalAddress := address;
+ tbe.ResponseType := CoherenceResponseType:NULL;
+ }
+ }
+
+ action(vd_allocateDmaRequestInTBE, "vd", desc="Record Data in TBE") {
+ check_allocate(TBEs);
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ TBEs.allocate(address);
+ set_tbe(TBEs[address]);
+ tbe.DmaDataBlk := in_msg.DataBlk;
+ tbe.PhysicalAddress := in_msg.PhysicalAddress;
+ tbe.Len := in_msg.Len;
+ tbe.DmaRequestor := in_msg.Requestor;
+ tbe.ResponseType := CoherenceResponseType:DATA_EXCLUSIVE;
+ //
+ // One ack for each last-level cache
+ //
+ tbe.NumPendingMsgs := machineCount(MachineType:L1Cache);
+ //
+ // Assume initially that the caches store a clean copy and that memory
+ // will provide the data
+ //
+ tbe.CacheDirty := false;
+ }
+ }
+
+ action(pa_setPendingMsgsToAll, "pa", desc="set pending msgs to all") {
+ assert(is_valid(tbe));
+ if (full_bit_dir_enabled) {
+ assert(is_valid(cache_entry));
+ tbe.NumPendingMsgs := cache_entry.Sharers.count();
+ } else {
+ tbe.NumPendingMsgs := machineCount(MachineType:L1Cache);
+ }
+ }
+
+ action(po_setPendingMsgsToOne, "po", desc="set pending msgs to one") {
+ assert(is_valid(tbe));
+ tbe.NumPendingMsgs := 1;
+ }
+
+ action(w_deallocateTBE, "w", desc="Deallocate TBE") {
+ TBEs.deallocate(address);
+ unset_tbe();
+ }
+
+ action(sa_setAcksToOne, "sa", desc="Forwarded request, set the ack amount to one") {
+ assert(is_valid(tbe));
+ peek(requestQueue_in, RequestMsg) {
+ if (full_bit_dir_enabled) {
+ assert(is_valid(cache_entry));
+ //
+ // If we are using the full-bit directory and no sharers exists beyond
+ // the requestor, then we must set the ack number to all, not one
+ //
+ fwd_set := cache_entry.Sharers;
+ fwd_set.remove(machineIDToNodeID(in_msg.Requestor));
+ if (fwd_set.count() > 0) {
+ tbe.Acks := 1;
+ tbe.SilentAcks := machineCount(MachineType:L1Cache) - fwd_set.count();
+ tbe.SilentAcks := tbe.SilentAcks - 1;
+ } else {
+ tbe.Acks := machineCount(MachineType:L1Cache);
+ tbe.SilentAcks := 0;
+ }
+ } else {
+ tbe.Acks := 1;
+ }
+ }
+ }
+
+ action(saa_setAcksToAllIfPF, "saa", desc="Non-forwarded request, set the ack amount to all") {
+ assert(is_valid(tbe));
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ tbe.Acks := machineCount(MachineType:L1Cache);
+ tbe.SilentAcks := 0;
+ } else {
+ tbe.Acks := 1;
+ }
+ }
+
+ action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") {
+ peek(responseToDir_in, ResponseMsg) {
+ assert(is_valid(tbe));
+ assert(in_msg.Acks > 0);
+ DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs);
+ //
+ // Note that cache data responses will have an ack count of 2. However,
+ // directory DMA requests must wait for acks from all LLC caches, so
+ // only decrement by 1.
+ //
+ if ((in_msg.Type == CoherenceResponseType:DATA_SHARED) ||
+ (in_msg.Type == CoherenceResponseType:DATA) ||
+ (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE)) {
+ tbe.NumPendingMsgs := tbe.NumPendingMsgs - 1;
+ } else {
+ tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks;
+ }
+ DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs);
+ }
+ }
+
+ action(mu_decrementNumberOfUnblocks, "mu", desc="Decrement the number of messages for which we're waiting") {
+ peek(unblockNetwork_in, ResponseMsg) {
+ assert(is_valid(tbe));
+ assert(in_msg.Type == CoherenceResponseType:UNBLOCKS);
+ DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs);
+ tbe.NumPendingMsgs := tbe.NumPendingMsgs - 1;
+ DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs);
+ }
+ }
+
+ action(n_popResponseQueue, "n", desc="Pop response queue") {
+ responseToDir_in.dequeue(clockEdge());
+ }
+
+ action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
+ assert(is_valid(tbe));
+ if (tbe.NumPendingMsgs == 0) {
+ enqueue(triggerQueue_out, TriggerMsg) {
+ out_msg.addr := address;
+ if (tbe.Sharers) {
+ if (tbe.Owned) {
+ out_msg.Type := TriggerType:ALL_ACKS_OWNER_EXISTS;
+ } else {
+ out_msg.Type := TriggerType:ALL_ACKS;
+ }
+ } else {
+ out_msg.Type := TriggerType:ALL_ACKS_NO_SHARERS;
+ }
+ }
+ }
+ }
+
+ action(os_checkForMergedGetSCompletion, "os", desc="Check for merged GETS completion") {
+ assert(is_valid(tbe));
+ if (tbe.NumPendingMsgs == 0) {
+ enqueue(triggerQueue_out, TriggerMsg) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:ALL_UNBLOCKS;
+ }
+ }
+ }
+
+ action(sp_setPendingMsgsToMergedSharers, "sp", desc="Set pending messages to waiting sharers") {
+ assert(is_valid(tbe));
+ tbe.NumPendingMsgs := tbe.GetSRequestors.count();
+ }
+
+ action(spa_setPendingAcksToZeroIfPF, "spa", desc="if probe filter, no need to wait for acks") {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ assert(is_valid(tbe));
+ tbe.NumPendingMsgs := 0;
+ }
+ }
+
+ action(sc_signalCompletionIfPF, "sc", desc="indicate that we should skip waiting for cpu acks") {
+ assert(is_valid(tbe));
+ if (tbe.NumPendingMsgs == 0) {
+ assert(probe_filter_enabled || full_bit_dir_enabled);
+ enqueue(triggerQueue_out, TriggerMsg) {
+ out_msg.addr := address;
+ out_msg.Type := TriggerType:ALL_ACKS_NO_SHARERS;
+ }
+ }
+ }
+
+ action(d_sendData, "d", desc="Send data to requestor") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, 1) {
+ assert(is_valid(tbe));
+ out_msg.addr := address;
+ out_msg.Type := tbe.ResponseType;
+ out_msg.Sender := machineID;
+ out_msg.Destination.add(in_msg.OriginalRequestorMachId);
+ out_msg.DataBlk := in_msg.DataBlk;
+ DPRINTF(RubySlicc, "%s\n", out_msg.DataBlk);
+ out_msg.Dirty := false; // By definition, the block is now clean
+ out_msg.Acks := tbe.Acks;
+ out_msg.SilentAcks := tbe.SilentAcks;
+ DPRINTF(RubySlicc, "%d\n", out_msg.Acks);
+ assert(out_msg.Acks > 0);
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
+
+ action(dr_sendDmaData, "dr", desc="Send Data to DMA controller from memory") {
+ peek(memQueue_in, MemoryMsg) {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, 1) {
+ assert(is_valid(tbe));
+ out_msg.PhysicalAddress := address;
+ out_msg.LineAddress := address;
+ out_msg.Type := DMAResponseType:DATA;
+ //
+ // we send the entire data block and rely on the dma controller to
+ // split it up if need be
+ //
+ out_msg.DataBlk := in_msg.DataBlk;
+ out_msg.Destination.add(tbe.DmaRequestor);
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
+
+ action(dt_sendDmaDataFromTbe, "dt", desc="Send Data to DMA controller from tbe") {
+ peek(triggerQueue_in, TriggerMsg) {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, 1) {
+ assert(is_valid(tbe));
+ out_msg.PhysicalAddress := address;
+ out_msg.LineAddress := address;
+ out_msg.Type := DMAResponseType:DATA;
+ //
+ // we send the entire data block and rely on the dma controller to
+ // split it up if need be
+ //
+ out_msg.DataBlk := tbe.DataBlk;
+ out_msg.Destination.add(tbe.DmaRequestor);
+ out_msg.MessageSize := MessageSizeType:Response_Data;
+ }
+ }
+ }
+
+ action(da_sendDmaAck, "da", desc="Send Ack to DMA controller") {
+ enqueue(dmaResponseNetwork_out, DMAResponseMsg, 1) {
+ assert(is_valid(tbe));
+ out_msg.PhysicalAddress := address;
+ out_msg.LineAddress := address;
+ out_msg.Type := DMAResponseType:ACK;
+ out_msg.Destination.add(tbe.DmaRequestor);
+ out_msg.MessageSize := MessageSizeType:Writeback_Control;
+ }
+ }
+
+ action(rx_recordExclusiveInTBE, "rx", desc="Record Exclusive in TBE") {
+ peek(requestQueue_in, RequestMsg) {
+ assert(is_valid(tbe));
+ tbe.ResponseType := CoherenceResponseType:DATA_EXCLUSIVE;
+ }
+ }
+
+ action(r_recordDataInTBE, "rt", desc="Record Data in TBE") {
+ peek(requestQueue_in, RequestMsg) {
+ assert(is_valid(tbe));
+ if (full_bit_dir_enabled) {
+ fwd_set := cache_entry.Sharers;
+ fwd_set.remove(machineIDToNodeID(in_msg.Requestor));
+ if (fwd_set.count() > 0) {
+ tbe.ResponseType := CoherenceResponseType:DATA;
+ } else {
+ tbe.ResponseType := CoherenceResponseType:DATA_EXCLUSIVE;
+ }
+ } else {
+ tbe.ResponseType := CoherenceResponseType:DATA;
+ }
+ }
+ }
+
+ action(rs_recordGetSRequestor, "rs", desc="Record GETS requestor in TBE") {
+ peek(requestQueue_in, RequestMsg) {
+ assert(is_valid(tbe));
+ tbe.GetSRequestors.add(in_msg.Requestor);
+ }
+ }
+
+ action(r_setSharerBit, "r", desc="We saw other sharers") {
+ assert(is_valid(tbe));
+ tbe.Sharers := true;
+ }
+
+ action(so_setOwnerBit, "so", desc="We saw other sharers") {
+ assert(is_valid(tbe));
+ tbe.Sharers := true;
+ tbe.Owned := true;
+ }
+
+ action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
+ peek(requestQueue_in, RequestMsg) {
+ queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency);
+ }
+ }
+
+ action(qd_queueMemoryRequestFromDmaRead, "qd", desc="Queue off-chip fetch request") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency);
+ }
+ }
+
+ action(fn_forwardRequestIfNecessary, "fn", desc="Forward requests if necessary") {
+ assert(is_valid(tbe));
+ if ((machineCount(MachineType:L1Cache) > 1) && (tbe.Acks <= 1)) {
+ if (full_bit_dir_enabled) {
+ assert(is_valid(cache_entry));
+ peek(requestQueue_in, RequestMsg) {
+ fwd_set := cache_entry.Sharers;
+ fwd_set.remove(machineIDToNodeID(in_msg.Requestor));
+ if (fwd_set.count() > 0) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.setNetDest(MachineType:L1Cache, fwd_set);
+ out_msg.MessageSize := MessageSizeType:Multicast_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ assert(tbe.SilentAcks > 0);
+ out_msg.SilentAcks := tbe.SilentAcks;
+ }
+ }
+ }
+ } else {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.broadcast(MachineType:L1Cache); // Send to all L1 caches
+ out_msg.Destination.remove(in_msg.Requestor); // Don't include the original requestor
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ }
+ }
+ }
+
+ action(ia_invalidateAllRequest, "ia", desc="invalidate all copies") {
+ if (machineCount(MachineType:L1Cache) > 1) {
+ if (full_bit_dir_enabled) {
+ assert(cache_entry.Sharers.count() > 0);
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:INV;
+ out_msg.Requestor := machineID;
+ out_msg.Destination.setNetDest(MachineType:L1Cache, cache_entry.Sharers);
+ out_msg.MessageSize := MessageSizeType:Multicast_Control;
+ }
+ }
+ } else {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:INV;
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache); // Send to all L1 caches
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ }
+ }
+ }
+ }
+
+ action(io_invalidateOwnerRequest, "io", desc="invalidate all copies") {
+ if (machineCount(MachineType:L1Cache) > 1) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ assert(is_valid(cache_entry));
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:INV;
+ out_msg.Requestor := machineID;
+ out_msg.Destination.add(cache_entry.Owner);
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ out_msg.DirectedProbe := true;
+ }
+ }
+ }
+
+ action(fb_forwardRequestBcast, "fb", desc="Forward requests to all nodes") {
+ if (machineCount(MachineType:L1Cache) > 1) {
+ peek(requestQueue_in, RequestMsg) {
+ if (full_bit_dir_enabled) {
+ fwd_set := cache_entry.Sharers;
+ fwd_set.remove(machineIDToNodeID(in_msg.Requestor));
+ if (fwd_set.count() > 0) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.setNetDest(MachineType:L1Cache, fwd_set);
+ out_msg.MessageSize := MessageSizeType:Multicast_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ out_msg.SilentAcks := machineCount(MachineType:L1Cache) - fwd_set.count();
+ out_msg.SilentAcks := out_msg.SilentAcks - 1;
+ }
+ }
+ } else {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.broadcast(MachineType:L1Cache); // Send to all L1 caches
+ out_msg.Destination.remove(in_msg.Requestor); // Don't include the original requestor
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ }
+ } else {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(responseNetwork_out, ResponseMsg, 1) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceResponseType:ACK;
+ out_msg.Sender := machineID;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.Dirty := false; // By definition, the block is now clean
+ out_msg.Acks := 0;
+ out_msg.SilentAcks := 0;
+ DPRINTF(RubySlicc, "%d\n", out_msg.Acks);
+ out_msg.MessageSize := MessageSizeType:Response_Control;
+ }
+ }
+ }
+ }
+
+ action(fr_forwardMergeReadRequestsToOwner, "frr", desc="Forward coalesced read request to owner") {
+ assert(machineCount(MachineType:L1Cache) > 1);
+ //
+ // Fixme! The unblock network should not stall on the forward network. Add a trigger queue to
+ // decouple the two.
+ //
+ peek(unblockNetwork_in, ResponseMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ assert(is_valid(tbe));
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:MERGED_GETS;
+ out_msg.MergedRequestors := tbe.GetSRequestors;
+ if (in_msg.Type == CoherenceResponseType:UNBLOCKS) {
+ out_msg.Destination.add(in_msg.CurOwner);
+ } else {
+ out_msg.Destination.add(in_msg.Sender);
+ }
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ out_msg.InitialRequestTime := zero_time();
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ }
+
+ action(fc_forwardRequestConditionalOwner, "fc", desc="Forward request to one or more nodes") {
+ assert(machineCount(MachineType:L1Cache) > 1);
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ assert(is_valid(cache_entry));
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.add(cache_entry.Owner);
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ out_msg.DirectedProbe := true;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ } else {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.broadcast(MachineType:L1Cache); // Send to all L1 caches
+ out_msg.Destination.remove(in_msg.Requestor); // Don't include the original requestor
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ }
+ }
+
+ action(nofc_forwardRequestConditionalOwner, "nofc", desc="Forward request to one or more nodes if the requestor is not the owner") {
+ if (machineCount(MachineType:L1Cache) > 1) {
+
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ peek(requestQueue_in, RequestMsg) {
+ if (in_msg.Requestor != cache_entry.Owner) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ assert(is_valid(cache_entry));
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.add(cache_entry.Owner);
+ out_msg.MessageSize := MessageSizeType:Request_Control;
+ out_msg.DirectedProbe := true;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ }
+ } else {
+ peek(requestQueue_in, RequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := in_msg.Type;
+ out_msg.Requestor := in_msg.Requestor;
+ out_msg.Destination.broadcast(MachineType:L1Cache); // Send to all L1 caches
+ out_msg.Destination.remove(in_msg.Requestor); // Don't include the original requestor
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ out_msg.InitialRequestTime := in_msg.InitialRequestTime;
+ out_msg.ForwardRequestTime := curCycle();
+ }
+ }
+ }
+ }
+ }
+
+ action(f_forwardWriteFromDma, "fw", desc="Forward requests") {
+ assert(is_valid(tbe));
+ if (tbe.NumPendingMsgs > 0) {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:GETX;
+ //
+ // Send to all L1 caches, since the requestor is the memory controller
+ // itself
+ //
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ }
+ }
+ }
+ }
+
+ action(f_forwardReadFromDma, "fr", desc="Forward requests") {
+ assert(is_valid(tbe));
+ if (tbe.NumPendingMsgs > 0) {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) {
+ out_msg.addr := address;
+ out_msg.Type := CoherenceRequestType:GETS;
+ //
+ // Send to all L1 caches, since the requestor is the memory controller
+ // itself
+ //
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.MessageSize := MessageSizeType:Broadcast_Control;
+ }
+ }
+ }
+ }
+
+ action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
+ requestQueue_in.dequeue(clockEdge());
+ }
+
+ action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
+ peek(unblockNetwork_in, ResponseMsg) {
+ APPEND_TRANSITION_COMMENT(in_msg.Sender);
+ }
+ unblockNetwork_in.dequeue(clockEdge());
+ }
+
+ action(k_wakeUpDependents, "k", desc="wake-up dependents") {
+ wakeUpBuffers(address);
+ }
+
+ action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
+ memQueue_in.dequeue(clockEdge());
+ }
+
+ action(g_popTriggerQueue, "g", desc="Pop trigger queue") {
+ triggerQueue_in.dequeue(clockEdge());
+ }
+
+ action(p_popDmaRequestQueue, "pd", desc="pop dma request queue") {
+ dmaRequestQueue_in.dequeue(clockEdge());
+ }
+
+ action(zd_stallAndWaitDMARequest, "zd", desc="Stall and wait the dma request queue") {
+ peek(dmaRequestQueue_in, DMARequestMsg) {
+ APPEND_TRANSITION_COMMENT(in_msg.Requestor);
+ }
+ stall_and_wait(dmaRequestQueue_in, address);
+ }
+
+ action(r_recordMemoryData, "rd", desc="record data from memory to TBE") {
+ peek(memQueue_in, MemoryMsg) {
+ assert(is_valid(tbe));
+ if (tbe.CacheDirty == false) {
+ tbe.DataBlk := in_msg.DataBlk;
+ }
+ }
+ }
+
+ action(r_recordCacheData, "rc", desc="record data from cache response to TBE") {
+ peek(responseToDir_in, ResponseMsg) {
+ assert(is_valid(tbe));
+ tbe.CacheDirty := true;
+ tbe.DataBlk := in_msg.DataBlk;
+ }
+ }
+
+ action(a_assertCacheData, "ac", desc="Assert that a cache provided the data") {
+ assert(is_valid(tbe));
+ assert(tbe.CacheDirty);
+ }
+
+ action(ano_assertNotOwner, "ano", desc="Assert that request is not current owner") {
+ if (probe_filter_enabled || full_bit_dir_enabled) {
+ peek(requestQueue_in, RequestMsg) {
+ assert(is_valid(cache_entry));
+ assert(cache_entry.Owner != in_msg.Requestor);
+ }
+ }
+ }
+
+ action(ans_assertNotSharer, "ans", desc="Assert that request is not a current sharer") {
+ if (full_bit_dir_enabled) {
+ peek(requestQueue_in, RequestMsg) {
+ assert(cache_entry.Sharers.isElement(machineIDToNodeID(in_msg.Requestor)) == false);
+ }
+ }
+ }
+
+ action(rs_removeSharer, "s", desc="remove current sharer") {
+ if (full_bit_dir_enabled) {
+ peek(unblockNetwork_in, ResponseMsg) {
+ assert(cache_entry.Sharers.isElement(machineIDToNodeID(in_msg.Sender)));
+ cache_entry.Sharers.remove(machineIDToNodeID(in_msg.Sender));
+ }
+ }
+ }
+
+ action(cs_clearSharers, "cs", desc="clear current sharers") {
+ if (full_bit_dir_enabled) {
+ peek(requestQueue_in, RequestMsg) {
+ cache_entry.Sharers.clear();
+ cache_entry.Sharers.add(machineIDToNodeID(in_msg.Requestor));
+ }
+ }
+ }
+
+ action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") {
+ peek(unblockNetwork_in, ResponseMsg) {
+ queueMemoryWrite(in_msg.Sender, address, to_memory_controller_latency,
+ in_msg.DataBlk);
+ }
+ }
+
+ action(ld_queueMemoryDmaWrite, "ld", desc="Write DMA data to memory") {
+ assert(is_valid(tbe));
+ queueMemoryWritePartial(tbe.DmaRequestor, tbe.PhysicalAddress,
+ to_memory_controller_latency, tbe.DmaDataBlk,
+ tbe.Len);
+ }
+
+ action(ly_queueMemoryWriteFromTBE, "ly", desc="Write data to memory from TBE") {
+ queueMemoryWrite(machineID, address, to_memory_controller_latency,
+ tbe.DataBlk);
+ }
+
+ action(ll_checkIncomingWriteback, "\l", desc="Check PUTX/PUTO response message") {
+ peek(unblockNetwork_in, ResponseMsg) {
+ assert(in_msg.Dirty == false);
+ assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
+ DPRINTF(RubySlicc, "%s\n", in_msg.DataBlk);
+ }
+ }
+
+ action(z_stallAndWaitRequest, "z", desc="Recycle the request queue") {
+ peek(requestQueue_in, RequestMsg) {
+ APPEND_TRANSITION_COMMENT(in_msg.Requestor);
+ }
+ stall_and_wait(requestQueue_in, address);
+ }
+
+ // TRANSITIONS
+
+ // Transitions out of E state
+ transition(E, GETX, NO_B_W) {
+ pfa_probeFilterAllocate;
+ v_allocateTBE;
+ rx_recordExclusiveInTBE;
+ saa_setAcksToAllIfPF;
+ qf_queueMemoryFetchRequest;
+ fn_forwardRequestIfNecessary;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(E, GETF, NO_F_W) {
+ pfa_probeFilterAllocate;
+ v_allocateTBE;
+ rx_recordExclusiveInTBE;
+ saa_setAcksToAllIfPF;
+ qf_queueMemoryFetchRequest;
+ fn_forwardRequestIfNecessary;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(E, GETS, NO_B_W) {
+ pfa_probeFilterAllocate;
+ v_allocateTBE;
+ rx_recordExclusiveInTBE;
+ saa_setAcksToAllIfPF;
+ qf_queueMemoryFetchRequest;
+ fn_forwardRequestIfNecessary;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(E, DMA_READ, NO_DR_B_W) {
+ vd_allocateDmaRequestInTBE;
+ qd_queueMemoryRequestFromDmaRead;
+ spa_setPendingAcksToZeroIfPF;
+ f_forwardReadFromDma;
+ p_popDmaRequestQueue;
+ }
+
+ transition(E, DMA_WRITE, NO_DW_B_W) {
+ vd_allocateDmaRequestInTBE;
+ spa_setPendingAcksToZeroIfPF;
+ sc_signalCompletionIfPF;
+ f_forwardWriteFromDma;
+ p_popDmaRequestQueue;
+ }
+
+ // Transitions out of O state
+ transition(O, GETX, NO_B_W) {
+ r_setMRU;
+ v_allocateTBE;
+ r_recordDataInTBE;
+ sa_setAcksToOne;
+ qf_queueMemoryFetchRequest;
+ fb_forwardRequestBcast;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(O, GETF, NO_F_W) {
+ r_setMRU;
+ v_allocateTBE;
+ r_recordDataInTBE;
+ sa_setAcksToOne;
+ qf_queueMemoryFetchRequest;
+ fb_forwardRequestBcast;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ // This transition is dumb, if a shared copy exists on-chip, then that should
+ // provide data, not slow off-chip dram. The problem is that the current
+ // caches don't provide data in S state
+ transition(O, GETS, O_B_W) {
+ r_setMRU;
+ v_allocateTBE;
+ r_recordDataInTBE;
+ saa_setAcksToAllIfPF;
+ qf_queueMemoryFetchRequest;
+ fn_forwardRequestIfNecessary;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(O, DMA_READ, O_DR_B_W) {
+ vd_allocateDmaRequestInTBE;
+ spa_setPendingAcksToZeroIfPF;
+ qd_queueMemoryRequestFromDmaRead;
+ f_forwardReadFromDma;
+ p_popDmaRequestQueue;
+ }
+
+ transition(O, Pf_Replacement, O_R) {
+ v_allocateTBE;
+ pa_setPendingMsgsToAll;
+ ia_invalidateAllRequest;
+ pfd_probeFilterDeallocate;
+ }
+
+ transition(S, Pf_Replacement, S_R) {
+ v_allocateTBE;
+ pa_setPendingMsgsToAll;
+ ia_invalidateAllRequest;
+ pfd_probeFilterDeallocate;
+ }
+
+ transition(NO, Pf_Replacement, NO_R) {
+ v_allocateTBE;
+ po_setPendingMsgsToOne;
+ io_invalidateOwnerRequest;
+ pfd_probeFilterDeallocate;
+ }
+
+ transition(NX, Pf_Replacement, NO_R) {
+ v_allocateTBE;
+ pa_setPendingMsgsToAll;
+ ia_invalidateAllRequest;
+ pfd_probeFilterDeallocate;
+ }
+
+ transition({O, S, NO, NX}, DMA_WRITE, NO_DW_B_W) {
+ vd_allocateDmaRequestInTBE;
+ f_forwardWriteFromDma;
+ p_popDmaRequestQueue;
+ }
+
+ // Transitions out of NO state
+ transition(NX, GETX, NO_B) {
+ r_setMRU;
+ fb_forwardRequestBcast;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(NX, GETF, NO_F) {
+ r_setMRU;
+ fb_forwardRequestBcast;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ // Transitions out of NO state
+ transition(NO, GETX, NO_B) {
+ r_setMRU;
+ ano_assertNotOwner;
+ fc_forwardRequestConditionalOwner;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(NO, GETF, NO_F) {
+ r_setMRU;
+ //ano_assertNotOwner;
+ nofc_forwardRequestConditionalOwner; //forward request if the requester is not the owner
+ cs_clearSharers;
+ oc_sendBlockAck; // send ack if the owner
+ i_popIncomingRequestQueue;
+ }
+
+ transition(S, GETX, NO_B) {
+ r_setMRU;
+ fb_forwardRequestBcast;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(S, GETF, NO_F) {
+ r_setMRU;
+ fb_forwardRequestBcast;
+ cs_clearSharers;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(S, GETS, NO_B) {
+ r_setMRU;
+ ano_assertNotOwner;
+ fb_forwardRequestBcast;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(NO, GETS, NO_B) {
+ r_setMRU;
+ ano_assertNotOwner;
+ ans_assertNotSharer;
+ fc_forwardRequestConditionalOwner;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(NX, GETS, NO_B) {
+ r_setMRU;
+ ano_assertNotOwner;
+ fc_forwardRequestConditionalOwner;
+ i_popIncomingRequestQueue;
+ }
+
+ transition({NO, NX, S}, PUT, WB) {
+ //
+ // note that the PUT requestor may not be the current owner if an invalidate
+ // raced with PUT
+ //
+ a_sendWriteBackAck;
+ i_popIncomingRequestQueue;
+ }
+
+ transition({NO, NX, S}, DMA_READ, NO_DR_B_D) {
+ vd_allocateDmaRequestInTBE;
+ f_forwardReadFromDma;
+ p_popDmaRequestQueue;
+ }
+
+ // Nack PUT requests when races cause us to believe we own the data
+ transition({O, E}, PUT) {
+ b_sendWriteBackNack;
+ i_popIncomingRequestQueue;
+ }
+
+ // Blocked transient states
+ transition({NO_B_X, O_B, NO_DR_B_W, NO_DW_B_W, NO_B_W, NO_DR_B_D,
+ NO_DR_B, O_DR_B, O_B_W, O_DR_B_W, NO_DW_W, NO_B_S_W,
+ NO_W, O_W, WB, WB_E_W, WB_O_W, O_R, S_R, NO_R, NO_F_W},
+ {GETS, GETX, GETF, PUT, Pf_Replacement}) {
+ z_stallAndWaitRequest;
+ }
+
+ transition(NO_F, {GETS, GETX, GETF, PUT, Pf_Replacement}){
+ z_stallAndWaitRequest;
+ }
+
+ transition(NO_B, {GETX, GETF}, NO_B_X) {
+ z_stallAndWaitRequest;
+ }
+
+ transition(NO_B, {PUT, Pf_Replacement}) {
+ z_stallAndWaitRequest;
+ }
+
+ transition(NO_B_S, {GETX, GETF, PUT, Pf_Replacement}) {
+ z_stallAndWaitRequest;
+ }
+
+ transition({NO_B_X, NO_B, NO_B_S, O_B, NO_DR_B_W, NO_DW_B_W, NO_B_W, NO_DR_B_D,
+ NO_DR_B, O_DR_B, O_B_W, O_DR_B_W, NO_DW_W, NO_B_S_W,
+ NO_W, O_W, WB, WB_E_W, WB_O_W, O_R, S_R, NO_R, NO_F_W},
+ {DMA_READ, DMA_WRITE}) {
+ zd_stallAndWaitDMARequest;
+ }
+
+ // merge GETS into one response
+ transition(NO_B, GETS, NO_B_S) {
+ v_allocateTBE;
+ rs_recordGetSRequestor;
+ i_popIncomingRequestQueue;
+ }
+
+ transition(NO_B_S, GETS) {
+ rs_recordGetSRequestor;
+ i_popIncomingRequestQueue;
+ }
+
+ // unblock responses
+ transition({NO_B, NO_B_X}, UnblockS, NX) {
+ us_updateSharerIfFBD;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition({NO_B, NO_B_X}, UnblockM, NO) {
+ uo_updateOwnerIfPf;
+ us_updateSharerIfFBD;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_B_S, UnblockS, NO_B_S_W) {
+ us_updateSharerIfFBD;
+ fr_forwardMergeReadRequestsToOwner;
+ sp_setPendingMsgsToMergedSharers;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_B_S, UnblockM, NO_B_S_W) {
+ uo_updateOwnerIfPf;
+ fr_forwardMergeReadRequestsToOwner;
+ sp_setPendingMsgsToMergedSharers;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_B_S_W, UnblockS) {
+ us_updateSharerIfFBD;
+ mu_decrementNumberOfUnblocks;
+ os_checkForMergedGetSCompletion;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_B_S_W, All_Unblocks, NX) {
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(O_B, UnblockS, O) {
+ us_updateSharerIfFBD;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(O_B, UnblockM, NO) {
+ us_updateSharerIfFBD;
+ uo_updateOwnerIfPf;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_B_W, Memory_Data, NO_B) {
+ d_sendData;
+ w_deallocateTBE;
+ l_popMemQueue;
+ }
+
+ transition(NO_F_W, Memory_Data, NO_F) {
+ d_sendData;
+ w_deallocateTBE;
+ l_popMemQueue;
+ }
+
+ transition(NO_DR_B_W, Memory_Data, NO_DR_B) {
+ r_recordMemoryData;
+ o_checkForCompletion;
+ l_popMemQueue;
+ }
+
+ transition(O_DR_B_W, Memory_Data, O_DR_B) {
+ r_recordMemoryData;
+ dr_sendDmaData;
+ o_checkForCompletion;
+ l_popMemQueue;
+ }
+
+ transition({NO_DR_B, O_DR_B, NO_DR_B_D, NO_DW_B_W}, Ack) {
+ m_decrementNumberOfMessages;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition({O_R, S_R, NO_R}, Ack) {
+ m_decrementNumberOfMessages;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition(S_R, Data) {
+ m_decrementNumberOfMessages;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition(NO_R, {Data, Exclusive_Data}) {
+ r_recordCacheData;
+ m_decrementNumberOfMessages;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition({O_R, S_R}, All_acks_and_data_no_sharers, E) {
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_R, All_acks_and_data_no_sharers, WB_E_W) {
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition({NO_DR_B_W, O_DR_B_W}, Ack) {
+ m_decrementNumberOfMessages;
+ n_popResponseQueue;
+ }
+
+ transition(NO_DR_B_W, Shared_Ack) {
+ m_decrementNumberOfMessages;
+ r_setSharerBit;
+ n_popResponseQueue;
+ }
+
+ transition(O_DR_B, Shared_Ack) {
+ m_decrementNumberOfMessages;
+ r_setSharerBit;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition(O_DR_B_W, Shared_Ack) {
+ m_decrementNumberOfMessages;
+ r_setSharerBit;
+ n_popResponseQueue;
+ }
+
+ transition({NO_DR_B, NO_DR_B_D}, Shared_Ack) {
+ m_decrementNumberOfMessages;
+ r_setSharerBit;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition(NO_DR_B_W, Shared_Data) {
+ r_recordCacheData;
+ m_decrementNumberOfMessages;
+ so_setOwnerBit;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition({NO_DR_B, NO_DR_B_D}, Shared_Data) {
+ r_recordCacheData;
+ m_decrementNumberOfMessages;
+ so_setOwnerBit;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition(NO_DR_B_W, {Exclusive_Data, Data}) {
+ r_recordCacheData;
+ m_decrementNumberOfMessages;
+ n_popResponseQueue;
+ }
+
+ transition({NO_DR_B, NO_DR_B_D, NO_DW_B_W}, {Exclusive_Data, Data}) {
+ r_recordCacheData;
+ m_decrementNumberOfMessages;
+ o_checkForCompletion;
+ n_popResponseQueue;
+ }
+
+ transition(NO_DR_B, All_acks_and_owner_data, WB_O_W) {
+ //
+ // Note that the DMA consistency model allows us to send the DMA device
+ // a response as soon as we receive valid data and prior to receiving
+ // all acks. However, to simplify the protocol we wait for all acks.
+ //
+ dt_sendDmaDataFromTbe;
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DR_B, All_acks_and_shared_data, S) {
+ //
+ // Note that the DMA consistency model allows us to send the DMA device
+ // a response as soon as we receive valid data and prior to receiving
+ // all acks. However, to simplify the protocol we wait for all acks.
+ //
+ dt_sendDmaDataFromTbe;
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DR_B_D, All_acks_and_owner_data, WB_O_W) {
+ //
+ // Note that the DMA consistency model allows us to send the DMA device
+ // a response as soon as we receive valid data and prior to receiving
+ // all acks. However, to simplify the protocol we wait for all acks.
+ //
+ dt_sendDmaDataFromTbe;
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DR_B_D, All_acks_and_shared_data, S) {
+ //
+ // Note that the DMA consistency model allows us to send the DMA device
+ // a response as soon as we receive valid data and prior to receiving
+ // all acks. However, to simplify the protocol we wait for all acks.
+ //
+ dt_sendDmaDataFromTbe;
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(O_DR_B, All_acks_and_owner_data, WB_O_W) {
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(O_DR_B, All_acks_and_data_no_sharers, WB_E_W) {
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ pfd_probeFilterDeallocate;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DR_B, All_acks_and_data_no_sharers, WB_E_W) {
+ //
+ // Note that the DMA consistency model allows us to send the DMA device
+ // a response as soon as we receive valid data and prior to receiving
+ // all acks. However, to simplify the protocol we wait for all acks.
+ //
+ dt_sendDmaDataFromTbe;
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ ppfd_possibleProbeFilterDeallocate;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DR_B_D, All_acks_and_data_no_sharers, WB_E_W) {
+ a_assertCacheData;
+ //
+ // Note that the DMA consistency model allows us to send the DMA device
+ // a response as soon as we receive valid data and prior to receiving
+ // all acks. However, to simplify the protocol we wait for all acks.
+ //
+ dt_sendDmaDataFromTbe;
+ ly_queueMemoryWriteFromTBE;
+ w_deallocateTBE;
+ ppfd_possibleProbeFilterDeallocate;
+ k_wakeUpDependents;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DW_B_W, All_acks_and_data_no_sharers, NO_DW_W) {
+ ld_queueMemoryDmaWrite;
+ g_popTriggerQueue;
+ }
+
+ transition(NO_DW_W, Memory_Ack, E) {
+ da_sendDmaAck;
+ w_deallocateTBE;
+ ppfd_possibleProbeFilterDeallocate;
+ k_wakeUpDependents;
+ l_popMemQueue;
+ }
+
+ transition(O_B_W, Memory_Data, O_B) {
+ d_sendData;
+ w_deallocateTBE;
+ l_popMemQueue;
+ }
+
+ transition(NO_B_W, UnblockM, NO_W) {
+ uo_updateOwnerIfPf;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_B_W, UnblockS, NO_W) {
+ us_updateSharerIfFBD;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(O_B_W, UnblockS, O_W) {
+ us_updateSharerIfFBD;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_W, Memory_Data, NO) {
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ l_popMemQueue;
+ }
+
+ transition(O_W, Memory_Data, O) {
+ w_deallocateTBE;
+ k_wakeUpDependents;
+ l_popMemQueue;
+ }
+
+ // WB State Transistions
+ transition(WB, Writeback_Dirty, WB_O_W) {
+ rs_removeSharer;
+ l_queueMemoryWBRequest;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(WB, Writeback_Exclusive_Dirty, WB_E_W) {
+ rs_removeSharer;
+ l_queueMemoryWBRequest;
+ pfd_probeFilterDeallocate;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(WB_E_W, Memory_Ack, E) {
+ k_wakeUpDependents;
+ l_popMemQueue;
+ }
+
+ transition(WB_O_W, Memory_Ack, O) {
+ k_wakeUpDependents;
+ l_popMemQueue;
+ }
+
+ transition(WB, Writeback_Clean, O) {
+ ll_checkIncomingWriteback;
+ rs_removeSharer;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(WB, Writeback_Exclusive_Clean, E) {
+ ll_checkIncomingWriteback;
+ rs_removeSharer;
+ pfd_probeFilterDeallocate;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(WB, Unblock, NX) {
+ auno_assertUnblockerNotOwner;
+ k_wakeUpDependents;
+ j_popIncomingUnblockQueue;
+ }
+
+ transition(NO_F, PUTF, WB) {
+ a_sendWriteBackAck;
+ i_popIncomingRequestQueue;
+ }
+
+ //possible race between GETF and UnblockM -- not sure needed any more?
+ transition(NO_F, UnblockM) {
+ us_updateSharerIfFBD;
+ uo_updateOwnerIfPf;
+ j_popIncomingUnblockQueue;
+ }
+}