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:Directory, "Token protocol")
30 : DirectoryMemory * directory;
31   int l2_select_num_bits;
32   Cycles directory_latency := 5;
33   bool distributed_persistent := "True";
34   Cycles fixed_timeout_latency := 100;
35   Cycles reissue_wakeup_latency := 10;
36   Cycles to_memory_controller_latency := 1;
37
38   // Message Queues from dir to other controllers / network
39   MessageBuffer * dmaResponseFromDir, network="To", virtual_network="5",
40        vnet_type="response";
41
42   MessageBuffer * responseFromDir, network="To", virtual_network="4",
43        vnet_type="response";
44
45   MessageBuffer * persistentFromDir, network="To", virtual_network="3",
46        vnet_type="persistent";
47
48   MessageBuffer * requestFromDir, network="To", virtual_network="1",
49        vnet_type="request";
50 
51   // Message Queues to dir from other controllers / network
52   MessageBuffer * responseToDir, network="From", virtual_network="4",
53        vnet_type="response";
54
55   MessageBuffer * persistentToDir, network="From", virtual_network="3",
56        vnet_type="persistent";
57   
58   MessageBuffer * requestToDir, network="From", virtual_network="2",
59        vnet_type="request";
60   
61   MessageBuffer * dmaRequestToDir, network="From", virtual_network="0",
62        vnet_type="request";
63
64   MessageBuffer * responseFromMemory;
65{
66  // STATES
67  state_declaration(State, desc="Directory states", default="Directory_State_O") {
68    // Base states
69    O, AccessPermission:Read_Only, desc="Owner, memory has valid data, but not necessarily all the tokens";
70    NO, AccessPermission:Maybe_Stale, desc="Not Owner";
71    L, AccessPermission:Busy, desc="Locked";
72
73    // Memory wait states - can block all messages including persistent requests
74    O_W, AccessPermission:Busy, desc="transitioning to Owner, waiting for memory write";
75    L_O_W, AccessPermission:Busy, desc="transitioning to Locked, waiting for memory read, could eventually return to O";
76    L_NO_W, AccessPermission:Busy, desc="transitioning to Locked, waiting for memory read, eventually return to NO";
77    DR_L_W, AccessPermission:Busy, desc="transitioning to Locked underneath a DMA read, waiting for memory data";
78    DW_L_W, AccessPermission:Busy, desc="transitioning to Locked underneath a DMA write, waiting for memory ack";
79    NO_W, AccessPermission:Busy, desc="transitioning to Not Owner, waiting for memory read";
80    O_DW_W, AccessPermission:Busy, desc="transitioning to Owner, waiting for memory before DMA ack";
81    O_DR_W, AccessPermission:Busy, desc="transitioning to Owner, waiting for memory before DMA data";
82
83    // DMA request transient states - must respond to persistent requests
84    O_DW, AccessPermission:Busy, desc="issued GETX for DMA write, waiting for all tokens";
85    NO_DW, AccessPermission:Busy, desc="issued GETX for DMA write, waiting for all tokens";
86    NO_DR, AccessPermission:Busy, desc="issued GETS for DMA read, waiting for data";
87
88    // DMA request in progress - competing with a CPU persistent request
89    DW_L, AccessPermission:Busy, desc="issued GETX for DMA write, CPU persistent request must complete first";
90    DR_L, AccessPermission:Busy, desc="issued GETS for DMA read, CPU persistent request must complete first";
91
92  }
93
94  // Events
95  enumeration(Event, desc="Directory events") {
96    GETX, desc="A GETX arrives";
97    GETS, desc="A GETS arrives";
98    Lockdown, desc="A lockdown request arrives";
99    Unlockdown, desc="An un-lockdown request arrives";
100    Own_Lock_or_Unlock, desc="own lock or unlock";
101    Own_Lock_or_Unlock_Tokens, desc="own lock or unlock with tokens";
102    Data_Owner, desc="Data arrive";
103    Data_All_Tokens, desc="Data and all tokens";
104    Ack_Owner, desc="Owner token arrived without data because it was clean";
105    Ack_Owner_All_Tokens, desc="All tokens including owner arrived without data because it was clean";
106    Tokens, desc="Tokens arrive";
107    Ack_All_Tokens, desc="All_Tokens arrive";
108    Request_Timeout, desc="A DMA request has timed out";
109
110    // Memory Controller
111    Memory_Data, desc="Fetched data from memory arrives";
112    Memory_Ack, desc="Writeback Ack from memory arrives";
113
114    // DMA requests
115    DMA_READ, desc="A DMA Read memory request";
116    DMA_WRITE, desc="A DMA Write memory request";
117    DMA_WRITE_All_Tokens, desc="A DMA Write memory request, directory has all tokens";
118  }
119
120  // TYPES
121
122  // DirectoryEntry
123  structure(Entry, desc="...", interface="AbstractEntry") {
124    State DirectoryState,          desc="Directory state";
125    int Tokens, default="max_tokens()", desc="Number of tokens for the line we're holding";
126
127    // The following state is provided to allow for bandwidth
128    // efficient directory-like operation.  However all of this state
129    // is 'soft state' that does not need to be correct (as long as
130    // you're eventually willing to resort to broadcast.)
131
132    Set Owner,                     desc="Probable Owner of the line.  More accurately, the set of processors who need to see a GetS or GetO.  We use a Set for convenience, but only one bit is set at a time.";
133    Set Sharers,                   desc="Probable sharers of the line.  More accurately, the set of processors who need to see a GetX";
134  }
135
136  structure(PersistentTable, external="yes") {
137    void persistentRequestLock(Addr, MachineID, AccessType);
138    void persistentRequestUnlock(Addr, MachineID);
139    bool okToIssueStarving(Addr, MachineID);
140    MachineID findSmallest(Addr);
141    AccessType typeOfSmallest(Addr);
142    void markEntries(Addr);
143    bool isLocked(Addr);
144    int countStarvingForAddress(Addr);
145    int countReadStarvingForAddress(Addr);
146  }
147
148  // TBE entries for DMA requests
149  structure(TBE, desc="TBE entries for outstanding DMA requests") {
150    Addr PhysicalAddress, desc="physical address";
151    State TBEState,        desc="Transient State";
152    DataBlock DataBlk,     desc="Current view of the associated address range";
153    int Len,               desc="...";
154    MachineID DmaRequestor, desc="DMA requestor";
155    bool WentPersistent,   desc="Did the DMA request require a persistent request";
156  }
157
158  structure(TBETable, external="yes") {
159    TBE lookup(Addr);
160    void allocate(Addr);
161    void deallocate(Addr);
162    bool isPresent(Addr);
163  }
164
165  // ** OBJECTS **
166
167  PersistentTable persistentTable;
168  TimerTable reissueTimerTable;
169
170  TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
171
172  bool starving, default="false";
173  int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
174
175  Tick clockEdge();
176  Tick clockEdge(Cycles c);
177  Tick cyclesToTicks(Cycles c);
178  void set_tbe(TBE b);
179  void unset_tbe();
180  MachineID mapAddressToMachine(Addr addr, MachineType mtype);
181
182  Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
183    Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
184
185    if (is_valid(dir_entry)) {
186      return dir_entry;
187    }
188
189    dir_entry :=  static_cast(Entry, "pointer",
190                              directory.allocate(addr, new Entry));
191    return dir_entry;
192  }
193
194  State getState(TBE tbe, Addr addr) {
195    if (is_valid(tbe)) {
196      return tbe.TBEState;
197    } else {
198      return getDirectoryEntry(addr).DirectoryState;
199    }
200  }
201
202  void setState(TBE tbe, Addr addr, State state) {
203    if (is_valid(tbe)) {
204      tbe.TBEState := state;
205    }
206    getDirectoryEntry(addr).DirectoryState := state;
207
208    if (state == State:L || state == State:DW_L || state == State:DR_L) {
209      assert(getDirectoryEntry(addr).Tokens == 0);
210    }
211
212    // We have one or zero owners
213    assert((getDirectoryEntry(addr).Owner.count() == 0) || (getDirectoryEntry(addr).Owner.count() == 1));
214
215    // Make sure the token count is in range
216    assert(getDirectoryEntry(addr).Tokens >= 0);
217    assert(getDirectoryEntry(addr).Tokens <= max_tokens());
218
219    if (state == State:O || state == State:O_W || state == State:O_DW) {
220      assert(getDirectoryEntry(addr).Tokens >= 1); // Must have at least one token
221      // assert(getDirectoryEntry(addr).Tokens >= (max_tokens() / 2)); // Only mostly true; this might not always hold
222    }
223  }
224
225  AccessPermission getAccessPermission(Addr addr) {
226    TBE tbe := TBEs[addr];
227    if(is_valid(tbe)) {
228      return Directory_State_to_permission(tbe.TBEState);
229    }
230
231    if (directory.isPresent(addr)) {
232      DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
233      return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
234    }
235
236    DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
237    return AccessPermission:NotPresent;
238  }
239
240  void setAccessPermission(Addr addr, State state) {
241    getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
242  }
243
244  bool okToIssueStarving(Addr addr, MachineID machinID) {
245    return persistentTable.okToIssueStarving(addr, machineID);
246  }
247
248  void markPersistentEntries(Addr addr) {
249    persistentTable.markEntries(addr);
250  }
251
252  void functionalRead(Addr addr, Packet *pkt) {
253    TBE tbe := TBEs[addr];
254    if(is_valid(tbe)) {
255      testAndRead(addr, tbe.DataBlk, pkt);
256    } else {
257      functionalMemoryRead(pkt);
258    }
259  }
260
261  int functionalWrite(Addr addr, Packet *pkt) {
262    int num_functional_writes := 0;
263
264    TBE tbe := TBEs[addr];
265    if(is_valid(tbe)) {
266      num_functional_writes := num_functional_writes +
267            testAndWrite(addr, tbe.DataBlk, pkt);
268    }
269
270    num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
271    return num_functional_writes;
272  }
273
274  // ** OUT_PORTS **
275  out_port(responseNetwork_out, ResponseMsg, responseFromDir);
276  out_port(persistentNetwork_out, PersistentMsg, persistentFromDir);
277  out_port(requestNetwork_out, RequestMsg, requestFromDir);
278  out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaResponseFromDir);
279
280  // ** IN_PORTS **
281  // off-chip memory request/response is done
282  in_port(memQueue_in, MemoryMsg, responseFromMemory) {
283    if (memQueue_in.isReady(clockEdge())) {
284      peek(memQueue_in, MemoryMsg) {
285        if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
286          trigger(Event:Memory_Data, in_msg.addr, TBEs[in_msg.addr]);
287        } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
288          trigger(Event:Memory_Ack, in_msg.addr, TBEs[in_msg.addr]);
289        } else {
290          DPRINTF(RubySlicc, "%s\n", in_msg.Type);
291          error("Invalid message");
292        }
293      }
294    }
295  }
296
297  // Reissue Timer
298  in_port(reissueTimerTable_in, Addr, reissueTimerTable) {
299    Tick current_time := clockEdge();
300    if (reissueTimerTable_in.isReady(current_time)) {
301      Addr addr := reissueTimerTable.nextAddress();
302      trigger(Event:Request_Timeout, addr, TBEs.lookup(addr));
303    }
304  }
305
306  in_port(responseNetwork_in, ResponseMsg, responseToDir) {
307    if (responseNetwork_in.isReady(clockEdge())) {
308      peek(responseNetwork_in, ResponseMsg) {
309        assert(in_msg.Destination.isElement(machineID));
310        if (getDirectoryEntry(in_msg.addr).Tokens + in_msg.Tokens == max_tokens()) {
311          if ((in_msg.Type == CoherenceResponseType:DATA_OWNER) ||
312              (in_msg.Type == CoherenceResponseType:DATA_SHARED)) {
313            trigger(Event:Data_All_Tokens, in_msg.addr,
314                    TBEs[in_msg.addr]);
315          } else if (in_msg.Type == CoherenceResponseType:ACK_OWNER) {
316            trigger(Event:Ack_Owner_All_Tokens, in_msg.addr,
317                    TBEs[in_msg.addr]);
318          } else if (in_msg.Type == CoherenceResponseType:ACK) {
319            trigger(Event:Ack_All_Tokens, in_msg.addr,
320                    TBEs[in_msg.addr]);
321          } else {
322            DPRINTF(RubySlicc, "%s\n", in_msg.Type);
323            error("Invalid message");
324          }
325        } else {
326          if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
327            trigger(Event:Data_Owner, in_msg.addr,
328                    TBEs[in_msg.addr]);
329          } else if ((in_msg.Type == CoherenceResponseType:ACK) ||
330                     (in_msg.Type == CoherenceResponseType:DATA_SHARED)) {
331            trigger(Event:Tokens, in_msg.addr,
332                    TBEs[in_msg.addr]);
333          } else if (in_msg.Type == CoherenceResponseType:ACK_OWNER) {
334            trigger(Event:Ack_Owner, in_msg.addr,
335                    TBEs[in_msg.addr]);
336          } else {
337            DPRINTF(RubySlicc, "%s\n", in_msg.Type);
338            error("Invalid message");
339          }
340        }
341      }
342    }
343  }
344
345  in_port(persistentNetwork_in, PersistentMsg, persistentToDir) {
346    if (persistentNetwork_in.isReady(clockEdge())) {
347      peek(persistentNetwork_in, PersistentMsg) {
348        assert(in_msg.Destination.isElement(machineID));
349
350        if (distributed_persistent) {
351          // Apply the lockdown or unlockdown message to the table
352          if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
353            persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Write);
354          } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
355            persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Read);
356          } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
357            persistentTable.persistentRequestUnlock(in_msg.addr, in_msg.Requestor);
358          } else {
359            error("Invalid message");
360          }
361
362          // React to the message based on the current state of the table
363          if (persistentTable.isLocked(in_msg.addr)) {
364            if (persistentTable.findSmallest(in_msg.addr) == machineID) {
365              if (getDirectoryEntry(in_msg.addr).Tokens > 0) {
366                trigger(Event:Own_Lock_or_Unlock_Tokens, in_msg.addr,
367                        TBEs[in_msg.addr]);
368              } else {
369                trigger(Event:Own_Lock_or_Unlock, in_msg.addr,
370                        TBEs[in_msg.addr]);
371              }
372            } else {
373              // locked
374              trigger(Event:Lockdown, in_msg.addr, TBEs[in_msg.addr]);
375            }
376          } else {
377            // unlocked
378            trigger(Event:Unlockdown, in_msg.addr, TBEs[in_msg.addr]);
379          }
380        }
381        else {
382          if (persistentTable.findSmallest(in_msg.addr) == machineID) {
383              if (getDirectoryEntry(in_msg.addr).Tokens > 0) {
384                trigger(Event:Own_Lock_or_Unlock_Tokens, in_msg.addr,
385                        TBEs[in_msg.addr]);
386              } else {
387                trigger(Event:Own_Lock_or_Unlock, in_msg.addr,
388                        TBEs[in_msg.addr]);
389              }
390          } else if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
391            // locked
392            trigger(Event:Lockdown, in_msg.addr, TBEs[in_msg.addr]);
393          } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
394            // locked
395            trigger(Event:Lockdown, in_msg.addr, TBEs[in_msg.addr]);
396          } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
397            // unlocked
398            trigger(Event:Unlockdown, in_msg.addr, TBEs[in_msg.addr]);
399          } else {
400            error("Invalid message");
401          }
402        }
403      }
404    }
405  }
406
407  in_port(requestNetwork_in, RequestMsg, requestToDir) {
408    if (requestNetwork_in.isReady(clockEdge())) {
409      peek(requestNetwork_in, RequestMsg) {
410        assert(in_msg.Destination.isElement(machineID));
411        if (in_msg.Type == CoherenceRequestType:GETS) {
412          trigger(Event:GETS, in_msg.addr, TBEs[in_msg.addr]);
413        } else if (in_msg.Type == CoherenceRequestType:GETX) {
414          trigger(Event:GETX, in_msg.addr, TBEs[in_msg.addr]);
415        } else {
416          error("Invalid message");
417        }
418      }
419    }
420  }
421
422  in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) {
423    if (dmaRequestQueue_in.isReady(clockEdge())) {
424      peek(dmaRequestQueue_in, DMARequestMsg) {
425        if (in_msg.Type == DMARequestType:READ) {
426          trigger(Event:DMA_READ, in_msg.LineAddress, TBEs[in_msg.LineAddress]);
427        } else if (in_msg.Type == DMARequestType:WRITE) {
428          if (getDirectoryEntry(in_msg.LineAddress).Tokens == max_tokens()) {
429            trigger(Event:DMA_WRITE_All_Tokens, in_msg.LineAddress,
430                    TBEs[in_msg.LineAddress]);
431          } else {
432            trigger(Event:DMA_WRITE, in_msg.LineAddress,
433                    TBEs[in_msg.LineAddress]);
434          }
435        } else {
436          error("Invalid message");
437        }
438      }
439    }
440  }
441
442  // Actions
443
444  action(a_sendTokens, "a", desc="Send tokens to requestor") {
445    // Only send a message if we have tokens to send
446    if (getDirectoryEntry(address).Tokens > 0) {
447      peek(requestNetwork_in, RequestMsg) {
448        enqueue(responseNetwork_out, ResponseMsg, directory_latency) {// FIXME?
449          out_msg.addr := address;
450          out_msg.Type := CoherenceResponseType:ACK;
451          out_msg.Sender := machineID;
452          out_msg.Destination.add(in_msg.Requestor);
453          out_msg.Tokens := getDirectoryEntry(in_msg.addr).Tokens;
454          out_msg.MessageSize := MessageSizeType:Response_Control;
455        }
456      }
457      getDirectoryEntry(address).Tokens := 0;
458    }
459  }
460
461  action(px_tryIssuingPersistentGETXRequest, "px", desc="...") {
462    if (okToIssueStarving(address, machineID) && (starving == false)) {
463      enqueue(persistentNetwork_out, PersistentMsg, 1) {
464        out_msg.addr := address;
465        out_msg.Type := PersistentRequestType:GETX_PERSISTENT;
466        out_msg.Requestor := machineID;
467        out_msg.Destination.broadcast(MachineType:L1Cache);
468
469        //
470        // Currently the configuration system limits the system to only one
471        // chip.  Therefore, if we assume one shared L2 cache, then only one
472        // pertinent L2 cache exist.
473        //
474        //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
475
476        out_msg.Destination.add(mapAddressToRange(address,
477                                  MachineType:L2Cache, l2_select_low_bit,
478                                  l2_select_num_bits, intToID(0)));
479
480        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
481        out_msg.MessageSize := MessageSizeType:Persistent_Control;
482        out_msg.Prefetch := PrefetchBit:No;
483        out_msg.AccessMode := RubyAccessMode:Supervisor;
484      }
485      markPersistentEntries(address);
486      starving := true;
487
488      tbe.WentPersistent := true;
489
490      // Do not schedule a wakeup, a persistent requests will always complete
491    } else {
492
493      // We'd like to issue a persistent request, but are not allowed
494      // to issue a P.R. right now.  This, we do not increment the
495      // IssueCount.
496
497      // Set a wakeup timer
498      reissueTimerTable.set(address, clockEdge(reissue_wakeup_latency));
499    }
500  }
501
502  action(bw_broadcastWrite, "bw", desc="Broadcast GETX if we need tokens") {
503    peek(dmaRequestQueue_in, DMARequestMsg) {
504      //
505      // Assser that we only send message if we don't already have all the tokens
506      //
507      assert(getDirectoryEntry(address).Tokens != max_tokens());
508      enqueue(requestNetwork_out, RequestMsg, 1) {
509        out_msg.addr := address;
510        out_msg.Type := CoherenceRequestType:GETX;
511        out_msg.Requestor := machineID;
512
513        //
514        // Since only one chip, assuming all L1 caches are local
515        //
516        out_msg.Destination.broadcast(MachineType:L1Cache);
517        out_msg.Destination.add(mapAddressToRange(address,
518                                  MachineType:L2Cache, l2_select_low_bit,
519                                  l2_select_num_bits, intToID(0)));
520
521        out_msg.RetryNum := 0;
522        out_msg.MessageSize := MessageSizeType:Broadcast_Control;
523        out_msg.Prefetch := PrefetchBit:No;
524        out_msg.AccessMode := RubyAccessMode:Supervisor;
525      }
526    }
527  }
528
529  action(ps_tryIssuingPersistentGETSRequest, "ps", desc="...") {
530    if (okToIssueStarving(address, machineID) && (starving == false)) {
531      enqueue(persistentNetwork_out, PersistentMsg, 1) {
532        out_msg.addr := address;
533        out_msg.Type := PersistentRequestType:GETS_PERSISTENT;
534        out_msg.Requestor := machineID;
535        out_msg.Destination.broadcast(MachineType:L1Cache);
536
537        //
538        // Currently the configuration system limits the system to only one
539        // chip.  Therefore, if we assume one shared L2 cache, then only one
540        // pertinent L2 cache exist.
541        //
542        //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
543
544        out_msg.Destination.add(mapAddressToRange(address,
545                                  MachineType:L2Cache, l2_select_low_bit,
546                                  l2_select_num_bits, intToID(0)));
547
548        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
549        out_msg.MessageSize := MessageSizeType:Persistent_Control;
550        out_msg.Prefetch := PrefetchBit:No;
551        out_msg.AccessMode := RubyAccessMode:Supervisor;
552      }
553      markPersistentEntries(address);
554      starving := true;
555
556      tbe.WentPersistent := true;
557
558      // Do not schedule a wakeup, a persistent requests will always complete
559    } else {
560
561      // We'd like to issue a persistent request, but are not allowed
562      // to issue a P.R. right now.  This, we do not increment the
563      // IssueCount.
564
565      // Set a wakeup timer
566      reissueTimerTable.set(address, clockEdge(reissue_wakeup_latency));
567    }
568  }
569
570  action(br_broadcastRead, "br", desc="Broadcast GETS for data") {
571    peek(dmaRequestQueue_in, DMARequestMsg) {
572      enqueue(requestNetwork_out, RequestMsg, 1) {
573        out_msg.addr := address;
574        out_msg.Type := CoherenceRequestType:GETS;
575        out_msg.Requestor := machineID;
576
577        //
578        // Since only one chip, assuming all L1 caches are local
579        //
580        out_msg.Destination.broadcast(MachineType:L1Cache);
581        out_msg.Destination.add(mapAddressToRange(address,
582                                  MachineType:L2Cache, l2_select_low_bit,
583                                  l2_select_num_bits, intToID(0)));
584
585        out_msg.RetryNum := 0;
586        out_msg.MessageSize := MessageSizeType:Broadcast_Control;
587        out_msg.Prefetch := PrefetchBit:No;
588        out_msg.AccessMode := RubyAccessMode:Supervisor;
589      }
590    }
591  }
592
593  action(aa_sendTokensToStarver, "\a", desc="Send tokens to starver") {
594    // Only send a message if we have tokens to send
595    if (getDirectoryEntry(address).Tokens > 0) {
596      enqueue(responseNetwork_out, ResponseMsg, directory_latency) {// FIXME?
597        out_msg.addr := address;
598        out_msg.Type := CoherenceResponseType:ACK;
599        out_msg.Sender := machineID;
600        out_msg.Destination.add(persistentTable.findSmallest(address));
601        out_msg.Tokens := getDirectoryEntry(address).Tokens;
602        out_msg.MessageSize := MessageSizeType:Response_Control;
603      }
604      getDirectoryEntry(address).Tokens := 0;
605    }
606  }
607
608  action(d_sendMemoryDataWithAllTokens, "d", desc="Send data and tokens to requestor") {
609    peek(memQueue_in, MemoryMsg) {
610      enqueue(responseNetwork_out, ResponseMsg, 1) {
611        out_msg.addr := address;
612        out_msg.Type := CoherenceResponseType:DATA_OWNER;
613        out_msg.Sender := machineID;
614        out_msg.Destination.add(in_msg.OriginalRequestorMachId);
615        assert(getDirectoryEntry(address).Tokens > 0);
616        out_msg.Tokens := getDirectoryEntry(in_msg.addr).Tokens;
617        out_msg.DataBlk := in_msg.DataBlk;
618        out_msg.Dirty := false;
619        out_msg.MessageSize := MessageSizeType:Response_Data;
620      }
621    }
622    getDirectoryEntry(address).Tokens := 0;
623  }
624
625  action(dd_sendMemDataToStarver, "\d", desc="Send data and tokens to starver") {
626    peek(memQueue_in, MemoryMsg) {
627      enqueue(responseNetwork_out, ResponseMsg, 1) {
628        out_msg.addr := address;
629        out_msg.Type := CoherenceResponseType:DATA_OWNER;
630        out_msg.Sender := machineID;
631        out_msg.Destination.add(persistentTable.findSmallest(address));
632        assert(getDirectoryEntry(address).Tokens > 0);
633        out_msg.Tokens := getDirectoryEntry(address).Tokens;
634        out_msg.DataBlk := in_msg.DataBlk;
635        out_msg.Dirty := false;
636        out_msg.MessageSize := MessageSizeType:Response_Data;
637      }
638    }
639    getDirectoryEntry(address).Tokens := 0;
640  }
641
642  action(de_sendTbeDataToStarver, "de", desc="Send data and tokens to starver") {
643    enqueue(responseNetwork_out, ResponseMsg, 1) {
644      out_msg.addr := address;
645      out_msg.Type := CoherenceResponseType:DATA_OWNER;
646      out_msg.Sender := machineID;
647      out_msg.Destination.add(persistentTable.findSmallest(address));
648      assert(getDirectoryEntry(address).Tokens > 0);
649      out_msg.Tokens := getDirectoryEntry(address).Tokens;
650      out_msg.DataBlk := tbe.DataBlk;
651      out_msg.Dirty := false;
652      out_msg.MessageSize := MessageSizeType:Response_Data;
653    }
654    getDirectoryEntry(address).Tokens := 0;
655  }
656
657  action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
658    peek(requestNetwork_in, RequestMsg) {
659      queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency);
660    }
661  }
662
663  action(qp_queueMemoryForPersistent, "qp", desc="Queue off-chip fetch request") {
664    queueMemoryRead(persistentTable.findSmallest(address), address,
665                    to_memory_controller_latency);
666  }
667
668  action(fd_memoryDma, "fd", desc="Queue off-chip fetch request") {
669    peek(dmaRequestQueue_in, DMARequestMsg) {
670      queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency);
671    }
672  }
673
674  action(lq_queueMemoryWbRequest, "lq", desc="Write data to memory") {
675    peek(responseNetwork_in, ResponseMsg) {
676      queueMemoryWrite(in_msg.Sender, address, to_memory_controller_latency,
677                       in_msg.DataBlk);
678    }
679  }
680
681  action(ld_queueMemoryDmaWriteFromTbe, "ld", desc="Write DMA data to memory") {
682    queueMemoryWritePartial(tbe.DmaRequestor, address,
683                            to_memory_controller_latency, tbe.DataBlk,
684                            tbe.Len);
685  }
686
687  action(lr_queueMemoryDmaReadWriteback, "lr",
688         desc="Write DMA data from read to memory") {
689    peek(responseNetwork_in, ResponseMsg) {
690      queueMemoryWrite(machineID, address, to_memory_controller_latency,
691                       in_msg.DataBlk);
692    }
693  }
694
695  action(vd_allocateDmaRequestInTBE, "vd", desc="Record Data in TBE") {
696    peek(dmaRequestQueue_in, DMARequestMsg) {
697      TBEs.allocate(address);
698      set_tbe(TBEs[address]);
699      tbe.DataBlk := in_msg.DataBlk;
700      tbe.PhysicalAddress := in_msg.PhysicalAddress;
701      tbe.Len := in_msg.Len;
702      tbe.DmaRequestor := in_msg.Requestor;
703      tbe.WentPersistent := false;
704    }
705  }
706
707  action(s_deallocateTBE, "s", desc="Deallocate TBE") {
708
709    if (tbe.WentPersistent) {
710      assert(starving);
711
712      enqueue(persistentNetwork_out, PersistentMsg, 1) {
713        out_msg.addr := address;
714        out_msg.Type := PersistentRequestType:DEACTIVATE_PERSISTENT;
715        out_msg.Requestor := machineID;
716        out_msg.Destination.broadcast(MachineType:L1Cache);
717
718        //
719        // Currently the configuration system limits the system to only one
720        // chip.  Therefore, if we assume one shared L2 cache, then only one
721        // pertinent L2 cache exist.
722        //
723        //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address));
724
725        out_msg.Destination.add(mapAddressToRange(address,
726                                  MachineType:L2Cache, l2_select_low_bit,
727                                  l2_select_num_bits, intToID(0)));
728
729        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
730        out_msg.MessageSize := MessageSizeType:Persistent_Control;
731      }
732      starving := false;
733    }
734
735    TBEs.deallocate(address);
736    unset_tbe();
737  }
738
739  action(rd_recordDataInTbe, "rd", desc="Record data in TBE") {
740    peek(responseNetwork_in, ResponseMsg) {
741      DataBlock DataBlk := tbe.DataBlk;
742      tbe.DataBlk := in_msg.DataBlk;
743      tbe.DataBlk.copyPartial(DataBlk, getOffset(tbe.PhysicalAddress),
744                              tbe.Len);
745    }
746  }
747
748  action(f_incrementTokens, "f", desc="Increment the number of tokens we're tracking") {
749    peek(responseNetwork_in, ResponseMsg) {
750      assert(in_msg.Tokens >= 1);
751      getDirectoryEntry(address).Tokens := getDirectoryEntry(address).Tokens + in_msg.Tokens;
752    }
753  }
754
755  action(aat_assertAllTokens, "aat", desc="assert that we have all tokens") {
756    assert(getDirectoryEntry(address).Tokens == max_tokens());
757  }
758
759  action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
760    requestNetwork_in.dequeue(clockEdge());
761  }
762
763  action(z_recycleRequest, "z", desc="Recycle the request queue") {
764    requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
765  }
766
767  action(k_popIncomingResponseQueue, "k", desc="Pop incoming response queue") {
768    responseNetwork_in.dequeue(clockEdge());
769  }
770
771  action(kz_recycleResponse, "kz", desc="Recycle incoming response queue") {
772    responseNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
773  }
774
775  action(l_popIncomingPersistentQueue, "l", desc="Pop incoming persistent queue") {
776    persistentNetwork_in.dequeue(clockEdge());
777  }
778
779  action(p_popDmaRequestQueue, "pd", desc="pop dma request queue") {
780    dmaRequestQueue_in.dequeue(clockEdge());
781  }
782
783  action(y_recycleDmaRequestQueue, "y", desc="recycle dma request queue") {
784    dmaRequestQueue_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
785  }
786
787  action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
788    memQueue_in.dequeue(clockEdge());
789  }
790
791  action(r_bounceResponse, "r", desc="Bounce response to starving processor") {
792    peek(responseNetwork_in, ResponseMsg) {
793      enqueue(responseNetwork_out, ResponseMsg, 1) {
794        out_msg.addr := address;
795        out_msg.Type := in_msg.Type;
796        out_msg.Sender := machineID;
797        out_msg.Destination.add(persistentTable.findSmallest(address));
798        out_msg.Tokens := in_msg.Tokens;
799        out_msg.MessageSize := in_msg.MessageSize;
800        out_msg.DataBlk := in_msg.DataBlk;
801        out_msg.Dirty := in_msg.Dirty;
802      }
803    }
804  }
805
806  action(rs_resetScheduleTimeout, "rs", desc="Reschedule Schedule Timeout") {
807    //
808    // currently only support a fixed timeout latency
809    //
810    if (reissueTimerTable.isSet(address)) {
811      reissueTimerTable.unset(address);
812      reissueTimerTable.set(address, clockEdge(fixed_timeout_latency));
813    }
814  }
815
816  action(st_scheduleTimeout, "st", desc="Schedule Timeout") {
817    //
818    // currently only support a fixed timeout latency
819    //
820    reissueTimerTable.set(address, clockEdge(fixed_timeout_latency));
821  }
822
823  action(ut_unsetReissueTimer, "ut", desc="Unset reissue timer.") {
824    if (reissueTimerTable.isSet(address)) {
825      reissueTimerTable.unset(address);
826    }
827  }
828
829  action(bd_bounceDatalessOwnerToken, "bd", desc="Bounce clean owner token to starving processor") {
830    peek(responseNetwork_in, ResponseMsg) {
831      assert(in_msg.Type == CoherenceResponseType:ACK_OWNER);
832      assert(in_msg.Dirty == false);
833      assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
834
835      // Bounce the message, but "re-associate" the data and the owner
836      // token.  In essence we're converting an ACK_OWNER message to a
837      // DATA_OWNER message, keeping the number of tokens the same.
838      enqueue(responseNetwork_out, ResponseMsg, 1) {
839        out_msg.addr := address;
840        out_msg.Type := CoherenceResponseType:DATA_OWNER;
841        out_msg.Sender := machineID;
842        out_msg.Destination.add(persistentTable.findSmallest(address));
843        out_msg.Tokens := in_msg.Tokens;
844        out_msg.Dirty := in_msg.Dirty;
845        out_msg.MessageSize := MessageSizeType:Response_Data;
846      }
847    }
848  }
849
850  action(da_sendDmaAck, "da", desc="Send Ack to DMA controller") {
851    enqueue(dmaResponseNetwork_out, DMAResponseMsg, 1) {
852      out_msg.PhysicalAddress := address;
853      out_msg.LineAddress := address;
854      out_msg.Type := DMAResponseType:ACK;
855      out_msg.Destination.add(tbe.DmaRequestor);
856      out_msg.MessageSize := MessageSizeType:Writeback_Control;
857    }
858  }
859
860  action(dm_sendMemoryDataToDma, "dm", desc="Send Data to DMA controller from memory") {
861    peek(memQueue_in, MemoryMsg) {
862      enqueue(dmaResponseNetwork_out, DMAResponseMsg, 1) {
863        out_msg.PhysicalAddress := address;
864        out_msg.LineAddress := address;
865        out_msg.Type := DMAResponseType:DATA;
866        //
867        // we send the entire data block and rely on the dma controller to
868        // split it up if need be
869        //
870        out_msg.DataBlk := in_msg.DataBlk;
871        out_msg.Destination.add(tbe.DmaRequestor);
872        out_msg.MessageSize := MessageSizeType:Response_Data;
873      }
874    }
875  }
876
877  action(dd_sendDmaData, "dd", desc="Send Data to DMA controller") {
878    peek(responseNetwork_in, ResponseMsg) {
879      enqueue(dmaResponseNetwork_out, DMAResponseMsg, 1) {
880        out_msg.PhysicalAddress := address;
881        out_msg.LineAddress := address;
882        out_msg.Type := DMAResponseType:DATA;
883        //
884        // we send the entire data block and rely on the dma controller to
885        // split it up if need be
886        //
887        out_msg.DataBlk := in_msg.DataBlk;
888        out_msg.Destination.add(tbe.DmaRequestor);
889        out_msg.MessageSize := MessageSizeType:Response_Data;
890      }
891    }
892  }
893
894  // TRANSITIONS
895
896  //
897  // Trans. from base state O
898  // the directory has valid data
899  //
900  transition(O, GETX, NO_W) {
901    qf_queueMemoryFetchRequest;
902    j_popIncomingRequestQueue;
903  }
904
905  transition(O, DMA_WRITE, O_DW) {
906    vd_allocateDmaRequestInTBE;
907    bw_broadcastWrite;
908    st_scheduleTimeout;
909    p_popDmaRequestQueue;
910  }
911
912  transition(O, DMA_WRITE_All_Tokens, O_DW_W) {
913    vd_allocateDmaRequestInTBE;
914    ld_queueMemoryDmaWriteFromTbe;
915    p_popDmaRequestQueue;
916  }
917
918  transition(O, GETS, NO_W) {
919    qf_queueMemoryFetchRequest;
920    j_popIncomingRequestQueue;
921  }
922
923  transition(O, DMA_READ, O_DR_W) {
924    vd_allocateDmaRequestInTBE;
925    fd_memoryDma;
926    st_scheduleTimeout;
927    p_popDmaRequestQueue;
928  }
929
930  transition(O, Lockdown, L_O_W) {
931    qp_queueMemoryForPersistent;
932    l_popIncomingPersistentQueue;
933  }
934
935  transition(O, {Tokens, Ack_All_Tokens}) {
936    f_incrementTokens;
937    k_popIncomingResponseQueue;
938  }
939
940  transition(O, {Data_Owner, Data_All_Tokens}) {
941    f_incrementTokens;
942    k_popIncomingResponseQueue;
943  }
944
945  transition({O, NO}, Unlockdown) {
946    l_popIncomingPersistentQueue;
947  }
948
949  //
950  // transitioning to Owner, waiting for memory before DMA ack
951  // All other events should recycle/stall
952  //
953  transition(O_DR_W, Memory_Data, O) {
954    dm_sendMemoryDataToDma;
955    ut_unsetReissueTimer;
956    s_deallocateTBE;
957    l_popMemQueue;
958  }
959
960  //
961  // issued GETX for DMA write, waiting for all tokens
962  //
963  transition(O_DW, Request_Timeout) {
964    ut_unsetReissueTimer;
965    px_tryIssuingPersistentGETXRequest;
966  }
967
968  transition(O_DW, Tokens) {
969    f_incrementTokens;
970    k_popIncomingResponseQueue;
971  }
972
973  transition(O_DW, Data_Owner) {
974    f_incrementTokens;
975    rd_recordDataInTbe;
976    k_popIncomingResponseQueue;
977  }
978
979  transition(O_DW, Ack_Owner) {
980    f_incrementTokens;
981    k_popIncomingResponseQueue;
982  }
983
984  transition(O_DW, Lockdown, DW_L) {
985    de_sendTbeDataToStarver;
986    l_popIncomingPersistentQueue;
987  }
988
989  transition({NO_DW, O_DW}, Data_All_Tokens, O_DW_W) {
990    f_incrementTokens;
991    rd_recordDataInTbe;
992    ld_queueMemoryDmaWriteFromTbe;
993    ut_unsetReissueTimer;
994    k_popIncomingResponseQueue;
995  }
996
997  transition(O_DW, Ack_All_Tokens, O_DW_W) {
998    f_incrementTokens;
999    ld_queueMemoryDmaWriteFromTbe;
1000    ut_unsetReissueTimer;
1001    k_popIncomingResponseQueue;
1002  }
1003
1004  transition(O_DW, Ack_Owner_All_Tokens, O_DW_W) {
1005    f_incrementTokens;
1006    ld_queueMemoryDmaWriteFromTbe;
1007    ut_unsetReissueTimer;
1008    k_popIncomingResponseQueue;
1009  }
1010
1011  transition(O_DW_W, Memory_Ack, O) {
1012    da_sendDmaAck;
1013    s_deallocateTBE;
1014    l_popMemQueue;
1015  }
1016
1017  //
1018  // Trans. from NO
1019  // The direcotry does not have valid data, but may have some tokens
1020  //
1021  transition(NO, GETX) {
1022    a_sendTokens;
1023    j_popIncomingRequestQueue;
1024  }
1025
1026  transition(NO, DMA_WRITE, NO_DW) {
1027    vd_allocateDmaRequestInTBE;
1028    bw_broadcastWrite;
1029    st_scheduleTimeout;
1030    p_popDmaRequestQueue;
1031  }
1032
1033  transition(NO, GETS) {
1034    j_popIncomingRequestQueue;
1035  }
1036
1037  transition(NO, DMA_READ, NO_DR) {
1038    vd_allocateDmaRequestInTBE;
1039    br_broadcastRead;
1040    st_scheduleTimeout;
1041    p_popDmaRequestQueue;
1042  }
1043
1044  transition(NO, Lockdown, L) {
1045    aa_sendTokensToStarver;
1046    l_popIncomingPersistentQueue;
1047  }
1048
1049  transition(NO, {Data_Owner, Data_All_Tokens}, O_W) {
1050    f_incrementTokens;
1051    lq_queueMemoryWbRequest;
1052    k_popIncomingResponseQueue;
1053  }
1054
1055  transition(NO, {Ack_Owner, Ack_Owner_All_Tokens}, O) {
1056    f_incrementTokens;
1057    k_popIncomingResponseQueue;
1058  }
1059
1060  transition(NO, Tokens) {
1061    f_incrementTokens;
1062    k_popIncomingResponseQueue;
1063  }
1064
1065  transition(NO_W, Memory_Data, NO) {
1066    d_sendMemoryDataWithAllTokens;
1067    l_popMemQueue;
1068  }
1069
1070  // Trans. from NO_DW
1071  transition(NO_DW, Request_Timeout) {
1072    ut_unsetReissueTimer;
1073    px_tryIssuingPersistentGETXRequest;
1074  }
1075
1076  transition(NO_DW, Lockdown, DW_L) {
1077    aa_sendTokensToStarver;
1078    l_popIncomingPersistentQueue;
1079  }
1080
1081  // Note: NO_DW, Data_All_Tokens transition is combined with O_DW
1082  // Note: NO_DW should not receive the action Ack_All_Tokens because the
1083  // directory does not have valid data
1084
1085  transition(NO_DW, Data_Owner, O_DW) {
1086    f_incrementTokens;
1087    rd_recordDataInTbe;
1088    k_popIncomingResponseQueue;
1089  }
1090
1091  transition({NO_DW, NO_DR}, Tokens) {
1092    f_incrementTokens;
1093    k_popIncomingResponseQueue;
1094  }
1095
1096  // Trans. from NO_DR
1097  transition(NO_DR, Request_Timeout) {
1098    ut_unsetReissueTimer;
1099    ps_tryIssuingPersistentGETSRequest;
1100  }
1101
1102  transition(NO_DR, Lockdown, DR_L) {
1103    aa_sendTokensToStarver;
1104    l_popIncomingPersistentQueue;
1105  }
1106
1107  transition(NO_DR, {Data_Owner, Data_All_Tokens}, O_W) {
1108    f_incrementTokens;
1109    dd_sendDmaData;
1110    lr_queueMemoryDmaReadWriteback;
1111    ut_unsetReissueTimer;
1112    s_deallocateTBE;
1113    k_popIncomingResponseQueue;
1114  }
1115
1116  // Trans. from L
1117  transition({L, DW_L, DR_L}, {GETX, GETS}) {
1118    j_popIncomingRequestQueue;
1119  }
1120
1121  transition({L, DW_L, DR_L, L_O_W, L_NO_W, DR_L_W, DW_L_W}, Lockdown) {
1122    l_popIncomingPersistentQueue;
1123  }
1124
1125  //
1126  // Received data for lockdown blocks
1127  // For blocks with outstanding dma requests to them
1128  // ...we could change this to write the data to memory and send it cleanly
1129  // ...we could also proactively complete our DMA requests
1130  // However, to keep my mind from spinning out-of-control, we won't for now :)
1131  //
1132  transition({DW_L, DR_L, L}, {Data_Owner, Data_All_Tokens}) {
1133    r_bounceResponse;
1134    k_popIncomingResponseQueue;
1135  }
1136
1137  transition({DW_L, DR_L, L}, Tokens) {
1138    r_bounceResponse;
1139    k_popIncomingResponseQueue;
1140  }
1141
1142  transition({DW_L, DR_L}, {Ack_Owner_All_Tokens, Ack_Owner}) {
1143    bd_bounceDatalessOwnerToken;
1144    k_popIncomingResponseQueue;
1145  }
1146
1147  transition(L, {Ack_Owner_All_Tokens, Ack_Owner}, L_O_W) {
1148    f_incrementTokens;
1149    qp_queueMemoryForPersistent;
1150    k_popIncomingResponseQueue;
1151  }
1152
1153  transition(L, {Unlockdown, Own_Lock_or_Unlock}, NO) {
1154    l_popIncomingPersistentQueue;
1155  }
1156
1157  transition(L, Own_Lock_or_Unlock_Tokens, O) {
1158    l_popIncomingPersistentQueue;
1159  }
1160
1161  transition({L_NO_W, L_O_W}, Memory_Data, L) {
1162    dd_sendMemDataToStarver;
1163    l_popMemQueue;
1164  }
1165
1166  transition(L_O_W, Memory_Ack) {
1167    qp_queueMemoryForPersistent;
1168    l_popMemQueue;
1169  }
1170
1171  transition(L_O_W, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}, O_W) {
1172    l_popIncomingPersistentQueue;
1173  }
1174
1175  transition(L_NO_W, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}, NO_W) {
1176    l_popIncomingPersistentQueue;
1177  }
1178
1179  transition(DR_L_W, Memory_Data, DR_L) {
1180    dd_sendMemDataToStarver;
1181    l_popMemQueue;
1182  }
1183
1184  transition(DW_L_W, Memory_Ack, L) {
1185    aat_assertAllTokens;
1186    da_sendDmaAck;
1187    s_deallocateTBE;
1188    dd_sendMemDataToStarver;
1189    l_popMemQueue;
1190  }
1191
1192  transition(DW_L, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}, NO_DW) {
1193    l_popIncomingPersistentQueue;
1194  }
1195
1196  transition(DR_L_W, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}, O_DR_W) {
1197    l_popIncomingPersistentQueue;
1198  }
1199
1200  transition(DW_L_W, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}, O_DW_W) {
1201    l_popIncomingPersistentQueue;
1202  }
1203
1204  transition({DW_L, DR_L_W, DW_L_W}, Request_Timeout) {
1205    ut_unsetReissueTimer;
1206    px_tryIssuingPersistentGETXRequest;
1207  }
1208
1209  transition(DR_L, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}, NO_DR) {
1210    l_popIncomingPersistentQueue;
1211  }
1212
1213  transition(DR_L, Request_Timeout) {
1214    ut_unsetReissueTimer;
1215    ps_tryIssuingPersistentGETSRequest;
1216  }
1217
1218  //
1219  // The O_W + Memory_Data > O transistion is confusing, but it can happen if a
1220  // presistent request is issued and resolve before memory returns with data
1221  //
1222  transition(O_W, {Memory_Ack, Memory_Data}, O) {
1223    l_popMemQueue;
1224  }
1225
1226  transition({O, NO}, {Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}) {
1227    l_popIncomingPersistentQueue;
1228  }
1229
1230  // Blocked states
1231  transition({NO_W, O_W, L_O_W, L_NO_W, DR_L_W, DW_L_W, O_DW_W, O_DR_W, O_DW, NO_DW, NO_DR}, {GETX, GETS}) {
1232    z_recycleRequest;
1233  }
1234
1235  transition({NO_W, O_W, L_O_W, L_NO_W, DR_L_W, DW_L_W, O_DW_W, O_DR_W, O_DW, NO_DW, NO_DR, L, DW_L, DR_L}, {DMA_READ, DMA_WRITE, DMA_WRITE_All_Tokens}) {
1236    y_recycleDmaRequestQueue;
1237  }
1238
1239  transition({NO_W, O_W, L_O_W, L_NO_W, DR_L_W, DW_L_W, O_DW_W, O_DR_W}, {Data_Owner, Ack_Owner, Tokens, Data_All_Tokens, Ack_All_Tokens}) {
1240    kz_recycleResponse;
1241  }
1242
1243  //
1244  // If we receive a request timeout while waiting for memory, it is likely that
1245  // the request will be satisfied and issuing a presistent request will do us
1246  // no good.  Just wait.
1247  //
1248  transition({O_DW_W, O_DR_W}, Request_Timeout) {
1249    rs_resetScheduleTimeout;
1250  }
1251
1252  transition(NO_W, Lockdown, L_NO_W) {
1253    l_popIncomingPersistentQueue;
1254  }
1255
1256  transition(O_W, Lockdown, L_O_W) {
1257    l_popIncomingPersistentQueue;
1258  }
1259
1260  transition(O_DR_W, Lockdown, DR_L_W) {
1261    l_popIncomingPersistentQueue;
1262  }
1263
1264  transition(O_DW_W, Lockdown, DW_L_W) {
1265    l_popIncomingPersistentQueue;
1266  }
1267
1268  transition({NO_W, O_W, O_DR_W, O_DW_W, O_DW, NO_DR, NO_DW}, {Unlockdown, Own_Lock_or_Unlock, Own_Lock_or_Unlock_Tokens}) {
1269    l_popIncomingPersistentQueue;
1270  }
1271}
1272