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
29machine(MachineType:L2Cache, "Token protocol")
30 : CacheMemory * L2cache;
31   int N_tokens;
32   Cycles l2_request_latency := 5;
33   Cycles l2_response_latency := 5;
34   bool filtering_enabled := "True";
35
36   // L2 BANK QUEUES
37   // From local bank of L2 cache TO the network
38 
39   // this L2 bank -> a local L1 || mod-directory
40   MessageBuffer * responseFromL2Cache, network="To", virtual_network="4",
41        vnet_type="response";
42   // this L2 bank -> mod-directory
43   MessageBuffer * GlobalRequestFromL2Cache, network="To", virtual_network="2",
44        vnet_type="request";
45   // this L2 bank -> a local L1
46   MessageBuffer * L1RequestFromL2Cache, network="To", virtual_network="1",
47        vnet_type="request";
48 
49 
50   // FROM the network to this local bank of L2 cache
51 
52   // a local L1 || mod-directory -> this L2 bank
53   MessageBuffer * responseToL2Cache, network="From", virtual_network="4",
54        vnet_type="response";
55   MessageBuffer * persistentToL2Cache, network="From", virtual_network="3",
56        vnet_type="persistent";
57   // mod-directory -> this L2 bank
58   MessageBuffer * GlobalRequestToL2Cache, network="From", virtual_network="2",
59        vnet_type="request";
60   // a local L1 -> this L2 bank
61   MessageBuffer * L1RequestToL2Cache, network="From", virtual_network="1",
62        vnet_type="request";
63
64{
65  // STATES
66  state_declaration(State, desc="L2 Cache states", default="L2Cache_State_I") {
67    // Base states
68    NP, AccessPermission:Invalid, desc="Not Present";
69    I, AccessPermission:Invalid, desc="Idle";
70    S, AccessPermission:Read_Only, desc="Shared, not present in any local L1s";
71    O, AccessPermission:Read_Only, desc="Owned, not present in any L1s";
72    M, AccessPermission:Read_Write, desc="Modified, not present in any L1s";
73
74    // Locked states
75    I_L, AccessPermission:Busy, "I^L", desc="Invalid, Locked";
76    S_L, AccessPermission:Busy, "S^L", desc="Shared, Locked";
77  }
78
79  // EVENTS
80  enumeration(Event, desc="Cache events") {
81
82    // Requests
83    L1_GETS,             desc="local L1 GETS request";
84    L1_GETS_Last_Token,    desc="local L1 GETS request";
85    L1_GETX,             desc="local L1 GETX request";
86    L1_INV,              desc="L1 no longer has tokens";
87    Transient_GETX,      desc="A GetX from another processor";
88    Transient_GETS,      desc="A GetS from another processor";
89    Transient_GETS_Last_Token,   desc="A GetS from another processor";
90
91    // events initiated by this L2
92    L2_Replacement,     desc="L2 Replacement", format="!r";
93
94    // events of external L2 responses
95
96    // Responses
97    Writeback_Tokens,               desc="Received a writeback from L1 with only tokens (no data)";
98    Writeback_Shared_Data,               desc="Received a writeback from L1 that includes clean data";
99    Writeback_All_Tokens,    desc="Received a writeback from L1";
100    Writeback_Owned,                desc="Received a writeback from L1";
101
102
103    Data_Shared,             desc="Received a data message, we are now a sharer";
104    Data_Owner,              desc="Received a data message, we are now the owner";
105    Data_All_Tokens,   desc="Received a data message, we are now the owner, we now have all the tokens";
106    Ack,                     desc="Received an ack message";
107    Ack_All_Tokens,          desc="Received an ack message, we now have all the tokens";
108
109    // Lock/Unlock
110    Persistent_GETX,     desc="Another processor has priority to read/write";
111    Persistent_GETS,     desc="Another processor has priority to read";
112    Persistent_GETS_Last_Token, desc="Another processor has priority to read";
113    Own_Lock_or_Unlock,  desc="This processor now has priority";
114  }
115
116  // TYPES
117
118  // CacheEntry
119  structure(Entry, desc="...", interface="AbstractCacheEntry") {
120    State CacheState,        desc="cache state";
121    bool Dirty,              desc="Is the data dirty (different than memory)?";
122    int Tokens,              desc="The number of tokens we're holding for the line";
123    DataBlock DataBlk,       desc="data for the block";
124  }
125
126  structure(DirEntry, desc="...", interface="AbstractEntry") {
127    Set Sharers,            desc="Set of the internal processors that want the block in shared state";
128    bool exclusive, default="false", desc="if local exclusive is likely";
129  }
130
131  structure(PerfectCacheMemory, external="yes") {
132    void allocate(Addr);
133    void deallocate(Addr);
134    DirEntry lookup(Addr);
135    bool isTagPresent(Addr);
136  }
137
138  structure(PersistentTable, external="yes") {
139    void persistentRequestLock(Addr, MachineID, AccessType);
140    void persistentRequestUnlock(Addr, MachineID);
141    MachineID findSmallest(Addr);
142    AccessType typeOfSmallest(Addr);
143    void markEntries(Addr);
144    bool isLocked(Addr);
145    int countStarvingForAddress(Addr);
146    int countReadStarvingForAddress(Addr);
147  }
148
149  PersistentTable persistentTable;
150  PerfectCacheMemory localDirectory, template="<L2Cache_DirEntry>";
151
152  Tick clockEdge();
153  void set_cache_entry(AbstractCacheEntry b);
154  void unset_cache_entry();
155  MachineID mapAddressToMachine(Addr addr, MachineType mtype);
156
157  Entry getCacheEntry(Addr address), return_by_pointer="yes" {
158    Entry cache_entry := static_cast(Entry, "pointer", L2cache.lookup(address));
159    return cache_entry;
160  }
161
162  DirEntry getDirEntry(Addr address), return_by_pointer="yes" {
163    return localDirectory.lookup(address);
164  }
165
166  void functionalRead(Addr addr, Packet *pkt) {
167    testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
168  }
169
170  int functionalWrite(Addr addr, Packet *pkt) {
171    int num_functional_writes := 0;
172    num_functional_writes := num_functional_writes +
173        testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
174    return num_functional_writes;
175  }
176
177  int getTokens(Entry cache_entry) {
178    if (is_valid(cache_entry)) {
179      return cache_entry.Tokens;
180    } else {
181      return 0;
182    }
183  }
184
185  State getState(Entry cache_entry, Addr addr) {
186    if (is_valid(cache_entry)) {
187      return cache_entry.CacheState;
188    } else if (persistentTable.isLocked(addr)) {
189      return State:I_L;
190    } else {
191      return State:NP;
192    }
193  }
194
195  void setState(Entry cache_entry, Addr addr, State state) {
196
197    if (is_valid(cache_entry)) {
198      // Make sure the token count is in range
199      assert(cache_entry.Tokens >= 0);
200      assert(cache_entry.Tokens <= max_tokens());
201      assert(cache_entry.Tokens != (max_tokens() / 2));
202
203      // Make sure we have no tokens in L
204      if ((state == State:I_L) ) {
205        assert(cache_entry.Tokens == 0);
206      }
207
208      // in M and E you have all the tokens
209      if (state == State:M ) {
210        assert(cache_entry.Tokens == max_tokens());
211      }
212
213      // in NP you have no tokens
214      if (state == State:NP) {
215        assert(cache_entry.Tokens == 0);
216      }
217
218      // You have at least one token in S-like states
219      if (state == State:S ) {
220        assert(cache_entry.Tokens > 0);
221      }
222
223      // You have at least half the token in O-like states
224      if (state == State:O ) {
225        assert(cache_entry.Tokens > (max_tokens() / 2));
226      }
227
228      cache_entry.CacheState := state;
229    }
230  }
231
232  AccessPermission getAccessPermission(Addr addr) {
233    Entry cache_entry := getCacheEntry(addr);
234    if(is_valid(cache_entry)) {
235      return L2Cache_State_to_permission(cache_entry.CacheState);
236    }
237
238    return AccessPermission:NotPresent;
239  }
240
241  void setAccessPermission(Entry cache_entry, Addr addr, State state) {
242    if (is_valid(cache_entry)) {
243      cache_entry.changePermission(L2Cache_State_to_permission(state));
244    }
245  }
246
247  void removeSharer(Addr addr, NodeID id) {
248
249    if (localDirectory.isTagPresent(addr)) {
250      DirEntry dir_entry := getDirEntry(addr);
251      dir_entry.Sharers.remove(id);
252      if (dir_entry.Sharers.count() == 0) {
253        localDirectory.deallocate(addr);
254      }
255    }
256  }
257
258  bool sharersExist(Addr addr) {
259    if (localDirectory.isTagPresent(addr)) {
260      DirEntry dir_entry := getDirEntry(addr);
261      if (dir_entry.Sharers.count() > 0) {
262        return true;
263      }
264      else {
265        return false;
266      }
267    }
268    else {
269      return false;
270    }
271  }
272
273  bool exclusiveExists(Addr addr) {
274    if (localDirectory.isTagPresent(addr)) {
275      DirEntry dir_entry := getDirEntry(addr);
276      if (dir_entry.exclusive) {
277        return true;
278      }
279      else {
280        return false;
281      }
282    }
283    else {
284      return false;
285    }
286  }
287
288  // assumes that caller will check to make sure tag is present
289  Set getSharers(Addr addr) {
290    DirEntry dir_entry := getDirEntry(addr);
291    return dir_entry.Sharers;
292  }
293
294  void setNewWriter(Addr addr, NodeID id) {
295    if (localDirectory.isTagPresent(addr) == false) {
296      localDirectory.allocate(addr);
297    }
298    DirEntry dir_entry := getDirEntry(addr);
299    dir_entry.Sharers.clear();
300    dir_entry.Sharers.add(id);
301    dir_entry.exclusive := true;
302  }
303
304  void addNewSharer(Addr addr, NodeID id) {
305    if (localDirectory.isTagPresent(addr) == false) {
306      localDirectory.allocate(addr);
307    }
308    DirEntry dir_entry := getDirEntry(addr);
309    dir_entry.Sharers.add(id);
310    // dir_entry.exclusive := false;
311  }
312
313  void clearExclusiveBitIfExists(Addr addr) {
314    if (localDirectory.isTagPresent(addr)) {
315      DirEntry dir_entry := getDirEntry(addr);
316      dir_entry.exclusive := false;
317    }
318  }
319
320  // ** OUT_PORTS **
321  out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache);
322  out_port(localRequestNetwork_out, RequestMsg, L1RequestFromL2Cache);
323  out_port(responseNetwork_out, ResponseMsg, responseFromL2Cache);
324
325
326
327  // ** IN_PORTS **
328
329  // Persistent Network
330  in_port(persistentNetwork_in, PersistentMsg, persistentToL2Cache) {
331    if (persistentNetwork_in.isReady(clockEdge())) {
332      peek(persistentNetwork_in, PersistentMsg) {
333        assert(in_msg.Destination.isElement(machineID));
334
335        if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
336          persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Write);
337        } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
338          persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Read);
339        } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
340          persistentTable.persistentRequestUnlock(in_msg.addr, in_msg.Requestor);
341        } else {
342          error("Unexpected message");
343        }
344
345        Entry cache_entry := getCacheEntry(in_msg.addr);
346        // React to the message based on the current state of the table
347        if (persistentTable.isLocked(in_msg.addr)) {
348
349          if (persistentTable.typeOfSmallest(in_msg.addr) == AccessType:Read) {
350            if (getTokens(cache_entry) == 1 ||
351                getTokens(cache_entry) == (max_tokens() / 2) + 1) {
352              trigger(Event:Persistent_GETS_Last_Token, in_msg.addr,
353                      cache_entry);
354            } else {
355              trigger(Event:Persistent_GETS, in_msg.addr, cache_entry);
356            }
357          } else {
358            trigger(Event:Persistent_GETX, in_msg.addr, cache_entry);
359          }
360        }
361        else {
362            trigger(Event:Own_Lock_or_Unlock, in_msg.addr, cache_entry);
363        }
364      }
365    }
366  }
367
368
369  // Request Network
370  in_port(requestNetwork_in, RequestMsg, GlobalRequestToL2Cache) {
371    if (requestNetwork_in.isReady(clockEdge())) {
372      peek(requestNetwork_in, RequestMsg) {
373        assert(in_msg.Destination.isElement(machineID));
374
375        Entry cache_entry := getCacheEntry(in_msg.addr);
376        if (in_msg.Type == CoherenceRequestType:GETX) {
377            trigger(Event:Transient_GETX, in_msg.addr, cache_entry);
378        } else if (in_msg.Type == CoherenceRequestType:GETS) {
379          if (getTokens(cache_entry) == 1) {
380            trigger(Event:Transient_GETS_Last_Token, in_msg.addr,
381                    cache_entry);
382          }
383          else {
384            trigger(Event:Transient_GETS, in_msg.addr, cache_entry);
385          }
386        } else {
387          error("Unexpected message");
388        }
389      }
390    }
391  }
392
393  in_port(L1requestNetwork_in, RequestMsg, L1RequestToL2Cache) {
394    if (L1requestNetwork_in.isReady(clockEdge())) {
395      peek(L1requestNetwork_in, RequestMsg) {
396        assert(in_msg.Destination.isElement(machineID));
397        Entry cache_entry := getCacheEntry(in_msg.addr);
398        if (in_msg.Type == CoherenceRequestType:GETX) {
399          trigger(Event:L1_GETX, in_msg.addr, cache_entry);
400        } else if (in_msg.Type == CoherenceRequestType:GETS) {
401          if (getTokens(cache_entry) == 1 ||
402              getTokens(cache_entry) == (max_tokens() / 2) + 1) {
403            trigger(Event:L1_GETS_Last_Token, in_msg.addr, cache_entry);
404          }
405          else {
406            trigger(Event:L1_GETS, in_msg.addr, cache_entry);
407          }
408        } else {
409          error("Unexpected message");
410        }
411      }
412    }
413  }
414
415
416  // Response Network
417  in_port(responseNetwork_in, ResponseMsg, responseToL2Cache) {
418    if (responseNetwork_in.isReady(clockEdge())) {
419      peek(responseNetwork_in, ResponseMsg) {
420        assert(in_msg.Destination.isElement(machineID));
421        Entry cache_entry := getCacheEntry(in_msg.addr);
422
423        if (getTokens(cache_entry) + in_msg.Tokens != max_tokens()) {
424          if (in_msg.Type == CoherenceResponseType:ACK) {
425            assert(in_msg.Tokens < (max_tokens() / 2));
426            trigger(Event:Ack, in_msg.addr, cache_entry);
427          } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
428            trigger(Event:Data_Owner, in_msg.addr, cache_entry);
429          } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
430            trigger(Event:Data_Shared, in_msg.addr, cache_entry);
431          } else if (in_msg.Type == CoherenceResponseType:WB_TOKENS ||
432                     in_msg.Type == CoherenceResponseType:WB_OWNED ||
433                     in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
434
435            if (L2cache.cacheAvail(in_msg.addr) || is_valid(cache_entry)) {
436
437              // either room is available or the block is already present
438
439              if (in_msg.Type == CoherenceResponseType:WB_TOKENS) {
440                assert(in_msg.Dirty == false);
441                trigger(Event:Writeback_Tokens, in_msg.addr, cache_entry);
442              } else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
443                assert(in_msg.Dirty == false);
444                trigger(Event:Writeback_Shared_Data, in_msg.addr, cache_entry);
445              }
446              else if (in_msg.Type == CoherenceResponseType:WB_OWNED) {
447                //assert(in_msg.Dirty == false);
448                trigger(Event:Writeback_Owned, in_msg.addr, cache_entry);
449              }
450            }
451            else {
452                Addr victim := L2cache.cacheProbe(in_msg.addr);
453                trigger(Event:L2_Replacement, victim, getCacheEntry(victim));
454            }
455          } else if (in_msg.Type == CoherenceResponseType:INV) {
456            trigger(Event:L1_INV, in_msg.addr, cache_entry);
457          } else {
458            error("Unexpected message");
459          }
460        } else {
461          if (in_msg.Type == CoherenceResponseType:ACK) {
462            assert(in_msg.Tokens < (max_tokens() / 2));
463            trigger(Event:Ack_All_Tokens, in_msg.addr, cache_entry);
464          } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER ||
465                     in_msg.Type == CoherenceResponseType:DATA_SHARED) {
466            trigger(Event:Data_All_Tokens, in_msg.addr, cache_entry);
467          } else if (in_msg.Type == CoherenceResponseType:WB_TOKENS ||
468                     in_msg.Type == CoherenceResponseType:WB_OWNED ||
469                     in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
470            if (L2cache.cacheAvail(in_msg.addr) || is_valid(cache_entry)) {
471
472              // either room is available or the block is already present
473
474              if (in_msg.Type == CoherenceResponseType:WB_TOKENS) {
475                assert(in_msg.Dirty == false);
476                assert(  (getState(cache_entry, in_msg.addr) != State:NP)
477                      && (getState(cache_entry, in_msg.addr) != State:I) );
478                trigger(Event:Writeback_All_Tokens, in_msg.addr, cache_entry);
479              } else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
480                assert(in_msg.Dirty == false);
481                trigger(Event:Writeback_All_Tokens, in_msg.addr, cache_entry);
482              }
483              else if (in_msg.Type == CoherenceResponseType:WB_OWNED) {
484                trigger(Event:Writeback_All_Tokens, in_msg.addr, cache_entry);
485              }
486            }
487            else {
488                Addr victim := L2cache.cacheProbe(in_msg.addr);
489                trigger(Event:L2_Replacement, victim, getCacheEntry(victim));
490            }
491          } else if (in_msg.Type == CoherenceResponseType:INV) {
492            trigger(Event:L1_INV, in_msg.addr, cache_entry);
493          } else {
494            DPRINTF(RubySlicc, "%s\n", in_msg.Type);
495            error("Unexpected message");
496          }
497        }
498      }
499    }
500  }
501
502
503  // ACTIONS
504
505  action(a_broadcastLocalRequest, "a", desc="broadcast local request globally") {
506
507    peek(L1requestNetwork_in, RequestMsg) {
508
509     // if this is a retry or no local sharers, broadcast normally
510        enqueue(globalRequestNetwork_out, RequestMsg, l2_request_latency) {
511           out_msg.addr := in_msg.addr;
512           out_msg.Type := in_msg.Type;
513           out_msg.Requestor := in_msg.Requestor;
514           out_msg.RetryNum := in_msg.RetryNum;
515
516           //
517           // If a statically shared L2 cache, then no other L2 caches can
518           // store the block
519           //
520           //out_msg.Destination.broadcast(MachineType:L2Cache);
521           //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
522           //out_msg.Destination.remove(map_L1CacheMachId_to_L2Cache(address, in_msg.Requestor));
523
524           out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
525           out_msg.MessageSize := MessageSizeType:Request_Control;
526           out_msg.AccessMode := in_msg.AccessMode;
527           out_msg.Prefetch := in_msg.Prefetch;
528        } //enqueue
529      // } // if
530
531         //profile_filter_action(0);
532    } // peek
533  } //action
534
535
536  action(bb_bounceResponse, "\b", desc="Bounce tokens and data to memory") {
537    peek(responseNetwork_in, ResponseMsg) {
538      // FIXME, should use a 3rd vnet
539      enqueue(responseNetwork_out, ResponseMsg, 1) {
540        out_msg.addr := address;
541        out_msg.Type := in_msg.Type;
542        out_msg.Sender := machineID;
543        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
544        out_msg.Tokens := in_msg.Tokens;
545        out_msg.MessageSize := in_msg.MessageSize;
546        out_msg.DataBlk := in_msg.DataBlk;
547        out_msg.Dirty := in_msg.Dirty;
548      }
549    }
550  }
551
552  action(c_cleanReplacement, "c", desc="Issue clean writeback") {
553    assert(is_valid(cache_entry));
554    if (cache_entry.Tokens > 0) {
555      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
556        out_msg.addr := address;
557        out_msg.Type := CoherenceResponseType:ACK;
558        out_msg.Sender := machineID;
559        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
560        out_msg.Tokens := cache_entry.Tokens;
561        out_msg.MessageSize := MessageSizeType:Writeback_Control;
562      }
563      cache_entry.Tokens := 0;
564    }
565  }
566
567  action(cc_dirtyReplacement, "\c", desc="Issue dirty writeback") {
568    assert(is_valid(cache_entry));
569    enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
570      out_msg.addr := address;
571      out_msg.Sender := machineID;
572      out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
573      out_msg.Tokens := cache_entry.Tokens;
574      out_msg.DataBlk := cache_entry.DataBlk;
575      out_msg.Dirty := cache_entry.Dirty;
576
577      if (cache_entry.Dirty) {
578        out_msg.MessageSize := MessageSizeType:Writeback_Data;
579        out_msg.Type := CoherenceResponseType:DATA_OWNER;
580      } else {
581        out_msg.MessageSize := MessageSizeType:Writeback_Control;
582        out_msg.Type := CoherenceResponseType:ACK_OWNER;
583      }
584    }
585    cache_entry.Tokens := 0;
586  }
587
588  action(d_sendDataWithTokens, "d", desc="Send data and a token from cache to requestor") {
589    peek(requestNetwork_in, RequestMsg) {
590      assert(is_valid(cache_entry));
591      if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) {
592        enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
593          out_msg.addr := address;
594          out_msg.Type := CoherenceResponseType:DATA_SHARED;
595          out_msg.Sender := machineID;
596          out_msg.Destination.add(in_msg.Requestor);
597          out_msg.Tokens := N_tokens;
598          out_msg.DataBlk := cache_entry.DataBlk;
599          out_msg.Dirty := false;
600          out_msg.MessageSize := MessageSizeType:Response_Data;
601        }
602        cache_entry.Tokens := cache_entry.Tokens - N_tokens;
603      }
604      else {
605        enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
606          out_msg.addr := address;
607          out_msg.Type := CoherenceResponseType:DATA_SHARED;
608          out_msg.Sender := machineID;
609          out_msg.Destination.add(in_msg.Requestor);
610          out_msg.Tokens := 1;
611          out_msg.DataBlk := cache_entry.DataBlk;
612          out_msg.Dirty := false;
613          out_msg.MessageSize := MessageSizeType:Response_Data;
614        }
615        cache_entry.Tokens := cache_entry.Tokens - 1;
616      }
617    }
618  }
619
620  action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") {
621    assert(is_valid(cache_entry));
622    peek(requestNetwork_in, RequestMsg) {
623      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
624        out_msg.addr := address;
625        out_msg.Type := CoherenceResponseType:DATA_OWNER;
626        out_msg.Sender := machineID;
627        out_msg.Destination.add(in_msg.Requestor);
628        assert(cache_entry.Tokens >= 1);
629        out_msg.Tokens := cache_entry.Tokens;
630        out_msg.DataBlk := cache_entry.DataBlk;
631        out_msg.Dirty := cache_entry.Dirty;
632        out_msg.MessageSize := MessageSizeType:Response_Data;
633      }
634    }
635    cache_entry.Tokens := 0;
636  }
637
638  action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") {
639    assert(is_valid(cache_entry));
640    if (cache_entry.Tokens > 0) {
641      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
642        out_msg.addr := address;
643        out_msg.Type := CoherenceResponseType:ACK;
644        out_msg.Sender := machineID;
645        out_msg.Destination.add(persistentTable.findSmallest(address));
646        assert(cache_entry.Tokens >= 1);
647        out_msg.Tokens := cache_entry.Tokens;
648        out_msg.MessageSize := MessageSizeType:Response_Control;
649      }
650    }
651    cache_entry.Tokens := 0;
652  }
653
654  action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") {
655    assert(is_valid(cache_entry));
656    enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
657      out_msg.addr := address;
658      out_msg.Type := CoherenceResponseType:DATA_OWNER;
659      out_msg.Sender := machineID;
660      out_msg.Destination.add(persistentTable.findSmallest(address));
661      assert(cache_entry.Tokens >= 1);
662      out_msg.Tokens := cache_entry.Tokens;
663      out_msg.DataBlk := cache_entry.DataBlk;
664      out_msg.Dirty := cache_entry.Dirty;
665      out_msg.MessageSize := MessageSizeType:Response_Data;
666    }
667    cache_entry.Tokens := 0;
668  }
669
670  action(f_sendAckWithAllButOneTokens, "f", desc="Send ack with all our tokens but one to starver.") {
671    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
672    assert(is_valid(cache_entry));
673    assert(cache_entry.Tokens > 0);
674    if (cache_entry.Tokens > 1) {
675      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
676        out_msg.addr := address;
677        out_msg.Type := CoherenceResponseType:ACK;
678        out_msg.Sender := machineID;
679        out_msg.Destination.add(persistentTable.findSmallest(address));
680        assert(cache_entry.Tokens >= 1);
681        out_msg.Tokens := cache_entry.Tokens - 1;
682        out_msg.MessageSize := MessageSizeType:Response_Control;
683      }
684    }
685    cache_entry.Tokens := 1;
686  }
687
688  action(ff_sendDataWithAllButOneTokens, "\f", desc="Send data and out tokens but one to starver") {
689    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
690    assert(is_valid(cache_entry));
691    assert(cache_entry.Tokens > (max_tokens() / 2) + 1);
692    enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
693        out_msg.addr := address;
694        out_msg.Type := CoherenceResponseType:DATA_OWNER;
695        out_msg.Sender := machineID;
696        out_msg.Destination.add(persistentTable.findSmallest(address));
697        out_msg.Tokens := cache_entry.Tokens - 1;
698        out_msg.DataBlk := cache_entry.DataBlk;
699        out_msg.Dirty := cache_entry.Dirty;
700        out_msg.MessageSize := MessageSizeType:Response_Data;
701    }
702    cache_entry.Tokens := 1;
703  }
704
705  action(fa_sendDataWithAllTokens, "fa", desc="Send data and out tokens but one to starver") {
706    //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself
707    assert(is_valid(cache_entry));
708    assert(cache_entry.Tokens == (max_tokens() / 2) + 1);
709    enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
710        out_msg.addr := address;
711        out_msg.Type := CoherenceResponseType:DATA_OWNER;
712        out_msg.Sender := machineID;
713        out_msg.Destination.add(persistentTable.findSmallest(address));
714        out_msg.Tokens := cache_entry.Tokens;
715        out_msg.DataBlk := cache_entry.DataBlk;
716        out_msg.Dirty := cache_entry.Dirty;
717        out_msg.MessageSize := MessageSizeType:Response_Data;
718    }
719    cache_entry.Tokens := 0;
720  }
721
722
723
724  action(gg_bounceResponseToStarver, "\g", desc="Redirect response to starving processor") {
725    // assert(persistentTable.isLocked(address));
726    peek(responseNetwork_in, ResponseMsg) {
727      // FIXME, should use a 3rd vnet in some cases
728      enqueue(responseNetwork_out, ResponseMsg, 1) {
729        out_msg.addr := address;
730        out_msg.Type := in_msg.Type;
731        out_msg.Sender := machineID;
732        out_msg.Destination.add(persistentTable.findSmallest(address));
733        out_msg.Tokens := in_msg.Tokens;
734        out_msg.DataBlk := in_msg.DataBlk;
735        out_msg.Dirty := in_msg.Dirty;
736        out_msg.MessageSize := in_msg.MessageSize;
737      }
738    }
739  }
740
741  action(gg_bounceWBSharedToStarver, "\gg", desc="Redirect response to starving processor") {
742    //assert(persistentTable.isLocked(address));
743    peek(responseNetwork_in, ResponseMsg) {
744      // FIXME, should use a 3rd vnet in some cases
745      enqueue(responseNetwork_out, ResponseMsg, 1) {
746        out_msg.addr := address;
747        if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) {
748          out_msg.Type := CoherenceResponseType:DATA_SHARED;
749        } else {
750          assert(in_msg.Tokens < (max_tokens() / 2));
751          out_msg.Type := CoherenceResponseType:ACK;
752        }
753        out_msg.Sender := machineID;
754        out_msg.Destination.add(persistentTable.findSmallest(address));
755        out_msg.Tokens := in_msg.Tokens;
756        out_msg.DataBlk := in_msg.DataBlk;
757        out_msg.Dirty := in_msg.Dirty;
758        out_msg.MessageSize := in_msg.MessageSize;
759      }
760    }
761  }
762
763  action(gg_bounceWBOwnedToStarver, "\ggg", desc="Redirect response to starving processor") {
764    // assert(persistentTable.isLocked(address));
765    peek(responseNetwork_in, ResponseMsg) {
766      // FIXME, should use a 3rd vnet in some cases
767      enqueue(responseNetwork_out, ResponseMsg, 1) {
768        out_msg.addr := address;
769        out_msg.Type := CoherenceResponseType:DATA_OWNER;
770        out_msg.Sender := machineID;
771        out_msg.Destination.add(persistentTable.findSmallest(address));
772        out_msg.Tokens := in_msg.Tokens;
773        out_msg.DataBlk := in_msg.DataBlk;
774        out_msg.Dirty := in_msg.Dirty;
775        out_msg.MessageSize := in_msg.MessageSize;
776      }
777    }
778  }
779
780
781  action(h_updateFilterFromL1HintOrWB, "h", desc="update filter from received writeback") {
782    peek(responseNetwork_in, ResponseMsg) {
783      removeSharer(in_msg.addr, machineIDToNodeID(in_msg.Sender));
784    }
785  }
786
787  action(j_forwardTransientRequestToLocalSharers, "j", desc="Forward external transient request to local sharers") {
788    peek(requestNetwork_in, RequestMsg) {
789      if (filtering_enabled && in_msg.RetryNum == 0 && sharersExist(in_msg.addr) == false) {
790        //profile_filter_action(1);
791        DPRINTF(RubySlicc, "filtered message, Retry Num: %d\n",
792                in_msg.RetryNum);
793      }
794      else {
795        enqueue(localRequestNetwork_out, RequestMsg, l2_response_latency ) {
796           out_msg.addr := in_msg.addr;
797           out_msg.Requestor := in_msg.Requestor;
798
799           //
800           // Currently assuming only one chip so all L1s are local
801           //
802           //out_msg.Destination := getLocalL1IDs(machineID);
803           out_msg.Destination.broadcast(MachineType:L1Cache);
804           out_msg.Destination.remove(in_msg.Requestor);
805
806           out_msg.Type := in_msg.Type;
807           out_msg.isLocal := false;
808           out_msg.MessageSize := MessageSizeType:Broadcast_Control;
809           out_msg.AccessMode := in_msg.AccessMode;
810           out_msg.Prefetch := in_msg.Prefetch;
811        }
812        //profile_filter_action(0);
813      }
814    }
815  }
816
817  action(k_dataFromL2CacheToL1Requestor, "k", desc="Send data and a token from cache to L1 requestor") {
818    peek(L1requestNetwork_in, RequestMsg) {
819      assert(is_valid(cache_entry));
820      assert(cache_entry.Tokens > 0);
821      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
822        out_msg.addr := address;
823        out_msg.Type := CoherenceResponseType:DATA_SHARED;
824        out_msg.Sender := machineID;
825        out_msg.Destination.add(in_msg.Requestor);
826        out_msg.DataBlk := cache_entry.DataBlk;
827        out_msg.Dirty := false;
828        out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
829        out_msg.Tokens := 1;
830      }
831      cache_entry.Tokens := cache_entry.Tokens - 1;
832    }
833  }
834
835  action(k_dataOwnerFromL2CacheToL1Requestor, "\k", desc="Send data and a token from cache to L1 requestor") {
836    peek(L1requestNetwork_in, RequestMsg) {
837      assert(is_valid(cache_entry));
838      assert(cache_entry.Tokens == (max_tokens() / 2) + 1);
839      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
840        out_msg.addr := address;
841        out_msg.Type := CoherenceResponseType:DATA_OWNER;
842        out_msg.Sender := machineID;
843        out_msg.Destination.add(in_msg.Requestor);
844        out_msg.DataBlk := cache_entry.DataBlk;
845        out_msg.Dirty := cache_entry.Dirty;
846        out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
847        out_msg.Tokens := cache_entry.Tokens;
848      }
849      cache_entry.Tokens := 0;
850    }
851  }
852
853  action(k_dataAndAllTokensFromL2CacheToL1Requestor, "\kk", desc="Send data and a token from cache to L1 requestor") {
854    peek(L1requestNetwork_in, RequestMsg) {
855      assert(is_valid(cache_entry));
856//      assert(cache_entry.Tokens == max_tokens());
857      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
858        out_msg.addr := address;
859        out_msg.Type := CoherenceResponseType:DATA_OWNER;
860        out_msg.Sender := machineID;
861        out_msg.Destination.add(in_msg.Requestor);
862        out_msg.DataBlk := cache_entry.DataBlk;
863        out_msg.Dirty := cache_entry.Dirty;
864        out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data;
865        //out_msg.Tokens := max_tokens();
866        out_msg.Tokens := cache_entry.Tokens;
867      }
868      cache_entry.Tokens := 0;
869    }
870  }
871
872  action(l_popPersistentQueue, "l", desc="Pop persistent queue.") {
873    persistentNetwork_in.dequeue(clockEdge());
874  }
875
876  action(m_popRequestQueue, "m", desc="Pop request queue.") {
877    requestNetwork_in.dequeue(clockEdge());
878  }
879
880  action(n_popResponseQueue, "n", desc="Pop response queue") {
881    responseNetwork_in.dequeue(clockEdge());
882  }
883
884  action(o_popL1RequestQueue, "o", desc="Pop L1 request queue.") {
885    L1requestNetwork_in.dequeue(clockEdge());
886  }
887
888
889  action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") {
890    peek(responseNetwork_in, ResponseMsg) {
891      assert(is_valid(cache_entry));
892      assert(in_msg.Tokens != 0);
893      cache_entry.Tokens := cache_entry.Tokens + in_msg.Tokens;
894
895      // this should ideally be in u_writeDataToCache, but Writeback_All_Tokens
896      //  may not trigger this action.
897      if ( (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:WB_OWNED) && in_msg.Dirty) {
898        cache_entry.Dirty := true;
899      }
900    }
901  }
902
903  action(r_markNewSharer, "r", desc="Mark the new local sharer from local request message") {
904    peek(L1requestNetwork_in, RequestMsg) {
905      if (machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache) {
906        if (in_msg.Type == CoherenceRequestType:GETX) {
907          setNewWriter(in_msg.addr, machineIDToNodeID(in_msg.Requestor));
908        } else if (in_msg.Type == CoherenceRequestType:GETS) {
909          addNewSharer(in_msg.addr, machineIDToNodeID(in_msg.Requestor));
910        }
911      }
912    }
913  }
914
915  action(r_clearExclusive, "\rrr", desc="clear exclusive bit") {
916    clearExclusiveBitIfExists(address);
917  }
918
919  action(r_setMRU, "\rr", desc="manually set the MRU bit for cache line" ) {
920    peek(L1requestNetwork_in, RequestMsg) {
921      if ((machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache) &&
922          (is_valid(cache_entry))) {
923        L2cache.setMRU(address);
924      }
925    }
926  }
927
928  action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") {
929    assert(is_valid(cache_entry));
930    if (cache_entry.Tokens > 0) {
931      peek(requestNetwork_in, RequestMsg) {
932        enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
933          out_msg.addr := address;
934          out_msg.Type := CoherenceResponseType:ACK;
935          out_msg.Sender := machineID;
936          out_msg.Destination.add(in_msg.Requestor);
937          assert(cache_entry.Tokens >= 1);
938          out_msg.Tokens := cache_entry.Tokens;
939          out_msg.MessageSize := MessageSizeType:Response_Control;
940        }
941      }
942    }
943    cache_entry.Tokens := 0;
944  }
945
946  action(tt_sendLocalAckWithCollectedTokens, "tt", desc="Send ack with the tokens we've collected thus far.") {
947    assert(is_valid(cache_entry));
948    if (cache_entry.Tokens > 0) {
949      peek(L1requestNetwork_in, RequestMsg) {
950        enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
951          out_msg.addr := address;
952          out_msg.Type := CoherenceResponseType:ACK;
953          out_msg.Sender := machineID;
954          out_msg.Destination.add(in_msg.Requestor);
955          assert(cache_entry.Tokens >= 1);
956          out_msg.Tokens := cache_entry.Tokens;
957          out_msg.MessageSize := MessageSizeType:Response_Control;
958        }
959      }
960    }
961    cache_entry.Tokens := 0;
962  }
963
964  action(u_writeDataToCache, "u", desc="Write data to cache") {
965    peek(responseNetwork_in, ResponseMsg) {
966      assert(is_valid(cache_entry));
967      cache_entry.DataBlk := in_msg.DataBlk;
968      if ((cache_entry.Dirty == false) && in_msg.Dirty) {
969        cache_entry.Dirty := in_msg.Dirty;
970      }
971    }
972  }
973
974  action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
975    set_cache_entry(L2cache.allocate(address, new Entry));
976  }
977
978  action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block.  Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
979    L2cache.deallocate(address);
980    unset_cache_entry();
981  }
982
983  action(uu_profileMiss, "\um", desc="Profile the demand miss") {
984      ++L2cache.demand_misses;
985  }
986
987  action(uu_profileHit, "\uh", desc="Profile the demand hit") {
988      ++L2cache.demand_hits;
989  }
990
991  action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") {
992    peek(responseNetwork_in, ResponseMsg) {
993      if (in_msg.Type != CoherenceResponseType:ACK &&
994          in_msg.Type != CoherenceResponseType:WB_TOKENS) {
995        assert(is_valid(cache_entry));
996        assert(cache_entry.DataBlk == in_msg.DataBlk);
997      }
998    }
999  }
1000
1001
1002  //*****************************************************
1003  // TRANSITIONS
1004  //*****************************************************
1005
1006  transition({NP, I, S, O, M, I_L, S_L}, L1_INV) {
1007
1008    h_updateFilterFromL1HintOrWB;
1009    n_popResponseQueue;
1010  }
1011
1012  transition({NP, I, S, O, M}, Own_Lock_or_Unlock) {
1013    l_popPersistentQueue;
1014  }
1015
1016
1017  // Transitions from NP
1018
1019  transition(NP, {Transient_GETX, Transient_GETS}) {
1020    // forward message to local sharers
1021    r_clearExclusive;
1022    j_forwardTransientRequestToLocalSharers;
1023    m_popRequestQueue;
1024  }
1025
1026
1027  transition(NP,  {L1_GETS, L1_GETX}) {
1028    a_broadcastLocalRequest;
1029    r_markNewSharer;
1030    uu_profileMiss;
1031    o_popL1RequestQueue;
1032  }
1033
1034  transition(NP, {Ack, Data_Shared, Data_Owner, Data_All_Tokens}) {
1035    bb_bounceResponse;
1036    n_popResponseQueue;
1037  }
1038
1039  transition(NP, Writeback_Shared_Data, S) {
1040    vv_allocateL2CacheBlock;
1041    u_writeDataToCache;
1042    q_updateTokensFromResponse;
1043    h_updateFilterFromL1HintOrWB;
1044    n_popResponseQueue;
1045  }
1046
1047  transition(NP, Writeback_Tokens, I) {
1048    vv_allocateL2CacheBlock;
1049    q_updateTokensFromResponse;
1050    h_updateFilterFromL1HintOrWB;
1051    n_popResponseQueue;
1052  }
1053
1054  transition(NP, Writeback_All_Tokens, M) {
1055    vv_allocateL2CacheBlock;
1056    u_writeDataToCache;
1057    q_updateTokensFromResponse;
1058    h_updateFilterFromL1HintOrWB;
1059    n_popResponseQueue;
1060  }
1061
1062  transition(NP, Writeback_Owned, O) {
1063    vv_allocateL2CacheBlock;
1064    u_writeDataToCache;
1065    q_updateTokensFromResponse;
1066    h_updateFilterFromL1HintOrWB;
1067    n_popResponseQueue;
1068  }
1069
1070
1071  transition(NP,
1072             {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token},
1073             I_L) {
1074    l_popPersistentQueue;
1075  }
1076
1077  // Transitions from Idle
1078
1079  transition(I, {L1_GETS, L1_GETS_Last_Token}) {
1080    a_broadcastLocalRequest;
1081    tt_sendLocalAckWithCollectedTokens;  // send any tokens we have collected
1082    r_markNewSharer;
1083    uu_profileMiss;
1084    o_popL1RequestQueue;
1085  }
1086
1087  transition(I, L1_GETX) {
1088    a_broadcastLocalRequest;
1089    tt_sendLocalAckWithCollectedTokens; // send any tokens we have collected
1090    r_markNewSharer;
1091    uu_profileMiss;
1092    o_popL1RequestQueue;
1093  }
1094
1095  transition(I, L2_Replacement) {
1096    c_cleanReplacement; // Only needed in some cases
1097    rr_deallocateL2CacheBlock;
1098  }
1099
1100  transition(I, {Transient_GETX, Transient_GETS, Transient_GETS_Last_Token}) {
1101    r_clearExclusive;
1102    t_sendAckWithCollectedTokens;
1103    j_forwardTransientRequestToLocalSharers;
1104    m_popRequestQueue;
1105  }
1106
1107  transition(I,
1108             {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token},
1109             I_L) {
1110    e_sendAckWithCollectedTokens;
1111    l_popPersistentQueue;
1112  }
1113
1114
1115  transition(I, Ack) {
1116    q_updateTokensFromResponse;
1117    n_popResponseQueue;
1118  }
1119
1120  transition(I, Data_Shared, S) {
1121    u_writeDataToCache;
1122    q_updateTokensFromResponse;
1123    n_popResponseQueue;
1124  }
1125
1126  transition(I, Writeback_Shared_Data, S) {
1127    u_writeDataToCache;
1128    q_updateTokensFromResponse;
1129    h_updateFilterFromL1HintOrWB;
1130    n_popResponseQueue;
1131  }
1132
1133  transition(I, Writeback_Tokens) {
1134    q_updateTokensFromResponse;
1135    h_updateFilterFromL1HintOrWB;
1136    n_popResponseQueue;
1137  }
1138
1139  transition(I, Data_Owner, O) {
1140    u_writeDataToCache;
1141    q_updateTokensFromResponse;
1142    n_popResponseQueue;
1143  }
1144
1145  transition(I, Writeback_Owned, O) {
1146    u_writeDataToCache;
1147    q_updateTokensFromResponse;
1148    h_updateFilterFromL1HintOrWB;
1149    n_popResponseQueue;
1150  }
1151
1152  transition(I, Data_All_Tokens, M) {
1153    u_writeDataToCache;
1154    q_updateTokensFromResponse;
1155    n_popResponseQueue;
1156  }
1157
1158
1159  transition(I, Writeback_All_Tokens, M) {
1160    u_writeDataToCache;
1161    q_updateTokensFromResponse;
1162    h_updateFilterFromL1HintOrWB;
1163    n_popResponseQueue;
1164  }
1165
1166  // Transitions from Shared
1167
1168  transition(S, L2_Replacement, I) {
1169    c_cleanReplacement;
1170    rr_deallocateL2CacheBlock;
1171  }
1172
1173  transition(S, Transient_GETX, I) {
1174    r_clearExclusive;
1175    t_sendAckWithCollectedTokens;
1176    j_forwardTransientRequestToLocalSharers;
1177    m_popRequestQueue;
1178  }
1179
1180  transition(S, {Transient_GETS, Transient_GETS_Last_Token}) {
1181    j_forwardTransientRequestToLocalSharers;
1182    r_clearExclusive;
1183    m_popRequestQueue;
1184  }
1185
1186  transition(S, Persistent_GETX, I_L) {
1187    e_sendAckWithCollectedTokens;
1188    l_popPersistentQueue;
1189  }
1190
1191
1192  transition(S, {Persistent_GETS, Persistent_GETS_Last_Token}, S_L) {
1193    f_sendAckWithAllButOneTokens;
1194    l_popPersistentQueue;
1195  }
1196
1197
1198  transition(S, Ack) {
1199    q_updateTokensFromResponse;
1200    n_popResponseQueue;
1201  }
1202
1203  transition(S, Data_Shared) {
1204    w_assertIncomingDataAndCacheDataMatch;
1205    q_updateTokensFromResponse;
1206    n_popResponseQueue;
1207  }
1208
1209  transition(S, Writeback_Tokens) {
1210    q_updateTokensFromResponse;
1211    h_updateFilterFromL1HintOrWB;
1212    n_popResponseQueue;
1213  }
1214
1215  transition(S, Writeback_Shared_Data) {
1216    w_assertIncomingDataAndCacheDataMatch;
1217    q_updateTokensFromResponse;
1218    h_updateFilterFromL1HintOrWB;
1219    n_popResponseQueue;
1220  }
1221
1222
1223  transition(S, Data_Owner, O) {
1224    w_assertIncomingDataAndCacheDataMatch;
1225    q_updateTokensFromResponse;
1226    n_popResponseQueue;
1227  }
1228
1229  transition(S, Writeback_Owned, O) {
1230    w_assertIncomingDataAndCacheDataMatch;
1231    q_updateTokensFromResponse;
1232    h_updateFilterFromL1HintOrWB;
1233    n_popResponseQueue;
1234  }
1235
1236  transition(S, Data_All_Tokens, M) {
1237    w_assertIncomingDataAndCacheDataMatch;
1238    q_updateTokensFromResponse;
1239    n_popResponseQueue;
1240  }
1241
1242  transition(S, Writeback_All_Tokens,  M) {
1243    w_assertIncomingDataAndCacheDataMatch;
1244    q_updateTokensFromResponse;
1245    h_updateFilterFromL1HintOrWB;
1246    n_popResponseQueue;
1247  }
1248
1249  transition(S, L1_GETX, I) {
1250    a_broadcastLocalRequest;
1251    tt_sendLocalAckWithCollectedTokens;
1252    r_markNewSharer;
1253    r_setMRU;
1254    uu_profileMiss;
1255    o_popL1RequestQueue;
1256  }
1257
1258
1259  transition(S, L1_GETS) {
1260    k_dataFromL2CacheToL1Requestor;
1261    r_markNewSharer;
1262    r_setMRU;
1263    uu_profileHit;
1264    o_popL1RequestQueue;
1265  }
1266
1267  transition(S, L1_GETS_Last_Token, I) {
1268
1269    k_dataFromL2CacheToL1Requestor;
1270    r_markNewSharer;
1271    r_setMRU;
1272    uu_profileHit;
1273    o_popL1RequestQueue;
1274  }
1275
1276  // Transitions from Owned
1277
1278  transition(O, L2_Replacement, I) {
1279    cc_dirtyReplacement;
1280    rr_deallocateL2CacheBlock;
1281  }
1282
1283  transition(O, Transient_GETX, I) {
1284    r_clearExclusive;
1285    dd_sendDataWithAllTokens;
1286    j_forwardTransientRequestToLocalSharers;
1287    m_popRequestQueue;
1288  }
1289
1290  transition(O, Persistent_GETX, I_L) {
1291    ee_sendDataWithAllTokens;
1292    l_popPersistentQueue;
1293  }
1294
1295  transition(O, Persistent_GETS, S_L) {
1296    ff_sendDataWithAllButOneTokens;
1297    l_popPersistentQueue;
1298  }
1299
1300  transition(O, Persistent_GETS_Last_Token, I_L) {
1301    fa_sendDataWithAllTokens;
1302    l_popPersistentQueue;
1303  }
1304
1305  transition(O, Transient_GETS) {
1306    // send multiple tokens
1307    r_clearExclusive;
1308    d_sendDataWithTokens;
1309    m_popRequestQueue;
1310  }
1311
1312  transition(O, Transient_GETS_Last_Token) {
1313    // WAIT FOR IT TO GO PERSISTENT
1314    r_clearExclusive;
1315    m_popRequestQueue;
1316  }
1317
1318  transition(O, Ack) {
1319    q_updateTokensFromResponse;
1320    n_popResponseQueue;
1321  }
1322
1323  transition(O, Ack_All_Tokens, M) {
1324    q_updateTokensFromResponse;
1325    n_popResponseQueue;
1326  }
1327
1328  transition(O, Data_Shared) {
1329    w_assertIncomingDataAndCacheDataMatch;
1330    q_updateTokensFromResponse;
1331    n_popResponseQueue;
1332  }
1333
1334
1335  transition(O, {Writeback_Tokens, Writeback_Shared_Data}) {
1336    w_assertIncomingDataAndCacheDataMatch;
1337    q_updateTokensFromResponse;
1338    h_updateFilterFromL1HintOrWB;
1339    n_popResponseQueue;
1340  }
1341
1342  transition(O, Data_All_Tokens, M) {
1343    w_assertIncomingDataAndCacheDataMatch;
1344    q_updateTokensFromResponse;
1345    n_popResponseQueue;
1346  }
1347
1348  transition(O, Writeback_All_Tokens, M) {
1349    w_assertIncomingDataAndCacheDataMatch;
1350    q_updateTokensFromResponse;
1351    h_updateFilterFromL1HintOrWB;
1352    n_popResponseQueue;
1353  }
1354
1355  transition(O, L1_GETS) {
1356    k_dataFromL2CacheToL1Requestor;
1357    r_markNewSharer;
1358    r_setMRU;
1359    uu_profileHit;
1360    o_popL1RequestQueue;
1361  }
1362
1363  transition(O, L1_GETS_Last_Token, I) {
1364    k_dataOwnerFromL2CacheToL1Requestor;
1365    r_markNewSharer;
1366    r_setMRU;
1367    uu_profileHit;
1368    o_popL1RequestQueue;
1369  }
1370
1371  transition(O, L1_GETX, I) {
1372    a_broadcastLocalRequest;
1373    k_dataAndAllTokensFromL2CacheToL1Requestor;
1374    r_markNewSharer;
1375    r_setMRU;
1376    uu_profileMiss;
1377    o_popL1RequestQueue;
1378  }
1379
1380  // Transitions from M
1381
1382  transition(M, L2_Replacement, I) {
1383    cc_dirtyReplacement;
1384    rr_deallocateL2CacheBlock;
1385  }
1386
1387  // MRM_DEBUG:  Give up all tokens even for GETS? ???
1388  transition(M, {Transient_GETX, Transient_GETS}, I) {
1389    r_clearExclusive;
1390    dd_sendDataWithAllTokens;
1391    m_popRequestQueue;
1392  }
1393
1394  transition(M, {Persistent_GETS, Persistent_GETX}, I_L) {
1395    ee_sendDataWithAllTokens;
1396    l_popPersistentQueue;
1397  }
1398
1399
1400  transition(M, L1_GETS, O) {
1401    k_dataFromL2CacheToL1Requestor;
1402    r_markNewSharer;
1403    r_setMRU;
1404    uu_profileHit;
1405    o_popL1RequestQueue;
1406  }
1407
1408  transition(M, L1_GETX, I) {
1409    k_dataAndAllTokensFromL2CacheToL1Requestor;
1410    r_markNewSharer;
1411    r_setMRU;
1412    uu_profileHit;
1413    o_popL1RequestQueue;
1414  }
1415
1416
1417  //Transitions from locked states
1418
1419  transition({I_L, S_L}, Ack) {
1420    gg_bounceResponseToStarver;
1421    n_popResponseQueue;
1422  }
1423
1424  transition({I_L, S_L}, {Data_Shared, Data_Owner, Data_All_Tokens}) {
1425    gg_bounceResponseToStarver;
1426    n_popResponseQueue;
1427  }
1428
1429  transition({I_L, S_L}, {Writeback_Tokens, Writeback_Shared_Data}) {
1430    gg_bounceWBSharedToStarver;
1431    h_updateFilterFromL1HintOrWB;
1432    n_popResponseQueue;
1433  }
1434
1435  transition({I_L, S_L}, {Writeback_Owned, Writeback_All_Tokens}) {
1436    gg_bounceWBOwnedToStarver;
1437    h_updateFilterFromL1HintOrWB;
1438    n_popResponseQueue;
1439  }
1440
1441  transition(S_L, L2_Replacement, I) {
1442    c_cleanReplacement;
1443    rr_deallocateL2CacheBlock;
1444  }
1445
1446  transition(I_L, L2_Replacement, I) {
1447    rr_deallocateL2CacheBlock;
1448  }
1449
1450  transition(I_L, Own_Lock_or_Unlock, I) {
1451    l_popPersistentQueue;
1452  }
1453
1454  transition(S_L, Own_Lock_or_Unlock, S) {
1455    l_popPersistentQueue;
1456  }
1457
1458  transition({I_L, S_L}, {Transient_GETS_Last_Token, Transient_GETS, Transient_GETX}) {
1459    r_clearExclusive;
1460    m_popRequestQueue;
1461  }
1462
1463  transition(I_L, {L1_GETX, L1_GETS}) {
1464    a_broadcastLocalRequest;
1465    r_markNewSharer;
1466    uu_profileMiss;
1467    o_popL1RequestQueue;
1468  }
1469
1470  transition(S_L, L1_GETX, I_L) {
1471    a_broadcastLocalRequest;
1472    tt_sendLocalAckWithCollectedTokens;
1473    r_markNewSharer;
1474    r_setMRU;
1475    uu_profileMiss;
1476    o_popL1RequestQueue;
1477  }
1478
1479  transition(S_L, L1_GETS) {
1480    k_dataFromL2CacheToL1Requestor;
1481    r_markNewSharer;
1482    r_setMRU;
1483    uu_profileHit;
1484    o_popL1RequestQueue;
1485  }
1486
1487  transition(S_L, L1_GETS_Last_Token, I_L) {
1488    k_dataFromL2CacheToL1Requestor;
1489    r_markNewSharer;
1490    r_setMRU;
1491    uu_profileHit;
1492    o_popL1RequestQueue;
1493  }
1494
1495  transition(S_L, Persistent_GETX, I_L) {
1496    e_sendAckWithCollectedTokens;
1497    l_popPersistentQueue;
1498  }
1499
1500  transition(S_L, {Persistent_GETS, Persistent_GETS_Last_Token}) {
1501    l_popPersistentQueue;
1502  }
1503
1504  transition(I_L, {Persistent_GETX, Persistent_GETS}) {
1505    l_popPersistentQueue;
1506  }
1507}
1508