/* * Copyright (c) 2010-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. * * Authors: Lisa Hsu */ machine(MachineType:Directory, "AMD_Base-like protocol") : DirectoryMemory * directory; CacheMemory * L3CacheMemory; Cycles response_latency := 5; Cycles response_latency_regionDir := 1; Cycles l3_hit_latency := 30; bool useL3OnWT := "False"; Cycles to_memory_controller_latency := 1; // From the Cores MessageBuffer * requestFromCores, network="From", virtual_network="0", vnet_type="request"; MessageBuffer * responseFromCores, network="From", virtual_network="2", vnet_type="response"; MessageBuffer * unblockFromCores, network="From", virtual_network="4", vnet_type="unblock"; // To the Cores MessageBuffer * probeToCore, network="To", virtual_network="0", vnet_type="request"; MessageBuffer * responseToCore, network="To", virtual_network="2", vnet_type="response"; // From region buffer MessageBuffer * reqFromRegBuf, network="From", virtual_network="7", vnet_type="request"; // To Region directory MessageBuffer * reqToRegDir, network="To", virtual_network="5", vnet_type="request"; MessageBuffer * reqFromRegDir, network="From", virtual_network="5", vnet_type="request"; MessageBuffer * unblockToRegDir, network="To", virtual_network="4", vnet_type="unblock"; MessageBuffer * triggerQueue; MessageBuffer * L3triggerQueue; MessageBuffer * responseFromMemory; { // STATES state_declaration(State, desc="Directory states", default="Directory_State_U") { U, AccessPermission:Backing_Store, desc="unblocked"; BR, AccessPermission:Backing_Store, desc="got CPU read request, blocked while sent to L3"; BW, AccessPermission:Backing_Store, desc="got CPU write request, blocked while sent to L3"; BL, AccessPermission:Busy, desc="got L3 WB request"; // BL is Busy because it's possible for the data only to be in the network // in the WB, L3 has sent it and gone on with its business in possibly I // state. BI, AccessPermission:Backing_Store, desc="Blocked waiting for inv ack from core"; 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"; // These are needed for when a private requests was issued before an inv was received // for writebacks BS_Pm_BL, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; BM_Pm_BL, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; B_Pm_BL, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; BP_BL, AccessPermission:Backing_Store, desc="blocked waiting for probes, no need for memory"; // for reads BS_Pm_B, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; BM_Pm_B, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; B_Pm_B, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; BP_B, AccessPermission:Backing_Store, desc="blocked waiting for probes, no need for memory"; } // Events enumeration(Event, desc="Directory events") { // CPU requests RdBlkS, desc="..."; RdBlkM, desc="..."; RdBlk, desc="..."; WriteThrough, desc="WriteThrough Message"; Atomic, desc="Atomic Message"; RdBlkSP, desc="..."; RdBlkMP, desc="..."; RdBlkP, desc="..."; VicDirtyP, desc="..."; VicCleanP, desc="..."; WriteThroughP, desc="WriteThrough Message"; AtomicP, desc="Atomic Message"; // writebacks VicDirty, desc="..."; VicClean, desc="..."; CPUData, desc="WB data from CPU"; StaleWB, desc="WB response for a no longer valid request"; // probe responses CPUPrbResp, desc="Probe Response Msg"; LastCPUPrbResp, desc="Last Probe Response Msg"; ProbeAcksComplete, desc="Probe Acks Complete"; L3Hit, desc="Hit in L3 return data to core"; // 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, self triggered"; StaleVicDirty, desc="Core invalidated before VicDirty processed"; StaleVicDirtyP, desc="Core invalidated before VicDirty processed"; // For region protocol CPUReq, desc="Generic CPU request"; Inv, desc="Region dir needs a block invalidated"; Downgrade, desc="Region dir needs a block downgraded"; // For private accesses (bypassed reg-dir) CPUReadP, desc="Initial req from core, sent to L3"; CPUWriteP, desc="Initial req from core, sent to L3"; } 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"; } // TYPES // 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"; } structure(TBE, desc="...") { State TBEState, desc="Transient state"; DataBlock DataBlk, desc="data for the block"; DataBlock DataBlkAux, desc="Auxiliary 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="..."; bool DemandRequest, desc="for profiling"; MachineID LastSender, desc="Mach which this block came from"; bool L3Hit, default="false", desc="Was this an L3 hit?"; bool TriggeredAcksComplete, default="false", desc="True if already triggered acks complete"; WriteMask writeMask, desc="outstanding write through mask"; } structure(TBETable, external="yes") { TBE lookup(Addr); void allocate(Addr); void deallocate(Addr); bool isPresent(Addr); } TBETable TBEs, template="", constructor="m_number_of_TBEs"; Tick clockEdge(); Tick cyclesToTicks(Cycles c); void set_tbe(TBE a); void unset_tbe(); void wakeUpAllBuffers(); void wakeUpBuffers(Addr a); Cycles curCycle(); MachineID mapAddressToMachine(Addr addr, MachineType mtype); 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) { return getDirectoryEntry(addr).DirectoryState; } State getStateFromAddr(Addr addr) { return getDirectoryEntry(addr).DirectoryState; } void setState(TBE tbe, CacheEntry entry, Addr addr, State state) { getDirectoryEntry(addr).DirectoryState := state; } 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 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; } 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); } } 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 { error("Invalid RequestType type in checkResourceAvailable"); return true; } } // ** OUT_PORTS ** out_port(probeNetwork_out, NBProbeRequestMsg, probeToCore); out_port(responseNetwork_out, ResponseMsg, responseToCore); out_port(requestNetworkReg_out, CPURequestMsg, reqToRegDir); out_port(regAckNetwork_out, UnblockMsg, unblockToRegDir); out_port(triggerQueue_out, TriggerMsg, triggerQueue); out_port(L3TriggerQueue_out, TriggerMsg, L3triggerQueue); // ** IN_PORTS ** // Trigger Queue in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=7) { 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=6) { 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=5) { 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=4) { if (responseNetwork_in.isReady(clockEdge())) { peek(responseNetwork_in, ResponseMsg) { DPRINTF(RubySlicc, "core responses %s\n", in_msg); TBE tbe := TBEs.lookup(in_msg.addr); CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); if (in_msg.Type == CoherenceResponseType:CPUPrbResp) { if (is_valid(tbe) && tbe.NumPendingAcks == 1 && tbe.TriggeredAcksComplete == false) { trigger(Event:LastCPUPrbResp, in_msg.addr, entry, tbe); } else { 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=3) { 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(regBuf_in, CPURequestMsg, reqFromRegBuf, rank=2) { if (regBuf_in.isReady(clockEdge())) { peek(regBuf_in, CPURequestMsg) { TBE tbe := TBEs.lookup(in_msg.addr); CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); if (in_msg.Type == CoherenceRequestType:ForceInv) { trigger(Event:Inv, in_msg.addr, entry, tbe); } else if (in_msg.Type == CoherenceRequestType:ForceDowngrade) { trigger(Event:Downgrade, in_msg.addr, entry, tbe); } else { error("Bad request from region buffer"); } } } } in_port(regDir_in, CPURequestMsg, reqFromRegDir, rank=1) { if (regDir_in.isReady(clockEdge())) { peek(regDir_in, CPURequestMsg) { TBE tbe := TBEs.lookup(in_msg.addr); CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); 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:Atomic) { trigger(Event:Atomic, 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: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 { 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 { trigger(Event:VicClean, in_msg.addr, entry, tbe); } } else { error("Bad message type fwded from Region Dir"); } } } } 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 (in_msg.Private) { // Bypass the region dir if (in_msg.Type == CoherenceRequestType:RdBlk) { trigger(Event:RdBlkP, in_msg.addr, entry, tbe); } else if (in_msg.Type == CoherenceRequestType:RdBlkS) { trigger(Event:RdBlkSP, in_msg.addr, entry, tbe); } else if (in_msg.Type == CoherenceRequestType:RdBlkM) { trigger(Event:RdBlkMP, in_msg.addr, entry, tbe); } else if (in_msg.Type == CoherenceRequestType:Atomic) { trigger(Event:AtomicP, in_msg.addr, entry, tbe); } else if (in_msg.Type == CoherenceRequestType:WriteThrough) { trigger(Event:WriteThroughP, 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 VicDirtyP for address %s\n", in_msg.addr); trigger(Event:StaleVicDirtyP, in_msg.addr, entry, tbe); } else { DPRINTF(RubySlicc, "Got VicDirty from %s on %s\n", in_msg.Requestor, in_msg.addr); trigger(Event:VicDirtyP, 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 VicCleanP for address %s\n", in_msg.addr); trigger(Event:StaleVicDirtyP, in_msg.addr, entry, tbe); } else { DPRINTF(RubySlicc, "Got VicClean from %s on %s\n", in_msg.Requestor, in_msg.addr); trigger(Event:VicCleanP, in_msg.addr, entry, tbe); } } else { error("Bad message type for private access"); } } else { trigger(Event:CPUReq, in_msg.addr, entry, tbe); } } } } // 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.DemandRequest := tbe.DemandRequest; 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.DemandRequest := tbe.DemandRequest; out_msg.L3Hit := tbe.L3Hit; DPRINTF(RubySlicc, "%s\n", out_msg); } } 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; out_msg.DemandRequest := tbe.DemandRequest; out_msg.L3Hit := tbe.L3Hit; if (tbe.atomicData) { out_msg.WTRequestor := tbe.WTRequestor; } DPRINTF(RubySlicc, "%s\n", out_msg); } if (tbe.atomicData) { enqueue(triggerQueue_out, TriggerMsg, 1) { out_msg.addr := address; out_msg.Type := TriggerType:UnblockWriteThrough; } } } } action(sb_sendResponseSBypass, "sb", desc="send Shared response") { peek(requestNetwork_in, CPURequestMsg) { 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(in_msg.Requestor); out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.Dirty := false; out_msg.State := CoherenceState:Shared; out_msg.InitialRequestTime := in_msg.InitialRequestTime; out_msg.ForwardRequestTime := curCycle(); out_msg.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; out_msg.OriginalResponder := tbe.LastSender; out_msg.DemandRequest := false; out_msg.L3Hit := tbe.L3Hit; DPRINTF(RubySlicc, "%s\n", out_msg); } } } action(esb_sendResponseESBypass, "esb", desc="send Exclusive or Shared response") { peek(requestNetwork_in, CPURequestMsg) { 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(in_msg.Requestor); out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.Dirty := tbe.Dirty; if (tbe.Cached || in_msg.ForceShared) { out_msg.State := CoherenceState:Shared; } else { out_msg.State := CoherenceState:Exclusive; } out_msg.InitialRequestTime := in_msg.InitialRequestTime; out_msg.ForwardRequestTime := curCycle(); out_msg.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; out_msg.OriginalResponder := tbe.LastSender; out_msg.DemandRequest := false; out_msg.L3Hit := tbe.L3Hit; DPRINTF(RubySlicc, "%s\n", out_msg); } } } action(mbwt_sendResponseWriteThroughBypass, "mbwt", desc="send write through response") { peek(requestNetwork_in, CPURequestMsg) { if (in_msg.Type == CoherenceRequestType:WriteThrough) { enqueue(responseNetwork_out, ResponseMsg, response_latency) { 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 := in_msg.ProbeRequestStartTime; out_msg.DemandRequest := false; } } else { assert(in_msg.Type == CoherenceRequestType:Atomic); 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(in_msg.Requestor); out_msg.DataBlk := getDirectoryEntry(address).DataBlk; out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.Dirty := in_msg.Dirty; out_msg.State := CoherenceState:Modified; out_msg.CtoD := false; out_msg.InitialRequestTime := in_msg.InitialRequestTime; out_msg.ForwardRequestTime := curCycle(); out_msg.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; out_msg.OriginalResponder := tbe.LastSender; out_msg.DemandRequest := false; out_msg.L3Hit := tbe.L3Hit; out_msg.WTRequestor := in_msg.WTRequestor; DPRINTF(RubySlicc, "%s\n", out_msg); } } enqueue(triggerQueue_out, TriggerMsg, 1) { out_msg.addr := address; out_msg.Type := TriggerType:UnblockWriteThrough; } } } action(mb_sendResponseMBypass, "mb", desc="send Modified response") { peek(requestNetwork_in, CPURequestMsg) { 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(in_msg.Requestor); 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 := in_msg.InitialRequestTime; out_msg.ForwardRequestTime := curCycle(); out_msg.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; out_msg.OriginalResponder := tbe.LastSender; out_msg.DemandRequest := false; out_msg.L3Hit := tbe.L3Hit; DPRINTF(RubySlicc, "%s\n", out_msg); } } } 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; out_msg.DemandRequest := tbe.DemandRequest; DPRINTF(RubySlicc, "%s\n", out_msg); } } action(cp_sendResponseCtoDP, "cp", desc="send CtoD Ack") { peek(requestNetwork_in, CPURequestMsg) { enqueue(responseNetwork_out, ResponseMsg, response_latency) { out_msg.addr := address; out_msg.Type := CoherenceResponseType:NBSysResp; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Response_Control; out_msg.Dirty := false; out_msg.State := CoherenceState:Modified; out_msg.CtoD := true; out_msg.InitialRequestTime := in_msg.InitialRequestTime; out_msg.ForwardRequestTime := curCycle(); out_msg.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; out_msg.DemandRequest := false; DPRINTF(RubySlicc, "%s\n", out_msg); } } } action(w_sendResponseWBAck, "w", desc="send WB Ack") { peek(regDir_in, CPURequestMsg) { enqueue(responseNetwork_out, ResponseMsg, response_latency) { 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 := in_msg.ForwardRequestTime; out_msg.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; out_msg.DemandRequest := false; } } } action(wp_sendResponseWBAckP, "wp", desc="send WB Ack") { peek(requestNetwork_in, CPURequestMsg) { enqueue(responseNetwork_out, ResponseMsg, response_latency) { 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 := in_msg.ProbeRequestStartTime; out_msg.DemandRequest := false; } } } action(wc_sendResponseWBAck, "wc", desc="send WB Ack for cancel") { peek(responseNetwork_in, ResponseMsg) { enqueue(responseNetwork_out, ResponseMsg, response_latency) { out_msg.addr := address; out_msg.Type := CoherenceResponseType:NBSysWBAck; out_msg.Destination.add(in_msg.Sender); out_msg.Sender := machineID; out_msg.MessageSize := MessageSizeType:Writeback_Control; } } } action(ra_ackRegionDir, "ra", desc="Ack region dir") { peek(regDir_in, CPURequestMsg) { if (in_msg.NoAckNeeded == false) { enqueue(responseNetwork_out, ResponseMsg, response_latency_regionDir) { out_msg.addr := address; out_msg.Type := CoherenceResponseType:DirReadyAck; out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); out_msg.Sender := machineID; out_msg.MessageSize := MessageSizeType:Writeback_Control; } } } } action(l_queueMemRdReq, "lr", desc="Read data from memory") { peek(regDir_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; DPRINTF(RubySlicc, "L3 data is %s\n", entry.DataBlk); L3CacheMemory.deallocate(address); } else { queueMemoryRead(machineID, address, to_memory_controller_latency); } } } action(lrp_queueMemRdReqP, "lrp", 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; DPRINTF(RubySlicc, "L3 data is %s\n", entry.DataBlk); L3CacheMemory.deallocate(address); } else { queueMemoryRead(machineID, address, to_memory_controller_latency); } } } action(dcr_probeInvCoreData, "dcr", desc="probe inv cores, return data") { peek(regBuf_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; out_msg.Destination := in_msg.Sharers; tbe.NumPendingAcks := tbe.NumPendingAcks + in_msg.Sharers.count(); DPRINTF(RubySlicc, "%s\n", out_msg); APPEND_TRANSITION_COMMENT(" dcr: Acks remaining: "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); tbe.ProbeRequestStartTime := curCycle(); } } } action(ddr_probeDownCoreData, "ddr", desc="probe inv cores, return data") { peek(regBuf_in, CPURequestMsg) { enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) { out_msg.addr := address; out_msg.Type := ProbeRequestType:PrbDowngrade; out_msg.ReturnData := true; out_msg.MessageSize := MessageSizeType:Control; out_msg.Destination := in_msg.Sharers; tbe.NumPendingAcks := tbe.NumPendingAcks + in_msg.Sharers.count(); DPRINTF(RubySlicc, "%s\n", out_msg); APPEND_TRANSITION_COMMENT(" dcr: Acks remaining: "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); 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; out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket tbe.NumPendingAcks := tbe.NumPendingAcks +machineCount(MachineType:CorePair) - 1; out_msg.Destination.broadcast(MachineType:TCP); tbe.NumPendingAcks := tbe.NumPendingAcks + machineCount(MachineType:TCP); out_msg.Destination.broadcast(MachineType:SQC); tbe.NumPendingAcks := tbe.NumPendingAcks + machineCount(MachineType:SQC); out_msg.Destination.remove(in_msg.Requestor); 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; out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket tbe.NumPendingAcks := tbe.NumPendingAcks +machineCount(MachineType:CorePair) - 1; out_msg.Destination.broadcast(MachineType:TCP); tbe.NumPendingAcks := tbe.NumPendingAcks + machineCount(MachineType:TCP); out_msg.Destination.broadcast(MachineType:SQC); tbe.NumPendingAcks := tbe.NumPendingAcks + machineCount(MachineType:SQC); out_msg.Destination.remove(in_msg.Requestor); APPEND_TRANSITION_COMMENT(" ic: Acks remaining: "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); DPRINTF(RubySlicc, "%s\n", out_msg); tbe.ProbeRequestStartTime := curCycle(); } } } 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(t_allocateTBE, "t", desc="allocate TBE Entry") { check_allocate(TBEs); peek(regDir_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; tbe.ForwardRequestTime := curCycle(); tbe.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; tbe.DemandRequest := in_msg.DemandRequest; } } action(tp_allocateTBEP, "tp", 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; tbe.ForwardRequestTime := curCycle(); tbe.ProbeRequestStartTime := in_msg.ProbeRequestStartTime; tbe.DemandRequest := false; } } action(sa_setAcks, "sa", desc="setAcks") { peek(regDir_in, CPURequestMsg) { tbe.NumPendingAcks := in_msg.Acks; APPEND_TRANSITION_COMMENT(" waiting for acks "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); } } action(tr_allocateTBE, "tr", desc="allocate TBE Entry for Region inv") { check_allocate(TBEs); TBEs.allocate(address); set_tbe(TBEs.lookup(address)); tbe.NumPendingAcks := 0; } action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") { TBEs.deallocate(address); unset_tbe(); } action(wdp_writeBackDataPrivate, "wdp", desc="Write back data if needed") { peek(requestNetwork_in, CPURequestMsg) { if (in_msg.Type == CoherenceRequestType:WriteThrough) { tbe.DataBlkAux := getDirectoryEntry(address).DataBlk; tbe.DataBlkAux.copyPartial(in_msg.DataBlk,in_msg.writeMask); getDirectoryEntry(address).DataBlk := tbe.DataBlkAux; } else{ assert(in_msg.Type == CoherenceRequestType:Atomic); tbe.DataBlkAux.atomicPartial(getDirectoryEntry(address).DataBlk,in_msg.writeMask); getDirectoryEntry(address).DataBlk := tbe.DataBlkAux; } } } 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 == true) { APPEND_TRANSITION_COMMENT(" Wrote data back "); getDirectoryEntry(address).DataBlk := tbe.DataBlk; } } action(wdi_writeBackDataInv, "wdi", desc="Write back inv data if needed") { // Kind of opposite from above...? if (tbe.Dirty == true) { getDirectoryEntry(address).DataBlk := tbe.DataBlk; APPEND_TRANSITION_COMMENT("Writing dirty data to dir"); DPRINTF(RubySlicc, "Data %s: %s\n", address, tbe.DataBlk); } else { APPEND_TRANSITION_COMMENT("NOT!!! Writing dirty data to dir"); } } action(wdt_writeBackDataInvNoTBE, "wdt", desc="Write back inv data if needed no TBE") { // Kind of opposite from above...? peek(responseNetwork_in, ResponseMsg) { if (in_msg.Dirty == true) { getDirectoryEntry(address).DataBlk := in_msg.DataBlk; APPEND_TRANSITION_COMMENT("Writing dirty data to dir"); DPRINTF(RubySlicc, "Data %s: %s\n", address, in_msg.DataBlk); } else { APPEND_TRANSITION_COMMENT("NOT!!! Writing dirty data to dir"); } } } action(mt_writeMemDataToTBE, "mt", desc="write Mem data to TBE") { peek(memQueue_in, MemoryMsg) { if (tbe.Dirty == false) { tbe.DataBlk := getDirectoryEntry(address).DataBlk; } tbe.MemData := true; } } action(ml_writeL3DataToTBE, "ml", desc="write L3 data to TBE") { assert(tbe.Dirty == false); CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address)); tbe.DataBlk := entry.DataBlk; tbe.LastSender := entry.LastSender; tbe.L3Hit := true; 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(yc_writeCPUDataToTBE, "yc", desc="write CPU 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.Dirty) { 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 } tbe.DataBlk := in_msg.DataBlk; tbe.Dirty := false; tbe.LastSender := in_msg.Sender; } } } action(x_decrementAcks, "x", desc="decrement Acks pending") { if (tbe.NumPendingAcks > 0) { tbe.NumPendingAcks := tbe.NumPendingAcks - 1; } else { APPEND_TRANSITION_COMMENT(" Double ack! "); } assert(tbe.NumPendingAcks >= 0); APPEND_TRANSITION_COMMENT(" Acks remaining: "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); } action(o_checkForCompletion, "o", desc="check for ack completion") { if (tbe.NumPendingAcks == 0 && tbe.TriggeredAcksComplete == false) { enqueue(triggerQueue_out, TriggerMsg, 1) { out_msg.addr := address; out_msg.Type := TriggerType:AcksComplete; } tbe.TriggeredAcksComplete := true; } APPEND_TRANSITION_COMMENT(" Check: Acks remaining: "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); } action(ont_checkForCompletionNoTrigger, "ont", desc="check for ack completion, no trigger") { if (tbe.NumPendingAcks == 0 && tbe.TriggeredAcksComplete == false) { tbe.TriggeredAcksComplete := true; } APPEND_TRANSITION_COMMENT(" Check: Acks remaining: "); APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); } action(rvp_removeVicDirtyIgnore, "rvp", desc="Remove ignored core") { peek(requestNetwork_in, CPURequestMsg) { getDirectoryEntry(address).VicDirtyIgnore.remove(in_msg.Requestor); } } action(rv_removeVicDirtyIgnore, "rv", desc="Remove ignored core") { peek(regDir_in, CPURequestMsg) { getDirectoryEntry(address).VicDirtyIgnore.remove(in_msg.Requestor); } } action(r_sendRequestToRegionDir, "r", desc="send request to Region Directory") { peek(requestNetwork_in, CPURequestMsg) { enqueue(requestNetworkReg_out, CPURequestMsg, 1) { out_msg.addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); out_msg.Shared := in_msg.Shared; out_msg.MessageSize := in_msg.MessageSize; DPRINTF(RubySlicc, "out dest: %s\n", mapAddressToMachine(address, MachineType:RegionDir)); } } } action(ai_ackInvalidate, "ai", desc="Ack to let the reg-dir know that the inv is ordered") { peek(regBuf_in, CPURequestMsg) { enqueue(regAckNetwork_out, UnblockMsg, 1) { out_msg.addr := address; out_msg.Destination.add(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Response_Control; DPRINTF(RubySlicc, "ai out_msg: %s\n", out_msg); } } } action(aic_ackInvalidate, "aic", desc="Ack to let the reg-dir know that the inv is ordered") { peek(responseNetwork_in, ResponseMsg) { if (in_msg.NoAckNeeded == false) { enqueue(regAckNetwork_out, UnblockMsg, 1) { out_msg.addr := address; if (machineIDToMachineType(in_msg.Sender) == MachineType:CorePair) { out_msg.Destination.add(createMachineID(MachineType:RegionBuffer, intToID(0))); } else { out_msg.Destination.add(createMachineID(MachineType:RegionBuffer, intToID(1))); } out_msg.MessageSize := MessageSizeType:Response_Control; DPRINTF(RubySlicc, "ai out_msg: %s\n", out_msg); out_msg.wasValid := in_msg.isValid; } } } } 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(ali_allocateL3Block, "ali", desc="allocate the L3 block on ForceInv") { if (tbe.Dirty == true) { 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(ali_allocateL3BlockNoTBE, "alt", desc="allocate the L3 block on ForceInv no TBE") { peek(responseNetwork_in, ResponseMsg) { if (in_msg.Dirty) { if (L3CacheMemory.isTagPresent(address)) { CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address)); APPEND_TRANSITION_COMMENT(" ali 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(" ali wrote data to L3 "); entry.DataBlk := in_msg.DataBlk; entry.LastSender := in_msg.Sender; } } } } 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(prd_popRegionQueue, "prd", desc="pop request queue") { regDir_in.dequeue(clockEdge()); } action(prb_popRegionBufQueue, "prb", desc="pop request queue") { regBuf_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(yy_recycleResponseQueue, "yy", desc="recycle response queue") { responseNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); } action(ww_stallAndWaitRegRequestQueue, "ww", desc="recycle region dir request queue") { stall_and_wait(regDir_in, address); } 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 // transitions from U transition({BR, BW, BL, BI, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, {Inv, Downgrade}) { ww_stallAndWaitRegRequestQueue; } transition(U, Inv, BI){L3TagArrayRead} { tr_allocateTBE; dcr_probeInvCoreData; // only need to invalidate sharers ai_ackInvalidate; prb_popRegionBufQueue; } transition(U, Downgrade, BI){L3TagArrayRead} { tr_allocateTBE; ddr_probeDownCoreData; // only need to invalidate sharers ai_ackInvalidate; prb_popRegionBufQueue; } // The next 2 transistions are needed in the event that an invalidation // is waiting for its ack from the core, but the event makes it through // the region directory before the acks. This wouldn't be needed if // we waited to ack the region dir until the directory got all the acks transition({BR, BW, BI, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, {RdBlkS, RdBlkM, RdBlk, WriteThrough, Atomic}) { ww_stallAndWaitRegRequestQueue; } transition({BR, BW, BI, BL, BS_M, BM_M, B_M, BS_PM, BM_PM, B_PM, B, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, {RdBlkSP, RdBlkMP, RdBlkP}) { st_stallAndWaitRequest; } transition({BR, BW, BI, BL, BS_M, BM_M, B_M, BS_PM, BM_PM, B_PM, B, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, {WriteThroughP,AtomicP}) { st_stallAndWaitRequest; } transition(U, {RdBlkS}, BS_PM) {L3TagArrayRead} { t_allocateTBE; l_queueMemRdReq; sa_setAcks; o_checkForCompletion; ra_ackRegionDir; prd_popRegionQueue; } transition(U, WriteThrough, BM_PM){L3TagArrayRead} { t_allocateTBE; w_sendResponseWBAck; l_queueMemRdReq; sa_setAcks; o_checkForCompletion; ra_ackRegionDir; prd_popRegionQueue; } transition(U, {RdBlkM,Atomic}, BM_PM){L3TagArrayRead} { t_allocateTBE; l_queueMemRdReq; sa_setAcks; o_checkForCompletion; ra_ackRegionDir; prd_popRegionQueue; } transition(U, RdBlk, B_PM){L3TagArrayRead} { t_allocateTBE; l_queueMemRdReq; sa_setAcks; o_checkForCompletion; ra_ackRegionDir; prd_popRegionQueue; } transition(U, {RdBlkSP}, BS_M) {L3TagArrayRead} { tp_allocateTBEP; lrp_queueMemRdReqP; p_popRequestQueue; } transition(U, WriteThroughP, BM_M) {L3TagArrayRead} { tp_allocateTBEP; wp_sendResponseWBAckP; lrp_queueMemRdReqP; p_popRequestQueue; } transition(U, {RdBlkMP,AtomicP}, BM_M) {L3TagArrayRead} { tp_allocateTBEP; lrp_queueMemRdReqP; p_popRequestQueue; } transition(U, RdBlkP, B_M) {L3TagArrayRead} { tp_allocateTBEP; lrp_queueMemRdReqP; p_popRequestQueue; } transition(U, VicDirtyP, BL) {L3TagArrayRead} { tp_allocateTBEP; wp_sendResponseWBAckP; p_popRequestQueue; } transition(U, VicCleanP, BL) {L3TagArrayRead} { tp_allocateTBEP; wp_sendResponseWBAckP; p_popRequestQueue; } transition(BM_Pm, RdBlkSP, BM_Pm_B) {L3DataArrayWrite} { sb_sendResponseSBypass; p_popRequestQueue; } transition(BS_Pm, RdBlkSP, BS_Pm_B) {L3DataArrayWrite} { sb_sendResponseSBypass; p_popRequestQueue; } transition(B_Pm, RdBlkSP, B_Pm_B) {L3DataArrayWrite} { sb_sendResponseSBypass; p_popRequestQueue; } transition(BP, RdBlkSP, BP_B) {L3DataArrayWrite} { sb_sendResponseSBypass; p_popRequestQueue; } transition(BM_Pm, RdBlkMP, BM_Pm_B) {L3DataArrayWrite} { mb_sendResponseMBypass; p_popRequestQueue; } transition(BS_Pm, RdBlkMP, BS_Pm_B) {L3DataArrayWrite} { mb_sendResponseMBypass; p_popRequestQueue; } transition(B_Pm, RdBlkMP, B_Pm_B) {L3DataArrayWrite} { mb_sendResponseMBypass; p_popRequestQueue; } transition(BP, RdBlkMP, BP_B) {L3DataArrayWrite} { mb_sendResponseMBypass; p_popRequestQueue; } transition(BM_Pm, {WriteThroughP,AtomicP}, BM_Pm_B) {L3DataArrayWrite} { wdp_writeBackDataPrivate; mbwt_sendResponseWriteThroughBypass; p_popRequestQueue; } transition(BS_Pm, {WriteThroughP,AtomicP}, BS_Pm_B) {L3DataArrayWrite} { wdp_writeBackDataPrivate; mbwt_sendResponseWriteThroughBypass; p_popRequestQueue; } transition(B_Pm, {WriteThroughP,AtomicP}, B_Pm_B) {L3DataArrayWrite} { wdp_writeBackDataPrivate; mbwt_sendResponseWriteThroughBypass; p_popRequestQueue; } transition(BP, {WriteThroughP,AtomicP}, BP_B) {L3DataArrayWrite} { wdp_writeBackDataPrivate; mbwt_sendResponseWriteThroughBypass; p_popRequestQueue; } transition(BM_Pm, RdBlkP, BM_Pm_B) {L3DataArrayWrite} { esb_sendResponseESBypass; p_popRequestQueue; } transition(BS_Pm, RdBlkP, BS_Pm_B) {L3DataArrayWrite} { esb_sendResponseESBypass; p_popRequestQueue; } transition(B_Pm, RdBlkP, B_Pm_B) {L3DataArrayWrite}{ esb_sendResponseESBypass; p_popRequestQueue; } transition(BP, RdBlkP, BP_B) {L3DataArrayWrite}{ esb_sendResponseESBypass; p_popRequestQueue; } transition(BM_Pm_B, CoreUnblock, BM_Pm) { wa_wakeUpDependents; pu_popUnblockQueue; } transition(BS_Pm_B, CoreUnblock, BS_Pm) { wa_wakeUpDependents; pu_popUnblockQueue; } transition(B_Pm_B, CoreUnblock, B_Pm) { wa_wakeUpDependents; pu_popUnblockQueue; } transition(BP_B, CoreUnblock, BP) { wa_wakeUpDependents; pu_popUnblockQueue; } transition(BM_Pm_B, UnblockWriteThrough, BM_Pm) { wa_wakeUpDependents; pt_popTriggerQueue; } transition(BS_Pm_B, UnblockWriteThrough, BS_Pm) { wa_wakeUpDependents; pt_popTriggerQueue; } transition(B_Pm_B, UnblockWriteThrough, B_Pm) { wa_wakeUpDependents; pt_popTriggerQueue; } transition(BP_B, UnblockWriteThrough, BP) { wa_wakeUpDependents; pt_popTriggerQueue; } transition(BM_Pm, VicDirtyP, BM_Pm_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(BS_Pm, VicDirtyP, BS_Pm_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(B_Pm, VicDirtyP, B_Pm_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(BP, VicDirtyP, BP_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(BM_Pm, VicCleanP, BM_Pm_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(BS_Pm, VicCleanP, BS_Pm_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(B_Pm, VicCleanP, B_Pm_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(BP, VicCleanP, BP_BL) { wp_sendResponseWBAckP; p_popRequestQueue; } transition(BM_Pm_BL, CPUData, BM_Pm) { yc_writeCPUDataToTBE; d_writeDataToMemory; wa_wakeUpDependents; pr_popResponseQueue; } transition(BS_Pm_BL, CPUData, BS_Pm) { yc_writeCPUDataToTBE; d_writeDataToMemory; wa_wakeUpDependents; pr_popResponseQueue; } transition(B_Pm_BL, CPUData, B_Pm) { yc_writeCPUDataToTBE; d_writeDataToMemory; wa_wakeUpDependents; pr_popResponseQueue; } transition(BP_BL, CPUData, BP) { yc_writeCPUDataToTBE; d_writeDataToMemory; wa_wakeUpDependents; pr_popResponseQueue; } transition({BR, BW, BL}, {VicDirtyP, VicCleanP}) { st_stallAndWaitRequest; } transition({BR, BW, BL}, {VicDirty, VicClean}) { ww_stallAndWaitRegRequestQueue; } transition(BL, CPUData, U) {L3TagArrayWrite, L3DataArrayWrite} { dt_deallocateTBE; d_writeDataToMemory; al_allocateL3Block; wa_wakeUpDependents; pr_popResponseQueue; } transition(BL, StaleWB, U) {L3TagArrayWrite} { dt_deallocateTBE; wa_wakeUpAllDependents; pr_popResponseQueue; } transition({BI, B, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, {VicDirty, VicClean}) { ww_stallAndWaitRegRequestQueue; } transition({BI, B, BS_M, BM_M, B_M, BS_PM, BM_PM, B_PM, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, {VicDirtyP, VicCleanP}) { st_stallAndWaitRequest; } transition({U, BR, BW, BL, BI, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, WBAck) { pm_popMemQueue; } transition({U, BR, BW, BL, BI, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, StaleVicDirtyP) { rvp_removeVicDirtyIgnore; wp_sendResponseWBAckP; p_popRequestQueue; } transition({U, BR, BW, BL, BI, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B, BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, StaleVicDirty) { rv_removeVicDirtyIgnore; w_sendResponseWBAck; prd_popRegionQueue; } transition(U, VicDirty, BL) {L3TagArrayRead} { t_allocateTBE; ra_ackRegionDir; w_sendResponseWBAck; prd_popRegionQueue; } transition(U, VicClean, BL) {L3TagArrayRead} { t_allocateTBE; ra_ackRegionDir; w_sendResponseWBAck; prd_popRegionQueue; } transition({B, BR}, CoreUnblock, U) { wa_wakeUpDependents; pu_popUnblockQueue; } transition({B, BR}, UnblockWriteThrough, U) { wa_wakeUpDependents; pt_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_PM, MemData, BS_Pm) {} { mt_writeMemDataToTBE; wa_wakeUpDependents; pm_popMemQueue; } transition(BM_PM, MemData, BM_Pm){} { mt_writeMemDataToTBE; wa_wakeUpDependents; pm_popMemQueue; } transition(B_PM, MemData, B_Pm){} { mt_writeMemDataToTBE; wa_wakeUpDependents; pm_popMemQueue; } transition(BS_M, L3Hit, B) {L3TagArrayWrite, L3DataArrayWrite} { s_sendResponseS; wd_writeBackData; alwt_allocateL3BlockOnWT; dt_deallocateTBE; ptl_popTriggerQueue; } transition(BM_M, L3Hit, B) {L3TagArrayWrite, L3DataArrayWrite} { m_sendResponseM; wd_writeBackData; alwt_allocateL3BlockOnWT; dt_deallocateTBE; ptl_popTriggerQueue; } transition(B_M, L3Hit, B) {L3TagArrayWrite, L3DataArrayWrite} { es_sendResponseES; wd_writeBackData; alwt_allocateL3BlockOnWT; dt_deallocateTBE; ptl_popTriggerQueue; } transition(BS_PM, L3Hit, BS_Pm) { wa_wakeUpDependents; ptl_popTriggerQueue; } transition(BM_PM, L3Hit, BM_Pm) { wa_wakeUpDependents; ptl_popTriggerQueue; } transition(B_PM, L3Hit, B_Pm) { wa_wakeUpDependents; ptl_popTriggerQueue; } transition({BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, BP, BI}, CPUPrbResp) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; pr_popResponseQueue; } transition({B, B_M, BS_M, BM_M}, {CPUPrbResp, LastCPUPrbResp}) { z_stall; } transition({BS_Pm_BL, BM_Pm_BL, B_Pm_BL, BP_BL, BS_Pm_B, BM_Pm_B, B_Pm_B, BP_B}, {CPUPrbResp, LastCPUPrbResp}) { // recycling because PrbResponse and data come on the same network yy_recycleResponseQueue; } transition(U, {CPUPrbResp, LastCPUPrbResp}) {L3TagArrayRead, L3DataArrayWrite} { aic_ackInvalidate; wdt_writeBackDataInvNoTBE; ali_allocateL3BlockNoTBE; pr_popResponseQueue; } transition(BL, {CPUPrbResp, LastCPUPrbResp}) {} { aic_ackInvalidate; y_writeProbeDataToTBE; wdi_writeBackDataInv; ali_allocateL3Block; pr_popResponseQueue; } transition(BS_PM, LastCPUPrbResp, BS_M) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; pr_popResponseQueue; } transition(BS_PM, ProbeAcksComplete, BS_M) {} { pt_popTriggerQueue; } transition(BM_PM, LastCPUPrbResp, BM_M) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; pr_popResponseQueue; } transition(BM_PM, ProbeAcksComplete, BM_M) {} { pt_popTriggerQueue; } transition(B_PM, LastCPUPrbResp, B_M) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; pr_popResponseQueue; } transition(B_PM, ProbeAcksComplete, B_M){} { pt_popTriggerQueue; } transition(BS_Pm, LastCPUPrbResp, B) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; s_sendResponseS; wd_writeBackData; alwt_allocateL3BlockOnWT; ali_allocateL3Block; dt_deallocateTBE; pr_popResponseQueue; } transition(BS_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} { s_sendResponseS; wd_writeBackData; alwt_allocateL3BlockOnWT; ali_allocateL3Block; dt_deallocateTBE; pt_popTriggerQueue; } transition(BM_Pm, LastCPUPrbResp, B) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; m_sendResponseM; wd_writeBackData; alwt_allocateL3BlockOnWT; ali_allocateL3Block; dt_deallocateTBE; pr_popResponseQueue; } transition(BM_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} { m_sendResponseM; wd_writeBackData; alwt_allocateL3BlockOnWT; ali_allocateL3Block; dt_deallocateTBE; pt_popTriggerQueue; } transition(B_Pm, LastCPUPrbResp, B) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; es_sendResponseES; wd_writeBackData; alwt_allocateL3BlockOnWT; ali_allocateL3Block; dt_deallocateTBE; pr_popResponseQueue; } transition(B_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} { es_sendResponseES; wd_writeBackData; alwt_allocateL3BlockOnWT; ali_allocateL3Block; dt_deallocateTBE; pt_popTriggerQueue; } transition(BP, LastCPUPrbResp, B) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; c_sendResponseCtoD; wd_writeBackData; alwt_allocateL3BlockOnWT; dt_deallocateTBE; pr_popResponseQueue; } transition(BP, ProbeAcksComplete, B){L3TagArrayWrite, L3TagArrayWrite} { c_sendResponseCtoD; wd_writeBackData; alwt_allocateL3BlockOnWT; dt_deallocateTBE; pt_popTriggerQueue; } transition(BI, LastCPUPrbResp, B) { aic_ackInvalidate; y_writeProbeDataToTBE; x_decrementAcks; ont_checkForCompletionNoTrigger; wa_wakeUpDependents; wdi_writeBackDataInv; ali_allocateL3Block; dt_deallocateTBE; pr_popResponseQueue; } transition(BI, ProbeAcksComplete, U) {L3TagArrayWrite, L3DataArrayWrite}{ wa_wakeUpDependents; wdi_writeBackDataInv; ali_allocateL3Block; dt_deallocateTBE; pt_popTriggerQueue; } }