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:L1Cache, "MESI Directory L1 Cache CMP")
30 : CacheMemory * cache;
31   int l2_select_num_bits;
32   Cycles l1_request_latency := 2;
33   Cycles l1_response_latency := 2;
34   Cycles to_l2_latency := 1;
35
36   // Message Buffers between the L1 and the L0 Cache
37   // From the L1 cache to the L0 cache
38   MessageBuffer * bufferToL0, network="To";
39
40   // From the L0 cache to the L1 cache
41   MessageBuffer * bufferFromL0, network="From";
42
43   // Message queue from this L1 cache TO the network / L2
44   MessageBuffer * requestToL2, network="To", virtual_network="0",
45        vnet_type="request";
46
47   MessageBuffer * responseToL2, network="To", virtual_network="1",
48        vnet_type="response";
49   MessageBuffer * unblockToL2, network="To", virtual_network="2",
50        vnet_type="unblock";
51
52   // To this L1 cache FROM the network / L2
53   MessageBuffer * requestFromL2, network="From", virtual_network="2",
54        vnet_type="request";
55   MessageBuffer * responseFromL2, network="From", virtual_network="1",
56        vnet_type="response";
57
58{
59  // STATES
60  state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
61    // Base states
62    I, AccessPermission:Invalid, desc="a L1 cache entry Idle";
63    S, AccessPermission:Read_Only, desc="a L1 cache entry Shared";
64    SS, AccessPermission:Read_Only, desc="a L1 cache entry Shared";
65    E, AccessPermission:Read_Only, desc="a L1 cache entry Exclusive";
66    EE, AccessPermission:Read_Write, desc="a L1 cache entry Exclusive";
67    M, AccessPermission:Maybe_Stale, desc="a L1 cache entry Modified", format="!b";
68    MM, AccessPermission:Read_Write, desc="a L1 cache entry Modified", format="!b";
69
70    // Transient States
71    IS, AccessPermission:Busy, desc="L1 idle, issued GETS, have not seen response yet";
72    IM, AccessPermission:Busy, desc="L1 idle, issued GETX, have not seen response yet";
73    SM, AccessPermission:Read_Only, desc="L1 idle, issued GETX, have not seen response yet";
74    IS_I, AccessPermission:Busy, desc="L1 idle, issued GETS, saw Inv before data because directory doesn't block on GETS hit";
75    M_I, AccessPermission:Busy, desc="L1 replacing, waiting for ACK";
76    SINK_WB_ACK, AccessPermission:Busy, desc="This is to sink WB_Acks from L2";
77
78    // For all of the following states, invalidate
79    // message has been sent to L0 cache. The response
80    // from the L0 cache has not been seen yet.
81    S_IL0, AccessPermission:Busy;
82    E_IL0, AccessPermission:Busy;
83    M_IL0, AccessPermission:Busy;
84    MM_IL0, AccessPermission:Read_Write;
85    SM_IL0, AccessPermission:Busy;
86  }
87
88  // EVENTS
89  enumeration(Event, desc="Cache events") {
90    // Requests from the L0 cache
91    Load,            desc="Load request";
92    Store,           desc="Store request";
93    WriteBack,       desc="Writeback request";
94
95    // Responses from the L0 Cache
96    // L0 cache received the invalidation message
97    // and has sent the data.
98    L0_DataAck;
99
100    Inv,           desc="Invalidate request from L2 bank";
101
102    // internal generated request
103    // Invalidate the line in L0 due to own requirements
104    L0_Invalidate_Own;
105    // Invalidate the line in L0 due to some other cache's requirements
106    L0_Invalidate_Else;
107    // Invalidate the line in the cache due to some one else / space needs.
108    L1_Replacement;
109
110    // other requests
111    Fwd_GETX,   desc="GETX from other processor";
112    Fwd_GETS,   desc="GETS from other processor";
113
114    Data,       desc="Data for processor";
115    Data_Exclusive,       desc="Data for processor";
116    DataS_fromL1,       desc="data for GETS request, need to unblock directory";
117    Data_all_Acks,       desc="Data for processor, all acks";
118
119    L0_Ack,        desc="Ack for processor";
120    Ack,        desc="Ack for processor";
121    Ack_all,      desc="Last ack for processor";
122
123    WB_Ack,        desc="Ack for replacement";
124  }
125
126  // TYPES
127
128  // CacheEntry
129  structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
130    State CacheState,        desc="cache state";
131    DataBlock DataBlk,       desc="data for the block";
132    bool Dirty, default="false",   desc="data is dirty";
133  }
134
135  // TBE fields
136  structure(TBE, desc="...") {
137    Addr addr,              desc="Physical address for this TBE";
138    State TBEState,        desc="Transient state";
139    DataBlock DataBlk,                desc="Buffer for the data block";
140    bool Dirty, default="false",   desc="data is dirty";
141    int pendingAcks, default="0", desc="number of pending acks";
142  }
143
144  structure(TBETable, external="yes") {
145    TBE lookup(Addr);
146    void allocate(Addr);
147    void deallocate(Addr);
148    bool isPresent(Addr);
149  }
150
151  TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
152
153  int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
154
155  Tick clockEdge();
156  Cycles ticksToCycles(Tick t);
157  void set_cache_entry(AbstractCacheEntry a);
158  void unset_cache_entry();
159  void set_tbe(TBE a);
160  void unset_tbe();
161  void wakeUpBuffers(Addr a);
162  void wakeUpAllBuffers(Addr a);
163  void profileMsgDelay(int virtualNetworkType, Cycles c);
164
165  // inclusive cache returns L1 entries only
166  Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
167    Entry cache_entry := static_cast(Entry, "pointer", cache[addr]);
168    return cache_entry;
169  }
170
171  State getState(TBE tbe, Entry cache_entry, Addr addr) {
172    if(is_valid(tbe)) {
173      return tbe.TBEState;
174    } else if (is_valid(cache_entry)) {
175      return cache_entry.CacheState;
176    }
177    return State:I;
178  }
179
180  void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
181    // MUST CHANGE
182    if(is_valid(tbe)) {
183      tbe.TBEState := state;
184    }
185
186    if (is_valid(cache_entry)) {
187      cache_entry.CacheState := state;
188    }
189  }
190
191  AccessPermission getAccessPermission(Addr addr) {
192    TBE tbe := TBEs[addr];
193    if(is_valid(tbe)) {
194      DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
195      return L1Cache_State_to_permission(tbe.TBEState);
196    }
197
198    Entry cache_entry := getCacheEntry(addr);
199    if(is_valid(cache_entry)) {
200      DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
201      return L1Cache_State_to_permission(cache_entry.CacheState);
202    }
203
204    DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
205    return AccessPermission:NotPresent;
206  }
207
208  void functionalRead(Addr addr, Packet *pkt) {
209    TBE tbe := TBEs[addr];
210    if(is_valid(tbe)) {
211      testAndRead(addr, tbe.DataBlk, pkt);
212    } else {
213      testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
214    }
215  }
216
217  int functionalWrite(Addr addr, Packet *pkt) {
218    int num_functional_writes := 0;
219
220    TBE tbe := TBEs[addr];
221    if(is_valid(tbe)) {
222      num_functional_writes := num_functional_writes +
223        testAndWrite(addr, tbe.DataBlk, pkt);
224      return num_functional_writes;
225    }
226
227    num_functional_writes := num_functional_writes +
228        testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
229    return num_functional_writes;
230  }
231
232  void setAccessPermission(Entry cache_entry, Addr addr, State state) {
233    if (is_valid(cache_entry)) {
234      cache_entry.changePermission(L1Cache_State_to_permission(state));
235    }
236  }
237
238  Event mandatory_request_type_to_event(CoherenceClass type) {
239    if (type == CoherenceClass:GETS) {
240      return Event:Load;
241    } else if ((type == CoherenceClass:GETX) ||
242               (type == CoherenceClass:UPGRADE)) {
243      return Event:Store;
244    } else if (type == CoherenceClass:PUTX) {
245      return Event:WriteBack;
246    } else {
247      error("Invalid RequestType");
248    }
249  }
250
251  int getPendingAcks(TBE tbe) {
252    return tbe.pendingAcks;
253  }
254
255  bool inL0Cache(State state) {
256    if (state == State:S || state == State:E || state == State:M ||
257        state == State:S_IL0 || state == State:E_IL0 ||
258        state == State:M_IL0 || state == State:SM_IL0) {
259        return true;
260    }
261
262    return false;
263  }
264
265  out_port(requestNetwork_out, RequestMsg, requestToL2);
266  out_port(responseNetwork_out, ResponseMsg, responseToL2);
267  out_port(unblockNetwork_out, ResponseMsg, unblockToL2);
268  out_port(bufferToL0_out, CoherenceMsg, bufferToL0);
269
270  // Response From the L2 Cache to this L1 cache
271  in_port(responseNetwork_in, ResponseMsg, responseFromL2, rank = 3) {
272    if (responseNetwork_in.isReady(clockEdge())) {
273      peek(responseNetwork_in, ResponseMsg) {
274        assert(in_msg.Destination.isElement(machineID));
275
276        Entry cache_entry := getCacheEntry(in_msg.addr);
277        TBE tbe := TBEs[in_msg.addr];
278
279        if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
280          trigger(Event:Data_Exclusive, in_msg.addr, cache_entry, tbe);
281        } else if(in_msg.Type == CoherenceResponseType:DATA) {
282          if ((getState(tbe, cache_entry, in_msg.addr) == State:IS ||
283               getState(tbe, cache_entry, in_msg.addr) == State:IS_I) &&
284              machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
285
286              trigger(Event:DataS_fromL1, in_msg.addr, cache_entry, tbe);
287
288          } else if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
289            trigger(Event:Data_all_Acks, in_msg.addr, cache_entry, tbe);
290          } else {
291            trigger(Event:Data, in_msg.addr, cache_entry, tbe);
292          }
293        } else if (in_msg.Type == CoherenceResponseType:ACK) {
294          if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
295            trigger(Event:Ack_all, in_msg.addr, cache_entry, tbe);
296          } else {
297            trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
298          }
299        } else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
300          trigger(Event:WB_Ack, in_msg.addr, cache_entry, tbe);
301        } else {
302          error("Invalid L1 response type");
303        }
304      }
305    }
306  }
307
308  // Request to this L1 cache from the shared L2
309  in_port(requestNetwork_in, RequestMsg, requestFromL2, rank = 2) {
310    if(requestNetwork_in.isReady(clockEdge())) {
311      peek(requestNetwork_in, RequestMsg) {
312        assert(in_msg.Destination.isElement(machineID));
313        Entry cache_entry := getCacheEntry(in_msg.addr);
314        TBE tbe := TBEs[in_msg.addr];
315
316        if (in_msg.Type == CoherenceRequestType:INV) {
317            if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
318                trigger(Event:L0_Invalidate_Else, in_msg.addr,
319                        cache_entry, tbe);
320            }  else {
321                trigger(Event:Inv, in_msg.addr, cache_entry, tbe);
322            }
323        } else if (in_msg.Type == CoherenceRequestType:GETX ||
324                   in_msg.Type == CoherenceRequestType:UPGRADE) {
325            if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
326                trigger(Event:L0_Invalidate_Else, in_msg.addr,
327                        cache_entry, tbe);
328            } else {
329                trigger(Event:Fwd_GETX, in_msg.addr, cache_entry, tbe);
330            }
331        } else if (in_msg.Type == CoherenceRequestType:GETS) {
332            if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
333                trigger(Event:L0_Invalidate_Else, in_msg.addr,
334                        cache_entry, tbe);
335            } else {
336                trigger(Event:Fwd_GETS, in_msg.addr, cache_entry, tbe);
337            }
338        } else {
339          error("Invalid forwarded request type");
340        }
341      }
342    }
343  }
344
345  // Requests to this L1 cache from the L0 cache.
346  in_port(messageBufferFromL0_in, CoherenceMsg, bufferFromL0, rank = 0) {
347    if (messageBufferFromL0_in.isReady(clockEdge())) {
348      peek(messageBufferFromL0_in, CoherenceMsg) {
349        Entry cache_entry := getCacheEntry(in_msg.addr);
350        TBE tbe := TBEs[in_msg.addr];
351
352        if(in_msg.Class == CoherenceClass:INV_DATA) {
353            trigger(Event:L0_DataAck, in_msg.addr, cache_entry, tbe);
354        }  else if (in_msg.Class == CoherenceClass:INV_ACK) {
355            trigger(Event:L0_Ack, in_msg.addr, cache_entry, tbe);
356        }  else {
357            if (is_valid(cache_entry)) {
358                trigger(mandatory_request_type_to_event(in_msg.Class),
359                        in_msg.addr, cache_entry, tbe);
360            } else {
361                if (cache.cacheAvail(in_msg.addr)) {
362                    // L1 does't have the line, but we have space for it
363                    // in the L1 let's see if the L2 has it
364                    trigger(mandatory_request_type_to_event(in_msg.Class),
365                            in_msg.addr, cache_entry, tbe);
366                } else {
367                    // No room in the L1, so we need to make room in the L1
368                    Addr victim := cache.cacheProbe(in_msg.addr);
369                    Entry victim_entry := getCacheEntry(victim);
370                    TBE victim_tbe := TBEs[victim];
371
372                    if (is_valid(victim_entry) && inL0Cache(victim_entry.CacheState)) {
373                        trigger(Event:L0_Invalidate_Own,
374                                victim, victim_entry, victim_tbe);
375                    }  else {
376                        trigger(Event:L1_Replacement,
377                                victim, victim_entry, victim_tbe);
378                    }
379                }
380            }
381        }
382      }
383    }
384  }
385
386  // ACTIONS
387  action(a_issueGETS, "a", desc="Issue GETS") {
388    peek(messageBufferFromL0_in, CoherenceMsg) {
389      enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
390        out_msg.addr := address;
391        out_msg.Type := CoherenceRequestType:GETS;
392        out_msg.Requestor := machineID;
393        out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
394                          l2_select_low_bit, l2_select_num_bits, clusterID));
395        DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
396                address, out_msg.Destination);
397        out_msg.MessageSize := MessageSizeType:Control;
398        out_msg.AccessMode := in_msg.AccessMode;
399      }
400    }
401  }
402
403  action(b_issueGETX, "b", desc="Issue GETX") {
404    peek(messageBufferFromL0_in, CoherenceMsg) {
405      enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
406        out_msg.addr := address;
407        out_msg.Type := CoherenceRequestType:GETX;
408        out_msg.Requestor := machineID;
409        DPRINTF(RubySlicc, "%s\n", machineID);
410        out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
411                          l2_select_low_bit, l2_select_num_bits, clusterID));
412        DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
413                address, out_msg.Destination);
414        out_msg.MessageSize := MessageSizeType:Control;
415        out_msg.AccessMode := in_msg.AccessMode;
416      }
417    }
418  }
419
420  action(c_issueUPGRADE, "c", desc="Issue GETX") {
421    peek(messageBufferFromL0_in, CoherenceMsg) {
422      enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
423        out_msg.addr := address;
424        out_msg.Type := CoherenceRequestType:UPGRADE;
425        out_msg.Requestor := machineID;
426        out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
427                          l2_select_low_bit, l2_select_num_bits, clusterID));
428        DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
429                address, out_msg.Destination);
430        out_msg.MessageSize := MessageSizeType:Control;
431        out_msg.AccessMode := in_msg.AccessMode;
432      }
433    }
434  }
435
436  action(d_sendDataToRequestor, "d", desc="send data to requestor") {
437    peek(requestNetwork_in, RequestMsg) {
438      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
439        assert(is_valid(cache_entry));
440        out_msg.addr := address;
441        out_msg.Type := CoherenceResponseType:DATA;
442        out_msg.DataBlk := cache_entry.DataBlk;
443        out_msg.Dirty := cache_entry.Dirty;
444        out_msg.Sender := machineID;
445        out_msg.Destination.add(in_msg.Requestor);
446        out_msg.MessageSize := MessageSizeType:Response_Data;
447      }
448    }
449  }
450
451  action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") {
452    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
453      assert(is_valid(cache_entry));
454      out_msg.addr := address;
455      out_msg.Type := CoherenceResponseType:DATA;
456      out_msg.DataBlk := cache_entry.DataBlk;
457      out_msg.Dirty := cache_entry.Dirty;
458      out_msg.Sender := machineID;
459      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
460                          l2_select_low_bit, l2_select_num_bits, clusterID));
461      out_msg.MessageSize := MessageSizeType:Response_Data;
462    }
463  }
464
465  action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") {
466    peek(requestNetwork_in, RequestMsg) {
467      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
468        assert(is_valid(tbe));
469        out_msg.addr := address;
470        out_msg.Type := CoherenceResponseType:DATA;
471        out_msg.DataBlk := tbe.DataBlk;
472        out_msg.Dirty := tbe.Dirty;
473        out_msg.Sender := machineID;
474        out_msg.Destination.add(in_msg.Requestor);
475        out_msg.MessageSize := MessageSizeType:Response_Data;
476      }
477    }
478  }
479
480  action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") {
481    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
482      assert(is_valid(tbe));
483      out_msg.addr := address;
484      out_msg.Type := CoherenceResponseType:DATA;
485      out_msg.DataBlk := tbe.DataBlk;
486      out_msg.Dirty := tbe.Dirty;
487      out_msg.Sender := machineID;
488      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
489                          l2_select_low_bit, l2_select_num_bits, clusterID));
490      out_msg.MessageSize := MessageSizeType:Response_Data;
491    }
492  }
493
494  action(e_sendAckToRequestor, "e", desc="send invalidate ack to requestor (could be L2 or L1)") {
495    peek(requestNetwork_in, RequestMsg) {
496      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
497        out_msg.addr := address;
498        out_msg.Type := CoherenceResponseType:ACK;
499        out_msg.Sender := machineID;
500        out_msg.Destination.add(in_msg.Requestor);
501        out_msg.MessageSize := MessageSizeType:Response_Control;
502      }
503    }
504  }
505
506  action(f_sendDataToL2, "f", desc="send data to the L2 cache") {
507    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
508      assert(is_valid(cache_entry));
509      out_msg.addr := address;
510      out_msg.Type := CoherenceResponseType:DATA;
511      out_msg.DataBlk := cache_entry.DataBlk;
512      out_msg.Dirty := cache_entry.Dirty;
513      out_msg.Sender := machineID;
514      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
515                          l2_select_low_bit, l2_select_num_bits, clusterID));
516      out_msg.MessageSize := MessageSizeType:Writeback_Data;
517    }
518  }
519
520  action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") {
521    enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
522      assert(is_valid(tbe));
523      out_msg.addr := address;
524      out_msg.Type := CoherenceResponseType:DATA;
525      out_msg.DataBlk := tbe.DataBlk;
526      out_msg.Dirty := tbe.Dirty;
527      out_msg.Sender := machineID;
528      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
529                          l2_select_low_bit, l2_select_num_bits, clusterID));
530      out_msg.MessageSize := MessageSizeType:Writeback_Data;
531    }
532  }
533
534  action(fi_sendInvAck, "fi", desc="send data to the L2 cache") {
535    peek(requestNetwork_in, RequestMsg) {
536      enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
537        out_msg.addr := address;
538        out_msg.Type := CoherenceResponseType:ACK;
539        out_msg.Sender := machineID;
540        out_msg.Destination.add(in_msg.Requestor);
541        out_msg.MessageSize := MessageSizeType:Response_Control;
542        out_msg.AckCount := 1;
543      }
544    }
545  }
546
547  action(forward_eviction_to_L0, "\cc", desc="sends eviction information to the processor") {
548      enqueue(bufferToL0_out, CoherenceMsg, l1_request_latency) {
549          out_msg.addr := address;
550          out_msg.Class := CoherenceClass:INV;
551          out_msg.Sender := machineID;
552          out_msg.Dest := createMachineID(MachineType:L0Cache, version);
553          out_msg.MessageSize := MessageSizeType:Control;
554      }
555  }
556
557  action(g_issuePUTX, "g", desc="send data to the L2 cache") {
558    enqueue(requestNetwork_out, RequestMsg, l1_response_latency) {
559      assert(is_valid(cache_entry));
560      out_msg.addr := address;
561      out_msg.Type := CoherenceRequestType:PUTX;
562      out_msg.Dirty := cache_entry.Dirty;
563      out_msg.Requestor:= machineID;
564      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
565                          l2_select_low_bit, l2_select_num_bits, clusterID));
566      if (cache_entry.Dirty) {
567        out_msg.MessageSize := MessageSizeType:Writeback_Data;
568        out_msg.DataBlk := cache_entry.DataBlk;
569      } else {
570        out_msg.MessageSize := MessageSizeType:Writeback_Control;
571      }
572    }
573  }
574
575  action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
576    enqueue(unblockNetwork_out, ResponseMsg, to_l2_latency) {
577      out_msg.addr := address;
578      out_msg.Type := CoherenceResponseType:UNBLOCK;
579      out_msg.Sender := machineID;
580      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
581                          l2_select_low_bit, l2_select_num_bits, clusterID));
582      out_msg.MessageSize := MessageSizeType:Response_Control;
583      DPRINTF(RubySlicc, "%#x\n", address);
584    }
585  }
586
587  action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
588    enqueue(unblockNetwork_out, ResponseMsg, to_l2_latency) {
589      out_msg.addr := address;
590      out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
591      out_msg.Sender := machineID;
592      out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
593                          l2_select_low_bit, l2_select_num_bits, clusterID));
594      out_msg.MessageSize := MessageSizeType:Response_Control;
595      DPRINTF(RubySlicc, "%#x\n", address);
596
597    }
598  }
599
600  action(h_data_to_l0, "h", desc="If not prefetch, send data to the L0 cache.") {
601      enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
602          assert(is_valid(cache_entry));
603
604          out_msg.addr := address;
605          out_msg.Class := CoherenceClass:DATA;
606          out_msg.Sender := machineID;
607          out_msg.Dest := createMachineID(MachineType:L0Cache, version);
608          out_msg.DataBlk := cache_entry.DataBlk;
609          out_msg.MessageSize := MessageSizeType:Response_Data;
610      }
611  }
612
613  action(hh_xdata_to_l0, "\h", desc="If not prefetch, notify sequencer that store completed.") {
614      enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
615          assert(is_valid(cache_entry));
616
617          out_msg.addr := address;
618          out_msg.Class := CoherenceClass:DATA_EXCLUSIVE;
619          out_msg.Sender := machineID;
620          out_msg.Dest := createMachineID(MachineType:L0Cache, version);
621          out_msg.DataBlk := cache_entry.DataBlk;
622          out_msg.Dirty := cache_entry.Dirty;
623          out_msg.MessageSize := MessageSizeType:Response_Data;
624
625          //cache_entry.Dirty := true;
626      }
627  }
628
629  action(h_stale_data_to_l0, "hs", desc="If not prefetch, send data to the L0 cache.") {
630      enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
631          assert(is_valid(cache_entry));
632
633          out_msg.addr := address;
634          out_msg.Class := CoherenceClass:STALE_DATA;
635          out_msg.Sender := machineID;
636          out_msg.Dest := createMachineID(MachineType:L0Cache, version);
637          out_msg.DataBlk := cache_entry.DataBlk;
638          out_msg.Dirty := cache_entry.Dirty;
639          out_msg.MessageSize := MessageSizeType:Response_Data;
640       }
641   }
642
643  action(i_allocateTBE, "i", desc="Allocate TBE (number of invalidates=0)") {
644    check_allocate(TBEs);
645    assert(is_valid(cache_entry));
646    TBEs.allocate(address);
647    set_tbe(TBEs[address]);
648    tbe.Dirty := cache_entry.Dirty;
649    tbe.DataBlk := cache_entry.DataBlk;
650  }
651
652  action(k_popL0RequestQueue, "k", desc="Pop mandatory queue.") {
653    messageBufferFromL0_in.dequeue(clockEdge());
654  }
655
656  action(l_popL2RequestQueue, "l",
657         desc="Pop incoming request queue and profile the delay within this virtual network") {
658    Tick delay := requestNetwork_in.dequeue(clockEdge());
659    profileMsgDelay(2, ticksToCycles(delay));
660  }
661
662  action(o_popL2ResponseQueue, "o",
663         desc="Pop Incoming Response queue and profile the delay within this virtual network") {
664    Tick delay := responseNetwork_in.dequeue(clockEdge());
665    profileMsgDelay(1, ticksToCycles(delay));
666  }
667
668  action(s_deallocateTBE, "s", desc="Deallocate TBE") {
669    TBEs.deallocate(address);
670    unset_tbe();
671  }
672
673  action(u_writeDataFromL0Request, "ureql0", desc="Write data to cache") {
674    peek(messageBufferFromL0_in, CoherenceMsg) {
675      assert(is_valid(cache_entry));
676      if (in_msg.Dirty) {
677          cache_entry.DataBlk := in_msg.DataBlk;
678          cache_entry.Dirty := in_msg.Dirty;
679      }
680    }
681  }
682
683  action(u_writeDataFromL2Response, "uresl2", desc="Write data to cache") {
684    peek(responseNetwork_in, ResponseMsg) {
685      assert(is_valid(cache_entry));
686      cache_entry.DataBlk := in_msg.DataBlk;
687    }
688  }
689
690  action(u_writeDataFromL0Response, "uresl0", desc="Write data to cache") {
691    peek(messageBufferFromL0_in, CoherenceMsg) {
692      assert(is_valid(cache_entry));
693      if (in_msg.Dirty) {
694          cache_entry.DataBlk := in_msg.DataBlk;
695          cache_entry.Dirty := in_msg.Dirty;
696      }
697    }
698  }
699
700  action(q_updateAckCount, "q", desc="Update ack count") {
701    peek(responseNetwork_in, ResponseMsg) {
702      assert(is_valid(tbe));
703      tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
704      APPEND_TRANSITION_COMMENT(in_msg.AckCount);
705      APPEND_TRANSITION_COMMENT(" p: ");
706      APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
707    }
708  }
709
710  action(ff_deallocateCacheBlock, "\f",
711         desc="Deallocate L1 cache block.") {
712    if (cache.isTagPresent(address)) {
713      cache.deallocate(address);
714    }
715    unset_cache_entry();
716  }
717
718  action(oo_allocateCacheBlock, "\o", desc="Set cache tag equal to tag of block B.") {
719    if (is_invalid(cache_entry)) {
720      set_cache_entry(cache.allocate(address, new Entry));
721    }
722  }
723
724  action(z0_stallAndWaitL0Queue, "\z0", desc="recycle L0 request queue") {
725    stall_and_wait(messageBufferFromL0_in, address);
726  }
727
728  action(z2_stallAndWaitL2Queue, "\z2", desc="recycle L2 request queue") {
729    stall_and_wait(requestNetwork_in, address);
730  }
731
732  action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
733    wakeUpAllBuffers(address);
734  }
735
736  action(uu_profileMiss, "\um", desc="Profile the demand miss") {
737      ++cache.demand_misses;
738  }
739
740  action(uu_profileHit, "\uh", desc="Profile the demand hit") {
741      ++cache.demand_hits;
742  }
743
744
745  //*****************************************************
746  // TRANSITIONS
747  //*****************************************************
748
749  // Transitions for Load/Store/Replacement/WriteBack from transient states
750  transition({IS, IM, IS_I, M_I, SM, SINK_WB_ACK, S_IL0, M_IL0, E_IL0, MM_IL0},
751             {Load, Store, L1_Replacement}) {
752    z0_stallAndWaitL0Queue;
753  }
754
755  transition(I, Load, IS) {
756    oo_allocateCacheBlock;
757    i_allocateTBE;
758    a_issueGETS;
759    uu_profileMiss;
760    k_popL0RequestQueue;
761  }
762
763  transition(I, Store, IM) {
764    oo_allocateCacheBlock;
765    i_allocateTBE;
766    b_issueGETX;
767    uu_profileMiss;
768    k_popL0RequestQueue;
769  }
770
771  transition(I, Inv) {
772    fi_sendInvAck;
773    l_popL2RequestQueue;
774  }
775
776  // Transitions from Shared
777  transition({S,SS}, Load, S) {
778    h_data_to_l0;
779    uu_profileHit;
780    k_popL0RequestQueue;
781  }
782
783  transition(EE, Load, E) {
784    hh_xdata_to_l0;
785    uu_profileHit;
786    k_popL0RequestQueue;
787  }
788
789  transition(MM, Load, M) {
790    hh_xdata_to_l0;
791    uu_profileHit;
792    k_popL0RequestQueue;
793  }
794
795  transition({S,SS}, Store, SM) {
796    i_allocateTBE;
797    c_issueUPGRADE;
798    uu_profileMiss;
799    k_popL0RequestQueue;
800  }
801
802  transition(SS, L1_Replacement, I) {
803    ff_deallocateCacheBlock;
804  }
805
806  transition(S, {L0_Invalidate_Own, L0_Invalidate_Else}, S_IL0) {
807    forward_eviction_to_L0;
808  }
809
810  transition(SS, Inv, I) {
811    fi_sendInvAck;
812    ff_deallocateCacheBlock;
813    l_popL2RequestQueue;
814  }
815
816  // Transitions from Exclusive
817
818  transition({EE,MM}, Store, M) {
819    hh_xdata_to_l0;
820    uu_profileHit;
821    k_popL0RequestQueue;
822  }
823
824  transition(EE, L1_Replacement, M_I) {
825    // silent E replacement??
826    i_allocateTBE;
827    g_issuePUTX;   // send data, but hold in case forwarded request
828    ff_deallocateCacheBlock;
829  }
830
831  transition(EE, Inv, I) {
832    // don't send data
833    fi_sendInvAck;
834    ff_deallocateCacheBlock;
835    l_popL2RequestQueue;
836  }
837
838  transition(EE, Fwd_GETX, I) {
839    d_sendDataToRequestor;
840    ff_deallocateCacheBlock;
841    l_popL2RequestQueue;
842  }
843
844  transition(EE, Fwd_GETS, SS) {
845    d_sendDataToRequestor;
846    d2_sendDataToL2;
847    l_popL2RequestQueue;
848  }
849
850  transition(E, {L0_Invalidate_Own, L0_Invalidate_Else}, E_IL0) {
851    forward_eviction_to_L0;
852  }
853
854  // Transitions from Modified
855  transition(MM, L1_Replacement, M_I) {
856    i_allocateTBE;
857    g_issuePUTX;   // send data, but hold in case forwarded request
858    ff_deallocateCacheBlock;
859  }
860
861  transition({M,E}, WriteBack, MM) {
862    u_writeDataFromL0Request;
863    k_popL0RequestQueue;
864  }
865
866  transition(M_I, WB_Ack, I) {
867    s_deallocateTBE;
868    o_popL2ResponseQueue;
869    ff_deallocateCacheBlock;
870    kd_wakeUpDependents;
871  }
872
873  transition(MM, Inv, I) {
874    f_sendDataToL2;
875    ff_deallocateCacheBlock;
876    l_popL2RequestQueue;
877  }
878
879  transition(M_I, Inv, SINK_WB_ACK) {
880    ft_sendDataToL2_fromTBE;
881    l_popL2RequestQueue;
882  }
883
884  transition(MM, Fwd_GETX, I) {
885    d_sendDataToRequestor;
886    ff_deallocateCacheBlock;
887    l_popL2RequestQueue;
888  }
889
890  transition(MM, Fwd_GETS, SS) {
891    d_sendDataToRequestor;
892    d2_sendDataToL2;
893    l_popL2RequestQueue;
894  }
895
896  transition(M, {L0_Invalidate_Own, L0_Invalidate_Else}, M_IL0) {
897    forward_eviction_to_L0;
898  }
899
900  transition(M_I, Fwd_GETX, SINK_WB_ACK) {
901    dt_sendDataToRequestor_fromTBE;
902    l_popL2RequestQueue;
903  }
904
905  transition(M_I, Fwd_GETS, SINK_WB_ACK) {
906    dt_sendDataToRequestor_fromTBE;
907    d2t_sendDataToL2_fromTBE;
908    l_popL2RequestQueue;
909  }
910
911  // Transitions from IS
912  transition({IS,IS_I}, Inv, IS_I) {
913    fi_sendInvAck;
914    l_popL2RequestQueue;
915  }
916
917  transition(IS, Data_all_Acks, S) {
918    u_writeDataFromL2Response;
919    h_data_to_l0;
920    s_deallocateTBE;
921    o_popL2ResponseQueue;
922    kd_wakeUpDependents;
923  }
924
925  transition(IS_I, Data_all_Acks, I) {
926    u_writeDataFromL2Response;
927    h_stale_data_to_l0;
928    s_deallocateTBE;
929    ff_deallocateCacheBlock;
930    o_popL2ResponseQueue;
931    kd_wakeUpDependents;
932  }
933
934  transition(IS, DataS_fromL1, S) {
935    u_writeDataFromL2Response;
936    j_sendUnblock;
937    h_data_to_l0;
938    s_deallocateTBE;
939    o_popL2ResponseQueue;
940    kd_wakeUpDependents;
941  }
942
943  transition(IS_I, DataS_fromL1, I) {
944    u_writeDataFromL2Response;
945    j_sendUnblock;
946    h_stale_data_to_l0;
947    s_deallocateTBE;
948    ff_deallocateCacheBlock;
949    o_popL2ResponseQueue;
950    kd_wakeUpDependents;
951  }
952
953  // directory is blocked when sending exclusive data
954  transition({IS,IS_I}, Data_Exclusive, E) {
955    u_writeDataFromL2Response;
956    hh_xdata_to_l0;
957    jj_sendExclusiveUnblock;
958    s_deallocateTBE;
959    o_popL2ResponseQueue;
960    kd_wakeUpDependents;
961  }
962
963  // Transitions from IM
964  transition({IM,SM}, Inv, IM) {
965    fi_sendInvAck;
966    l_popL2RequestQueue;
967  }
968
969  transition(IM, Data, SM) {
970    u_writeDataFromL2Response;
971    q_updateAckCount;
972    o_popL2ResponseQueue;
973  }
974
975  transition(IM, Data_all_Acks, M) {
976    u_writeDataFromL2Response;
977    hh_xdata_to_l0;
978    jj_sendExclusiveUnblock;
979    s_deallocateTBE;
980    o_popL2ResponseQueue;
981    kd_wakeUpDependents;
982  }
983
984  transition({SM, IM}, Ack) {
985    q_updateAckCount;
986    o_popL2ResponseQueue;
987  }
988
989  transition(SM, Ack_all, M) {
990    jj_sendExclusiveUnblock;
991    hh_xdata_to_l0;
992    s_deallocateTBE;
993    o_popL2ResponseQueue;
994    kd_wakeUpDependents;
995  }
996
997  transition(SM, L0_Invalidate_Else, SM_IL0) {
998    forward_eviction_to_L0;
999  }
1000
1001  transition(SINK_WB_ACK, Inv){
1002    fi_sendInvAck;
1003    l_popL2RequestQueue;
1004  }
1005
1006  transition(SINK_WB_ACK, WB_Ack, I){
1007    s_deallocateTBE;
1008    o_popL2ResponseQueue;
1009    ff_deallocateCacheBlock;
1010    kd_wakeUpDependents;
1011  }
1012
1013  transition({M_IL0, E_IL0}, WriteBack, MM_IL0) {
1014    u_writeDataFromL0Request;
1015    k_popL0RequestQueue;
1016    kd_wakeUpDependents;
1017  }
1018
1019  transition({M_IL0, E_IL0}, L0_DataAck, MM) {
1020    u_writeDataFromL0Response;
1021    k_popL0RequestQueue;
1022    kd_wakeUpDependents;
1023  }
1024
1025  transition({M_IL0, MM_IL0}, L0_Ack, MM) {
1026    k_popL0RequestQueue;
1027    kd_wakeUpDependents;
1028  }
1029
1030  transition(E_IL0, L0_Ack, EE) {
1031    k_popL0RequestQueue;
1032    kd_wakeUpDependents;
1033  }
1034
1035  transition(S_IL0, L0_Ack, SS) {
1036    k_popL0RequestQueue;
1037    kd_wakeUpDependents;
1038  }
1039
1040  transition(SM_IL0, L0_Ack, IM) {
1041    k_popL0RequestQueue;
1042    kd_wakeUpDependents;
1043  }
1044
1045  transition({S_IL0, M_IL0, E_IL0, SM_IL0, SM}, L0_Invalidate_Own) {
1046    z0_stallAndWaitL0Queue;
1047  }
1048
1049  transition({S_IL0, M_IL0, E_IL0, SM_IL0}, L0_Invalidate_Else) {
1050    z2_stallAndWaitL2Queue;
1051  }
1052
1053  transition({S_IL0, M_IL0, E_IL0, MM_IL0}, {Inv, Fwd_GETX, Fwd_GETS}) {
1054    z2_stallAndWaitL2Queue;
1055  }
1056}
1057