MOESI_CMP_directory-dir.sm revision 14184:11ac1337c5e2
1/*
2 * Copyright (c) 2019 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41machine(MachineType:Directory, "Directory protocol")
42:  DirectoryMemory * directory;
43   Cycles directory_latency := 6;
44   Cycles to_memory_controller_latency := 1;
45
46   // Message Queues
47   MessageBuffer * requestToDir, network="From", virtual_network="1",
48        vnet_type="request";  // a mod-L2 bank -> this Dir
49   MessageBuffer * responseToDir, network="From", virtual_network="2",
50        vnet_type="response";  // a mod-L2 bank -> this Dir
51
52   MessageBuffer * forwardFromDir, network="To", virtual_network="1",
53        vnet_type="forward";
54   MessageBuffer * responseFromDir, network="To", virtual_network="2",
55        vnet_type="response";  // Dir -> mod-L2 bank
56
57   MessageBuffer * responseFromMemory;
58{
59  // STATES
60  state_declaration(State, desc="Directory states", default="Directory_State_I") {
61    // Base states
62    I, AccessPermission:Read_Write, desc="Invalid";
63    S, AccessPermission:Read_Only, desc="Shared";
64    O, AccessPermission:Maybe_Stale, desc="Owner";
65    M, AccessPermission:Maybe_Stale, desc="Modified";
66
67    IS, AccessPermission:Busy, desc="Blocked, was in idle";
68    SS, AccessPermission:Read_Only, desc="Blocked, was in shared";
69    OO, AccessPermission:Busy, desc="Blocked, was in owned";
70    MO, AccessPermission:Busy, desc="Blocked, going to owner or maybe modified";
71    MM, AccessPermission:Busy, desc="Blocked, going to modified";
72
73    MI, AccessPermission:Busy, desc="Blocked on a writeback";
74    MIS, AccessPermission:Busy, desc="Blocked on a writeback, but don't remove from sharers when received";
75    OS, AccessPermission:Busy, desc="Blocked on a writeback";
76    OSS, AccessPermission:Busy, desc="Blocked on a writeback, but don't remove from sharers when received";
77
78    XI_M, AccessPermission:Busy, desc="In a stable state, going to I, waiting for the memory controller";
79    XI_U, AccessPermission:Busy, desc="In a stable state, going to I, waiting for an unblock";
80    OI_D, AccessPermission:Busy, desc="In O, going to I, waiting for data";
81
82    OD, AccessPermission:Busy, desc="In O, waiting for dma ack from L2";
83    MD, AccessPermission:Busy, desc="In M, waiting for dma ack from L2";
84  }
85
86  // Events
87  enumeration(Event, desc="Directory events") {
88    GETX, desc="A GETX arrives";
89    GETS, desc="A GETS arrives";
90    PUTX, desc="A PUTX arrives";
91    PUTO, desc="A PUTO arrives";
92    PUTO_SHARERS, desc="A PUTO arrives, but don't remove from sharers list";
93    Unblock, desc="An unblock message arrives";
94    Last_Unblock, desc="An unblock message arrives, we're not waiting for any additional unblocks";
95    Exclusive_Unblock, desc="The processor become the exclusive owner (E or M) of the line";
96    Clean_Writeback, desc="The final message as part of a PutX/PutS, no data";
97    Dirty_Writeback, desc="The final message as part of a PutX/PutS, contains data";
98    Memory_Data,   desc="Fetched data from memory arrives";
99    Memory_Ack,    desc="Writeback Ack from memory arrives";
100    DMA_READ,      desc="DMA Read";
101    DMA_WRITE,     desc="DMA Write";
102    DMA_ACK,       desc="DMA Ack";
103    Data,          desc="Data to directory";
104  }
105
106  // TYPES
107
108  // DirectoryEntry
109  structure(Entry, desc="...", interface='AbstractEntry') {
110    State DirectoryState,          desc="Directory state";
111    NetDest Sharers,                   desc="Sharers for this block";
112    NetDest Owner,                     desc="Owner of this block";
113    int WaitingUnblocks,           desc="Number of acks we're waiting for";
114  }
115
116  structure(TBE, desc="...") {
117    Addr PhysicalAddress,   desc="Physical address for this entry";
118    int Len,           desc="Length of request";
119    DataBlock DataBlk, desc="DataBlk";
120    MachineID Requestor, desc="original requestor";
121  }
122
123  structure(TBETable, external = "yes") {
124    TBE lookup(Addr);
125    void allocate(Addr);
126    void deallocate(Addr);
127    bool isPresent(Addr);
128  }
129
130  // ** OBJECTS **
131  TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
132
133  Tick clockEdge();
134  Tick cyclesToTicks(Cycles c);
135  void set_tbe(TBE b);
136  void unset_tbe();
137
138  Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
139    Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
140
141    if (is_valid(dir_entry)) {
142      return dir_entry;
143    }
144
145    dir_entry :=  static_cast(Entry, "pointer",
146                              directory.allocate(addr, new Entry));
147    return dir_entry;
148  }
149
150  State getState(TBE tbe, Addr addr) {
151    return getDirectoryEntry(addr).DirectoryState;
152  }
153
154  void setState(TBE tbe, Addr addr, State state) {
155    if (directory.isPresent(addr)) {
156
157      if (state == State:I) {
158        assert(getDirectoryEntry(addr).Owner.count() == 0);
159        assert(getDirectoryEntry(addr).Sharers.count() == 0);
160      }
161
162      if (state == State:S) {
163        assert(getDirectoryEntry(addr).Owner.count() == 0);
164      }
165
166      if (state == State:O) {
167        assert(getDirectoryEntry(addr).Owner.count() == 1);
168        assert(getDirectoryEntry(addr).Sharers.isSuperset(getDirectoryEntry(addr).Owner) == false);
169      }
170
171      if (state == State:M) {
172        assert(getDirectoryEntry(addr).Owner.count() == 1);
173        assert(getDirectoryEntry(addr).Sharers.count() == 0);
174      }
175
176      if ((state != State:SS) && (state != State:OO)) {
177        assert(getDirectoryEntry(addr).WaitingUnblocks == 0);
178      }
179
180      if ( (getDirectoryEntry(addr).DirectoryState != State:I) && (state == State:I) ) {
181        getDirectoryEntry(addr).DirectoryState := state;
182         // disable coherence checker
183        // sequencer.checkCoherence(addr);
184      }
185      else {
186        getDirectoryEntry(addr).DirectoryState := state;
187      }
188    }
189  }
190
191  AccessPermission getAccessPermission(Addr addr) {
192    if (directory.isPresent(addr)) {
193      DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
194      return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
195    }
196
197    DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
198    return AccessPermission:NotPresent;
199  }
200
201  void setAccessPermission(Addr addr, State state) {
202    if (directory.isPresent(addr)) {
203      getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
204    }
205  }
206
207  void functionalRead(Addr addr, Packet *pkt) {
208    functionalMemoryRead(pkt);
209  }
210
211  int functionalWrite(Addr addr, Packet *pkt) {
212    int num_functional_writes := 0;
213    num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
214    return num_functional_writes;
215  }
216
217  // if no sharers, then directory can be considered
218  // both a sharer and exclusive w.r.t. coherence checking
219  bool isBlockShared(Addr addr) {
220    if (directory.isPresent(addr)) {
221      if (getDirectoryEntry(addr).DirectoryState == State:I) {
222        return true;
223      }
224    }
225    return false;
226  }
227
228  bool isBlockExclusive(Addr addr) {
229    if (directory.isPresent(addr)) {
230      if (getDirectoryEntry(addr).DirectoryState == State:I) {
231        return true;
232      }
233    }
234    return false;
235  }
236
237  // ** OUT_PORTS **
238  out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
239  out_port(responseNetwork_out, ResponseMsg, responseFromDir);
240
241  // ** IN_PORTS **
242
243  in_port(unblockNetwork_in, ResponseMsg, responseToDir, rank=2) {
244    if (unblockNetwork_in.isReady(clockEdge())) {
245      peek(unblockNetwork_in, ResponseMsg) {
246        if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
247          if (getDirectoryEntry(in_msg.addr).WaitingUnblocks == 1) {
248            trigger(Event:Last_Unblock, in_msg.addr,
249                    TBEs[in_msg.addr]);
250          } else {
251            trigger(Event:Unblock, in_msg.addr,
252                    TBEs[in_msg.addr]);
253          }
254        } else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
255          trigger(Event:Exclusive_Unblock, in_msg.addr,
256                  TBEs[in_msg.addr]);
257        } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
258          trigger(Event:Data, in_msg.addr,
259                  TBEs[in_msg.addr]);
260        } else if (in_msg.Type == CoherenceResponseType:DMA_ACK) {
261          trigger(Event:DMA_ACK, in_msg.addr,
262                  TBEs[in_msg.addr]);
263        } else {
264          error("Invalid message");
265        }
266      }
267    }
268  }
269
270  in_port(requestQueue_in, RequestMsg, requestToDir, rank=1) {
271    if (requestQueue_in.isReady(clockEdge())) {
272      peek(requestQueue_in, RequestMsg) {
273        if (in_msg.Type == CoherenceRequestType:GETS) {
274          trigger(Event:GETS, in_msg.addr, TBEs[in_msg.addr]);
275        } else if (in_msg.Type == CoherenceRequestType:GETX) {
276          trigger(Event:GETX, in_msg.addr, TBEs[in_msg.addr]);
277        } else if (in_msg.Type == CoherenceRequestType:PUTX) {
278          trigger(Event:PUTX, in_msg.addr, TBEs[in_msg.addr]);
279        } else if (in_msg.Type == CoherenceRequestType:PUTO) {
280          trigger(Event:PUTO, in_msg.addr, TBEs[in_msg.addr]);
281        } else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) {
282          trigger(Event:PUTO_SHARERS, in_msg.addr, TBEs[in_msg.addr]);
283        } else if (in_msg.Type == CoherenceRequestType:WRITEBACK_DIRTY_DATA) {
284          trigger(Event:Dirty_Writeback, in_msg.addr,
285                  TBEs[in_msg.addr]);
286        } else if (in_msg.Type == CoherenceRequestType:WRITEBACK_CLEAN_ACK) {
287          trigger(Event:Clean_Writeback, in_msg.addr,
288                  TBEs[in_msg.addr]);
289        } else if (in_msg.Type == CoherenceRequestType:DMA_READ) {
290          trigger(Event:DMA_READ, makeLineAddress(in_msg.addr),
291                  TBEs[makeLineAddress(in_msg.addr)]);
292        } else if (in_msg.Type == CoherenceRequestType:DMA_WRITE) {
293          trigger(Event:DMA_WRITE, makeLineAddress(in_msg.addr),
294                  TBEs[makeLineAddress(in_msg.addr)]);
295        } else {
296          error("Invalid message");
297        }
298      }
299    }
300  }
301
302  // off-chip memory request/response is done
303  in_port(memQueue_in, MemoryMsg, responseFromMemory, rank=0) {
304    if (memQueue_in.isReady(clockEdge())) {
305      peek(memQueue_in, MemoryMsg) {
306        if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
307          trigger(Event:Memory_Data, in_msg.addr, TBEs[in_msg.addr]);
308        } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
309          trigger(Event:Memory_Ack, in_msg.addr, TBEs[in_msg.addr]);
310        } else {
311          DPRINTF(RubySlicc, "%s\n", in_msg.Type);
312          error("Invalid message");
313        }
314      }
315    }
316  }
317
318  // Actions
319
320  action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
321    peek(requestQueue_in, RequestMsg) {
322      enqueue(responseNetwork_out, ResponseMsg, directory_latency) {
323        out_msg.addr := address;
324        out_msg.Type := CoherenceResponseType:WB_ACK;
325        out_msg.Sender := in_msg.Requestor;
326        out_msg.SenderMachine := MachineType:Directory;
327        out_msg.Destination.add(in_msg.Requestor);
328        out_msg.MessageSize := MessageSizeType:Writeback_Control;
329      }
330    }
331  }
332
333  action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
334    peek(requestQueue_in, RequestMsg) {
335      enqueue(responseNetwork_out, ResponseMsg, directory_latency) {
336        out_msg.addr := address;
337        out_msg.Type := CoherenceResponseType:WB_NACK;
338        out_msg.Sender := in_msg.Requestor;
339        out_msg.SenderMachine := MachineType:Directory;
340        out_msg.Destination.add(in_msg.Requestor);
341        out_msg.MessageSize := MessageSizeType:Writeback_Control;
342      }
343    }
344  }
345
346  action(c_clearOwner, "c", desc="Clear the owner field") {
347    getDirectoryEntry(address).Owner.clear();
348  }
349
350  action(c_moveOwnerToSharer, "cc", desc="Move owner to sharers") {
351    getDirectoryEntry(address).Sharers.addNetDest(getDirectoryEntry(address).Owner);
352    getDirectoryEntry(address).Owner.clear();
353  }
354
355  action(cc_clearSharers, "\c", desc="Clear the sharers field") {
356    getDirectoryEntry(address).Sharers.clear();
357  }
358
359  action(d_sendDataMsg, "d", desc="Send data to requestor") {
360    peek(memQueue_in, MemoryMsg) {
361      enqueue(responseNetwork_out, ResponseMsg, 1) {
362        out_msg.addr := address;
363        out_msg.Sender := machineID;
364        out_msg.SenderMachine := MachineType:Directory;
365        out_msg.Destination.add(in_msg.OriginalRequestorMachId);
366        out_msg.DataBlk := in_msg.DataBlk;
367        out_msg.Dirty := false; // By definition, the block is now clean
368        out_msg.Acks := in_msg.Acks;
369        if (in_msg.ReadX) {
370          out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
371        } else {
372          out_msg.Type := CoherenceResponseType:DATA;
373        }
374        out_msg.MessageSize := MessageSizeType:Response_Data;
375      }
376    }
377  }
378
379  action(p_fwdDataToDMA, "\d", desc="Send data to requestor") {
380    peek(requestQueue_in, RequestMsg) {
381      enqueue(responseNetwork_out, ResponseMsg, 1) {
382        out_msg.addr := address;
383        out_msg.Sender := machineID;
384        out_msg.SenderMachine := MachineType:Directory;
385        out_msg.Destination.add(in_msg.Requestor);
386        out_msg.Dirty := false; // By definition, the block is now clean
387        out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
388        out_msg.MessageSize := MessageSizeType:Response_Data;
389      }
390    }
391  }
392
393  action(e_ownerIsUnblocker, "e", desc="The owner is now the unblocker") {
394    peek(unblockNetwork_in, ResponseMsg) {
395      getDirectoryEntry(address).Owner.clear();
396      getDirectoryEntry(address).Owner.add(in_msg.Sender);
397    }
398  }
399
400  action(f_forwardRequest, "f", desc="Forward request to owner") {
401    peek(requestQueue_in, RequestMsg) {
402      enqueue(forwardNetwork_out, RequestMsg, directory_latency) {
403        out_msg.addr := address;
404        out_msg.Type := in_msg.Type;
405        out_msg.Requestor := in_msg.Requestor;
406        out_msg.RequestorMachine := machineIDToMachineType(in_msg.Requestor);
407        out_msg.Destination.addNetDest(getDirectoryEntry(in_msg.addr).Owner);
408        out_msg.Acks := getDirectoryEntry(address).Sharers.count();
409        if (getDirectoryEntry(address).Sharers.isElement(in_msg.Requestor)) {
410          out_msg.Acks := out_msg.Acks - 1;
411        }
412        out_msg.MessageSize := MessageSizeType:Forwarded_Control;
413      }
414    }
415  }
416
417  action(f_forwardRequestDirIsRequestor, "\f", desc="Forward request to owner") {
418    peek(requestQueue_in, RequestMsg) {
419      enqueue(forwardNetwork_out, RequestMsg, directory_latency) {
420        out_msg.addr := address;
421        out_msg.Type := in_msg.Type;
422        out_msg.Requestor := machineID;
423        out_msg.RequestorMachine := machineIDToMachineType(in_msg.Requestor);
424        out_msg.Destination.addNetDest(getDirectoryEntry(in_msg.addr).Owner);
425        out_msg.Acks := getDirectoryEntry(address).Sharers.count();
426        if (getDirectoryEntry(address).Sharers.isElement(in_msg.Requestor)) {
427          out_msg.Acks := out_msg.Acks - 1;
428        }
429        out_msg.MessageSize := MessageSizeType:Forwarded_Control;
430      }
431    }
432  }
433
434  action(g_sendInvalidations, "g", desc="Send invalidations to sharers, not including the requester") {
435    peek(requestQueue_in, RequestMsg) {
436      if ((getDirectoryEntry(in_msg.addr).Sharers.count() > 1) ||
437          ((getDirectoryEntry(in_msg.addr).Sharers.count() > 0) &&
438           (getDirectoryEntry(in_msg.addr).Sharers.isElement(in_msg.Requestor) == false))) {
439        enqueue(forwardNetwork_out, RequestMsg, directory_latency) {
440          out_msg.addr := address;
441          out_msg.Type := CoherenceRequestType:INV;
442          out_msg.Requestor := in_msg.Requestor;
443          out_msg.RequestorMachine := machineIDToMachineType(in_msg.Requestor);
444          // out_msg.Destination := getDirectoryEntry(in_msg.addr).Sharers;
445          out_msg.Destination.addNetDest(getDirectoryEntry(in_msg.addr).Sharers);
446          out_msg.Destination.remove(in_msg.Requestor);
447          out_msg.MessageSize := MessageSizeType:Invalidate_Control;
448        }
449      }
450    }
451  }
452
453  action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
454    requestQueue_in.dequeue(clockEdge());
455  }
456
457  action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
458    unblockNetwork_in.dequeue(clockEdge());
459  }
460
461  action(m_addUnlockerToSharers, "m", desc="Add the unlocker to the sharer list") {
462    peek(unblockNetwork_in, ResponseMsg) {
463      getDirectoryEntry(address).Sharers.add(in_msg.Sender);
464    }
465  }
466
467  action(n_incrementOutstanding, "n", desc="Increment outstanding requests") {
468    getDirectoryEntry(address).WaitingUnblocks := getDirectoryEntry(address).WaitingUnblocks + 1;
469  }
470
471  action(o_decrementOutstanding, "o", desc="Decrement outstanding requests") {
472    getDirectoryEntry(address).WaitingUnblocks := getDirectoryEntry(address).WaitingUnblocks - 1;
473    assert(getDirectoryEntry(address).WaitingUnblocks >= 0);
474  }
475
476  action(q_popMemQueue, "q", desc="Pop off-chip request queue") {
477    memQueue_in.dequeue(clockEdge());
478  }
479
480  action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
481    peek(requestQueue_in, RequestMsg) {
482      queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency);
483    }
484  }
485
486  action(qw_queueMemoryWBFromCacheRequest, "qw", desc="Queue off-chip writeback request") {
487    peek(requestQueue_in, RequestMsg) {
488      if (is_valid(tbe)) {
489        queueMemoryWrite(tbe.Requestor, address, to_memory_controller_latency,
490                         in_msg.DataBlk);
491      } else {
492        queueMemoryWrite(in_msg.Requestor, address, to_memory_controller_latency,
493                         in_msg.DataBlk);
494      }
495    }
496  }
497
498  action(qw_queueMemoryWBRequestFromMessageAndTBE, "qwmt",
499    desc="Queue off-chip writeback request") {
500    peek(unblockNetwork_in, ResponseMsg) {
501      DataBlock DataBlk := in_msg.DataBlk;
502      DataBlk.copyPartial(tbe.DataBlk, getOffset(tbe.PhysicalAddress),
503                          tbe.Len);
504      queueMemoryWrite(tbe.Requestor, address, to_memory_controller_latency,
505                       DataBlk);
506    }
507  }
508
509  action(qw_queueMemoryWBFromDMARequest, "/qw", desc="Queue off-chip writeback request") {
510    peek(requestQueue_in, RequestMsg) {
511      queueMemoryWrite(in_msg.Requestor, address, to_memory_controller_latency,
512                       in_msg.DataBlk);
513    }
514  }
515
516  action(zz_recycleRequest, "\z", desc="Recycle the request queue") {
517    requestQueue_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
518  }
519
520  action(a_sendDMAAck, "\a", desc="Send DMA Ack that write completed, along with Inv Ack count") {
521    peek(requestQueue_in, RequestMsg) {
522      enqueue(responseNetwork_out, ResponseMsg, 1) {
523      out_msg.addr := address;
524      out_msg.Sender := machineID;
525      out_msg.SenderMachine := MachineType:Directory;
526      out_msg.Destination.add(in_msg.Requestor);
527      out_msg.DataBlk := in_msg.DataBlk;
528      out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
529      out_msg.Type := CoherenceResponseType:DMA_ACK;
530      out_msg.MessageSize := MessageSizeType:Writeback_Control;
531      }
532    }
533  }
534
535  action(a_sendDMAAck2, "\aa", desc="Send DMA Ack that write completed, along with Inv Ack count") {
536    peek(unblockNetwork_in, ResponseMsg) {
537      enqueue(responseNetwork_out, ResponseMsg, 1) {
538      out_msg.addr := address;
539      out_msg.Sender := machineID;
540      out_msg.SenderMachine := MachineType:Directory;
541      if (is_valid(tbe)) {
542        out_msg.Destination.add(tbe.Requestor);
543      }
544      out_msg.DataBlk := in_msg.DataBlk;
545      out_msg.Acks := getDirectoryEntry(address).Sharers.count();  // for dma requests
546      out_msg.Type := CoherenceResponseType:DMA_ACK;
547      out_msg.MessageSize := MessageSizeType:Writeback_Control;
548      }
549    }
550  }
551
552  action(v_allocateTBE, "v", desc="Allocate TBE entry") {
553    peek (requestQueue_in, RequestMsg) {
554      TBEs.allocate(address);
555      set_tbe(TBEs[address]);
556      tbe.PhysicalAddress := in_msg.addr;
557      tbe.Len := in_msg.Len;
558      tbe.DataBlk := in_msg.DataBlk;
559      tbe.Requestor := in_msg.Requestor;
560    }
561  }
562
563  action(w_deallocateTBE, "w", desc="Deallocate TBE entry") {
564    TBEs.deallocate(address);
565    unset_tbe();
566  }
567
568
569  // TRANSITIONS
570  transition(I, GETX, MM) {
571    qf_queueMemoryFetchRequest;
572    i_popIncomingRequestQueue;
573  }
574
575  transition(I, DMA_READ, XI_M) {
576    qf_queueMemoryFetchRequest;
577    i_popIncomingRequestQueue;
578  }
579
580  transition(I, DMA_WRITE, XI_U) {
581    qw_queueMemoryWBFromDMARequest;
582    a_sendDMAAck;  // ack count may be zero
583    i_popIncomingRequestQueue;
584  }
585
586  transition(XI_M, Memory_Data, I) {
587    d_sendDataMsg;  // ack count may be zero
588    q_popMemQueue;
589  }
590
591  transition(XI_U, Exclusive_Unblock, I) {
592    cc_clearSharers;
593    c_clearOwner;
594    j_popIncomingUnblockQueue;
595  }
596
597  transition(S, GETX, MM) {
598    qf_queueMemoryFetchRequest;
599    g_sendInvalidations;
600    i_popIncomingRequestQueue;
601  }
602
603  transition(S, DMA_READ) {
604    //qf_queueMemoryFetchRequest;
605    p_fwdDataToDMA;
606    //g_sendInvalidations;  // the DMA will collect the invalidations then send an Unblock Exclusive
607    i_popIncomingRequestQueue;
608  }
609
610  transition(S, DMA_WRITE, XI_U) {
611    qw_queueMemoryWBFromDMARequest;
612    a_sendDMAAck;  // ack count may be zero
613    g_sendInvalidations;  // the DMA will collect invalidations
614    i_popIncomingRequestQueue;
615  }
616
617  transition(I, GETS, IS) {
618    qf_queueMemoryFetchRequest;
619    i_popIncomingRequestQueue;
620  }
621
622  transition({S, SS}, GETS, SS) {
623    qf_queueMemoryFetchRequest;
624    n_incrementOutstanding;
625    i_popIncomingRequestQueue;
626  }
627
628  transition({I, S}, PUTO) {
629    b_sendWriteBackNack;
630    i_popIncomingRequestQueue;
631  }
632
633  transition({I, S, O}, PUTX) {
634    b_sendWriteBackNack;
635    i_popIncomingRequestQueue;
636  }
637
638  transition(O, GETX, MM) {
639    f_forwardRequest;
640    g_sendInvalidations;
641    i_popIncomingRequestQueue;
642  }
643
644  transition(O, DMA_READ, OD) {
645    f_forwardRequest;     // this will cause the data to go to DMA directly
646    //g_sendInvalidations;  // this will cause acks to be sent to the DMA
647    i_popIncomingRequestQueue;
648  }
649
650  transition(OD, DMA_ACK, O) {
651    j_popIncomingUnblockQueue;
652  }
653
654  transition({O,M}, DMA_WRITE, OI_D) {
655    f_forwardRequestDirIsRequestor;    // need the modified data before we can proceed
656    g_sendInvalidations;               // these go to the DMA Controller
657    v_allocateTBE;
658    i_popIncomingRequestQueue;
659  }
660
661  transition(OI_D, Data, XI_U) {
662    qw_queueMemoryWBRequestFromMessageAndTBE;
663    a_sendDMAAck2;  // ack count may be zero
664    w_deallocateTBE;
665    j_popIncomingUnblockQueue;
666  }
667
668  transition({O, OO}, GETS, OO) {
669    f_forwardRequest;
670    n_incrementOutstanding;
671    i_popIncomingRequestQueue;
672  }
673
674  transition(M, GETX, MM) {
675    f_forwardRequest;
676    i_popIncomingRequestQueue;
677  }
678
679  // no exclusive unblock will show up to the directory
680  transition(M, DMA_READ, MD) {
681    f_forwardRequest;     // this will cause the data to go to DMA directly
682    i_popIncomingRequestQueue;
683  }
684
685  transition(MD, DMA_ACK, M) {
686    j_popIncomingUnblockQueue;
687  }
688
689  transition(M, GETS, MO) {
690    f_forwardRequest;
691    i_popIncomingRequestQueue;
692  }
693
694  transition(M, PUTX, MI) {
695    a_sendWriteBackAck;
696    i_popIncomingRequestQueue;
697  }
698
699  // happens if M->O transition happens on-chip
700  transition(M, PUTO, MI) {
701    a_sendWriteBackAck;
702    i_popIncomingRequestQueue;
703  }
704
705  transition(M, PUTO_SHARERS, MIS) {
706    a_sendWriteBackAck;
707    i_popIncomingRequestQueue;
708  }
709
710  transition(O, PUTO, OS) {
711    a_sendWriteBackAck;
712    i_popIncomingRequestQueue;
713  }
714
715  transition(O, PUTO_SHARERS, OSS) {
716    a_sendWriteBackAck;
717    i_popIncomingRequestQueue;
718  }
719
720
721  transition({MM, MO, MI, MIS, OS, OSS, XI_M, XI_U, OI_D, OD, MD}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) {
722    zz_recycleRequest;
723  }
724
725  transition({MM, MO}, Exclusive_Unblock, M) {
726    cc_clearSharers;
727    e_ownerIsUnblocker;
728    j_popIncomingUnblockQueue;
729  }
730
731  transition(MO, Unblock, O) {
732    m_addUnlockerToSharers;
733    j_popIncomingUnblockQueue;
734  }
735
736  transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) {
737    zz_recycleRequest;
738  }
739
740  transition(IS, GETS) {
741    zz_recycleRequest;
742  }
743
744  transition(IS, Unblock, S) {
745    m_addUnlockerToSharers;
746    j_popIncomingUnblockQueue;
747  }
748
749  transition(IS, Exclusive_Unblock, M) {
750    cc_clearSharers;
751    e_ownerIsUnblocker;
752    j_popIncomingUnblockQueue;
753  }
754
755  transition(SS, Unblock) {
756    m_addUnlockerToSharers;
757    o_decrementOutstanding;
758    j_popIncomingUnblockQueue;
759  }
760
761  transition(SS, Last_Unblock, S) {
762    m_addUnlockerToSharers;
763    o_decrementOutstanding;
764    j_popIncomingUnblockQueue;
765  }
766
767  transition(OO, Unblock) {
768    m_addUnlockerToSharers;
769    o_decrementOutstanding;
770    j_popIncomingUnblockQueue;
771  }
772
773  transition(OO, Last_Unblock, O) {
774    m_addUnlockerToSharers;
775    o_decrementOutstanding;
776    j_popIncomingUnblockQueue;
777  }
778
779  transition(MI, Dirty_Writeback, I) {
780    c_clearOwner;
781    cc_clearSharers;
782    qw_queueMemoryWBFromCacheRequest;
783    i_popIncomingRequestQueue;
784  }
785
786  transition(MIS, Dirty_Writeback, S) {
787    c_moveOwnerToSharer;
788    qw_queueMemoryWBFromCacheRequest;
789    i_popIncomingRequestQueue;
790  }
791
792  transition(MIS, Clean_Writeback, S) {
793    c_moveOwnerToSharer;
794    i_popIncomingRequestQueue;
795  }
796
797  transition(OS, Dirty_Writeback, S) {
798    c_clearOwner;
799    qw_queueMemoryWBFromCacheRequest;
800    i_popIncomingRequestQueue;
801  }
802
803  transition(OSS, Dirty_Writeback, S) {
804    c_moveOwnerToSharer;
805    qw_queueMemoryWBFromCacheRequest;
806    i_popIncomingRequestQueue;
807  }
808
809  transition(OSS, Clean_Writeback, S) {
810    c_moveOwnerToSharer;
811    i_popIncomingRequestQueue;
812  }
813
814  transition(MI, Clean_Writeback, I) {
815    c_clearOwner;
816    cc_clearSharers;
817    i_popIncomingRequestQueue;
818  }
819
820  transition(OS, Clean_Writeback, S) {
821    c_clearOwner;
822    i_popIncomingRequestQueue;
823  }
824
825  transition({MI, MIS}, Unblock, M) {
826    j_popIncomingUnblockQueue;
827  }
828
829  transition({OS, OSS}, Unblock, O) {
830    j_popIncomingUnblockQueue;
831  }
832
833  transition({I, S, O, M, IS, SS, OO, MO, MM, MI, MIS, OS, OSS}, Memory_Data) {
834    d_sendDataMsg;
835    q_popMemQueue;
836  }
837
838  transition({I, S, O, M, IS, SS, OO, MO, MM, MI, MIS, OS, OSS, XI_U, XI_M}, Memory_Ack) {
839    //a_sendAck;
840    q_popMemQueue;
841  }
842
843}
844