| /* | |
| * 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="AbstractCacheEntry", main="false") { | |
| 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="<Directory_TBE>", 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; | |
| } | |
| } |