| |
| /* |
| * 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: MOSI_directory_1level-cache.sm 1.18 04/09/07 13:52:52-05:00 mikem@maya.cs.wisc.edu $ |
| * |
| */ |
| |
| machine(L1Cache, "MOSI Directory Optimized") { |
| |
| MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="false"; |
| MessageBuffer responseFromCache, network="To", virtual_network="2", ordered="false"; |
| |
| MessageBuffer forwardedRequestToCache, network="From", virtual_network="1", ordered="true"; |
| MessageBuffer responseToCache, network="From", virtual_network="2", ordered="false"; |
| |
| // STATES |
| enumeration(State, desc="Cache states", default="L1Cache_State_I") { |
| // Base states |
| I, desc="Idle"; |
| S, desc="Shared"; |
| O, desc="Owned"; |
| M, desc="Modified", format="!b"; |
| |
| // Transient States |
| MI, desc="modified, issued PUTX, have not seen response yet"; |
| OI, desc="owned, issued PUTX, have not seen response yet"; |
| |
| IS, desc="idle, issued GETS, have not seen response yet"; |
| ISI, desc="idle, issued GETS, saw INV, have not seen data for GETS yet", format="!b"; |
| |
| IM, desc="idle, issued GETX, have not seen response yet"; |
| IMI, desc="idle, issued GETX, saw forwarded GETX"; |
| IMO, desc="idle, issued GETX, saw forwarded GETS"; |
| IMOI, desc="idle, issued GETX, saw forwarded GETS, saw forwarded GETX"; |
| |
| // Note: OM is a strange state, because it is waiting for the line |
| // to be stolen away, or look like it has been stolen away. The |
| // common case is that we see a forward from the directory that is |
| // really from us, we forwarded the data to our dataqueue, and |
| // everythings works fine. |
| |
| OM, desc="owned, issued GETX, have not seen response yet"; |
| } |
| |
| // EVENTS |
| enumeration(Event, desc="Cache events") { |
| Load, desc="Load request from the processor"; |
| Load_prefetch, desc="Load prefetch request from the processor"; |
| Ifetch, desc="I-fetch request from the processor"; |
| Store_prefetch, desc="Store prefetch request from the processor"; |
| Store, desc="Store request from the processor"; |
| Replacement, desc="Replacement", format="!r"; |
| |
| Forwarded_GETS, "Forwarded GETS", desc="Directory forwards GETS to us"; |
| Forwarded_GETX, "Forwarded GETX", desc="Directory forwards GETX to us"; |
| INV, "INV", desc="Invalidation", format="!r"; |
| |
| Proc_ack, "Proc ack", desc="Ack from proc"; |
| Proc_last_ack, "Proc last ack", desc="Last ack", format="!r"; |
| |
| Data_ack_0, "Data ack 0", desc="Data with ack count = 0"; |
| Data_ack_not_0, "Data ack not 0", desc="Data with ack count != 0 (but haven't seen all acks first"; |
| Data_ack_not_0_last, "Data ack not 0 last", desc="Data with ack count != 0 after having received all acks"; |
| |
| Dir_WB_ack, "WB ack", desc="Writeback ack from dir"; |
| } |
| |
| // 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"; |
| int NumPendingAcks, desc="Number of acks that this processor is waiting for"; |
| NetDest ForwardGetS_IDs, desc="Set of the processors to forward the block"; |
| MachineID ForwardGetX_ID, desc="ID of the processor to forward the block"; |
| int ForwardGetX_AckCount, desc="Number of acks the GetX we are forwarded needs"; |
| 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); |
| } |
| |
| MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true"; |
| MessageBuffer optionalQueue, ordered="false", abstract_chip_ptr="true"; |
| Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i"; |
| StoreBuffer storeBuffer, abstract_chip_ptr="true", constructor_hack="i"; |
| |
| TBETable TBEs, template_hack="<L1Cache_TBE>"; |
| CacheMemory cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_unified L1"', abstract_chip_ptr="true"; |
| |
| State getState(Address addr) { |
| if(TBEs.isPresent(addr)) { |
| return TBEs[addr].TBEState; |
| } else if (cacheMemory.isTagPresent(addr)) { |
| return cacheMemory[addr].CacheState; |
| } |
| return State:I; |
| } |
| |
| void setState(Address addr, State state) { |
| if (TBEs.isPresent(addr)) { |
| TBEs[addr].TBEState := state; |
| } |
| if (cacheMemory.isTagPresent(addr)) { |
| cacheMemory[addr].CacheState := state; |
| |
| // Set permission |
| if ((state == State:I) || (state == State:MI) || (state == State:OI)) { |
| cacheMemory.changePermission(addr, AccessPermission:Invalid); |
| } else if (state == State:S || state == State:O) { |
| cacheMemory.changePermission(addr, AccessPermission:Read_Only); |
| } else if (state == State:M) { |
| cacheMemory.changePermission(addr, AccessPermission:Read_Write); |
| } else { |
| cacheMemory.changePermission(addr, AccessPermission:Busy); |
| } |
| } |
| } |
| |
| // ** OUT_PORTS ** |
| |
| out_port(requestNetwork_out, RequestMsg, requestFromCache); |
| out_port(responseNetwork_out, ResponseMsg, responseFromCache); |
| |
| // ** IN_PORTS ** |
| |
| // Response Network |
| in_port(responseNetwork_in, ResponseMsg, responseToCache) { |
| if (responseNetwork_in.isReady()) { |
| peek(responseNetwork_in, ResponseMsg) { |
| if(in_msg.Type == CoherenceResponseType:DATA) { |
| if(in_msg.NumPendingAcks == 0) { |
| trigger(Event:Data_ack_0, in_msg.Address); |
| } else { |
| if(in_msg.NumPendingAcks + TBEs[in_msg.Address].NumPendingAcks != 0) { |
| trigger(Event:Data_ack_not_0, in_msg.Address); |
| } else { |
| trigger(Event:Data_ack_not_0_last, in_msg.Address); |
| } |
| } |
| } else if(in_msg.Type == CoherenceResponseType:ACK) { |
| if(TBEs[in_msg.Address].NumPendingAcks != 1){ |
| trigger(Event:Proc_ack, in_msg.Address); |
| } else { |
| trigger(Event:Proc_last_ack, in_msg.Address); |
| } |
| } |
| } |
| } |
| } |
| |
| // Forwarded Request network |
| in_port(forwardedRequestNetwork_in, RequestMsg, forwardedRequestToCache) { |
| if(forwardedRequestNetwork_in.isReady()) { |
| peek(forwardedRequestNetwork_in, RequestMsg) { |
| if(in_msg.Type == CoherenceRequestType:GETS) { |
| trigger(Event:Forwarded_GETS, in_msg.Address); |
| } else if (in_msg.Type == CoherenceRequestType:GETX) { |
| trigger(Event:Forwarded_GETX, in_msg.Address); |
| } else if (in_msg.Type == CoherenceRequestType:INV) { |
| trigger(Event:INV, in_msg.Address); |
| } else if (in_msg.Type == CoherenceRequestType:WB_ACK) { |
| trigger(Event:Dir_WB_ack, in_msg.Address); |
| } else { |
| error("Invalid forwarded request type"); |
| } |
| } |
| } |
| } |
| |
| // Mandatory Queue |
| in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") { |
| if (mandatoryQueue_in.isReady()) { |
| peek(mandatoryQueue_in, CacheMsg) { |
| if (cacheMemory.cacheAvail(in_msg.Address) == false) { |
| trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address)); |
| } else { |
| if (in_msg.Type == CacheRequestType:LD) { |
| trigger(Event:Load, in_msg.Address); |
| } else if (in_msg.Type == CacheRequestType:IFETCH) { |
| trigger(Event:Ifetch, in_msg.Address); |
| } else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) { |
| trigger(Event:Store, in_msg.Address); |
| } else { |
| error("Invalid CacheRequestType"); |
| } |
| } |
| } |
| } |
| } |
| |
| // Optional Queue |
| in_port(optionalQueue_in, CacheMsg, optionalQueue, desc="...") { |
| if (optionalQueue_in.isReady()) { |
| peek(optionalQueue_in, CacheMsg) { |
| if (cacheMemory.cacheAvail(in_msg.Address) == false) { |
| trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address)); |
| } else { |
| if (in_msg.Type == CacheRequestType:LD) { |
| trigger(Event:Load_prefetch, in_msg.Address); |
| } else if (in_msg.Type == CacheRequestType:IFETCH) { |
| trigger(Event:Load_prefetch, in_msg.Address); |
| } else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) { |
| trigger(Event:Store_prefetch, in_msg.Address); |
| } else { |
| error("Invalid CacheRequestType"); |
| } |
| } |
| } |
| } |
| } |
| |
| // ACTIONS |
| |
| action(a_issueGETS, "a", desc="Issue GETS") { |
| enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceRequestType:GETS; |
| out_msg.Requestor := machineID; |
| out_msg.Destination.add(map_Address_to_Directory(address)); |
| out_msg.MessageSize := MessageSizeType:Control; |
| } |
| } |
| |
| action(b_issueGETX, "b", desc="Issue GETX") { |
| enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceRequestType:GETX; |
| out_msg.Requestor := machineID; |
| out_msg.Destination.add(map_Address_to_Directory(address)); |
| out_msg.MessageSize := MessageSizeType:Control; |
| } |
| } |
| |
| action(d_issuePUTX, "d", desc="Issue PUTX") { |
| enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceRequestType:PUTX; |
| out_msg.Requestor := machineID; |
| out_msg.Destination.add(map_Address_to_Directory(address)); |
| out_msg.DataBlk := cacheMemory[address].DataBlk; |
| out_msg.MessageSize := MessageSizeType:Data; |
| } |
| } |
| |
| action(e_dataFromCacheToRequestor, "e", desc="Send data from cache to requestor") { |
| peek(forwardedRequestNetwork_in, RequestMsg) { |
| enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceResponseType:DATA; |
| out_msg.Sender := machineID; |
| out_msg.SenderMachine := MachineType:L1Cache; |
| out_msg.NumPendingAcks := in_msg.NumPendingAcks; // Needed when in state O and we see a GetX |
| out_msg.Destination.add(in_msg.Requestor); |
| out_msg.DestMachine := MachineType:L1Cache; |
| DEBUG_EXPR(out_msg.Destination); |
| out_msg.DataBlk := cacheMemory[address].DataBlk; |
| out_msg.MessageSize := MessageSizeType:Data; |
| } |
| } |
| } |
| |
| action(g_allocateCacheBlock, "g", desc="Allocate cache block") { |
| if (cacheMemory.isTagPresent(address) == false) { |
| cacheMemory.allocate(address); |
| } |
| } |
| |
| action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") { |
| DEBUG_EXPR(cacheMemory[address].DataBlk); |
| if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) { |
| // Non-prefetch |
| sequencer.readCallback(address, cacheMemory[address].DataBlk); |
| } else { |
| // Prefetch - don't call back |
| } |
| } |
| |
| action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") { |
| DEBUG_EXPR(cacheMemory[address].DataBlk); |
| if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) { |
| // Non-prefetch |
| sequencer.writeCallback(address, cacheMemory[address].DataBlk); |
| } else { |
| // Prefetch - don't call back |
| } |
| } |
| |
| action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") { |
| check_allocate(TBEs); |
| TBEs.allocate(address); |
| TBEs[address].NumPendingAcks := 0; // default value |
| TBEs[address].isPrefetch := false; |
| TBEs[address].ForwardGetS_IDs.clear(); |
| } |
| |
| action(j_setPrefetchBit, "j", desc="Set prefetch bit") { |
| TBEs[address].isPrefetch := true; |
| } |
| |
| action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") { |
| mandatoryQueue_in.dequeue(); |
| } |
| |
| action(l_popForwardedRequestQueue, "l", desc="Pop incoming forwarded request queue") { |
| forwardedRequestNetwork_in.dequeue(); |
| } |
| |
| action(m_popOptionalQueue, "m", desc="Pop optional queue") { |
| optionalQueue_in.dequeue(); |
| } |
| |
| action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") { |
| responseNetwork_in.dequeue(); |
| } |
| |
| action(p_addNumberOfPendingAcks, "p", desc="Add number of pending acks to TBE") { |
| peek(responseNetwork_in, ResponseMsg) { |
| DEBUG_EXPR(TBEs[address].NumPendingAcks); |
| TBEs[address].NumPendingAcks := TBEs[address].NumPendingAcks + in_msg.NumPendingAcks; |
| DEBUG_EXPR(in_msg.NumPendingAcks); |
| DEBUG_EXPR(TBEs[address].NumPendingAcks); |
| } |
| } |
| |
| action(q_decrementNumberOfPendingAcks, "q", desc="Decrement number of pending invalidations by one") { |
| DEBUG_EXPR(TBEs[address].NumPendingAcks); |
| TBEs[address].NumPendingAcks := TBEs[address].NumPendingAcks - 1; |
| DEBUG_EXPR(TBEs[address].NumPendingAcks); |
| } |
| |
| action(s_deallocateTBE, "s", desc="Deallocate TBE") { |
| TBEs.deallocate(address); |
| } |
| |
| action(t_sendAckToInvalidator, "t", desc="Send ack to invalidator") { |
| peek(forwardedRequestNetwork_in, RequestMsg) { |
| enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceResponseType:ACK; |
| out_msg.Sender := machineID; |
| out_msg.SenderMachine := MachineType:L1Cache; |
| out_msg.Destination.add(in_msg.Requestor); |
| out_msg.DestMachine := MachineType:L1Cache; |
| DEBUG_EXPR(out_msg.Destination); |
| out_msg.NumPendingAcks := 0; |
| out_msg.MessageSize := MessageSizeType:Control; |
| } |
| } |
| } |
| |
| action(u_writeDataToCache, "u", desc="Write data to cache") { |
| peek(responseNetwork_in, ResponseMsg) { |
| cacheMemory[address].DataBlk := in_msg.DataBlk; |
| } |
| } |
| |
| action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") { |
| TBEs[address].DataBlk := cacheMemory[address].DataBlk; |
| } |
| |
| action(y_dataFromTBEToRequestor, "y", desc="Send data from TBE to requestor") { |
| peek(forwardedRequestNetwork_in, RequestMsg) { |
| enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceResponseType:DATA; |
| out_msg.Sender := machineID; |
| out_msg.SenderMachine := MachineType:L1Cache; |
| out_msg.NumPendingAcks := in_msg.NumPendingAcks; // Needed when in state MS and we see a GetX |
| out_msg.Destination.add(in_msg.Requestor); |
| out_msg.DestMachine := MachineType:L1Cache; |
| DEBUG_EXPR(out_msg.Destination); |
| out_msg.DataBlk := TBEs[address].DataBlk; |
| out_msg.MessageSize := MessageSizeType:Data; |
| } |
| } |
| } |
| |
| action(z_stall, "z", desc="Stall") { |
| } |
| |
| action(dd_recordGetSForwardID, "\d", desc="Record forwarded GetS for future forwarding") { |
| peek(forwardedRequestNetwork_in, RequestMsg) { |
| TBEs[address].ForwardGetS_IDs.add(in_msg.Requestor); |
| } |
| } |
| |
| action(ee_dataFromCacheToGetSForwardIDs, "\e", desc="Send data from cache to GetS ForwardIDs") { |
| // FIXME - In some cases this should be from the TBE, not the cache. |
| enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceResponseType:DATA; |
| out_msg.Sender := machineID; |
| out_msg.SenderMachine := MachineType:L1Cache; |
| out_msg.Destination := TBEs[address].ForwardGetS_IDs; |
| out_msg.DestMachine := MachineType:L1Cache; |
| DEBUG_EXPR(out_msg.Destination); |
| out_msg.DataBlk := cacheMemory[address].DataBlk; |
| out_msg.NumPendingAcks := 0; |
| out_msg.MessageSize := MessageSizeType:Data; |
| } |
| } |
| |
| action(ff_deallocateCacheBlock, "\f", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") { |
| cacheMemory.deallocate(address); |
| } |
| |
| action(gg_dataFromCacheToGetXForwardID, "\g", desc="Send data from cache to GetX ForwardID") { |
| // FIXME - In some cases this should be from the TBE, not the cache. |
| enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") { |
| out_msg.Address := address; |
| out_msg.Type := CoherenceResponseType:DATA; |
| out_msg.Sender := machineID; |
| out_msg.SenderMachine := MachineType:L1Cache; |
| out_msg.Destination.add(TBEs[address].ForwardGetX_ID); |
| out_msg.DestMachine := MachineType:L1Cache; |
| DEBUG_EXPR(out_msg.Destination); |
| out_msg.DataBlk := cacheMemory[address].DataBlk; |
| out_msg.NumPendingAcks := TBEs[address].ForwardGetX_AckCount; |
| out_msg.MessageSize := MessageSizeType:Data; |
| } |
| } |
| |
| action(ii_recordGetXForwardID, "\i", desc="Record forwarded GetX and ack count for future forwarding") { |
| peek(forwardedRequestNetwork_in, RequestMsg) { |
| TBEs[address].ForwardGetX_ID := in_msg.Requestor; |
| TBEs[address].ForwardGetX_AckCount := in_msg.NumPendingAcks; |
| } |
| } |
| |
| //***************************************************** |
| // TRANSITIONS |
| //***************************************************** |
| |
| // Transitions for Load/Store/Prefetch/Replacement from transient states |
| transition({OM, OI, IS, ISI, IM, IMO, IMOI, IMI, MI}, {Load, Load_prefetch, Ifetch, Store, Store_prefetch, Replacement}) { |
| z_stall; |
| } |
| |
| // Transitions from Idle |
| transition(I, {Load,Ifetch}, IS) { |
| g_allocateCacheBlock; |
| i_allocateTBE; |
| a_issueGETS; |
| k_popMandatoryQueue; |
| } |
| |
| transition(I, {Load_prefetch}, IS) { |
| g_allocateCacheBlock; |
| i_allocateTBE; |
| j_setPrefetchBit; |
| a_issueGETS; |
| m_popOptionalQueue; |
| } |
| |
| transition(I, Store, IM) { |
| g_allocateCacheBlock; |
| i_allocateTBE; |
| b_issueGETX; |
| k_popMandatoryQueue; |
| } |
| |
| transition(I, Store_prefetch, IM) { |
| g_allocateCacheBlock; |
| i_allocateTBE; |
| j_setPrefetchBit; |
| b_issueGETX; |
| m_popOptionalQueue; |
| } |
| |
| transition(I, Replacement) { |
| ff_deallocateCacheBlock; |
| } |
| |
| transition(I, INV) { |
| t_sendAckToInvalidator; |
| l_popForwardedRequestQueue; |
| } |
| |
| // Transitions from Shared |
| transition({S, O}, {Load,Ifetch}) { |
| h_load_hit; |
| k_popMandatoryQueue; |
| } |
| |
| transition({S, O, M}, Load_prefetch) { |
| m_popOptionalQueue; |
| } |
| |
| transition(S, Store, IM) { |
| i_allocateTBE; |
| b_issueGETX; |
| k_popMandatoryQueue; |
| } |
| |
| transition(S, Store_prefetch, IM) { |
| i_allocateTBE; |
| j_setPrefetchBit; |
| b_issueGETX; |
| m_popOptionalQueue; |
| } |
| |
| transition(S, Replacement, I) { |
| ff_deallocateCacheBlock; |
| } |
| |
| transition(S, INV, I) { |
| t_sendAckToInvalidator; |
| l_popForwardedRequestQueue; |
| } |
| |
| // Transitions from Modified |
| transition(M, {Load, Ifetch}) { |
| h_load_hit; |
| k_popMandatoryQueue; |
| } |
| |
| transition(M, Store) { |
| hh_store_hit; |
| k_popMandatoryQueue; |
| } |
| |
| transition(M, Store_prefetch) { |
| m_popOptionalQueue; |
| } |
| |
| transition(M, Replacement, MI) { |
| i_allocateTBE; |
| d_issuePUTX; |
| x_copyDataFromCacheToTBE; |
| ff_deallocateCacheBlock; |
| } |
| |
| transition(M, Forwarded_GETS, O) { |
| e_dataFromCacheToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(M, Forwarded_GETX, I) { |
| e_dataFromCacheToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| // Transitions from O |
| transition(O, Store, OM) { |
| i_allocateTBE; |
| b_issueGETX; |
| k_popMandatoryQueue; |
| } |
| |
| transition(O, Store_prefetch, OM) { |
| i_allocateTBE; |
| j_setPrefetchBit; |
| b_issueGETX; |
| m_popOptionalQueue; |
| } |
| |
| transition(O, Replacement, OI){ |
| i_allocateTBE; |
| d_issuePUTX; |
| x_copyDataFromCacheToTBE; |
| ff_deallocateCacheBlock; |
| } |
| |
| transition(O, Forwarded_GETS) { |
| e_dataFromCacheToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(O, Forwarded_GETX, I) { |
| e_dataFromCacheToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| // transitions from OI |
| |
| transition(OI, Forwarded_GETS) { |
| y_dataFromTBEToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(OI, Forwarded_GETX) { |
| y_dataFromTBEToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(OI, Dir_WB_ack, I) { |
| s_deallocateTBE; |
| l_popForwardedRequestQueue; |
| } |
| |
| // Transitions from IS |
| |
| transition(IS, INV, ISI) { |
| t_sendAckToInvalidator; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(IS, Data_ack_0, S) { |
| u_writeDataToCache; |
| h_load_hit; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| // transitions from ISI |
| |
| // in ISI, could get data from the Proc whose GETX caused INV to go from IS to ISI |
| // or, could get data from Dir if Dir's data lost race to Dir's INV |
| // or, could get data from Dir, if my GETS took forever to get to Dir, and the GETX |
| // processor already wrote it back |
| |
| transition(ISI, Data_ack_0, I) { |
| u_writeDataToCache; |
| h_load_hit; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(ISI, INV) { |
| t_sendAckToInvalidator; |
| l_popForwardedRequestQueue; |
| } |
| |
| // Transitions from IM |
| |
| transition(IM, INV) { // do not need to go to IMI, since INV is for earlier epoch |
| t_sendAckToInvalidator; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition({IM, IMO}, Forwarded_GETS, IMO) { |
| dd_recordGetSForwardID; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(IM, Forwarded_GETX, IMI) { |
| ii_recordGetXForwardID; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(IM, {Data_ack_0, Data_ack_not_0_last}, M) { |
| u_writeDataToCache; |
| hh_store_hit; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IM, Data_ack_not_0) { |
| u_writeDataToCache; |
| p_addNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IM, Proc_ack) { |
| q_decrementNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IM, Proc_last_ack, M) { |
| hh_store_hit; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| // transitions from IMO |
| |
| transition(IMO, Forwarded_GETX, IMOI) { |
| ii_recordGetXForwardID; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(IMO, {Data_ack_0, Data_ack_not_0_last}, O) { |
| u_writeDataToCache; |
| hh_store_hit; |
| ee_dataFromCacheToGetSForwardIDs; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMO, Data_ack_not_0) { |
| u_writeDataToCache; |
| p_addNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMO, Proc_ack) { |
| q_decrementNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMO, Proc_last_ack, O) { |
| hh_store_hit; |
| ee_dataFromCacheToGetSForwardIDs; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| // transitions from IMI |
| |
| transition(IMI, {Data_ack_0, Data_ack_not_0_last}, I) { |
| u_writeDataToCache; |
| hh_store_hit; |
| gg_dataFromCacheToGetXForwardID; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMI, Data_ack_not_0) { |
| u_writeDataToCache; |
| p_addNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMI, Proc_ack) { |
| q_decrementNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMI, Proc_last_ack, I) { |
| hh_store_hit; |
| gg_dataFromCacheToGetXForwardID; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| // transitions from IMOI |
| |
| transition(IMOI, {Data_ack_0, Data_ack_not_0_last}, I) { |
| u_writeDataToCache; |
| hh_store_hit; |
| ee_dataFromCacheToGetSForwardIDs; |
| gg_dataFromCacheToGetXForwardID; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMOI, Data_ack_not_0) { |
| u_writeDataToCache; |
| p_addNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMOI, Proc_ack) { |
| q_decrementNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(IMOI, Proc_last_ack, I) { |
| hh_store_hit; |
| ee_dataFromCacheToGetSForwardIDs; |
| gg_dataFromCacheToGetXForwardID; |
| s_deallocateTBE; |
| o_popIncomingResponseQueue; |
| } |
| |
| // Transitions from OM |
| transition(OM, Proc_ack) { |
| q_decrementNumberOfPendingAcks; |
| o_popIncomingResponseQueue; |
| } |
| |
| transition(OM, Forwarded_GETS) { |
| e_dataFromCacheToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(OM, Forwarded_GETX, IM) { |
| e_dataFromCacheToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| // Transitions from MI |
| |
| transition(MI, Forwarded_GETS) { |
| y_dataFromTBEToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(MI, Forwarded_GETX) { |
| y_dataFromTBEToRequestor; |
| l_popForwardedRequestQueue; |
| } |
| |
| transition(MI, Dir_WB_ack, I) { |
| s_deallocateTBE; |
| l_popForwardedRequestQueue; |
| } |
| } |