diff options
Diffstat (limited to 'src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm')
-rw-r--r-- | src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm | 799 |
1 files changed, 799 insertions, 0 deletions
diff --git a/src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm b/src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm new file mode 100644 index 000000000..c16a2fe80 --- /dev/null +++ b/src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm @@ -0,0 +1,799 @@ + +/* + * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $Id$ + * + */ + + +machine(L1Cache, "MSI Directory L1 Cache CMP") { + + // NODE L1 CACHE + // From this node's L1 cache TO the network + // a local L1 -> this L2 bank, currently ordered with directory forwarded requests + MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="true"; + MessageBuffer dummyFrom1, network="To", virtual_network="1", ordered="false"; // dummy buffer that shouldn't be used + MessageBuffer dummyFrom2, network="To", virtual_network="2", ordered="false"; // dummy buffer that shouldn't be used + // a local L1 -> this L2 bank + MessageBuffer responseFromL1Cache, network="To", virtual_network="3", ordered="false"; + MessageBuffer dummyFrom4, network="To", virtual_network="4", ordered="false"; // dummy buffer that shouldn't be used + + + // To this node's L1 cache FROM the network + MessageBuffer dummyTo0, network="From", virtual_network="0", ordered="false"; // dummy buffer that shouldn't be used + MessageBuffer dummyTo1, network="From", virtual_network="1", ordered="false"; // dummy buffer that shouldn't be used + // a L2 bank -> this L1 + MessageBuffer requestToL1Cache, network="From", virtual_network="2", ordered="true"; + // a L2 bank -> this L1 + MessageBuffer responseToL1Cache, network="From", virtual_network="3", ordered="false"; + MessageBuffer dummyTo4, network="From", virtual_network="4", ordered="false"; // dummy buffer that shouldn't be used + + // STATES + enumeration(State, desc="Cache states", default="L1Cache_State_L1_I") { + // Base states + NP, desc="Not present in either cache"; + L1_I, desc="a L1 cache entry Idle"; + L1_S, desc="a L1 cache entry Shared"; + L1_M, desc="a L1 cache entry Modified", format="!b"; + + // Transient States + L1_IS, desc="L1 idle, issued GETS, have not seen response yet"; + L1_ISI, desc="L1 idle, issued GETS, saw INV, still waiting for data"; + L1_IM, desc="L1 idle, issued GETX, have not seen response yet"; + L1_IMI, desc="L1 idle, issued GETX, saw INV, still waiting for data"; + L1_IMS, desc="L1 idle, issued GETX, saw DownGrade, still waiting for data"; + L1_IMSI, desc="L1 idle, issued GETX, saw DownGrade, saw INV, still waiting for data"; + + L1_SI, desc="issued PUTS, waiting for response"; + L1_MI, desc="issued PUTX, waiting for response"; + } + + // EVENTS + enumeration(Event, desc="Cache events") { + // L1 events + Load, desc="Load request from the home processor"; + Ifetch, desc="I-fetch request from the home processor"; + Store, desc="Store request from the home processor"; + + // L1 is required to send response to the L2 immediately + L1_INV, "INV", desc="L1 Invalidation of M data", format="!r"; + L1_INV_S, "INV", desc="L1 Invalidation of S data", format="!r"; + L1_DownGrade, "Force DownGrade", desc="L2 cache forces an L1 cache in M to downgrade to S and writeback result"; + + // receiving of data + L1_Data, "Data", desc="Data in response to an L1 request, transistion to M or S depending on request"; + L1_Data_S, "Data S", desc="Data in response to an L1 request, write data then transistion to S"; + L1_Data_I, "Data I", desc="Data in response to an L1 request, write data then transistion to I"; + + // receiving of acks + L1_PutAck, "Put Ack", desc="PutS or PutX ack from L2"; + + // internal generated request + // L1 request to replace block, results in either a PUTS or PUTX request + L1_Replacement, desc="L1 Replacement", format="!r"; + // Currently same as replacement, request initiated when block is in the wrong L1 cache + L1_WriteBack, desc="on-chip L1 cache must write back to shared L2"; + } + + // TYPES + + // CacheEntry + structure(Entry, desc="...", interface="AbstractCacheEntry" ) { + State CacheState, desc="cache state"; + DataBlock DataBlk, desc="data for the block"; + } + + // TBE fields + structure(TBE, desc="...") { + Address Address, desc="Physical address for this TBE"; + State TBEState, desc="Transient state"; + DataBlock DataBlk, desc="Buffer for the data block"; + bool isPrefetch, desc="Set if this was caused by a prefetch"; + } + + external_type(CacheMemory) { + bool cacheAvail(Address); + Address cacheProbe(Address); + void allocate(Address); + void deallocate(Address); + Entry lookup(Address); + void changePermission(Address, AccessPermission); + bool isTagPresent(Address); + } + + external_type(TBETable) { + TBE lookup(Address); + void allocate(Address); + void deallocate(Address); + bool isPresent(Address); + } + + TBETable L1_TBEs, template_hack="<L1Cache_TBE>"; + + CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true"; + CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true"; + + MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true"; + // the optionalQueue doesn't have to be ordered for correctness + // however inforcing order ensures the prefetches reach the L2 in order + MessageBuffer optionalQueue, ordered="true", rank="101", abstract_chip_ptr="true"; + + Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i"; + + int cache_state_to_int(State state); + + // inclusive cache returns L1 entries only + Entry getL1CacheEntry(Address addr), return_by_ref="yes" { + if (L1DcacheMemory.isTagPresent(addr)) { + return L1DcacheMemory[addr]; + } else { + return L1IcacheMemory[addr]; + } + } + + void changeL1Permission(Address addr, AccessPermission permission) { + if (L1DcacheMemory.isTagPresent(addr)) { + return L1DcacheMemory.changePermission(addr, permission); + } else if(L1IcacheMemory.isTagPresent(addr)) { + return L1IcacheMemory.changePermission(addr, permission); + } else { + error("cannot change permission, L1 block not present"); + } + } + + bool isL1CacheTagPresent(Address addr) { + return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr)); + } + + State getState(Address addr) { + if((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == true){ + DEBUG_EXPR(id); + DEBUG_EXPR(addr); + } + assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); + + if(L1_TBEs.isPresent(addr)) { + return L1_TBEs[addr].TBEState; + } else if (isL1CacheTagPresent(addr)) { + return getL1CacheEntry(addr).CacheState; + } + return State:NP; + } + + string getStateStr(Address addr) { + return L1Cache_State_to_string(getState(addr)); + } + + // when is this called? + void setState(Address addr, State state) { + assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); + + // MUST CHANGE + if(L1_TBEs.isPresent(addr)) { + L1_TBEs[addr].TBEState := state; + } + + if (isL1CacheTagPresent(addr)) { + getL1CacheEntry(addr).CacheState := state; + + // Set permission + if (state == State:L1_I || state == State:L1_SI || state == State:L1_MI) { + changeL1Permission(addr, AccessPermission:Invalid); + } else if (state == State:L1_S) { + changeL1Permission(addr, AccessPermission:Read_Only); + } else if (state == State:L1_M) { + changeL1Permission(addr, AccessPermission:Read_Write); + } else { + changeL1Permission(addr, AccessPermission:Busy); + } + } + } + + Event mandatory_request_type_to_event(CacheRequestType type) { + if (type == CacheRequestType:LD) { + return Event:Load; + } else if (type == CacheRequestType:IFETCH) { + return Event:Ifetch; + } else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) { + return Event:Store; + } else { + error("Invalid CacheRequestType"); + } + } + + // ** OUT_PORTS ** + // All ports are to the same CMP network, queue id numbers determine IntraChip Switch location + + out_port(requestIntraChipL1Network_out, RequestMsg, requestFromL1Cache); + out_port(responseIntraChipL1Network_out, ResponseMsg, responseFromL1Cache); + + // ** IN_PORTS ** + in_port(dummyTo0_in, RequestMsg, dummyTo0) { + if (dummyTo0_in.isReady()) { + peek(dummyTo0_in, RequestMsg) { + DEBUG_EXPR(in_msg.Address); + DEBUG_EXPR(machineID); + DEBUG_EXPR(in_msg.Type); + DEBUG_EXPR(getState(in_msg.Address)); + DEBUG_EXPR(in_msg.RequestorMachId); + } + error("dummyTo0 port should not be used"); + } + } + + in_port(dummyTo1_in, RequestMsg, dummyTo1) { + if (dummyTo1_in.isReady()) { + peek(dummyTo1_in, RequestMsg) { + DEBUG_EXPR(in_msg.Address); + DEBUG_EXPR(machineID); + DEBUG_EXPR(in_msg.Type); + DEBUG_EXPR(getState(in_msg.Address)); + DEBUG_EXPR(in_msg.RequestorMachId); + } + error("dummyTo1 port should not be used"); + } + } + + in_port(dummyTo4_in, ResponseMsg, dummyTo4) { + if (dummyTo4_in.isReady()) { + peek(dummyTo4_in, ResponseMsg) { + DEBUG_EXPR(in_msg.Address); + DEBUG_EXPR(machineID); + DEBUG_EXPR(in_msg.Type); + DEBUG_EXPR(getState(in_msg.Address)); + DEBUG_EXPR(in_msg.SenderMachId); + } + error("dummyTo4 port should not be used"); + } + } + + // Response IntraChip L1 Network - response msg to this L1 cache + in_port(responseIntraChipL1Network_in, ResponseMsg, responseToL1Cache) { + if (responseIntraChipL1Network_in.isReady()) { + peek(responseIntraChipL1Network_in, ResponseMsg) { + DEBUG_EXPR(in_msg.Address); + DEBUG_EXPR(in_msg.Destination); + DEBUG_EXPR(in_msg.SenderMachId); + DEBUG_EXPR(machineID); + assert(in_msg.Destination.isElement(machineID)); + if(machineIDToMachineType(in_msg.SenderMachId) == MachineType:L2Cache) { + if(in_msg.Type == CoherenceResponseType:DATA) { + trigger(Event:L1_Data, in_msg.Address); // L1 now has data in its desired state + } else if(in_msg.Type == CoherenceResponseType:DATA_S) { + trigger(Event:L1_Data_S, in_msg.Address); // L1 now has data but must imediately move to S state + } else if(in_msg.Type == CoherenceResponseType:DATA_I) { + trigger(Event:L1_Data_I, in_msg.Address); // L1 now has data but must imediately move to INV state + } else if(in_msg.Type == CoherenceResponseType:ACK) { + trigger(Event:L1_PutAck, in_msg.Address); + } else { + error("Invalid L1 response type"); + } + } else { + error("A non-L2 cache sent a response to a L1 cache"); + } + } + } + } + + // Request InterChip network - request from this L1 cache to the shared L2 + in_port(requestIntraChipL1Network_in, RequestMsg, requestToL1Cache) { + if(requestIntraChipL1Network_in.isReady()) { + peek(requestIntraChipL1Network_in, RequestMsg) { + assert(in_msg.Destination.isElement(machineID)); + if(machineIDToMachineType(in_msg.RequestorMachId) == MachineType:L2Cache) { + if(in_msg.Type == CoherenceRequestType:L1_DG) { + trigger(Event:L1_DownGrade, in_msg.Address); // Force L1 to downgrade to S state + } else if (in_msg.Type == CoherenceRequestType:INV) { + trigger(Event:L1_INV, in_msg.Address); // L1 must invalidate it's modified version + } else if (in_msg.Type == CoherenceRequestType:INV_S) { + trigger(Event:L1_INV_S, in_msg.Address); // L1 must invalidate it's shared version + } else { + error("Invalid forwarded request type"); + } + } else { + error("A non-L2 cache sent a request to a L1 cache"); + } + } + } + } + + // Mandatory Queue betweens Node's CPU and it's L1 caches + in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") { + if (mandatoryQueue_in.isReady()) { + peek(mandatoryQueue_in, CacheMsg) { + + // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache + + if (in_msg.Type == CacheRequestType:IFETCH) { + // ** INSTRUCTION ACCESS *** + + // Check to see if it is in the OTHER L1 + if (L1DcacheMemory.isTagPresent(in_msg.Address)) { + // The block is in the wrong L1, put the request on the queue to the shared L2 + trigger(Event:L1_WriteBack, in_msg.Address); + } + if (L1IcacheMemory.isTagPresent(in_msg.Address)) { + // The tag matches for the L1, so the L1 asks the L2 for it. + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address); + } else { + if (L1IcacheMemory.cacheAvail(in_msg.Address)) { + // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address); + } else { + // No room in the L1, so we need to make room in the L1 + trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address)); + } + } + } else { + // *** DATA ACCESS *** + + // Check to see if it is in the OTHER L1 + if (L1IcacheMemory.isTagPresent(in_msg.Address)) { + // The block is in the wrong L1, put the request on the queue to the shared L2 + trigger(Event:L1_WriteBack, in_msg.Address); + } + if (L1DcacheMemory.isTagPresent(in_msg.Address)) { + // The tag matches for the L1, so the L1 ask the L2 for it + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address); + } else { + if (L1DcacheMemory.cacheAvail(in_msg.Address)) { + // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address); + } else { + // No room in the L1, so we need to make room in the L1 + trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address)); + } + } + } + } + } + } + + // ACTIONS + action(a_issueGETS, "a", desc="Issue GETS") { + peek(mandatoryQueue_in, CacheMsg) { + enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceRequestType:GETS; + out_msg.RequestorMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + out_msg.MessageSize := MessageSizeType:Control; + out_msg.L1CacheStateStr := getStateStr(address); + out_msg.Prefetch := in_msg.Prefetch; + out_msg.AccessMode := in_msg.AccessMode; + } + } + } + + action(b_issueGETX, "b", desc="Issue GETX") { + peek(mandatoryQueue_in, CacheMsg) { + enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceRequestType:GETX; + out_msg.RequestorMachId := machineID; + DEBUG_EXPR(machineID); + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + out_msg.MessageSize := MessageSizeType:Control; + out_msg.L1CacheStateStr := getStateStr(address); + out_msg.Prefetch := in_msg.Prefetch; + out_msg.AccessMode := in_msg.AccessMode; + } + } + } + + action(c_issueUPGRADE, "c", desc="Issue GETX") { + peek(mandatoryQueue_in, CacheMsg) { + enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceRequestType:UPGRADE; + out_msg.RequestorMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + out_msg.MessageSize := MessageSizeType:Control; + out_msg.L1CacheStateStr := getStateStr(address); + out_msg.Prefetch := in_msg.Prefetch; + out_msg.AccessMode := in_msg.AccessMode; + } + } + } + + action(f_issueGETINSTR, "g", desc="Issue GETINSTR") { + peek(mandatoryQueue_in, CacheMsg) { + enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceRequestType:GET_INSTR; + out_msg.RequestorMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + out_msg.MessageSize := MessageSizeType:Control; + out_msg.L1CacheStateStr := getStateStr(address); + out_msg.Prefetch := in_msg.Prefetch; + out_msg.AccessMode := in_msg.AccessMode; + } + } + } + + action(d_issuePUTX, "d", desc="Issue PUTX") { + enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceRequestType:PUTX; + out_msg.RequestorMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + out_msg.DataBlk := getL1CacheEntry(address).DataBlk; + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + DEBUG_EXPR(out_msg.DataBlk); + out_msg.MessageSize := MessageSizeType:Data; + out_msg.L1CacheStateStr := getStateStr(address); + } + } + + action(q_issuePUTS, "q", desc="Issue PUTS") { + enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceRequestType:PUTS; + out_msg.RequestorMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + out_msg.DataBlk := getL1CacheEntry(address).DataBlk; + out_msg.MessageSize := MessageSizeType:Data; + out_msg.L1CacheStateStr := getStateStr(address); + } + } + + // L1 responding to a L2 request with data + action(e_dataFromL1CacheToL2Cache, "e", desc="Send data from L1 cache to L2 Cache") { + enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceResponseType:DATA; + out_msg.SenderMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + out_msg.DataBlk := getL1CacheEntry(address).DataBlk; + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + DEBUG_EXPR(out_msg.DataBlk); + out_msg.MessageSize := MessageSizeType:Data; + } + } + + action(f_dataFromTBEToL2Cache, "f", desc="Send data from L1_TBE to L2 Cache") { + peek(requestIntraChipL1Network_in, RequestMsg) { + enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceResponseType:DATA; + out_msg.SenderMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + out_msg.DataBlk := L1_TBEs[in_msg.Address].DataBlk; + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + DEBUG_EXPR(out_msg.DataBlk); + out_msg.MessageSize := MessageSizeType:Data; + } + } + } + + // L1 responding to a L2 request with an invadiation ack + action(t_sendInvAckToL2Cache, "t", desc="Send Invadiation ack to L2 Cache") { + enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") { + out_msg.Address := address; + out_msg.Type := CoherenceResponseType:INV_ACK; + out_msg.SenderMachId := machineID; + out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID)); + DEBUG_EXPR(address); + DEBUG_EXPR(out_msg.Destination); + out_msg.MessageSize := MessageSizeType:Control; + } + } + + action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") { + DEBUG_EXPR(getL1CacheEntry(address).DataBlk); + sequencer.readCallback(address, getL1CacheEntry(address).DataBlk); + } + + action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") { + DEBUG_EXPR(getL1CacheEntry(address).DataBlk); + sequencer.writeCallback(address, getL1CacheEntry(address).DataBlk); + } + + action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") { + check_allocate(L1_TBEs); + L1_TBEs.allocate(address); + L1_TBEs[address].isPrefetch := false; + } + + action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") { + mandatoryQueue_in.dequeue(); + } + + action(l_popRequestQueue, "l", desc="Pop incoming request queue and profile the delay within this virtual network") { + profileMsgDelay(2, requestIntraChipL1Network_in.dequeue_getDelayCycles()); + } + + action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue and profile the delay within this virtual network") { + profileMsgDelay(3, responseIntraChipL1Network_in.dequeue_getDelayCycles()); + } + + action(s_deallocateTBE, "s", desc="Deallocate TBE") { + L1_TBEs.deallocate(address); + } + + action(u_writeDataToL1Cache, "u", desc="Write data to cache") { + peek(responseIntraChipL1Network_in, ResponseMsg) { + getL1CacheEntry(address).DataBlk := in_msg.DataBlk; + } + } + + action(x_copyDataFromL1CacheToTBE, "x", desc="Copy data from cache to TBE") { + L1_TBEs[address].DataBlk := getL1CacheEntry(address).DataBlk; + } + + action(z_stall, "z", desc="Stall") { + } + + action(ff_deallocateL1CacheBlock, "\f", desc="Deallocate L1 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") { + if (L1DcacheMemory.isTagPresent(address)) { + L1DcacheMemory.deallocate(address); + } else { + L1IcacheMemory.deallocate(address); + } + } + + action(oo_allocateL1DCacheBlock, "\o", desc="Set L1 D-cache tag equal to tag of block B.") { + if (L1DcacheMemory.isTagPresent(address) == false) { + L1DcacheMemory.allocate(address); + } + } + + action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") { + if (L1IcacheMemory.isTagPresent(address) == false) { + L1IcacheMemory.allocate(address); + } + } + + //***************************************************** + // TRANSITIONS + //***************************************************** + + // Transitions for Load/Store/Replacement/WriteBack from transient states + transition({L1_IS, L1_IM, L1_ISI, L1_IMI, L1_IMS, L1_IMSI, L1_SI, L1_MI}, {Load, Ifetch, Store, L1_Replacement, L1_WriteBack}) { + z_stall; + } + + // Transitions from Idle + transition({NP,L1_I}, {L1_Replacement, L1_WriteBack}) { + ff_deallocateL1CacheBlock; + } + + transition({NP,L1_I}, Load, L1_IS) { + oo_allocateL1DCacheBlock; + i_allocateTBE; + a_issueGETS; + k_popMandatoryQueue; + } + + transition({NP,L1_I}, Ifetch, L1_IS) { + pp_allocateL1ICacheBlock; + i_allocateTBE; + f_issueGETINSTR; + k_popMandatoryQueue; + } + + transition({NP,L1_I}, Store, L1_IM) { + oo_allocateL1DCacheBlock; + i_allocateTBE; + b_issueGETX; + k_popMandatoryQueue; + } + + // Transitions from Shared + transition({L1_S}, {Load,Ifetch}) { + h_load_hit; + k_popMandatoryQueue; + } + + transition(L1_S, Store, L1_IM) { + i_allocateTBE; + c_issueUPGRADE; + k_popMandatoryQueue; + } + + transition(L1_S, {L1_Replacement,L1_WriteBack}, L1_SI) { + i_allocateTBE; + q_issuePUTS; + x_copyDataFromL1CacheToTBE; + ff_deallocateL1CacheBlock; + } + + transition(L1_S, L1_INV_S, L1_I) { + t_sendInvAckToL2Cache; + l_popRequestQueue; + } + + // Transitions from Modified + transition(L1_M, {Load, Ifetch}) { + h_load_hit; + k_popMandatoryQueue; + } + + transition(L1_M, Store) { + hh_store_hit; + k_popMandatoryQueue; + } + + transition(L1_M, {L1_Replacement, L1_WriteBack}, L1_MI) { + i_allocateTBE; + d_issuePUTX; + x_copyDataFromL1CacheToTBE; + ff_deallocateL1CacheBlock; + } + + transition(L1_M, L1_INV, L1_I) { + e_dataFromL1CacheToL2Cache; + l_popRequestQueue; + } + + transition(L1_M, L1_DownGrade, L1_S) { + e_dataFromL1CacheToL2Cache; + l_popRequestQueue; + } + + // Transitions from L1_IS + transition(L1_IS, L1_INV_S, L1_ISI) { + t_sendInvAckToL2Cache; + l_popRequestQueue; + } + + transition(L1_IS, L1_Data, L1_S) { + u_writeDataToL1Cache; + h_load_hit; + s_deallocateTBE; + o_popIncomingResponseQueue; + } + + transition(L1_IS, L1_Data_I, L1_I) { + u_writeDataToL1Cache; + h_load_hit; + s_deallocateTBE; + o_popIncomingResponseQueue; + } + + // Transitions from L1_ISI + transition(L1_ISI, L1_Data, L1_I) { + u_writeDataToL1Cache; + h_load_hit; + s_deallocateTBE; + o_popIncomingResponseQueue; + } + + // Transitions from L1_IM + transition(L1_IM, L1_INV, L1_IMI) { // we don't have to respond immediately because we know the data is coming + l_popRequestQueue; + } + + transition(L1_IM, L1_INV_S) { + t_sendInvAckToL2Cache; + l_popRequestQueue; + } + + transition(L1_IM, L1_DownGrade, L1_IMS) { + l_popRequestQueue; + } + + transition(L1_IM, L1_Data, L1_M) { + u_writeDataToL1Cache; + hh_store_hit; + s_deallocateTBE; + o_popIncomingResponseQueue; + } + + transition(L1_IM, L1_Data_S, L1_S) { + u_writeDataToL1Cache; + hh_store_hit; + s_deallocateTBE; + e_dataFromL1CacheToL2Cache; + o_popIncomingResponseQueue; + } + + transition(L1_IM, L1_Data_I, L1_I) { + u_writeDataToL1Cache; + hh_store_hit; + s_deallocateTBE; + e_dataFromL1CacheToL2Cache; + o_popIncomingResponseQueue; + } + + // Transitions from L1_IMI - data should arrive and no request are possilbe + transition(L1_IMI, L1_Data, L1_I) { + u_writeDataToL1Cache; + hh_store_hit; + s_deallocateTBE; + e_dataFromL1CacheToL2Cache; + o_popIncomingResponseQueue; + } + + // Transitions from L1_IMS + transition(L1_IMS, L1_Data, L1_S) { + u_writeDataToL1Cache; + hh_store_hit; + s_deallocateTBE; + e_dataFromL1CacheToL2Cache; + o_popIncomingResponseQueue; + } + + transition(L1_IMS, L1_INV_S, L1_IMSI) { + l_popRequestQueue; + } + + // Transitions from L1_IMSI + transition(L1_IMSI, L1_Data, L1_I) { + u_writeDataToL1Cache; + hh_store_hit; + s_deallocateTBE; + e_dataFromL1CacheToL2Cache; + o_popIncomingResponseQueue; + } + + // Transitions from L1_SI + transition(L1_SI, L1_INV_S) { + t_sendInvAckToL2Cache; + l_popRequestQueue; + } + + transition(L1_SI, L1_PutAck, L1_I) { + s_deallocateTBE; + o_popIncomingResponseQueue; + } + + // Transitions from L1_MI + transition(L1_MI, L1_INV) { + f_dataFromTBEToL2Cache; + l_popRequestQueue; + } + + transition(L1_MI, L1_DownGrade, L1_SI) { + f_dataFromTBEToL2Cache; + l_popRequestQueue; + } + + transition(L1_MI, L1_PutAck, L1_I) { + s_deallocateTBE; + o_popIncomingResponseQueue; + } +} + + + |