1/*
2 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29machine(MachineType:L2Cache, "MESI Directory L2 Cache CMP")
30 : CacheMemory * L2cache;
31   Cycles l2_request_latency := 2;
32   Cycles l2_response_latency := 2;
33   Cycles to_l1_latency := 1;
34
35  // Message Queues
36  // From local bank of L2 cache TO the network
37  MessageBuffer * DirRequestFromL2Cache, network="To", virtual_network="0",
38    vnet_type="request";  // this L2 bank -> Memory
39
40  MessageBuffer * L1RequestFromL2Cache, network="To", virtual_network="2",
41    vnet_type="request";  // this L2 bank -> a local L1
42
43  MessageBuffer * responseFromL2Cache, network="To", virtual_network="1",
44    vnet_type="response";  // this L2 bank -> a local L1 || Memory
45
46  // FROM the network to this local bank of L2 cache
47  MessageBuffer * unblockToL2Cache, network="From", virtual_network="2",
48    vnet_type="unblock";  // a local L1 || Memory -> this L2 bank
49
50  MessageBuffer * L1RequestToL2Cache, network="From", virtual_network="0",
51    vnet_type="request";  // a local L1 -> this L2 bank
52
53  MessageBuffer * responseToL2Cache, network="From", virtual_network="1",
54    vnet_type="response";  // a local L1 || Memory -> this L2 bank
55{
56  // STATES
57  state_declaration(State, desc="L2 Cache states", default="L2Cache_State_NP") {
58    // Base states
59    NP, AccessPermission:Invalid, desc="Not present in either cache";
60    SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s";
61    M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b";
62    MT, AccessPermission:Maybe_Stale, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
63
64    // L2 replacement
65    M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
66    MT_I, AccessPermission:Busy, desc="L2 cache replacing, getting data from exclusive";
67    MCT_I, AccessPermission:Busy, desc="L2 cache replacing, clean in L2, getting data or ack from exclusive";
68    I_I, AccessPermission:Busy, desc="L2 replacing clean data, need to inv sharers and then drop data";
69    S_I, AccessPermission:Busy, desc="L2 replacing dirty data, collecting acks from L1s";
70
71    // Transient States for fetching data from memory
72    ISS, AccessPermission:Busy, desc="L2 idle, got single L1_GETS, issued memory fetch, have not seen response yet";
73    IS, AccessPermission:Busy, desc="L2 idle, got L1_GET_INSTR or multiple L1_GETS, issued memory fetch, have not seen response yet";
74    IM, AccessPermission:Busy, desc="L2 idle, got L1_GETX, issued memory fetch, have not seen response(s) yet";
75
76    // Blocking states
77    SS_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from SS";
78    MT_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from MT";
79
80    MT_IIB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, waiting for unblock and data";
81    MT_IB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got unblock, waiting for data";
82    MT_SB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got data,  waiting for unblock";
83
84  }
85
86  // EVENTS
87  enumeration(Event, desc="L2 Cache events") {
88    // L2 events
89
90    // events initiated by the local L1s
91    L1_GET_INSTR,            desc="a L1I GET INSTR request for a block maped to us";
92    L1_GETS,                 desc="a L1D GETS request for a block maped to us";
93    L1_GETX,                 desc="a L1D GETX request for a block maped to us";
94    L1_UPGRADE,                 desc="a L1D GETX request for a block maped to us";
95
96    L1_PUTX,                 desc="L1 replacing data";
97    L1_PUTX_old,             desc="L1 replacing data, but no longer sharer";
98
99    // events initiated by this L2
100    L2_Replacement,     desc="L2 Replacement", format="!r";
101    L2_Replacement_clean,     desc="L2 Replacement, but data is clean", format="!r";
102
103    // events from memory controller
104    Mem_Data,     desc="data from memory", format="!r";
105    Mem_Ack,     desc="ack from memory", format="!r";
106
107    // M->S data writeback
108    WB_Data,  desc="data from L1";
109    WB_Data_clean,  desc="clean data from L1";
110    Ack,      desc="writeback ack";
111    Ack_all,      desc="writeback ack";
112
113    Unblock, desc="Unblock from L1 requestor";
114    Exclusive_Unblock, desc="Unblock from L1 requestor";
115
116    MEM_Inv, desc="Invalidation from directory";
117  }
118
119  // TYPES
120
121  // CacheEntry
122  structure(Entry, desc="...", interface="AbstractCacheEntry") {
123    State CacheState,          desc="cache state";
124    NetDest Sharers,               desc="tracks the L1 shares on-chip";
125    MachineID Exclusive,          desc="Exclusive holder of block";
126    DataBlock DataBlk,       desc="data for the block";
127    bool Dirty, default="false", desc="data is dirty";
128  }
129
130  // TBE fields
131  structure(TBE, desc="...") {
132    Addr addr,            desc="Physical address for this TBE";
133    State TBEState,             desc="Transient state";
134    DataBlock DataBlk,          desc="Buffer for the data block";
135    bool Dirty, default="false", desc="Data is Dirty";
136
137    NetDest L1_GetS_IDs,            desc="Set of the internal processors that want the block in shared state";
138    MachineID L1_GetX_ID,          desc="ID of the L1 cache to forward the block to once we get a response";
139    int pendingAcks,            desc="number of pending acks for invalidates during writeback";
140  }
141
142  structure(TBETable, external="yes") {
143    TBE lookup(Addr);
144    void allocate(Addr);
145    void deallocate(Addr);
146    bool isPresent(Addr);
147  }
148
149  TBETable TBEs, template="<L2Cache_TBE>", constructor="m_number_of_TBEs";
150
151  Tick clockEdge();
152  Tick cyclesToTicks(Cycles c);
153  Cycles ticksToCycles(Tick t);
154
155  void set_cache_entry(AbstractCacheEntry a);
156  void unset_cache_entry();
157  void set_tbe(TBE a);
158  void unset_tbe();
159  void wakeUpBuffers(Addr a);
160  void profileMsgDelay(int virtualNetworkType, Cycles c);
161  MachineID mapAddressToMachine(Addr addr, MachineType mtype);
162
163  // inclusive cache, returns L2 entries only
164  Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
165    return static_cast(Entry, "pointer", L2cache[addr]);
166  }
167
168  bool isSharer(Addr addr, MachineID requestor, Entry cache_entry) {
169    if (is_valid(cache_entry)) {
170      return cache_entry.Sharers.isElement(requestor);
171    } else {
172      return false;
173    }
174  }
175
176  void addSharer(Addr addr, MachineID requestor, Entry cache_entry) {
177    assert(is_valid(cache_entry));
178    DPRINTF(RubySlicc, "machineID: %s, requestor: %s, address: %#x\n",
179            machineID, requestor, addr);
180    cache_entry.Sharers.add(requestor);
181  }
182
183  State getState(TBE tbe, Entry cache_entry, Addr addr) {
184    if(is_valid(tbe)) {
185      return tbe.TBEState;
186    } else if (is_valid(cache_entry)) {
187      return cache_entry.CacheState;
188    }
189    return State:NP;
190  }
191
192  void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
193    // MUST CHANGE
194    if (is_valid(tbe)) {
195      tbe.TBEState := state;
196    }
197
198    if (is_valid(cache_entry)) {
199      cache_entry.CacheState := state;
200    }
201  }
202
203  AccessPermission getAccessPermission(Addr addr) {
204    TBE tbe := TBEs[addr];
205    if(is_valid(tbe)) {
206      DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
207      return L2Cache_State_to_permission(tbe.TBEState);
208    }
209
210    Entry cache_entry := getCacheEntry(addr);
211    if(is_valid(cache_entry)) {
212      DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
213      return L2Cache_State_to_permission(cache_entry.CacheState);
214    }
215
216    DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
217    return AccessPermission:NotPresent;
218  }
219
220  void functionalRead(Addr addr, Packet *pkt) {
221    TBE tbe := TBEs[addr];
222    if(is_valid(tbe)) {
223      testAndRead(addr, tbe.DataBlk, pkt);
224    } else {
225      testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
226    }
227  }
228
229  int functionalWrite(Addr addr, Packet *pkt) {
230    int num_functional_writes := 0;
231
232    TBE tbe := TBEs[addr];
233    if(is_valid(tbe)) {
234      num_functional_writes := num_functional_writes +
235        testAndWrite(addr, tbe.DataBlk, pkt);
236      return num_functional_writes;
237    }
238
239    num_functional_writes := num_functional_writes +
240        testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
241    return num_functional_writes;
242  }
243
244  void setAccessPermission(Entry cache_entry, Addr addr, State state) {
245    if (is_valid(cache_entry)) {
246      cache_entry.changePermission(L2Cache_State_to_permission(state));
247    }
248  }
249
250  Event L1Cache_request_type_to_event(CoherenceRequestType type, Addr addr,
251                                      MachineID requestor, Entry cache_entry) {
252    if(type == CoherenceRequestType:GETS) {
253      return Event:L1_GETS;
254    } else if(type == CoherenceRequestType:GET_INSTR) {
255      return Event:L1_GET_INSTR;
256    } else if (type == CoherenceRequestType:GETX) {
257      return Event:L1_GETX;
258    } else if (type == CoherenceRequestType:UPGRADE) {
259      if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) {
260        return Event:L1_UPGRADE;
261      } else {
262        return Event:L1_GETX;
263      }
264    } else if (type == CoherenceRequestType:PUTX) {
265      if (isSharer(addr, requestor, cache_entry)) {
266        return Event:L1_PUTX;
267      } else {
268        return Event:L1_PUTX_old;
269      }
270    } else {
271      DPRINTF(RubySlicc, "address: %#x, Request Type: %s\n", addr, type);
272      error("Invalid L1 forwarded request type");
273    }
274  }
275
276  int getPendingAcks(TBE tbe) {
277    return tbe.pendingAcks;
278  }
279
280  bool isDirty(Entry cache_entry) {
281    assert(is_valid(cache_entry));
282    return cache_entry.Dirty;
283  }
284
285  // ** OUT_PORTS **
286
287  out_port(L1RequestL2Network_out, RequestMsg, L1RequestFromL2Cache);
288  out_port(DirRequestL2Network_out, RequestMsg, DirRequestFromL2Cache);
289  out_port(responseL2Network_out, ResponseMsg, responseFromL2Cache);
290
291
292  in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache, rank = 2) {
293    if(L1unblockNetwork_in.isReady(clockEdge())) {
294      peek(L1unblockNetwork_in,  ResponseMsg) {
295        Entry cache_entry := getCacheEntry(in_msg.addr);
296        TBE tbe := TBEs[in_msg.addr];
297        DPRINTF(RubySlicc, "Addr: %#x State: %s Sender: %s Type: %s Dest: %s\n",
298                in_msg.addr, getState(tbe, cache_entry, in_msg.addr),
299                in_msg.Sender, in_msg.Type, in_msg.Destination);
300
301        assert(in_msg.Destination.isElement(machineID));
302        if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) {
303          trigger(Event:Exclusive_Unblock, in_msg.addr, cache_entry, tbe);
304        } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
305          trigger(Event:Unblock, in_msg.addr, cache_entry, tbe);
306        } else {
307          error("unknown unblock message");
308        }
309      }
310    }
311  }
312
313  // Response  L2 Network - response msg to this particular L2 bank
314  in_port(responseL2Network_in, ResponseMsg, responseToL2Cache, rank = 1) {
315    if (responseL2Network_in.isReady(clockEdge())) {
316      peek(responseL2Network_in, ResponseMsg) {
317        // test wether it's from a local L1 or an off chip source
318        assert(in_msg.Destination.isElement(machineID));
319        Entry cache_entry := getCacheEntry(in_msg.addr);
320        TBE tbe := TBEs[in_msg.addr];
321
322        if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
323          if(in_msg.Type == CoherenceResponseType:DATA) {
324            if (in_msg.Dirty) {
325              trigger(Event:WB_Data, in_msg.addr, cache_entry, tbe);
326            } else {
327              trigger(Event:WB_Data_clean, in_msg.addr, cache_entry, tbe);
328            }
329          } else if (in_msg.Type == CoherenceResponseType:ACK) {
330            if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) {
331              trigger(Event:Ack_all, in_msg.addr, cache_entry, tbe);
332            } else {
333              trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
334            }
335          } else {
336            error("unknown message type");
337          }
338
339        } else { // external message
340          if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
341              trigger(Event:Mem_Data, in_msg.addr, cache_entry, tbe);
342          } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) {
343              trigger(Event:Mem_Ack, in_msg.addr, cache_entry, tbe);
344          } else if(in_msg.Type == CoherenceResponseType:INV) {
345              trigger(Event:MEM_Inv, in_msg.addr, cache_entry, tbe);
346          } else {
347            error("unknown message type");
348          }
349        }
350      }
351    }  // if not ready, do nothing
352  }
353
354  // L1 Request
355  in_port(L1RequestL2Network_in, RequestMsg, L1RequestToL2Cache, rank = 0) {
356    if(L1RequestL2Network_in.isReady(clockEdge())) {
357      peek(L1RequestL2Network_in,  RequestMsg) {
358        Entry cache_entry := getCacheEntry(in_msg.addr);
359        TBE tbe := TBEs[in_msg.addr];
360
361        DPRINTF(RubySlicc, "Addr: %#x State: %s Req: %s Type: %s Dest: %s\n",
362                in_msg.addr, getState(tbe, cache_entry, in_msg.addr),
363                in_msg.Requestor, in_msg.Type, in_msg.Destination);
364
365        assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache);
366        assert(in_msg.Destination.isElement(machineID));
367
368        if (is_valid(cache_entry)) {
369          // The L2 contains the block, so proceeded with handling the request
370          trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.addr,
371                                                in_msg.Requestor, cache_entry),
372                  in_msg.addr, cache_entry, tbe);
373        } else {
374          if (L2cache.cacheAvail(in_msg.addr)) {
375            // L2 does't have the line, but we have space for it in the L2
376            trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.addr,
377                                                  in_msg.Requestor, cache_entry),
378                    in_msg.addr, cache_entry, tbe);
379          } else {
380            // No room in the L2, so we need to make room before handling the request
381            Addr victim := L2cache.cacheProbe(in_msg.addr);
382            Entry L2cache_entry := getCacheEntry(victim);
383            if (isDirty(L2cache_entry)) {
384              trigger(Event:L2_Replacement, victim, L2cache_entry, TBEs[victim]);
385            } else {
386              trigger(Event:L2_Replacement_clean,
387                      victim, L2cache_entry, TBEs[victim]);
388            }
389          }
390        }
391      }
392    }
393  }
394
395
396  // ACTIONS
397
398  action(a_issueFetchToMemory, "a", desc="fetch data from memory") {
399    peek(L1RequestL2Network_in, RequestMsg) {
400      enqueue(DirRequestL2Network_out, RequestMsg, l2_request_latency) {
401        out_msg.addr := address;
402        out_msg.Type := CoherenceRequestType:GETS;
403        out_msg.Requestor := machineID;
404        out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
405        out_msg.MessageSize := MessageSizeType:Control;
406      }
407    }
408  }
409
410  action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") {
411    peek(L1RequestL2Network_in, RequestMsg) {
412      enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
413        assert(is_valid(cache_entry));
414        out_msg.addr := address;
415        out_msg.Type := in_msg.Type;
416        out_msg.Requestor := in_msg.Requestor;
417        out_msg.Destination.add(cache_entry.Exclusive);
418        out_msg.MessageSize := MessageSizeType:Request_Control;
419      }
420    }
421  }
422
423  action(c_exclusiveReplacement, "c", desc="Send data to memory") {
424    enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
425      assert(is_valid(cache_entry));
426      out_msg.addr := address;
427      out_msg.Type := CoherenceResponseType:MEMORY_DATA;
428      out_msg.Sender := machineID;
429      out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
430      out_msg.DataBlk := cache_entry.DataBlk;
431      out_msg.Dirty := cache_entry.Dirty;
432      out_msg.MessageSize := MessageSizeType:Response_Data;
433    }
434  }
435
436  action(c_exclusiveCleanReplacement, "cc", desc="Send ack to memory for clean replacement") {
437    enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
438      out_msg.addr := address;
439      out_msg.Type := CoherenceResponseType:ACK;
440      out_msg.Sender := machineID;
441      out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
442      out_msg.MessageSize := MessageSizeType:Response_Control;
443    }
444  }
445
446  action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") {
447    enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
448      assert(is_valid(tbe));
449      out_msg.addr := address;
450      out_msg.Type := CoherenceResponseType:MEMORY_DATA;
451      out_msg.Sender := machineID;
452      out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
453      out_msg.DataBlk := tbe.DataBlk;
454      out_msg.Dirty := tbe.Dirty;
455      out_msg.MessageSize := MessageSizeType:Response_Data;
456    }
457  }
458
459  action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") {
460    peek(L1RequestL2Network_in, RequestMsg) {
461      enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
462        assert(is_valid(cache_entry));
463        out_msg.addr := address;
464        out_msg.Type := CoherenceResponseType:DATA;
465        out_msg.Sender := machineID;
466        out_msg.Destination.add(in_msg.Requestor);
467        out_msg.DataBlk := cache_entry.DataBlk;
468        out_msg.MessageSize := MessageSizeType:Response_Data;
469
470        out_msg.AckCount := 0 - cache_entry.Sharers.count();
471        if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
472          out_msg.AckCount := out_msg.AckCount + 1;
473        }
474      }
475    }
476  }
477
478  action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") {
479    peek(L1RequestL2Network_in, RequestMsg) {
480      enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
481        assert(is_valid(cache_entry));
482        out_msg.addr := address;
483        out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
484        out_msg.Sender := machineID;
485        out_msg.Destination.add(in_msg.Requestor);
486        out_msg.DataBlk := cache_entry.DataBlk;
487        out_msg.MessageSize := MessageSizeType:Response_Data;
488
489        out_msg.AckCount := 0 - cache_entry.Sharers.count();
490        if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
491          out_msg.AckCount := out_msg.AckCount + 1;
492        }
493      }
494    }
495  }
496
497  action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") {
498    peek(L1RequestL2Network_in, RequestMsg) {
499      enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
500        assert(is_valid(cache_entry));
501        out_msg.addr := address;
502        out_msg.Type := CoherenceResponseType:DATA;
503        out_msg.Sender := machineID;
504        out_msg.Destination.add(in_msg.Requestor);
505        out_msg.DataBlk := cache_entry.DataBlk;
506        out_msg.MessageSize := MessageSizeType:Response_Data;
507        out_msg.AckCount := 0;
508      }
509    }
510  }
511
512  action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") {
513    assert(is_valid(tbe));
514    assert(tbe.L1_GetS_IDs.count() > 0);
515    enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
516      assert(is_valid(cache_entry));
517      out_msg.addr := address;
518      out_msg.Type := CoherenceResponseType:DATA;
519      out_msg.Sender := machineID;
520      out_msg.Destination := tbe.L1_GetS_IDs;  // internal nodes
521      out_msg.DataBlk := cache_entry.DataBlk;
522      out_msg.MessageSize := MessageSizeType:Response_Data;
523    }
524  }
525
526  action(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") {
527    assert(is_valid(tbe));
528    assert(tbe.L1_GetS_IDs.count() == 1);
529    enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
530      assert(is_valid(cache_entry));
531      out_msg.addr := address;
532      out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
533      out_msg.Sender := machineID;
534      out_msg.Destination := tbe.L1_GetS_IDs;  // internal nodes
535      out_msg.DataBlk := cache_entry.DataBlk;
536      out_msg.MessageSize := MessageSizeType:Response_Data;
537    }
538  }
539
540  action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") {
541    enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
542      assert(is_valid(tbe));
543      assert(is_valid(cache_entry));
544      out_msg.addr := address;
545      out_msg.Type := CoherenceResponseType:DATA;
546      out_msg.Sender := machineID;
547      out_msg.Destination.add(tbe.L1_GetX_ID);
548      DPRINTF(RubySlicc, "%s\n", out_msg.Destination);
549      out_msg.DataBlk := cache_entry.DataBlk;
550      DPRINTF(RubySlicc, "Address: %#x, Destination: %s, DataBlock: %s\n",
551              out_msg.addr, out_msg.Destination, out_msg.DataBlk);
552      out_msg.MessageSize := MessageSizeType:Response_Data;
553    }
554  }
555
556  action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") {
557    enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
558      assert(is_valid(cache_entry));
559      out_msg.addr := address;
560      out_msg.Type := CoherenceRequestType:INV;
561      out_msg.Requestor := machineID;
562      out_msg.Destination := cache_entry.Sharers;
563      out_msg.MessageSize := MessageSizeType:Request_Control;
564    }
565  }
566
567  action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") {
568    peek(L1RequestL2Network_in, RequestMsg) {
569      enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
570        assert(is_valid(cache_entry));
571        out_msg.addr := address;
572        out_msg.Type := CoherenceRequestType:INV;
573        out_msg.Requestor := in_msg.Requestor;
574        out_msg.Destination := cache_entry.Sharers;
575        out_msg.MessageSize := MessageSizeType:Request_Control;
576      }
577    }
578  }
579
580  action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") {
581    peek(L1RequestL2Network_in, RequestMsg) {
582      enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
583        assert(is_valid(cache_entry));
584        out_msg.addr := address;
585        out_msg.Type := CoherenceRequestType:INV;
586        out_msg.Requestor := in_msg.Requestor;
587        out_msg.Destination := cache_entry.Sharers;
588        out_msg.Destination.remove(in_msg.Requestor);
589        out_msg.MessageSize := MessageSizeType:Request_Control;
590      }
591    }
592  }
593
594  // OTHER ACTIONS
595  action(i_allocateTBE, "i", desc="Allocate TBE for request") {
596    check_allocate(TBEs);
597    assert(is_valid(cache_entry));
598    TBEs.allocate(address);
599    set_tbe(TBEs[address]);
600    tbe.L1_GetS_IDs.clear();
601    tbe.DataBlk := cache_entry.DataBlk;
602    tbe.Dirty := cache_entry.Dirty;
603    tbe.pendingAcks := cache_entry.Sharers.count();
604  }
605
606  action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
607    TBEs.deallocate(address);
608    unset_tbe();
609  }
610
611  action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
612    Tick delay := L1RequestL2Network_in.dequeue(clockEdge());
613    profileMsgDelay(0, ticksToCycles(delay));
614  }
615
616  action(k_popUnblockQueue, "k", desc="Pop incoming unblock queue") {
617    Tick delay := L1unblockNetwork_in.dequeue(clockEdge());
618    profileMsgDelay(0, ticksToCycles(delay));
619  }
620
621  action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
622    Tick delay := responseL2Network_in.dequeue(clockEdge());
623    profileMsgDelay(1, ticksToCycles(delay));
624  }
625
626  action(m_writeDataToCache, "m", desc="Write data from response queue to cache") {
627    peek(responseL2Network_in, ResponseMsg) {
628      assert(is_valid(cache_entry));
629      cache_entry.DataBlk := in_msg.DataBlk;
630      if (in_msg.Dirty) {
631        cache_entry.Dirty := in_msg.Dirty;
632      }
633    }
634  }
635
636  action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") {
637    peek(L1RequestL2Network_in, RequestMsg) {
638      assert(is_valid(cache_entry));
639      if (in_msg.Dirty) {
640        cache_entry.DataBlk := in_msg.DataBlk;
641        cache_entry.Dirty := in_msg.Dirty;
642      }
643    }
644  }
645
646  action(q_updateAck, "q", desc="update pending ack count") {
647    peek(responseL2Network_in, ResponseMsg) {
648      assert(is_valid(tbe));
649      tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
650      APPEND_TRANSITION_COMMENT(in_msg.AckCount);
651      APPEND_TRANSITION_COMMENT(" p: ");
652      APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
653    }
654  }
655
656  action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") {
657    peek(responseL2Network_in, ResponseMsg) {
658      assert(is_valid(tbe));
659      tbe.DataBlk := in_msg.DataBlk;
660      tbe.Dirty := in_msg.Dirty;
661    }
662  }
663
664  action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") {
665    peek(L1RequestL2Network_in, RequestMsg) {
666      assert(is_valid(tbe));
667      tbe.L1_GetS_IDs.add(in_msg.Requestor);
668    }
669  }
670
671  action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
672    peek(L1RequestL2Network_in, RequestMsg) {
673      assert(is_valid(tbe));
674      tbe.L1_GetX_ID := in_msg.Requestor;
675    }
676  }
677
678  action(set_setMRU, "\set", desc="set the MRU entry") {
679    L2cache.setMRU(address);
680  }
681
682  action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
683    if (is_invalid(cache_entry)) {
684      set_cache_entry(L2cache.allocate(address, new Entry));
685    }
686  }
687
688  action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block.  Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
689    L2cache.deallocate(address);
690    unset_cache_entry();
691  }
692
693  action(t_sendWBAck, "t", desc="Send writeback ACK") {
694    peek(L1RequestL2Network_in, RequestMsg) {
695      enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
696        out_msg.addr := address;
697        out_msg.Type := CoherenceResponseType:WB_ACK;
698        out_msg.Sender := machineID;
699        out_msg.Destination.add(in_msg.Requestor);
700        out_msg.MessageSize := MessageSizeType:Response_Control;
701      }
702    }
703  }
704
705  action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") {
706    peek(L1RequestL2Network_in, RequestMsg) {
707      enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
708        assert(is_valid(cache_entry));
709        out_msg.addr := address;
710        out_msg.Type := CoherenceResponseType:ACK;
711        out_msg.Sender := machineID;
712        out_msg.Destination.add(in_msg.Requestor);
713        out_msg.MessageSize := MessageSizeType:Response_Control;
714        // upgrader doesn't get ack from itself, hence the + 1
715        out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1;
716      }
717    }
718  }
719
720  action(uu_profileMiss, "\um", desc="Profile the demand miss") {
721      ++L2cache.demand_misses;
722  }
723
724  action(uu_profileHit, "\uh", desc="Profile the demand hit") {
725      ++L2cache.demand_hits;
726  }
727
728  action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
729    peek(L1RequestL2Network_in, RequestMsg) {
730      assert(is_valid(cache_entry));
731      addSharer(address, in_msg.Requestor, cache_entry);
732      APPEND_TRANSITION_COMMENT( cache_entry.Sharers );
733    }
734  }
735
736  action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") {
737    peek(L1unblockNetwork_in, ResponseMsg) {
738      assert(is_valid(cache_entry));
739      addSharer(address, in_msg.Sender, cache_entry);
740    }
741  }
742
743  action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
744    peek(L1RequestL2Network_in, RequestMsg) {
745      assert(is_valid(cache_entry));
746      cache_entry.Sharers.remove(in_msg.Requestor);
747    }
748  }
749
750  action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
751    peek(L1RequestL2Network_in, RequestMsg) {
752      assert(is_valid(cache_entry));
753      cache_entry.Sharers.clear();
754    }
755  }
756
757  action(mm_markExclusive, "\m", desc="set the exclusive owner") {
758    peek(L1RequestL2Network_in, RequestMsg) {
759      assert(is_valid(cache_entry));
760      cache_entry.Sharers.clear();
761      cache_entry.Exclusive := in_msg.Requestor;
762      addSharer(address, in_msg.Requestor, cache_entry);
763    }
764  }
765
766  action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") {
767    peek(L1unblockNetwork_in, ResponseMsg) {
768      assert(is_valid(cache_entry));
769      cache_entry.Sharers.clear();
770      cache_entry.Exclusive := in_msg.Sender;
771      addSharer(address, in_msg.Sender, cache_entry);
772    }
773  }
774
775  action(zz_stallAndWaitL1RequestQueue, "zz", desc="recycle L1 request queue") {
776    stall_and_wait(L1RequestL2Network_in, address);
777  }
778
779  action(zn_recycleResponseNetwork, "zn", desc="recycle memory request") {
780    responseL2Network_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
781  }
782
783  action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
784    wakeUpBuffers(address);
785  }
786
787  //*****************************************************
788  // TRANSITIONS
789  //*****************************************************
790
791
792  //===============================================
793  // BASE STATE - I
794
795  // Transitions from I (Idle)
796  transition({NP, IS, ISS, IM, SS, M, M_I, I_I, S_I, MT_IB, MT_SB}, L1_PUTX) {
797    t_sendWBAck;
798    jj_popL1RequestQueue;
799  }
800
801  transition({NP, SS, M, MT, M_I, I_I, S_I, IS, ISS, IM, MT_IB, MT_SB}, L1_PUTX_old) {
802    t_sendWBAck;
803    jj_popL1RequestQueue;
804  }
805
806  transition({IM, IS, ISS, SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L2_Replacement, L2_Replacement_clean}) {
807    zz_stallAndWaitL1RequestQueue;
808  }
809
810  transition({IM, IS, ISS, SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, MEM_Inv) {
811    zn_recycleResponseNetwork;
812  }
813
814  transition({I_I, S_I, M_I, MT_I, MCT_I, NP}, MEM_Inv) {
815    o_popIncomingResponseQueue;
816  }
817
818
819  transition({SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE}) {
820    zz_stallAndWaitL1RequestQueue;
821  }
822
823
824  transition(NP, L1_GETS,  ISS) {
825    qq_allocateL2CacheBlock;
826    ll_clearSharers;
827    nn_addSharer;
828    i_allocateTBE;
829    ss_recordGetSL1ID;
830    a_issueFetchToMemory;
831    uu_profileMiss;
832    jj_popL1RequestQueue;
833  }
834
835  transition(NP, L1_GET_INSTR, IS) {
836    qq_allocateL2CacheBlock;
837    ll_clearSharers;
838    nn_addSharer;
839    i_allocateTBE;
840    ss_recordGetSL1ID;
841    a_issueFetchToMemory;
842    uu_profileMiss;
843    jj_popL1RequestQueue;
844  }
845
846  transition(NP, L1_GETX, IM) {
847    qq_allocateL2CacheBlock;
848    ll_clearSharers;
849    // nn_addSharer;
850    i_allocateTBE;
851    xx_recordGetXL1ID;
852    a_issueFetchToMemory;
853    uu_profileMiss;
854    jj_popL1RequestQueue;
855  }
856
857
858  // transitions from IS/IM
859
860  transition(ISS, Mem_Data, MT_MB) {
861    m_writeDataToCache;
862    ex_sendExclusiveDataToGetSRequestors;
863    s_deallocateTBE;
864    o_popIncomingResponseQueue;
865  }
866
867  transition(IS, Mem_Data, SS) {
868    m_writeDataToCache;
869    e_sendDataToGetSRequestors;
870    s_deallocateTBE;
871    o_popIncomingResponseQueue;
872    kd_wakeUpDependents;
873  }
874
875  transition(IM, Mem_Data, MT_MB) {
876    m_writeDataToCache;
877    ee_sendDataToGetXRequestor;
878    s_deallocateTBE;
879    o_popIncomingResponseQueue;
880  }
881
882  transition({IS, ISS}, {L1_GETS, L1_GET_INSTR}, IS) {
883    nn_addSharer;
884    ss_recordGetSL1ID;
885    uu_profileMiss;
886    jj_popL1RequestQueue;
887  }
888
889  transition({IS, ISS}, L1_GETX) {
890    zz_stallAndWaitL1RequestQueue;
891  }
892
893  transition(IM, {L1_GETX, L1_GETS, L1_GET_INSTR}) {
894    zz_stallAndWaitL1RequestQueue;
895  }
896
897  // transitions from SS
898  transition(SS, {L1_GETS, L1_GET_INSTR}) {
899    ds_sendSharedDataToRequestor;
900    nn_addSharer;
901    set_setMRU;
902    uu_profileHit;
903    jj_popL1RequestQueue;
904  }
905
906
907  transition(SS, L1_GETX, SS_MB) {
908    d_sendDataToRequestor;
909    // fw_sendFwdInvToSharers;
910    fwm_sendFwdInvToSharersMinusRequestor;
911    set_setMRU;
912    uu_profileHit;
913    jj_popL1RequestQueue;
914  }
915
916  transition(SS, L1_UPGRADE, SS_MB) {
917    fwm_sendFwdInvToSharersMinusRequestor;
918    ts_sendInvAckToUpgrader;
919    set_setMRU;
920    uu_profileHit;
921    jj_popL1RequestQueue;
922  }
923
924  transition(SS, L2_Replacement_clean, I_I) {
925    i_allocateTBE;
926    f_sendInvToSharers;
927    rr_deallocateL2CacheBlock;
928  }
929
930  transition(SS, {L2_Replacement, MEM_Inv}, S_I) {
931    i_allocateTBE;
932    f_sendInvToSharers;
933    rr_deallocateL2CacheBlock;
934  }
935
936
937  transition(M, L1_GETX, MT_MB) {
938    d_sendDataToRequestor;
939    set_setMRU;
940    uu_profileHit;
941    jj_popL1RequestQueue;
942  }
943
944  transition(M, L1_GET_INSTR, SS) {
945    d_sendDataToRequestor;
946    nn_addSharer;
947    set_setMRU;
948    uu_profileHit;
949    jj_popL1RequestQueue;
950  }
951
952  transition(M, L1_GETS, MT_MB) {
953    dd_sendExclusiveDataToRequestor;
954    set_setMRU;
955    uu_profileHit;
956    jj_popL1RequestQueue;
957  }
958
959  transition(M, {L2_Replacement, MEM_Inv}, M_I) {
960    i_allocateTBE;
961    c_exclusiveReplacement;
962    rr_deallocateL2CacheBlock;
963  }
964
965  transition(M, L2_Replacement_clean, M_I) {
966    i_allocateTBE;
967    c_exclusiveCleanReplacement;
968    rr_deallocateL2CacheBlock;
969  }
970
971
972  // transitions from MT
973
974  transition(MT, L1_GETX, MT_MB) {
975    b_forwardRequestToExclusive;
976    uu_profileMiss;
977    set_setMRU;
978    jj_popL1RequestQueue;
979  }
980
981
982  transition(MT, {L1_GETS, L1_GET_INSTR}, MT_IIB) {
983    b_forwardRequestToExclusive;
984    uu_profileMiss;
985    set_setMRU;
986    jj_popL1RequestQueue;
987  }
988
989  transition(MT, {L2_Replacement, MEM_Inv}, MT_I) {
990    i_allocateTBE;
991    f_sendInvToSharers;
992    rr_deallocateL2CacheBlock;
993  }
994
995  transition(MT, L2_Replacement_clean, MCT_I) {
996    i_allocateTBE;
997    f_sendInvToSharers;
998    rr_deallocateL2CacheBlock;
999  }
1000
1001  transition(MT, L1_PUTX, M) {
1002    ll_clearSharers;
1003    mr_writeDataToCacheFromRequest;
1004    t_sendWBAck;
1005    jj_popL1RequestQueue;
1006  }
1007
1008  transition({SS_MB,MT_MB}, Exclusive_Unblock, MT) {
1009    // update actual directory
1010    mmu_markExclusiveFromUnblock;
1011    k_popUnblockQueue;
1012    kd_wakeUpDependents;
1013  }
1014
1015  transition(MT_IIB, {L1_PUTX, L1_PUTX_old}){
1016    zz_stallAndWaitL1RequestQueue;
1017  }
1018
1019  transition(MT_IIB, Unblock, MT_IB) {
1020    nnu_addSharerFromUnblock;
1021    k_popUnblockQueue;
1022  }
1023
1024  transition(MT_IIB, {WB_Data, WB_Data_clean}, MT_SB) {
1025    m_writeDataToCache;
1026    o_popIncomingResponseQueue;
1027  }
1028
1029  transition(MT_IB, {WB_Data, WB_Data_clean}, SS) {
1030    m_writeDataToCache;
1031    o_popIncomingResponseQueue;
1032    kd_wakeUpDependents;
1033  }
1034
1035  transition(MT_SB, Unblock, SS) {
1036    nnu_addSharerFromUnblock;
1037    k_popUnblockQueue;
1038    kd_wakeUpDependents;
1039  }
1040
1041  // writeback states
1042  transition({I_I, S_I, MT_I, MCT_I, M_I}, {L1_GETX, L1_UPGRADE, L1_GETS, L1_GET_INSTR}) {
1043    zz_stallAndWaitL1RequestQueue;
1044  }
1045
1046  transition(I_I, Ack) {
1047    q_updateAck;
1048    o_popIncomingResponseQueue;
1049  }
1050
1051  transition(I_I, Ack_all, M_I) {
1052    c_exclusiveCleanReplacement;
1053    o_popIncomingResponseQueue;
1054  }
1055
1056  transition({MT_I, MCT_I}, WB_Data, M_I) {
1057    qq_writeDataToTBE;
1058    ct_exclusiveReplacementFromTBE;
1059    o_popIncomingResponseQueue;
1060  }
1061
1062  transition(MCT_I, {WB_Data_clean, Ack_all}, M_I) {
1063    c_exclusiveCleanReplacement;
1064    o_popIncomingResponseQueue;
1065  }
1066
1067  transition(MCT_I,  {L1_PUTX, L1_PUTX_old}){
1068    zz_stallAndWaitL1RequestQueue;
1069  }
1070
1071  // L1 never changed Dirty data
1072  transition(MT_I, {WB_Data_clean, Ack_all}, M_I) {
1073    ct_exclusiveReplacementFromTBE;
1074    o_popIncomingResponseQueue;
1075  }
1076
1077  transition(MT_I, {L1_PUTX, L1_PUTX_old}){
1078    zz_stallAndWaitL1RequestQueue;
1079  }
1080
1081  // possible race between unblock and immediate replacement
1082  transition({MT_MB,SS_MB}, {L1_PUTX, L1_PUTX_old}) {
1083    zz_stallAndWaitL1RequestQueue;
1084  }
1085
1086  transition(S_I, Ack) {
1087    q_updateAck;
1088    o_popIncomingResponseQueue;
1089  }
1090
1091  transition(S_I, Ack_all, M_I) {
1092    ct_exclusiveReplacementFromTBE;
1093    o_popIncomingResponseQueue;
1094  }
1095
1096  transition(M_I, Mem_Ack, NP) {
1097    s_deallocateTBE;
1098    o_popIncomingResponseQueue;
1099    kd_wakeUpDependents;
1100  }
1101}
1102