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              Addr victim := L1Icache.cacheProbe(in_msg.LineAddress);
700              trigger(Event:L1_Replacement,
701                      victim, getL1ICacheEntry(victim), L1_TBEs[victim]);
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              Addr victim := L1Dcache.cacheProbe(in_msg.LineAddress);
730              trigger(Event:L1_Replacement,
731                      victim, getL1DCacheEntry(victim), L1_TBEs[victim]);
732            }
733          }
734        }
735      }
736    }
737  }
738
739  // ACTIONS
740
741  action(a_issueReadRequest, "a", desc="Issue GETS") {
742      assert(is_valid(tbe));
743      if (tbe.IssueCount == 0) {
744        // Update outstanding requests
745        //profile_outstanding_request(outstandingRequests);
746        outstandingRequests := outstandingRequests + 1;
747      }
748
749      if (tbe.IssueCount >= retry_threshold) {
750        // Issue a persistent request if possible
751        if (okToIssueStarving(address, machineID) && (starving == false)) {
752          enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) {
753            out_msg.addr := address;
754            out_msg.Type := PersistentRequestType:GETS_PERSISTENT;
755            out_msg.Requestor := machineID;
756            out_msg.Destination.broadcast(MachineType:L1Cache);
757
758            //
759            // Currently the configuration system limits the system to only one
760            // chip.  Therefore, if we assume one shared L2 cache, then only one
761            // pertinent L2 cache exist.
762            //
763            //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
764
765            out_msg.Destination.add(mapAddressToRange(address,
766                                      MachineType:L2Cache, l2_select_low_bit,
767                                      l2_select_num_bits, intToID(0)));
768
769            out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
770            out_msg.MessageSize := MessageSizeType:Persistent_Control;
771            out_msg.Prefetch := tbe.Prefetch;
772            out_msg.AccessMode := tbe.AccessMode;
773          }
774          markPersistentEntries(address);
775          starving := true;
776
777          if (tbe.IssueCount == 0) {
778            //profile_persistent_prediction(address, tbe.TypeOfAccess);
779          }
780
781          // Update outstanding requests
782          //profile_outstanding_persistent_request(outstandingPersistentRequests);
783          outstandingPersistentRequests := outstandingPersistentRequests + 1;
784
785          // Increment IssueCount
786          tbe.IssueCount := tbe.IssueCount + 1;
787
788          tbe.WentPersistent := true;
789
790          // Do not schedule a wakeup, a persistent requests will always complete
791        }
792        else {
793
794          // We'd like to issue a persistent request, but are not allowed
795          // to issue a P.R. right now.  This, we do not increment the
796          // IssueCount.
797
798          // Set a wakeup timer
799          reissueTimerTable.set(
800            address, clockEdge() + cyclesToTicks(reissue_wakeup_latency));
801
802        }
803      } else {
804        // Make a normal request
805        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
806          out_msg.addr := address;
807          out_msg.Type := CoherenceRequestType:GETS;
808          out_msg.Requestor := machineID;
809          out_msg.Destination.add(mapAddressToRange(address,
810                                    MachineType:L2Cache, l2_select_low_bit,
811                                    l2_select_num_bits, intToID(0)));
812
813          out_msg.RetryNum := tbe.IssueCount;
814          if (tbe.IssueCount == 0) {
815            out_msg.MessageSize := MessageSizeType:Request_Control;
816          } else {
817            out_msg.MessageSize := MessageSizeType:Reissue_Control;
818          }
819          out_msg.Prefetch := tbe.Prefetch;
820          out_msg.AccessMode := tbe.AccessMode;
821        }
822
823        // send to other local L1s, with local bit set
824        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
825          out_msg.addr := address;
826          out_msg.Type := CoherenceRequestType:GETS;
827          out_msg.Requestor := machineID;
828          //
829          // Since only one chip, assuming all L1 caches are local
830          //
831          //out_msg.Destination := getOtherLocalL1IDs(machineID);
832          out_msg.Destination.broadcast(MachineType:L1Cache);
833          out_msg.Destination.remove(machineID);
834
835          out_msg.RetryNum := tbe.IssueCount;
836          out_msg.isLocal := true;
837          if (tbe.IssueCount == 0) {
838            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
839          } else {
840            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
841          }
842          out_msg.Prefetch := tbe.Prefetch;
843          out_msg.AccessMode := tbe.AccessMode;
844        }
845
846        // Increment IssueCount
847        tbe.IssueCount := tbe.IssueCount + 1;
848
849        // Set a wakeup timer
850
851        if (dynamic_timeout_enabled) {
852          reissueTimerTable.set(
853            address, clockEdge() + cyclesToTicks(averageLatencyEstimate()));
854        } else {
855          reissueTimerTable.set(
856            address, clockEdge() + cyclesToTicks(fixed_timeout_latency));
857        }
858
859      }
860  }
861
862  action(b_issueWriteRequest, "b", desc="Issue GETX") {
863
864      assert(is_valid(tbe));
865      if (tbe.IssueCount == 0) {
866        // Update outstanding requests
867        //profile_outstanding_request(outstandingRequests);
868        outstandingRequests := outstandingRequests + 1;
869      }
870
871      if (tbe.IssueCount >= retry_threshold) {
872        // Issue a persistent request if possible
873        if ( okToIssueStarving(address, machineID) && (starving == false)) {
874          enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) {
875            out_msg.addr := address;
876            out_msg.Type := PersistentRequestType:GETX_PERSISTENT;
877            out_msg.Requestor := machineID;
878            out_msg.Destination.broadcast(MachineType:L1Cache);
879
880            //
881            // Currently the configuration system limits the system to only one
882            // chip.  Therefore, if we assume one shared L2 cache, then only one
883            // pertinent L2 cache exist.
884            //
885            //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
886
887            out_msg.Destination.add(mapAddressToRange(address,
888                                      MachineType:L2Cache, l2_select_low_bit,
889                                      l2_select_num_bits, intToID(0)));
890
891            out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
892            out_msg.MessageSize := MessageSizeType:Persistent_Control;
893            out_msg.Prefetch := tbe.Prefetch;
894            out_msg.AccessMode := tbe.AccessMode;
895          }
896          markPersistentEntries(address);
897          starving := true;
898
899          // Update outstanding requests
900          //profile_outstanding_persistent_request(outstandingPersistentRequests);
901          outstandingPersistentRequests := outstandingPersistentRequests + 1;
902
903          if (tbe.IssueCount == 0) {
904            //profile_persistent_prediction(address, tbe.TypeOfAccess);
905          }
906
907          // Increment IssueCount
908          tbe.IssueCount := tbe.IssueCount + 1;
909
910          tbe.WentPersistent := true;
911
912          // Do not schedule a wakeup, a persistent requests will always complete
913        }
914        else {
915
916          // We'd like to issue a persistent request, but are not allowed
917          // to issue a P.R. right now.  This, we do not increment the
918          // IssueCount.
919
920          // Set a wakeup timer
921          reissueTimerTable.set(
922            address, clockEdge() + cyclesToTicks(reissue_wakeup_latency));
923        }
924
925      } else  {
926        // Make a normal request
927        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
928          out_msg.addr := address;
929          out_msg.Type := CoherenceRequestType:GETX;
930          out_msg.Requestor := machineID;
931
932          out_msg.Destination.add(mapAddressToRange(address,
933                                    MachineType:L2Cache, l2_select_low_bit,
934                                    l2_select_num_bits, intToID(0)));
935
936          out_msg.RetryNum := tbe.IssueCount;
937
938          if (tbe.IssueCount == 0) {
939            out_msg.MessageSize := MessageSizeType:Request_Control;
940          } else {
941            out_msg.MessageSize := MessageSizeType:Reissue_Control;
942          }
943          out_msg.Prefetch := tbe.Prefetch;
944          out_msg.AccessMode := tbe.AccessMode;
945        }
946
947        // send to other local L1s too
948        enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
949          out_msg.addr := address;
950          out_msg.Type := CoherenceRequestType:GETX;
951          out_msg.Requestor := machineID;
952          out_msg.isLocal := true;
953
954          //
955          // Since only one chip, assuming all L1 caches are local
956          //
957          //out_msg.Destination := getOtherLocalL1IDs(machineID);
958          out_msg.Destination.broadcast(MachineType:L1Cache);
959          out_msg.Destination.remove(machineID);
960
961          out_msg.RetryNum := tbe.IssueCount;
962          if (tbe.IssueCount == 0) {
963            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
964          } else {
965            out_msg.MessageSize := MessageSizeType:Broadcast_Control;
966          }
967          out_msg.Prefetch := tbe.Prefetch;
968          out_msg.AccessMode := tbe.AccessMode;
969        }
970
971        // Increment IssueCount
972        tbe.IssueCount := tbe.IssueCount + 1;
973
974        DPRINTF(RubySlicc, "incremented issue count to %d\n",
975                tbe.IssueCount);
976
977        // Set a wakeup timer
978        if (dynamic_timeout_enabled) {
979          reissueTimerTable.set(
980            address, clockEdge() + cyclesToTicks(averageLatencyEstimate()));
981        } else {
982          reissueTimerTable.set(
983            address, clockEdge() + cyclesToTicks(fixed_timeout_latency));
984        }
985      }
986  }
987
988  action(bb_bounceResponse, "\b", desc="Bounce tokens and data to memory") {
989    peek(responseNetwork_in, ResponseMsg) {
990      // FIXME, should use a 3rd vnet
991      enqueue(responseNetwork_out, ResponseMsg, 1) {
992        out_msg.addr := address;
993        out_msg.Type := in_msg.Type;
994        out_msg.Sender := machineID;
995        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
996        out_msg.Tokens := in_msg.Tokens;
997        out_msg.MessageSize := in_msg.MessageSize;
998        out_msg.DataBlk := in_msg.DataBlk;
999        out_msg.Dirty := in_msg.Dirty;
1000      }
1001    }
1002  }
1003
1004  action(c_ownedReplacement, "c", desc="Issue writeback") {
1005    assert(is_valid(cache_entry));
1006    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1007      out_msg.addr := address;
1008      out_msg.Sender := machineID;
1009
1010      out_msg.Destination.add(mapAddressToRange(address,
1011                                MachineType:L2Cache, l2_select_low_bit,
1012                                l2_select_num_bits, intToID(0)));
1013
1014      out_msg.Tokens := cache_entry.Tokens;
1015      out_msg.DataBlk := cache_entry.DataBlk;
1016      out_msg.Dirty := cache_entry.Dirty;
1017      out_msg.Type := CoherenceResponseType:WB_OWNED;
1018
1019      // always send the data?
1020      out_msg.MessageSize := MessageSizeType:Writeback_Data;
1021    }
1022    cache_entry.Tokens := 0;
1023  }
1024
1025  action(cc_sharedReplacement, "\c", desc="Issue shared writeback") {
1026
1027    // don't send writeback if replacing block with no tokens
1028    assert(is_valid(cache_entry));
1029    assert (cache_entry.Tokens > 0);
1030    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1031        out_msg.addr := address;
1032        out_msg.Sender := machineID;
1033
1034        out_msg.Destination.add(mapAddressToRange(address,
1035                                  MachineType:L2Cache, l2_select_low_bit,
1036                                  l2_select_num_bits, intToID(0)));
1037
1038        out_msg.Tokens := cache_entry.Tokens;
1039        out_msg.DataBlk := cache_entry.DataBlk;
1040        // assert(cache_entry.Dirty == false);
1041        out_msg.Dirty := false;
1042
1043        out_msg.MessageSize := MessageSizeType:Writeback_Data;
1044        out_msg.Type := CoherenceResponseType:WB_SHARED_DATA;
1045    }
1046    cache_entry.Tokens := 0;
1047  }
1048
1049  action(tr_tokenReplacement, "tr", desc="Issue token writeback") {
1050    assert(is_valid(cache_entry));
1051    if (cache_entry.Tokens > 0) {
1052      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1053        out_msg.addr := address;
1054        out_msg.Sender := machineID;
1055
1056        out_msg.Destination.add(mapAddressToRange(address,
1057                                  MachineType:L2Cache, l2_select_low_bit,
1058                                  l2_select_num_bits, intToID(0)));
1059
1060        out_msg.Tokens := cache_entry.Tokens;
1061        out_msg.DataBlk := cache_entry.DataBlk;
1062        // assert(cache_entry.Dirty == false);
1063        out_msg.Dirty := false;
1064
1065        // always send the data?
1066        out_msg.MessageSize := MessageSizeType:Writeback_Control;
1067        out_msg.Type := CoherenceResponseType:WB_TOKENS;
1068      }
1069    }
1070    cache_entry.Tokens := 0;
1071  }
1072
1073
1074  action(d_sendDataWithToken, "d", desc="Send data and a token from cache to requestor") {
1075    assert(is_valid(cache_entry));
1076    peek(requestNetwork_in, RequestMsg) {
1077      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1078        out_msg.addr := address;
1079        out_msg.Type := CoherenceResponseType:DATA_SHARED;
1080        out_msg.Sender := machineID;
1081        out_msg.Destination.add(in_msg.Requestor);
1082        out_msg.Tokens := 1;
1083        out_msg.DataBlk := cache_entry.DataBlk;
1084        // out_msg.Dirty := cache_entry.Dirty;
1085        out_msg.Dirty := false;
1086        if (in_msg.isLocal) {
1087          out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1088        } else {
1089          out_msg.MessageSize := MessageSizeType:Response_Data;
1090        }
1091      }
1092    }
1093    cache_entry.Tokens := cache_entry.Tokens - 1;
1094    assert(cache_entry.Tokens >= 1);
1095  }
1096
1097  action(d_sendDataWithNTokenIfAvail, "\dd", desc="Send data and a token from cache to requestor") {
1098    assert(is_valid(cache_entry));
1099    peek(requestNetwork_in, RequestMsg) {
1100      if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
1101        enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1102          out_msg.addr := address;
1103          out_msg.Type := CoherenceResponseType:DATA_SHARED;
1104          out_msg.Sender := machineID;
1105          out_msg.Destination.add(in_msg.Requestor);
1106          out_msg.Tokens := N_tokens;
1107          out_msg.DataBlk := cache_entry.DataBlk;
1108          // out_msg.Dirty := cache_entry.Dirty;
1109          out_msg.Dirty := false;
1110          if (in_msg.isLocal) {
1111            out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1112          } else {
1113            out_msg.MessageSize := MessageSizeType:Response_Data;
1114          }
1115        }
1116        cache_entry.Tokens := cache_entry.Tokens - N_tokens;
1117      }
1118      else if (cache_entry.Tokens > 1) {
1119        enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1120          out_msg.addr := address;
1121          out_msg.Type := CoherenceResponseType:DATA_SHARED;
1122          out_msg.Sender := machineID;
1123          out_msg.Destination.add(in_msg.Requestor);
1124          out_msg.Tokens := 1;
1125          out_msg.DataBlk := cache_entry.DataBlk;
1126          // out_msg.Dirty := cache_entry.Dirty;
1127          out_msg.Dirty := false;
1128          if (in_msg.isLocal) {
1129            out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1130          } else {
1131            out_msg.MessageSize := MessageSizeType:Response_Data;
1132          }
1133        }
1134        cache_entry.Tokens := cache_entry.Tokens - 1;
1135      }
1136    }
1137//    assert(cache_entry.Tokens >= 1);
1138  }
1139
1140  action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") {
1141    peek(requestNetwork_in, RequestMsg) {
1142    assert(is_valid(cache_entry));
1143      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1144        out_msg.addr := address;
1145        out_msg.Type := CoherenceResponseType:DATA_OWNER;
1146        out_msg.Sender := machineID;
1147        out_msg.Destination.add(in_msg.Requestor);
1148        assert(cache_entry.Tokens > (max_tokens() / 2));
1149        out_msg.Tokens := cache_entry.Tokens;
1150        out_msg.DataBlk := cache_entry.DataBlk;
1151        out_msg.Dirty := cache_entry.Dirty;
1152        if (in_msg.isLocal) {
1153          out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
1154        } else {
1155          out_msg.MessageSize := MessageSizeType:Response_Data;
1156        }
1157      }
1158    }
1159    cache_entry.Tokens := 0;
1160  }
1161
1162  action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") {
1163    // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1164    assert(is_valid(cache_entry));
1165    if (cache_entry.Tokens > 0) {
1166      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1167        out_msg.addr := address;
1168        if (cache_entry.Tokens > (max_tokens() / 2)) {
1169          out_msg.Type := CoherenceResponseType:DATA_OWNER;
1170        } else {
1171          out_msg.Type := CoherenceResponseType:ACK;
1172        }
1173        out_msg.Sender := machineID;
1174        out_msg.Destination.add(persistentTable.findSmallest(address));
1175        assert(cache_entry.Tokens >= 1);
1176        out_msg.Tokens := cache_entry.Tokens;
1177        out_msg.DataBlk := cache_entry.DataBlk;
1178        out_msg.MessageSize := MessageSizeType:Response_Control;
1179      }
1180    }
1181    cache_entry.Tokens := 0;
1182  }
1183
1184  action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") {
1185    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1186    assert(is_valid(cache_entry));
1187    assert(cache_entry.Tokens > 0);
1188    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1189      out_msg.addr := address;
1190      out_msg.Type := CoherenceResponseType:DATA_OWNER;
1191      out_msg.Sender := machineID;
1192      out_msg.Destination.add(persistentTable.findSmallest(address));
1193      assert(cache_entry.Tokens > (max_tokens() / 2));
1194      out_msg.Tokens := cache_entry.Tokens;
1195      out_msg.DataBlk := cache_entry.DataBlk;
1196      out_msg.Dirty := cache_entry.Dirty;
1197      out_msg.MessageSize := MessageSizeType:Response_Data;
1198    }
1199    cache_entry.Tokens := 0;
1200  }
1201
1202  action(f_sendAckWithAllButNorOneTokens, "f", desc="Send ack with all our tokens but one to starver.") {
1203    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1204    assert(is_valid(cache_entry));
1205    assert(cache_entry.Tokens > 0);
1206    if (cache_entry.Tokens > 1) {
1207      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1208        out_msg.addr := address;
1209        if (cache_entry.Tokens > (max_tokens() / 2)) {
1210          out_msg.Type := CoherenceResponseType:DATA_OWNER;
1211        } else {
1212          out_msg.Type := CoherenceResponseType:ACK;
1213        }
1214        out_msg.Sender := machineID;
1215        out_msg.Destination.add(persistentTable.findSmallest(address));
1216        assert(cache_entry.Tokens >= 1);
1217        if (cache_entry.Tokens > N_tokens) {
1218          out_msg.Tokens := cache_entry.Tokens - N_tokens;
1219        } else {
1220          out_msg.Tokens := cache_entry.Tokens - 1;
1221        }
1222        out_msg.DataBlk := cache_entry.DataBlk;
1223        out_msg.MessageSize := MessageSizeType:Response_Control;
1224      }
1225    }
1226    if (cache_entry.Tokens > N_tokens) {
1227      cache_entry.Tokens := N_tokens;
1228    } else {
1229      cache_entry.Tokens := 1;
1230    }
1231  }
1232
1233  action(ff_sendDataWithAllButNorOneTokens, "\f", desc="Send data and out tokens but one to starver") {
1234    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1235    assert(is_valid(cache_entry));
1236    assert(cache_entry.Tokens > ((max_tokens() / 2) + 1));
1237    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1238        out_msg.addr := address;
1239        out_msg.Type := CoherenceResponseType:DATA_OWNER;
1240        out_msg.Sender := machineID;
1241        out_msg.Destination.add(persistentTable.findSmallest(address));
1242        if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
1243          out_msg.Tokens := cache_entry.Tokens - N_tokens;
1244        } else {
1245          out_msg.Tokens := cache_entry.Tokens - 1;
1246        }
1247        assert(out_msg.Tokens > (max_tokens() / 2));
1248        out_msg.DataBlk := cache_entry.DataBlk;
1249        out_msg.Dirty := cache_entry.Dirty;
1250        out_msg.MessageSize := MessageSizeType:Response_Data;
1251    }
1252    if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
1253      cache_entry.Tokens := N_tokens;
1254    } else {
1255      cache_entry.Tokens := 1;
1256    }
1257  }
1258
1259  action(fo_sendDataWithOwnerToken, "fo", desc="Send data and owner tokens") {
1260    assert(is_valid(cache_entry));
1261    assert(cache_entry.Tokens == ((max_tokens() / 2) + 1));
1262    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1263        out_msg.addr := address;
1264        out_msg.Type := CoherenceResponseType:DATA_OWNER;
1265        out_msg.Sender := machineID;
1266        out_msg.Destination.add(persistentTable.findSmallest(address));
1267        out_msg.Tokens := cache_entry.Tokens;
1268        assert(out_msg.Tokens > (max_tokens() / 2));
1269        out_msg.DataBlk := cache_entry.DataBlk;
1270        out_msg.Dirty := cache_entry.Dirty;
1271        out_msg.MessageSize := MessageSizeType:Response_Data;
1272    }
1273    cache_entry.Tokens := 0;
1274  }
1275
1276  action(g_bounceResponseToStarver, "g", desc="Redirect response to starving processor") {
1277    // assert(persistentTable.isLocked(address));
1278
1279    peek(responseNetwork_in, ResponseMsg) {
1280      // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
1281      // FIXME, should use a 3rd vnet in some cases
1282      enqueue(responseNetwork_out, ResponseMsg, 1) {
1283        out_msg.addr := address;
1284        out_msg.Type := in_msg.Type;
1285        out_msg.Sender := machineID;
1286        out_msg.Destination.add(persistentTable.findSmallest(address));
1287        out_msg.Tokens := in_msg.Tokens;
1288        out_msg.DataBlk := in_msg.DataBlk;
1289        out_msg.Dirty := in_msg.Dirty;
1290        out_msg.MessageSize := in_msg.MessageSize;
1291      }
1292    }
1293  }
1294
1295  action(h_load_hit, "hd", desc="Notify sequencer the load completed.") {
1296    assert(is_valid(cache_entry));
1297    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1298            address, cache_entry.DataBlk);
1299
1300    L1Dcache.setMRU(cache_entry);
1301    sequencer.readCallback(address, cache_entry.DataBlk, false,
1302                           MachineType:L1Cache);
1303  }
1304
1305  action(h_ifetch_hit, "hi", desc="Notify sequencer the load completed.") {
1306    assert(is_valid(cache_entry));
1307    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1308            address, cache_entry.DataBlk);
1309
1310    L1Icache.setMRU(cache_entry);
1311    sequencer.readCallback(address, cache_entry.DataBlk, false,
1312                           MachineType:L1Cache);
1313  }
1314
1315  action(x_external_load_hit, "x", desc="Notify sequencer the load completed.") {
1316    assert(is_valid(cache_entry));
1317    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1318            address, cache_entry.DataBlk);
1319    peek(responseNetwork_in, ResponseMsg) {
1320      L1Icache.setMRU(address);
1321      L1Dcache.setMRU(address);
1322      sequencer.readCallback(address, cache_entry.DataBlk,
1323                             isExternalHit(address, in_msg.Sender),
1324                             machineIDToMachineType(in_msg.Sender));
1325    }
1326  }
1327
1328  action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
1329    assert(is_valid(cache_entry));
1330    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1331            address, cache_entry.DataBlk);
1332
1333    L1Dcache.setMRU(cache_entry);
1334    sequencer.writeCallback(address, cache_entry.DataBlk, false,
1335                            MachineType:L1Cache);
1336    cache_entry.Dirty := true;
1337    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
1338  }
1339
1340  action(xx_external_store_hit, "\x", desc="Notify sequencer that store completed.") {
1341    assert(is_valid(cache_entry));
1342    DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n",
1343            address, cache_entry.DataBlk);
1344    peek(responseNetwork_in, ResponseMsg) {
1345      L1Icache.setMRU(address);
1346      L1Dcache.setMRU(address);
1347      sequencer.writeCallback(address, cache_entry.DataBlk,
1348                              isExternalHit(address, in_msg.Sender),
1349                              machineIDToMachineType(in_msg.Sender));
1350    }
1351    cache_entry.Dirty := true;
1352    DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
1353  }
1354
1355  action(i_allocateTBE, "i", desc="Allocate TBE") {
1356    check_allocate(L1_TBEs);
1357    L1_TBEs.allocate(address);
1358    set_tbe(L1_TBEs[address]);
1359    tbe.IssueCount := 0;
1360    peek(mandatoryQueue_in, RubyRequest) {
1361      tbe.PC := in_msg.ProgramCounter;
1362      tbe.TypeOfAccess := cache_request_type_to_access_type(in_msg.Type);
1363      if (in_msg.Type == RubyRequestType:ATOMIC) {
1364        tbe.IsAtomic := true;
1365      }
1366      tbe.Prefetch := in_msg.Prefetch;
1367      tbe.AccessMode := in_msg.AccessMode;
1368    }
1369    tbe.IssueTime := curCycle();
1370  }
1371
1372  action(ta_traceStalledAddress, "ta", desc="Trace Stalled Address") {
1373    peek(mandatoryQueue_in, RubyRequest) {
1374      APPEND_TRANSITION_COMMENT(in_msg.LineAddress);
1375    }
1376  }
1377
1378  action(j_unsetReissueTimer, "j", desc="Unset reissue timer.") {
1379    if (reissueTimerTable.isSet(address)) {
1380      reissueTimerTable.unset(address);
1381    }
1382  }
1383
1384  action(jj_unsetUseTimer, "\j", desc="Unset use timer.") {
1385    useTimerTable.unset(address);
1386  }
1387
1388  action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
1389    mandatoryQueue_in.dequeue(clockEdge());
1390  }
1391
1392  action(l_popPersistentQueue, "l", desc="Pop persistent queue.") {
1393    persistentNetwork_in.dequeue(clockEdge());
1394  }
1395
1396  action(m_popRequestQueue, "m", desc="Pop request queue.") {
1397    requestNetwork_in.dequeue(clockEdge());
1398  }
1399
1400  action(n_popResponseQueue, "n", desc="Pop response queue") {
1401    responseNetwork_in.dequeue(clockEdge());
1402  }
1403
1404  action(o_scheduleUseTimeout, "o", desc="Schedule a use timeout.") {
1405    useTimerTable.set(
1406        address, clockEdge() + cyclesToTicks(use_timeout_latency));
1407  }
1408
1409  action(p_informL2AboutTokenLoss, "p", desc="Inform L2 about loss of all tokens") {
1410    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1411       out_msg.addr := address;
1412       out_msg.Type := CoherenceResponseType:INV;
1413       out_msg.Tokens := 0;
1414       out_msg.Sender := machineID;
1415
1416       out_msg.Destination.add(mapAddressToRange(address,
1417                                 MachineType:L2Cache, l2_select_low_bit,
1418                                 l2_select_num_bits, intToID(0)));
1419       out_msg.MessageSize := MessageSizeType:Response_Control;
1420    }
1421  }
1422
1423  action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") {
1424    peek(responseNetwork_in, ResponseMsg) {
1425      assert(is_valid(cache_entry));
1426      assert(in_msg.Tokens != 0);
1427      DPRINTF(RubySlicc, "L1 received tokens for address: %#x, tokens: %d\n",
1428              in_msg.addr, in_msg.Tokens);
1429      cache_entry.Tokens := cache_entry.Tokens + in_msg.Tokens;
1430      DPRINTF(RubySlicc, "%d\n", cache_entry.Tokens);
1431
1432      if (cache_entry.Dirty == false && in_msg.Dirty) {
1433        cache_entry.Dirty := true;
1434      }
1435    }
1436  }
1437
1438  action(s_deallocateTBE, "s", desc="Deallocate TBE") {
1439
1440    assert(is_valid(tbe));
1441    if (tbe.WentPersistent) {
1442      // assert(starving);
1443      outstandingRequests := outstandingRequests - 1;
1444      enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) {
1445        out_msg.addr := address;
1446        out_msg.Type := PersistentRequestType:DEACTIVATE_PERSISTENT;
1447        out_msg.Requestor := machineID;
1448        out_msg.Destination.broadcast(MachineType:L1Cache);
1449
1450        //
1451        // Currently the configuration system limits the system to only one
1452        // chip.  Therefore, if we assume one shared L2 cache, then only one
1453        // pertinent L2 cache exist.
1454        //
1455        //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
1456
1457        out_msg.Destination.add(mapAddressToRange(address,
1458                                  MachineType:L2Cache, l2_select_low_bit,
1459                                  l2_select_num_bits, intToID(0)));
1460
1461        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
1462        out_msg.MessageSize := MessageSizeType:Persistent_Control;
1463      }
1464      starving := false;
1465    }
1466
1467    // Update average latency
1468    if (tbe.IssueCount <= 1) {
1469      if (tbe.ExternalResponse) {
1470        updateAverageLatencyEstimate(curCycle() - tbe.IssueTime);
1471      }
1472    }
1473
1474    // Profile
1475    //if (tbe.WentPersistent) {
1476    //  profile_token_retry(address, tbe.TypeOfAccess, 2);
1477    //}
1478    //else {
1479    //  profile_token_retry(address, tbe.TypeOfAccess, 1);
1480    //}
1481
1482    //profile_token_retry(address, tbe.TypeOfAccess, tbe.IssueCount);
1483    L1_TBEs.deallocate(address);
1484    unset_tbe();
1485  }
1486
1487  action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") {
1488    assert(is_valid(cache_entry));
1489    if (cache_entry.Tokens > 0) {
1490      peek(requestNetwork_in, RequestMsg) {
1491        enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
1492          out_msg.addr := address;
1493          if (cache_entry.Tokens > (max_tokens() / 2)) {
1494            out_msg.Type := CoherenceResponseType:DATA_OWNER;
1495          } else {
1496            out_msg.Type := CoherenceResponseType:ACK;
1497          }
1498          out_msg.Sender := machineID;
1499          out_msg.Destination.add(in_msg.Requestor);
1500          assert(cache_entry.Tokens >= 1);
1501          out_msg.Tokens := cache_entry.Tokens;
1502          out_msg.DataBlk := cache_entry.DataBlk;
1503          out_msg.MessageSize := MessageSizeType:Response_Control;
1504        }
1505      }
1506    }
1507    cache_entry.Tokens := 0;
1508  }
1509
1510  action(u_writeDataToCache, "u", desc="Write data to cache") {
1511    peek(responseNetwork_in, ResponseMsg) {
1512      assert(is_valid(cache_entry));
1513      cache_entry.DataBlk := in_msg.DataBlk;
1514      if (cache_entry.Dirty == false && in_msg.Dirty) {
1515        cache_entry.Dirty := in_msg.Dirty;
1516      }
1517
1518    }
1519  }
1520
1521  action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block.  Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
1522    assert(getTokens(cache_entry) == 0);
1523    if (L1Dcache.isTagPresent(address)) {
1524      L1Dcache.deallocate(address);
1525    } else {
1526      L1Icache.deallocate(address);
1527    }
1528    unset_cache_entry();
1529  }
1530
1531  action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
1532    if (is_valid(cache_entry)) {
1533    } else {
1534      set_cache_entry(L1Dcache.allocate(address, new Entry));
1535    }
1536  }
1537
1538  action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
1539    if (is_valid(cache_entry)) {
1540    } else {
1541      set_cache_entry(L1Icache.allocate(address, new Entry));
1542    }
1543  }
1544
1545  action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
1546    if (send_evictions) {
1547      DPRINTF(RubySlicc, "Sending invalidation for %#x to the CPU\n", address);
1548      sequencer.evictionCallback(address);
1549    }
1550  }
1551
1552  action(uu_profileInstMiss, "\uim", desc="Profile the demand miss") {
1553      ++L1Icache.demand_misses;
1554  }
1555
1556  action(uu_profileInstHit, "\uih", desc="Profile the demand hit") {
1557      ++L1Icache.demand_hits;
1558  }
1559
1560  action(uu_profileDataMiss, "\udm", desc="Profile the demand miss") {
1561      ++L1Dcache.demand_misses;
1562  }
1563
1564  action(uu_profileDataHit, "\udh", desc="Profile the demand hit") {
1565      ++L1Dcache.demand_hits;
1566  }
1567
1568  action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") {
1569    peek(responseNetwork_in, ResponseMsg) {
1570      assert(is_valid(cache_entry));
1571      assert(cache_entry.DataBlk == in_msg.DataBlk);
1572    }
1573  }
1574
1575  action(zz_stallAndWaitMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
1576    peek(mandatoryQueue_in, RubyRequest) {
1577      APPEND_TRANSITION_COMMENT(in_msg.LineAddress);
1578    }
1579    stall_and_wait(mandatoryQueue_in, address);
1580  }
1581
1582  action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
1583    wakeUpBuffers(address);
1584  }
1585
1586  action(ka_wakeUpAllDependents, "ka", desc="wake-up all dependents") {
1587    wakeUpAllBuffers();
1588  }
1589
1590  //*****************************************************
1591  // TRANSITIONS
1592  //*****************************************************
1593
1594  // Transitions for Load/Store/L2_Replacement from transient states
1595  transition({IM, SM, OM, IS, IM_L, IS_L, I_L, S_L, SM_L, M_W, MM_W}, L1_Replacement) {
1596    ta_traceStalledAddress;
1597    zz_stallAndWaitMandatoryQueue;
1598  }
1599
1600  transition({IM, SM, OM, IS, IM_L, IS_L, SM_L}, {Store, Atomic}) {
1601    zz_stallAndWaitMandatoryQueue;
1602  }
1603
1604  transition({IM, IS, IM_L, IS_L}, {Load, Ifetch}) {
1605    zz_stallAndWaitMandatoryQueue;
1606  }
1607
1608  // Lockdowns
1609  transition({NP, I, S, O, M, MM, M_W, MM_W, IM, SM, OM, IS}, Own_Lock_or_Unlock) {
1610    l_popPersistentQueue;
1611  }
1612
1613  // Transitions from NP
1614  transition(NP, Load, IS) {
1615    ii_allocateL1DCacheBlock;
1616    i_allocateTBE;
1617    a_issueReadRequest;
1618    uu_profileDataMiss;
1619    k_popMandatoryQueue;
1620  }
1621
1622  transition(NP, Ifetch, IS) {
1623    pp_allocateL1ICacheBlock;
1624    i_allocateTBE;
1625    a_issueReadRequest;
1626    uu_profileInstMiss;
1627    k_popMandatoryQueue;
1628  }
1629
1630  transition(NP, {Store, Atomic}, IM) {
1631    ii_allocateL1DCacheBlock;
1632    i_allocateTBE;
1633    b_issueWriteRequest;
1634    uu_profileDataMiss;
1635    k_popMandatoryQueue;
1636  }
1637
1638  transition(NP, {Ack, Data_Shared, Data_Owner, Data_All_Tokens}) {
1639    bb_bounceResponse;
1640    n_popResponseQueue;
1641  }
1642
1643  transition(NP, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) {
1644    m_popRequestQueue;
1645  }
1646
1647  transition(NP, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, I_L) {
1648    l_popPersistentQueue;
1649  }
1650
1651  // Transitions from Idle
1652  transition(I, Load, IS) {
1653    i_allocateTBE;
1654    a_issueReadRequest;
1655    uu_profileDataMiss;
1656    k_popMandatoryQueue;
1657  }
1658
1659  transition(I, Ifetch, IS) {
1660    i_allocateTBE;
1661    a_issueReadRequest;
1662    uu_profileInstMiss;
1663    k_popMandatoryQueue;
1664  }
1665
1666  transition(I, {Store, Atomic}, IM) {
1667    i_allocateTBE;
1668    b_issueWriteRequest;
1669    uu_profileDataMiss;
1670    k_popMandatoryQueue;
1671  }
1672
1673  transition(I, L1_Replacement) {
1674    ta_traceStalledAddress;
1675    tr_tokenReplacement;
1676    gg_deallocateL1CacheBlock;
1677    ka_wakeUpAllDependents;
1678  }
1679
1680  transition(I, {Transient_GETX, Transient_Local_GETX}) {
1681    t_sendAckWithCollectedTokens;
1682    m_popRequestQueue;
1683  }
1684
1685  transition(I, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
1686    m_popRequestQueue;
1687  }
1688
1689  transition(I, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, I_L) {
1690    e_sendAckWithCollectedTokens;
1691    l_popPersistentQueue;
1692  }
1693
1694  transition(I_L, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}) {
1695    l_popPersistentQueue;
1696  }
1697
1698  transition(I, Ack) {
1699    q_updateTokensFromResponse;
1700    n_popResponseQueue;
1701  }
1702
1703  transition(I, Data_Shared, S) {
1704    u_writeDataToCache;
1705    q_updateTokensFromResponse;
1706    n_popResponseQueue;
1707  }
1708
1709  transition(I, Data_Owner, O) {
1710    u_writeDataToCache;
1711    q_updateTokensFromResponse;
1712    n_popResponseQueue;
1713  }
1714
1715  transition(I, Data_All_Tokens, M) {
1716    u_writeDataToCache;
1717    q_updateTokensFromResponse;
1718    n_popResponseQueue;
1719  }
1720
1721  // Transitions from Shared
1722  transition({S, SM, S_L, SM_L}, Load) {
1723    h_load_hit;
1724    uu_profileDataHit;
1725    k_popMandatoryQueue;
1726  }
1727
1728  transition({S, SM, S_L, SM_L}, Ifetch) {
1729    h_ifetch_hit;
1730    uu_profileInstHit;
1731    k_popMandatoryQueue;
1732  }
1733
1734  transition(S, {Store, Atomic}, SM) {
1735    i_allocateTBE;
1736    b_issueWriteRequest;
1737    uu_profileDataMiss;
1738    k_popMandatoryQueue;
1739  }
1740
1741  transition(S, L1_Replacement, I) {
1742    ta_traceStalledAddress;
1743    cc_sharedReplacement; // Only needed in some cases
1744    forward_eviction_to_cpu;
1745    gg_deallocateL1CacheBlock;
1746    ka_wakeUpAllDependents;
1747  }
1748
1749  transition(S, {Transient_GETX, Transient_Local_GETX}, I) {
1750    t_sendAckWithCollectedTokens;
1751    p_informL2AboutTokenLoss;
1752    forward_eviction_to_cpu
1753    m_popRequestQueue;
1754  }
1755
1756  // only owner responds to non-local requests
1757  transition(S, Transient_GETS) {
1758    m_popRequestQueue;
1759  }
1760
1761  transition(S, Transient_Local_GETS) {
1762    d_sendDataWithToken;
1763    m_popRequestQueue;
1764  }
1765
1766  transition(S, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) {
1767    m_popRequestQueue;
1768  }
1769
1770  transition({S, S_L}, Persistent_GETX, I_L) {
1771    e_sendAckWithCollectedTokens;
1772    p_informL2AboutTokenLoss;
1773    forward_eviction_to_cpu
1774    l_popPersistentQueue;
1775  }
1776
1777  transition(S, {Persistent_GETS, Persistent_GETS_Last_Token}, S_L) {
1778    f_sendAckWithAllButNorOneTokens;
1779    l_popPersistentQueue;
1780  }
1781
1782  transition(S_L, {Persistent_GETS, Persistent_GETS_Last_Token}) {
1783    l_popPersistentQueue;
1784  }
1785
1786  transition(S, Ack) {
1787    q_updateTokensFromResponse;
1788    n_popResponseQueue;
1789  }
1790
1791  transition(S, Data_Shared) {
1792    w_assertIncomingDataAndCacheDataMatch;
1793    q_updateTokensFromResponse;
1794    n_popResponseQueue;
1795  }
1796
1797  transition(S, Data_Owner, O) {
1798    w_assertIncomingDataAndCacheDataMatch;
1799    q_updateTokensFromResponse;
1800    n_popResponseQueue;
1801  }
1802
1803  transition(S, Data_All_Tokens, M) {
1804    w_assertIncomingDataAndCacheDataMatch;
1805    q_updateTokensFromResponse;
1806    n_popResponseQueue;
1807  }
1808
1809  // Transitions from Owned
1810  transition({O, OM}, Ifetch) {
1811    h_ifetch_hit;
1812    uu_profileInstHit;
1813    k_popMandatoryQueue;
1814  }
1815
1816  transition({O, OM}, Load) {
1817    h_load_hit;
1818    uu_profileDataHit;
1819    k_popMandatoryQueue;
1820  }
1821
1822  transition(O, {Store, Atomic}, OM) {
1823    i_allocateTBE;
1824    b_issueWriteRequest;
1825    uu_profileDataMiss;
1826    k_popMandatoryQueue;
1827  }
1828
1829  transition(O, L1_Replacement, I) {
1830    ta_traceStalledAddress;
1831    c_ownedReplacement;
1832    forward_eviction_to_cpu
1833    gg_deallocateL1CacheBlock;
1834    ka_wakeUpAllDependents;
1835  }
1836
1837  transition(O, {Transient_GETX, Transient_Local_GETX}, I) {
1838    dd_sendDataWithAllTokens;
1839    p_informL2AboutTokenLoss;
1840    forward_eviction_to_cpu
1841    m_popRequestQueue;
1842  }
1843
1844  transition(O, Persistent_GETX, I_L) {
1845    ee_sendDataWithAllTokens;
1846    p_informL2AboutTokenLoss;
1847    forward_eviction_to_cpu
1848    l_popPersistentQueue;
1849  }
1850
1851  transition(O, Persistent_GETS, S_L) {
1852    ff_sendDataWithAllButNorOneTokens;
1853    l_popPersistentQueue;
1854  }
1855
1856  transition(O, Persistent_GETS_Last_Token, I_L) {
1857    fo_sendDataWithOwnerToken;
1858    forward_eviction_to_cpu
1859    l_popPersistentQueue;
1860  }
1861
1862  transition(O, Transient_GETS) {
1863    d_sendDataWithToken;
1864    m_popRequestQueue;
1865  }
1866
1867  transition(O, Transient_Local_GETS) {
1868    d_sendDataWithToken;
1869    m_popRequestQueue;
1870  }
1871
1872  // ran out of tokens, wait for it to go persistent
1873  transition(O, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) {
1874    m_popRequestQueue;
1875  }
1876
1877  transition(O, Ack) {
1878    q_updateTokensFromResponse;
1879    n_popResponseQueue;
1880  }
1881
1882  transition(O, Ack_All_Tokens, M) {
1883    q_updateTokensFromResponse;
1884    n_popResponseQueue;
1885  }
1886
1887  transition(O, Data_Shared) {
1888    w_assertIncomingDataAndCacheDataMatch;
1889    q_updateTokensFromResponse;
1890    n_popResponseQueue;
1891  }
1892
1893  transition(O, Data_All_Tokens, M) {
1894    w_assertIncomingDataAndCacheDataMatch;
1895    q_updateTokensFromResponse;
1896    n_popResponseQueue;
1897  }
1898
1899  // Transitions from Modified
1900  transition({MM, MM_W}, Ifetch) {
1901    h_ifetch_hit;
1902    uu_profileInstHit;
1903    k_popMandatoryQueue;
1904  }
1905
1906  transition({MM, MM_W}, Load) {
1907    h_load_hit;
1908    uu_profileDataHit;
1909    k_popMandatoryQueue;
1910  }
1911
1912  transition({MM_W}, {Store, Atomic}) {
1913    hh_store_hit;
1914    uu_profileDataHit;
1915    k_popMandatoryQueue;
1916  }
1917
1918  transition(MM, Store) {
1919    hh_store_hit;
1920    uu_profileDataHit;
1921    k_popMandatoryQueue;
1922  }
1923
1924  transition(MM, Atomic, M) {
1925    hh_store_hit;
1926    uu_profileDataHit;
1927    k_popMandatoryQueue;
1928  }
1929
1930  transition(MM, L1_Replacement, I) {
1931    ta_traceStalledAddress;
1932    c_ownedReplacement;
1933    forward_eviction_to_cpu
1934    gg_deallocateL1CacheBlock;
1935    ka_wakeUpAllDependents;
1936  }
1937
1938  transition(MM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}, I) {
1939    dd_sendDataWithAllTokens;
1940    p_informL2AboutTokenLoss;
1941    forward_eviction_to_cpu
1942    m_popRequestQueue;
1943  }
1944
1945  transition({MM_W}, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request
1946    m_popRequestQueue;
1947  }
1948
1949  // Implement the migratory sharing optimization, even for persistent requests
1950  transition(MM, {Persistent_GETX, Persistent_GETS}, I_L) {
1951    ee_sendDataWithAllTokens;
1952    p_informL2AboutTokenLoss;
1953    forward_eviction_to_cpu
1954    l_popPersistentQueue;
1955  }
1956
1957  // ignore persistent requests in lockout period
1958  transition(MM_W, {Persistent_GETX, Persistent_GETS}) {
1959    l_popPersistentQueue;
1960  }
1961
1962  transition(MM_W, Use_TimeoutNoStarvers, MM) {
1963    s_deallocateTBE;
1964    jj_unsetUseTimer;
1965    kd_wakeUpDependents;
1966  }
1967
1968  transition(MM_W, Use_TimeoutNoStarvers_NoMig, M) {
1969    s_deallocateTBE;
1970    jj_unsetUseTimer;
1971    kd_wakeUpDependents;
1972  }
1973
1974  // Transitions from Dirty Exclusive
1975  transition({M, M_W}, Ifetch) {
1976    h_ifetch_hit;
1977    uu_profileInstHit;
1978    k_popMandatoryQueue;
1979  }
1980
1981  transition({M, M_W}, Load) {
1982    h_load_hit;
1983    uu_profileDataHit;
1984    k_popMandatoryQueue;
1985  }
1986
1987  transition(M, Store, MM) {
1988    hh_store_hit;
1989    uu_profileDataHit;
1990    k_popMandatoryQueue;
1991  }
1992
1993  transition(M, Atomic) {
1994    hh_store_hit;
1995    uu_profileDataHit;
1996    k_popMandatoryQueue;
1997  }
1998
1999  transition(M_W, Store, MM_W) {
2000    hh_store_hit;
2001    uu_profileDataHit;
2002    k_popMandatoryQueue;
2003  }
2004
2005  transition(M_W, Atomic) {
2006    hh_store_hit;
2007    uu_profileDataHit;
2008    k_popMandatoryQueue;
2009  }
2010
2011  transition(M, L1_Replacement, I) {
2012    ta_traceStalledAddress;
2013    c_ownedReplacement;
2014    forward_eviction_to_cpu
2015    gg_deallocateL1CacheBlock;
2016    ka_wakeUpAllDependents;
2017  }
2018
2019  transition(M, {Transient_GETX, Transient_Local_GETX}, I) {
2020    dd_sendDataWithAllTokens;
2021    p_informL2AboutTokenLoss;
2022    forward_eviction_to_cpu
2023    m_popRequestQueue;
2024  }
2025
2026  transition(M, Transient_Local_GETS, O) {
2027    d_sendDataWithToken;
2028    m_popRequestQueue;
2029  }
2030
2031  transition(M, Transient_GETS, O) {
2032    d_sendDataWithNTokenIfAvail;
2033    m_popRequestQueue;
2034  }
2035
2036  transition(M_W, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request
2037    m_popRequestQueue;
2038  }
2039
2040  transition(M, Persistent_GETX, I_L) {
2041    ee_sendDataWithAllTokens;
2042    p_informL2AboutTokenLoss;
2043    forward_eviction_to_cpu
2044    l_popPersistentQueue;
2045  }
2046
2047  transition(M, Persistent_GETS, S_L) {
2048    ff_sendDataWithAllButNorOneTokens;
2049    l_popPersistentQueue;
2050  }
2051
2052  // ignore persistent requests in lockout period
2053  transition(M_W, {Persistent_GETX, Persistent_GETS}) {
2054    l_popPersistentQueue;
2055  }
2056
2057  transition(M_W, Use_TimeoutStarverS, S_L) {
2058    s_deallocateTBE;
2059    ff_sendDataWithAllButNorOneTokens;
2060    jj_unsetUseTimer;
2061  }
2062
2063  // someone unlocked during timeout
2064  transition(M_W, {Use_TimeoutNoStarvers, Use_TimeoutNoStarvers_NoMig}, M) {
2065    s_deallocateTBE;
2066    jj_unsetUseTimer;
2067    kd_wakeUpDependents;
2068  }
2069
2070  transition(M_W, Use_TimeoutStarverX, I_L) {
2071    s_deallocateTBE;
2072    ee_sendDataWithAllTokens;
2073    forward_eviction_to_cpu;
2074    p_informL2AboutTokenLoss;
2075    jj_unsetUseTimer;
2076  }
2077
2078  // migratory
2079  transition(MM_W, {Use_TimeoutStarverX, Use_TimeoutStarverS}, I_L) {
2080    s_deallocateTBE;
2081    ee_sendDataWithAllTokens;
2082    forward_eviction_to_cpu;
2083    p_informL2AboutTokenLoss;
2084    jj_unsetUseTimer;
2085
2086  }
2087
2088  // Transient_GETX and Transient_GETS in transient states
2089  transition(OM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
2090    m_popRequestQueue;  // Even if we have the data, we can pretend we don't have it yet.
2091  }
2092
2093  transition(IS, {Transient_GETX, Transient_Local_GETX}) {
2094    t_sendAckWithCollectedTokens;
2095    m_popRequestQueue;
2096  }
2097
2098  transition(IS, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
2099    m_popRequestQueue;
2100  }
2101
2102  transition(IS, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, IS_L) {
2103    e_sendAckWithCollectedTokens;
2104    l_popPersistentQueue;
2105  }
2106
2107  transition(IS_L, {Persistent_GETX, Persistent_GETS}) {
2108    l_popPersistentQueue;
2109  }
2110
2111  transition(IM, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, IM_L) {
2112    e_sendAckWithCollectedTokens;
2113    l_popPersistentQueue;
2114  }
2115
2116  transition(IM_L, {Persistent_GETX, Persistent_GETS}) {
2117    l_popPersistentQueue;
2118  }
2119
2120  transition({SM, SM_L}, Persistent_GETX, IM_L) {
2121    e_sendAckWithCollectedTokens;
2122    forward_eviction_to_cpu
2123    l_popPersistentQueue;
2124  }
2125
2126  transition(SM, {Persistent_GETS, Persistent_GETS_Last_Token}, SM_L) {
2127    f_sendAckWithAllButNorOneTokens;
2128    l_popPersistentQueue;
2129  }
2130
2131  transition(SM_L, {Persistent_GETS, Persistent_GETS_Last_Token}) {
2132    l_popPersistentQueue;
2133  }
2134
2135  transition(OM, Persistent_GETX, IM_L) {
2136    ee_sendDataWithAllTokens;
2137    forward_eviction_to_cpu
2138    l_popPersistentQueue;
2139  }
2140
2141  transition(OM, Persistent_GETS, SM_L) {
2142    ff_sendDataWithAllButNorOneTokens;
2143    l_popPersistentQueue;
2144  }
2145
2146  transition(OM, Persistent_GETS_Last_Token, IM_L) {
2147    fo_sendDataWithOwnerToken;
2148    l_popPersistentQueue;
2149  }
2150
2151  // Transitions from IM/SM
2152
2153  transition({IM, SM}, Ack) {
2154    q_updateTokensFromResponse;
2155    n_popResponseQueue;
2156  }
2157
2158  transition(IM, Data_Shared, SM) {
2159    u_writeDataToCache;
2160    q_updateTokensFromResponse;
2161    n_popResponseQueue;
2162  }
2163
2164  transition(IM, Data_Owner, OM) {
2165    u_writeDataToCache;
2166    q_updateTokensFromResponse;
2167    n_popResponseQueue;
2168  }
2169
2170  transition(IM, Data_All_Tokens, MM_W) {
2171    u_writeDataToCache;
2172    q_updateTokensFromResponse;
2173    xx_external_store_hit;
2174    o_scheduleUseTimeout;
2175    j_unsetReissueTimer;
2176    n_popResponseQueue;
2177    kd_wakeUpDependents;
2178  }
2179
2180  transition(SM, Data_Shared) {
2181    w_assertIncomingDataAndCacheDataMatch;
2182    q_updateTokensFromResponse;
2183    n_popResponseQueue;
2184  }
2185
2186  transition(SM, Data_Owner, OM) {
2187    w_assertIncomingDataAndCacheDataMatch;
2188    q_updateTokensFromResponse;
2189    n_popResponseQueue;
2190  }
2191
2192  transition(SM, Data_All_Tokens, MM_W) {
2193    w_assertIncomingDataAndCacheDataMatch;
2194    q_updateTokensFromResponse;
2195    xx_external_store_hit;
2196    o_scheduleUseTimeout;
2197    j_unsetReissueTimer;
2198    n_popResponseQueue;
2199    kd_wakeUpDependents;
2200  }
2201
2202  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
2203    t_sendAckWithCollectedTokens;
2204    forward_eviction_to_cpu;
2205    m_popRequestQueue;
2206  }
2207
2208  transition({IM, SM}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
2209    m_popRequestQueue;
2210  }
2211
2212  transition({IM, SM}, Request_Timeout) {
2213    j_unsetReissueTimer;
2214    b_issueWriteRequest;
2215  }
2216
2217  // Transitions from OM
2218
2219  transition(OM, Ack) {
2220    q_updateTokensFromResponse;
2221    n_popResponseQueue;
2222  }
2223
2224  transition(OM, Ack_All_Tokens, MM_W) {
2225    q_updateTokensFromResponse;
2226    xx_external_store_hit;
2227    o_scheduleUseTimeout;
2228    j_unsetReissueTimer;
2229    n_popResponseQueue;
2230    kd_wakeUpDependents;
2231  }
2232
2233  transition(OM, Data_Shared) {
2234    w_assertIncomingDataAndCacheDataMatch;
2235    q_updateTokensFromResponse;
2236    n_popResponseQueue;
2237  }
2238
2239  transition(OM, Data_All_Tokens, MM_W) {
2240    w_assertIncomingDataAndCacheDataMatch;
2241    q_updateTokensFromResponse;
2242    xx_external_store_hit;
2243    o_scheduleUseTimeout;
2244    j_unsetReissueTimer;
2245    n_popResponseQueue;
2246    kd_wakeUpDependents;
2247  }
2248
2249  transition(OM, Request_Timeout) {
2250    j_unsetReissueTimer;
2251    b_issueWriteRequest;
2252  }
2253
2254  // Transitions from IS
2255
2256  transition(IS, Ack) {
2257    q_updateTokensFromResponse;
2258    n_popResponseQueue;
2259  }
2260
2261  transition(IS, Data_Shared, S) {
2262    u_writeDataToCache;
2263    q_updateTokensFromResponse;
2264    x_external_load_hit;
2265    s_deallocateTBE;
2266    j_unsetReissueTimer;
2267    n_popResponseQueue;
2268    kd_wakeUpDependents;
2269  }
2270
2271  transition(IS, Data_Owner, O) {
2272    u_writeDataToCache;
2273    q_updateTokensFromResponse;
2274    x_external_load_hit;
2275    s_deallocateTBE;
2276    j_unsetReissueTimer;
2277    n_popResponseQueue;
2278    kd_wakeUpDependents;
2279  }
2280
2281  transition(IS, Data_All_Tokens, M_W) {
2282    u_writeDataToCache;
2283    q_updateTokensFromResponse;
2284    x_external_load_hit;
2285    o_scheduleUseTimeout;
2286    j_unsetReissueTimer;
2287    n_popResponseQueue;
2288    kd_wakeUpDependents;
2289  }
2290
2291  transition(IS, Request_Timeout) {
2292    j_unsetReissueTimer;
2293    a_issueReadRequest;
2294  }
2295
2296  // Transitions from I_L
2297
2298  transition(I_L, Load, IS_L) {
2299    ii_allocateL1DCacheBlock;
2300    i_allocateTBE;
2301    a_issueReadRequest;
2302    uu_profileDataMiss;
2303    k_popMandatoryQueue;
2304  }
2305
2306  transition(I_L, Ifetch, IS_L) {
2307    pp_allocateL1ICacheBlock;
2308    i_allocateTBE;
2309    a_issueReadRequest;
2310    uu_profileInstMiss;
2311    k_popMandatoryQueue;
2312  }
2313
2314  transition(I_L, {Store, Atomic}, IM_L) {
2315    ii_allocateL1DCacheBlock;
2316    i_allocateTBE;
2317    b_issueWriteRequest;
2318    uu_profileDataMiss;
2319    k_popMandatoryQueue;
2320  }
2321
2322
2323  // Transitions from S_L
2324
2325  transition(S_L, {Store, Atomic}, SM_L) {
2326    i_allocateTBE;
2327    b_issueWriteRequest;
2328    uu_profileDataMiss;
2329    k_popMandatoryQueue;
2330  }
2331
2332  // Other transitions from *_L states
2333
2334  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}) {
2335    m_popRequestQueue;
2336  }
2337
2338  transition({I_L, IM_L, IS_L, S_L, SM_L}, Ack) {
2339    g_bounceResponseToStarver;
2340    n_popResponseQueue;
2341  }
2342
2343  transition({I_L, IM_L, S_L, SM_L}, {Data_Shared, Data_Owner}) {
2344    g_bounceResponseToStarver;
2345    n_popResponseQueue;
2346  }
2347
2348  transition({I_L, S_L}, Data_All_Tokens) {
2349    g_bounceResponseToStarver;
2350    n_popResponseQueue;
2351  }
2352
2353  transition(IS_L, Request_Timeout) {
2354    j_unsetReissueTimer;
2355    a_issueReadRequest;
2356  }
2357
2358  transition({IM_L, SM_L}, Request_Timeout) {
2359    j_unsetReissueTimer;
2360    b_issueWriteRequest;
2361  }
2362
2363  // Opportunisticly Complete the memory operation in the following
2364  // cases.  Note: these transitions could just use
2365  // g_bounceResponseToStarver, but if we have the data and tokens, we
2366  // might as well complete the memory request while we have the
2367  // chance (and then immediately forward on the data)
2368
2369  transition(IM_L, Data_All_Tokens, MM_W) {
2370    u_writeDataToCache;
2371    q_updateTokensFromResponse;
2372    xx_external_store_hit;
2373    j_unsetReissueTimer;
2374    o_scheduleUseTimeout;
2375    n_popResponseQueue;
2376    kd_wakeUpDependents;
2377  }
2378
2379  transition(SM_L, Data_All_Tokens, S_L) {
2380    u_writeDataToCache;
2381    q_updateTokensFromResponse;
2382    xx_external_store_hit;
2383    ff_sendDataWithAllButNorOneTokens;
2384    s_deallocateTBE;
2385    j_unsetReissueTimer;
2386    n_popResponseQueue;
2387  }
2388
2389  transition(IS_L, Data_Shared, I_L) {
2390    u_writeDataToCache;
2391    q_updateTokensFromResponse;
2392    x_external_load_hit;
2393    s_deallocateTBE;
2394    e_sendAckWithCollectedTokens;
2395    p_informL2AboutTokenLoss;
2396    j_unsetReissueTimer;
2397    n_popResponseQueue;
2398  }
2399
2400  transition(IS_L, Data_Owner, I_L) {
2401    u_writeDataToCache;
2402    q_updateTokensFromResponse;
2403    x_external_load_hit;
2404    ee_sendDataWithAllTokens;
2405    s_deallocateTBE;
2406    p_informL2AboutTokenLoss;
2407    j_unsetReissueTimer;
2408    n_popResponseQueue;
2409  }
2410
2411  transition(IS_L, Data_All_Tokens, M_W) {
2412    u_writeDataToCache;
2413    q_updateTokensFromResponse;
2414    x_external_load_hit;
2415    j_unsetReissueTimer;
2416    o_scheduleUseTimeout;
2417    n_popResponseQueue;
2418    kd_wakeUpDependents;
2419  }
2420
2421  // Own_Lock_or_Unlock
2422
2423  transition(I_L, Own_Lock_or_Unlock, I) {
2424    l_popPersistentQueue;
2425    kd_wakeUpDependents;
2426  }
2427
2428  transition(S_L, Own_Lock_or_Unlock, S) {
2429    l_popPersistentQueue;
2430    kd_wakeUpDependents;
2431  }
2432
2433  transition(IM_L, Own_Lock_or_Unlock, IM) {
2434    l_popPersistentQueue;
2435    kd_wakeUpDependents;
2436  }
2437
2438  transition(IS_L, Own_Lock_or_Unlock, IS) {
2439    l_popPersistentQueue;
2440    kd_wakeUpDependents;
2441  }
2442
2443  transition(SM_L, Own_Lock_or_Unlock, SM) {
2444    l_popPersistentQueue;
2445    kd_wakeUpDependents;
2446  }
2447}
2448