summaryrefslogtreecommitdiff
path: root/src/mem/protocol/MOSI_SMP_bcast-cache.sm
diff options
context:
space:
mode:
authorNathan Binkert <nate@binkert.org>2009-05-11 10:38:43 -0700
committerNathan Binkert <nate@binkert.org>2009-05-11 10:38:43 -0700
commit2f30950143cc70bc42a3c8a4111d7cf8198ec881 (patch)
tree708f6c22edb3c6feb31dd82866c26623a5329580 /src/mem/protocol/MOSI_SMP_bcast-cache.sm
parentc70241810d4e4f523f173c1646b008dc40faad8e (diff)
downloadgem5-2f30950143cc70bc42a3c8a4111d7cf8198ec881.tar.xz
ruby: Import ruby and slicc from GEMS
We eventually plan to replace the m5 cache hierarchy with the GEMS hierarchy, but for now we will make both live alongside eachother.
Diffstat (limited to 'src/mem/protocol/MOSI_SMP_bcast-cache.sm')
-rw-r--r--src/mem/protocol/MOSI_SMP_bcast-cache.sm1000
1 files changed, 1000 insertions, 0 deletions
diff --git a/src/mem/protocol/MOSI_SMP_bcast-cache.sm b/src/mem/protocol/MOSI_SMP_bcast-cache.sm
new file mode 100644
index 000000000..6512b435a
--- /dev/null
+++ b/src/mem/protocol/MOSI_SMP_bcast-cache.sm
@@ -0,0 +1,1000 @@
+
+/*
+ * 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, "MOSI Broadcast Optimized") {
+
+ MessageBuffer addressFromCache, network="To", virtual_network="0", ordered="true";
+ MessageBuffer dataFromCache, network="To", virtual_network="1", ordered="false";
+
+ MessageBuffer addressToCache, network="From", virtual_network="0", ordered="true";
+ MessageBuffer dataToCache, network="From", virtual_network="1", ordered="false";
+
+ // STATES
+
+ enumeration(State, desc="Cache states", default="L1Cache_State_I") {
+ NP, desc="Not Present";
+ I, desc="Idle";
+ S, desc="Shared";
+ O, desc="Owned";
+ M, desc="Modified", format="!b";
+ IS_AD, "IS^AD", desc="idle, issued GETS, have not seen GETS or data yet";
+ IM_AD, "IM^AD", desc="idle, issued GETX, have not seen GETX or data yet";
+ SM_AD, "SM^AD",desc="shared, issued GETX, have not seen GETX or data yet";
+ OM_A, "OM^A",desc="owned, issued GETX, have not seen GETX yet", format="!b";
+
+ IS_A, "IS^A",desc="idle, issued GETS, have not seen GETS, have seen data";
+ IM_A, "IM^A",desc="idle, issued GETX, have not seen GETX, have seen data";
+ SM_A, "SM^A",desc="shared, issued GETX, have not seen GETX, have seen data", format="!b";
+
+ MI_A, "MI^A", desc="modified, issued PUTX, have not seen PUTX yet";
+ OI_A, "OI^A", desc="owned, issued PUTX, have not seen PUTX yet";
+ II_A, "II^A", desc="modified, issued PUTX, have not seen PUTX, then saw other GETX", format="!b";
+
+ IS_D, "IS^D", desc="idle, issued GETS, have seen GETS, have not seen data yet";
+ IS_D_I, "IS^D^I", desc="idle, issued GETS, have seen GETS, have not seen data, then saw other GETX";
+ IM_D, "IM^D", desc="idle, issued GETX, have seen GETX, have not seen data yet";
+ IM_D_O, "IM^D^O", desc="idle, issued GETX, have seen GETX, have not seen data yet, then saw other GETS";
+ IM_D_I, "IM^D^I", desc="idle, issued GETX, have seen GETX, have not seen data yet, then saw other GETX";
+ IM_D_OI, "IM^D^OI", desc="idle, issued GETX, have seen GETX, have not seen data yet, then saw other GETS, then saw other GETX";
+ SM_D, "SM^D", desc="shared, issued GETX, have seen GETX, have not seen data yet";
+ SM_D_O, "SM^D^O", desc="shared, issued GETX, have seen GETX, have not seen data yet, then saw other GETS";
+ }
+
+ // ** EVENTS **
+
+ enumeration(Event, desc="Cache events") {
+ // From processor
+ Load, desc="Load request from the processor";
+ Ifetch, desc="I-fetch request from the processor";
+ Store, desc="Store request from the processor";
+ L1_to_L2, desc="L1 to L2 transfer";
+ L2_to_L1D, desc="L2 to L1-Data transfer";
+ L2_to_L1I, desc="L2 to L1-Instruction transfer";
+ L2_Replacement, desc="L2 Replacement";
+
+ // From Address network
+ Own_GETS, desc="Occurs when we observe our own GETS request in the global order";
+ Own_GET_INSTR, desc="Occurs when we observe our own GETInstr request in the global order";
+ Own_GETX, desc="Occurs when we observe our own GETX request in the global order";
+ Own_PUTX, desc="Occurs when we observe our own PUTX request in the global order", format="!r";
+ Other_GETS, desc="Occurs when we observe a GETS request from another processor";
+ Other_GET_INSTR, desc="Occurs when we observe a GETInstr request from another processor";
+ Other_GETX, desc="Occurs when we observe a GETX request from another processor";
+ Other_PUTX, desc="Occurs when we observe a PUTX request from another processor", format="!r";
+
+ // From Data network
+ Data, desc="Data for this block from the data network";
+ }
+
+ // 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";
+ NetDest ForwardIDs, desc="IDs of the processors to forward the block";
+ Address ForwardAddress, desc="Address of request for forwarding";
+ }
+
+
+ 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 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";
+ CacheMemory L2cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L2"', abstract_chip_ptr="true";
+
+ MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
+ Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
+ StoreBuffer storeBuffer, abstract_chip_ptr="true", constructor_hack="i";
+
+ int cache_state_to_int(State state);
+
+ Entry getCacheEntry(Address addr), return_by_ref="yes" {
+ if (L2cacheMemory.isTagPresent(addr)) {
+ return L2cacheMemory[addr];
+ } else if (L1DcacheMemory.isTagPresent(addr)) {
+ return L1DcacheMemory[addr];
+ } else {
+ return L1IcacheMemory[addr];
+ }
+ }
+
+ void changePermission(Address addr, AccessPermission permission) {
+ if (L2cacheMemory.isTagPresent(addr)) {
+ return L2cacheMemory.changePermission(addr, permission);
+ } else if (L1DcacheMemory.isTagPresent(addr)) {
+ return L1DcacheMemory.changePermission(addr, permission);
+ } else {
+ return L1IcacheMemory.changePermission(addr, permission);
+ }
+ }
+
+ bool isCacheTagPresent(Address addr) {
+ return (L2cacheMemory.isTagPresent(addr) || L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
+ }
+
+ State getState(Address addr) {
+ assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
+ assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
+ assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
+
+ if(TBEs.isPresent(addr)) {
+ return TBEs[addr].TBEState;
+ } else if (isCacheTagPresent(addr)) {
+ return getCacheEntry(addr).CacheState;
+ }
+ return State:NP;
+ }
+
+ void setState(Address addr, State state) {
+ assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
+ assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
+ assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
+
+ if (TBEs.isPresent(addr)) {
+ TBEs[addr].TBEState := state;
+ }
+
+ if (isCacheTagPresent(addr)) {
+ getCacheEntry(addr).CacheState := state;
+
+ // Set permission
+ if ((state == State:I) || (state == State:MI_A) || (state == State:II_A)) {
+ changePermission(addr, AccessPermission:Invalid);
+ } else if (state == State:S || state == State:O) {
+ changePermission(addr, AccessPermission:Read_Only);
+ } else if (state == State:M) {
+ changePermission(addr, AccessPermission:Read_Write);
+ } else {
+ changePermission(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 **
+
+ out_port(dataNetwork_out, DataMsg, dataFromCache);
+ out_port(addressNetwork_out, AddressMsg, addressFromCache);
+
+ // ** IN_PORTS **
+
+ // Data Network
+ in_port(dataNetwork_in, DataMsg, dataToCache) {
+ if (dataNetwork_in.isReady()) {
+ peek(dataNetwork_in, DataMsg) {
+ trigger(Event:Data, in_msg.Address);
+ }
+ }
+ }
+
+ // Address Network
+ in_port(addressNetwork_in, AddressMsg, addressToCache) {
+ if (addressNetwork_in.isReady()) {
+ peek(addressNetwork_in, AddressMsg) {
+ if (in_msg.Type == CoherenceRequestType:GETS) {
+ if (in_msg.Requestor == machineID) {
+ trigger(Event:Own_GETS, in_msg.Address);
+ } else {
+ trigger(Event:Other_GETS, in_msg.Address);
+ }
+ } else if (in_msg.Type == CoherenceRequestType:GETX) {
+ if (in_msg.Requestor == machineID) {
+ trigger(Event:Own_GETX, in_msg.Address);
+ } else {
+ trigger(Event:Other_GETX, in_msg.Address);
+ }
+ } else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
+ if (in_msg.Requestor == machineID) {
+ trigger(Event:Own_GET_INSTR, in_msg.Address);
+ } else {
+ trigger(Event:Other_GET_INSTR, in_msg.Address);
+ }
+ } else if (in_msg.Type == CoherenceRequestType:PUTX) {
+ if (in_msg.Requestor == machineID) {
+ trigger(Event:Own_PUTX, in_msg.Address);
+ } else {
+ trigger(Event:Other_PUTX, in_msg.Address);
+ }
+ } else {
+ error("Unexpected message");
+ }
+ }
+ }
+ }
+
+ // Mandatory Queue
+ 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, try to write it to the L2
+ if (L2cacheMemory.cacheAvail(in_msg.Address)) {
+ trigger(Event:L1_to_L2, in_msg.Address);
+ } else {
+ trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
+ }
+ } else if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
+ // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ } else {
+ // not in any L1
+ if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
+ // L1 does't have the line, but we have space for it in the L1
+ if (L2cacheMemory.isTagPresent(in_msg.Address)) {
+ // L2 has it (maybe not with the right permissions)
+ trigger(Event:L2_to_L1I, in_msg.Address);
+ } else {
+ // We have room, the L2 doesn't have it, so the L1 fetches the line
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ }
+ } else {
+ // No room in the L1, so we need to make room
+ if (L2cacheMemory.cacheAvail(L1IcacheMemory.cacheProbe(in_msg.Address))) {
+ // The L2 has room, so we move the line from the L1 to the L2
+ trigger(Event:L1_to_L2, L1IcacheMemory.cacheProbe(in_msg.Address));
+ } else {
+ // The L2 does not have room, so we replace a line from the L2
+ trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(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, try to write it to the L2
+ if (L2cacheMemory.cacheAvail(in_msg.Address)) {
+ trigger(Event:L1_to_L2, in_msg.Address);
+ } else {
+ trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
+ }
+ } else if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
+ // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ } else {
+ // not in any L1
+ if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
+ // L1 does't have the line, but we have space for it in the L1
+ if (L2cacheMemory.isTagPresent(in_msg.Address)) {
+ // L2 has it (maybe not with the right permissions)
+ trigger(Event:L2_to_L1D, in_msg.Address);
+ } else {
+ // We have room, the L2 doesn't have it, so the L1 fetches the line
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
+ }
+ } else {
+ // No room in the L1, so we need to make room
+ if (L2cacheMemory.cacheAvail(L1DcacheMemory.cacheProbe(in_msg.Address))) {
+ // The L2 has room, so we move the line from the L1 to the L2
+ trigger(Event:L1_to_L2, L1DcacheMemory.cacheProbe(in_msg.Address));
+ } else {
+ // The L2 does not have room, so we replace a line from the L2
+ trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.Address)));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // ACTIONS
+ action(a_allocateTBE, "a", desc="Allocate TBE with Address=B, ForwardID=null, RetryCount=zero, ForwardIDRetryCount=zero, ForwardProgressBit=unset.") {
+ check_allocate(TBEs);
+ TBEs.allocate(address);
+ TBEs[address].ForwardIDs.clear();
+
+ // Keep the TBE state consistent with the cache state
+ if (isCacheTagPresent(address)) {
+ TBEs[address].TBEState := getCacheEntry(address).CacheState;
+ }
+ }
+
+ action(c_allocateL1DCacheBlock, "c", desc="Set L1 D-cache tag equal to tag of block B.") {
+ if (L1DcacheMemory.isTagPresent(address) == false) {
+ L1DcacheMemory.allocate(address);
+ }
+ }
+
+ action(c_allocateL1ICacheBlock, "c'", desc="Set L1 I-cache tag equal to tag of block B.") {
+ if (L1IcacheMemory.isTagPresent(address) == false) {
+ L1IcacheMemory.allocate(address);
+ }
+ }
+
+ action(cc_allocateL2CacheBlock, "\c", desc="Set L2 cache tag equal to tag of block B.") {
+ if (L2cacheMemory.isTagPresent(address) == false) {
+ L2cacheMemory.allocate(address);
+ }
+ }
+
+ action(d_deallocateTBE, "d", desc="Deallocate TBE.") {
+ TBEs.deallocate(address);
+ }
+
+ action(e_recordForwardingInfo, "e", desc="Record ID of other processor in ForwardID.") {
+ peek(addressNetwork_in, AddressMsg){
+ TBEs[address].ForwardIDs.add(in_msg.Requestor);
+ TBEs[address].ForwardAddress := in_msg.Address;
+ }
+ }
+
+ action(f_issueGETS, "f", desc="Issue GETS.") {
+ enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GETS;
+ out_msg.CacheState := cache_state_to_int(getState(address));
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Control;
+ }
+ }
+
+ action(g_issueGETX, "g", desc="Issue GETX.") {
+ enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GETX;
+ out_msg.CacheState := cache_state_to_int(getState(address));
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Control;
+ }
+ }
+
+ action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ sequencer.readCallback(address, getCacheEntry(address).DataBlk);
+ }
+
+ action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ sequencer.writeCallback(address, getCacheEntry(address).DataBlk);
+ }
+
+ action(i_popAddressQueue, "i", desc="Pop incoming address queue.") {
+ addressNetwork_in.dequeue();
+ }
+
+ action(j_popDataQueue, "j", desc="Pop incoming data queue.") {
+ dataNetwork_in.dequeue();
+ }
+
+ action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
+ mandatoryQueue_in.dequeue();
+ }
+
+ action(m_deallocateL1CacheBlock, "m", 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(mm_deallocateL2CacheBlock, "\m", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
+ L2cacheMemory.deallocate(address);
+ }
+
+ action(n_copyFromL1toL2, "n", desc="Copy data block from L1 (I or D) to L2") {
+ if (L1DcacheMemory.isTagPresent(address)) {
+ L2cacheMemory[address].DataBlk := L1DcacheMemory[address].DataBlk;
+ } else {
+ L2cacheMemory[address].DataBlk := L1IcacheMemory[address].DataBlk;
+ }
+ }
+
+ action(nn_copyFromL2toL1, "\n", desc="Copy data block from L2 to L1 (I or D)") {
+ if (L1DcacheMemory.isTagPresent(address)) {
+ L1DcacheMemory[address].DataBlk := L2cacheMemory[address].DataBlk;
+ } else {
+ L1IcacheMemory[address].DataBlk := L2cacheMemory[address].DataBlk;
+ }
+ }
+
+ action(o_cacheToForward, "o", desc="Send data from the cache to the processor indicated by ForwardIDs.") {
+ peek(dataNetwork_in, DataMsg){
+ // This has a CACHE_RESPONSE_LATENCY latency because we want to avoid the
+ // timing strangeness that can occur if requests that source the
+ // data from the TBE are faster than data sourced from the cache
+ enqueue(dataNetwork_out, DataMsg, latency="CACHE_RESPONSE_LATENCY"){
+ out_msg.Address := TBEs[address].ForwardAddress;
+ out_msg.Sender := machineID;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.Destination := TBEs[address].ForwardIDs;
+ out_msg.DestMachine := MachineType:L1Cache;
+ out_msg.MessageSize := MessageSizeType:Data;
+ }
+ }
+ }
+
+ action(p_issuePUTX, "p", desc="Issue PUTX.") {
+ enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:PUTX;
+ out_msg.CacheState := cache_state_to_int(getState(address));
+ out_msg.Requestor := machineID;
+ out_msg.Destination.add(map_Address_to_Directory(address)); // To memory
+ out_msg.Destination.add(machineID); // Back to us
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.MessageSize := MessageSizeType:Data;
+ }
+ }
+
+ action(q_writeDataFromCacheToTBE, "q", desc="Write data from the cache into the TBE.") {
+ TBEs[address].DataBlk := getCacheEntry(address).DataBlk;
+ DEBUG_EXPR(TBEs[address].DataBlk);
+ }
+
+ action(r_cacheToRequestor, "r", desc="Send data from the cache to the requestor") {
+ peek(addressNetwork_in, AddressMsg) {
+ enqueue(dataNetwork_out, DataMsg, latency="CACHE_RESPONSE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Sender := machineID;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.DestMachine := MachineType:L1Cache;
+ out_msg.DataBlk := getCacheEntry(address).DataBlk;
+ out_msg.MessageSize := MessageSizeType:Data;
+ }
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ }
+ }
+
+ action(s_saveDataInTBE, "s", desc="Save data in data field of TBE.") {
+ peek(dataNetwork_in, DataMsg) {
+ TBEs[address].DataBlk := in_msg.DataBlk;
+ DEBUG_EXPR(TBEs[address].DataBlk);
+ }
+ }
+
+ action(t_issueGET_INSTR, "t", desc="Issue GETInstr.") {
+ enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
+ out_msg.Address := address;
+ out_msg.Type := CoherenceRequestType:GET_INSTR;
+ out_msg.CacheState := cache_state_to_int(getState(address));
+ out_msg.Requestor := machineID;
+ out_msg.Destination.broadcast(MachineType:L1Cache);
+ out_msg.Destination.add(map_Address_to_Directory(address));
+ out_msg.MessageSize := MessageSizeType:Control;
+ }
+ }
+
+ action(w_writeDataFromTBEToCache, "w", desc="Write data from the TBE into the cache.") {
+ getCacheEntry(address).DataBlk := TBEs[address].DataBlk;
+ DEBUG_EXPR(getCacheEntry(address).DataBlk);
+ }
+
+ action(x_profileMiss, "x", desc="Profile the demand miss") {
+ peek(mandatoryQueue_in, CacheMsg) {
+ profile_miss(in_msg, id);
+ }
+ }
+
+ action(y_tbeToReq, "y", desc="Send data from the TBE to the requestor.") {
+ peek(addressNetwork_in, AddressMsg) {
+ enqueue(dataNetwork_out, DataMsg, latency="CACHE_RESPONSE_LATENCY") { // Either this or the PutX should have a real latency
+ out_msg.Address := address;
+ out_msg.Sender := machineID;
+ out_msg.Destination.add(in_msg.Requestor);
+ out_msg.DestMachine := MachineType:L1Cache;
+ out_msg.DataBlk := TBEs[address].DataBlk;
+ out_msg.MessageSize := MessageSizeType:Data;
+ }
+ }
+ }
+
+ // action(z_stall, "z", desc="Cannot be handled right now.") {
+ // Special name recognized as do nothing case
+ // }
+
+ action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
+ mandatoryQueue_in.recycle();
+ }
+
+ // TRANSITIONS
+
+ // Transitions from Idle
+ transition({NP, I}, Load, IS_AD) {
+ f_issueGETS;
+ c_allocateL1DCacheBlock;
+ a_allocateTBE;
+ x_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition({NP, I}, Ifetch, IS_AD) {
+ t_issueGET_INSTR;
+ c_allocateL1ICacheBlock;
+ a_allocateTBE;
+ x_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition({NP, I}, Store, IM_AD) {
+ g_issueGETX;
+ c_allocateL1DCacheBlock;
+ a_allocateTBE;
+ x_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(I, L2_Replacement) {
+ mm_deallocateL2CacheBlock;
+ }
+
+ transition({NP, I}, { Other_GETS, Other_GET_INSTR, Other_GETX } ) {
+ i_popAddressQueue;
+ }
+
+ // Transitions from Shared
+ transition(S, {Load,Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(S, Store, SM_AD) {
+ g_issueGETX;
+ a_allocateTBE;
+ x_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(S, L2_Replacement, I) {
+ mm_deallocateL2CacheBlock;
+ }
+
+ transition(S, {Other_GETS, Other_GET_INSTR}) {
+ i_popAddressQueue;
+ }
+
+ transition(S, Other_GETX, I) {
+ i_popAddressQueue;
+ }
+
+ // Transitions from Owned
+ transition(O, {Load,Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(O, Store, OM_A){
+ g_issueGETX;
+ a_allocateTBE;
+ x_profileMiss;
+ k_popMandatoryQueue;
+ }
+
+ transition(O, L2_Replacement, OI_A) {
+ p_issuePUTX;
+ a_allocateTBE;
+ q_writeDataFromCacheToTBE;// the cache line is now empty
+ mm_deallocateL2CacheBlock;
+ }
+
+ transition(O, {Other_GETS,Other_GET_INSTR}) {
+ r_cacheToRequestor;
+ i_popAddressQueue;
+ }
+
+ transition(O, Other_GETX, I) {
+ r_cacheToRequestor;
+ i_popAddressQueue;
+ }
+
+ // Transitions from Modified
+ transition(M, {Load,Ifetch}) {
+ h_load_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(M, Store) {
+ hh_store_hit;
+ k_popMandatoryQueue;
+ }
+
+ transition(M, L2_Replacement, MI_A) {
+ p_issuePUTX;
+ a_allocateTBE;
+ q_writeDataFromCacheToTBE;// the cache line is now empty
+ mm_deallocateL2CacheBlock;
+ }
+
+ transition(M, {Other_GETS,Other_GET_INSTR}, O) {
+ r_cacheToRequestor;
+ i_popAddressQueue;
+ }
+
+ transition(M, Other_GETX, I) {
+ r_cacheToRequestor;
+ i_popAddressQueue;
+ }
+
+ // Transitions moving data between the L1 and L2 caches
+
+ transition({I, S, O, M}, L1_to_L2) {
+ cc_allocateL2CacheBlock;
+ n_copyFromL1toL2; // Not really needed for state I
+ m_deallocateL1CacheBlock;
+ }
+
+ transition({I, S, O, M}, L2_to_L1D) {
+ c_allocateL1DCacheBlock;
+ nn_copyFromL2toL1; // Not really needed for state I
+ mm_deallocateL2CacheBlock;
+ }
+
+ transition({I, S, O, M}, L2_to_L1I) {
+ c_allocateL1ICacheBlock;
+ nn_copyFromL2toL1; // Not really needed for state I
+ mm_deallocateL2CacheBlock;
+ }
+
+ // Transitions for Load/Store/Replacement from transient states
+
+ transition({IS_AD, IM_AD, IS_A, IM_A, SM_AD, OM_A, SM_A, IS_D, IS_D_I, IM_D, IM_D_O, IM_D_I, IM_D_OI, SM_D, SM_D_O}, {Load, Ifetch, Store, L2_Replacement, L1_to_L2, L2_to_L1D, L2_to_L1I}) {
+ zz_recycleMandatoryQueue;
+ }
+
+ transition({MI_A, OI_A, II_A}, {Load, Ifetch, Store, L2_Replacement, L1_to_L2, L2_to_L1D, L2_to_L1I}) {
+ zz_recycleMandatoryQueue;
+ }
+
+ // Always ignore PUTXs which we are not the owner of
+ transition({NP, I, S, O, M, IS_AD, IM_AD, SM_AD, OM_A, IS_A, IM_A, SM_A, MI_A, OI_A, II_A, IS_D, IS_D_I, IM_D, IM_D_O, IM_D_I, IM_D_OI, SM_D, SM_D_O }, Other_PUTX) {
+ i_popAddressQueue;
+ }
+
+ // transitions from IS_AD
+
+ transition(IS_AD, {Own_GETS,Own_GET_INSTR}, IS_D) {
+ i_popAddressQueue;
+ }
+ transition(IS_AD, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
+ i_popAddressQueue;
+ }
+ transition(IS_AD, Data, IS_A) {
+ s_saveDataInTBE;
+ j_popDataQueue;
+ }
+
+
+ // Transitions from IM_AD
+
+ transition(IM_AD, Own_GETX, IM_D) {
+ i_popAddressQueue;
+ }
+ transition(IM_AD, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
+ i_popAddressQueue;
+ }
+ transition(IM_AD, Data, IM_A) {
+ s_saveDataInTBE;
+ j_popDataQueue;
+ }
+
+ // Transitions from OM_A
+
+ transition(OM_A, Own_GETX, M){
+ hh_store_hit;
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+
+ transition(OM_A, {Other_GETS, Other_GET_INSTR}){
+ r_cacheToRequestor;
+ i_popAddressQueue;
+ }
+
+ transition(OM_A, Other_GETX, IM_AD){
+ r_cacheToRequestor;
+ i_popAddressQueue;
+ }
+
+ transition(OM_A, Data, IM_A) { // if we get data, we know we're going to lose block before we see own GETX
+ s_saveDataInTBE;
+ j_popDataQueue;
+ }
+
+ // Transitions from SM_AD
+
+ transition(SM_AD, Own_GETX, SM_D) {
+ i_popAddressQueue;
+ }
+ transition(SM_AD, {Other_GETS,Other_GET_INSTR}) {
+ i_popAddressQueue;
+ }
+ transition(SM_AD, Other_GETX, IM_AD) {
+ i_popAddressQueue;
+ }
+ transition(SM_AD, Data, SM_A) {
+ s_saveDataInTBE;
+ j_popDataQueue;
+ }
+
+
+ // Transitions from IS_A
+
+ transition(IS_A, {Own_GETS,Own_GET_INSTR}, S) {
+ w_writeDataFromTBEToCache;
+ h_load_hit;
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+ transition(IS_A, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
+ i_popAddressQueue;
+ }
+
+ // Transitions from IM_A
+
+ transition(IM_A, Own_GETX, M) {
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+ transition(IM_A, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
+ i_popAddressQueue;
+ }
+
+ // Transitions from SM_A
+
+ transition(SM_A, Own_GETX, M) {
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+ transition(SM_A, {Other_GETS,Other_GET_INSTR}) {
+ i_popAddressQueue;
+ }
+ transition(SM_A, Other_GETX, IM_A) {
+ i_popAddressQueue;
+ }
+
+
+ // Transitions from MI_A
+
+ transition(MI_A, Own_PUTX, I) {
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+
+ transition(MI_A, {Other_GETS, Other_GET_INSTR}) {
+ y_tbeToReq;
+ i_popAddressQueue;
+ }
+
+ transition(MI_A, Other_GETX, II_A) {
+ y_tbeToReq;
+ i_popAddressQueue;
+ }
+
+ // Transitions from OI_A
+
+ transition(OI_A, Own_PUTX, I) {
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+
+ transition(OI_A, {Other_GETS, Other_GET_INSTR}) {
+ y_tbeToReq;
+ i_popAddressQueue;
+ }
+
+ transition(OI_A, Other_GETX, II_A) {
+ y_tbeToReq;
+ i_popAddressQueue;
+ }
+
+
+ // Transitions from II_A
+
+ transition(II_A, Own_PUTX, I) {
+ d_deallocateTBE;
+ i_popAddressQueue;
+ }
+
+ transition(II_A, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
+ i_popAddressQueue;
+ }
+
+ // Transitions from IS_D, IS_D_I
+
+ transition({IS_D, IS_D_I}, {Other_GETS,Other_GET_INSTR}) {
+ i_popAddressQueue;
+ }
+ transition(IS_D, Other_GETX, IS_D_I) {
+ i_popAddressQueue;
+ }
+ transition(IS_D_I, Other_GETX) {
+ i_popAddressQueue;
+ }
+ transition(IS_D, Data, S) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ h_load_hit;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ transition(IS_D_I, Data, I) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ h_load_hit;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ // Transitions from IM_D, IM_D_O, IM_D_I, IM_D_OI
+
+ transition( IM_D, {Other_GETS,Other_GET_INSTR}, IM_D_O ) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition( IM_D, Other_GETX, IM_D_I ) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition(IM_D_O, {Other_GETS,Other_GET_INSTR} ) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition(IM_D_O, Other_GETX, IM_D_OI) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition( {IM_D_I, IM_D_OI}, {Other_GETS, Other_GET_INSTR, Other_GETX} ) {
+ i_popAddressQueue;
+ }
+
+ transition(IM_D, Data, M) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ transition(IM_D_O, Data, O) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ o_cacheToForward;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ transition(IM_D_I, Data, I) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ o_cacheToForward;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ transition(IM_D_OI, Data, I) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ o_cacheToForward;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ // Transitions for SM_D, SM_D_O
+
+ transition(SM_D, {Other_GETS,Other_GET_INSTR}, SM_D_O) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition(SM_D, Other_GETX, IM_D_I) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition(SM_D_O, {Other_GETS,Other_GET_INSTR}) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition(SM_D_O, Other_GETX, IM_D_OI) {
+ e_recordForwardingInfo;
+ i_popAddressQueue;
+ }
+
+ transition(SM_D, Data, M) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+
+ transition(SM_D_O, Data, O) {
+ s_saveDataInTBE;
+ w_writeDataFromTBEToCache;
+ hh_store_hit;
+ o_cacheToForward;
+ d_deallocateTBE;
+ j_popDataQueue;
+ }
+}