| /* | |
| * Copyright (c) 2012-2015 Advanced Micro Devices, Inc. | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are met: | |
| * | |
| * 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. | |
| */ | |
| machine(MachineType:RegionDir, "Region Directory for AMD_Base-like protocol") | |
| : CacheMemory *cacheMemory; // stores only region addresses. Must set block size same as below | |
| NodeID cpuRegionBufferNum; | |
| NodeID gpuRegionBufferNum; | |
| int blocksPerRegion := 64; // 4k regions | |
| Cycles toDirLatency := 10; // Latency to fwd requests and send invs to directory | |
| bool always_migrate := "False"; | |
| bool sym_migrate := "False"; | |
| bool asym_migrate := "False"; | |
| bool noTCCdir := "False"; | |
| int TCC_select_num_bits := 1; | |
| // To the directory | |
| MessageBuffer * requestToDir, network="To", virtual_network="5", vnet_type="request"; | |
| // To the region buffers | |
| MessageBuffer * notifyToRBuffer, network="To", virtual_network="7", vnet_type="request"; | |
| MessageBuffer * probeToRBuffer, network="To", virtual_network="8", vnet_type="request"; | |
| // From the region buffers | |
| MessageBuffer * responseFromRBuffer, network="From", virtual_network="2", vnet_type="response"; | |
| MessageBuffer * requestFromRegBuf, network="From", virtual_network="0", vnet_type="request"; | |
| MessageBuffer * triggerQueue; | |
| { | |
| // States | |
| state_declaration(State, desc="Region states", default="RegionDir_State_NP") { | |
| NP, AccessPermission:Invalid, desc="Not present in region directory"; | |
| P, AccessPermission:Invalid, desc="Region is private to owner"; | |
| S, AccessPermission:Invalid, desc="Region is shared between CPU and GPU"; | |
| P_NP, AccessPermission:Invalid, desc="Evicting the region"; | |
| NP_P, AccessPermission:Invalid, desc="Must wait for ack from R-buf"; | |
| NP_S, AccessPermission:Invalid, desc="Must wait for ack from R-buf"; | |
| P_P, AccessPermission:Invalid, desc="Waiting for ack from R-buf"; | |
| S_S, AccessPermission:Invalid, desc="Waiting for ack from R-buf"; | |
| P_S, AccessPermission:Invalid, desc="Downgrading the region"; | |
| S_P, AccessPermission:Invalid, desc="Upgrading the region"; | |
| P_AS, AccessPermission:Invalid, desc="Sent invalidates, waiting for acks"; | |
| S_AP, AccessPermission:Invalid, desc="Sent invalidates, waiting for acks"; | |
| P_AP, AccessPermission:Invalid, desc="Sent invalidates, waiting for acks"; | |
| SP_NP_W, AccessPermission:Invalid, desc="Last sharer writing back, waiting for ack"; | |
| S_W, AccessPermission:Invalid, desc="Sharer writing back, waiting for ack"; | |
| P_AP_W, AccessPermission:Invalid, desc="Fwded request to dir, waiting for ack"; | |
| P_AS_W, AccessPermission:Invalid, desc="Fwded request to dir, waiting for ack"; | |
| S_AP_W, AccessPermission:Invalid, desc="Fwded request to dir, waiting for ack"; | |
| } | |
| enumeration(Event, desc="Region directory events") { | |
| SendInv, desc="Send inv message to any machine that has a region buffer"; | |
| SendUpgrade, desc="Send upgrade message to any machine that has a region buffer"; | |
| SendDowngrade, desc="Send downgrade message to any machine that has a region buffer"; | |
| Evict, desc="Evict this region"; | |
| UpgradeRequest, desc="Request from r-buf for an upgrade"; | |
| SharedRequest, desc="Request from r-buf for read"; | |
| PrivateRequest, desc="Request from r-buf for write"; | |
| InvAckCore, desc="Ack from region buffer to order the invalidate"; | |
| InvAckCoreNoShare, desc="Ack from region buffer to order the invalidate, and it does not have the region"; | |
| CPUPrivateAck, desc="Ack from region buffer to order private notification"; | |
| LastAck, desc="Done eviciting all the blocks"; | |
| StaleCleanWbRequest, desc="stale clean writeback reqeust"; | |
| StaleCleanWbRequestNoShare, desc="stale clean wb req from a cache which should be removed from sharers"; | |
| CleanWbRequest, desc="clean writeback reqeust, multiple sharers"; | |
| CleanWbRequest_LastSharer, desc="clean writeback reqeust, last sharer"; | |
| WritebackAck, desc="Writeback Ack from region buffer"; | |
| DirReadyAck, desc="Directory is ready, waiting Ack from region buffer"; | |
| TriggerInv, desc="trigger invalidate message"; | |
| TriggerDowngrade, desc="trigger downgrade message"; | |
| } | |
| enumeration(RequestType, desc="To communicate stats from transitions to recordStats") { | |
| DataArrayRead, desc="Read the data array"; | |
| DataArrayWrite, desc="Write the data array"; | |
| TagArrayRead, desc="Read the data array"; | |
| TagArrayWrite, desc="Write the data array"; | |
| } | |
| structure(BoolVec, external="yes") { | |
| bool at(int); | |
| void resize(int); | |
| void clear(); | |
| } | |
| structure(Entry, desc="Region entry", interface="AbstractCacheEntry") { | |
| Addr addr, desc="Base address of this region"; | |
| NetDest Sharers, desc="Set of machines that are sharing, but not owners"; | |
| State RegionState, desc="Region state"; | |
| DataBlock DataBlk, desc="Data for the block (always empty in region dir)"; | |
| MachineID Owner, desc="Machine which owns all blocks in this region"; | |
| Cycles ProbeStart, desc="Time when the first probe request was issued"; | |
| bool LastWriten, default="false", desc="The last time someone accessed this region, it wrote it"; | |
| bool LastWritenByCpu, default="false", desc="The last time the CPU accessed this region, it wrote it"; | |
| bool LastWritenByGpu, default="false", desc="The last time the GPU accessed this region, it wrote it"; | |
| } | |
| structure(TBE, desc="...") { | |
| State TBEState, desc="Transient state"; | |
| MachineID Owner, desc="Machine which owns all blocks in this region"; | |
| NetDest Sharers, desc="Set of machines to send evicts"; | |
| int NumValidBlocks, desc="Number of blocks valid so we don't have to count a BoolVec"; | |
| bool AllAcksReceived, desc="Got all necessary acks from dir"; | |
| CoherenceRequestType MsgType, desc="Msg type for the evicts could be inv or dwngrd"; | |
| Cycles ProbeRequestTime, default="Cycles(0)", desc="Start of probe request"; | |
| Cycles InitialRequestTime, default="Cycles(0)", desc="To forward back on out msg"; | |
| Addr DemandAddress, desc="Demand address from original request"; | |
| uint64_t probe_id, desc="probe id for lifetime profiling"; | |
| } | |
| structure(TBETable, external="yes") { | |
| TBE lookup(Addr); | |
| void allocate(Addr); | |
| void deallocate(Addr); | |
| bool isPresent(Addr); | |
| } | |
| // Stores only region addresses | |
| TBETable TBEs, template="<RegionDir_TBE>", constructor="m_number_of_TBEs"; | |
| int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()"; | |
| Tick clockEdge(); | |
| Tick cyclesToTicks(Cycles c); | |
| void set_cache_entry(AbstractCacheEntry b); | |
| void unset_cache_entry(); | |
| void set_tbe(TBE b); | |
| void unset_tbe(); | |
| void wakeUpAllBuffers(); | |
| void wakeUpBuffers(Addr a); | |
| Cycles curCycle(); | |
| MachineID mapAddressToMachine(Addr addr, MachineType mtype); | |
| int blockBits, default="RubySystem::getBlockSizeBits()"; | |
| int blockBytes, default="RubySystem::getBlockSizeBytes()"; | |
| int regionBits, default="log2(m_blocksPerRegion)"; | |
| // Functions | |
| MachineID getCoreMachine(MachineID rBuf, Addr address) { | |
| if (machineIDToNodeID(rBuf) == cpuRegionBufferNum) { | |
| return createMachineID(MachineType:CorePair, intToID(0)); | |
| } else if (machineIDToNodeID(rBuf) == gpuRegionBufferNum) { | |
| if (noTCCdir) { | |
| return mapAddressToRange(address,MachineType:TCC, | |
| TCC_select_low_bit, TCC_select_num_bits); | |
| } else { | |
| return createMachineID(MachineType:TCCdir, intToID(0)); | |
| } | |
| } else { | |
| error("Unexpected region buffer number"); | |
| } | |
| } | |
| bool isCpuMachine(MachineID rBuf) { | |
| if (machineIDToNodeID(rBuf) == cpuRegionBufferNum) { | |
| return true; | |
| } else if (machineIDToNodeID(rBuf) == gpuRegionBufferNum) { | |
| return false; | |
| } else { | |
| error("Unexpected region buffer number"); | |
| } | |
| } | |
| bool symMigrate(Entry cache_entry) { | |
| return cache_entry.LastWriten; | |
| } | |
| bool asymMigrate(Entry cache_entry, MachineID requestor) { | |
| if (isCpuMachine(requestor)) { | |
| return cache_entry.LastWritenByCpu; | |
| } else { | |
| return cache_entry.LastWritenByGpu; | |
| } | |
| } | |
| int getRegionOffset(Addr addr) { | |
| if (blocksPerRegion > 1) { | |
| Addr offset := bitSelect(addr, blockBits, regionBits+blockBits-1); | |
| int ret := addressToInt(offset); | |
| assert(ret < blocksPerRegion); | |
| return ret; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| Addr getRegionBase(Addr addr) { | |
| return maskLowOrderBits(addr, blockBits+regionBits); | |
| } | |
| Addr getNextBlock(Addr addr) { | |
| Addr a := addr; | |
| makeNextStrideAddress(a, 1); | |
| return a; | |
| } | |
| bool presentOrAvail(Addr addr) { | |
| DPRINTF(RubySlicc, "Present? %s, avail? %s\n", cacheMemory.isTagPresent(getRegionBase(addr)), cacheMemory.cacheAvail(getRegionBase(addr))); | |
| return cacheMemory.isTagPresent(getRegionBase(addr)) || cacheMemory.cacheAvail(getRegionBase(addr)); | |
| } | |
| // Returns a region entry! | |
| Entry getCacheEntry(Addr addr), return_by_pointer="yes" { | |
| return static_cast(Entry, "pointer", cacheMemory.lookup(getRegionBase(addr))); | |
| } | |
| TBE getTBE(Addr addr), return_by_pointer="yes" { | |
| return TBEs.lookup(getRegionBase(addr)); | |
| } | |
| DataBlock getDataBlock(Addr addr), return_by_ref="yes" { | |
| return getCacheEntry(getRegionBase(addr)).DataBlk; | |
| } | |
| State getState(TBE tbe, Entry cache_entry, Addr addr) { | |
| if (is_valid(tbe)) { | |
| return tbe.TBEState; | |
| } else if (is_valid(cache_entry)) { | |
| return cache_entry.RegionState; | |
| } | |
| return State:NP; | |
| } | |
| void setState(TBE tbe, Entry cache_entry, Addr addr, State state) { | |
| if (is_valid(tbe)) { | |
| tbe.TBEState := state; | |
| } | |
| if (is_valid(cache_entry)) { | |
| cache_entry.RegionState := state; | |
| } | |
| } | |
| AccessPermission getAccessPermission(Addr addr) { | |
| TBE tbe := getTBE(addr); | |
| if(is_valid(tbe)) { | |
| return RegionDir_State_to_permission(tbe.TBEState); | |
| } | |
| Entry cache_entry := getCacheEntry(addr); | |
| if(is_valid(cache_entry)) { | |
| return RegionDir_State_to_permission(cache_entry.RegionState); | |
| } | |
| return AccessPermission:NotPresent; | |
| } | |
| void setAccessPermission(Entry cache_entry, Addr addr, State state) { | |
| if (is_valid(cache_entry)) { | |
| cache_entry.changePermission(RegionDir_State_to_permission(state)); | |
| } | |
| } | |
| void functionalRead(Addr addr, Packet *pkt) { | |
| functionalMemoryRead(pkt); | |
| } | |
| int functionalWrite(Addr addr, Packet *pkt) { | |
| if (functionalMemoryWrite(pkt)) { | |
| return 1; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| void recordRequestType(RequestType request_type, Addr addr) { | |
| if (request_type == RequestType:DataArrayRead) { | |
| cacheMemory.recordRequestType(CacheRequestType:DataArrayRead, addr); | |
| } else if (request_type == RequestType:DataArrayWrite) { | |
| cacheMemory.recordRequestType(CacheRequestType:DataArrayWrite, addr); | |
| } else if (request_type == RequestType:TagArrayRead) { | |
| cacheMemory.recordRequestType(CacheRequestType:TagArrayRead, addr); | |
| } else if (request_type == RequestType:TagArrayWrite) { | |
| cacheMemory.recordRequestType(CacheRequestType:TagArrayWrite, addr); | |
| } | |
| } | |
| bool checkResourceAvailable(RequestType request_type, Addr addr) { | |
| if (request_type == RequestType:DataArrayRead) { | |
| return cacheMemory.checkResourceAvailable(CacheResourceType:DataArray, addr); | |
| } else if (request_type == RequestType:DataArrayWrite) { | |
| return cacheMemory.checkResourceAvailable(CacheResourceType:DataArray, addr); | |
| } else if (request_type == RequestType:TagArrayRead) { | |
| return cacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr); | |
| } else if (request_type == RequestType:TagArrayWrite) { | |
| return cacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr); | |
| } else { | |
| error("Invalid RequestType type in checkResourceAvailable"); | |
| return true; | |
| } | |
| } | |
| out_port(triggerQueue_out, TriggerMsg, triggerQueue); | |
| out_port(requestNetwork_out, CPURequestMsg, requestToDir); | |
| out_port(notifyNetwork_out, CPURequestMsg, notifyToRBuffer); | |
| out_port(probeNetwork_out, NBProbeRequestMsg, probeToRBuffer); | |
| in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=2) { | |
| if (triggerQueue_in.isReady(clockEdge())) { | |
| peek(triggerQueue_in, TriggerMsg) { | |
| assert(in_msg.addr == getRegionBase(in_msg.addr)); | |
| Entry cache_entry := getCacheEntry(in_msg.addr); | |
| TBE tbe := getTBE(in_msg.addr); | |
| DPRINTF(RubySlicc, "trigger msg: %s (%s)\n", in_msg, getRegionBase(in_msg.addr)); | |
| if (in_msg.Type == TriggerType:AcksComplete) { | |
| assert(is_valid(tbe)); | |
| trigger(Event:LastAck, in_msg.addr, cache_entry, tbe); | |
| } else if (in_msg.Type == TriggerType:InvRegion) { | |
| assert(is_valid(tbe)); | |
| trigger(Event:TriggerInv, in_msg.addr, cache_entry, tbe); | |
| } else if (in_msg.Type == TriggerType:DowngradeRegion) { | |
| assert(is_valid(tbe)); | |
| trigger(Event:TriggerDowngrade, in_msg.addr, cache_entry, tbe); | |
| } else { | |
| error("Unknown trigger message"); | |
| } | |
| } | |
| } | |
| } | |
| in_port(responseNetwork_in, ResponseMsg, responseFromRBuffer, rank=1) { | |
| if (responseNetwork_in.isReady(clockEdge())) { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| TBE tbe := getTBE(in_msg.addr); | |
| Entry cache_entry := getCacheEntry(in_msg.addr); | |
| if (in_msg.Type == CoherenceResponseType:CPUPrbResp) { | |
| assert(in_msg.addr == getRegionBase(in_msg.addr)); | |
| assert(is_valid(tbe)); | |
| if (in_msg.NotCached) { | |
| trigger(Event:InvAckCoreNoShare, in_msg.addr, cache_entry, tbe); | |
| } else { | |
| trigger(Event:InvAckCore, in_msg.addr, cache_entry, tbe); | |
| } | |
| } else if (in_msg.Type == CoherenceResponseType:PrivateAck) { | |
| assert(in_msg.addr == getRegionBase(in_msg.addr)); | |
| assert(is_valid(cache_entry)); | |
| //Fix Me...add back in: assert(cache_entry.Sharers.isElement(in_msg.Sender)); | |
| trigger(Event:CPUPrivateAck, in_msg.addr, cache_entry, tbe); | |
| } else if (in_msg.Type == CoherenceResponseType:RegionWbAck) { | |
| //Fix Me...add back in: assert(cache_entry.Sharers.isElement(in_msg.Sender) == false); | |
| assert(in_msg.addr == getRegionBase(in_msg.addr)); | |
| trigger(Event:WritebackAck, in_msg.addr, cache_entry, tbe); | |
| } else if (in_msg.Type == CoherenceResponseType:DirReadyAck) { | |
| assert(is_valid(tbe)); | |
| trigger(Event:DirReadyAck, getRegionBase(in_msg.addr), cache_entry, tbe); | |
| } else { | |
| error("Invalid response type"); | |
| } | |
| } | |
| } | |
| } | |
| // In from cores | |
| // NOTE: We get the cache / TBE entry based on the region address, | |
| // but pass the block address to the actions | |
| in_port(requestNetwork_in, CPURequestMsg, requestFromRegBuf, rank=0) { | |
| if (requestNetwork_in.isReady(clockEdge())) { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| //assert(in_msg.addr == getRegionBase(in_msg.addr)); | |
| Addr address := getRegionBase(in_msg.addr); | |
| DPRINTF(RubySlicc, "Got %s, base %s\n", in_msg.addr, address); | |
| if (presentOrAvail(address)) { | |
| TBE tbe := getTBE(address); | |
| Entry cache_entry := getCacheEntry(address); | |
| if (in_msg.Type == CoherenceRequestType:PrivateRequest) { | |
| if (is_valid(cache_entry) && (cache_entry.Owner != in_msg.Requestor || | |
| getState(tbe, cache_entry, address) == State:S)) { | |
| trigger(Event:SendInv, address, cache_entry, tbe); | |
| } else { | |
| trigger(Event:PrivateRequest, address, cache_entry, tbe); | |
| } | |
| } else if (in_msg.Type == CoherenceRequestType:SharedRequest) { | |
| if (is_invalid(cache_entry)) { | |
| // If no one has ever requested this region give private permissions | |
| trigger(Event:PrivateRequest, address, cache_entry, tbe); | |
| } else { | |
| if (always_migrate || | |
| (sym_migrate && symMigrate(cache_entry)) || | |
| (asym_migrate && asymMigrate(cache_entry, in_msg.Requestor))) { | |
| if (cache_entry.Sharers.count() == 1 && | |
| cache_entry.Sharers.isElement(in_msg.Requestor)) { | |
| trigger(Event:UpgradeRequest, address, cache_entry, tbe); | |
| } else { | |
| trigger(Event:SendInv, address, cache_entry, tbe); | |
| } | |
| } else { // don't migrate | |
| if(cache_entry.Sharers.isElement(in_msg.Requestor) || | |
| getState(tbe, cache_entry, address) == State:S) { | |
| trigger(Event:SharedRequest, address, cache_entry, tbe); | |
| } else { | |
| trigger(Event:SendDowngrade, address, cache_entry, tbe); | |
| } | |
| } | |
| } | |
| } else if (in_msg.Type == CoherenceRequestType:UpgradeRequest) { | |
| if (is_invalid(cache_entry)) { | |
| trigger(Event:PrivateRequest, address, cache_entry, tbe); | |
| } else if (cache_entry.Sharers.count() == 1 && cache_entry.Sharers.isElement(in_msg.Requestor)) { | |
| trigger(Event:UpgradeRequest, address, cache_entry, tbe); | |
| } else { | |
| trigger(Event:SendUpgrade, address, cache_entry, tbe); | |
| } | |
| } else if (in_msg.Type == CoherenceRequestType:CleanWbRequest) { | |
| if (is_invalid(cache_entry) || cache_entry.Sharers.isElement(in_msg.Requestor) == false) { | |
| trigger(Event:StaleCleanWbRequest, address, cache_entry, tbe); | |
| } else { | |
| DPRINTF(RubySlicc, "wb address %s(%s) owner %s sharers %s requestor %s %d %d\n", in_msg.addr, getRegionBase(in_msg.addr), cache_entry.Owner, cache_entry.Sharers, in_msg.Requestor, cache_entry.Sharers.isElement(in_msg.Requestor), cache_entry.Sharers.count()); | |
| if (cache_entry.Sharers.isElement(in_msg.Requestor) && cache_entry.Sharers.count() == 1) { | |
| DPRINTF(RubySlicc, "last wb\n"); | |
| trigger(Event:CleanWbRequest_LastSharer, address, cache_entry, tbe); | |
| } else { | |
| DPRINTF(RubySlicc, "clean wb\n"); | |
| trigger(Event:CleanWbRequest, address, cache_entry, tbe); | |
| } | |
| } | |
| } else { | |
| error("unknown region dir request type"); | |
| } | |
| } else { | |
| Addr victim := cacheMemory.cacheProbe(getRegionBase(in_msg.addr)); | |
| TBE victim_tbe := getTBE(victim); | |
| Entry victim_entry := getCacheEntry(victim); | |
| DPRINTF(RubySlicc, "Evicting address %s for new region at address %s(%s)\n", victim, in_msg.addr, getRegionBase(in_msg.addr)); | |
| assert(is_valid(victim_entry)); | |
| trigger(Event:Evict, victim, victim_entry, victim_tbe); | |
| } | |
| } | |
| } | |
| } | |
| // Actions | |
| action(f_fwdReqToDir, "f", desc="Forward CPU request to directory") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(requestNetwork_out, CPURequestMsg, toDirLatency) { | |
| out_msg.addr := in_msg.addr; // This is the block address. "address" is the region address | |
| out_msg.Type := in_msg.OriginalType; | |
| out_msg.DataBlk := in_msg.DataBlk; | |
| out_msg.Dirty := in_msg.Dirty; | |
| out_msg.Requestor := getCoreMachine(in_msg.Requestor,address); | |
| out_msg.WTRequestor := in_msg.WTRequestor; | |
| out_msg.Destination.add(mapAddressToMachine(in_msg.addr, MachineType:Directory)); | |
| out_msg.Shared := in_msg.Shared; | |
| out_msg.MessageSize := in_msg.MessageSize; | |
| out_msg.Private := in_msg.Private; | |
| out_msg.NoAckNeeded := true; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| out_msg.ProbeRequestStartTime := curCycle(); | |
| out_msg.DemandRequest := true; | |
| if (is_valid(cache_entry) && getState(tbe, cache_entry, address) != State:S) { | |
| out_msg.Acks := cache_entry.Sharers.count(); | |
| } else { | |
| out_msg.Acks := 0; | |
| } | |
| } | |
| } | |
| } | |
| action(f_fwdReqToDirShared, "fs", desc="Forward CPU request to directory (shared)") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(requestNetwork_out, CPURequestMsg, toDirLatency) { | |
| out_msg.addr := in_msg.addr; // This is the block address. "address" is the region address | |
| out_msg.Type := in_msg.OriginalType; | |
| out_msg.DataBlk := in_msg.DataBlk; | |
| out_msg.Dirty := in_msg.Dirty; | |
| out_msg.Requestor := getCoreMachine(in_msg.Requestor,address); | |
| out_msg.WTRequestor := in_msg.WTRequestor; | |
| out_msg.Destination.add(mapAddressToMachine(in_msg.addr, MachineType:Directory)); | |
| out_msg.Shared := in_msg.Shared; | |
| out_msg.MessageSize := in_msg.MessageSize; | |
| out_msg.Private := in_msg.Private; | |
| out_msg.NoAckNeeded := true; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| out_msg.ProbeRequestStartTime := curCycle(); | |
| out_msg.DemandRequest := true; | |
| out_msg.ForceShared := true; | |
| if (is_valid(cache_entry) && getState(tbe, cache_entry, address) != State:S) { | |
| out_msg.Acks := cache_entry.Sharers.count(); | |
| } else { | |
| out_msg.Acks := 0; | |
| } | |
| } | |
| } | |
| } | |
| action(f_fwdReqToDirWithAck, "fa", desc="Forward CPU request to directory with ack request") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(requestNetwork_out, CPURequestMsg, toDirLatency) { | |
| out_msg.addr := in_msg.addr; // This is the block address. "address" is the region address | |
| out_msg.Type := in_msg.OriginalType; | |
| out_msg.DataBlk := in_msg.DataBlk; | |
| out_msg.Dirty := in_msg.Dirty; | |
| out_msg.Requestor := getCoreMachine(in_msg.Requestor,address); | |
| out_msg.WTRequestor := in_msg.WTRequestor; | |
| out_msg.Destination.add(mapAddressToMachine(in_msg.addr, MachineType:Directory)); | |
| out_msg.Shared := in_msg.Shared; | |
| out_msg.MessageSize := in_msg.MessageSize; | |
| out_msg.Private := in_msg.Private; | |
| out_msg.NoAckNeeded := false; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| out_msg.ProbeRequestStartTime := curCycle(); | |
| out_msg.DemandRequest := true; | |
| if (is_valid(cache_entry)) { | |
| out_msg.Acks := cache_entry.Sharers.count(); | |
| // Don't need an ack from the requestor! | |
| if (cache_entry.Sharers.isElement(in_msg.Requestor)) { | |
| out_msg.Acks := out_msg.Acks - 1; | |
| } | |
| } else { | |
| out_msg.Acks := 0; | |
| } | |
| } | |
| } | |
| } | |
| action(f_fwdReqToDirWithAckShared, "fas", desc="Forward CPU request to directory with ack request") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(requestNetwork_out, CPURequestMsg, toDirLatency) { | |
| out_msg.addr := in_msg.addr; // This is the block address. "address" is the region address | |
| out_msg.Type := in_msg.OriginalType; | |
| out_msg.DataBlk := in_msg.DataBlk; | |
| out_msg.Dirty := in_msg.Dirty; | |
| out_msg.Requestor := getCoreMachine(in_msg.Requestor,address); | |
| out_msg.WTRequestor := in_msg.WTRequestor; | |
| out_msg.Destination.add(mapAddressToMachine(in_msg.addr, MachineType:Directory)); | |
| out_msg.Shared := in_msg.Shared; | |
| out_msg.MessageSize := in_msg.MessageSize; | |
| out_msg.Private := in_msg.Private; | |
| out_msg.NoAckNeeded := false; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| out_msg.ProbeRequestStartTime := curCycle(); | |
| out_msg.DemandRequest := true; | |
| out_msg.ForceShared := true; | |
| if (is_valid(cache_entry)) { | |
| out_msg.Acks := cache_entry.Sharers.count(); | |
| // Don't need an ack from the requestor! | |
| if (cache_entry.Sharers.isElement(in_msg.Requestor)) { | |
| out_msg.Acks := out_msg.Acks - 1; | |
| } | |
| } else { | |
| out_msg.Acks := 0; | |
| } | |
| } | |
| } | |
| } | |
| action(a_allocateRegionEntry, "a", desc="Allocate a new entry") { | |
| set_cache_entry(cacheMemory.allocate(getRegionBase(address), new Entry)); | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| APPEND_TRANSITION_COMMENT(in_msg.Requestor); | |
| } | |
| } | |
| action(d_deallocateRegionEntry, "d", desc="Deallocate region entry") { | |
| cacheMemory.deallocate(getRegionBase(address)); | |
| unset_cache_entry(); | |
| } | |
| action(ra_receiveAck, "ra", desc="Mark TBE entry as received this ack") { | |
| //assert(tbe.ValidBlocks.at(getRegionOffset(address))); | |
| DPRINTF(RubySlicc, "received ack for %s reg: %s\n", address, getRegionBase(address)); | |
| tbe.NumValidBlocks := tbe.NumValidBlocks - 1; | |
| assert(tbe.NumValidBlocks >= 0); | |
| if (tbe.NumValidBlocks == 0) { | |
| tbe.AllAcksReceived := true; | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.Type := TriggerType:AcksComplete; | |
| out_msg.addr := address; | |
| } | |
| } | |
| APPEND_TRANSITION_COMMENT(getRegionBase(address)); | |
| APPEND_TRANSITION_COMMENT(" Acks left receive "); | |
| APPEND_TRANSITION_COMMENT(tbe.NumValidBlocks); | |
| } | |
| action(ca_checkAcks, "ca", desc="Check to see if we need more acks") { | |
| if (tbe.NumValidBlocks == 0) { | |
| tbe.AllAcksReceived := true; | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.Type := TriggerType:AcksComplete; | |
| out_msg.addr := address; | |
| } | |
| } | |
| } | |
| action(ti_triggerInv, "ti", desc="") { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.Type := TriggerType:InvRegion; | |
| out_msg.addr := address; | |
| } | |
| } | |
| action(td_triggerDowngrade, "td", desc="") { | |
| enqueue(triggerQueue_out, TriggerMsg, 1) { | |
| out_msg.Type := TriggerType:DowngradeRegion; | |
| out_msg.addr := address; | |
| } | |
| } | |
| action(t_allocateTBE, "t", desc="allocate TBE Entry") { | |
| check_allocate(TBEs); | |
| TBEs.allocate(getRegionBase(address)); | |
| set_tbe(getTBE(address)); | |
| if (is_valid(cache_entry)) { | |
| tbe.Owner := cache_entry.Owner; | |
| tbe.Sharers := cache_entry.Sharers; | |
| tbe.AllAcksReceived := true; // assume no acks are required | |
| } | |
| tbe.ProbeRequestTime := curCycle(); | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| tbe.InitialRequestTime := in_msg.InitialRequestTime; | |
| tbe.DemandAddress := in_msg.addr; | |
| } | |
| APPEND_TRANSITION_COMMENT(getRegionBase(address)); | |
| APPEND_TRANSITION_COMMENT(" Acks left "); | |
| APPEND_TRANSITION_COMMENT(tbe.NumValidBlocks); | |
| APPEND_TRANSITION_COMMENT(" Owner, "); | |
| APPEND_TRANSITION_COMMENT(tbe.Owner); | |
| APPEND_TRANSITION_COMMENT(" sharers, "); | |
| APPEND_TRANSITION_COMMENT(tbe.Sharers); | |
| } | |
| action(ss_setSharers, "ss", desc="Add requestor to sharers") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| cache_entry.Sharers.add(in_msg.Requestor); | |
| APPEND_TRANSITION_COMMENT(cache_entry.Sharers); | |
| } | |
| } | |
| action(rs_removeSharer, "rs", desc="Remove requestor to sharers") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| cache_entry.Sharers.remove(in_msg.Requestor); | |
| APPEND_TRANSITION_COMMENT(" removing "); | |
| APPEND_TRANSITION_COMMENT(in_msg.Requestor); | |
| APPEND_TRANSITION_COMMENT(" sharers "); | |
| APPEND_TRANSITION_COMMENT(cache_entry.Sharers); | |
| } | |
| } | |
| action(rsr_removeSharerResponse, "rsr", desc="Remove requestor to sharers") { | |
| peek(responseNetwork_in, ResponseMsg) { | |
| cache_entry.Sharers.remove(in_msg.Sender); | |
| APPEND_TRANSITION_COMMENT(cache_entry.Sharers); | |
| } | |
| } | |
| action(cs_clearSharers, "cs", desc="Add requestor to sharers") { | |
| cache_entry.Sharers.clear(); | |
| } | |
| action(so_setOwner, "so", desc="Set the owner to the requestor") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| cache_entry.Owner := in_msg.Requestor; | |
| APPEND_TRANSITION_COMMENT(" Owner now: "); | |
| APPEND_TRANSITION_COMMENT(cache_entry.Owner); | |
| } | |
| } | |
| action(rr_removeRequestorFromTBE, "rr", desc="Remove requestor from TBE sharers") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| tbe.Sharers.remove(in_msg.Requestor); | |
| } | |
| } | |
| action(ur_updateDirtyStatusOnRequest, "ur", desc="Update dirty status on demand request") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| if (is_valid(cache_entry)) { | |
| if ((in_msg.Type == CoherenceRequestType:SharedRequest) && | |
| (cache_entry.Sharers.isElement(in_msg.Requestor) == false)) { | |
| cache_entry.LastWriten := false; | |
| if (isCpuMachine(in_msg.Requestor)) { | |
| cache_entry.LastWritenByCpu := false; | |
| } else { | |
| cache_entry.LastWritenByGpu := false; | |
| } | |
| } else if ((in_msg.Type == CoherenceRequestType:PrivateRequest) || | |
| (in_msg.Type == CoherenceRequestType:UpgradeRequest)) { | |
| cache_entry.LastWriten := true; | |
| if (isCpuMachine(in_msg.Requestor)) { | |
| cache_entry.LastWritenByCpu := true; | |
| } else { | |
| cache_entry.LastWritenByGpu := true; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| action(ud_updateDirtyStatusWithWb, "ud", desc="Update dirty status on writeback") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| if (is_valid(cache_entry) && in_msg.Dirty) { | |
| cache_entry.LastWriten := true; | |
| if (isCpuMachine(in_msg.Requestor)) { | |
| cache_entry.LastWritenByCpu := true; | |
| } else { | |
| cache_entry.LastWritenByGpu := true; | |
| } | |
| } | |
| } | |
| } | |
| action(sns_setNumAcksSharers, "sns", desc="Set number of acks to one per shared region buffer") { | |
| assert(is_valid(tbe)); | |
| assert(is_valid(cache_entry)); | |
| tbe.NumValidBlocks := tbe.Sharers.count(); | |
| } | |
| action(sno_setNumAcksOne, "sno", desc="Set number of acks to one per shared region buffer") { | |
| assert(is_valid(tbe)); | |
| assert(is_valid(cache_entry)); | |
| tbe.NumValidBlocks := 1; | |
| } | |
| action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") { | |
| TBEs.deallocate(getRegionBase(address)); | |
| APPEND_TRANSITION_COMMENT(" reg: "); | |
| APPEND_TRANSITION_COMMENT(getRegionBase(address)); | |
| unset_tbe(); | |
| } | |
| action(wb_sendWbNotice, "wb", desc="Send notice to cache that writeback is acknowledged") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(notifyNetwork_out, CPURequestMsg, 1) { | |
| out_msg.addr := getRegionBase(address); | |
| out_msg.Type := CoherenceRequestType:WbNotify; | |
| out_msg.Destination.add(in_msg.Requestor); | |
| out_msg.Requestor := machineID; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| } | |
| } | |
| } | |
| action(wbn_sendWbNoticeNoAck, "wbn", desc="Send notice to cache that writeback is acknowledged (no ack needed)") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(notifyNetwork_out, CPURequestMsg, 1) { | |
| out_msg.addr := getRegionBase(address); | |
| out_msg.Type := CoherenceRequestType:WbNotify; | |
| out_msg.Destination.add(in_msg.Requestor); | |
| out_msg.Requestor := machineID; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| out_msg.NoAckNeeded := true; | |
| } | |
| } | |
| } | |
| action(b_sendPrivateNotice, "b", desc="Send notice to private cache that it has private access") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(notifyNetwork_out, CPURequestMsg, 1) { | |
| out_msg.addr := getRegionBase(address); | |
| out_msg.Type := CoherenceRequestType:PrivateNotify; | |
| out_msg.Destination.add(in_msg.Requestor); | |
| out_msg.Requestor := machineID; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| } | |
| } | |
| } | |
| action(bs_sendSharedNotice, "bs", desc="Send notice to private cache that it has private access") { | |
| peek(requestNetwork_in, CPURequestMsg) { | |
| enqueue(notifyNetwork_out, CPURequestMsg, 1) { | |
| out_msg.addr := getRegionBase(address); | |
| out_msg.Type := CoherenceRequestType:SharedNotify; | |
| out_msg.Destination.add(in_msg.Requestor); | |
| out_msg.Requestor := machineID; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| out_msg.InitialRequestTime := in_msg.InitialRequestTime; | |
| } | |
| } | |
| } | |
| action(c_sendSharedNoticeToOrigReq, "c", desc="Send notice to private cache that it has shared access") { | |
| assert(is_valid(tbe)); | |
| enqueue(notifyNetwork_out, CPURequestMsg, 1) { | |
| out_msg.addr := getRegionBase(address); | |
| out_msg.Type := CoherenceRequestType:SharedNotify; | |
| out_msg.Destination.add(tbe.Owner); | |
| out_msg.Requestor := machineID; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| out_msg.ProbeRequestStartTime := tbe.ProbeRequestTime; | |
| out_msg.InitialRequestTime := tbe.InitialRequestTime; | |
| APPEND_TRANSITION_COMMENT("dest: "); | |
| APPEND_TRANSITION_COMMENT(out_msg.Destination); | |
| } | |
| } | |
| action(sp_sendPrivateNoticeToOrigReq, "sp", desc="Send notice to private cache that it has private access") { | |
| assert(is_valid(tbe)); | |
| enqueue(notifyNetwork_out, CPURequestMsg, 1) { | |
| out_msg.addr := getRegionBase(address); | |
| out_msg.Type := CoherenceRequestType:PrivateNotify; | |
| out_msg.Destination.add(tbe.Owner); | |
| out_msg.Requestor := machineID; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| out_msg.ProbeRequestStartTime := tbe.ProbeRequestTime; | |
| out_msg.InitialRequestTime := tbe.InitialRequestTime; | |
| APPEND_TRANSITION_COMMENT("dest: "); | |
| APPEND_TRANSITION_COMMENT(out_msg.Destination); | |
| } | |
| } | |
| action(i_RegionInvNotify, "i", desc="Send notice to private cache that it no longer has private access") { | |
| enqueue(probeNetwork_out, NBProbeRequestMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.DemandAddress := tbe.DemandAddress; | |
| //out_msg.Requestor := tbe.Requestor; | |
| out_msg.Requestor := machineID; | |
| out_msg.Type := ProbeRequestType:PrbInv; | |
| //Fix me: assert(tbe.Sharers.count() > 0); | |
| out_msg.DemandRequest := true; | |
| out_msg.Destination := tbe.Sharers; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| APPEND_TRANSITION_COMMENT("dest: "); | |
| APPEND_TRANSITION_COMMENT(out_msg.Destination); | |
| } | |
| } | |
| action(i0_RegionInvNotifyDemand0, "i0", desc="Send notice to private cache that it no longer has private access") { | |
| enqueue(probeNetwork_out, NBProbeRequestMsg, 1) { | |
| out_msg.addr := address; | |
| // Demand address should default to 0 -> out_msg.DemandAddress := 0; | |
| out_msg.Requestor := machineID; | |
| out_msg.Type := ProbeRequestType:PrbInv; | |
| out_msg.Destination := tbe.Sharers; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| APPEND_TRANSITION_COMMENT("dest: "); | |
| APPEND_TRANSITION_COMMENT(out_msg.Destination); | |
| } | |
| } | |
| action(rd_RegionDowngrade, "rd", desc="Send notice to private cache that it only has shared access") { | |
| enqueue(probeNetwork_out, NBProbeRequestMsg, 1) { | |
| out_msg.addr := address; | |
| out_msg.DemandAddress := tbe.DemandAddress; | |
| out_msg.Requestor := machineID; | |
| out_msg.Type := ProbeRequestType:PrbDowngrade; | |
| out_msg.DemandRequest := true; | |
| out_msg.Destination := tbe.Sharers; | |
| out_msg.MessageSize := MessageSizeType:Request_Control; | |
| APPEND_TRANSITION_COMMENT("dest: "); | |
| APPEND_TRANSITION_COMMENT(out_msg.Destination); | |
| } | |
| } | |
| action(p_popRequestQueue, "p", desc="Pop the request queue") { | |
| requestNetwork_in.dequeue(clockEdge()); | |
| } | |
| action(pt_popTriggerQueue, "pt", desc="Pop the trigger queue") { | |
| triggerQueue_in.dequeue(clockEdge()); | |
| } | |
| action(pr_popResponseQueue, "pr", desc="Pop the response queue") { | |
| responseNetwork_in.dequeue(clockEdge()); | |
| } | |
| action(s_stallAndWaitRequest, "s", desc="Stall and wait on the region address") { | |
| Addr regAddr := getRegionBase(address); | |
| stall_and_wait(requestNetwork_in, regAddr); | |
| } | |
| action(w_wakeUpRegionDependents, "w", desc="Wake up any requests waiting for this region") { | |
| wakeUpBuffers(getRegionBase(address)); | |
| } | |
| action(wa_wakeUpAllDependents, "wa", desc="Wake up any requests waiting for this region") { | |
| wakeUpAllBuffers(); | |
| } | |
| action(zz_recycleRequestQueue, "\z", desc="...") { | |
| requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); | |
| } | |
| action(z_stall, "z", desc="stall request queue") { | |
| // fake state | |
| } | |
| action(mru_setMRU, "mru", desc="set MRU") { | |
| cacheMemory.setMRU(address); | |
| } | |
| // Transistions | |
| transition({NP_P, P_P, NP_S, S_S, S_P, P_S, P_NP, S_AP, P_AS, P_AP, SP_NP_W, S_W, P_AP_W, P_AS_W, S_AP_W}, {PrivateRequest, SharedRequest, UpgradeRequest, SendInv, SendUpgrade, SendDowngrade, CleanWbRequest, CleanWbRequest_LastSharer, StaleCleanWbRequest}) { | |
| s_stallAndWaitRequest | |
| } | |
| transition({NP_P, P_P, NP_S, S_S, S_P, S_W, P_S, P_NP, S_AP, P_AS, P_AP, P_AP_W, P_AS_W, S_AP_W}, Evict) { | |
| zz_recycleRequestQueue; | |
| } | |
| transition(NP, {PrivateRequest, SendUpgrade}, NP_P) {TagArrayRead, TagArrayWrite} { | |
| a_allocateRegionEntry; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDir; | |
| b_sendPrivateNotice; | |
| so_setOwner; | |
| ss_setSharers; | |
| t_allocateTBE; | |
| p_popRequestQueue; | |
| } | |
| transition(P, {PrivateRequest, UpgradeRequest}, P_P) {TagArrayRead} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDir; | |
| b_sendPrivateNotice; | |
| t_allocateTBE; | |
| p_popRequestQueue; | |
| } | |
| transition({NP_P, P_P}, CPUPrivateAck, P) { | |
| dt_deallocateTBE; | |
| w_wakeUpRegionDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition({NP, P, S}, StaleCleanWbRequest) {TagArrayRead, TagArrayWrite} { | |
| wbn_sendWbNoticeNoAck; | |
| ud_updateDirtyStatusWithWb; | |
| p_popRequestQueue; | |
| } | |
| transition(NP, SharedRequest, NP_S) {TagArrayRead, TagArrayWrite} { | |
| a_allocateRegionEntry; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirShared; | |
| bs_sendSharedNotice; | |
| so_setOwner; | |
| ss_setSharers; | |
| t_allocateTBE; | |
| p_popRequestQueue; | |
| } | |
| // Could probably do this in parallel with other shared requests | |
| transition(S, SharedRequest, S_S) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirShared; | |
| bs_sendSharedNotice; | |
| ss_setSharers; | |
| t_allocateTBE; | |
| p_popRequestQueue; | |
| } | |
| transition({P, S}, CleanWbRequest_LastSharer, SP_NP_W) {TagArrayRead, TagArrayWrite} { | |
| ud_updateDirtyStatusWithWb; | |
| wb_sendWbNotice; | |
| rs_removeSharer; | |
| t_allocateTBE; | |
| d_deallocateRegionEntry; | |
| p_popRequestQueue; | |
| } | |
| transition(S, CleanWbRequest, S_W) {TagArrayRead, TagArrayWrite} { | |
| ud_updateDirtyStatusWithWb; | |
| wb_sendWbNotice; | |
| rs_removeSharer; | |
| t_allocateTBE; | |
| p_popRequestQueue; | |
| } | |
| transition(SP_NP_W, WritebackAck, NP) { | |
| dt_deallocateTBE; | |
| w_wakeUpRegionDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition(S_W, WritebackAck, S) { | |
| dt_deallocateTBE; | |
| w_wakeUpRegionDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition({NP_S, S_S}, CPUPrivateAck, S) { | |
| dt_deallocateTBE; | |
| w_wakeUpRegionDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition(S, UpgradeRequest, S_P) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDir; | |
| b_sendPrivateNotice; | |
| so_setOwner; | |
| t_allocateTBE; | |
| p_popRequestQueue; | |
| } | |
| transition(S_P, CPUPrivateAck, P) { | |
| dt_deallocateTBE; | |
| w_wakeUpRegionDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition(P, SendInv, P_AP_W) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirWithAck; | |
| so_setOwner; | |
| t_allocateTBE; | |
| rr_removeRequestorFromTBE; | |
| sns_setNumAcksSharers; | |
| cs_clearSharers; | |
| ss_setSharers; | |
| //i_RegionInvNotify; | |
| p_popRequestQueue; | |
| } | |
| transition({P_AP_W, S_AP_W}, DirReadyAck) { | |
| ti_triggerInv; | |
| pr_popResponseQueue; | |
| } | |
| transition(P_AS_W, DirReadyAck) { | |
| td_triggerDowngrade; | |
| pr_popResponseQueue; | |
| } | |
| transition(P_AS_W, TriggerDowngrade, P_AS) { | |
| rd_RegionDowngrade; | |
| pt_popTriggerQueue; | |
| } | |
| transition(P_AP_W, TriggerInv, P_AP) { | |
| i_RegionInvNotify; | |
| pt_popTriggerQueue; | |
| } | |
| transition(S_AP_W, TriggerInv, S_AP) { | |
| i_RegionInvNotify; | |
| pt_popTriggerQueue; | |
| } | |
| transition(P, SendUpgrade, P_AP_W) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirWithAck; | |
| so_setOwner; | |
| t_allocateTBE; | |
| rr_removeRequestorFromTBE; | |
| sns_setNumAcksSharers; | |
| cs_clearSharers; | |
| ss_setSharers; | |
| p_popRequestQueue; | |
| } | |
| transition(P, Evict, P_NP) {TagArrayRead, TagArrayWrite} { | |
| t_allocateTBE; | |
| sns_setNumAcksSharers; | |
| i0_RegionInvNotifyDemand0; | |
| d_deallocateRegionEntry; | |
| } | |
| transition(S, SendInv, P_AP_W) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirWithAck; | |
| so_setOwner; | |
| t_allocateTBE; | |
| rr_removeRequestorFromTBE; | |
| sns_setNumAcksSharers; | |
| cs_clearSharers; | |
| ss_setSharers; | |
| p_popRequestQueue; | |
| } | |
| transition(S, Evict, P_NP) {TagArrayRead, TagArrayWrite} { | |
| t_allocateTBE; | |
| sns_setNumAcksSharers; | |
| i0_RegionInvNotifyDemand0; | |
| d_deallocateRegionEntry; | |
| } | |
| transition(P_NP, LastAck, NP) { | |
| dt_deallocateTBE; | |
| wa_wakeUpAllDependents; | |
| pt_popTriggerQueue; | |
| } | |
| transition(S, SendUpgrade, S_AP_W) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirWithAck; | |
| so_setOwner; | |
| t_allocateTBE; | |
| rr_removeRequestorFromTBE; | |
| sns_setNumAcksSharers; | |
| cs_clearSharers; | |
| ss_setSharers; | |
| p_popRequestQueue; | |
| } | |
| transition(S_AP, LastAck, S_P) { | |
| sp_sendPrivateNoticeToOrigReq; | |
| pt_popTriggerQueue; | |
| } | |
| transition(P_AP, LastAck, P_P) { | |
| sp_sendPrivateNoticeToOrigReq; | |
| pt_popTriggerQueue; | |
| } | |
| transition(P, SendDowngrade, P_AS_W) {TagArrayRead, TagArrayWrite} { | |
| mru_setMRU; | |
| ur_updateDirtyStatusOnRequest; | |
| f_fwdReqToDirWithAckShared; | |
| so_setOwner; | |
| t_allocateTBE; | |
| sns_setNumAcksSharers; | |
| ss_setSharers; //why do we set the sharers before sending the downgrade? Are we sending a downgrade to the requestor? | |
| p_popRequestQueue; | |
| } | |
| transition(P_AS, LastAck, P_S) { | |
| c_sendSharedNoticeToOrigReq; | |
| pt_popTriggerQueue; | |
| } | |
| transition(P_S, CPUPrivateAck, S) { | |
| dt_deallocateTBE; | |
| w_wakeUpRegionDependents; | |
| pr_popResponseQueue; | |
| } | |
| transition({P_NP, P_AS, S_AP, P_AP}, InvAckCore) {} { | |
| ra_receiveAck; | |
| pr_popResponseQueue; | |
| } | |
| transition({P_NP, S_AP, P_AP}, InvAckCoreNoShare) {} { | |
| ra_receiveAck; | |
| pr_popResponseQueue; | |
| } | |
| transition(P_AS, InvAckCoreNoShare) {} { | |
| ra_receiveAck; | |
| rsr_removeSharerResponse; | |
| pr_popResponseQueue; | |
| } | |
| } | |