MSI-cache.sm revision 14184
112608Sjason@lowepower.com/* 212608Sjason@lowepower.com * Copyright (c) 2017 Jason Lowe-Power 312608Sjason@lowepower.com * All rights reserved. 412608Sjason@lowepower.com * 512608Sjason@lowepower.com * Redistribution and use in source and binary forms, with or without 612608Sjason@lowepower.com * modification, are permitted provided that the following conditions are 712608Sjason@lowepower.com * met: redistributions of source code must retain the above copyright 812608Sjason@lowepower.com * notice, this list of conditions and the following disclaimer; 912608Sjason@lowepower.com * redistributions in binary form must reproduce the above copyright 1012608Sjason@lowepower.com * notice, this list of conditions and the following disclaimer in the 1112608Sjason@lowepower.com * documentation and/or other materials provided with the distribution; 1212608Sjason@lowepower.com * neither the name of the copyright holders nor the names of its 1312608Sjason@lowepower.com * contributors may be used to endorse or promote products derived from 1412608Sjason@lowepower.com * this software without specific prior written permission. 1512608Sjason@lowepower.com * 1612608Sjason@lowepower.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712608Sjason@lowepower.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812608Sjason@lowepower.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912608Sjason@lowepower.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012608Sjason@lowepower.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112608Sjason@lowepower.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212608Sjason@lowepower.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312608Sjason@lowepower.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412608Sjason@lowepower.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512608Sjason@lowepower.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612608Sjason@lowepower.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712608Sjason@lowepower.com */ 2812608Sjason@lowepower.com 2912608Sjason@lowepower.com/** 3012608Sjason@lowepower.com * This file contains a simple example MSI protocol. 3112608Sjason@lowepower.com * 3212608Sjason@lowepower.com * The protocol in this file is based off of the MSI protocol found in 3312608Sjason@lowepower.com * A Primer on Memory Consistency and Cache Coherence 3412608Sjason@lowepower.com * Daniel J. Sorin, Mark D. Hill, and David A. Wood 3512608Sjason@lowepower.com * Synthesis Lectures on Computer Architecture 2011 6:3, 141-149 3612608Sjason@lowepower.com * 3712608Sjason@lowepower.com * Table 8.1 contains the transitions and actions found in this file and 3812608Sjason@lowepower.com * section 8.2.4 explains the protocol in detail. 3912608Sjason@lowepower.com * 4012608Sjason@lowepower.com * See Learning gem5 Part 3: Ruby for more details. 4112608Sjason@lowepower.com * 4212608Sjason@lowepower.com * Authors: Jason Lowe-Power 4312608Sjason@lowepower.com */ 4412608Sjason@lowepower.com 4512608Sjason@lowepower.com/// Declare a machine with type L1Cache. 4612608Sjason@lowepower.commachine(MachineType:L1Cache, "MSI cache") 4712608Sjason@lowepower.com : Sequencer *sequencer; // Incoming request from CPU come from this 4812608Sjason@lowepower.com CacheMemory *cacheMemory; // This stores the data and cache states 4912608Sjason@lowepower.com bool send_evictions; // Needed to support O3 CPU and mwait 5012608Sjason@lowepower.com 5112608Sjason@lowepower.com // Other declarations 5212608Sjason@lowepower.com // Message buffers are required to send and receive data from the Ruby 5312608Sjason@lowepower.com // network. The from/to and request/response can be confusing! 5412608Sjason@lowepower.com // Virtual networks are needed to prevent deadlock (e.g., it is bad if a 5512608Sjason@lowepower.com // response gets stuck behind a stalled request). In this protocol, we are 5612608Sjason@lowepower.com // using three virtual networks. The highest priority is responses, 5712608Sjason@lowepower.com // followed by forwarded requests, then requests have the lowest priority. 5812608Sjason@lowepower.com 5912608Sjason@lowepower.com // Requests *to* the directory 6012608Sjason@lowepower.com MessageBuffer * requestToDir, network="To", virtual_network="0", 6112608Sjason@lowepower.com vnet_type="request"; 6212608Sjason@lowepower.com // Responses *to* the directory or other caches 6312608Sjason@lowepower.com MessageBuffer * responseToDirOrSibling, network="To", virtual_network="2", 6412608Sjason@lowepower.com vnet_type="response"; 6512608Sjason@lowepower.com 6612608Sjason@lowepower.com // Requests *from* the directory for fwds, invs, and put acks. 6712608Sjason@lowepower.com MessageBuffer * forwardFromDir, network="From", virtual_network="1", 6812608Sjason@lowepower.com vnet_type="forward"; 6912608Sjason@lowepower.com // Responses *from* directory and other caches for this cache's reqs. 7012608Sjason@lowepower.com MessageBuffer * responseFromDirOrSibling, network="From", 7112608Sjason@lowepower.com virtual_network="2", vnet_type="response"; 7212608Sjason@lowepower.com 7312608Sjason@lowepower.com // This is all of the incoming requests from the core via the sequencer 7412608Sjason@lowepower.com MessageBuffer * mandatoryQueue; 7512608Sjason@lowepower.com{ 7612608Sjason@lowepower.com // Declare the states that this cache will use. These are both stable 7712608Sjason@lowepower.com // states (no underscore) and transient states (with underscore). Letters 7812608Sjason@lowepower.com // after the underscores are superscript in Sorin et al. 7912608Sjason@lowepower.com // Underscores and "desc" are used when generating HTML tables. 8012608Sjason@lowepower.com // Access permissions are used for functional accesses. For reads, the 8112608Sjason@lowepower.com // functional access reads *all* of the blocks with a matching address that 8212608Sjason@lowepower.com // have read-only or read-write permission. For functional writes, all 8312608Sjason@lowepower.com // blocks are updated with new data if they have busy, read-only, or 8412608Sjason@lowepower.com // read-write permission. 8512608Sjason@lowepower.com state_declaration(State, desc="Cache states") { 8612608Sjason@lowepower.com I, AccessPermission:Invalid, 8712608Sjason@lowepower.com desc="Not present/Invalid"; 8812608Sjason@lowepower.com 8912608Sjason@lowepower.com // States moving out of I 9012608Sjason@lowepower.com IS_D, AccessPermission:Invalid, 9112608Sjason@lowepower.com desc="Invalid, moving to S, waiting for data"; 9212608Sjason@lowepower.com IM_AD, AccessPermission:Invalid, 9312608Sjason@lowepower.com desc="Invalid, moving to M, waiting for acks and data"; 9412608Sjason@lowepower.com IM_A, AccessPermission:Busy, 9512608Sjason@lowepower.com desc="Invalid, moving to M, waiting for acks"; 9612608Sjason@lowepower.com 9712608Sjason@lowepower.com S, AccessPermission:Read_Only, 9812608Sjason@lowepower.com desc="Shared. Read-only, other caches may have the block"; 9912608Sjason@lowepower.com 10012608Sjason@lowepower.com // States moving out of S 10112608Sjason@lowepower.com SM_AD, AccessPermission:Read_Only, 10212608Sjason@lowepower.com desc="Shared, moving to M, waiting for acks and 'data'"; 10312608Sjason@lowepower.com SM_A, AccessPermission:Read_Only, 10412608Sjason@lowepower.com desc="Shared, moving to M, waiting for acks"; 10512608Sjason@lowepower.com 10612608Sjason@lowepower.com M, AccessPermission:Read_Write, 10712608Sjason@lowepower.com desc="Modified. Read & write permissions. Owner of block"; 10812608Sjason@lowepower.com 10912608Sjason@lowepower.com // States moving to Invalid 11012608Sjason@lowepower.com MI_A, AccessPermission:Busy, 11112608Sjason@lowepower.com desc="Was modified, moving to I, waiting for put ack"; 11212608Sjason@lowepower.com SI_A, AccessPermission:Busy, 11312608Sjason@lowepower.com desc="Was shared, moving to I, waiting for put ack"; 11412608Sjason@lowepower.com II_A, AccessPermission:Invalid, 11512608Sjason@lowepower.com desc="Sent valid data before receiving put ack. "; 11612608Sjason@lowepower.com //"Waiting for put ack."; 11712608Sjason@lowepower.com } 11812608Sjason@lowepower.com 11912608Sjason@lowepower.com // Events that can be triggered on incoming messages. These are the events 12012608Sjason@lowepower.com // that will trigger transitions 12112608Sjason@lowepower.com enumeration(Event, desc="Cache events") { 12212608Sjason@lowepower.com // From the processor/sequencer/mandatory queue 12312608Sjason@lowepower.com Load, desc="Load from processor"; 12412608Sjason@lowepower.com Store, desc="Store from processor"; 12512608Sjason@lowepower.com 12612608Sjason@lowepower.com // Internal event (only triggered from processor requests) 12712608Sjason@lowepower.com Replacement, desc="Triggered when block is chosen as victim"; 12812608Sjason@lowepower.com 12912608Sjason@lowepower.com // Forwarded reqeust from other cache via dir on the forward network 13012608Sjason@lowepower.com FwdGetS, desc="Directory sent us a request to satisfy GetS. "; 13112608Sjason@lowepower.com //"We must have the block in M to respond to this."; 13212608Sjason@lowepower.com FwdGetM, desc="Directory sent us a request to satisfy GetM. "; 13312608Sjason@lowepower.com //"We must have the block in M to respond to this."; 13412608Sjason@lowepower.com Inv, desc="Invalidate from the directory."; 13512608Sjason@lowepower.com PutAck, desc="Response from directory after we issue a put. "; 13612608Sjason@lowepower.com //"This must be on the fwd network to avoid"; 13712608Sjason@lowepower.com //"deadlock."; 13812608Sjason@lowepower.com 13912608Sjason@lowepower.com // Responses from directory 14012608Sjason@lowepower.com DataDirNoAcks, desc="Data from directory (acks = 0)"; 14112608Sjason@lowepower.com DataDirAcks, desc="Data from directory (acks > 0)"; 14212608Sjason@lowepower.com 14312608Sjason@lowepower.com // Responses from other caches 14412608Sjason@lowepower.com DataOwner, desc="Data from owner"; 14512608Sjason@lowepower.com InvAck, desc="Invalidation ack from other cache after Inv"; 14612608Sjason@lowepower.com 14712608Sjason@lowepower.com // Special internally triggered event to simplify implementation 14812608Sjason@lowepower.com LastInvAck, desc="Triggered after the last ack is received"; 14912608Sjason@lowepower.com } 15012608Sjason@lowepower.com 15112608Sjason@lowepower.com // A structure for the cache entry. This stores the cache data and state 15212608Sjason@lowepower.com // as defined above. You can put any other information here you like. 15312608Sjason@lowepower.com // The AbstractCacheEntry is defined in 15412608Sjason@lowepower.com // src/mem/ruby/slic_interface/AbstractCacheEntry.hh 15512608Sjason@lowepower.com // If you want to use any of the functions in the abstract entry declare 15612608Sjason@lowepower.com // them here. 15712608Sjason@lowepower.com structure(Entry, desc="Cache entry", interface="AbstractCacheEntry") { 15812608Sjason@lowepower.com State CacheState, desc="cache state"; 15912608Sjason@lowepower.com DataBlock DataBlk, desc="Data in the block"; 16012608Sjason@lowepower.com } 16112608Sjason@lowepower.com 16212608Sjason@lowepower.com // TBE is the "transaction buffer entry". This stores information needed 16312608Sjason@lowepower.com // during transient states. This is *like* an MSHR. It functions as an MSHR 16412608Sjason@lowepower.com // in this protocol, but the entry is also allocated for other uses. 16512608Sjason@lowepower.com structure(TBE, desc="Entry for transient requests") { 16612608Sjason@lowepower.com State TBEState, desc="State of block"; 16712608Sjason@lowepower.com DataBlock DataBlk, desc="Data for the block. Needed for MI_A"; 16812608Sjason@lowepower.com int AcksOutstanding, default=0, desc="Number of acks left to receive."; 16912608Sjason@lowepower.com } 17012608Sjason@lowepower.com 17112608Sjason@lowepower.com // Table of TBE entries. This is defined externally in 17212608Sjason@lowepower.com // src/mem/ruby/structures/TBETable.hh. It is templatized on the TBE 17312608Sjason@lowepower.com // structure defined above. 17412608Sjason@lowepower.com structure(TBETable, external="yes") { 17512608Sjason@lowepower.com TBE lookup(Addr); 17612608Sjason@lowepower.com void allocate(Addr); 17712608Sjason@lowepower.com void deallocate(Addr); 17812608Sjason@lowepower.com bool isPresent(Addr); 17912608Sjason@lowepower.com } 18012608Sjason@lowepower.com 18112608Sjason@lowepower.com /*************************************************************************/ 18212608Sjason@lowepower.com // Some declarations of member functions and member variables. 18312608Sjason@lowepower.com 18412608Sjason@lowepower.com // The TBE table for this machine. It is templatized under the covers. 18512608Sjason@lowepower.com // NOTE: SLICC mangles names with the machine type. Thus, the TBE declared 18612608Sjason@lowepower.com // above will be L1Cache_TBE in C++. 18712608Sjason@lowepower.com // We also have to pass through a parameter to the machine to the TBETable. 18812608Sjason@lowepower.com TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs"; 18912608Sjason@lowepower.com 19012608Sjason@lowepower.com // Declare all of the functions of the AbstractController that we may use 19112608Sjason@lowepower.com // in this file. 19212608Sjason@lowepower.com // Functions from clocked object 19312608Sjason@lowepower.com Tick clockEdge(); 19412608Sjason@lowepower.com 19512608Sjason@lowepower.com // Functions we must use to set things up for the transitions to execute 19612608Sjason@lowepower.com // correctly. 19712608Sjason@lowepower.com // These next set/unset functions are used to populate the implicit 19812608Sjason@lowepower.com // variables used in actions. This is required when a transition has 19912608Sjason@lowepower.com // multiple actions. 20012608Sjason@lowepower.com void set_cache_entry(AbstractCacheEntry a); 20112608Sjason@lowepower.com void unset_cache_entry(); 20212608Sjason@lowepower.com void set_tbe(TBE b); 20312608Sjason@lowepower.com void unset_tbe(); 20412608Sjason@lowepower.com 20512608Sjason@lowepower.com // Given an address and machine type this queries the network to check 20612608Sjason@lowepower.com // where it should be sent. In a real implementation, this might be fixed 20712608Sjason@lowepower.com // at design time, but this function gives us flexibility at runtime. 20812608Sjason@lowepower.com // For example, if you have multiple memory channels, this function will 20912608Sjason@lowepower.com // tell you which addresses to send to which memory controller. 21012608Sjason@lowepower.com MachineID mapAddressToMachine(Addr addr, MachineType mtype); 21112608Sjason@lowepower.com 21212608Sjason@lowepower.com // Convience function to look up the cache entry. 21312608Sjason@lowepower.com // Needs a pointer so it will be a reference and can be updated in actions 21412608Sjason@lowepower.com Entry getCacheEntry(Addr address), return_by_pointer="yes" { 21512608Sjason@lowepower.com return static_cast(Entry, "pointer", cacheMemory.lookup(address)); 21612608Sjason@lowepower.com } 21712608Sjason@lowepower.com 21812608Sjason@lowepower.com /*************************************************************************/ 21912608Sjason@lowepower.com // Functions that we need to define/override to use our specific structures 22012608Sjason@lowepower.com // in this implementation. 22112608Sjason@lowepower.com 22212608Sjason@lowepower.com // Required function for getting the current state of the block. 22312608Sjason@lowepower.com // This is called from the transition to know which transition to execute 22412608Sjason@lowepower.com State getState(TBE tbe, Entry cache_entry, Addr addr) { 22512608Sjason@lowepower.com // The TBE state will override the state in cache memory, if valid 22612608Sjason@lowepower.com if (is_valid(tbe)) { return tbe.TBEState; } 22712608Sjason@lowepower.com // Next, if the cache entry is valid, it holds the state 22812608Sjason@lowepower.com else if (is_valid(cache_entry)) { return cache_entry.CacheState; } 22912608Sjason@lowepower.com // If the block isn't present, then it's state must be I. 23012608Sjason@lowepower.com else { return State:I; } 23112608Sjason@lowepower.com } 23212608Sjason@lowepower.com 23312608Sjason@lowepower.com 23412608Sjason@lowepower.com // Required function for setting the current state of the block. 23512608Sjason@lowepower.com // This is called from the transition to set the ending state. 23612608Sjason@lowepower.com // Needs to set both the TBE and the cache entry state. 23712608Sjason@lowepower.com // This is also called when transitioning to I so it's possible the TBE and/ 23812608Sjason@lowepower.com // or the cache_entry is invalid. 23912608Sjason@lowepower.com void setState(TBE tbe, Entry cache_entry, Addr addr, State state) { 24012608Sjason@lowepower.com if (is_valid(tbe)) { tbe.TBEState := state; } 24112608Sjason@lowepower.com if (is_valid(cache_entry)) { cache_entry.CacheState := state; } 24212608Sjason@lowepower.com } 24312608Sjason@lowepower.com 24412608Sjason@lowepower.com // Required function to override. Used for functional access to know where 24512608Sjason@lowepower.com // the valid data is. NOTE: L1Cache_State_to_permission is automatically 24612608Sjason@lowepower.com // created based on the access permissions in the state_declaration. 24712608Sjason@lowepower.com // This is mangled by both the MachineType and the name of the state 24812608Sjason@lowepower.com // declaration ("State" in this case) 24912608Sjason@lowepower.com AccessPermission getAccessPermission(Addr addr) { 25012608Sjason@lowepower.com TBE tbe := TBEs[addr]; 25112608Sjason@lowepower.com if(is_valid(tbe)) { 25212608Sjason@lowepower.com return L1Cache_State_to_permission(tbe.TBEState); 25312608Sjason@lowepower.com } 25412608Sjason@lowepower.com 25512608Sjason@lowepower.com Entry cache_entry := getCacheEntry(addr); 25612608Sjason@lowepower.com if(is_valid(cache_entry)) { 25712608Sjason@lowepower.com return L1Cache_State_to_permission(cache_entry.CacheState); 25812608Sjason@lowepower.com } 25912608Sjason@lowepower.com 26012608Sjason@lowepower.com return AccessPermission:NotPresent; 26112608Sjason@lowepower.com } 26212608Sjason@lowepower.com 26312608Sjason@lowepower.com // Required function to override. Like above function, but sets thte state. 26412608Sjason@lowepower.com void setAccessPermission(Entry cache_entry, Addr addr, State state) { 26512608Sjason@lowepower.com if (is_valid(cache_entry)) { 26612608Sjason@lowepower.com cache_entry.changePermission(L1Cache_State_to_permission(state)); 26712608Sjason@lowepower.com } 26812608Sjason@lowepower.com } 26912608Sjason@lowepower.com 27012608Sjason@lowepower.com // Required function to override for functionally reading/writing data. 27112608Sjason@lowepower.com // NOTE: testAndRead/Write defined in src/mem/ruby/slicc_interface/Util.hh 27212608Sjason@lowepower.com void functionalRead(Addr addr, Packet *pkt) { 27312608Sjason@lowepower.com TBE tbe := TBEs[addr]; 27412608Sjason@lowepower.com if(is_valid(tbe)) { 27512608Sjason@lowepower.com testAndRead(addr, tbe.DataBlk, pkt); 27612608Sjason@lowepower.com } else { 27712608Sjason@lowepower.com testAndRead(addr, getCacheEntry(addr).DataBlk, pkt); 27812608Sjason@lowepower.com } 27912608Sjason@lowepower.com } 28012608Sjason@lowepower.com 28112608Sjason@lowepower.com int functionalWrite(Addr addr, Packet *pkt) { 28212608Sjason@lowepower.com TBE tbe := TBEs[addr]; 28312608Sjason@lowepower.com if(is_valid(tbe)) { 28412608Sjason@lowepower.com if (testAndWrite(addr, tbe.DataBlk, pkt)) { 28512608Sjason@lowepower.com return 1; 28612608Sjason@lowepower.com } else { 28712608Sjason@lowepower.com return 0; 28812608Sjason@lowepower.com } 28912608Sjason@lowepower.com } else { 29012608Sjason@lowepower.com if (testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt)) { 29112608Sjason@lowepower.com return 1; 29212608Sjason@lowepower.com } else { 29312608Sjason@lowepower.com return 0; 29412608Sjason@lowepower.com } 29512608Sjason@lowepower.com } 29612608Sjason@lowepower.com } 29712608Sjason@lowepower.com 29812608Sjason@lowepower.com /*************************************************************************/ 29912608Sjason@lowepower.com // Input/output network definitions 30012608Sjason@lowepower.com 30112608Sjason@lowepower.com // Output ports. This defines the message types that will flow ocross the 30212608Sjason@lowepower.com // output buffers as defined above. These must be "to" networks. 30312608Sjason@lowepower.com // "request_out" is the name we'll use later to send requests. 30412608Sjason@lowepower.com // "RequestMsg" is the message type we will send (see MSI-msg.sm) 30512608Sjason@lowepower.com // "requestToDir" is the name of the MessageBuffer declared above that 30612608Sjason@lowepower.com // we are sending these requests out of. 30712608Sjason@lowepower.com out_port(request_out, RequestMsg, requestToDir); 30812608Sjason@lowepower.com out_port(response_out, ResponseMsg, responseToDirOrSibling); 30912608Sjason@lowepower.com 31012608Sjason@lowepower.com // Input ports. The order here is/(can be) important. The code in each 31112608Sjason@lowepower.com // in_port is executed in the order specified in this file (or by the rank 31212608Sjason@lowepower.com // parameter). Thus, we must sort these based on the network priority. 31312608Sjason@lowepower.com // In this cache, the order is responses from other caches, forwards, then 31412608Sjason@lowepower.com // requests from the CPU. 31512608Sjason@lowepower.com 31612608Sjason@lowepower.com // Like the out_port above 31712608Sjason@lowepower.com // "response_in" is the name we'll use later when we refer to this port 31812608Sjason@lowepower.com // "ResponseMsg" is the type of message we expect on this port 31912608Sjason@lowepower.com // "responseFromDirOrSibling" is the name of the buffer this in_port is 32012608Sjason@lowepower.com // connected to for responses from other caches and the directory. 32112608Sjason@lowepower.com in_port(response_in, ResponseMsg, responseFromDirOrSibling) { 32212608Sjason@lowepower.com // NOTE: You have to check to make sure the message buffer has a valid 32312608Sjason@lowepower.com // message at the head. The code in in_port is executed either way. 32412608Sjason@lowepower.com if (response_in.isReady(clockEdge())) { 32512608Sjason@lowepower.com // Peek is a special function. Any code inside a peek statement has 32612608Sjason@lowepower.com // a special variable declared and populated: in_msg. This contains 32712608Sjason@lowepower.com // the message (of type RequestMsg in this case) at the head. 32812608Sjason@lowepower.com // "forward_in" is the port we want to peek into 32912608Sjason@lowepower.com // "RequestMsg" is the type of message we expect. 33012608Sjason@lowepower.com peek(response_in, ResponseMsg) { 33112608Sjason@lowepower.com // Grab the entry and tbe if they exist. 33212608Sjason@lowepower.com Entry cache_entry := getCacheEntry(in_msg.addr); 33312608Sjason@lowepower.com TBE tbe := TBEs[in_msg.addr]; 33412608Sjason@lowepower.com // The TBE better exist since this is a response and we need to 33512608Sjason@lowepower.com // be able to check the remaining acks. 33612608Sjason@lowepower.com assert(is_valid(tbe)); 33712608Sjason@lowepower.com 33812608Sjason@lowepower.com // If it's from the directory... 33912608Sjason@lowepower.com if (machineIDToMachineType(in_msg.Sender) == 34012608Sjason@lowepower.com MachineType:Directory) { 34112608Sjason@lowepower.com if (in_msg.Type != CoherenceResponseType:Data) { 34212608Sjason@lowepower.com error("Directory should only reply with data"); 34312608Sjason@lowepower.com } 34412608Sjason@lowepower.com // Take the in_msg acks and add (sub) the Acks we've seen. 34512608Sjason@lowepower.com // The InvAck will decrement the acks we're waiting for in 34612608Sjason@lowepower.com // tbe.AcksOutstanding to below 0 if we haven't gotten the 34712608Sjason@lowepower.com // dir resp yet. So, if this is 0 we don't need to wait 34812608Sjason@lowepower.com assert(in_msg.Acks + tbe.AcksOutstanding >= 0); 34912608Sjason@lowepower.com if (in_msg.Acks + tbe.AcksOutstanding == 0) { 35012608Sjason@lowepower.com trigger(Event:DataDirNoAcks, in_msg.addr, cache_entry, 35112608Sjason@lowepower.com tbe); 35212608Sjason@lowepower.com } else { 35312608Sjason@lowepower.com // If it's not 0, then we need to wait for more acks 35412608Sjason@lowepower.com // and we'll trigger LastInvAck later. 35512608Sjason@lowepower.com trigger(Event:DataDirAcks, in_msg.addr, cache_entry, 35612608Sjason@lowepower.com tbe); 35712608Sjason@lowepower.com } 35812608Sjason@lowepower.com } else { 35912608Sjason@lowepower.com // This is from another cache. 36012608Sjason@lowepower.com if (in_msg.Type == CoherenceResponseType:Data) { 36112608Sjason@lowepower.com trigger(Event:DataOwner, in_msg.addr, cache_entry, 36212608Sjason@lowepower.com tbe); 36312608Sjason@lowepower.com } else if (in_msg.Type == CoherenceResponseType:InvAck) { 36412608Sjason@lowepower.com DPRINTF(RubySlicc, "Got inv ack. %d left\n", 36512608Sjason@lowepower.com tbe.AcksOutstanding); 36612608Sjason@lowepower.com if (tbe.AcksOutstanding == 1) { 36712608Sjason@lowepower.com // If there is exactly one ack remaining then we 36812608Sjason@lowepower.com // know it is the last ack. 36912608Sjason@lowepower.com trigger(Event:LastInvAck, in_msg.addr, cache_entry, 37012608Sjason@lowepower.com tbe); 37112608Sjason@lowepower.com } else { 37212608Sjason@lowepower.com trigger(Event:InvAck, in_msg.addr, cache_entry, 37312608Sjason@lowepower.com tbe); 37412608Sjason@lowepower.com } 37512608Sjason@lowepower.com } else { 37612608Sjason@lowepower.com error("Unexpected response from other cache"); 37712608Sjason@lowepower.com } 37812608Sjason@lowepower.com } 37912608Sjason@lowepower.com } 38012608Sjason@lowepower.com } 38112608Sjason@lowepower.com } 38212608Sjason@lowepower.com 38312608Sjason@lowepower.com // Forward requests for other caches. 38412608Sjason@lowepower.com in_port(forward_in, RequestMsg, forwardFromDir) { 38512608Sjason@lowepower.com if (forward_in.isReady(clockEdge())) { 38612608Sjason@lowepower.com peek(forward_in, RequestMsg) { 38712608Sjason@lowepower.com // Grab the entry and tbe if they exist. 38812608Sjason@lowepower.com Entry cache_entry := getCacheEntry(in_msg.addr); 38912608Sjason@lowepower.com TBE tbe := TBEs[in_msg.addr]; 39012608Sjason@lowepower.com 39112608Sjason@lowepower.com if (in_msg.Type == CoherenceRequestType:GetS) { 39212608Sjason@lowepower.com // This is a special function that will trigger a 39312608Sjason@lowepower.com // transition (as defined below). It *must* have these 39412608Sjason@lowepower.com // parameters. 39512608Sjason@lowepower.com trigger(Event:FwdGetS, in_msg.addr, cache_entry, tbe); 39612608Sjason@lowepower.com } else if (in_msg.Type == CoherenceRequestType:GetM) { 39712608Sjason@lowepower.com trigger(Event:FwdGetM, in_msg.addr, cache_entry, tbe); 39812608Sjason@lowepower.com } else if (in_msg.Type == CoherenceRequestType:Inv) { 39912608Sjason@lowepower.com trigger(Event:Inv, in_msg.addr, cache_entry, tbe); 40012608Sjason@lowepower.com } else if (in_msg.Type == CoherenceRequestType:PutAck) { 40112608Sjason@lowepower.com trigger(Event:PutAck, in_msg.addr, cache_entry, tbe); 40212608Sjason@lowepower.com } else { 40312608Sjason@lowepower.com error("Unexpected forward message!"); 40412608Sjason@lowepower.com } 40512608Sjason@lowepower.com } 40612608Sjason@lowepower.com } 40712608Sjason@lowepower.com } 40812608Sjason@lowepower.com 40912608Sjason@lowepower.com // The "mandatory queue" is the port/queue from the CPU or other processor. 41012608Sjason@lowepower.com // This is *always* a RubyRequest 41112608Sjason@lowepower.com in_port(mandatory_in, RubyRequest, mandatoryQueue) { 41212608Sjason@lowepower.com if (mandatory_in.isReady(clockEdge())) { 41312608Sjason@lowepower.com // Block all requests if there is already an outstanding request 41412608Sjason@lowepower.com // that has the same line address. This is unblocked when we 41512608Sjason@lowepower.com // finally respond to the request. 41612608Sjason@lowepower.com peek(mandatory_in, RubyRequest, block_on="LineAddress") { 41712608Sjason@lowepower.com // NOTE: Using LineAddress here to promote smaller requests to 41812608Sjason@lowepower.com // full cache block requests. 41912608Sjason@lowepower.com Entry cache_entry := getCacheEntry(in_msg.LineAddress); 42012608Sjason@lowepower.com TBE tbe := TBEs[in_msg.LineAddress]; 42112608Sjason@lowepower.com // If there isn't a matching entry and no room in the cache, 42212608Sjason@lowepower.com // then we need to find a victim. 42312608Sjason@lowepower.com if (is_invalid(cache_entry) && 42412608Sjason@lowepower.com cacheMemory.cacheAvail(in_msg.LineAddress) == false ) { 42512608Sjason@lowepower.com // make room for the block 42612608Sjason@lowepower.com // The "cacheProbe" function looks at the cache set for 42712608Sjason@lowepower.com // the address and queries the replacement protocol for 42812608Sjason@lowepower.com // the address to replace. It returns the address to repl. 42912608Sjason@lowepower.com Addr addr := cacheMemory.cacheProbe(in_msg.LineAddress); 43012608Sjason@lowepower.com Entry victim_entry := getCacheEntry(addr); 43112608Sjason@lowepower.com TBE victim_tbe := TBEs[addr]; 43212608Sjason@lowepower.com trigger(Event:Replacement, addr, victim_entry, victim_tbe); 43312608Sjason@lowepower.com } else { 43412608Sjason@lowepower.com if (in_msg.Type == RubyRequestType:LD || 43512608Sjason@lowepower.com in_msg.Type == RubyRequestType:IFETCH) { 43612608Sjason@lowepower.com trigger(Event:Load, in_msg.LineAddress, cache_entry, 43712608Sjason@lowepower.com tbe); 43812608Sjason@lowepower.com } else if (in_msg.Type == RubyRequestType:ST) { 43912608Sjason@lowepower.com trigger(Event:Store, in_msg.LineAddress, cache_entry, 44012608Sjason@lowepower.com tbe); 44112608Sjason@lowepower.com } else { 44212608Sjason@lowepower.com error("Unexpected type from processor"); 44312608Sjason@lowepower.com } 44412608Sjason@lowepower.com } 44512608Sjason@lowepower.com } 44612608Sjason@lowepower.com } 44712608Sjason@lowepower.com } 44812608Sjason@lowepower.com 44912608Sjason@lowepower.com 45012608Sjason@lowepower.com /*************************************************************************/ 45112608Sjason@lowepower.com // Below are all of the actions that might be taken on a transition. 45212608Sjason@lowepower.com 45312608Sjason@lowepower.com // Each actions has a name, a shorthand, and a description. 45412608Sjason@lowepower.com // The shorthand is used when generating the HTML tables for the protocol. 45512608Sjason@lowepower.com // "\" in the shorthand cause that letter to be bold. Underscores insert a 45612608Sjason@lowepower.com // space, ^ makes the rest of the letters superscript. 45712608Sjason@lowepower.com // The description is also shown in the HTML table when clicked 45812608Sjason@lowepower.com 45912608Sjason@lowepower.com // The first set of actions are things we will do to interact with the 46012608Sjason@lowepower.com // rest of the system. Things like sending requests/responses. 46112608Sjason@lowepower.com 46212608Sjason@lowepower.com // Action blocks define a number of implicit variables that are useful. 46312608Sjason@lowepower.com // These variables come straight from the trigger() call in the in_port 46412608Sjason@lowepower.com // blocks. 46512608Sjason@lowepower.com // address: The address passed in the trigger (usually the in_msg.addr, 46612608Sjason@lowepower.com // though it can be different. E.g., on a replacement it is the 46712608Sjason@lowepower.com // victim address). 46812608Sjason@lowepower.com // cache_entry: The cache entry passed in the trigger call 46912608Sjason@lowepower.com // tbe: The TBE passed in the trigger call 47012608Sjason@lowepower.com action(sendGetS, 'gS', desc="Send GetS to the directory") { 47112608Sjason@lowepower.com // The syntax for enqueue is a lot like peek. Instead of populating 47212608Sjason@lowepower.com // in_msg, enqueue has an out_msg reference. Whatever you set on out_msg 47312608Sjason@lowepower.com // is sent through the out port specified. "request_out" is the port 47412608Sjason@lowepower.com // we're sending the message out of "RequestMsg" is the type of message 47512608Sjason@lowepower.com // we're sending "1" is the latency (in cycles) the port waits before 47612608Sjason@lowepower.com // sending the message. 47712608Sjason@lowepower.com enqueue(request_out, RequestMsg, 1) { 47812608Sjason@lowepower.com out_msg.addr := address; 47912608Sjason@lowepower.com // This type is defined in MSI-msg.sm for this protocol. 48012608Sjason@lowepower.com out_msg.Type := CoherenceRequestType:GetS; 48112608Sjason@lowepower.com // The destination may change depending on the address striping 48212608Sjason@lowepower.com // across different directories, so query the network. 48312608Sjason@lowepower.com out_msg.Destination.add(mapAddressToMachine(address, 48412608Sjason@lowepower.com MachineType:Directory)); 48514184Sgabeblack@google.com // See mem/ruby/protocol/RubySlicc_Exports.sm for possible sizes. 48612608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Control; 48712608Sjason@lowepower.com // Set that the reqeustor is this machine so we get the response. 48812608Sjason@lowepower.com out_msg.Requestor := machineID; 48912608Sjason@lowepower.com } 49012608Sjason@lowepower.com } 49112608Sjason@lowepower.com 49212608Sjason@lowepower.com action(sendGetM, "gM", desc="Send GetM to the directory") { 49312608Sjason@lowepower.com enqueue(request_out, RequestMsg, 1) { 49412608Sjason@lowepower.com out_msg.addr := address; 49512608Sjason@lowepower.com out_msg.Type := CoherenceRequestType:GetM; 49612608Sjason@lowepower.com out_msg.Destination.add(mapAddressToMachine(address, 49712608Sjason@lowepower.com MachineType:Directory)); 49812608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Control; 49912608Sjason@lowepower.com out_msg.Requestor := machineID; 50012608Sjason@lowepower.com } 50112608Sjason@lowepower.com } 50212608Sjason@lowepower.com 50312608Sjason@lowepower.com // NOTE: Clean evict. Required to keep the directory state up-to-date 50412608Sjason@lowepower.com action(sendPutS, "pS", desc="Send PutS to the directory") { 50512608Sjason@lowepower.com enqueue(request_out, RequestMsg, 1) { 50612608Sjason@lowepower.com out_msg.addr := address; 50712608Sjason@lowepower.com out_msg.Type := CoherenceRequestType:PutS; 50812608Sjason@lowepower.com out_msg.Destination.add(mapAddressToMachine(address, 50912608Sjason@lowepower.com MachineType:Directory)); 51012608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Control; 51112608Sjason@lowepower.com out_msg.Requestor := machineID; 51212608Sjason@lowepower.com } 51312608Sjason@lowepower.com } 51412608Sjason@lowepower.com 51512608Sjason@lowepower.com action(sendPutM, "pM", desc="Send putM+data to the directory") { 51612608Sjason@lowepower.com enqueue(request_out, RequestMsg, 1) { 51712608Sjason@lowepower.com out_msg.addr := address; 51812608Sjason@lowepower.com out_msg.Type := CoherenceRequestType:PutM; 51912608Sjason@lowepower.com out_msg.Destination.add(mapAddressToMachine(address, 52012608Sjason@lowepower.com MachineType:Directory)); 52112608Sjason@lowepower.com out_msg.DataBlk := cache_entry.DataBlk; 52212608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Data; 52312608Sjason@lowepower.com out_msg.Requestor := machineID; 52412608Sjason@lowepower.com } 52512608Sjason@lowepower.com } 52612608Sjason@lowepower.com 52712608Sjason@lowepower.com action(sendCacheDataToReq, "cdR", desc="Send cache data to requestor") { 52812608Sjason@lowepower.com // We have to peek into the request to see who to send to. 52912608Sjason@lowepower.com // If we are in both the peek and the enqueue block then we have access 53012608Sjason@lowepower.com // to both in_msg and out_msg. 53112608Sjason@lowepower.com assert(is_valid(cache_entry)); 53212608Sjason@lowepower.com peek(forward_in, RequestMsg) { 53312608Sjason@lowepower.com enqueue(response_out, ResponseMsg, 1) { 53412608Sjason@lowepower.com out_msg.addr := address; 53512608Sjason@lowepower.com out_msg.Type := CoherenceResponseType:Data; 53612608Sjason@lowepower.com out_msg.Destination.add(in_msg.Requestor); 53712608Sjason@lowepower.com out_msg.DataBlk := cache_entry.DataBlk; 53812608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Data; 53912608Sjason@lowepower.com out_msg.Sender := machineID; 54012608Sjason@lowepower.com } 54112608Sjason@lowepower.com } 54212608Sjason@lowepower.com } 54312608Sjason@lowepower.com 54412608Sjason@lowepower.com action(sendCacheDataToDir, "cdD", desc="Send the cache data to the dir") { 54512608Sjason@lowepower.com enqueue(response_out, ResponseMsg, 1) { 54612608Sjason@lowepower.com out_msg.addr := address; 54712608Sjason@lowepower.com out_msg.Type := CoherenceResponseType:Data; 54812608Sjason@lowepower.com out_msg.Destination.add(mapAddressToMachine(address, 54912608Sjason@lowepower.com MachineType:Directory)); 55012608Sjason@lowepower.com out_msg.DataBlk := cache_entry.DataBlk; 55112608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Data; 55212608Sjason@lowepower.com out_msg.Sender := machineID; 55312608Sjason@lowepower.com } 55412608Sjason@lowepower.com } 55512608Sjason@lowepower.com 55612608Sjason@lowepower.com action(sendInvAcktoReq, "iaR", desc="Send inv-ack to requestor") { 55712608Sjason@lowepower.com peek(forward_in, RequestMsg) { 55812608Sjason@lowepower.com enqueue(response_out, ResponseMsg, 1) { 55912608Sjason@lowepower.com out_msg.addr := address; 56012608Sjason@lowepower.com out_msg.Type := CoherenceResponseType:InvAck; 56112608Sjason@lowepower.com out_msg.Destination.add(in_msg.Requestor); 56212608Sjason@lowepower.com out_msg.DataBlk := cache_entry.DataBlk; 56312608Sjason@lowepower.com out_msg.MessageSize := MessageSizeType:Control; 56412608Sjason@lowepower.com out_msg.Sender := machineID; 56512608Sjason@lowepower.com } 56612608Sjason@lowepower.com } 56712608Sjason@lowepower.com } 56812608Sjason@lowepower.com 56912608Sjason@lowepower.com action(decrAcks, "da", desc="Decrement the number of acks") { 57012608Sjason@lowepower.com assert(is_valid(tbe)); 57112608Sjason@lowepower.com tbe.AcksOutstanding := tbe.AcksOutstanding - 1; 57212608Sjason@lowepower.com // This annotates the protocol trace 57312608Sjason@lowepower.com APPEND_TRANSITION_COMMENT("Acks: "); 57412608Sjason@lowepower.com APPEND_TRANSITION_COMMENT(tbe.AcksOutstanding); 57512608Sjason@lowepower.com } 57612608Sjason@lowepower.com 57712608Sjason@lowepower.com action(storeAcks, "sa", desc="Store the needed acks to the TBE") { 57812608Sjason@lowepower.com assert(is_valid(tbe)); 57912608Sjason@lowepower.com peek(response_in, ResponseMsg) { 58012608Sjason@lowepower.com tbe.AcksOutstanding := in_msg.Acks + tbe.AcksOutstanding; 58112608Sjason@lowepower.com } 58212608Sjason@lowepower.com assert(tbe.AcksOutstanding > 0); 58312608Sjason@lowepower.com } 58412608Sjason@lowepower.com 58512608Sjason@lowepower.com // Responses to CPU requests (e.g., hits and store acks) 58612608Sjason@lowepower.com 58712608Sjason@lowepower.com action(loadHit, "Lh", desc="Load hit") { 58812608Sjason@lowepower.com assert(is_valid(cache_entry)); 58912608Sjason@lowepower.com // Set this entry as the most recently used for the replacement policy 59012608Sjason@lowepower.com cacheMemory.setMRU(cache_entry); 59112608Sjason@lowepower.com // Send the data back to the sequencer/CPU. NOTE: False means it was 59212608Sjason@lowepower.com // not an "external hit", but hit in this local cache. 59312608Sjason@lowepower.com sequencer.readCallback(address, cache_entry.DataBlk, false); 59412608Sjason@lowepower.com } 59512608Sjason@lowepower.com 59612608Sjason@lowepower.com action(externalLoadHit, "xLh", desc="External load hit (was a miss)") { 59712608Sjason@lowepower.com assert(is_valid(cache_entry)); 59812608Sjason@lowepower.com peek(response_in, ResponseMsg) { 59912608Sjason@lowepower.com cacheMemory.setMRU(cache_entry); 60012608Sjason@lowepower.com // Forward the type of machine that responded to this request 60112608Sjason@lowepower.com // E.g., another cache or the directory. This is used for tracking 60212608Sjason@lowepower.com // statistics. 60312608Sjason@lowepower.com sequencer.readCallback(address, cache_entry.DataBlk, true, 60412608Sjason@lowepower.com machineIDToMachineType(in_msg.Sender)); 60512608Sjason@lowepower.com } 60612608Sjason@lowepower.com } 60712608Sjason@lowepower.com 60812608Sjason@lowepower.com action(storeHit, "Sh", desc="Store hit") { 60912608Sjason@lowepower.com assert(is_valid(cache_entry)); 61012608Sjason@lowepower.com cacheMemory.setMRU(cache_entry); 61112608Sjason@lowepower.com // The same as the read callback above. 61212608Sjason@lowepower.com sequencer.writeCallback(address, cache_entry.DataBlk, false); 61312608Sjason@lowepower.com } 61412608Sjason@lowepower.com 61512608Sjason@lowepower.com action(externalStoreHit, "xSh", desc="External store hit (was a miss)") { 61612608Sjason@lowepower.com assert(is_valid(cache_entry)); 61712608Sjason@lowepower.com peek(response_in, ResponseMsg) { 61812608Sjason@lowepower.com cacheMemory.setMRU(cache_entry); 61912608Sjason@lowepower.com sequencer.writeCallback(address, cache_entry.DataBlk, true, 62012608Sjason@lowepower.com // Note: this could be the last ack. 62112608Sjason@lowepower.com machineIDToMachineType(in_msg.Sender)); 62212608Sjason@lowepower.com } 62312608Sjason@lowepower.com } 62412608Sjason@lowepower.com 62512608Sjason@lowepower.com action(forwardEviction, "e", desc="sends eviction notification to CPU") { 62612608Sjason@lowepower.com if (send_evictions) { 62712608Sjason@lowepower.com sequencer.evictionCallback(address); 62812608Sjason@lowepower.com } 62912608Sjason@lowepower.com } 63012608Sjason@lowepower.com 63112608Sjason@lowepower.com // Cache management actions 63212608Sjason@lowepower.com 63312608Sjason@lowepower.com action(allocateCacheBlock, "a", desc="Allocate a cache block") { 63412608Sjason@lowepower.com assert(is_invalid(cache_entry)); 63512608Sjason@lowepower.com assert(cacheMemory.cacheAvail(address)); 63612608Sjason@lowepower.com // Create a new entry and update cache_entry to the new entry 63712608Sjason@lowepower.com set_cache_entry(cacheMemory.allocate(address, new Entry)); 63812608Sjason@lowepower.com } 63912608Sjason@lowepower.com 64012608Sjason@lowepower.com action(deallocateCacheBlock, "d", desc="Deallocate a cache block") { 64112608Sjason@lowepower.com assert(is_valid(cache_entry)); 64212608Sjason@lowepower.com cacheMemory.deallocate(address); 64312608Sjason@lowepower.com // clear the cache_entry variable (now it's invalid) 64412608Sjason@lowepower.com unset_cache_entry(); 64512608Sjason@lowepower.com } 64612608Sjason@lowepower.com 64712608Sjason@lowepower.com action(writeDataToCache, "wd", desc="Write data to the cache") { 64812608Sjason@lowepower.com peek(response_in, ResponseMsg) { 64912608Sjason@lowepower.com assert(is_valid(cache_entry)); 65012608Sjason@lowepower.com cache_entry.DataBlk := in_msg.DataBlk; 65112608Sjason@lowepower.com } 65212608Sjason@lowepower.com } 65312608Sjason@lowepower.com 65412608Sjason@lowepower.com action(allocateTBE, "aT", desc="Allocate TBE") { 65512608Sjason@lowepower.com assert(is_invalid(tbe)); 65612608Sjason@lowepower.com TBEs.allocate(address); 65712608Sjason@lowepower.com // this updates the tbe variable for other actions 65812608Sjason@lowepower.com set_tbe(TBEs[address]); 65912608Sjason@lowepower.com } 66012608Sjason@lowepower.com 66112608Sjason@lowepower.com action(deallocateTBE, "dT", desc="Deallocate TBE") { 66212608Sjason@lowepower.com assert(is_valid(tbe)); 66312608Sjason@lowepower.com TBEs.deallocate(address); 66412608Sjason@lowepower.com // this makes the tbe varible invalid 66512608Sjason@lowepower.com unset_tbe(); 66612608Sjason@lowepower.com } 66712608Sjason@lowepower.com 66812608Sjason@lowepower.com // Queue management actions 66912608Sjason@lowepower.com 67012608Sjason@lowepower.com action(popMandatoryQueue, "pQ", desc="Pop the mandatory queue") { 67112608Sjason@lowepower.com mandatory_in.dequeue(clockEdge()); 67212608Sjason@lowepower.com } 67312608Sjason@lowepower.com 67412608Sjason@lowepower.com action(popResponseQueue, "pR", desc="Pop the response queue") { 67512608Sjason@lowepower.com response_in.dequeue(clockEdge()); 67612608Sjason@lowepower.com } 67712608Sjason@lowepower.com 67812608Sjason@lowepower.com action(popForwardQueue, "pF", desc="Pop the forward queue") { 67912608Sjason@lowepower.com forward_in.dequeue(clockEdge()); 68012608Sjason@lowepower.com } 68112608Sjason@lowepower.com 68212608Sjason@lowepower.com // Stalling actions 68312608Sjason@lowepower.com 68412608Sjason@lowepower.com action(stall, "z", desc="Stall the incoming request") { 68512608Sjason@lowepower.com // Do nothing. However, the transition must have some action to be 68612608Sjason@lowepower.com // valid which is why this is needed. 68712608Sjason@lowepower.com // NOTE: There are other more complicated but higher performing stalls 68812608Sjason@lowepower.com // in Ruby like recycle() or stall_and_wait. 68912608Sjason@lowepower.com // z_stall stalls everything in the queue behind this request. 69012608Sjason@lowepower.com } 69112608Sjason@lowepower.com 69212608Sjason@lowepower.com 69312608Sjason@lowepower.com /*************************************************************************/ 69412608Sjason@lowepower.com // These are the transition definition. These are simply each cell in the 69512608Sjason@lowepower.com // table from Sorin et al. These are mostly in upper-left to bottom-right 69612608Sjason@lowepower.com // order 69712608Sjason@lowepower.com 69812608Sjason@lowepower.com // Each transtiion has (up to) 3 parameters, the current state, the 69912608Sjason@lowepower.com // triggering event and the final state. Thus, the below transition reads 70012608Sjason@lowepower.com // "Move from state I on a Load event to state IS_D". Below are other 70112608Sjason@lowepower.com // examples of transition statements. 70212608Sjason@lowepower.com // Within the transition statement is a set of action to take during the 70312608Sjason@lowepower.com // transition. These actions are executed atomically (i.e., all or nothing) 70412608Sjason@lowepower.com transition(I, Load, IS_D) { 70512608Sjason@lowepower.com // Make sure there is room in the cache to put the block whenever the 70612608Sjason@lowepower.com // miss returns. Otherwise we could deadlock. 70712608Sjason@lowepower.com allocateCacheBlock; 70812608Sjason@lowepower.com // We may need to track acks for this block and only the TBE holds an 70912608Sjason@lowepower.com // ack count. Thus, we need to allocate both a TBE and cache block. 71012608Sjason@lowepower.com allocateTBE; 71112608Sjason@lowepower.com // Actually send the request to the directory 71212608Sjason@lowepower.com sendGetS; 71312608Sjason@lowepower.com // Since we have handled this request on the mandatory queue, we can pop 71412608Sjason@lowepower.com popMandatoryQueue; 71512608Sjason@lowepower.com } 71612608Sjason@lowepower.com 71712608Sjason@lowepower.com transition(I, Store, IM_AD) { 71812608Sjason@lowepower.com allocateCacheBlock; 71912608Sjason@lowepower.com allocateTBE; 72012608Sjason@lowepower.com sendGetM; 72112608Sjason@lowepower.com popMandatoryQueue; 72212608Sjason@lowepower.com } 72312608Sjason@lowepower.com 72412608Sjason@lowepower.com // You can use {} to specify multiple states or events for which the 72512608Sjason@lowepower.com // transition applies. For instance, below. If we are in IS_D, then on any 72612608Sjason@lowepower.com // of the following Events (Load, Store, Replacement, Inv) we should stall 72712608Sjason@lowepower.com // When there is no third parameter to transition, it means that we want 72812608Sjason@lowepower.com // to stay in the initial state. 72912608Sjason@lowepower.com transition(IS_D, {Load, Store, Replacement, Inv}) { 73012608Sjason@lowepower.com stall; 73112608Sjason@lowepower.com } 73212608Sjason@lowepower.com 73312608Sjason@lowepower.com // Similarly, on either DataDirNoAcks or DataOwner we should go to S 73412608Sjason@lowepower.com transition(IS_D, {DataDirNoAcks, DataOwner}, S) { 73512608Sjason@lowepower.com writeDataToCache; 73612608Sjason@lowepower.com deallocateTBE; 73712608Sjason@lowepower.com externalLoadHit; 73812608Sjason@lowepower.com popResponseQueue; 73912608Sjason@lowepower.com } 74012608Sjason@lowepower.com 74112608Sjason@lowepower.com transition({IM_AD, IM_A}, {Load, Store, Replacement, FwdGetS, FwdGetM}) { 74212608Sjason@lowepower.com stall; 74312608Sjason@lowepower.com } 74412608Sjason@lowepower.com 74512608Sjason@lowepower.com transition({IM_AD, SM_AD}, {DataDirNoAcks, DataOwner}, M) { 74612608Sjason@lowepower.com writeDataToCache; 74712608Sjason@lowepower.com deallocateTBE; 74812608Sjason@lowepower.com externalStoreHit; 74912608Sjason@lowepower.com popResponseQueue; 75012608Sjason@lowepower.com } 75112608Sjason@lowepower.com 75212608Sjason@lowepower.com transition(IM_AD, DataDirAcks, IM_A) { 75312608Sjason@lowepower.com writeDataToCache; 75412608Sjason@lowepower.com storeAcks; 75512608Sjason@lowepower.com popResponseQueue; 75612608Sjason@lowepower.com } 75712608Sjason@lowepower.com 75812608Sjason@lowepower.com transition({IM_AD, IM_A, SM_AD, SM_A}, InvAck) { 75912608Sjason@lowepower.com decrAcks; 76012608Sjason@lowepower.com popResponseQueue; 76112608Sjason@lowepower.com } 76212608Sjason@lowepower.com 76312608Sjason@lowepower.com transition({IM_A, SM_A}, LastInvAck, M) { 76412608Sjason@lowepower.com deallocateTBE; 76512608Sjason@lowepower.com externalStoreHit; 76612608Sjason@lowepower.com popResponseQueue; 76712608Sjason@lowepower.com } 76812608Sjason@lowepower.com 76912608Sjason@lowepower.com transition({S, SM_AD, SM_A, M}, Load) { 77012608Sjason@lowepower.com loadHit; 77112608Sjason@lowepower.com popMandatoryQueue; 77212608Sjason@lowepower.com } 77312608Sjason@lowepower.com 77412608Sjason@lowepower.com transition(S, Store, SM_AD) { 77512608Sjason@lowepower.com allocateTBE; 77612608Sjason@lowepower.com sendGetM; 77712608Sjason@lowepower.com popMandatoryQueue; 77812608Sjason@lowepower.com } 77912608Sjason@lowepower.com 78012608Sjason@lowepower.com transition(S, Replacement, SI_A) { 78112608Sjason@lowepower.com sendPutS; 78212608Sjason@lowepower.com } 78312608Sjason@lowepower.com 78412608Sjason@lowepower.com transition(S, Inv, I) { 78512608Sjason@lowepower.com sendInvAcktoReq; 78612608Sjason@lowepower.com forwardEviction; 78712608Sjason@lowepower.com deallocateCacheBlock; 78812608Sjason@lowepower.com popForwardQueue; 78912608Sjason@lowepower.com } 79012608Sjason@lowepower.com 79112608Sjason@lowepower.com transition({SM_AD, SM_A}, {Store, Replacement, FwdGetS, FwdGetM}) { 79212608Sjason@lowepower.com stall; 79312608Sjason@lowepower.com } 79412608Sjason@lowepower.com 79512608Sjason@lowepower.com transition(SM_AD, Inv, IM_AD) { 79612608Sjason@lowepower.com sendInvAcktoReq; 79712608Sjason@lowepower.com popForwardQueue; 79812608Sjason@lowepower.com } 79912608Sjason@lowepower.com 80012608Sjason@lowepower.com transition(SM_AD, DataDirAcks, SM_A) { 80112608Sjason@lowepower.com writeDataToCache; 80212608Sjason@lowepower.com storeAcks; 80312608Sjason@lowepower.com popResponseQueue; 80412608Sjason@lowepower.com } 80512608Sjason@lowepower.com 80612608Sjason@lowepower.com transition(M, Store) { 80712608Sjason@lowepower.com storeHit; 80812608Sjason@lowepower.com forwardEviction; 80912608Sjason@lowepower.com popMandatoryQueue; 81012608Sjason@lowepower.com } 81112608Sjason@lowepower.com 81212608Sjason@lowepower.com transition(M, Replacement, MI_A) { 81312608Sjason@lowepower.com sendPutM; 81412608Sjason@lowepower.com } 81512608Sjason@lowepower.com 81612608Sjason@lowepower.com transition(M, FwdGetS, S) { 81712608Sjason@lowepower.com sendCacheDataToReq; 81812608Sjason@lowepower.com sendCacheDataToDir; 81912608Sjason@lowepower.com popForwardQueue; 82012608Sjason@lowepower.com } 82112608Sjason@lowepower.com 82212608Sjason@lowepower.com transition(M, FwdGetM, I) { 82312608Sjason@lowepower.com sendCacheDataToReq; 82412608Sjason@lowepower.com deallocateCacheBlock; 82512608Sjason@lowepower.com popForwardQueue; 82612608Sjason@lowepower.com } 82712608Sjason@lowepower.com 82812608Sjason@lowepower.com transition({MI_A, SI_A, II_A}, {Load, Store, Replacement}) { 82912608Sjason@lowepower.com stall; 83012608Sjason@lowepower.com } 83112608Sjason@lowepower.com 83212608Sjason@lowepower.com transition(MI_A, FwdGetS, SI_A) { 83312608Sjason@lowepower.com sendCacheDataToReq; 83412608Sjason@lowepower.com sendCacheDataToDir; 83512608Sjason@lowepower.com popForwardQueue; 83612608Sjason@lowepower.com } 83712608Sjason@lowepower.com 83812608Sjason@lowepower.com transition(MI_A, FwdGetM, II_A) { 83912608Sjason@lowepower.com sendCacheDataToReq; 84012608Sjason@lowepower.com popForwardQueue; 84112608Sjason@lowepower.com } 84212608Sjason@lowepower.com 84312608Sjason@lowepower.com transition({MI_A, SI_A, II_A}, PutAck, I) { 84412608Sjason@lowepower.com deallocateCacheBlock; 84512608Sjason@lowepower.com popForwardQueue; 84612608Sjason@lowepower.com } 84712608Sjason@lowepower.com 84812608Sjason@lowepower.com transition(SI_A, Inv, II_A) { 84912608Sjason@lowepower.com sendInvAcktoReq; 85012608Sjason@lowepower.com popForwardQueue; 85112608Sjason@lowepower.com } 85212608Sjason@lowepower.com 85312608Sjason@lowepower.com} 854