1/*
2 * Copyright (c) 2010-2015 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * For use for simulation and test purposes only
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Authors: Lisa Hsu
34 */
35
36machine(MachineType:Directory, "AMD Baseline protocol")
37: DirectoryMemory * directory;
38  CacheMemory * L3CacheMemory;
39  Cycles response_latency := 5;
40  Cycles l3_hit_latency := 50;
41  bool noTCCdir := "False";
42  bool CPUonly := "False";
43  int TCC_select_num_bits;
44  bool useL3OnWT := "False";
45  Cycles to_memory_controller_latency := 1;
46
47  // From the Cores
48  MessageBuffer * requestFromCores, network="From", virtual_network="0", vnet_type="request";
49  MessageBuffer * responseFromCores, network="From", virtual_network="2", vnet_type="response";
50  MessageBuffer * unblockFromCores, network="From", virtual_network="4", vnet_type="unblock";
51
52  MessageBuffer * probeToCore, network="To", virtual_network="0", vnet_type="request";
53  MessageBuffer * responseToCore, network="To", virtual_network="2", vnet_type="response";
54
55  MessageBuffer * triggerQueue;
56  MessageBuffer * L3triggerQueue;
57  MessageBuffer * responseFromMemory;
58{
59  // STATES
60  state_declaration(State, desc="Directory states", default="Directory_State_U") {
61    U, AccessPermission:Backing_Store,                 desc="unblocked";
62    BL, AccessPermission:Busy,                  desc="got L3 WB request";
63    // BL is Busy because it's possible for the data only to be in the network
64    // in the WB, L3 has sent it and gone on with its business in possibly I
65    // state.
66    BS_M, AccessPermission:Backing_Store,                 desc="blocked waiting for memory";
67    BM_M, AccessPermission:Backing_Store,                 desc="blocked waiting for memory";
68    B_M, AccessPermission:Backing_Store,                 desc="blocked waiting for memory";
69    BP, AccessPermission:Backing_Store,                 desc="blocked waiting for probes, no need for memory";
70    BS_PM, AccessPermission:Backing_Store,                desc="blocked waiting for probes and Memory";
71    BM_PM, AccessPermission:Backing_Store,                desc="blocked waiting for probes and Memory";
72    B_PM, AccessPermission:Backing_Store,                desc="blocked waiting for probes and Memory";
73    BS_Pm, AccessPermission:Backing_Store,                desc="blocked waiting for probes, already got memory";
74    BM_Pm, AccessPermission:Backing_Store,                desc="blocked waiting for probes, already got memory";
75    B_Pm, AccessPermission:Backing_Store,                desc="blocked waiting for probes, already got memory";
76    B, AccessPermission:Backing_Store,                  desc="sent response, Blocked til ack";
77  }
78
79  // Events
80  enumeration(Event, desc="Directory events") {
81    // CPU requests
82    RdBlkS,             desc="...";
83    RdBlkM,             desc="...";
84    RdBlk,              desc="...";
85    CtoD,               desc="...";
86    WriteThrough,       desc="WriteThrough Message";
87    Atomic,             desc="Atomic Message";
88
89    // writebacks
90    VicDirty,           desc="...";
91    VicClean,           desc="...";
92    CPUData,            desc="WB data from CPU";
93    StaleWB,         desc="Notification that WB has been superceded by a probe";
94
95    // probe responses
96    CPUPrbResp,            desc="Probe Response Msg";
97
98    ProbeAcksComplete,  desc="Probe Acks Complete";
99
100    L3Hit,              desc="Hit in L3 return data to core";
101
102    // Memory Controller
103    MemData, desc="Fetched data from memory arrives";
104    WBAck, desc="Writeback Ack from memory arrives";
105
106    CoreUnblock,            desc="Core received data, unblock";
107    UnblockWriteThrough,    desc="Unblock because of writethrough request finishing";
108
109    StaleVicDirty,        desc="Core invalidated before VicDirty processed";
110  }
111
112  enumeration(RequestType, desc="To communicate stats from transitions to recordStats") {
113    L3DataArrayRead,    desc="Read the data array";
114    L3DataArrayWrite,   desc="Write the data array";
115    L3TagArrayRead,     desc="Read the data array";
116    L3TagArrayWrite,    desc="Write the data array";
117  }
118
119  // TYPES
120
121  // DirectoryEntry
122  structure(Entry, desc="...", interface="AbstractEntry") {
123    State DirectoryState,          desc="Directory state";
124    DataBlock DataBlk,             desc="data for the block";
125    NetDest VicDirtyIgnore,  desc="VicDirty coming from whom to ignore";
126  }
127
128  structure(CacheEntry, desc="...", interface="AbstractCacheEntry") {
129    DataBlock DataBlk,          desc="data for the block";
130    MachineID LastSender,       desc="Mach which this block came from";
131  }
132
133  structure(TBE, desc="...") {
134    State TBEState,     desc="Transient state";
135    DataBlock DataBlk,  desc="data for the block";
136    bool Dirty,         desc="Is the data dirty?";
137    int NumPendingAcks,        desc="num acks expected";
138    MachineID OriginalRequestor,        desc="Original Requestor";
139    MachineID WTRequestor,        desc="WT Requestor";
140    bool Cached,        desc="data hit in Cache";
141    bool MemData,       desc="Got MemData?",default="false";
142    bool wtData,       desc="Got write through data?",default="false";
143    bool atomicData,   desc="Got Atomic op?",default="false";
144    Cycles InitialRequestTime, desc="...";
145    Cycles ForwardRequestTime, desc="...";
146    Cycles ProbeRequestStartTime, desc="...";
147    MachineID LastSender, desc="Mach which this block came from";
148    bool L3Hit, default="false", desc="Was this an L3 hit?";
149    uint64_t probe_id,        desc="probe id for lifetime profiling";
150    WriteMask writeMask,    desc="outstanding write through mask";
151  }
152
153  structure(TBETable, external="yes") {
154    TBE lookup(Addr);
155    void allocate(Addr);
156    void deallocate(Addr);
157    bool isPresent(Addr);
158  }
159
160  TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
161
162  int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()";
163
164  Tick clockEdge();
165  Tick cyclesToTicks(Cycles c);
166
167  void set_tbe(TBE a);
168  void unset_tbe();
169  void wakeUpAllBuffers();
170  void wakeUpBuffers(Addr a);
171  Cycles curCycle();
172
173  Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
174    Entry dir_entry := static_cast(Entry, "pointer", directory.lookup(addr));
175
176    if (is_valid(dir_entry)) {
177      return dir_entry;
178    }
179
180    dir_entry :=  static_cast(Entry, "pointer",
181                              directory.allocate(addr, new Entry));
182    return dir_entry;
183  }
184
185  DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
186    TBE tbe := TBEs.lookup(addr);
187    if (is_valid(tbe) && tbe.MemData) {
188      DPRINTF(RubySlicc, "Returning DataBlk from TBE %s:%s\n", addr, tbe);
189      return tbe.DataBlk;
190    }
191    DPRINTF(RubySlicc, "Returning DataBlk from Dir %s:%s\n", addr, getDirectoryEntry(addr));
192    return getDirectoryEntry(addr).DataBlk;
193  }
194
195  State getState(TBE tbe, CacheEntry entry, Addr addr) {
196    return getDirectoryEntry(addr).DirectoryState;
197  }
198
199  void setState(TBE tbe, CacheEntry entry, Addr addr, State state) {
200    getDirectoryEntry(addr).DirectoryState := state;
201  }
202
203  void functionalRead(Addr addr, Packet *pkt) {
204    TBE tbe := TBEs.lookup(addr);
205    if(is_valid(tbe)) {
206      testAndRead(addr, tbe.DataBlk, pkt);
207    } else {
208      functionalMemoryRead(pkt);
209    }
210  }
211
212  int functionalWrite(Addr addr, Packet *pkt) {
213    int num_functional_writes := 0;
214
215    TBE tbe := TBEs.lookup(addr);
216    if(is_valid(tbe)) {
217      num_functional_writes := num_functional_writes +
218            testAndWrite(addr, tbe.DataBlk, pkt);
219    }
220
221    num_functional_writes := num_functional_writes
222        + functionalMemoryWrite(pkt);
223    return num_functional_writes;
224  }
225
226  AccessPermission getAccessPermission(Addr addr) {
227    // For this Directory, all permissions are just tracked in Directory, since
228    // it's not possible to have something in TBE but not Dir, just keep track
229    // of state all in one place.
230    if (directory.isPresent(addr)) {
231      return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
232    }
233
234    return AccessPermission:NotPresent;
235  }
236
237  void setAccessPermission(CacheEntry entry, Addr addr, State state) {
238    getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
239  }
240
241  void recordRequestType(RequestType request_type, Addr addr) {
242    if (request_type == RequestType:L3DataArrayRead) {
243        L3CacheMemory.recordRequestType(CacheRequestType:DataArrayRead, addr);
244    } else if (request_type == RequestType:L3DataArrayWrite) {
245        L3CacheMemory.recordRequestType(CacheRequestType:DataArrayWrite, addr);
246    } else if (request_type == RequestType:L3TagArrayRead) {
247        L3CacheMemory.recordRequestType(CacheRequestType:TagArrayRead, addr);
248    } else if (request_type == RequestType:L3TagArrayWrite) {
249        L3CacheMemory.recordRequestType(CacheRequestType:TagArrayWrite, addr);
250    }
251  }
252
253  bool checkResourceAvailable(RequestType request_type, Addr addr) {
254    if (request_type == RequestType:L3DataArrayRead) {
255      return L3CacheMemory.checkResourceAvailable(CacheResourceType:DataArray, addr);
256    } else if (request_type == RequestType:L3DataArrayWrite) {
257      return L3CacheMemory.checkResourceAvailable(CacheResourceType:DataArray, addr);
258    } else if (request_type == RequestType:L3TagArrayRead) {
259      return L3CacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr);
260    } else if (request_type == RequestType:L3TagArrayWrite) {
261      return L3CacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr);
262    } else {
263      error("Invalid RequestType type in checkResourceAvailable");
264      return true;
265    }
266  }
267
268  // ** OUT_PORTS **
269  out_port(probeNetwork_out, NBProbeRequestMsg, probeToCore);
270  out_port(responseNetwork_out, ResponseMsg, responseToCore);
271
272  out_port(triggerQueue_out, TriggerMsg, triggerQueue);
273  out_port(L3TriggerQueue_out, TriggerMsg, L3triggerQueue);
274
275  // ** IN_PORTS **
276
277  // Trigger Queue
278  in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=5) {
279    if (triggerQueue_in.isReady(clockEdge())) {
280      peek(triggerQueue_in, TriggerMsg) {
281        TBE tbe := TBEs.lookup(in_msg.addr);
282        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
283        if (in_msg.Type == TriggerType:AcksComplete) {
284          trigger(Event:ProbeAcksComplete, in_msg.addr, entry, tbe);
285        }else if (in_msg.Type == TriggerType:UnblockWriteThrough) {
286          trigger(Event:UnblockWriteThrough, in_msg.addr, entry, tbe);
287        } else {
288          error("Unknown trigger msg");
289        }
290      }
291    }
292  }
293
294  in_port(L3TriggerQueue_in, TriggerMsg, L3triggerQueue, rank=4) {
295    if (L3TriggerQueue_in.isReady(clockEdge())) {
296      peek(L3TriggerQueue_in, TriggerMsg) {
297        TBE tbe := TBEs.lookup(in_msg.addr);
298        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
299        if (in_msg.Type == TriggerType:L3Hit) {
300          trigger(Event:L3Hit, in_msg.addr, entry, tbe);
301        } else {
302          error("Unknown trigger msg");
303        }
304      }
305    }
306  }
307
308  // Unblock Network
309  in_port(unblockNetwork_in, UnblockMsg, unblockFromCores, rank=3) {
310    if (unblockNetwork_in.isReady(clockEdge())) {
311      peek(unblockNetwork_in, UnblockMsg) {
312        TBE tbe := TBEs.lookup(in_msg.addr);
313        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
314        trigger(Event:CoreUnblock, in_msg.addr, entry, tbe);
315      }
316    }
317  }
318
319  // Core response network
320  in_port(responseNetwork_in, ResponseMsg, responseFromCores, rank=2) {
321    if (responseNetwork_in.isReady(clockEdge())) {
322      peek(responseNetwork_in, ResponseMsg) {
323        TBE tbe := TBEs.lookup(in_msg.addr);
324        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
325        if (in_msg.Type == CoherenceResponseType:CPUPrbResp) {
326          trigger(Event:CPUPrbResp, in_msg.addr, entry, tbe);
327        } else if (in_msg.Type == CoherenceResponseType:CPUData) {
328          trigger(Event:CPUData, in_msg.addr, entry, tbe);
329        } else if (in_msg.Type == CoherenceResponseType:StaleNotif) {
330            trigger(Event:StaleWB, in_msg.addr, entry, tbe);
331        } else {
332          error("Unexpected response type");
333        }
334      }
335    }
336  }
337
338  // off-chip memory request/response is done
339  in_port(memQueue_in, MemoryMsg, responseFromMemory, rank=1) {
340    if (memQueue_in.isReady(clockEdge())) {
341      peek(memQueue_in, MemoryMsg) {
342        TBE tbe := TBEs.lookup(in_msg.addr);
343        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
344        if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
345          trigger(Event:MemData, in_msg.addr, entry, tbe);
346          DPRINTF(RubySlicc, "%s\n", in_msg);
347        } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
348          trigger(Event:WBAck, in_msg.addr, entry, tbe); // ignore WBAcks, don't care about them.
349        } else {
350          DPRINTF(RubySlicc, "%s\n", in_msg.Type);
351          error("Invalid message");
352        }
353      }
354    }
355  }
356
357  in_port(requestNetwork_in, CPURequestMsg, requestFromCores, rank=0) {
358    if (requestNetwork_in.isReady(clockEdge())) {
359      peek(requestNetwork_in, CPURequestMsg) {
360        TBE tbe := TBEs.lookup(in_msg.addr);
361        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(in_msg.addr));
362        if (in_msg.Type == CoherenceRequestType:RdBlk) {
363          trigger(Event:RdBlk, in_msg.addr, entry, tbe);
364        } else if (in_msg.Type == CoherenceRequestType:RdBlkS) {
365          trigger(Event:RdBlkS, in_msg.addr, entry, tbe);
366        } else if (in_msg.Type == CoherenceRequestType:RdBlkM) {
367          trigger(Event:RdBlkM, in_msg.addr, entry, tbe);
368        } else if (in_msg.Type == CoherenceRequestType:WriteThrough) {
369          trigger(Event:WriteThrough, in_msg.addr, entry, tbe);
370        } else if (in_msg.Type == CoherenceRequestType:Atomic) {
371          trigger(Event:Atomic, in_msg.addr, entry, tbe);
372        } else if (in_msg.Type == CoherenceRequestType:VicDirty) {
373          if (getDirectoryEntry(in_msg.addr).VicDirtyIgnore.isElement(in_msg.Requestor)) {
374            DPRINTF(RubySlicc, "Dropping VicDirty for address %s\n", in_msg.addr);
375            trigger(Event:StaleVicDirty, in_msg.addr, entry, tbe);
376          } else {
377            DPRINTF(RubySlicc, "Got VicDirty from %s on %s\n", in_msg.Requestor, in_msg.addr);
378            trigger(Event:VicDirty, in_msg.addr, entry, tbe);
379          }
380        } else if (in_msg.Type == CoherenceRequestType:VicClean) {
381          if (getDirectoryEntry(in_msg.addr).VicDirtyIgnore.isElement(in_msg.Requestor)) {
382            DPRINTF(RubySlicc, "Dropping VicClean for address %s\n", in_msg.addr);
383            trigger(Event:StaleVicDirty, in_msg.addr, entry, tbe);
384          } else {
385            DPRINTF(RubySlicc, "Got VicClean from %s on %s\n", in_msg.Requestor, in_msg.addr);
386            trigger(Event:VicClean, in_msg.addr, entry, tbe);
387          }
388        } else {
389          error("Bad request message type");
390        }
391      }
392    }
393  }
394
395  // Actions
396  action(s_sendResponseS, "s", desc="send Shared response") {
397    enqueue(responseNetwork_out, ResponseMsg, response_latency) {
398      out_msg.addr := address;
399      out_msg.Type := CoherenceResponseType:NBSysResp;
400      if (tbe.L3Hit) {
401        out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0));
402      } else {
403        out_msg.Sender := machineID;
404      }
405      out_msg.Destination.add(tbe.OriginalRequestor);
406      out_msg.DataBlk := tbe.DataBlk;
407      out_msg.MessageSize := MessageSizeType:Response_Data;
408      out_msg.Dirty := false;
409      out_msg.State := CoherenceState:Shared;
410      out_msg.InitialRequestTime := tbe.InitialRequestTime;
411      out_msg.ForwardRequestTime := tbe.ForwardRequestTime;
412      out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
413      out_msg.OriginalResponder := tbe.LastSender;
414      out_msg.L3Hit := tbe.L3Hit;
415      DPRINTF(RubySlicc, "%s\n", out_msg);
416    }
417  }
418
419  action(es_sendResponseES, "es", desc="send Exclusive or Shared response") {
420    enqueue(responseNetwork_out, ResponseMsg, response_latency) {
421      out_msg.addr := address;
422      out_msg.Type := CoherenceResponseType:NBSysResp;
423      if (tbe.L3Hit) {
424        out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0));
425      } else {
426        out_msg.Sender := machineID;
427      }
428      out_msg.Destination.add(tbe.OriginalRequestor);
429      out_msg.DataBlk := tbe.DataBlk;
430      out_msg.MessageSize := MessageSizeType:Response_Data;
431      out_msg.Dirty := tbe.Dirty;
432      if (tbe.Cached) {
433        out_msg.State := CoherenceState:Shared;
434      } else {
435        out_msg.State := CoherenceState:Exclusive;
436      }
437      out_msg.InitialRequestTime := tbe.InitialRequestTime;
438      out_msg.ForwardRequestTime := tbe.ForwardRequestTime;
439      out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
440      out_msg.OriginalResponder := tbe.LastSender;
441      out_msg.L3Hit := tbe.L3Hit;
442      DPRINTF(RubySlicc, "%s\n", out_msg);
443    }
444  }
445
446  action(m_sendResponseM, "m", desc="send Modified response") {
447    if (tbe.wtData) {
448      enqueue(triggerQueue_out, TriggerMsg, 1) {
449        out_msg.addr := address;
450        out_msg.Type := TriggerType:UnblockWriteThrough;
451      }
452    }else{
453      enqueue(responseNetwork_out, ResponseMsg, response_latency) {
454        out_msg.addr := address;
455        out_msg.Type := CoherenceResponseType:NBSysResp;
456        if (tbe.L3Hit) {
457          out_msg.Sender := createMachineID(MachineType:L3Cache, intToID(0));
458        } else {
459          out_msg.Sender := machineID;
460        }
461        out_msg.Destination.add(tbe.OriginalRequestor);
462        out_msg.DataBlk := tbe.DataBlk;
463        out_msg.MessageSize := MessageSizeType:Response_Data;
464        out_msg.Dirty := tbe.Dirty;
465        out_msg.State := CoherenceState:Modified;
466        out_msg.CtoD := false;
467        out_msg.InitialRequestTime := tbe.InitialRequestTime;
468        out_msg.ForwardRequestTime := tbe.ForwardRequestTime;
469        out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
470        out_msg.OriginalResponder := tbe.LastSender;
471        if(tbe.atomicData){
472          out_msg.WTRequestor := tbe.WTRequestor;
473        }
474        out_msg.L3Hit := tbe.L3Hit;
475        DPRINTF(RubySlicc, "%s\n", out_msg);
476      }
477      if (tbe.atomicData) {
478        enqueue(triggerQueue_out, TriggerMsg, 1) {
479          out_msg.addr := address;
480          out_msg.Type := TriggerType:UnblockWriteThrough;
481        }
482      }
483    }
484  }
485
486  action(c_sendResponseCtoD, "c", desc="send CtoD Ack") {
487      enqueue(responseNetwork_out, ResponseMsg, response_latency) {
488        out_msg.addr := address;
489        out_msg.Type := CoherenceResponseType:NBSysResp;
490        out_msg.Sender := machineID;
491        out_msg.Destination.add(tbe.OriginalRequestor);
492        out_msg.MessageSize := MessageSizeType:Response_Control;
493        out_msg.Dirty := false;
494        out_msg.State := CoherenceState:Modified;
495        out_msg.CtoD := true;
496        out_msg.InitialRequestTime := tbe.InitialRequestTime;
497        out_msg.ForwardRequestTime := curCycle();
498        out_msg.ProbeRequestStartTime := tbe.ProbeRequestStartTime;
499        DPRINTF(RubySlicc, "%s\n", out_msg);
500      }
501  }
502
503  action(w_sendResponseWBAck, "w", desc="send WB Ack") {
504    peek(requestNetwork_in, CPURequestMsg) {
505      enqueue(responseNetwork_out, ResponseMsg, 1) {
506        out_msg.addr := address;
507        out_msg.Type := CoherenceResponseType:NBSysWBAck;
508        out_msg.Destination.add(in_msg.Requestor);
509        out_msg.WTRequestor := in_msg.WTRequestor;
510        out_msg.Sender := machineID;
511        out_msg.MessageSize := MessageSizeType:Writeback_Control;
512        out_msg.InitialRequestTime := in_msg.InitialRequestTime;
513        out_msg.ForwardRequestTime := curCycle();
514        out_msg.ProbeRequestStartTime := curCycle();
515      }
516    }
517  }
518
519  action(l_queueMemWBReq, "lq", desc="Write WB data to memory") {
520    peek(responseNetwork_in, ResponseMsg) {
521      queueMemoryWrite(machineID, address, to_memory_controller_latency,
522                       in_msg.DataBlk);
523    }
524  }
525
526  action(l_queueMemRdReq, "lr", desc="Read data from memory") {
527    peek(requestNetwork_in, CPURequestMsg) {
528      if (L3CacheMemory.isTagPresent(address)) {
529        enqueue(L3TriggerQueue_out, TriggerMsg, l3_hit_latency) {
530          out_msg.addr := address;
531          out_msg.Type := TriggerType:L3Hit;
532          DPRINTF(RubySlicc, "%s\n", out_msg);
533        }
534        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address));
535        if (tbe.Dirty == false) {
536          tbe.DataBlk := entry.DataBlk;
537        }
538        tbe.LastSender := entry.LastSender;
539        tbe.L3Hit := true;
540        tbe.MemData := true;
541        L3CacheMemory.deallocate(address);
542      } else {
543        queueMemoryRead(machineID, address, to_memory_controller_latency);
544      }
545    }
546  }
547
548  action(dc_probeInvCoreData, "dc", desc="probe inv cores, return data") {
549    peek(requestNetwork_in, CPURequestMsg) {
550      enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
551        out_msg.addr := address;
552        out_msg.Type := ProbeRequestType:PrbInv;
553        out_msg.ReturnData := true;
554        out_msg.MessageSize := MessageSizeType:Control;
555        out_msg.Destination.broadcast(MachineType:CorePair);  // won't be realistic for multisocket
556
557        // add relevant TCC node to list. This replaces all TCPs and SQCs
558        if (((in_msg.Type == CoherenceRequestType:WriteThrough ||
559              in_msg.Type == CoherenceRequestType:Atomic) &&
560             in_msg.NoWriteConflict) ||
561            CPUonly) {
562        } else if (noTCCdir) {
563          out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
564                                  TCC_select_low_bit, TCC_select_num_bits));
565        } else {
566	      out_msg.Destination.add(mapAddressToRange(address,
567                                                    MachineType:TCCdir,
568                            TCC_select_low_bit, TCC_select_num_bits));
569        }
570        out_msg.Destination.remove(in_msg.Requestor);
571        tbe.NumPendingAcks := out_msg.Destination.count();
572        if (tbe.NumPendingAcks == 0) {
573          enqueue(triggerQueue_out, TriggerMsg, 1) {
574            out_msg.addr := address;
575            out_msg.Type := TriggerType:AcksComplete;
576          }
577        }
578        DPRINTF(RubySlicc, "%s\n", out_msg);
579        APPEND_TRANSITION_COMMENT(" dc: Acks remaining: ");
580        APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
581        tbe.ProbeRequestStartTime := curCycle();
582      }
583    }
584  }
585
586  action(sc_probeShrCoreData, "sc", desc="probe shared cores, return data") {
587    peek(requestNetwork_in, CPURequestMsg) { // not the right network?
588      enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
589        out_msg.addr := address;
590        out_msg.Type := ProbeRequestType:PrbDowngrade;
591        out_msg.ReturnData := true;
592        out_msg.MessageSize := MessageSizeType:Control;
593        out_msg.Destination.broadcast(MachineType:CorePair);  // won't be realistic for multisocket
594        // add relevant TCC node to the list. This replaces all TCPs and SQCs
595        if (noTCCdir || CPUonly) {
596          //Don't need to notify TCC about reads
597        } else {
598	      out_msg.Destination.add(mapAddressToRange(address,
599                                                    MachineType:TCCdir,
600                            TCC_select_low_bit, TCC_select_num_bits));
601          tbe.NumPendingAcks := tbe.NumPendingAcks + 1;
602        }
603        if (noTCCdir && !CPUonly) {
604          out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
605                                  TCC_select_low_bit, TCC_select_num_bits));
606        }
607        out_msg.Destination.remove(in_msg.Requestor);
608        tbe.NumPendingAcks := out_msg.Destination.count();
609        if (tbe.NumPendingAcks == 0) {
610          enqueue(triggerQueue_out, TriggerMsg, 1) {
611            out_msg.addr := address;
612            out_msg.Type := TriggerType:AcksComplete;
613          }
614        }
615        DPRINTF(RubySlicc, "%s\n", (out_msg));
616        APPEND_TRANSITION_COMMENT(" sc: Acks remaining: ");
617        APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
618        tbe.ProbeRequestStartTime := curCycle();
619      }
620    }
621  }
622
623  action(ic_probeInvCore, "ic", desc="probe invalidate core, no return data needed") {
624    peek(requestNetwork_in, CPURequestMsg) { // not the right network?
625      enqueue(probeNetwork_out, NBProbeRequestMsg, response_latency) {
626        out_msg.addr := address;
627        out_msg.Type := ProbeRequestType:PrbInv;
628        out_msg.ReturnData := false;
629        out_msg.MessageSize := MessageSizeType:Control;
630        out_msg.Destination.broadcast(MachineType:CorePair);  // won't be realistic for multisocket
631
632        // add relevant TCC node to the list. This replaces all TCPs and SQCs
633        if (noTCCdir && !CPUonly) {
634            out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
635                              TCC_select_low_bit, TCC_select_num_bits));
636        } else {
637            if (!noTCCdir) {
638                out_msg.Destination.add(mapAddressToRange(address,
639                                                          MachineType:TCCdir,
640                                                          TCC_select_low_bit,
641                                                          TCC_select_num_bits));
642            }
643        }
644        out_msg.Destination.remove(in_msg.Requestor);
645        tbe.NumPendingAcks := out_msg.Destination.count();
646        if (tbe.NumPendingAcks == 0) {
647          enqueue(triggerQueue_out, TriggerMsg, 1) {
648            out_msg.addr := address;
649            out_msg.Type := TriggerType:AcksComplete;
650          }
651        }
652        APPEND_TRANSITION_COMMENT(" ic: Acks remaining: ");
653        APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
654        DPRINTF(RubySlicc, "%s\n", out_msg);
655        tbe.ProbeRequestStartTime := curCycle();
656      }
657    }
658  }
659
660  action(d_writeDataToMemory, "d", desc="Write data to memory") {
661    peek(responseNetwork_in, ResponseMsg) {
662      getDirectoryEntry(address).DataBlk := in_msg.DataBlk;
663      if (tbe.Dirty == false) {
664          // have to update the TBE, too, because of how this
665          // directory deals with functional writes
666        tbe.DataBlk := in_msg.DataBlk;
667      }
668    }
669  }
670
671  action(t_allocateTBE, "t", desc="allocate TBE Entry") {
672    check_allocate(TBEs);
673    peek(requestNetwork_in, CPURequestMsg) {
674      TBEs.allocate(address);
675      set_tbe(TBEs.lookup(address));
676      if (in_msg.Type == CoherenceRequestType:WriteThrough) {
677        tbe.writeMask.clear();
678        tbe.writeMask.orMask(in_msg.writeMask);
679        tbe.wtData := true;
680        tbe.WTRequestor := in_msg.WTRequestor;
681        tbe.LastSender := in_msg.Requestor;
682      }
683      if (in_msg.Type == CoherenceRequestType:Atomic) {
684        tbe.writeMask.clear();
685        tbe.writeMask.orMask(in_msg.writeMask);
686        tbe.atomicData := true;
687        tbe.WTRequestor := in_msg.WTRequestor;
688        tbe.LastSender := in_msg.Requestor;
689      }
690      tbe.DataBlk := getDirectoryEntry(address).DataBlk; // Data only for WBs
691      tbe.Dirty := false;
692      if (in_msg.Type == CoherenceRequestType:WriteThrough) {
693        tbe.DataBlk.copyPartial(in_msg.DataBlk,in_msg.writeMask);
694        tbe.Dirty := true;
695      }
696      tbe.OriginalRequestor := in_msg.Requestor;
697      tbe.NumPendingAcks := 0;
698      tbe.Cached := in_msg.ForceShared;
699      tbe.InitialRequestTime := in_msg.InitialRequestTime;
700    }
701  }
702
703  action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") {
704    if (tbe.Dirty == false) {
705        getDirectoryEntry(address).DataBlk := tbe.DataBlk;
706    }
707    TBEs.deallocate(address);
708    unset_tbe();
709  }
710
711  action(wd_writeBackData, "wd", desc="Write back data if needed") {
712    if (tbe.wtData) {
713      getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, tbe.writeMask);
714    } else if (tbe.atomicData) {
715      tbe.DataBlk.atomicPartial(getDirectoryEntry(address).DataBlk,tbe.writeMask);
716      getDirectoryEntry(address).DataBlk := tbe.DataBlk;
717    } else if (tbe.Dirty == false) {
718      getDirectoryEntry(address).DataBlk := tbe.DataBlk;
719    }
720  }
721
722  action(mt_writeMemDataToTBE, "mt", desc="write Mem data to TBE") {
723    peek(memQueue_in, MemoryMsg) {
724      if (tbe.wtData == true) {
725          // do nothing
726      } else if (tbe.Dirty == false) {
727        tbe.DataBlk := getDirectoryEntry(address).DataBlk;
728      }
729      tbe.MemData := true;
730    }
731  }
732
733  action(y_writeProbeDataToTBE, "y", desc="write Probe Data to TBE") {
734    peek(responseNetwork_in, ResponseMsg) {
735      if (in_msg.Dirty) {
736        if (tbe.wtData) {
737          DataBlock tmp := in_msg.DataBlk;
738          tmp.copyPartial(tbe.DataBlk,tbe.writeMask);
739          tbe.DataBlk := tmp;
740          tbe.writeMask.fillMask();
741        } else if (tbe.Dirty) {
742          if(tbe.atomicData == false && tbe.wtData == false) {
743            DPRINTF(RubySlicc, "Got double data for %s from %s\n", address, in_msg.Sender);
744            assert(tbe.DataBlk == in_msg.DataBlk);  // in case of double data
745          }
746        } else {
747          tbe.DataBlk := in_msg.DataBlk;
748          tbe.Dirty := in_msg.Dirty;
749          tbe.LastSender := in_msg.Sender;
750        }
751      }
752      if (in_msg.Hit) {
753        tbe.Cached := true;
754      }
755    }
756  }
757
758  action(mwc_markSinkWriteCancel, "mwc", desc="Mark to sink impending VicDirty") {
759    peek(responseNetwork_in, ResponseMsg) {
760      getDirectoryEntry(address).VicDirtyIgnore.add(in_msg.Sender);
761      APPEND_TRANSITION_COMMENT(" setting bit to sink VicDirty ");
762    }
763  }
764
765  action(x_decrementAcks, "x", desc="decrement Acks pending") {
766    tbe.NumPendingAcks := tbe.NumPendingAcks - 1;
767    APPEND_TRANSITION_COMMENT(" Acks remaining: ");
768    APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
769  }
770
771  action(o_checkForCompletion, "o", desc="check for ack completion") {
772    if (tbe.NumPendingAcks == 0) {
773      enqueue(triggerQueue_out, TriggerMsg, 1) {
774        out_msg.addr := address;
775        out_msg.Type := TriggerType:AcksComplete;
776      }
777    }
778    APPEND_TRANSITION_COMMENT(" Check: Acks remaining: ");
779    APPEND_TRANSITION_COMMENT(tbe.NumPendingAcks);
780  }
781
782  action(rv_removeVicDirtyIgnore, "rv", desc="Remove ignored core") {
783    peek(requestNetwork_in, CPURequestMsg) {
784      getDirectoryEntry(address).VicDirtyIgnore.remove(in_msg.Requestor);
785    }
786  }
787
788  action(al_allocateL3Block, "al", desc="allocate the L3 block on WB") {
789    peek(responseNetwork_in, ResponseMsg) {
790      if (L3CacheMemory.isTagPresent(address)) {
791        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address));
792        APPEND_TRANSITION_COMMENT(" al wrote data to L3 (hit) ");
793        entry.DataBlk := in_msg.DataBlk;
794        entry.LastSender := in_msg.Sender;
795      } else {
796        if (L3CacheMemory.cacheAvail(address) == false) {
797          Addr victim := L3CacheMemory.cacheProbe(address);
798          CacheEntry victim_entry := static_cast(CacheEntry, "pointer",
799                                                 L3CacheMemory.lookup(victim));
800          queueMemoryWrite(machineID, victim, to_memory_controller_latency,
801                           victim_entry.DataBlk);
802          L3CacheMemory.deallocate(victim);
803        }
804        assert(L3CacheMemory.cacheAvail(address));
805        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.allocate(address, new CacheEntry));
806        APPEND_TRANSITION_COMMENT(" al wrote data to L3 ");
807        entry.DataBlk := in_msg.DataBlk;
808
809        entry.LastSender := in_msg.Sender;
810      }
811    }
812  }
813
814  action(alwt_allocateL3BlockOnWT, "alwt", desc="allocate the L3 block on WT") {
815    if ((tbe.wtData || tbe.atomicData) && useL3OnWT) {
816      if (L3CacheMemory.isTagPresent(address)) {
817        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.lookup(address));
818        APPEND_TRANSITION_COMMENT(" al wrote data to L3 (hit) ");
819        entry.DataBlk := tbe.DataBlk;
820        entry.LastSender := tbe.LastSender;
821      } else {
822        if (L3CacheMemory.cacheAvail(address) == false) {
823          Addr victim := L3CacheMemory.cacheProbe(address);
824          CacheEntry victim_entry := static_cast(CacheEntry, "pointer",
825                                                 L3CacheMemory.lookup(victim));
826          queueMemoryWrite(machineID, victim, to_memory_controller_latency,
827                           victim_entry.DataBlk);
828          L3CacheMemory.deallocate(victim);
829        }
830        assert(L3CacheMemory.cacheAvail(address));
831        CacheEntry entry := static_cast(CacheEntry, "pointer", L3CacheMemory.allocate(address, new CacheEntry));
832        APPEND_TRANSITION_COMMENT(" al wrote data to L3 ");
833        entry.DataBlk := tbe.DataBlk;
834        entry.LastSender := tbe.LastSender;
835      }
836    }
837  }
838
839  action(sf_setForwardReqTime, "sf", desc="...") {
840    tbe.ForwardRequestTime := curCycle();
841  }
842
843  action(dl_deallocateL3, "dl", desc="deallocate the L3 block") {
844    L3CacheMemory.deallocate(address);
845  }
846
847  action(p_popRequestQueue, "p", desc="pop request queue") {
848    requestNetwork_in.dequeue(clockEdge());
849  }
850
851  action(pr_popResponseQueue, "pr", desc="pop response queue") {
852    responseNetwork_in.dequeue(clockEdge());
853  }
854
855  action(pm_popMemQueue, "pm", desc="pop mem queue") {
856    memQueue_in.dequeue(clockEdge());
857  }
858
859  action(pt_popTriggerQueue, "pt", desc="pop trigger queue") {
860    triggerQueue_in.dequeue(clockEdge());
861  }
862
863  action(ptl_popTriggerQueue, "ptl", desc="pop L3 trigger queue") {
864    L3TriggerQueue_in.dequeue(clockEdge());
865  }
866
867  action(pu_popUnblockQueue, "pu", desc="pop unblock queue") {
868    unblockNetwork_in.dequeue(clockEdge());
869  }
870
871  action(zz_recycleRequestQueue, "zz", desc="recycle request queue") {
872    requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
873  }
874
875  action(yy_recycleResponseQueue, "yy", desc="recycle response queue") {
876    responseNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
877  }
878
879  action(st_stallAndWaitRequest, "st", desc="Stall and wait on the address") {
880    stall_and_wait(requestNetwork_in, address);
881  }
882
883  action(wa_wakeUpDependents, "wa", desc="Wake up any requests waiting for this address") {
884    wakeUpBuffers(address);
885  }
886
887  action(wa_wakeUpAllDependents, "waa", desc="Wake up any requests waiting for this region") {
888    wakeUpAllBuffers();
889  }
890
891  action(z_stall, "z", desc="...") {
892  }
893
894  // TRANSITIONS
895  transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, {RdBlkS, RdBlkM, RdBlk, CtoD}) {
896      st_stallAndWaitRequest;
897  }
898
899  // It may be possible to save multiple invalidations here!
900  transition({BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, {Atomic, WriteThrough}) {
901      st_stallAndWaitRequest;
902  }
903
904
905  // transitions from U
906  transition(U, {RdBlkS}, BS_PM) {L3TagArrayRead} {
907    t_allocateTBE;
908    l_queueMemRdReq;
909    sc_probeShrCoreData;
910    p_popRequestQueue;
911  }
912
913  transition(U, WriteThrough, BM_PM) {L3TagArrayRead, L3TagArrayWrite} {
914    t_allocateTBE;
915    w_sendResponseWBAck;
916    l_queueMemRdReq;
917    dc_probeInvCoreData;
918    p_popRequestQueue;
919  }
920
921  transition(U, Atomic, BM_PM) {L3TagArrayRead, L3TagArrayWrite} {
922    t_allocateTBE;
923    l_queueMemRdReq;
924    dc_probeInvCoreData;
925    p_popRequestQueue;
926  }
927
928  transition(U, {RdBlkM}, BM_PM) {L3TagArrayRead} {
929    t_allocateTBE;
930    l_queueMemRdReq;
931    dc_probeInvCoreData;
932    p_popRequestQueue;
933  }
934
935  transition(U, RdBlk, B_PM) {L3TagArrayRead}{
936    t_allocateTBE;
937    l_queueMemRdReq;
938    sc_probeShrCoreData;
939    p_popRequestQueue;
940  }
941
942  transition(U, CtoD, BP) {L3TagArrayRead} {
943    t_allocateTBE;
944    ic_probeInvCore;
945    p_popRequestQueue;
946  }
947
948  transition(U, VicDirty, BL) {L3TagArrayRead} {
949    t_allocateTBE;
950    w_sendResponseWBAck;
951    p_popRequestQueue;
952  }
953
954  transition(U, VicClean, BL) {L3TagArrayRead} {
955    t_allocateTBE;
956    w_sendResponseWBAck;
957    p_popRequestQueue;
958  }
959
960  transition(BL, {VicDirty, VicClean}) {
961    zz_recycleRequestQueue;
962  }
963
964  transition(BL, CPUData, U) {L3TagArrayWrite, L3DataArrayWrite} {
965    d_writeDataToMemory;
966    al_allocateL3Block;
967    wa_wakeUpDependents;
968    dt_deallocateTBE;
969    pr_popResponseQueue;
970  }
971
972  transition(BL, StaleWB, U) {L3TagArrayWrite} {
973    dt_deallocateTBE;
974    wa_wakeUpAllDependents;
975    pr_popResponseQueue;
976  }
977
978  transition({B, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm}, {VicDirty, VicClean}) {
979    z_stall;
980  }
981
982  transition({U, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, WBAck) {
983    pm_popMemQueue;
984  }
985
986  transition({U, BL, BS_M, BM_M, B_M, BP, BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, B}, StaleVicDirty) {
987    rv_removeVicDirtyIgnore;
988    w_sendResponseWBAck;
989    p_popRequestQueue;
990  }
991
992  transition({B}, CoreUnblock, U) {
993    wa_wakeUpDependents;
994    pu_popUnblockQueue;
995  }
996
997  transition(B, UnblockWriteThrough, U) {
998    wa_wakeUpDependents;
999    pt_popTriggerQueue;
1000  }
1001
1002  transition(BS_PM, MemData, BS_Pm) {} {
1003    mt_writeMemDataToTBE;
1004    pm_popMemQueue;
1005  }
1006
1007  transition(BM_PM, MemData, BM_Pm){} {
1008    mt_writeMemDataToTBE;
1009    pm_popMemQueue;
1010  }
1011
1012  transition(B_PM, MemData, B_Pm){} {
1013    mt_writeMemDataToTBE;
1014    pm_popMemQueue;
1015  }
1016
1017  transition(BS_PM, L3Hit, BS_Pm) {} {
1018    ptl_popTriggerQueue;
1019  }
1020
1021  transition(BM_PM, L3Hit, BM_Pm) {} {
1022    ptl_popTriggerQueue;
1023  }
1024
1025  transition(B_PM, L3Hit, B_Pm) {} {
1026    ptl_popTriggerQueue;
1027  }
1028
1029  transition(BS_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} {
1030    mt_writeMemDataToTBE;
1031    s_sendResponseS;
1032    wd_writeBackData;
1033    alwt_allocateL3BlockOnWT;
1034    dt_deallocateTBE;
1035    pm_popMemQueue;
1036  }
1037
1038  transition(BM_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} {
1039    mt_writeMemDataToTBE;
1040    m_sendResponseM;
1041    wd_writeBackData;
1042    alwt_allocateL3BlockOnWT;
1043    dt_deallocateTBE;
1044    pm_popMemQueue;
1045  }
1046
1047  transition(B_M, MemData, B){L3TagArrayWrite, L3DataArrayWrite} {
1048    mt_writeMemDataToTBE;
1049    es_sendResponseES;
1050    wd_writeBackData;
1051    alwt_allocateL3BlockOnWT;
1052    dt_deallocateTBE;
1053    pm_popMemQueue;
1054  }
1055
1056  transition(BS_M, L3Hit, B) {L3TagArrayWrite, L3DataArrayWrite} {
1057    s_sendResponseS;
1058    wd_writeBackData;
1059    alwt_allocateL3BlockOnWT;
1060    dt_deallocateTBE;
1061    ptl_popTriggerQueue;
1062  }
1063
1064  transition(BM_M, L3Hit, B) {L3DataArrayWrite, L3TagArrayWrite} {
1065    m_sendResponseM;
1066    wd_writeBackData;
1067    alwt_allocateL3BlockOnWT;
1068    dt_deallocateTBE;
1069    ptl_popTriggerQueue;
1070  }
1071
1072  transition(B_M, L3Hit, B) {L3DataArrayWrite, L3TagArrayWrite} {
1073    es_sendResponseES;
1074    wd_writeBackData;
1075    alwt_allocateL3BlockOnWT;
1076    dt_deallocateTBE;
1077    ptl_popTriggerQueue;
1078  }
1079
1080  transition({BS_PM, BM_PM, B_PM, BS_Pm, BM_Pm, B_Pm, BP}, CPUPrbResp) {
1081    y_writeProbeDataToTBE;
1082    x_decrementAcks;
1083    o_checkForCompletion;
1084    pr_popResponseQueue;
1085  }
1086
1087  transition(BS_PM, ProbeAcksComplete, BS_M) {} {
1088    sf_setForwardReqTime;
1089    pt_popTriggerQueue;
1090  }
1091
1092  transition(BM_PM, ProbeAcksComplete, BM_M) {} {
1093    sf_setForwardReqTime;
1094    pt_popTriggerQueue;
1095  }
1096
1097  transition(B_PM, ProbeAcksComplete, B_M){} {
1098    sf_setForwardReqTime;
1099    pt_popTriggerQueue;
1100  }
1101
1102  transition(BS_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} {
1103    sf_setForwardReqTime;
1104    s_sendResponseS;
1105    wd_writeBackData;
1106    alwt_allocateL3BlockOnWT;
1107    dt_deallocateTBE;
1108    pt_popTriggerQueue;
1109  }
1110
1111  transition(BM_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} {
1112    sf_setForwardReqTime;
1113    m_sendResponseM;
1114    wd_writeBackData;
1115    alwt_allocateL3BlockOnWT;
1116    dt_deallocateTBE;
1117    pt_popTriggerQueue;
1118  }
1119
1120  transition(B_Pm, ProbeAcksComplete, B){L3DataArrayWrite, L3TagArrayWrite} {
1121    sf_setForwardReqTime;
1122    es_sendResponseES;
1123    wd_writeBackData;
1124    alwt_allocateL3BlockOnWT;
1125    dt_deallocateTBE;
1126    pt_popTriggerQueue;
1127  }
1128
1129  transition(BP, ProbeAcksComplete, B){L3TagArrayWrite, L3TagArrayWrite} {
1130    sf_setForwardReqTime;
1131    c_sendResponseCtoD;
1132    wd_writeBackData;
1133    alwt_allocateL3BlockOnWT;
1134    dt_deallocateTBE;
1135    pt_popTriggerQueue;
1136  }
1137}
1138