| /* | |
| * 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 Baseline protocol") | |
| : DirectoryMemory * directory; | |
| CacheMemory * L3CacheMemory; | |
| Cycles response_latency := 5; | |
| Cycles l3_hit_latency := 50; | |
| bool noTCCdir := "False"; | |
| bool CPUonly := "False"; | |
| int TCC_select_num_bits; | |
| 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"; | |
| MessageBuffer * probeToCore, network="To", virtual_network="0", vnet_type="request"; | |
| MessageBuffer * responseToCore, network="To", virtual_network="2", vnet_type="response"; | |
| MessageBuffer * triggerQueue; | |
| MessageBuffer * L3triggerQueue; | |
| MessageBuffer * responseFromMemory; | |
| { | |
| // STATES | |
| state_declaration(State, desc="Directory states", default="Directory_State_U") { | |
| U, AccessPermission:Backing_Store, desc="unblocked"; | |
| BL, AccessPermission:Busy, desc="got L3 WB request"; | |
| // BL is Busy because it'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. | |
| BS_M, AccessPermission:Backing_Store, desc="blocked waiting for memory"; | |
| BM_M, AccessPermission:Backing_Store, desc="blocked waiting for memory"; | |
| B_M, AccessPermission:Backing_Store, desc="blocked waiting for memory"; | |
| BP, AccessPermission:Backing_Store, desc="blocked waiting for probes, no need for memory"; | |
| BS_PM, AccessPermission:Backing_Store, desc="blocked waiting for probes and Memory"; | |
| BM_PM, AccessPermission:Backing_Store, desc="blocked waiting for probes and Memory"; | |
| B_PM, AccessPermission:Backing_Store, desc="blocked waiting for probes and Memory"; | |
| BS_Pm, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; | |
| BM_Pm, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; | |
| B_Pm, AccessPermission:Backing_Store, desc="blocked waiting for probes, already got memory"; | |
| B, AccessPermission:Backing_Store, desc="sent response, Blocked til ack"; | |
| } | |
| // Events | |
| enumeration(Event, desc="Directory events") { | |
| // CPU requests | |
| RdBlkS, desc="..."; | |
| RdBlkM, desc="..."; | |
| RdBlk, desc="..."; | |
| CtoD, desc="..."; | |
| WriteThrough, desc="WriteThrough Message"; | |
| Atomic, desc="Atomic Message"; | |
| // writebacks | |
| VicDirty, desc="..."; | |
| VicClean, desc="..."; | |
| CPUData, desc="WB data from CPU"; | |
| StaleWB, desc="Notification that WB has been superceded by a probe"; | |
| // probe responses | |
| CPUPrbResp, desc="Probe Response Msg"; | |
| ProbeAcksComplete, desc="Probe Acks Complete"; | |
| L3Hit, desc="Hit in L3 return data to core"; | |
| // Memory Controller | |
| MemData, desc="Fetched data from memory arrives"; | |
| WBAck, desc="Writeback Ack from memory arrives"; | |
| CoreUnblock, desc="Core received data, unblock"; | |
| UnblockWriteThrough, desc="Unblock because of writethrough request finishing"; | |
| StaleVicDirty, desc="Core invalidated before VicDirty processed"; | |
| } | |
| enumeration(RequestType, desc="To communicate stats from transitions to recordStats") { | |
| L3DataArrayRead, desc="Read the data array"; | |
| L3DataArrayWrite, desc="Write the data array"; | |
| L3TagArrayRead, desc="Read the data array"; | |
| L3TagArrayWrite, desc="Write the data array"; | |
| } | |
| // 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"; | |
| bool Dirty, desc="Is the data dirty?"; | |
| int NumPendingAcks, desc="num acks expected"; | |
| MachineID OriginalRequestor, desc="Original Requestor"; | |
| MachineID WTRequestor, desc="WT Requestor"; | |
| bool Cached, desc="data hit in Cache"; | |
| bool MemData, desc="Got MemData?",default="false"; | |
| bool wtData, desc="Got write through data?",default="false"; | |
| bool atomicData, desc="Got Atomic op?",default="false"; | |
| Cycles InitialRequestTime, desc="..."; | |
| Cycles ForwardRequestTime, desc="..."; | |
| Cycles ProbeRequestStartTime, desc="..."; | |
| MachineID LastSender, desc="Mach which this block came from"; | |
| bool L3Hit, default="false", desc="Was this an L3 hit?"; | |
| uint64_t probe_id, desc="probe id for lifetime profiling"; | |
| WriteMask writeMask, desc="outstanding write through mask"; | |
| } | |
| structure(TBETable, external="yes") { | |
| TBE lookup(Addr); | |
| void allocate(Addr); | |
| void deallocate(Addr); | |
| bool isPresent(Addr); | |
| } | |
| TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs"; | |
| int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()"; | |
| Tick clockEdge(); | |
| Tick cyclesToTicks(Cycles c); | |
| void set_tbe(TBE a); | |
| void unset_tbe(); | |
| void wakeUpAllBuffers(); | |
| void wakeUpBuffers(Addr a); | |
| Cycles curCycle(); | |
| Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" { | |
| Entry dir_entry := static_cast(Entry, "pointer", directory.lookup(addr)); | |
| if (is_valid(dir_entry)) { | |
| 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; | |
| } | |
| void setState(TBE tbe, CacheEntry entry, Addr addr, State state) { | |
| getDirectoryEntry(addr).DirectoryState := state; | |
| } | |
| void functionalRead(Addr addr, Packet *pkt) { | |
| TBE tbe := TBEs.lookup(addr); | |
| if(is_valid(tbe)) { | |
| testAndRead(addr, tbe.DataBlk, pkt); | |
| } else { | |
| functionalMemoryRead(pkt); | |
| } | |
| } | |
| int functionalWrite(Addr addr, Packet *pkt) { | |
| int num_functional_writes := 0; | |
| TBE tbe := TBEs.lookup(addr); | |
| if(is_valid(tbe)) { | |
| num_functional_writes := num_functional_writes + | |
| testAndWrite(addr, tbe.DataBlk, pkt); | |
| } | |
| num_functional_writes := num_functional_writes | |
| + functionalMemoryWrite(pkt); | |
| return num_functional_writes; | |
| } | |
| AccessPermission getAccessPermission(Addr addr) { | |
| // For this Directory, all permissions are just tracked in Directory, since | |
| // it's not possible to have something in TBE but not Dir, just keep track | |
| // of state all in one place. | |
| if (directory.isPresent(addr)) { | |
| return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); | |
| } | |
| return AccessPermission:NotPresent; | |
| } | |
| void setAccessPermission(CacheEntry entry, Addr addr, State state) { | |
| getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state)); | |
| } | |
| void recordRequestType(RequestType request_type, Addr addr) { | |
| if (request_type == RequestType:L3DataArrayRead) { | |
| L3CacheMemory.recordRequestType(CacheRequestType:DataArrayRead, addr); | |
| } else if (request_type == RequestType:L3DataArrayWrite) { | |
| L3CacheMemory.recordRequestType(CacheRequestType:DataArrayWrite, addr); | |
| } else if (request_type == RequestType:L3TagArrayRead) { | |
| L3CacheMemory.recordRequestType(CacheRequestType:TagArrayRead, addr); | |
| } else if (request_type == RequestType:L3TagArrayWrite) { | |
| L3CacheMemory.recordRequestType(CacheRequestType:TagArrayWrite, addr); | |
| } | |
| } | |
| 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(triggerQueue_out, TriggerMsg, triggerQueue); | |
| out_port(L3TriggerQueue_out, TriggerMsg, L3triggerQueue); | |
| // ** IN_PORTS ** | |
| // Trigger Queue | |
| in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=5) { | |
| if (triggerQueue_in.isReady(clockEdge())) { | |
| peek(triggerQueue_in, TriggerMsg) { | |
| TBE tbe := TBEs.lookup(in_msg.addr); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); | |
| if (in_msg.Type == TriggerType:AcksComplete) { | |
| trigger(Event:ProbeAcksComplete, in_msg.addr, entry, tbe); | |
| }else if (in_msg.Type == TriggerType:UnblockWriteThrough) { | |
| trigger(Event:UnblockWriteThrough, in_msg.addr, entry, tbe); | |
| } else { | |
| error("Unknown trigger msg"); | |
| } | |
| } | |
| } | |
| } | |
| in_port(L3TriggerQueue_in, TriggerMsg, L3triggerQueue, rank=4) { | |
| if (L3TriggerQueue_in.isReady(clockEdge())) { | |
| peek(L3TriggerQueue_in, TriggerMsg) { | |
| TBE tbe := TBEs.lookup(in_msg.addr); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); | |
| if (in_msg.Type == TriggerType:L3Hit) { | |
| trigger(Event:L3Hit, in_msg.addr, entry, tbe); | |
| } else { | |
| error("Unknown trigger msg"); | |
| } | |
| } | |
| } | |
| } | |
| // Unblock Network | |
| in_port(unblockNetwork_in, UnblockMsg, unblockFromCores, rank=3) { | |
| if (unblockNetwork_in.isReady(clockEdge())) { | |
| peek(unblockNetwork_in, UnblockMsg) { | |
| TBE tbe := TBEs.lookup(in_msg.addr); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); | |
| trigger(Event:CoreUnblock, in_msg.addr, entry, tbe); | |
| } | |
| } | |
| } | |
| // Core response network | |
| in_port(responseNetwork_in, ResponseMsg, responseFromCores, rank=2) { | |
| if (responseNetwork_in.isReady(clockEdge())) { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| TBE tbe := TBEs.lookup(in_msg.addr); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); | |
| if (in_msg.Type == CoherenceResponseType:CPUPrbResp) { | |
| trigger(Event:CPUPrbResp, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceResponseType:CPUData) { | |
| trigger(Event:CPUData, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceResponseType:StaleNotif) { | |
| trigger(Event:StaleWB, in_msg.addr, entry, tbe); | |
| } else { | |
| error("Unexpected response type"); | |
| } | |
| } | |
| } | |
| } | |
| // off-chip memory request/response is done | |
| in_port(memQueue_in, MemoryMsg, responseFromMemory, rank=1) { | |
| if (memQueue_in.isReady(clockEdge())) { | |
| peek(memQueue_in, MemoryMsg) { | |
| TBE tbe := TBEs.lookup(in_msg.addr); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); | |
| if (in_msg.Type == MemoryRequestType:MEMORY_READ) { | |
| trigger(Event:MemData, in_msg.addr, entry, tbe); | |
| DPRINTF(RubySlicc, "%s\n", in_msg); | |
| } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { | |
| trigger(Event:WBAck, in_msg.addr, entry, tbe); // ignore WBAcks, don't care about them. | |
| } else { | |
| DPRINTF(RubySlicc, "%s\n", in_msg.Type); | |
| error("Invalid message"); | |
| } | |
| } | |
| } | |
| } | |
| in_port(requestNetwork_in, CPURequestMsg, requestFromCores, rank=0) { | |
| if (requestNetwork_in.isReady(clockEdge())) { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| TBE tbe := TBEs.lookup(in_msg.addr); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr)); | |
| if (in_msg.Type == CoherenceRequestType:RdBlk) { | |
| trigger(Event:RdBlk, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceRequestType:RdBlkS) { | |
| trigger(Event:RdBlkS, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceRequestType:RdBlkM) { | |
| trigger(Event:RdBlkM, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceRequestType:WriteThrough) { | |
| trigger(Event:WriteThrough, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceRequestType:Atomic) { | |
| trigger(Event:Atomic, in_msg.addr, entry, tbe); | |
| } else if (in_msg.Type == CoherenceRequestType:VicDirty) { | |
| if (getDirectoryEntry(in_msg.addr).VicDirtyIgnore.isElement(in_msg.Requestor)) { | |
| DPRINTF(RubySlicc, "Dropping VicDirty for address %s\n", in_msg.addr); | |
| trigger(Event:StaleVicDirty, in_msg.addr, entry, tbe); | |
| } else { | |
| DPRINTF(RubySlicc, "Got VicDirty from %s on %s\n", in_msg.Requestor, in_msg.addr); | |
| trigger(Event:VicDirty, in_msg.addr, entry, tbe); | |
| } | |
| } else if (in_msg.Type == CoherenceRequestType:VicClean) { | |
| if (getDirectoryEntry(in_msg.addr).VicDirtyIgnore.isElement(in_msg.Requestor)) { | |
| DPRINTF(RubySlicc, "Dropping VicClean for address %s\n", in_msg.addr); | |
| trigger(Event:StaleVicDirty, in_msg.addr, entry, tbe); | |
| } else { | |
| DPRINTF(RubySlicc, "Got VicClean from %s on %s\n", in_msg.Requestor, in_msg.addr); | |
| trigger(Event:VicClean, in_msg.addr, entry, tbe); | |
| } | |
| } else { | |
| error("Bad request message type"); | |
| } | |
| } | |
| } | |
| } | |
| // Actions | |
| action(s_sendResponseS, "s", desc="send Shared response") { | |
| enqueue(responseNetwork_out, ResponseMsg, response_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := CoherenceResponseType:NBSysResp; | |
| if (tbe.L3Hit) { | |
| out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0)); | |
| } else { | |
| out_msg.Sender := machineID; | |
| } | |
| out_msg.Destination.add(tbe.OriginalRequestor); | |
| out_msg.DataBlk := tbe.DataBlk; | |
| out_msg.MessageSize := MessageSizeType:Response_Data; | |
| out_msg.Dirty := false; | |
| out_msg.State := CoherenceState:Shared; | |
| out_msg.InitialRequestTime := tbe.InitialRequestTime; | |
| out_msg.ForwardRequestTime := tbe.ForwardRequestTime; | |
| out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime; | |
| out_msg.OriginalResponder := tbe.LastSender; | |
| out_msg.L3Hit := tbe.L3Hit; | |
| DPRINTF(RubySlicc, "%s\n", out_msg); | |
| } | |
| } | |
| action(es_sendResponseES, "es", desc="send Exclusive or Shared response") { | |
| enqueue(responseNetwork_out, ResponseMsg, response_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := CoherenceResponseType:NBSysResp; | |
| if (tbe.L3Hit) { | |
| out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0)); | |
| } else { | |
| out_msg.Sender := machineID; | |
| } | |
| out_msg.Destination.add(tbe.OriginalRequestor); | |
| out_msg.DataBlk := tbe.DataBlk; | |
| out_msg.MessageSize := MessageSizeType:Response_Data; | |
| out_msg.Dirty := tbe.Dirty; | |
| if (tbe.Cached) { | |
| out_msg.State := CoherenceState:Shared; | |
| } else { | |
| out_msg.State := CoherenceState:Exclusive; | |
| } | |
| out_msg.InitialRequestTime := tbe.InitialRequestTime; | |
| out_msg.ForwardRequestTime := tbe.ForwardRequestTime; | |
| out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime; | |
| out_msg.OriginalResponder := tbe.LastSender; | |
| out_msg.L3Hit := tbe.L3Hit; | |
| DPRINTF(RubySlicc, "%s\n", out_msg); | |
| } | |
| } | |
| action(m_sendResponseM, "m", desc="send Modified response") { | |
| if (tbe.wtData) { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:UnblockWriteThrough; | |
| } | |
| }else{ | |
| enqueue(responseNetwork_out, ResponseMsg, response_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := CoherenceResponseType:NBSysResp; | |
| if (tbe.L3Hit) { | |
| out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0)); | |
| } else { | |
| out_msg.Sender := machineID; | |
| } | |
| out_msg.Destination.add(tbe.OriginalRequestor); | |
| out_msg.DataBlk := tbe.DataBlk; | |
| out_msg.MessageSize := MessageSizeType:Response_Data; | |
| out_msg.Dirty := tbe.Dirty; | |
| out_msg.State := CoherenceState:Modified; | |
| out_msg.CtoD := false; | |
| out_msg.InitialRequestTime := tbe.InitialRequestTime; | |
| out_msg.ForwardRequestTime := tbe.ForwardRequestTime; | |
| out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime; | |
| out_msg.OriginalResponder := tbe.LastSender; | |
| if(tbe.atomicData){ | |
| out_msg.WTRequestor := tbe.WTRequestor; | |
| } | |
| out_msg.L3Hit := tbe.L3Hit; | |
| DPRINTF(RubySlicc, "%s\n", out_msg); | |
| } | |
| if (tbe.atomicData) { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:UnblockWriteThrough; | |
| } | |
| } | |
| } | |
| } | |
| action(c_sendResponseCtoD, "c", desc="send CtoD Ack") { | |
| enqueue(responseNetwork_out, ResponseMsg, response_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := CoherenceResponseType:NBSysResp; | |
| out_msg.Sender := machineID; | |
| out_msg.Destination.add(tbe.OriginalRequestor); | |
| out_msg.MessageSize := MessageSizeType:Response_Control; | |
| out_msg.Dirty := false; | |
| out_msg.State := CoherenceState:Modified; | |
| out_msg.CtoD := true; | |
| out_msg.InitialRequestTime := tbe.InitialRequestTime; | |
| out_msg.ForwardRequestTime := curCycle(); | |
| out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime; | |
| DPRINTF(RubySlicc, "%s\n", out_msg); | |
| } | |
| } | |
| action(w_sendResponseWBAck, "w", desc="send WB Ack") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(responseNetwork_out, ResponseMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := CoherenceResponseType:NBSysWBAck; | |
| out_msg.Destination.add(in_msg.Requestor); | |
| out_msg.WTRequestor := in_msg.WTRequestor; | |
| out_msg.Sender := machineID; | |
| out_msg.MessageSize := MessageSizeType:Writeback_Control; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| out_msg.ForwardRequestTime := curCycle(); | |
| out_msg.ProbeRequestStartTime := curCycle(); | |
| } | |
| } | |
| } | |
| action(l_queueMemWBReq, "lq", desc="Write WB data to memory") { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| queueMemoryWrite(machineID, address, to_memory_controller_latency, | |
| in_msg.DataBlk); | |
| } | |
| } | |
| action(l_queueMemRdReq, "lr", desc="Read data from memory") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| if (L3CacheMemory.isTagPresent(address)) { | |
| enqueue(L3TriggerQueue_out, TriggerMsg, l3_hit_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:L3Hit; | |
| DPRINTF(RubySlicc, "%s\n", out_msg); | |
| } | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address)); | |
| if (tbe.Dirty == false) { | |
| tbe.DataBlk := entry.DataBlk; | |
| } | |
| tbe.LastSender := entry.LastSender; | |
| tbe.L3Hit := true; | |
| tbe.MemData := true; | |
| L3CacheMemory.deallocate(address); | |
| } else { | |
| queueMemoryRead(machineID, address, to_memory_controller_latency); | |
| } | |
| } | |
| } | |
| action(dc_probeInvCoreData, "dc", desc="probe inv cores, return data") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := ProbeRequestType:PrbInv; | |
| out_msg.ReturnData := true; | |
| out_msg.MessageSize := MessageSizeType:Control; | |
| out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket | |
| // add relevant TCC node to list. This replaces all TCPs and SQCs | |
| if (((in_msg.Type == CoherenceRequestType:WriteThrough || | |
| in_msg.Type == CoherenceRequestType:Atomic) && | |
| in_msg.NoWriteConflict) || | |
| CPUonly) { | |
| } else if (noTCCdir) { | |
| out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC, | |
| TCC_select_low_bit, TCC_select_num_bits)); | |
| } else { | |
| out_msg.Destination.add(mapAddressToRange(address, | |
| MachineType:TCCdir, | |
| TCC_select_low_bit, TCC_select_num_bits)); | |
| } | |
| out_msg.Destination.remove(in_msg.Requestor); | |
| tbe.NumPendingAcks := out_msg.Destination.count(); | |
| if (tbe.NumPendingAcks == 0) { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:AcksComplete; | |
| } | |
| } | |
| DPRINTF(RubySlicc, "%s\n", out_msg); | |
| APPEND_TRANSITION_COMMENT(" dc: 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 | |
| // add relevant TCC node to the list. This replaces all TCPs and SQCs | |
| if (noTCCdir || CPUonly) { | |
| //Don't need to notify TCC about reads | |
| } else { | |
| out_msg.Destination.add(mapAddressToRange(address, | |
| MachineType:TCCdir, | |
| TCC_select_low_bit, TCC_select_num_bits)); | |
| tbe.NumPendingAcks := tbe.NumPendingAcks + 1; | |
| } | |
| if (noTCCdir && !CPUonly) { | |
| out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC, | |
| TCC_select_low_bit, TCC_select_num_bits)); | |
| } | |
| out_msg.Destination.remove(in_msg.Requestor); | |
| tbe.NumPendingAcks := out_msg.Destination.count(); | |
| if (tbe.NumPendingAcks == 0) { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:AcksComplete; | |
| } | |
| } | |
| DPRINTF(RubySlicc, "%s\n", (out_msg)); | |
| APPEND_TRANSITION_COMMENT(" sc: Acks remaining: "); | |
| APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); | |
| tbe.ProbeRequestStartTime := curCycle(); | |
| } | |
| } | |
| } | |
| action(ic_probeInvCore, "ic", desc="probe invalidate core, no return data needed") { | |
| peek(requestNetwork_in, CPURequestMsg) { // not the right network? | |
| enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) { | |
| out_msg.addr := address; | |
| out_msg.Type := ProbeRequestType:PrbInv; | |
| out_msg.ReturnData := false; | |
| out_msg.MessageSize := MessageSizeType:Control; | |
| out_msg.Destination.broadcast(MachineType:CorePair); // won't be realistic for multisocket | |
| // add relevant TCC node to the list. This replaces all TCPs and SQCs | |
| if (noTCCdir && !CPUonly) { | |
| out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC, | |
| TCC_select_low_bit, TCC_select_num_bits)); | |
| } else { | |
| if (!noTCCdir) { | |
| out_msg.Destination.add(mapAddressToRange(address, | |
| MachineType:TCCdir, | |
| TCC_select_low_bit, | |
| TCC_select_num_bits)); | |
| } | |
| } | |
| out_msg.Destination.remove(in_msg.Requestor); | |
| tbe.NumPendingAcks := out_msg.Destination.count(); | |
| if (tbe.NumPendingAcks == 0) { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:AcksComplete; | |
| } | |
| } | |
| 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; | |
| if (tbe.Dirty == false) { | |
| // have to update the TBE, too, because of how this | |
| // directory deals with functional writes | |
| tbe.DataBlk := in_msg.DataBlk; | |
| } | |
| } | |
| } | |
| action(t_allocateTBE, "t", desc="allocate TBE Entry") { | |
| check_allocate(TBEs); | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| TBEs.allocate(address); | |
| set_tbe(TBEs.lookup(address)); | |
| if (in_msg.Type == CoherenceRequestType:WriteThrough) { | |
| tbe.writeMask.clear(); | |
| tbe.writeMask.orMask(in_msg.writeMask); | |
| tbe.wtData := true; | |
| tbe.WTRequestor := in_msg.WTRequestor; | |
| tbe.LastSender := in_msg.Requestor; | |
| } | |
| if (in_msg.Type == CoherenceRequestType:Atomic) { | |
| tbe.writeMask.clear(); | |
| tbe.writeMask.orMask(in_msg.writeMask); | |
| tbe.atomicData := true; | |
| tbe.WTRequestor := in_msg.WTRequestor; | |
| tbe.LastSender := in_msg.Requestor; | |
| } | |
| tbe.DataBlk := getDirectoryEntry(address).DataBlk; // Data only for WBs | |
| tbe.Dirty := false; | |
| if (in_msg.Type == CoherenceRequestType:WriteThrough) { | |
| tbe.DataBlk.copyPartial(in_msg.DataBlk,in_msg.writeMask); | |
| tbe.Dirty := true; | |
| } | |
| tbe.OriginalRequestor := in_msg.Requestor; | |
| tbe.NumPendingAcks := 0; | |
| tbe.Cached := in_msg.ForceShared; | |
| tbe.InitialRequestTime := in_msg.InitialRequestTime; | |
| } | |
| } | |
| action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") { | |
| if (tbe.Dirty == false) { | |
| getDirectoryEntry(address).DataBlk := tbe.DataBlk; | |
| } | |
| TBEs.deallocate(address); | |
| unset_tbe(); | |
| } | |
| action(wd_writeBackData, "wd", desc="Write back data if needed") { | |
| if (tbe.wtData) { | |
| getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, tbe.writeMask); | |
| } else if (tbe.atomicData) { | |
| tbe.DataBlk.atomicPartial(getDirectoryEntry(address).DataBlk,tbe.writeMask); | |
| getDirectoryEntry(address).DataBlk := tbe.DataBlk; | |
| } else if (tbe.Dirty == false) { | |
| getDirectoryEntry(address).DataBlk := tbe.DataBlk; | |
| } | |
| } | |
| action(mt_writeMemDataToTBE, "mt", desc="write Mem data to TBE") { | |
| peek(memQueue_in, MemoryMsg) { | |
| if (tbe.wtData == true) { | |
| // do nothing | |
| } else if (tbe.Dirty == false) { | |
| tbe.DataBlk := getDirectoryEntry(address).DataBlk; | |
| } | |
| tbe.MemData := true; | |
| } | |
| } | |
| action(y_writeProbeDataToTBE, "y", desc="write Probe Data to TBE") { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| if (in_msg.Dirty) { | |
| if (tbe.wtData) { | |
| DataBlock tmp := in_msg.DataBlk; | |
| tmp.copyPartial(tbe.DataBlk,tbe.writeMask); | |
| tbe.DataBlk := tmp; | |
| tbe.writeMask.fillMask(); | |
| } else if (tbe.Dirty) { | |
| if(tbe.atomicData == false && tbe.wtData == false) { | |
| DPRINTF(RubySlicc, "Got double data for %s from %s\n", address, in_msg.Sender); | |
| assert(tbe.DataBlk == in_msg.DataBlk); // in case of double data | |
| } | |
| } else { | |
| tbe.DataBlk := in_msg.DataBlk; | |
| tbe.Dirty := in_msg.Dirty; | |
| tbe.LastSender := in_msg.Sender; | |
| } | |
| } | |
| if (in_msg.Hit) { | |
| tbe.Cached := true; | |
| } | |
| } | |
| } | |
| action(mwc_markSinkWriteCancel, "mwc", desc="Mark to sink impending VicDirty") { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| getDirectoryEntry(address).VicDirtyIgnore.add(in_msg.Sender); | |
| APPEND_TRANSITION_COMMENT(" setting bit to sink VicDirty "); | |
| } | |
| } | |
| action(x_decrementAcks, "x", desc="decrement Acks pending") { | |
| tbe.NumPendingAcks := tbe.NumPendingAcks - 1; | |
| APPEND_TRANSITION_COMMENT(" Acks remaining: "); | |
| APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); | |
| } | |
| action(o_checkForCompletion, "o", desc="check for ack completion") { | |
| if (tbe.NumPendingAcks == 0) { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.Type := TriggerType:AcksComplete; | |
| } | |
| } | |
| APPEND_TRANSITION_COMMENT(" Check: Acks remaining: "); | |
| APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks); | |
| } | |
| action(rv_removeVicDirtyIgnore, "rv", desc="Remove ignored core") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| getDirectoryEntry(address).VicDirtyIgnore.remove(in_msg.Requestor); | |
| } | |
| } | |
| action(al_allocateL3Block, "al", desc="allocate the L3 block on WB") { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| if (L3CacheMemory.isTagPresent(address)) { | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address)); | |
| APPEND_TRANSITION_COMMENT(" al wrote data to L3 (hit) "); | |
| entry.DataBlk := in_msg.DataBlk; | |
| entry.LastSender := in_msg.Sender; | |
| } else { | |
| if (L3CacheMemory.cacheAvail(address) == false) { | |
| Addr victim := L3CacheMemory.cacheProbe(address); | |
| CacheEntry victim_entry := static_cast(CacheEntry, "pointer", | |
| L3CacheMemory.lookup(victim)); | |
| queueMemoryWrite(machineID, victim, to_memory_controller_latency, | |
| victim_entry.DataBlk); | |
| L3CacheMemory.deallocate(victim); | |
| } | |
| assert(L3CacheMemory.cacheAvail(address)); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.allocate(address, new CacheEntry)); | |
| APPEND_TRANSITION_COMMENT(" al wrote data to L3 "); | |
| entry.DataBlk := in_msg.DataBlk; | |
| entry.LastSender := in_msg.Sender; | |
| } | |
| } | |
| } | |
| action(alwt_allocateL3BlockOnWT, "alwt", desc="allocate the L3 block on WT") { | |
| if ((tbe.wtData || tbe.atomicData) && useL3OnWT) { | |
| if (L3CacheMemory.isTagPresent(address)) { | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address)); | |
| APPEND_TRANSITION_COMMENT(" al wrote data to L3 (hit) "); | |
| entry.DataBlk := tbe.DataBlk; | |
| entry.LastSender := tbe.LastSender; | |
| } else { | |
| if (L3CacheMemory.cacheAvail(address) == false) { | |
| Addr victim := L3CacheMemory.cacheProbe(address); | |
| CacheEntry victim_entry := static_cast(CacheEntry, "pointer", | |
| L3CacheMemory.lookup(victim)); | |
| queueMemoryWrite(machineID, victim, to_memory_controller_latency, | |
| victim_entry.DataBlk); | |
| L3CacheMemory.deallocate(victim); | |
| } | |
| assert(L3CacheMemory.cacheAvail(address)); | |
| CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.allocate(address, new CacheEntry)); | |
| APPEND_TRANSITION_COMMENT(" al wrote data to L3 "); | |
| entry.DataBlk := tbe.DataBlk; | |
| entry.LastSender := tbe.LastSender; | |
| } | |
| } | |
| } | |
| action(sf_setForwardReqTime, "sf", desc="...") { | |
| tbe.ForwardRequestTime := curCycle(); | |
| } | |
| action(dl_deallocateL3, "dl", desc="deallocate the L3 block") { | |
| L3CacheMemory.deallocate(address); | |
| } | |
| action(p_popRequestQueue, "p", desc="pop request queue") { | |
| requestNetwork_in.dequeue(clockEdge()); | |
| } | |
| action(pr_popResponseQueue, "pr", desc="pop response queue") { | |
| responseNetwork_in.dequeue(clockEdge()); | |
| } | |
| action(pm_popMemQueue, "pm", desc="pop mem queue") { | |
| memQueue_in.dequeue(clockEdge()); | |
| } | |
| action(pt_popTriggerQueue, "pt", desc="pop trigger queue") { | |
| triggerQueue_in.dequeue(clockEdge()); | |
| } | |
| action(ptl_popTriggerQueue, "ptl", desc="pop L3 trigger queue") { | |
| L3TriggerQueue_in.dequeue(clockEdge()); | |
| } | |
| action(pu_popUnblockQueue, "pu", desc="pop unblock queue") { | |
| unblockNetwork_in.dequeue(clockEdge()); | |
| } | |
| action(zz_recycleRequestQueue, "zz", desc="recycle request queue") { | |
| requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); | |
| } | |
| action(yy_recycleResponseQueue, "yy", desc="recycle response queue") { | |
| responseNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); | |
| } | |
| action(st_stallAndWaitRequest, "st", desc="Stall and wait on the address") { | |
| stall_and_wait(requestNetwork_in, address); | |
| } | |
| action(wa_wakeUpDependents, "wa", desc="Wake up any requests waiting for this address") { | |
| wakeUpBuffers(address); | |
| } | |
| action(wa_wakeUpAllDependents, "waa", desc="Wake up any requests waiting for this region") { | |
| wakeUpAllBuffers(); | |
| } | |
| action(z_stall, "z", desc="...") { | |
| } | |
| // TRANSITIONS | |
| transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, {RdBlkS, RdBlkM, RdBlk, CtoD}) { | |
| st_stallAndWaitRequest; | |
| } | |
| // It may be possible to save multiple invalidations here! | |
| transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, {Atomic, WriteThrough}) { | |
| st_stallAndWaitRequest; | |
| } | |
| // transitions from U | |
| transition(U, {RdBlkS}, BS_PM) {L3TagArrayRead} { | |
| t_allocateTBE; | |
| l_queueMemRdReq; | |
| sc_probeShrCoreData; | |
| p_popRequestQueue; | |
| } | |
| transition(U, WriteThrough, BM_PM) {L3TagArrayRead, L3TagArrayWrite} { | |
| t_allocateTBE; | |
| w_sendResponseWBAck; | |
| l_queueMemRdReq; | |
| dc_probeInvCoreData; | |
| p_popRequestQueue; | |
| } | |
| transition(U, Atomic, BM_PM) {L3TagArrayRead, L3TagArrayWrite} { | |
| t_allocateTBE; | |
| l_queueMemRdReq; | |
| dc_probeInvCoreData; | |
| p_popRequestQueue; | |
| } | |
| transition(U, {RdBlkM}, BM_PM) {L3TagArrayRead} { | |
| t_allocateTBE; | |
| l_queueMemRdReq; | |
| dc_probeInvCoreData; | |
| p_popRequestQueue; | |
| } | |
| transition(U, RdBlk, B_PM) {L3TagArrayRead}{ | |
| t_allocateTBE; | |
| l_queueMemRdReq; | |
| sc_probeShrCoreData; | |
| p_popRequestQueue; | |
| } | |
| transition(U, CtoD, BP) {L3TagArrayRead} { | |
| t_allocateTBE; | |
| ic_probeInvCore; | |
| p_popRequestQueue; | |
| } | |
| transition(U, VicDirty, BL) {L3TagArrayRead} { | |
| t_allocateTBE; | |
| w_sendResponseWBAck; | |
| p_popRequestQueue; | |
| } | |
| transition(U, VicClean, BL) {L3TagArrayRead} { | |
| t_allocateTBE; | |
| w_sendResponseWBAck; | |
| p_popRequestQueue; | |
| } | |
| transition(BL, {VicDirty, VicClean}) { | |
| zz_recycleRequestQueue; | |
| } | |
| transition(BL, CPUData, U) {L3TagArrayWrite, L3DataArrayWrite} { | |
| d_writeDataToMemory; | |
| al_allocateL3Block; | |
| wa_wakeUpDependents; | |
| dt_deallocateTBE; | |
| pr_popResponseQueue; | |
| } | |
| transition(BL, StaleWB, U) {L3TagArrayWrite} { | |
| dt_deallocateTBE; | |
| wa_wakeUpAllDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition({B, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm}, {VicDirty, VicClean}) { | |
| z_stall; | |
| } | |
| transition({U, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, WBAck) { | |
| pm_popMemQueue; | |
| } | |
| transition({U, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, StaleVicDirty) { | |
| rv_removeVicDirtyIgnore; | |
| w_sendResponseWBAck; | |
| p_popRequestQueue; | |
| } | |
| transition({B}, CoreUnblock, U) { | |
| wa_wakeUpDependents; | |
| pu_popUnblockQueue; | |
| } | |
| transition(B, UnblockWriteThrough, U) { | |
| wa_wakeUpDependents; | |
| pt_popTriggerQueue; | |
| } | |
| transition(BS_PM, MemData, BS_Pm) {} { | |
| mt_writeMemDataToTBE; | |
| pm_popMemQueue; | |
| } | |
| transition(BM_PM, MemData, BM_Pm){} { | |
| mt_writeMemDataToTBE; | |
| pm_popMemQueue; | |
| } | |
| transition(B_PM, MemData, B_Pm){} { | |
| mt_writeMemDataToTBE; | |
| pm_popMemQueue; | |
| } | |
| transition(BS_PM, L3Hit, BS_Pm) {} { | |
| ptl_popTriggerQueue; | |
| } | |
| transition(BM_PM, L3Hit, BM_Pm) {} { | |
| ptl_popTriggerQueue; | |
| } | |
| transition(B_PM, L3Hit, B_Pm) {} { | |
| ptl_popTriggerQueue; | |
| } | |
| transition(BS_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} { | |
| mt_writeMemDataToTBE; | |
| s_sendResponseS; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pm_popMemQueue; | |
| } | |
| transition(BM_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} { | |
| mt_writeMemDataToTBE; | |
| m_sendResponseM; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pm_popMemQueue; | |
| } | |
| transition(B_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} { | |
| mt_writeMemDataToTBE; | |
| es_sendResponseES; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pm_popMemQueue; | |
| } | |
| transition(BS_M, L3Hit, B) {L3TagArrayWrite, L3DataArrayWrite} { | |
| s_sendResponseS; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| ptl_popTriggerQueue; | |
| } | |
| transition(BM_M, L3Hit, B) {L3DataArrayWrite, L3TagArrayWrite} { | |
| m_sendResponseM; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| ptl_popTriggerQueue; | |
| } | |
| transition(B_M, L3Hit, B) {L3DataArrayWrite, L3TagArrayWrite} { | |
| es_sendResponseES; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| ptl_popTriggerQueue; | |
| } | |
| transition({BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, BP}, CPUPrbResp) { | |
| y_writeProbeDataToTBE; | |
| x_decrementAcks; | |
| o_checkForCompletion; | |
| pr_popResponseQueue; | |
| } | |
| transition(BS_PM, ProbeAcksComplete, BS_M) {} { | |
| sf_setForwardReqTime; | |
| pt_popTriggerQueue; | |
| } | |
| transition(BM_PM, ProbeAcksComplete, BM_M) {} { | |
| sf_setForwardReqTime; | |
| pt_popTriggerQueue; | |
| } | |
| transition(B_PM, ProbeAcksComplete, B_M){} { | |
| sf_setForwardReqTime; | |
| pt_popTriggerQueue; | |
| } | |
| transition(BS_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} { | |
| sf_setForwardReqTime; | |
| s_sendResponseS; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pt_popTriggerQueue; | |
| } | |
| transition(BM_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} { | |
| sf_setForwardReqTime; | |
| m_sendResponseM; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pt_popTriggerQueue; | |
| } | |
| transition(B_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} { | |
| sf_setForwardReqTime; | |
| es_sendResponseES; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pt_popTriggerQueue; | |
| } | |
| transition(BP, ProbeAcksComplete, B){L3TagArrayWrite, L3TagArrayWrite} { | |
| sf_setForwardReqTime; | |
| c_sendResponseCtoD; | |
| wd_writeBackData; | |
| alwt_allocateL3BlockOnWT; | |
| dt_deallocateTBE; | |
| pt_popTriggerQueue; | |
| } | |
| } |