MOESI_CMP_token-L1cache.sm revision 14184:11ac1337c5e2
1/*
2 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * $Id: MOESI_CMP_token-L1cache.sm 1.22 05/01/19 15:55:39-06:00 beckmann@s0-28.cs.wisc.edu $
31 *
32 */
33
34machine(MachineType:L1Cache, "Token protocol")
35 : Sequencer * sequencer;
36   CacheMemory * L1Icache;
37   CacheMemory * L1Dcache;
38   int l2_select_num_bits;
39   int N_tokens;
40
41   Cycles l1_request_latency := 2;
42   Cycles l1_response_latency := 2;
43   int retry_threshold := 1;
44   Cycles fixed_timeout_latency := 100;
45   Cycles reissue_wakeup_latency := 10;
46   Cycles use_timeout_latency := 50;
47
48   bool dynamic_timeout_enabled := "True";
49   bool no_mig_atomic := "True";
50   bool send_evictions;
51
52   // Message Queues
53   // From this node's L1 cache TO the network
54 
55   // a local L1 -> this L2 bank
56   MessageBuffer * responseFromL1Cache, network="To", virtual_network="4",
57        vnet_type="response";
58   MessageBuffer * persistentFromL1Cache, network="To", virtual_network="3",
59        vnet_type="persistent";
60   // a local L1 -> this L2 bank, currently ordered with directory forwarded requests
61   MessageBuffer * requestFromL1Cache, network="To", virtual_network="1",
62        vnet_type="request";
63 
64   // To this node's L1 cache FROM the network
65
66   // a L2 bank -> this L1
67   MessageBuffer * responseToL1Cache, network="From", virtual_network="4",
68        vnet_type="response";
69   MessageBuffer * persistentToL1Cache, network="From", virtual_network="3",
70        vnet_type="persistent";
71   // a L2 bank -> this L1
72   MessageBuffer * requestToL1Cache, network="From", virtual_network="1",
73        vnet_type="request";
74
75   MessageBuffer * mandatoryQueue;
76{
77  // STATES
78  state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
79    // Base states
80    NP, AccessPermission:Invalid, "NP", desc="Not Present";
81    I, AccessPermission:Invalid, "I", desc="Idle";
82    S, AccessPermission:Read_Only, "S", desc="Shared";
83    O, AccessPermission:Read_Only, "O", desc="Owned";
84    M, AccessPermission:Read_Only, "M", desc="Modified (dirty)";
85    MM, AccessPermission:Read_Write, "MM", desc="Modified (dirty and locally modified)";
86    M_W, AccessPermission:Read_Only, "M^W", desc="Modified (dirty), waiting";
87    MM_W, AccessPermission:Read_Write, "MM^W", desc="Modified (dirty and locally modified), waiting";
88
89    // Transient States
90    IM, AccessPermission:Busy, "IM", desc="Issued GetX";
91    SM, AccessPermission:Read_Only, "SM", desc="Issued GetX, we still have an old copy of the line";
92    OM, AccessPermission:Read_Only, "OM", desc="Issued GetX, received data";
93    IS, AccessPermission:Busy, "IS", desc="Issued GetS";
94
95    // Locked states
96    I_L, AccessPermission:Busy, "I^L", desc="Invalid, Locked";
97    S_L, AccessPermission:Busy, "S^L", desc="Shared, Locked";
98    IM_L, AccessPermission:Busy, "IM^L", desc="Invalid, Locked, trying to go to Modified";
99    SM_L, AccessPermission:Busy, "SM^L", desc="Shared, Locked, trying to go to Modified";
100    IS_L, AccessPermission:Busy, "IS^L", desc="Invalid, Locked, trying to go to Shared";
101  }
102
103  // EVENTS
104  enumeration(Event, desc="Cache events") {
105    Load,            desc="Load request from the processor";
106    Ifetch,          desc="I-fetch request from the processor";
107    Store,           desc="Store request from the processor";
108    Atomic,          desc="Atomic request from the processor";
109    L1_Replacement,  desc="L1 Replacement";
110
111    // Responses
112    Data_Shared,             desc="Received a data message, we are now a sharer";
113    Data_Owner,              desc="Received a data message, we are now the owner";
114    Data_All_Tokens,   desc="Received a data message, we are now the owner, we now have all the tokens";
115    Ack,                     desc="Received an ack message";
116    Ack_All_Tokens,          desc="Received an ack message, we now have all the tokens";
117
118    // Requests
119    Transient_GETX,  desc="A GetX from another processor";
120    Transient_Local_GETX,  desc="A GetX from another processor";
121    Transient_GETS,  desc="A GetS from another processor";
122    Transient_Local_GETS,  desc="A GetS from another processor";
123    Transient_GETS_Last_Token,  desc="A GetS from another processor";
124    Transient_Local_GETS_Last_Token,  desc="A GetS from another processor";
125
126    // Lock/Unlock for distributed
127    Persistent_GETX,     desc="Another processor has priority to read/write";
128    Persistent_GETS,     desc="Another processor has priority to read";
129    Persistent_GETS_Last_Token, desc="Another processor has priority to read, no more tokens";
130    Own_Lock_or_Unlock,  desc="This processor now has priority";
131
132    // Triggers
133    Request_Timeout,         desc="Timeout";
134    Use_TimeoutStarverX,             desc="Timeout";
135    Use_TimeoutStarverS,             desc="Timeout";
136    Use_TimeoutNoStarvers,             desc="Timeout";
137    Use_TimeoutNoStarvers_NoMig,     desc="Timeout Don't Migrate";
138  }
139
140  // TYPES
141
142  // CacheEntry
143  structure(Entry, desc="...", interface="AbstractCacheEntry") {
144    State CacheState,        desc="cache state";
145    bool Dirty,              desc="Is the data dirty (different than memory)?";
146    int Tokens,              desc="The number of tokens we're holding for the line";
147    DataBlock DataBlk,       desc="data for the block";
148  }
149
150
151  // TBE fields
152  structure(TBE, desc="...") {
153    Addr addr,                      desc="Physical address for this TBE";
154    State TBEState,                       desc="Transient state";
155    int IssueCount,      default="0",     desc="The number of times we've issued a request for this line.";
156    Addr PC,                           desc="Program counter of request";
157
158    bool WentPersistent, default="false",  desc="Request went persistent";
159    bool ExternalResponse, default="false", desc="Response came from an external controller";
160    bool IsAtomic, default="false",       desc="Request was an atomic request";
161
162    AccessType TypeOfAccess,                desc="Type of request (used for profiling)";
163    Cycles IssueTime,                       desc="Time the request was issued";
164    RubyAccessMode AccessMode,    desc="user/supervisor access type";
165    PrefetchBit Prefetch,         desc="Is this a prefetch request";
166  }
167
168  structure(TBETable, external="yes") {
169    TBE lookup(Addr);
170    void allocate(Addr);
171    void deallocate(Addr);
172    bool isPresent(Addr);
173  }
174
175  structure(PersistentTable, external="yes") {
176    void persistentRequestLock(Addr, MachineID, AccessType);
177    void persistentRequestUnlock(Addr, MachineID);
178    bool okToIssueStarving(Addr, MachineID);
179    MachineID findSmallest(Addr);
180    AccessType typeOfSmallest(Addr);
181    void markEntries(Addr);
182    bool isLocked(Addr);
183    int countStarvingForAddress(Addr);
184    int countReadStarvingForAddress(Addr);
185  }
186
187  Tick clockEdge();
188  Tick cyclesToTicks(Cycles c);
189  void set_cache_entry(AbstractCacheEntry b);
190  void unset_cache_entry();
191  void set_tbe(TBE b);
192  void unset_tbe();
193  void wakeUpAllBuffers();
194  void wakeUpBuffers(Addr a);
195  Cycles curCycle();
196  MachineID mapAddressToMachine(Addr addr, MachineType mtype);
197
198  TBETable L1_TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
199
200  bool starving, default="false";
201  int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
202
203  PersistentTable persistentTable;
204  TimerTable useTimerTable;
205  TimerTable reissueTimerTable;
206
207  int outstandingRequests, default="0";
208  int outstandingPersistentRequests, default="0";
209
210  // Constant that provides hysteresis for calculated the estimated average
211  int averageLatencyHysteresis, default="(8)";
212  Cycles averageLatencyCounter,
213        default="(Cycles(500) << (*m_averageLatencyHysteresis_ptr))";
214
215  Cycles averageLatencyEstimate() {
216    DPRINTF(RubySlicc, "%d\n",
217            (averageLatencyCounter >> averageLatencyHysteresis));
218    return averageLatencyCounter >> averageLatencyHysteresis;
219  }
220
221  void updateAverageLatencyEstimate(Cycles latency) {
222    DPRINTF(RubySlicc, "%d\n", latency);
223
224    // By subtracting the current average and then adding the most
225    // recent sample, we calculate an estimate of the recent average.
226    // If we simply used a running sum and divided by the total number
227    // of entries, the estimate of the average would adapt very slowly
228    // after the execution has run for a long time.
229    // averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency;
230
231    averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency;
232  }
233
234  Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
235    Entry L1Dcache_entry := static_cast(Entry, "pointer", L1Dcache.lookup(addr));
236    if(is_valid(L1Dcache_entry)) {
237      return L1Dcache_entry;
238    }
239
240    Entry L1Icache_entry := static_cast(Entry, "pointer", L1Icache.lookup(addr));
241    return L1Icache_entry;
242  }
243
244  void functionalRead(Addr addr, Packet *pkt) {
245    testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
246  }
247
248  int functionalWrite(Addr addr, Packet *pkt) {
249    int num_functional_writes := 0;
250    num_functional_writes := num_functional_writes +
251        testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
252    return num_functional_writes;
253  }
254
255  Entry getL1DCacheEntry(Addr addr), return_by_pointer="yes" {
256    Entry L1Dcache_entry := static_cast(Entry, "pointer", L1Dcache.lookup(addr));
257    return L1Dcache_entry;
258  }
259
260  Entry getL1ICacheEntry(Addr addr), return_by_pointer="yes" {
261    Entry L1Icache_entry := static_cast(Entry, "pointer", L1Icache.lookup(addr));
262    return L1Icache_entry;
263  }
264
265  int getTokens(Entry cache_entry) {
266    if (is_valid(cache_entry)) {
267      return cache_entry.Tokens;
268    }
269    return 0;
270  }
271
272  State getState(TBE tbe, Entry cache_entry, Addr addr) {
273
274    if (is_valid(tbe)) {
275      return tbe.TBEState;
276    } else if (is_valid(cache_entry)) {
277      return cache_entry.CacheState;
278    } else {
279      if (persistentTable.isLocked(addr) && (persistentTable.findSmallest(addr) != machineID)) {
280      // Not in cache, in persistent table, but this processor isn't highest priority
281      return State:I_L;
282      } else {
283        return State:NP;
284      }
285    }
286  }
287
288  void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
289    assert((L1Dcache.isTagPresent(addr) && L1Icache.isTagPresent(addr)) == false);
290
291    if (is_valid(tbe)) {
292      assert(state != State:I);
293      assert(state != State:S);
294      assert(state != State:O);
295      assert(state != State:MM);
296      assert(state != State:M);
297      tbe.TBEState := state;
298    }
299
300    if (is_valid(cache_entry)) {
301      // Make sure the token count is in range
302      assert(cache_entry.Tokens >= 0);
303      assert(cache_entry.Tokens <= max_tokens());
304      assert(cache_entry.Tokens != (max_tokens() / 2));
305
306      if ((state == State:I_L) ||
307          (state == State:IM_L) ||
308          (state == State:IS_L)) {
309        // Make sure we have no tokens in the "Invalid, locked" states
310          assert(cache_entry.Tokens == 0);
311
312        // Make sure the line is locked
313        // assert(persistentTable.isLocked(addr));
314
315        // But we shouldn't have highest priority for it
316        // assert(persistentTable.findSmallest(addr) != id);
317
318      } else if ((state == State:S_L) ||
319                 (state == State:SM_L)) {
320        assert(cache_entry.Tokens >= 1);
321        assert(cache_entry.Tokens < (max_tokens() / 2));
322
323        // Make sure the line is locked...
324        // assert(persistentTable.isLocked(addr));
325
326        // ...But we shouldn't have highest priority for it...
327        // assert(persistentTable.findSmallest(addr) != id);
328
329        // ...And it must be a GETS request
330        // assert(persistentTable.typeOfSmallest(addr) == AccessType:Read);
331
332      } else {
333
334        // If there is an entry in the persistent table of this block,
335        // this processor needs to have an entry in the table for this
336        // block, and that entry better be the smallest (highest
337        // priority).  Otherwise, the state should have been one of
338        // locked states
339
340        //if (persistentTable.isLocked(addr)) {
341        //  assert(persistentTable.findSmallest(addr) == id);
342        //}
343      }
344
345      // in M and E you have all the tokens
346      if (state == State:MM || state == State:M || state == State:MM_W || state == State:M_W) {
347        assert(cache_entry.Tokens == max_tokens());
348      }
349
350      // in NP you have no tokens
351      if (state == State:NP) {
352        assert(cache_entry.Tokens == 0);
353      }
354
355      // You have at least one token in S-like states
356      if (state == State:S || state == State:SM) {
357        assert(cache_entry.Tokens > 0);
358      }
359
360      // You have at least half the token in O-like states
361      if (state == State:O && state == State:OM) {
362        assert(cache_entry.Tokens > (max_tokens() / 2));
363      }
364
365      cache_entry.CacheState := state;
366    }
367  }
368
369  AccessPermission getAccessPermission(Addr addr) {
370    TBE tbe := L1_TBEs[addr];
371    if(is_valid(tbe)) {
372      return L1Cache_State_to_permission(tbe.TBEState);
373    }
374
375    Entry cache_entry := getCacheEntry(addr);
376    if(is_valid(cache_entry)) {
377      return L1Cache_State_to_permission(cache_entry.CacheState);
378    }
379
380    return AccessPermission:NotPresent;
381  }
382
383  void setAccessPermission(Entry cache_entry, Addr addr, State state) {
384    if (is_valid(cache_entry)) {
385      cache_entry.changePermission(L1Cache_State_to_permission(state));
386    }
387  }
388
389  Event mandatory_request_type_to_event(RubyRequestType type) {
390    if (type == RubyRequestType:LD) {
391      return Event:Load;
392    } else if (type == RubyRequestType:IFETCH) {
393      return Event:Ifetch;
394    } else if (type == RubyRequestType:ST) {
395      return Event:Store;
396    } else if (type == RubyRequestType:ATOMIC) {
397      if (no_mig_atomic) {
398        return Event:Atomic;
399      } else {
400        return Event:Store;
401      }
402    } else {
403      error("Invalid RubyRequestType");
404    }
405  }
406
407  AccessType cache_request_type_to_access_type(RubyRequestType type) {
408    if ((type == RubyRequestType:LD) || (type == RubyRequestType:IFETCH)) {
409      return AccessType:Read;
410    } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
411      return AccessType:Write;
412    } else {
413      error("Invalid RubyRequestType");
414    }
415  }
416
417  // NOTE: direct local hits should not call this function
418  bool isExternalHit(Addr addr, MachineID sender) {
419    if (machineIDToMachineType(sender) == MachineType:L1Cache) {
420      return true;
421    } else if (machineIDToMachineType(sender) == MachineType:L2Cache) {
422
423      if (sender == mapAddressToRange(addr, MachineType:L2Cache,
424                      l2_select_low_bit, l2_select_num_bits, intToID(0))) {
425        return false;
426      } else {
427        return  true;
428      }
429    }
430
431    return true;
432  }
433
434  bool okToIssueStarving(Addr addr, MachineID machineID) {
435    return persistentTable.okToIssueStarving(addr, machineID);
436  }
437
438  void markPersistentEntries(Addr addr) {
439    persistentTable.markEntries(addr);
440  }
441
442  void setExternalResponse(TBE tbe) {
443    assert(is_valid(tbe));
444    tbe.ExternalResponse := true;
445  }
446
447  bool IsAtomic(TBE tbe) {
448    assert(is_valid(tbe));
449    return tbe.IsAtomic;
450  }
451
452  // ** OUT_PORTS **
453  out_port(persistentNetwork_out, PersistentMsg, persistentFromL1Cache);
454  out_port(requestNetwork_out, RequestMsg, requestFromL1Cache);
455  out_port(responseNetwork_out, ResponseMsg, responseFromL1Cache);
456  out_port(requestRecycle_out, RequestMsg, requestToL1Cache);
457
458  // ** IN_PORTS **
459
460  // Use Timer
461  in_port(useTimerTable_in, Addr, useTimerTable, rank=5) {
462    if (useTimerTable_in.isReady(clockEdge())) {
463      Addr readyAddress := useTimerTable.nextAddress();
464      TBE tbe := L1_TBEs.lookup(readyAddress);
465
466      if (persistentTable.isLocked(readyAddress) &&
467          (persistentTable.findSmallest(readyAddress) != machineID)) {
468        if (persistentTable.typeOfSmallest(readyAddress) == AccessType:Write) {
469          trigger(Event:Use_TimeoutStarverX, readyAddress,
470                  getCacheEntry(readyAddress), tbe);
471        } else {
472          trigger(Event:Use_TimeoutStarverS, readyAddress,
473                  getCacheEntry(readyAddress), tbe);
474        }
475      } else {
476        if (no_mig_atomic && IsAtomic(tbe)) {
477          trigger(Event:Use_TimeoutNoStarvers_NoMig, readyAddress,
478                  getCacheEntry(readyAddress), tbe);
479        } else {
480          trigger(Event:Use_TimeoutNoStarvers, readyAddress,
481                  getCacheEntry(readyAddress), tbe);
482        }
483      }
484    }
485  }
486
487  // Reissue Timer
488  in_port(reissueTimerTable_in, Addr, reissueTimerTable, rank=4) {
489    Tick current_time := clockEdge();
490    if (reissueTimerTable_in.isReady(current_time)) {
491      Addr addr := reissueTimerTable.nextAddress();
492      trigger(Event:Request_Timeout, addr, getCacheEntry(addr),
493              L1_TBEs.lookup(addr));
494    }
495  }
496
497  // Persistent Network
498  in_port(persistentNetwork_in, PersistentMsg, persistentToL1Cache, rank=3) {
499    if (persistentNetwork_in.isReady(clockEdge())) {
500      peek(persistentNetwork_in, PersistentMsg, block_on="addr") {
501        assert(in_msg.Destination.isElement(machineID));
502
503        // Apply the lockdown or unlockdown message to the table
504        if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
505          persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Write);
506        } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
507          persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Read);
508        } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
509          persistentTable.persistentRequestUnlock(in_msg.addr, in_msg.Requestor);
510        } else {
511          error("Unexpected message");
512        }
513
514        // React to the message based on the current state of the table
515        Entry cache_entry := getCacheEntry(in_msg.addr);
516        TBE tbe := L1_TBEs[in_msg.addr];
517
518        if (persistentTable.isLocked(in_msg.addr)) {
519          if (persistentTable.findSmallest(in_msg.addr) == machineID) {
520            // Our Own Lock - this processor is highest priority
521            trigger(Event:Own_Lock_or_Unlock, in_msg.addr,
522                    cache_entry, tbe);
523          } else {
524            if (persistentTable.typeOfSmallest(in_msg.addr) == AccessType:Read) {
525              if (getTokens(cache_entry) == 1 ||
526                  getTokens(cache_entry) == (max_tokens() / 2) + 1) {
527                trigger(Event:Persistent_GETS_Last_Token, in_msg.addr,
528                        cache_entry, tbe);
529              } else {
530                trigger(Event:Persistent_GETS, in_msg.addr,
531                        cache_entry, tbe);
532              }
533            } else {
534              trigger(Event:Persistent_GETX, in_msg.addr,
535                      cache_entry, tbe);
536            }
537          }
538        } else {
539          // Unlock case - no entries in the table
540          trigger(Event:Own_Lock_or_Unlock, in_msg.addr,
541                  cache_entry, tbe);
542        }
543      }
544    }
545  }
546
547  // Response Network
548  in_port(responseNetwork_in, ResponseMsg, responseToL1Cache, rank=2) {
549    if (responseNetwork_in.isReady(clockEdge())) {
550      peek(responseNetwork_in, ResponseMsg, block_on="addr") {
551        assert(in_msg.Destination.isElement(machineID));
552
553        Entry cache_entry := getCacheEntry(in_msg.addr);
554        TBE tbe := L1_TBEs[in_msg.addr];
555
556        // Mark TBE flag if response received off-chip.  Use this to update average latency estimate
557        if ( machineIDToMachineType(in_msg.Sender) == MachineType:L2Cache ) {
558
559          if (in_msg.Sender == mapAddressToRange(in_msg.addr,
560                                 MachineType:L2Cache, l2_select_low_bit,
561                                 l2_select_num_bits, intToID(0))) {
562
563            // came from an off-chip L2 cache
564            if (is_valid(tbe)) {
565               // L1_TBEs[in_msg.addr].ExternalResponse := true;
566               // profile_offchipL2_response(in_msg.addr);
567            }
568          }
569          else {
570               // profile_onchipL2_response(in_msg.addr );
571          }
572        } else if ( machineIDToMachineType(in_msg.Sender) == MachineType:Directory ) {
573          if (is_valid(tbe)) {
574            setExternalResponse(tbe);
575            // profile_memory_response( in_msg.addr);
576          }
577        } else if ( machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
578          //if (isLocalProcessor(machineID, in_msg.Sender) == false) {
579            //if (is_valid(tbe)) {
580               // tbe.ExternalResponse := true;
581               // profile_offchipL1_response(in_msg.addr );
582            //}
583          //}
584          //else {
585               // profile_onchipL1_response(in_msg.addr );
586          //}
587        } else {
588          error("unexpected SenderMachine");
589        }
590
591
592        if (getTokens(cache_entry) + in_msg.Tokens != max_tokens()) {
593          if (in_msg.Type == CoherenceResponseType:ACK) {
594            assert(in_msg.Tokens < (max_tokens() / 2));
595            trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
596          } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
597            trigger(Event:Data_Owner, in_msg.addr, cache_entry, tbe);
598          } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
599            assert(in_msg.Tokens < (max_tokens() / 2));
600            trigger(Event:Data_Shared, in_msg.addr, cache_entry, tbe);
601          } else {
602            error("Unexpected message");
603          }
604        } else {
605          if (in_msg.Type == CoherenceResponseType:ACK) {
606            assert(in_msg.Tokens < (max_tokens() / 2));
607            trigger(Event:Ack_All_Tokens, in_msg.addr, cache_entry, tbe);
608          } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:DATA_SHARED) {
609            trigger(Event:Data_All_Tokens, in_msg.addr, cache_entry, tbe);
610          } else {
611            error("Unexpected message");
612          }
613        }
614      }
615    }
616  }
617
618  // Request Network
619  in_port(requestNetwork_in, RequestMsg, requestToL1Cache) {
620    if (requestNetwork_in.isReady(clockEdge())) {
621      peek(requestNetwork_in, RequestMsg, block_on="addr") {
622        assert(in_msg.Destination.isElement(machineID));
623
624        Entry cache_entry := getCacheEntry(in_msg.addr);
625        TBE tbe := L1_TBEs[in_msg.addr];
626
627        if (in_msg.Type == CoherenceRequestType:GETX) {
628          if (in_msg.isLocal) {
629            trigger(Event:Transient_Local_GETX, in_msg.addr,
630                    cache_entry, tbe);
631          }
632          else {
633            trigger(Event:Transient_GETX, in_msg.addr,
634                    cache_entry, tbe);
635          }
636        } else if (in_msg.Type == CoherenceRequestType:GETS) {
637          if (getTokens(cache_entry) == 1 ||
638              getTokens(cache_entry) == (max_tokens() / 2) + 1) {
639            if (in_msg.isLocal) {
640              trigger(Event:Transient_Local_GETS_Last_Token, in_msg.addr,
641                      cache_entry, tbe);
642            }
643            else {
644              trigger(Event:Transient_GETS_Last_Token, in_msg.addr,
645                      cache_entry, tbe);
646            }
647          }
648          else {
649            if (in_msg.isLocal) {
650              trigger(Event:Transient_Local_GETS, in_msg.addr,
651                      cache_entry, tbe);
652            }
653            else {
654              trigger(Event:Transient_GETS, in_msg.addr,
655                      cache_entry, tbe);
656            }
657          }
658        } else {
659          error("Unexpected message");
660        }
661      }
662    }
663  }
664
665  // Mandatory Queue
666  in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...", rank=0) {
667    if (mandatoryQueue_in.isReady(clockEdge())) {
668      peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
669        // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
670
671        TBE tbe := L1_TBEs[in_msg.LineAddress];
672
673        if (in_msg.Type == RubyRequestType:IFETCH) {
674          // ** INSTRUCTION ACCESS ***
675
676          Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
677          if (is_valid(L1Icache_entry)) {
678            // The tag matches for the L1, so the L1 fetches the line.
679            // We know it can't be in the L2 due to exclusion.
680            trigger(mandatory_request_type_to_event(in_msg.Type),
681                    in_msg.LineAddress, L1Icache_entry, tbe);
682          } else {
683
684            // Check to see if it is in the OTHER L1
685            Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
686            if (is_valid(L1Dcache_entry)) {
687              // The block is in the wrong L1, try to write it to the L2
688                trigger(Event:L1_Replacement, in_msg.LineAddress,
689                        L1Dcache_entry, tbe);
690            }
691
692            if (L1Icache.cacheAvail(in_msg.LineAddress)) {
693              // L1 does't have the line, but we have space for it in the L1
694              trigger(mandatory_request_type_to_event(in_msg.Type),
695                      in_msg.LineAddress, L1Icache_entry, tbe);
696            } else {
697              // No room in the L1, so we need to make room
698              trigger(Event:L1_Replacement,
699                      L1Icache.cacheProbe(in_msg.LineAddress),
700                      getL1ICacheEntry(L1Icache.cacheProbe(in_msg.LineAddress)),
701                      L1_TBEs[L1Icache.cacheProbe(in_msg.LineAddress)]);
702            }
703          }
704        } else {
705          // *** DATA ACCESS ***
706
707          Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
708          if (is_valid(L1Dcache_entry)) {
709            // The tag matches for the L1, so the L1 fetches the line.
710            // We know it can't be in the L2 due to exclusion.
711            trigger(mandatory_request_type_to_event(in_msg.Type),
712                    in_msg.LineAddress, L1Dcache_entry, tbe);
713          } else {
714
715            // Check to see if it is in the OTHER L1
716            Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
717            if (is_valid(L1Icache_entry)) {
718              // The block is in the wrong L1, try to write it to the L2
719              trigger(Event:L1_Replacement, in_msg.LineAddress,
720                      L1Icache_entry, tbe);
721            }
722
723            if (L1Dcache.cacheAvail(in_msg.LineAddress)) {
724              // L1 does't have the line, but we have space for it in the L1
725              trigger(mandatory_request_type_to_event(in_msg.Type),
726                      in_msg.LineAddress, L1Dcache_entry, tbe);
727            } else {
728              // No room in the L1, so we need to make room
729              trigger(Event:L1_Replacement,
730                      L1Dcache.cacheProbe(in_msg.LineAddress),
731                      getL1DCacheEntry(L1Dcache.cacheProbe(in_msg.LineAddress)),
732                      L1_TBEs[L1Dcache.cacheProbe(in_msg.LineAddress)]);
733            }
734          }
735        }
736      }
737    }
738  }
739
740  // ACTIONS
741
742  action(a_issueReadRequest, "a", desc="Issue GETS") {
743      assert(is_valid(tbe));
744      if (tbe.IssueCount == 0) {
745        // Update outstanding requests
746        //profile_outstanding_request(outstandingRequests);
747        outstandingRequests := outstandingRequests + 1;
748      }
749
750      if (tbe.IssueCount >= retry_threshold) {
751        // Issue a persistent request if possible
752        if (okToIssueStarving(address, machineID) && (starving == false)) {
753          enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) {
754            out_msg.addr := address;
755            out_msg.Type := PersistentRequestType:GETS_PERSISTENT;
756            out_msg.Requestor := machineID;
757            out_msg.Destination.broadcast(MachineType:L1Cache);
758
759            //
760            // Currently the configuration system limits the system to only one
761            // chip.  Therefore, if we assume one shared L2 cache, then only one
762            // pertinent L2 cache exist.
763            //
764            //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
765
766            out_msg.Destination.add(mapAddressToRange(address,
767                                      MachineType:L2Cache, l2_select_low_bit,
768                                      l2_select_num_bits, intToID(0)));
769
770            out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
771            out_msg.MessageSize := MessageSizeType:Persistent_Control;
772            out_msg.Prefetch := tbe.Prefetch;
773            out_msg.AccessMode := tbe.AccessMode;
774          }
775          markPersistentEntries(address);
776          starving := true;
777
778          if (tbe.IssueCount == 0) {
779            //profile_persistent_prediction(address, tbe.TypeOfAccess);
780          }
781
782          // Update outstanding requests
783          //profile_outstanding_persistent_request(outstandingPersistentRequests);
784          outstandingPersistentRequests := outstandingPersistentRequests + 1;
785
786          // Increment IssueCount
787          tbe.IssueCount := tbe.IssueCount + 1;
788
789          tbe.WentPersistent := true;
790
791          // Do not schedule a wakeup, a persistent requests will always complete
792        }
793        else {
794
795          // We'd like to issue a persistent request, but are not allowed
796          // to issue a P.R. right now.  This, we do not increment the
797          // IssueCount.
798
799          // Set a wakeup timer
800          reissueTimerTable.set(
801            address, clockEdge() + cyclesToTicks(reissue_wakeup_latency));
802
803        }
804      } else {
805        // Make a normal request
806        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
807          out_msg.addr := address;
808          out_msg.Type := CoherenceRequestType:GETS;
809          out_msg.Requestor := machineID;
810          out_msg.Destination.add(mapAddressToRange(address,
811                                    MachineType:L2Cache, l2_select_low_bit,
812                                    l2_select_num_bits, intToID(0)));
813
814          out_msg.RetryNum := tbe.IssueCount;
815          if (tbe.IssueCount == 0) {
816            out_msg.MessageSize := MessageSizeType:Request_Control;
817          } else {
818            out_msg.MessageSize := MessageSizeType:Reissue_Control;
819          }
820          out_msg.Prefetch := tbe.Prefetch;
821          out_msg.AccessMode := tbe.AccessMode;
822        }
823
824        // send to other local L1s, with local bit set
825        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
826          out_msg.addr := address;
827          out_msg.Type := CoherenceRequestType:GETS;
828          out_msg.Requestor := machineID;
829          //
830          // Since only one chip, assuming all L1 caches are local
831          //
832          //out_msg.Destination := getOtherLocalL1IDs(machineID);
833          out_msg.Destination.broadcast(MachineType:L1Cache);
834          out_msg.Destination.remove(machineID);
835
836          out_msg.RetryNum := tbe.IssueCount;
837          out_msg.isLocal := true;
838          if (tbe.IssueCount == 0) {
839            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
840          } else {
841            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
842          }
843          out_msg.Prefetch := tbe.Prefetch;
844          out_msg.AccessMode := tbe.AccessMode;
845        }
846
847        // Increment IssueCount
848        tbe.IssueCount := tbe.IssueCount + 1;
849
850        // Set a wakeup timer
851
852        if (dynamic_timeout_enabled) {
853          reissueTimerTable.set(
854            address, clockEdge() + cyclesToTicks(averageLatencyEstimate()));
855        } else {
856          reissueTimerTable.set(
857            address, clockEdge() + cyclesToTicks(fixed_timeout_latency));
858        }
859
860      }
861  }
862
863  action(b_issueWriteRequest, "b", desc="Issue GETX") {
864
865      assert(is_valid(tbe));
866      if (tbe.IssueCount == 0) {
867        // Update outstanding requests
868        //profile_outstanding_request(outstandingRequests);
869        outstandingRequests := outstandingRequests + 1;
870      }
871
872      if (tbe.IssueCount >= retry_threshold) {
873        // Issue a persistent request if possible
874        if ( okToIssueStarving(address, machineID) && (starving == false)) {
875          enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) {
876            out_msg.addr := address;
877            out_msg.Type := PersistentRequestType:GETX_PERSISTENT;
878            out_msg.Requestor := machineID;
879            out_msg.Destination.broadcast(MachineType:L1Cache);
880
881            //
882            // Currently the configuration system limits the system to only one
883            // chip.  Therefore, if we assume one shared L2 cache, then only one
884            // pertinent L2 cache exist.
885            //
886            //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
887
888            out_msg.Destination.add(mapAddressToRange(address,
889                                      MachineType:L2Cache, l2_select_low_bit,
890                                      l2_select_num_bits, intToID(0)));
891
892            out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
893            out_msg.MessageSize := MessageSizeType:Persistent_Control;
894            out_msg.Prefetch := tbe.Prefetch;
895            out_msg.AccessMode := tbe.AccessMode;
896          }
897          markPersistentEntries(address);
898          starving := true;
899
900          // Update outstanding requests
901          //profile_outstanding_persistent_request(outstandingPersistentRequests);
902          outstandingPersistentRequests := outstandingPersistentRequests + 1;
903
904          if (tbe.IssueCount == 0) {
905            //profile_persistent_prediction(address, tbe.TypeOfAccess);
906          }
907
908          // Increment IssueCount
909          tbe.IssueCount := tbe.IssueCount + 1;
910
911          tbe.WentPersistent := true;
912
913          // Do not schedule a wakeup, a persistent requests will always complete
914        }
915        else {
916
917          // We'd like to issue a persistent request, but are not allowed
918          // to issue a P.R. right now.  This, we do not increment the
919          // IssueCount.
920
921          // Set a wakeup timer
922          reissueTimerTable.set(
923            address, clockEdge() + cyclesToTicks(reissue_wakeup_latency));
924        }
925
926      } else  {
927        // Make a normal request
928        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
929          out_msg.addr := address;
930          out_msg.Type := CoherenceRequestType:GETX;
931          out_msg.Requestor := machineID;
932
933          out_msg.Destination.add(mapAddressToRange(address,
934                                    MachineType:L2Cache, l2_select_low_bit,
935                                    l2_select_num_bits, intToID(0)));
936
937          out_msg.RetryNum := tbe.IssueCount;
938
939          if (tbe.IssueCount == 0) {
940            out_msg.MessageSize := MessageSizeType:Request_Control;
941          } else {
942            out_msg.MessageSize := MessageSizeType:Reissue_Control;
943          }
944          out_msg.Prefetch := tbe.Prefetch;
945          out_msg.AccessMode := tbe.AccessMode;
946        }
947
948        // send to other local L1s too
949        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
950          out_msg.addr := address;
951          out_msg.Type := CoherenceRequestType:GETX;
952          out_msg.Requestor := machineID;
953          out_msg.isLocal := true;
954
955          //
956          // Since only one chip, assuming all L1 caches are local
957          //
958          //out_msg.Destination := getOtherLocalL1IDs(machineID);
959          out_msg.Destination.broadcast(MachineType:L1Cache);
960          out_msg.Destination.remove(machineID);
961
962          out_msg.RetryNum := tbe.IssueCount;
963          if (tbe.IssueCount == 0) {
964            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
965          } else {
966            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
967          }
968          out_msg.Prefetch := tbe.Prefetch;
969          out_msg.AccessMode := tbe.AccessMode;
970        }
971
972        // Increment IssueCount
973        tbe.IssueCount := tbe.IssueCount + 1;
974
975        DPRINTF(RubySlicc, "incremented issue count to %d\n",
976                tbe.IssueCount);
977
978        // Set a wakeup timer
979        if (dynamic_timeout_enabled) {
980          reissueTimerTable.set(
981            address, clockEdge() + cyclesToTicks(averageLatencyEstimate()));
982        } else {
983          reissueTimerTable.set(
984            address, clockEdge() + cyclesToTicks(fixed_timeout_latency));
985        }
986      }
987  }
988
989  action(bb_bounceResponse, "\b", desc="Bounce tokens and data to memory") {
990    peek(responseNetwork_in, ResponseMsg) {
991      // FIXME, should use a 3rd vnet
992      enqueue(responseNetwork_out, ResponseMsg, 1) {
993        out_msg.addr := address;
994        out_msg.Type := in_msg.Type;
995        out_msg.Sender := machineID;
996        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
997        out_msg.Tokens := in_msg.Tokens;
998        out_msg.MessageSize := in_msg.MessageSize;
999        out_msg.DataBlk := in_msg.DataBlk;
1000        out_msg.Dirty := in_msg.Dirty;
1001      }
1002    }
1003  }
1004
1005  action(c_ownedReplacement, "c", desc="Issue writeback") {
1006    assert(is_valid(cache_entry));
1007    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1008      out_msg.addr := address;
1009      out_msg.Sender := machineID;
1010
1011      out_msg.Destination.add(mapAddressToRange(address,
1012                                MachineType:L2Cache, l2_select_low_bit,
1013                                l2_select_num_bits, intToID(0)));
1014
1015      out_msg.Tokens := cache_entry.Tokens;
1016      out_msg.DataBlk := cache_entry.DataBlk;
1017      out_msg.Dirty := cache_entry.Dirty;
1018      out_msg.Type := CoherenceResponseType:WB_OWNED;
1019
1020      // always send the data?
1021      out_msg.MessageSize := MessageSizeType:Writeback_Data;
1022    }
1023    cache_entry.Tokens := 0;
1024  }
1025
1026  action(cc_sharedReplacement, "\c", desc="Issue shared writeback") {
1027
1028    // don't send writeback if replacing block with no tokens
1029    assert(is_valid(cache_entry));
1030    assert (cache_entry.Tokens > 0);
1031    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1032        out_msg.addr := address;
1033        out_msg.Sender := machineID;
1034
1035        out_msg.Destination.add(mapAddressToRange(address,
1036                                  MachineType:L2Cache, l2_select_low_bit,
1037                                  l2_select_num_bits, intToID(0)));
1038
1039        out_msg.Tokens := cache_entry.Tokens;
1040        out_msg.DataBlk := cache_entry.DataBlk;
1041        // assert(cache_entry.Dirty == false);
1042        out_msg.Dirty := false;
1043
1044        out_msg.MessageSize := MessageSizeType:Writeback_Data;
1045        out_msg.Type := CoherenceResponseType:WB_SHARED_DATA;
1046    }
1047    cache_entry.Tokens := 0;
1048  }
1049
1050  action(tr_tokenReplacement, "tr", desc="Issue token writeback") {
1051    assert(is_valid(cache_entry));
1052    if (cache_entry.Tokens > 0) {
1053      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1054        out_msg.addr := address;
1055        out_msg.Sender := machineID;
1056
1057        out_msg.Destination.add(mapAddressToRange(address,
1058                                  MachineType:L2Cache, l2_select_low_bit,
1059                                  l2_select_num_bits, intToID(0)));
1060
1061        out_msg.Tokens := cache_entry.Tokens;
1062        out_msg.DataBlk := cache_entry.DataBlk;
1063        // assert(cache_entry.Dirty == false);
1064        out_msg.Dirty := false;
1065
1066        // always send the data?
1067        out_msg.MessageSize := MessageSizeType:Writeback_Control;
1068        out_msg.Type := CoherenceResponseType:WB_TOKENS;
1069      }
1070    }
1071    cache_entry.Tokens := 0;
1072  }
1073
1074
1075  action(d_sendDataWithToken, "d", desc="Send data and a token from cache to requestor") {
1076    assert(is_valid(cache_entry));
1077    peek(requestNetwork_in, RequestMsg) {
1078      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1079        out_msg.addr := address;
1080        out_msg.Type := CoherenceResponseType:DATA_SHARED;
1081        out_msg.Sender := machineID;
1082        out_msg.Destination.add(in_msg.Requestor);
1083        out_msg.Tokens := 1;
1084        out_msg.DataBlk := cache_entry.DataBlk;
1085        // out_msg.Dirty := cache_entry.Dirty;
1086        out_msg.Dirty := false;
1087        if (in_msg.isLocal) {
1088          out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1089        } else {
1090          out_msg.MessageSize := MessageSizeType:Response_Data;
1091        }
1092      }
1093    }
1094    cache_entry.Tokens := cache_entry.Tokens - 1;
1095    assert(cache_entry.Tokens >= 1);
1096  }
1097
1098  action(d_sendDataWithNTokenIfAvail, "\dd", desc="Send data and a token from cache to requestor") {
1099    assert(is_valid(cache_entry));
1100    peek(requestNetwork_in, RequestMsg) {
1101      if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
1102        enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1103          out_msg.addr := address;
1104          out_msg.Type := CoherenceResponseType:DATA_SHARED;
1105          out_msg.Sender := machineID;
1106          out_msg.Destination.add(in_msg.Requestor);
1107          out_msg.Tokens := N_tokens;
1108          out_msg.DataBlk := cache_entry.DataBlk;
1109          // out_msg.Dirty := cache_entry.Dirty;
1110          out_msg.Dirty := false;
1111          if (in_msg.isLocal) {
1112            out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1113          } else {
1114            out_msg.MessageSize := MessageSizeType:Response_Data;
1115          }
1116        }
1117        cache_entry.Tokens := cache_entry.Tokens - N_tokens;
1118      }
1119      else if (cache_entry.Tokens > 1) {
1120        enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1121          out_msg.addr := address;
1122          out_msg.Type := CoherenceResponseType:DATA_SHARED;
1123          out_msg.Sender := machineID;
1124          out_msg.Destination.add(in_msg.Requestor);
1125          out_msg.Tokens := 1;
1126          out_msg.DataBlk := cache_entry.DataBlk;
1127          // out_msg.Dirty := cache_entry.Dirty;
1128          out_msg.Dirty := false;
1129          if (in_msg.isLocal) {
1130            out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1131          } else {
1132            out_msg.MessageSize := MessageSizeType:Response_Data;
1133          }
1134        }
1135        cache_entry.Tokens := cache_entry.Tokens - 1;
1136      }
1137    }
1138//    assert(cache_entry.Tokens >= 1);
1139  }
1140
1141  action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") {
1142    peek(requestNetwork_in, RequestMsg) {
1143    assert(is_valid(cache_entry));
1144      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1145        out_msg.addr := address;
1146        out_msg.Type := CoherenceResponseType:DATA_OWNER;
1147        out_msg.Sender := machineID;
1148        out_msg.Destination.add(in_msg.Requestor);
1149        assert(cache_entry.Tokens > (max_tokens() / 2));
1150        out_msg.Tokens := cache_entry.Tokens;
1151        out_msg.DataBlk := cache_entry.DataBlk;
1152        out_msg.Dirty := cache_entry.Dirty;
1153        if (in_msg.isLocal) {
1154          out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1155        } else {
1156          out_msg.MessageSize := MessageSizeType:Response_Data;
1157        }
1158      }
1159    }
1160    cache_entry.Tokens := 0;
1161  }
1162
1163  action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") {
1164    // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1165    assert(is_valid(cache_entry));
1166    if (cache_entry.Tokens > 0) {
1167      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1168        out_msg.addr := address;
1169        if (cache_entry.Tokens > (max_tokens() / 2)) {
1170          out_msg.Type := CoherenceResponseType:DATA_OWNER;
1171        } else {
1172          out_msg.Type := CoherenceResponseType:ACK;
1173        }
1174        out_msg.Sender := machineID;
1175        out_msg.Destination.add(persistentTable.findSmallest(address));
1176        assert(cache_entry.Tokens >= 1);
1177        out_msg.Tokens := cache_entry.Tokens;
1178        out_msg.DataBlk := cache_entry.DataBlk;
1179        out_msg.MessageSize := MessageSizeType:Response_Control;
1180      }
1181    }
1182    cache_entry.Tokens := 0;
1183  }
1184
1185  action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") {
1186    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1187    assert(is_valid(cache_entry));
1188    assert(cache_entry.Tokens > 0);
1189    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1190      out_msg.addr := address;
1191      out_msg.Type := CoherenceResponseType:DATA_OWNER;
1192      out_msg.Sender := machineID;
1193      out_msg.Destination.add(persistentTable.findSmallest(address));
1194      assert(cache_entry.Tokens > (max_tokens() / 2));
1195      out_msg.Tokens := cache_entry.Tokens;
1196      out_msg.DataBlk := cache_entry.DataBlk;
1197      out_msg.Dirty := cache_entry.Dirty;
1198      out_msg.MessageSize := MessageSizeType:Response_Data;
1199    }
1200    cache_entry.Tokens := 0;
1201  }
1202
1203  action(f_sendAckWithAllButNorOneTokens, "f", desc="Send ack with all our tokens but one to starver.") {
1204    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1205    assert(is_valid(cache_entry));
1206    assert(cache_entry.Tokens > 0);
1207    if (cache_entry.Tokens > 1) {
1208      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1209        out_msg.addr := address;
1210        if (cache_entry.Tokens > (max_tokens() / 2)) {
1211          out_msg.Type := CoherenceResponseType:DATA_OWNER;
1212        } else {
1213          out_msg.Type := CoherenceResponseType:ACK;
1214        }
1215        out_msg.Sender := machineID;
1216        out_msg.Destination.add(persistentTable.findSmallest(address));
1217        assert(cache_entry.Tokens >= 1);
1218        if (cache_entry.Tokens > N_tokens) {
1219          out_msg.Tokens := cache_entry.Tokens - N_tokens;
1220        } else {
1221          out_msg.Tokens := cache_entry.Tokens - 1;
1222        }
1223        out_msg.DataBlk := cache_entry.DataBlk;
1224        out_msg.MessageSize := MessageSizeType:Response_Control;
1225      }
1226    }
1227    if (cache_entry.Tokens > N_tokens) {
1228      cache_entry.Tokens := N_tokens;
1229    } else {
1230      cache_entry.Tokens := 1;
1231    }
1232  }
1233
1234  action(ff_sendDataWithAllButNorOneTokens, "\f", desc="Send data and out tokens but one to starver") {
1235    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1236    assert(is_valid(cache_entry));
1237    assert(cache_entry.Tokens > ((max_tokens() / 2) + 1));
1238    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1239        out_msg.addr := address;
1240        out_msg.Type := CoherenceResponseType:DATA_OWNER;
1241        out_msg.Sender := machineID;
1242        out_msg.Destination.add(persistentTable.findSmallest(address));
1243        if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
1244          out_msg.Tokens := cache_entry.Tokens - N_tokens;
1245        } else {
1246          out_msg.Tokens := cache_entry.Tokens - 1;
1247        }
1248        assert(out_msg.Tokens > (max_tokens() / 2));
1249        out_msg.DataBlk := cache_entry.DataBlk;
1250        out_msg.Dirty := cache_entry.Dirty;
1251        out_msg.MessageSize := MessageSizeType:Response_Data;
1252    }
1253    if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
1254      cache_entry.Tokens := N_tokens;
1255    } else {
1256      cache_entry.Tokens := 1;
1257    }
1258  }
1259
1260  action(fo_sendDataWithOwnerToken, "fo", desc="Send data and owner tokens") {
1261    assert(is_valid(cache_entry));
1262    assert(cache_entry.Tokens == ((max_tokens() / 2) + 1));
1263    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1264        out_msg.addr := address;
1265        out_msg.Type := CoherenceResponseType:DATA_OWNER;
1266        out_msg.Sender := machineID;
1267        out_msg.Destination.add(persistentTable.findSmallest(address));
1268        out_msg.Tokens := cache_entry.Tokens;
1269        assert(out_msg.Tokens > (max_tokens() / 2));
1270        out_msg.DataBlk := cache_entry.DataBlk;
1271        out_msg.Dirty := cache_entry.Dirty;
1272        out_msg.MessageSize := MessageSizeType:Response_Data;
1273    }
1274    cache_entry.Tokens := 0;
1275  }
1276
1277  action(g_bounceResponseToStarver, "g", desc="Redirect response to starving processor") {
1278    // assert(persistentTable.isLocked(address));
1279
1280    peek(responseNetwork_in, ResponseMsg) {
1281      // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1282      // FIXME, should use a 3rd vnet in some cases
1283      enqueue(responseNetwork_out, ResponseMsg, 1) {
1284        out_msg.addr := address;
1285        out_msg.Type := in_msg.Type;
1286        out_msg.Sender := machineID;
1287        out_msg.Destination.add(persistentTable.findSmallest(address));
1288        out_msg.Tokens := in_msg.Tokens;
1289        out_msg.DataBlk := in_msg.DataBlk;
1290        out_msg.Dirty := in_msg.Dirty;
1291        out_msg.MessageSize := in_msg.MessageSize;
1292      }
1293    }
1294  }
1295
1296  action(h_load_hit, "hd", desc="Notify sequencer the load completed.") {
1297    assert(is_valid(cache_entry));
1298    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1299            address, cache_entry.DataBlk);
1300
1301    L1Dcache.setMRU(cache_entry);
1302    sequencer.readCallback(address, cache_entry.DataBlk, false,
1303                           MachineType:L1Cache);
1304  }
1305
1306  action(h_ifetch_hit, "hi", desc="Notify sequencer the load completed.") {
1307    assert(is_valid(cache_entry));
1308    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1309            address, cache_entry.DataBlk);
1310
1311    L1Icache.setMRU(cache_entry);
1312    sequencer.readCallback(address, cache_entry.DataBlk, false,
1313                           MachineType:L1Cache);
1314  }
1315
1316  action(x_external_load_hit, "x", desc="Notify sequencer the load completed.") {
1317    assert(is_valid(cache_entry));
1318    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1319            address, cache_entry.DataBlk);
1320    peek(responseNetwork_in, ResponseMsg) {
1321      L1Icache.setMRU(address);
1322      L1Dcache.setMRU(address);
1323      sequencer.readCallback(address, cache_entry.DataBlk,
1324                             isExternalHit(address, in_msg.Sender),
1325                             machineIDToMachineType(in_msg.Sender));
1326    }
1327  }
1328
1329  action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
1330    assert(is_valid(cache_entry));
1331    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1332            address, cache_entry.DataBlk);
1333
1334    L1Dcache.setMRU(cache_entry);
1335    sequencer.writeCallback(address, cache_entry.DataBlk, false,
1336                            MachineType:L1Cache);
1337    cache_entry.Dirty := true;
1338    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
1339  }
1340
1341  action(xx_external_store_hit, "\x", desc="Notify sequencer that store completed.") {
1342    assert(is_valid(cache_entry));
1343    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1344            address, cache_entry.DataBlk);
1345    peek(responseNetwork_in, ResponseMsg) {
1346      L1Icache.setMRU(address);
1347      L1Dcache.setMRU(address);
1348      sequencer.writeCallback(address, cache_entry.DataBlk,
1349                              isExternalHit(address, in_msg.Sender),
1350                              machineIDToMachineType(in_msg.Sender));
1351    }
1352    cache_entry.Dirty := true;
1353    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
1354  }
1355
1356  action(i_allocateTBE, "i", desc="Allocate TBE") {
1357    check_allocate(L1_TBEs);
1358    L1_TBEs.allocate(address);
1359    set_tbe(L1_TBEs[address]);
1360    tbe.IssueCount := 0;
1361    peek(mandatoryQueue_in, RubyRequest) {
1362      tbe.PC := in_msg.ProgramCounter;
1363      tbe.TypeOfAccess := cache_request_type_to_access_type(in_msg.Type);
1364      if (in_msg.Type == RubyRequestType:ATOMIC) {
1365        tbe.IsAtomic := true;
1366      }
1367      tbe.Prefetch := in_msg.Prefetch;
1368      tbe.AccessMode := in_msg.AccessMode;
1369    }
1370    tbe.IssueTime := curCycle();
1371  }
1372
1373  action(ta_traceStalledAddress, "ta", desc="Trace Stalled Address") {
1374    peek(mandatoryQueue_in, RubyRequest) {
1375      APPEND_TRANSITION_COMMENT(in_msg.LineAddress);
1376    }
1377  }
1378
1379  action(j_unsetReissueTimer, "j", desc="Unset reissue timer.") {
1380    if (reissueTimerTable.isSet(address)) {
1381      reissueTimerTable.unset(address);
1382    }
1383  }
1384
1385  action(jj_unsetUseTimer, "\j", desc="Unset use timer.") {
1386    useTimerTable.unset(address);
1387  }
1388
1389  action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
1390    mandatoryQueue_in.dequeue(clockEdge());
1391  }
1392
1393  action(l_popPersistentQueue, "l", desc="Pop persistent queue.") {
1394    persistentNetwork_in.dequeue(clockEdge());
1395  }
1396
1397  action(m_popRequestQueue, "m", desc="Pop request queue.") {
1398    requestNetwork_in.dequeue(clockEdge());
1399  }
1400
1401  action(n_popResponseQueue, "n", desc="Pop response queue") {
1402    responseNetwork_in.dequeue(clockEdge());
1403  }
1404
1405  action(o_scheduleUseTimeout, "o", desc="Schedule a use timeout.") {
1406    useTimerTable.set(
1407        address, clockEdge() + cyclesToTicks(use_timeout_latency));
1408  }
1409
1410  action(p_informL2AboutTokenLoss, "p", desc="Inform L2 about loss of all tokens") {
1411    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1412       out_msg.addr := address;
1413       out_msg.Type := CoherenceResponseType:INV;
1414       out_msg.Tokens := 0;
1415       out_msg.Sender := machineID;
1416
1417       out_msg.Destination.add(mapAddressToRange(address,
1418                                 MachineType:L2Cache, l2_select_low_bit,
1419                                 l2_select_num_bits, intToID(0)));
1420       out_msg.MessageSize := MessageSizeType:Response_Control;
1421    }
1422  }
1423
1424  action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") {
1425    peek(responseNetwork_in, ResponseMsg) {
1426      assert(is_valid(cache_entry));
1427      assert(in_msg.Tokens != 0);
1428      DPRINTF(RubySlicc, "L1 received tokens for address: %#x, tokens: %d\n",
1429              in_msg.addr, in_msg.Tokens);
1430      cache_entry.Tokens := cache_entry.Tokens + in_msg.Tokens;
1431      DPRINTF(RubySlicc, "%d\n", cache_entry.Tokens);
1432
1433      if (cache_entry.Dirty == false && in_msg.Dirty) {
1434        cache_entry.Dirty := true;
1435      }
1436    }
1437  }
1438
1439  action(s_deallocateTBE, "s", desc="Deallocate TBE") {
1440
1441    assert(is_valid(tbe));
1442    if (tbe.WentPersistent) {
1443      // assert(starving);
1444      outstandingRequests := outstandingRequests - 1;
1445      enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) {
1446        out_msg.addr := address;
1447        out_msg.Type := PersistentRequestType:DEACTIVATE_PERSISTENT;
1448        out_msg.Requestor := machineID;
1449        out_msg.Destination.broadcast(MachineType:L1Cache);
1450
1451        //
1452        // Currently the configuration system limits the system to only one
1453        // chip.  Therefore, if we assume one shared L2 cache, then only one
1454        // pertinent L2 cache exist.
1455        //
1456        //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
1457
1458        out_msg.Destination.add(mapAddressToRange(address,
1459                                  MachineType:L2Cache, l2_select_low_bit,
1460                                  l2_select_num_bits, intToID(0)));
1461
1462        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
1463        out_msg.MessageSize := MessageSizeType:Persistent_Control;
1464      }
1465      starving := false;
1466    }
1467
1468    // Update average latency
1469    if (tbe.IssueCount <= 1) {
1470      if (tbe.ExternalResponse) {
1471        updateAverageLatencyEstimate(curCycle() - tbe.IssueTime);
1472      }
1473    }
1474
1475    // Profile
1476    //if (tbe.WentPersistent) {
1477    //  profile_token_retry(address, tbe.TypeOfAccess, 2);
1478    //}
1479    //else {
1480    //  profile_token_retry(address, tbe.TypeOfAccess, 1);
1481    //}
1482
1483    //profile_token_retry(address, tbe.TypeOfAccess, tbe.IssueCount);
1484    L1_TBEs.deallocate(address);
1485    unset_tbe();
1486  }
1487
1488  action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") {
1489    assert(is_valid(cache_entry));
1490    if (cache_entry.Tokens > 0) {
1491      peek(requestNetwork_in, RequestMsg) {
1492        enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1493          out_msg.addr := address;
1494          if (cache_entry.Tokens > (max_tokens() / 2)) {
1495            out_msg.Type := CoherenceResponseType:DATA_OWNER;
1496          } else {
1497            out_msg.Type := CoherenceResponseType:ACK;
1498          }
1499          out_msg.Sender := machineID;
1500          out_msg.Destination.add(in_msg.Requestor);
1501          assert(cache_entry.Tokens >= 1);
1502          out_msg.Tokens := cache_entry.Tokens;
1503          out_msg.DataBlk := cache_entry.DataBlk;
1504          out_msg.MessageSize := MessageSizeType:Response_Control;
1505        }
1506      }
1507    }
1508    cache_entry.Tokens := 0;
1509  }
1510
1511  action(u_writeDataToCache, "u", desc="Write data to cache") {
1512    peek(responseNetwork_in, ResponseMsg) {
1513      assert(is_valid(cache_entry));
1514      cache_entry.DataBlk := in_msg.DataBlk;
1515      if (cache_entry.Dirty == false && in_msg.Dirty) {
1516        cache_entry.Dirty := in_msg.Dirty;
1517      }
1518
1519    }
1520  }
1521
1522  action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block.  Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
1523    assert(getTokens(cache_entry) == 0);
1524    if (L1Dcache.isTagPresent(address)) {
1525      L1Dcache.deallocate(address);
1526    } else {
1527      L1Icache.deallocate(address);
1528    }
1529    unset_cache_entry();
1530  }
1531
1532  action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
1533    if (is_valid(cache_entry)) {
1534    } else {
1535      set_cache_entry(L1Dcache.allocate(address, new Entry));
1536    }
1537  }
1538
1539  action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
1540    if (is_valid(cache_entry)) {
1541    } else {
1542      set_cache_entry(L1Icache.allocate(address, new Entry));
1543    }
1544  }
1545
1546  action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
1547    if (send_evictions) {
1548      DPRINTF(RubySlicc, "Sending invalidation for %#x to the CPU\n", address);
1549      sequencer.evictionCallback(address);
1550    }
1551  }
1552
1553  action(uu_profileInstMiss, "\uim", desc="Profile the demand miss") {
1554      ++L1Icache.demand_misses;
1555  }
1556
1557  action(uu_profileInstHit, "\uih", desc="Profile the demand hit") {
1558      ++L1Icache.demand_hits;
1559  }
1560
1561  action(uu_profileDataMiss, "\udm", desc="Profile the demand miss") {
1562      ++L1Dcache.demand_misses;
1563  }
1564
1565  action(uu_profileDataHit, "\udh", desc="Profile the demand hit") {
1566      ++L1Dcache.demand_hits;
1567  }
1568
1569  action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") {
1570    peek(responseNetwork_in, ResponseMsg) {
1571      assert(is_valid(cache_entry));
1572      assert(cache_entry.DataBlk == in_msg.DataBlk);
1573    }
1574  }
1575
1576  action(zz_stallAndWaitMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
1577    peek(mandatoryQueue_in, RubyRequest) {
1578      APPEND_TRANSITION_COMMENT(in_msg.LineAddress);
1579    }
1580    stall_and_wait(mandatoryQueue_in, address);
1581  }
1582
1583  action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
1584    wakeUpBuffers(address);
1585  }
1586
1587  action(ka_wakeUpAllDependents, "ka", desc="wake-up all dependents") {
1588    wakeUpAllBuffers();
1589  }
1590
1591  //*****************************************************
1592  // TRANSITIONS
1593  //*****************************************************
1594
1595  // Transitions for Load/Store/L2_Replacement from transient states
1596  transition({IM, SM, OM, IS, IM_L, IS_L, I_L, S_L, SM_L, M_W, MM_W}, L1_Replacement) {
1597    ta_traceStalledAddress;
1598    zz_stallAndWaitMandatoryQueue;
1599  }
1600
1601  transition({IM, SM, OM, IS, IM_L, IS_L, SM_L}, {Store, Atomic}) {
1602    zz_stallAndWaitMandatoryQueue;
1603  }
1604
1605  transition({IM, IS, IM_L, IS_L}, {Load, Ifetch}) {
1606    zz_stallAndWaitMandatoryQueue;
1607  }
1608
1609  // Lockdowns
1610  transition({NP, I, S, O, M, MM, M_W, MM_W, IM, SM, OM, IS}, Own_Lock_or_Unlock) {
1611    l_popPersistentQueue;
1612  }
1613
1614  // Transitions from NP
1615  transition(NP, Load, IS) {
1616    ii_allocateL1DCacheBlock;
1617    i_allocateTBE;
1618    a_issueReadRequest;
1619    uu_profileDataMiss;
1620    k_popMandatoryQueue;
1621  }
1622
1623  transition(NP, Ifetch, IS) {
1624    pp_allocateL1ICacheBlock;
1625    i_allocateTBE;
1626    a_issueReadRequest;
1627    uu_profileInstMiss;
1628    k_popMandatoryQueue;
1629  }
1630
1631  transition(NP, {Store, Atomic}, IM) {
1632    ii_allocateL1DCacheBlock;
1633    i_allocateTBE;
1634    b_issueWriteRequest;
1635    uu_profileDataMiss;
1636    k_popMandatoryQueue;
1637  }
1638
1639  transition(NP, {Ack, Data_Shared, Data_Owner, Data_All_Tokens}) {
1640    bb_bounceResponse;
1641    n_popResponseQueue;
1642  }
1643
1644  transition(NP, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) {
1645    m_popRequestQueue;
1646  }
1647
1648  transition(NP, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, I_L) {
1649    l_popPersistentQueue;
1650  }
1651
1652  // Transitions from Idle
1653  transition(I, Load, IS) {
1654    i_allocateTBE;
1655    a_issueReadRequest;
1656    uu_profileDataMiss;
1657    k_popMandatoryQueue;
1658  }
1659
1660  transition(I, Ifetch, IS) {
1661    i_allocateTBE;
1662    a_issueReadRequest;
1663    uu_profileInstMiss;
1664    k_popMandatoryQueue;
1665  }
1666
1667  transition(I, {Store, Atomic}, IM) {
1668    i_allocateTBE;
1669    b_issueWriteRequest;
1670    uu_profileDataMiss;
1671    k_popMandatoryQueue;
1672  }
1673
1674  transition(I, L1_Replacement) {
1675    ta_traceStalledAddress;
1676    tr_tokenReplacement;
1677    gg_deallocateL1CacheBlock;
1678    ka_wakeUpAllDependents;
1679  }
1680
1681  transition(I, {Transient_GETX, Transient_Local_GETX}) {
1682    t_sendAckWithCollectedTokens;
1683    m_popRequestQueue;
1684  }
1685
1686  transition(I, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
1687    m_popRequestQueue;
1688  }
1689
1690  transition(I, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, I_L) {
1691    e_sendAckWithCollectedTokens;
1692    l_popPersistentQueue;
1693  }
1694
1695  transition(I_L, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}) {
1696    l_popPersistentQueue;
1697  }
1698
1699  transition(I, Ack) {
1700    q_updateTokensFromResponse;
1701    n_popResponseQueue;
1702  }
1703
1704  transition(I, Data_Shared, S) {
1705    u_writeDataToCache;
1706    q_updateTokensFromResponse;
1707    n_popResponseQueue;
1708  }
1709
1710  transition(I, Data_Owner, O) {
1711    u_writeDataToCache;
1712    q_updateTokensFromResponse;
1713    n_popResponseQueue;
1714  }
1715
1716  transition(I, Data_All_Tokens, M) {
1717    u_writeDataToCache;
1718    q_updateTokensFromResponse;
1719    n_popResponseQueue;
1720  }
1721
1722  // Transitions from Shared
1723  transition({S, SM, S_L, SM_L}, Load) {
1724    h_load_hit;
1725    uu_profileDataHit;
1726    k_popMandatoryQueue;
1727  }
1728
1729  transition({S, SM, S_L, SM_L}, Ifetch) {
1730    h_ifetch_hit;
1731    uu_profileInstHit;
1732    k_popMandatoryQueue;
1733  }
1734
1735  transition(S, {Store, Atomic}, SM) {
1736    i_allocateTBE;
1737    b_issueWriteRequest;
1738    uu_profileDataMiss;
1739    k_popMandatoryQueue;
1740  }
1741
1742  transition(S, L1_Replacement, I) {
1743    ta_traceStalledAddress;
1744    cc_sharedReplacement; // Only needed in some cases
1745    forward_eviction_to_cpu;
1746    gg_deallocateL1CacheBlock;
1747    ka_wakeUpAllDependents;
1748  }
1749
1750  transition(S, {Transient_GETX, Transient_Local_GETX}, I) {
1751    t_sendAckWithCollectedTokens;
1752    p_informL2AboutTokenLoss;
1753    forward_eviction_to_cpu
1754    m_popRequestQueue;
1755  }
1756
1757  // only owner responds to non-local requests
1758  transition(S, Transient_GETS) {
1759    m_popRequestQueue;
1760  }
1761
1762  transition(S, Transient_Local_GETS) {
1763    d_sendDataWithToken;
1764    m_popRequestQueue;
1765  }
1766
1767  transition(S, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) {
1768    m_popRequestQueue;
1769  }
1770
1771  transition({S, S_L}, Persistent_GETX, I_L) {
1772    e_sendAckWithCollectedTokens;
1773    p_informL2AboutTokenLoss;
1774    forward_eviction_to_cpu
1775    l_popPersistentQueue;
1776  }
1777
1778  transition(S, {Persistent_GETS, Persistent_GETS_Last_Token}, S_L) {
1779    f_sendAckWithAllButNorOneTokens;
1780    l_popPersistentQueue;
1781  }
1782
1783  transition(S_L, {Persistent_GETS, Persistent_GETS_Last_Token}) {
1784    l_popPersistentQueue;
1785  }
1786
1787  transition(S, Ack) {
1788    q_updateTokensFromResponse;
1789    n_popResponseQueue;
1790  }
1791
1792  transition(S, Data_Shared) {
1793    w_assertIncomingDataAndCacheDataMatch;
1794    q_updateTokensFromResponse;
1795    n_popResponseQueue;
1796  }
1797
1798  transition(S, Data_Owner, O) {
1799    w_assertIncomingDataAndCacheDataMatch;
1800    q_updateTokensFromResponse;
1801    n_popResponseQueue;
1802  }
1803
1804  transition(S, Data_All_Tokens, M) {
1805    w_assertIncomingDataAndCacheDataMatch;
1806    q_updateTokensFromResponse;
1807    n_popResponseQueue;
1808  }
1809
1810  // Transitions from Owned
1811  transition({O, OM}, Ifetch) {
1812    h_ifetch_hit;
1813    uu_profileInstHit;
1814    k_popMandatoryQueue;
1815  }
1816
1817  transition({O, OM}, Load) {
1818    h_load_hit;
1819    uu_profileDataHit;
1820    k_popMandatoryQueue;
1821  }
1822
1823  transition(O, {Store, Atomic}, OM) {
1824    i_allocateTBE;
1825    b_issueWriteRequest;
1826    uu_profileDataMiss;
1827    k_popMandatoryQueue;
1828  }
1829
1830  transition(O, L1_Replacement, I) {
1831    ta_traceStalledAddress;
1832    c_ownedReplacement;
1833    forward_eviction_to_cpu
1834    gg_deallocateL1CacheBlock;
1835    ka_wakeUpAllDependents;
1836  }
1837
1838  transition(O, {Transient_GETX, Transient_Local_GETX}, I) {
1839    dd_sendDataWithAllTokens;
1840    p_informL2AboutTokenLoss;
1841    forward_eviction_to_cpu
1842    m_popRequestQueue;
1843  }
1844
1845  transition(O, Persistent_GETX, I_L) {
1846    ee_sendDataWithAllTokens;
1847    p_informL2AboutTokenLoss;
1848    forward_eviction_to_cpu
1849    l_popPersistentQueue;
1850  }
1851
1852  transition(O, Persistent_GETS, S_L) {
1853    ff_sendDataWithAllButNorOneTokens;
1854    l_popPersistentQueue;
1855  }
1856
1857  transition(O, Persistent_GETS_Last_Token, I_L) {
1858    fo_sendDataWithOwnerToken;
1859    forward_eviction_to_cpu
1860    l_popPersistentQueue;
1861  }
1862
1863  transition(O, Transient_GETS) {
1864    d_sendDataWithToken;
1865    m_popRequestQueue;
1866  }
1867
1868  transition(O, Transient_Local_GETS) {
1869    d_sendDataWithToken;
1870    m_popRequestQueue;
1871  }
1872
1873  // ran out of tokens, wait for it to go persistent
1874  transition(O, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) {
1875    m_popRequestQueue;
1876  }
1877
1878  transition(O, Ack) {
1879    q_updateTokensFromResponse;
1880    n_popResponseQueue;
1881  }
1882
1883  transition(O, Ack_All_Tokens, M) {
1884    q_updateTokensFromResponse;
1885    n_popResponseQueue;
1886  }
1887
1888  transition(O, Data_Shared) {
1889    w_assertIncomingDataAndCacheDataMatch;
1890    q_updateTokensFromResponse;
1891    n_popResponseQueue;
1892  }
1893
1894  transition(O, Data_All_Tokens, M) {
1895    w_assertIncomingDataAndCacheDataMatch;
1896    q_updateTokensFromResponse;
1897    n_popResponseQueue;
1898  }
1899
1900  // Transitions from Modified
1901  transition({MM, MM_W}, Ifetch) {
1902    h_ifetch_hit;
1903    uu_profileInstHit;
1904    k_popMandatoryQueue;
1905  }
1906
1907  transition({MM, MM_W}, Load) {
1908    h_load_hit;
1909    uu_profileDataHit;
1910    k_popMandatoryQueue;
1911  }
1912
1913  transition({MM_W}, {Store, Atomic}) {
1914    hh_store_hit;
1915    uu_profileDataHit;
1916    k_popMandatoryQueue;
1917  }
1918
1919  transition(MM, Store) {
1920    hh_store_hit;
1921    uu_profileDataHit;
1922    k_popMandatoryQueue;
1923  }
1924
1925  transition(MM, Atomic, M) {
1926    hh_store_hit;
1927    uu_profileDataHit;
1928    k_popMandatoryQueue;
1929  }
1930
1931  transition(MM, L1_Replacement, I) {
1932    ta_traceStalledAddress;
1933    c_ownedReplacement;
1934    forward_eviction_to_cpu
1935    gg_deallocateL1CacheBlock;
1936    ka_wakeUpAllDependents;
1937  }
1938
1939  transition(MM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}, I) {
1940    dd_sendDataWithAllTokens;
1941    p_informL2AboutTokenLoss;
1942    forward_eviction_to_cpu
1943    m_popRequestQueue;
1944  }
1945
1946  transition({MM_W}, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request
1947    m_popRequestQueue;
1948  }
1949
1950  // Implement the migratory sharing optimization, even for persistent requests
1951  transition(MM, {Persistent_GETX, Persistent_GETS}, I_L) {
1952    ee_sendDataWithAllTokens;
1953    p_informL2AboutTokenLoss;
1954    forward_eviction_to_cpu
1955    l_popPersistentQueue;
1956  }
1957
1958  // ignore persistent requests in lockout period
1959  transition(MM_W, {Persistent_GETX, Persistent_GETS}) {
1960    l_popPersistentQueue;
1961  }
1962
1963  transition(MM_W, Use_TimeoutNoStarvers, MM) {
1964    s_deallocateTBE;
1965    jj_unsetUseTimer;
1966    kd_wakeUpDependents;
1967  }
1968
1969  transition(MM_W, Use_TimeoutNoStarvers_NoMig, M) {
1970    s_deallocateTBE;
1971    jj_unsetUseTimer;
1972    kd_wakeUpDependents;
1973  }
1974
1975  // Transitions from Dirty Exclusive
1976  transition({M, M_W}, Ifetch) {
1977    h_ifetch_hit;
1978    uu_profileInstHit;
1979    k_popMandatoryQueue;
1980  }
1981
1982  transition({M, M_W}, Load) {
1983    h_load_hit;
1984    uu_profileDataHit;
1985    k_popMandatoryQueue;
1986  }
1987
1988  transition(M, Store, MM) {
1989    hh_store_hit;
1990    uu_profileDataHit;
1991    k_popMandatoryQueue;
1992  }
1993
1994  transition(M, Atomic) {
1995    hh_store_hit;
1996    uu_profileDataHit;
1997    k_popMandatoryQueue;
1998  }
1999
2000  transition(M_W, Store, MM_W) {
2001    hh_store_hit;
2002    uu_profileDataHit;
2003    k_popMandatoryQueue;
2004  }
2005
2006  transition(M_W, Atomic) {
2007    hh_store_hit;
2008    uu_profileDataHit;
2009    k_popMandatoryQueue;
2010  }
2011
2012  transition(M, L1_Replacement, I) {
2013    ta_traceStalledAddress;
2014    c_ownedReplacement;
2015    forward_eviction_to_cpu
2016    gg_deallocateL1CacheBlock;
2017    ka_wakeUpAllDependents;
2018  }
2019
2020  transition(M, {Transient_GETX, Transient_Local_GETX}, I) {
2021    dd_sendDataWithAllTokens;
2022    p_informL2AboutTokenLoss;
2023    forward_eviction_to_cpu
2024    m_popRequestQueue;
2025  }
2026
2027  transition(M, Transient_Local_GETS, O) {
2028    d_sendDataWithToken;
2029    m_popRequestQueue;
2030  }
2031
2032  transition(M, Transient_GETS, O) {
2033    d_sendDataWithNTokenIfAvail;
2034    m_popRequestQueue;
2035  }
2036
2037  transition(M_W, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request
2038    m_popRequestQueue;
2039  }
2040
2041  transition(M, Persistent_GETX, I_L) {
2042    ee_sendDataWithAllTokens;
2043    p_informL2AboutTokenLoss;
2044    forward_eviction_to_cpu
2045    l_popPersistentQueue;
2046  }
2047
2048  transition(M, Persistent_GETS, S_L) {
2049    ff_sendDataWithAllButNorOneTokens;
2050    l_popPersistentQueue;
2051  }
2052
2053  // ignore persistent requests in lockout period
2054  transition(M_W, {Persistent_GETX, Persistent_GETS}) {
2055    l_popPersistentQueue;
2056  }
2057
2058  transition(M_W, Use_TimeoutStarverS, S_L) {
2059    s_deallocateTBE;
2060    ff_sendDataWithAllButNorOneTokens;
2061    jj_unsetUseTimer;
2062  }
2063
2064  // someone unlocked during timeout
2065  transition(M_W, {Use_TimeoutNoStarvers, Use_TimeoutNoStarvers_NoMig}, M) {
2066    s_deallocateTBE;
2067    jj_unsetUseTimer;
2068    kd_wakeUpDependents;
2069  }
2070
2071  transition(M_W, Use_TimeoutStarverX, I_L) {
2072    s_deallocateTBE;
2073    ee_sendDataWithAllTokens;
2074    forward_eviction_to_cpu;
2075    p_informL2AboutTokenLoss;
2076    jj_unsetUseTimer;
2077  }
2078
2079  // migratory
2080  transition(MM_W, {Use_TimeoutStarverX, Use_TimeoutStarverS}, I_L) {
2081    s_deallocateTBE;
2082    ee_sendDataWithAllTokens;
2083    forward_eviction_to_cpu;
2084    p_informL2AboutTokenLoss;
2085    jj_unsetUseTimer;
2086
2087  }
2088
2089  // Transient_GETX and Transient_GETS in transient states
2090  transition(OM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
2091    m_popRequestQueue;  // Even if we have the data, we can pretend we don't have it yet.
2092  }
2093
2094  transition(IS, {Transient_GETX, Transient_Local_GETX}) {
2095    t_sendAckWithCollectedTokens;
2096    m_popRequestQueue;
2097  }
2098
2099  transition(IS, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
2100    m_popRequestQueue;
2101  }
2102
2103  transition(IS, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, IS_L) {
2104    e_sendAckWithCollectedTokens;
2105    l_popPersistentQueue;
2106  }
2107
2108  transition(IS_L, {Persistent_GETX, Persistent_GETS}) {
2109    l_popPersistentQueue;
2110  }
2111
2112  transition(IM, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, IM_L) {
2113    e_sendAckWithCollectedTokens;
2114    l_popPersistentQueue;
2115  }
2116
2117  transition(IM_L, {Persistent_GETX, Persistent_GETS}) {
2118    l_popPersistentQueue;
2119  }
2120
2121  transition({SM, SM_L}, Persistent_GETX, IM_L) {
2122    e_sendAckWithCollectedTokens;
2123    forward_eviction_to_cpu
2124    l_popPersistentQueue;
2125  }
2126
2127  transition(SM, {Persistent_GETS, Persistent_GETS_Last_Token}, SM_L) {
2128    f_sendAckWithAllButNorOneTokens;
2129    l_popPersistentQueue;
2130  }
2131
2132  transition(SM_L, {Persistent_GETS, Persistent_GETS_Last_Token}) {
2133    l_popPersistentQueue;
2134  }
2135
2136  transition(OM, Persistent_GETX, IM_L) {
2137    ee_sendDataWithAllTokens;
2138    forward_eviction_to_cpu
2139    l_popPersistentQueue;
2140  }
2141
2142  transition(OM, Persistent_GETS, SM_L) {
2143    ff_sendDataWithAllButNorOneTokens;
2144    l_popPersistentQueue;
2145  }
2146
2147  transition(OM, Persistent_GETS_Last_Token, IM_L) {
2148    fo_sendDataWithOwnerToken;
2149    l_popPersistentQueue;
2150  }
2151
2152  // Transitions from IM/SM
2153
2154  transition({IM, SM}, Ack) {
2155    q_updateTokensFromResponse;
2156    n_popResponseQueue;
2157  }
2158
2159  transition(IM, Data_Shared, SM) {
2160    u_writeDataToCache;
2161    q_updateTokensFromResponse;
2162    n_popResponseQueue;
2163  }
2164
2165  transition(IM, Data_Owner, OM) {
2166    u_writeDataToCache;
2167    q_updateTokensFromResponse;
2168    n_popResponseQueue;
2169  }
2170
2171  transition(IM, Data_All_Tokens, MM_W) {
2172    u_writeDataToCache;
2173    q_updateTokensFromResponse;
2174    xx_external_store_hit;
2175    o_scheduleUseTimeout;
2176    j_unsetReissueTimer;
2177    n_popResponseQueue;
2178    kd_wakeUpDependents;
2179  }
2180
2181  transition(SM, Data_Shared) {
2182    w_assertIncomingDataAndCacheDataMatch;
2183    q_updateTokensFromResponse;
2184    n_popResponseQueue;
2185  }
2186
2187  transition(SM, Data_Owner, OM) {
2188    w_assertIncomingDataAndCacheDataMatch;
2189    q_updateTokensFromResponse;
2190    n_popResponseQueue;
2191  }
2192
2193  transition(SM, Data_All_Tokens, MM_W) {
2194    w_assertIncomingDataAndCacheDataMatch;
2195    q_updateTokensFromResponse;
2196    xx_external_store_hit;
2197    o_scheduleUseTimeout;
2198    j_unsetReissueTimer;
2199    n_popResponseQueue;
2200    kd_wakeUpDependents;
2201  }
2202
2203  transition({IM, SM}, {Transient_GETX, Transient_Local_GETX}, IM) { // We don't have the data yet, but we might have collected some tokens.  We give them up here to avoid livelock
2204    t_sendAckWithCollectedTokens;
2205    forward_eviction_to_cpu;
2206    m_popRequestQueue;
2207  }
2208
2209  transition({IM, SM}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
2210    m_popRequestQueue;
2211  }
2212
2213  transition({IM, SM}, Request_Timeout) {
2214    j_unsetReissueTimer;
2215    b_issueWriteRequest;
2216  }
2217
2218  // Transitions from OM
2219
2220  transition(OM, Ack) {
2221    q_updateTokensFromResponse;
2222    n_popResponseQueue;
2223  }
2224
2225  transition(OM, Ack_All_Tokens, MM_W) {
2226    q_updateTokensFromResponse;
2227    xx_external_store_hit;
2228    o_scheduleUseTimeout;
2229    j_unsetReissueTimer;
2230    n_popResponseQueue;
2231    kd_wakeUpDependents;
2232  }
2233
2234  transition(OM, Data_Shared) {
2235    w_assertIncomingDataAndCacheDataMatch;
2236    q_updateTokensFromResponse;
2237    n_popResponseQueue;
2238  }
2239
2240  transition(OM, Data_All_Tokens, MM_W) {
2241    w_assertIncomingDataAndCacheDataMatch;
2242    q_updateTokensFromResponse;
2243    xx_external_store_hit;
2244    o_scheduleUseTimeout;
2245    j_unsetReissueTimer;
2246    n_popResponseQueue;
2247    kd_wakeUpDependents;
2248  }
2249
2250  transition(OM, Request_Timeout) {
2251    j_unsetReissueTimer;
2252    b_issueWriteRequest;
2253  }
2254
2255  // Transitions from IS
2256
2257  transition(IS, Ack) {
2258    q_updateTokensFromResponse;
2259    n_popResponseQueue;
2260  }
2261
2262  transition(IS, Data_Shared, S) {
2263    u_writeDataToCache;
2264    q_updateTokensFromResponse;
2265    x_external_load_hit;
2266    s_deallocateTBE;
2267    j_unsetReissueTimer;
2268    n_popResponseQueue;
2269    kd_wakeUpDependents;
2270  }
2271
2272  transition(IS, Data_Owner, O) {
2273    u_writeDataToCache;
2274    q_updateTokensFromResponse;
2275    x_external_load_hit;
2276    s_deallocateTBE;
2277    j_unsetReissueTimer;
2278    n_popResponseQueue;
2279    kd_wakeUpDependents;
2280  }
2281
2282  transition(IS, Data_All_Tokens, M_W) {
2283    u_writeDataToCache;
2284    q_updateTokensFromResponse;
2285    x_external_load_hit;
2286    o_scheduleUseTimeout;
2287    j_unsetReissueTimer;
2288    n_popResponseQueue;
2289    kd_wakeUpDependents;
2290  }
2291
2292  transition(IS, Request_Timeout) {
2293    j_unsetReissueTimer;
2294    a_issueReadRequest;
2295  }
2296
2297  // Transitions from I_L
2298
2299  transition(I_L, Load, IS_L) {
2300    ii_allocateL1DCacheBlock;
2301    i_allocateTBE;
2302    a_issueReadRequest;
2303    uu_profileDataMiss;
2304    k_popMandatoryQueue;
2305  }
2306
2307  transition(I_L, Ifetch, IS_L) {
2308    pp_allocateL1ICacheBlock;
2309    i_allocateTBE;
2310    a_issueReadRequest;
2311    uu_profileInstMiss;
2312    k_popMandatoryQueue;
2313  }
2314
2315  transition(I_L, {Store, Atomic}, IM_L) {
2316    ii_allocateL1DCacheBlock;
2317    i_allocateTBE;
2318    b_issueWriteRequest;
2319    uu_profileDataMiss;
2320    k_popMandatoryQueue;
2321  }
2322
2323
2324  // Transitions from S_L
2325
2326  transition(S_L, {Store, Atomic}, SM_L) {
2327    i_allocateTBE;
2328    b_issueWriteRequest;
2329    uu_profileDataMiss;
2330    k_popMandatoryQueue;
2331  }
2332
2333  // Other transitions from *_L states
2334
2335  transition({I_L, IM_L, IS_L, S_L, SM_L}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS, Transient_GETX, Transient_Local_GETX}) {
2336    m_popRequestQueue;
2337  }
2338
2339  transition({I_L, IM_L, IS_L, S_L, SM_L}, Ack) {
2340    g_bounceResponseToStarver;
2341    n_popResponseQueue;
2342  }
2343
2344  transition({I_L, IM_L, S_L, SM_L}, {Data_Shared, Data_Owner}) {
2345    g_bounceResponseToStarver;
2346    n_popResponseQueue;
2347  }
2348
2349  transition({I_L, S_L}, Data_All_Tokens) {
2350    g_bounceResponseToStarver;
2351    n_popResponseQueue;
2352  }
2353
2354  transition(IS_L, Request_Timeout) {
2355    j_unsetReissueTimer;
2356    a_issueReadRequest;
2357  }
2358
2359  transition({IM_L, SM_L}, Request_Timeout) {
2360    j_unsetReissueTimer;
2361    b_issueWriteRequest;
2362  }
2363
2364  // Opportunisticly Complete the memory operation in the following
2365  // cases.  Note: these transitions could just use
2366  // g_bounceResponseToStarver, but if we have the data and tokens, we
2367  // might as well complete the memory request while we have the
2368  // chance (and then immediately forward on the data)
2369
2370  transition(IM_L, Data_All_Tokens, MM_W) {
2371    u_writeDataToCache;
2372    q_updateTokensFromResponse;
2373    xx_external_store_hit;
2374    j_unsetReissueTimer;
2375    o_scheduleUseTimeout;
2376    n_popResponseQueue;
2377    kd_wakeUpDependents;
2378  }
2379
2380  transition(SM_L, Data_All_Tokens, S_L) {
2381    u_writeDataToCache;
2382    q_updateTokensFromResponse;
2383    xx_external_store_hit;
2384    ff_sendDataWithAllButNorOneTokens;
2385    s_deallocateTBE;
2386    j_unsetReissueTimer;
2387    n_popResponseQueue;
2388  }
2389
2390  transition(IS_L, Data_Shared, I_L) {
2391    u_writeDataToCache;
2392    q_updateTokensFromResponse;
2393    x_external_load_hit;
2394    s_deallocateTBE;
2395    e_sendAckWithCollectedTokens;
2396    p_informL2AboutTokenLoss;
2397    j_unsetReissueTimer;
2398    n_popResponseQueue;
2399  }
2400
2401  transition(IS_L, Data_Owner, I_L) {
2402    u_writeDataToCache;
2403    q_updateTokensFromResponse;
2404    x_external_load_hit;
2405    ee_sendDataWithAllTokens;
2406    s_deallocateTBE;
2407    p_informL2AboutTokenLoss;
2408    j_unsetReissueTimer;
2409    n_popResponseQueue;
2410  }
2411
2412  transition(IS_L, Data_All_Tokens, M_W) {
2413    u_writeDataToCache;
2414    q_updateTokensFromResponse;
2415    x_external_load_hit;
2416    j_unsetReissueTimer;
2417    o_scheduleUseTimeout;
2418    n_popResponseQueue;
2419    kd_wakeUpDependents;
2420  }
2421
2422  // Own_Lock_or_Unlock
2423
2424  transition(I_L, Own_Lock_or_Unlock, I) {
2425    l_popPersistentQueue;
2426    kd_wakeUpDependents;
2427  }
2428
2429  transition(S_L, Own_Lock_or_Unlock, S) {
2430    l_popPersistentQueue;
2431    kd_wakeUpDependents;
2432  }
2433
2434  transition(IM_L, Own_Lock_or_Unlock, IM) {
2435    l_popPersistentQueue;
2436    kd_wakeUpDependents;
2437  }
2438
2439  transition(IS_L, Own_Lock_or_Unlock, IS) {
2440    l_popPersistentQueue;
2441    kd_wakeUpDependents;
2442  }
2443
2444  transition(SM_L, Own_Lock_or_Unlock, SM) {
2445    l_popPersistentQueue;
2446    kd_wakeUpDependents;
2447  }
2448}
2449