1/*
2 * Copyright (c) 2010-2015 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * For use for simulation and test purposes only
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Authors: Lisa Hsu
34 */
35
36machine(MachineType:TCC, "TCC Cache")
37 : CacheMemory * L2cache;
38   WireBuffer * w_reqToTCCDir;
39   WireBuffer * w_respToTCCDir;
40   WireBuffer * w_TCCUnblockToTCCDir;
41   WireBuffer * w_reqToTCC;
42   WireBuffer * w_probeToTCC;
43   WireBuffer * w_respToTCC;
44   int TCC_select_num_bits;
45   Cycles l2_request_latency := 1;
46   Cycles l2_response_latency := 20;
47
48  // To the general response network
49  MessageBuffer * responseFromTCC, network="To", virtual_network="3", vnet_type="response";
50
51  // From the general response network
52  MessageBuffer * responseToTCC, network="From", virtual_network="3", vnet_type="response";
53
54{
55  // EVENTS
56  enumeration(Event, desc="TCC Events") {
57    // Requests coming from the Cores
58    RdBlk,                  desc="CPU RdBlk event";
59    RdBlkM,                 desc="CPU RdBlkM event";
60    RdBlkS,                 desc="CPU RdBlkS event";
61    CtoD,                   desc="Change to Dirty request";
62    WrVicBlk,               desc="L1 Victim (dirty)";
63    WrVicBlkShared,               desc="L1 Victim (dirty)";
64    ClVicBlk,               desc="L1 Victim (clean)";
65    ClVicBlkShared,               desc="L1 Victim (clean)";
66
67    CPUData,                      desc="WB data from CPU";
68    CPUDataShared,                desc="WB data from CPU, NBReqShared 1";
69    StaleWB,                desc="Stale WB, No data";
70
71    L2_Repl,             desc="L2 Replacement";
72
73    // Probes
74    PrbInvData,         desc="Invalidating probe, return dirty data";
75    PrbInv,             desc="Invalidating probe, no need to return data";
76    PrbShrData,         desc="Downgrading probe, return data";
77
78    // Coming from Memory Controller
79    WBAck,                     desc="ack from memory";
80
81    CancelWB,                   desc="Cancel WB from L2";
82  }
83
84  // STATES
85  state_declaration(State, desc="TCC State", default="TCC_State_I") {
86    M, AccessPermission:Read_Write, desc="Modified";  // No other cache has copy, memory stale
87    O, AccessPermission:Read_Only, desc="Owned";     // Correct most recent copy, others may exist in S
88    E, AccessPermission:Read_Write, desc="Exclusive"; // Correct, most recent, and only copy (and == Memory)
89    S, AccessPermission:Read_Only, desc="Shared";    // Correct, most recent. If no one in O, then == Memory
90    I, AccessPermission:Invalid, desc="Invalid";
91
92    I_M, AccessPermission:Busy, desc="Invalid, received WrVicBlk, sent Ack, waiting for Data";
93    I_O, AccessPermission:Busy, desc="Invalid, received WrVicBlk, sent Ack, waiting for Data";
94    I_E, AccessPermission:Busy, desc="Invalid, receive ClVicBlk, sent Ack, waiting for Data";
95    I_S, AccessPermission:Busy, desc="Invalid, receive ClVicBlk, sent Ack, waiting for Data";
96    S_M, AccessPermission:Busy, desc="received WrVicBlk, sent Ack, waiting for Data, then go to M";
97    S_O, AccessPermission:Busy, desc="received WrVicBlkShared, sent Ack, waiting for Data, then go to O";
98    S_E, AccessPermission:Busy, desc="Shared, received ClVicBlk, sent Ack, waiting for Data, then go to E";
99    S_S, AccessPermission:Busy, desc="Shared, received ClVicBlk, sent Ack, waiting for Data, then go to S";
100    E_M, AccessPermission:Busy, desc="received WrVicBlk, sent Ack, waiting for Data, then go to O";
101    E_O, AccessPermission:Busy, desc="received WrVicBlkShared, sent Ack, waiting for Data, then go to O";
102    E_E, AccessPermission:Busy, desc="received WrVicBlk, sent Ack, waiting for Data, then go to O";
103    E_S, AccessPermission:Busy, desc="Shared, received WrVicBlk, sent Ack, waiting for Data";
104    O_M, AccessPermission:Busy, desc="...";
105    O_O, AccessPermission:Busy, desc="...";
106    O_E, AccessPermission:Busy, desc="...";
107    M_M, AccessPermission:Busy, desc="...";
108    M_O, AccessPermission:Busy, desc="...";
109    M_E, AccessPermission:Busy, desc="...";
110    M_S, AccessPermission:Busy, desc="...";
111    D_I, AccessPermission:Invalid,  desc="drop WB data on the floor when receive";
112    MOD_I, AccessPermission:Busy, desc="drop WB data on the floor, waiting for WBAck from Mem";
113    MO_I, AccessPermission:Busy, desc="M or O, received L2_Repl, waiting for WBAck from Mem";
114    ES_I, AccessPermission:Busy, desc="E or S, received L2_Repl, waiting for WBAck from Mem";
115    I_C, AccessPermission:Invalid, desc="sent cancel, just waiting to receive mem wb ack so nothing gets confused";
116  }
117
118  enumeration(RequestType, desc="To communicate stats from transitions to recordStats") {
119    DataArrayRead,    desc="Read the data array";
120    DataArrayWrite,   desc="Write the data array";
121    TagArrayRead,     desc="Read the data array";
122    TagArrayWrite,    desc="Write the data array";
123  }
124
125
126  // STRUCTURES
127
128  structure(Entry, desc="...", interface="AbstractCacheEntry") {
129    State CacheState,           desc="cache state";
130    bool Dirty,                 desc="Is the data dirty (diff from memory?)";
131    DataBlock DataBlk,          desc="Data for the block";
132  }
133
134  structure(TBE, desc="...") {
135    State TBEState,     desc="Transient state";
136    DataBlock DataBlk,  desc="data for the block";
137    bool Dirty,         desc="Is the data dirty?";
138    bool Shared,        desc="Victim hit by shared probe";
139    MachineID From,     desc="Waiting for writeback from...";
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="<TCC_TBE>", constructor="m_number_of_TBEs";
150  int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()";
151
152  void set_cache_entry(AbstractCacheEntry b);
153  void unset_cache_entry();
154  void set_tbe(TBE b);
155  void unset_tbe();
156  void wakeUpAllBuffers();
157  void wakeUpBuffers(Addr a);
158
159
160  // FUNCTION DEFINITIONS
161  Tick clockEdge();
162  Tick cyclesToTicks(Cycles c);
163
164  Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
165    return static_cast(Entry, "pointer", L2cache.lookup(addr));
166  }
167
168  DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
169    return getCacheEntry(addr).DataBlk;
170  }
171
172  bool presentOrAvail(Addr addr) {
173    return L2cache.isTagPresent(addr) || L2cache.cacheAvail(addr);
174  }
175
176  State getState(TBE tbe, Entry cache_entry, Addr addr) {
177    if (is_valid(tbe)) {
178      return tbe.TBEState;
179    } else if (is_valid(cache_entry)) {
180      return cache_entry.CacheState;
181    }
182    return State:I;
183  }
184
185  void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
186    if (is_valid(tbe)) {
187        tbe.TBEState := state;
188    }
189
190    if (is_valid(cache_entry)) {
191        cache_entry.CacheState := state;
192    }
193  }
194
195  AccessPermission getAccessPermission(Addr addr) {
196    TBE tbe := TBEs.lookup(addr);
197    if(is_valid(tbe)) {
198      return TCC_State_to_permission(tbe.TBEState);
199    }
200
201    Entry cache_entry := getCacheEntry(addr);
202    if(is_valid(cache_entry)) {
203      return TCC_State_to_permission(cache_entry.CacheState);
204    }
205
206    return AccessPermission:NotPresent;
207  }
208
209  void setAccessPermission(Entry cache_entry, Addr addr, State state) {
210    if (is_valid(cache_entry)) {
211      cache_entry.changePermission(TCC_State_to_permission(state));
212    }
213  }
214
215  void functionalRead(Addr addr, Packet *pkt) {
216    TBE tbe := TBEs.lookup(addr);
217    if(is_valid(tbe)) {
218      testAndRead(addr, tbe.DataBlk, pkt);
219    } else {
220      functionalMemoryRead(pkt);
221    }
222  }
223
224  int functionalWrite(Addr addr, Packet *pkt) {
225    int num_functional_writes := 0;
226
227    TBE tbe := TBEs.lookup(addr);
228    if(is_valid(tbe)) {
229      num_functional_writes := num_functional_writes +
230            testAndWrite(addr, tbe.DataBlk, pkt);
231    }
232
233    num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
234    return num_functional_writes;
235  }
236
237  void recordRequestType(RequestType request_type, Addr addr) {
238    if (request_type == RequestType:DataArrayRead) {
239        L2cache.recordRequestType(CacheRequestType:DataArrayRead, addr);
240    } else if (request_type == RequestType:DataArrayWrite) {
241        L2cache.recordRequestType(CacheRequestType:DataArrayWrite, addr);
242    } else if (request_type == RequestType:TagArrayRead) {
243        L2cache.recordRequestType(CacheRequestType:TagArrayRead, addr);
244    } else if (request_type == RequestType:TagArrayWrite) {
245        L2cache.recordRequestType(CacheRequestType:TagArrayWrite, addr);
246    }
247  }
248
249  bool checkResourceAvailable(RequestType request_type, Addr addr) {
250    if (request_type == RequestType:DataArrayRead) {
251      return L2cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
252    } else if (request_type == RequestType:DataArrayWrite) {
253      return L2cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
254    } else if (request_type == RequestType:TagArrayRead) {
255      return L2cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
256    } else if (request_type == RequestType:TagArrayWrite) {
257      return L2cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
258    } else {
259      error("Invalid RequestType type in checkResourceAvailable");
260      return true;
261    }
262  }
263
264
265
266  // OUT PORTS
267  out_port(w_requestNetwork_out, CPURequestMsg, w_reqToTCCDir);
268  out_port(w_TCCResp_out, ResponseMsg, w_respToTCCDir);
269  out_port(responseNetwork_out, ResponseMsg, responseFromTCC);
270  out_port(w_unblockNetwork_out, UnblockMsg, w_TCCUnblockToTCCDir);
271
272  // IN PORTS
273  in_port(TDResponse_in, ResponseMsg, w_respToTCC) {
274    if (TDResponse_in.isReady(clockEdge())) {
275      peek(TDResponse_in, ResponseMsg) {
276        Entry cache_entry := getCacheEntry(in_msg.addr);
277        TBE tbe := TBEs.lookup(in_msg.addr);
278        if (in_msg.Type == CoherenceResponseType:TDSysWBAck) {
279          trigger(Event:WBAck, in_msg.addr, cache_entry, tbe);
280        }
281        else {
282          DPRINTF(RubySlicc, "%s\n", in_msg);
283          error("Error on TDResponse Type");
284        }
285      }
286    }
287  }
288
289  // Response Network
290  in_port(responseNetwork_in, ResponseMsg, responseToTCC) {
291    if (responseNetwork_in.isReady(clockEdge())) {
292      peek(responseNetwork_in, ResponseMsg) {
293        Entry cache_entry := getCacheEntry(in_msg.addr);
294        TBE tbe := TBEs.lookup(in_msg.addr);
295        if (in_msg.Type == CoherenceResponseType:CPUData) {
296          if (in_msg.NbReqShared) {
297            trigger(Event:CPUDataShared, in_msg.addr, cache_entry, tbe);
298          } else {
299            trigger(Event:CPUData, in_msg.addr, cache_entry, tbe);
300          }
301        } else if (in_msg.Type == CoherenceResponseType:StaleNotif) {
302            trigger(Event:StaleWB, in_msg.addr, cache_entry, tbe);
303        } else {
304          DPRINTF(RubySlicc, "%s\n", in_msg);
305          error("Error on TDResponse Type");
306        }
307      }
308    }
309  }
310
311  // probe network
312  in_port(probeNetwork_in, TDProbeRequestMsg, w_probeToTCC) {
313    if (probeNetwork_in.isReady(clockEdge())) {
314      peek(probeNetwork_in, TDProbeRequestMsg) {
315        Entry cache_entry := getCacheEntry(in_msg.addr);
316        TBE tbe := TBEs.lookup(in_msg.addr);
317        if (in_msg.Type == ProbeRequestType:PrbInv) {
318          if (in_msg.ReturnData) {
319            trigger(Event:PrbInvData, in_msg.addr, cache_entry, tbe);
320          } else {
321            trigger(Event:PrbInv, in_msg.addr, cache_entry, tbe);
322          }
323        } else if (in_msg.Type == ProbeRequestType:PrbDowngrade) {
324          if (in_msg.ReturnData) {
325            trigger(Event:PrbShrData, in_msg.addr, cache_entry, tbe);
326          } else {
327            error("Don't think I should get any of these");
328          }
329        }
330      }
331    }
332  }
333
334  // Request Network
335  in_port(requestNetwork_in, CPURequestMsg, w_reqToTCC) {
336    if (requestNetwork_in.isReady(clockEdge())) {
337      peek(requestNetwork_in, CPURequestMsg) {
338        assert(in_msg.Destination.isElement(machineID));
339        Entry cache_entry := getCacheEntry(in_msg.addr);
340        TBE tbe := TBEs.lookup(in_msg.addr);
341        if (in_msg.Type == CoherenceRequestType:RdBlk) {
342          trigger(Event:RdBlk, in_msg.addr, cache_entry, tbe);
343        } else if (in_msg.Type == CoherenceRequestType:RdBlkS) {
344          trigger(Event:RdBlkS, in_msg.addr, cache_entry, tbe);
345        } else if (in_msg.Type == CoherenceRequestType:RdBlkM) {
346          trigger(Event:RdBlkM, in_msg.addr, cache_entry, tbe);
347        } else if (in_msg.Type == CoherenceRequestType:VicClean) {
348          if (presentOrAvail(in_msg.addr)) {
349            if (in_msg.Shared) {
350              trigger(Event:ClVicBlkShared, in_msg.addr, cache_entry, tbe);
351            } else {
352              trigger(Event:ClVicBlk, in_msg.addr, cache_entry, tbe);
353            }
354          } else {
355            Addr victim :=  L2cache.cacheProbe(in_msg.addr);
356            trigger(Event:L2_Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
357          }
358        } else if (in_msg.Type == CoherenceRequestType:VicDirty) {
359          if (presentOrAvail(in_msg.addr)) {
360            if (in_msg.Shared) {
361              trigger(Event:WrVicBlkShared, in_msg.addr, cache_entry, tbe);
362            } else {
363              trigger(Event:WrVicBlk, in_msg.addr, cache_entry, tbe);
364            }
365          } else {
366            Addr victim := L2cache.cacheProbe(in_msg.addr);
367            trigger(Event:L2_Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
368          }
369        } else {
370            requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
371        }
372      }
373    }
374  }
375
376  // BEGIN ACTIONS
377
378  action(i_invL2, "i", desc="invalidate TCC cache block") {
379    if (is_valid(cache_entry)) {
380        L2cache.deallocate(address);
381    }
382    unset_cache_entry();
383  }
384
385  action(rm_sendResponseM, "rm", desc="send Modified response") {
386    peek(requestNetwork_in, CPURequestMsg) {
387      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
388        out_msg.addr := address;
389        out_msg.Type := CoherenceResponseType:TDSysResp;
390        out_msg.Sender := machineID;
391        out_msg.Destination.add(in_msg.Requestor);
392        out_msg.DataBlk := cache_entry.DataBlk;
393        out_msg.MessageSize := MessageSizeType:Response_Data;
394        out_msg.Dirty := cache_entry.Dirty;
395        out_msg.State := CoherenceState:Modified;
396        DPRINTF(RubySlicc, "%s\n", out_msg);
397      }
398    }
399  }
400
401  action(rs_sendResponseS, "rs", desc="send Shared response") {
402    peek(requestNetwork_in, CPURequestMsg) {
403      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
404        out_msg.addr := address;
405        out_msg.Type := CoherenceResponseType:TDSysResp;
406        out_msg.Sender := machineID;
407        out_msg.Destination.add(in_msg.Requestor);
408        out_msg.DataBlk := cache_entry.DataBlk;
409        out_msg.MessageSize := MessageSizeType:Response_Data;
410        out_msg.Dirty := cache_entry.Dirty;
411        out_msg.State := CoherenceState:Shared;
412        DPRINTF(RubySlicc, "%s\n", out_msg);
413      }
414    }
415  }
416
417
418  action(r_requestToTD, "r", desc="Miss in L2, pass on") {
419    peek(requestNetwork_in, CPURequestMsg) {
420      enqueue(w_requestNetwork_out, CPURequestMsg, l2_request_latency) {
421        out_msg.addr := address;
422        out_msg.Type := in_msg.Type;
423        out_msg.Requestor := in_msg.Requestor;
424        out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
425                                TCC_select_low_bit, TCC_select_num_bits));
426        out_msg.Shared := false; // unneeded for this request
427        out_msg.MessageSize := in_msg.MessageSize;
428        DPRINTF(RubySlicc, "%s\n", out_msg);
429      }
430    }
431  }
432
433  action(t_allocateTBE, "t", desc="allocate TBE Entry") {
434    TBEs.allocate(address);
435    set_tbe(TBEs.lookup(address));
436    if (is_valid(cache_entry)) {
437      tbe.DataBlk := cache_entry.DataBlk; // Data only for WBs
438      tbe.Dirty := cache_entry.Dirty;
439    }
440    tbe.From := machineID;
441  }
442
443  action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") {
444    TBEs.deallocate(address);
445    unset_tbe();
446  }
447
448  action(vc_vicClean, "vc", desc="Victimize Clean L2 data") {
449    enqueue(w_requestNetwork_out, CPURequestMsg, l2_request_latency) {
450      out_msg.addr := address;
451      out_msg.Type := CoherenceRequestType:VicClean;
452      out_msg.Requestor := machineID;
453      out_msg.DataBlk := cache_entry.DataBlk;
454      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
455                              TCC_select_low_bit, TCC_select_num_bits));
456      out_msg.MessageSize := MessageSizeType:Response_Data;
457    }
458  }
459
460  action(vd_vicDirty, "vd", desc="Victimize dirty L2 data") {
461    enqueue(w_requestNetwork_out, CPURequestMsg, l2_request_latency) {
462      out_msg.addr := address;
463      out_msg.Type := CoherenceRequestType:VicDirty;
464      out_msg.Requestor := machineID;
465      out_msg.DataBlk := cache_entry.DataBlk;
466      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
467                              TCC_select_low_bit, TCC_select_num_bits));
468      out_msg.MessageSize := MessageSizeType:Response_Data;
469    }
470  }
471
472  action(w_sendResponseWBAck, "w", desc="send WB Ack") {
473    peek(requestNetwork_in, CPURequestMsg) {
474      enqueue(responseNetwork_out, ResponseMsg, l2_response_latency) {
475        out_msg.addr := address;
476        out_msg.Type := CoherenceResponseType:TDSysWBAck;
477        out_msg.Destination.add(in_msg.Requestor);
478        out_msg.Sender := machineID;
479        out_msg.MessageSize := MessageSizeType:Writeback_Control;
480      }
481    }
482  }
483
484  action(pi_sendProbeResponseInv, "pi", desc="send probe ack inv, no data") {
485    enqueue(w_TCCResp_out, ResponseMsg, l2_request_latency) {
486      out_msg.addr := address;
487      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // TCC and CPUs respond in same way to probes
488      out_msg.Sender := machineID;
489      // will this always be ok? probably not for multisocket
490      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
491                              TCC_select_low_bit, TCC_select_num_bits));
492      out_msg.Dirty := false;
493      out_msg.Hit := false;
494      out_msg.Ntsl := true;
495      out_msg.State := CoherenceState:NA;
496      out_msg.MessageSize := MessageSizeType:Response_Control;
497    }
498  }
499
500  action(ph_sendProbeResponseHit, "ph", desc="send probe ack, no data") {
501    enqueue(w_TCCResp_out, ResponseMsg, l2_request_latency) {
502      out_msg.addr := address;
503      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // TCC and CPUs respond in same way to probes
504      out_msg.Sender := machineID;
505      // will this always be ok? probably not for multisocket
506      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
507                              TCC_select_low_bit, TCC_select_num_bits));
508      out_msg.Dirty := false;
509      out_msg.Hit := true;
510      out_msg.Ntsl := false;
511      out_msg.State := CoherenceState:NA;
512      out_msg.MessageSize := MessageSizeType:Response_Control;
513    }
514  }
515
516  action(pm_sendProbeResponseMiss, "pm", desc="send probe ack, no data") {
517    enqueue(w_TCCResp_out, ResponseMsg, l2_request_latency) {
518      out_msg.addr := address;
519      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // TCC and CPUs respond in same way to probes
520      out_msg.Sender := machineID;
521      // will this always be ok? probably not for multisocket
522      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
523                              TCC_select_low_bit, TCC_select_num_bits));
524      out_msg.Dirty := false;
525      out_msg.Hit := false;
526      out_msg.Ntsl := false;
527      out_msg.State := CoherenceState:NA;
528      out_msg.MessageSize := MessageSizeType:Response_Control;
529    }
530  }
531
532  action(pd_sendProbeResponseData, "pd", desc="send probe ack, with data") {
533    enqueue(w_TCCResp_out, ResponseMsg, l2_request_latency) {
534      out_msg.addr := address;
535      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // TCC and CPUs respond in same way to probes
536      out_msg.Sender := machineID;
537      // will this always be ok? probably not for multisocket
538      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
539                              TCC_select_low_bit, TCC_select_num_bits));
540      out_msg.DataBlk := cache_entry.DataBlk;
541      //assert(cache_entry.Dirty); Not needed in TCC where TCC can supply clean data
542      out_msg.Dirty := cache_entry.Dirty;
543      out_msg.Hit := true;
544      out_msg.State := CoherenceState:NA;
545      out_msg.MessageSize := MessageSizeType:Response_Data;
546    }
547  }
548
549  action(pdt_sendProbeResponseDataFromTBE, "pdt", desc="send probe ack with data") {
550    enqueue(w_TCCResp_out, ResponseMsg, l2_request_latency) {
551      out_msg.addr := address;
552      out_msg.Type := CoherenceResponseType:CPUPrbResp;
553      out_msg.Sender := machineID;
554      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
555                              TCC_select_low_bit, TCC_select_num_bits));
556      out_msg.DataBlk := tbe.DataBlk;
557      //assert(tbe.Dirty);
558      out_msg.Dirty := tbe.Dirty;
559      out_msg.Hit := true;
560      out_msg.MessageSize := MessageSizeType:Response_Data;
561      out_msg.State := CoherenceState:NA;
562      DPRINTF(RubySlicc, "%s\n", out_msg);
563    }
564  }
565
566  action(mc_cancelMemWriteback, "mc", desc="send writeback cancel to memory") {
567    enqueue(w_requestNetwork_out, CPURequestMsg, l2_request_latency) {
568      out_msg.addr := address;
569      out_msg.Type := CoherenceRequestType:WrCancel;
570      out_msg.Requestor := machineID;
571      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
572                              TCC_select_low_bit, TCC_select_num_bits));
573      out_msg.MessageSize := MessageSizeType:Request_Control;
574    }
575  }
576
577  action(a_allocateBlock, "a", desc="allocate TCC block") {
578    if (is_invalid(cache_entry)) {
579      set_cache_entry(L2cache.allocate(address, new Entry));
580    }
581  }
582
583  action(d_writeData, "d", desc="write data to TCC") {
584    peek(responseNetwork_in, ResponseMsg) {
585      if (in_msg.Dirty) {
586        cache_entry.Dirty := in_msg.Dirty;
587      }
588      cache_entry.DataBlk := in_msg.DataBlk;
589      DPRINTF(RubySlicc, "Writing to TCC: %s\n", in_msg);
590    }
591  }
592
593  action(rd_copyDataFromRequest, "rd", desc="write data to TCC") {
594    peek(requestNetwork_in, CPURequestMsg) {
595      cache_entry.DataBlk := in_msg.DataBlk;
596      cache_entry.Dirty := true;
597    }
598  }
599
600  action(f_setFrom, "f", desc="set who WB is expected to come from") {
601    peek(requestNetwork_in, CPURequestMsg) {
602      tbe.From := in_msg.Requestor;
603    }
604  }
605
606  action(rf_resetFrom, "rf", desc="reset From") {
607    tbe.From := machineID;
608  }
609
610  action(wb_data, "wb", desc="write back data") {
611    enqueue(w_TCCResp_out, ResponseMsg, l2_request_latency) {
612      out_msg.addr := address;
613      out_msg.Type := CoherenceResponseType:CPUData;
614      out_msg.Sender := machineID;
615      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
616                              TCC_select_low_bit, TCC_select_num_bits));
617      out_msg.DataBlk := tbe.DataBlk;
618      out_msg.Dirty := tbe.Dirty;
619      if (tbe.Shared) {
620        out_msg.NbReqShared := true;
621      } else {
622        out_msg.NbReqShared := false;
623      }
624      out_msg.State := CoherenceState:Shared; // faux info
625      out_msg.MessageSize := MessageSizeType:Writeback_Data;
626      DPRINTF(RubySlicc, "%s\n", out_msg);
627    }
628  }
629
630  action(wt_writeDataToTBE, "wt", desc="write WB data to TBE") {
631    peek(responseNetwork_in, ResponseMsg) {
632      tbe.DataBlk := in_msg.DataBlk;
633      tbe.Dirty := in_msg.Dirty;
634    }
635  }
636
637  action(uo_sendUnblockOwner, "uo", desc="state changed to E, M, or O, unblock") {
638    enqueue(w_unblockNetwork_out, UnblockMsg, l2_request_latency) {
639      out_msg.addr := address;
640      out_msg.Sender := machineID;
641      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
642                              TCC_select_low_bit, TCC_select_num_bits));
643      out_msg.MessageSize := MessageSizeType:Unblock_Control;
644      out_msg.currentOwner := true;
645      out_msg.valid := true;
646      DPRINTF(RubySlicc, "%s\n", out_msg);
647    }
648  }
649
650  action(us_sendUnblockSharer, "us", desc="state changed to S , unblock") {
651    enqueue(w_unblockNetwork_out, UnblockMsg, l2_request_latency) {
652      out_msg.addr := address;
653      out_msg.Sender := machineID;
654      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
655                              TCC_select_low_bit, TCC_select_num_bits));
656      out_msg.MessageSize := MessageSizeType:Unblock_Control;
657      out_msg.currentOwner := false;
658      out_msg.valid := true;
659      DPRINTF(RubySlicc, "%s\n", out_msg);
660    }
661  }
662
663  action(un_sendUnblockNotValid, "un", desc="state changed toI, unblock") {
664    enqueue(w_unblockNetwork_out, UnblockMsg, l2_request_latency) {
665      out_msg.addr := address;
666      out_msg.Sender := machineID;
667      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
668                              TCC_select_low_bit, TCC_select_num_bits));
669      out_msg.MessageSize := MessageSizeType:Unblock_Control;
670      out_msg.currentOwner := false;
671      out_msg.valid := false;
672      DPRINTF(RubySlicc, "%s\n", out_msg);
673    }
674  }
675
676  action(ut_updateTag, "ut", desc="update Tag (i.e. set MRU)") {
677    L2cache.setMRU(address);
678  }
679
680  action(p_popRequestQueue, "p", desc="pop request queue") {
681    requestNetwork_in.dequeue(clockEdge());
682  }
683
684  action(pr_popResponseQueue, "pr", desc="pop response queue") {
685    responseNetwork_in.dequeue(clockEdge());
686  }
687
688  action(pn_popTDResponseQueue, "pn", desc="pop TD response queue") {
689    TDResponse_in.dequeue(clockEdge());
690  }
691
692  action(pp_popProbeQueue, "pp", desc="pop probe queue") {
693    probeNetwork_in.dequeue(clockEdge());
694  }
695
696  action(zz_recycleRequestQueue, "\z", desc="recycle request queue") {
697    requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
698  }
699
700
701  // END ACTIONS
702
703  // BEGIN TRANSITIONS
704
705  // transitions from base
706
707  transition({I, I_C}, {RdBlk, RdBlkS, RdBlkM, CtoD}){TagArrayRead} {
708    // TCCdir already knows that the block is not here. This is to allocate and get the block.
709    r_requestToTD;
710    p_popRequestQueue;
711  }
712
713// check
714  transition({M, O}, RdBlk, O){TagArrayRead, TagArrayWrite} {
715    rs_sendResponseS;
716    ut_updateTag;
717    // detect 2nd chancing
718    p_popRequestQueue;
719  }
720
721//check
722  transition({E, S}, RdBlk, S){TagArrayRead, TagArrayWrite} {
723    rs_sendResponseS;
724    ut_updateTag;
725    // detect 2nd chancing
726    p_popRequestQueue;
727  }
728
729// check
730  transition({M, O}, RdBlkS, O){TagArrayRead, TagArrayWrite} {
731    rs_sendResponseS;
732    ut_updateTag;
733    // detect 2nd chance sharing
734    p_popRequestQueue;
735  }
736
737//check
738  transition({E, S}, RdBlkS, S){TagArrayRead, TagArrayWrite} {
739    rs_sendResponseS;
740    ut_updateTag;
741    // detect 2nd chance sharing
742    p_popRequestQueue;
743  }
744
745// check
746  transition(M, RdBlkM, I){TagArrayRead, TagArrayWrite} {
747    rm_sendResponseM;
748    i_invL2;
749    p_popRequestQueue;
750  }
751
752  //check
753  transition(E, RdBlkM, I){TagArrayRead, TagArrayWrite} {
754    rm_sendResponseM;
755    i_invL2;
756    p_popRequestQueue;
757  }
758
759// check
760  transition({I}, WrVicBlk, I_M){TagArrayRead} {
761    a_allocateBlock;
762    t_allocateTBE;
763    f_setFrom;
764    w_sendResponseWBAck;
765    p_popRequestQueue;
766  }
767
768  transition(I_C, {WrVicBlk, WrVicBlkShared, ClVicBlk, ClVicBlkShared}) {
769    zz_recycleRequestQueue;
770  }
771
772//check
773  transition({I}, WrVicBlkShared, I_O) {TagArrayRead}{
774    a_allocateBlock;
775    t_allocateTBE;
776    f_setFrom;
777//    rd_copyDataFromRequest;
778    w_sendResponseWBAck;
779    p_popRequestQueue;
780  }
781
782//check
783  transition(S, WrVicBlkShared, S_O){TagArrayRead} {
784    t_allocateTBE;
785    f_setFrom;
786    w_sendResponseWBAck;
787    p_popRequestQueue;
788  }
789
790// a stale writeback
791 transition(S, WrVicBlk, S_S){TagArrayRead} {
792   t_allocateTBE;
793   f_setFrom;
794   w_sendResponseWBAck;
795   p_popRequestQueue;
796 }
797
798// a stale writeback
799  transition(E, WrVicBlk, E_E){TagArrayRead} {
800    t_allocateTBE;
801    f_setFrom;
802    w_sendResponseWBAck;
803    p_popRequestQueue;
804  }
805
806// a stale writeback
807  transition(E, WrVicBlkShared, E_E){TagArrayRead} {
808    t_allocateTBE;
809    f_setFrom;
810    w_sendResponseWBAck;
811    p_popRequestQueue;
812  }
813
814// a stale writeback
815  transition(O, WrVicBlk, O_O){TagArrayRead} {
816    t_allocateTBE;
817    f_setFrom;
818    w_sendResponseWBAck;
819    p_popRequestQueue;
820  }
821
822// a stale writeback
823 transition(O, WrVicBlkShared, O_O){TagArrayRead} {
824   t_allocateTBE;
825   f_setFrom;
826   w_sendResponseWBAck;
827   p_popRequestQueue;
828 }
829
830// a stale writeback
831  transition(M, WrVicBlk, M_M){TagArrayRead} {
832    t_allocateTBE;
833    f_setFrom;
834    w_sendResponseWBAck;
835    p_popRequestQueue;
836  }
837
838// a stale writeback
839  transition(M, WrVicBlkShared, M_O){TagArrayRead} {
840    t_allocateTBE;
841    f_setFrom;
842    w_sendResponseWBAck;
843    p_popRequestQueue;
844  }
845
846//check
847  transition({I}, ClVicBlk, I_E){TagArrayRead} {
848    t_allocateTBE;
849    f_setFrom;
850    a_allocateBlock;
851    w_sendResponseWBAck;
852    p_popRequestQueue;
853  }
854
855  transition({I}, ClVicBlkShared, I_S){TagArrayRead} {
856    t_allocateTBE;
857    f_setFrom;
858    a_allocateBlock;
859    w_sendResponseWBAck;
860    p_popRequestQueue;
861  }
862
863//check
864  transition(S, ClVicBlkShared, S_S){TagArrayRead} {
865    t_allocateTBE;
866    f_setFrom;
867    w_sendResponseWBAck;
868    p_popRequestQueue;
869  }
870
871// a stale writeback
872  transition(E, ClVicBlk, E_E){TagArrayRead} {
873    t_allocateTBE;
874    f_setFrom;
875    w_sendResponseWBAck;
876    p_popRequestQueue;
877  }
878
879// a stale writeback
880  transition(E, ClVicBlkShared, E_S){TagArrayRead} {
881    t_allocateTBE;
882    f_setFrom;
883    w_sendResponseWBAck;
884    p_popRequestQueue;
885  }
886
887// a stale writeback
888 transition(O, ClVicBlk, O_O){TagArrayRead} {
889   t_allocateTBE;
890   f_setFrom;
891   w_sendResponseWBAck;
892   p_popRequestQueue;
893 }
894
895// check. Original L3 ahd it going from O to O_S. Something can go from O to S only on writeback.
896  transition(O, ClVicBlkShared, O_O){TagArrayRead} {
897    t_allocateTBE;
898    f_setFrom;
899    w_sendResponseWBAck;
900    p_popRequestQueue;
901  }
902
903// a stale writeback
904 transition(M, ClVicBlk, M_E){TagArrayRead} {
905   t_allocateTBE;
906   f_setFrom;
907   w_sendResponseWBAck;
908   p_popRequestQueue;
909 }
910
911// a stale writeback
912 transition(M, ClVicBlkShared, M_S){TagArrayRead} {
913   t_allocateTBE;
914   f_setFrom;
915   w_sendResponseWBAck;
916   p_popRequestQueue;
917 }
918
919
920  transition({MO_I}, {RdBlk, RdBlkS, RdBlkM, CtoD}) {
921    a_allocateBlock;
922    t_allocateTBE;
923    f_setFrom;
924    r_requestToTD;
925    p_popRequestQueue;
926  }
927
928  transition(MO_I, {WrVicBlkShared, WrVicBlk, ClVicBlk, ClVicBlkShared}, MOD_I) {
929    f_setFrom;
930    w_sendResponseWBAck;
931    p_popRequestQueue;
932  }
933
934  transition(I_M, CPUData, M){TagArrayWrite} {
935    uo_sendUnblockOwner;
936    dt_deallocateTBE;
937    d_writeData;
938    pr_popResponseQueue;
939  }
940
941  transition(I_M, CPUDataShared, O){TagArrayWrite, DataArrayWrite} {
942    uo_sendUnblockOwner;
943    dt_deallocateTBE;
944    d_writeData;
945    pr_popResponseQueue;
946  }
947
948  transition(I_O, {CPUData, CPUDataShared}, O){TagArrayWrite, DataArrayWrite}  {
949    uo_sendUnblockOwner;
950    dt_deallocateTBE;
951    d_writeData;
952    pr_popResponseQueue;
953  }
954
955  transition(I_E, CPUData, E){TagArrayWrite, DataArrayWrite}  {
956    uo_sendUnblockOwner;
957    dt_deallocateTBE;
958    d_writeData;
959    pr_popResponseQueue;
960  }
961
962  transition(I_E, CPUDataShared, S){TagArrayWrite, DataArrayWrite}  {
963    us_sendUnblockSharer;
964    dt_deallocateTBE;
965    d_writeData;
966    pr_popResponseQueue;
967  }
968
969  transition(I_S, {CPUData, CPUDataShared}, S){TagArrayWrite, DataArrayWrite}  {
970    us_sendUnblockSharer;
971    dt_deallocateTBE;
972    d_writeData;
973    pr_popResponseQueue;
974  }
975
976  transition(S_M, CPUDataShared, O){TagArrayWrite, DataArrayWrite}  {
977    uo_sendUnblockOwner;
978    dt_deallocateTBE;
979    d_writeData;
980    ut_updateTag;  // update tag on writeback hits.
981    pr_popResponseQueue;
982  }
983
984  transition(S_O, {CPUData, CPUDataShared}, O){TagArrayWrite, DataArrayWrite}  {
985    uo_sendUnblockOwner;
986    dt_deallocateTBE;
987    d_writeData;
988    ut_updateTag;  // update tag on writeback hits.
989    pr_popResponseQueue;
990  }
991
992  transition(S_E, CPUDataShared, S){TagArrayWrite, DataArrayWrite}  {
993    us_sendUnblockSharer;
994    dt_deallocateTBE;
995    d_writeData;
996    ut_updateTag;  // update tag on writeback hits.
997    pr_popResponseQueue;
998  }
999
1000  transition(S_S, {CPUData, CPUDataShared}, S){TagArrayWrite, DataArrayWrite}  {
1001    us_sendUnblockSharer;
1002    dt_deallocateTBE;
1003    d_writeData;
1004    ut_updateTag;  // update tag on writeback hits.
1005    pr_popResponseQueue;
1006  }
1007
1008  transition(O_E, CPUDataShared, O){TagArrayWrite, DataArrayWrite}  {
1009    uo_sendUnblockOwner;
1010    dt_deallocateTBE;
1011    d_writeData;
1012    ut_updateTag;  // update tag on writeback hits.
1013    pr_popResponseQueue;
1014  }
1015
1016  transition(O_O, {CPUData, CPUDataShared}, O){TagArrayWrite, DataArrayWrite}  {
1017    uo_sendUnblockOwner;
1018    dt_deallocateTBE;
1019    d_writeData;
1020    ut_updateTag;  // update tag on writeback hits.
1021    pr_popResponseQueue;
1022  }
1023
1024  transition({D_I}, {CPUData, CPUDataShared}, I){TagArrayWrite}  {
1025    un_sendUnblockNotValid;
1026    dt_deallocateTBE;
1027    pr_popResponseQueue;
1028  }
1029
1030  transition(MOD_I, {CPUData, CPUDataShared}, MO_I) {
1031    un_sendUnblockNotValid;
1032    rf_resetFrom;
1033    pr_popResponseQueue;
1034  }
1035
1036  transition({O,S,I}, CPUData) {
1037    pr_popResponseQueue;
1038  }
1039
1040  transition({M, O}, L2_Repl, MO_I){TagArrayRead, DataArrayRead} {
1041    t_allocateTBE;
1042    vd_vicDirty;
1043    i_invL2;
1044  }
1045
1046  transition({E, S,}, L2_Repl, ES_I){TagArrayRead, DataArrayRead} {
1047    t_allocateTBE;
1048    vc_vicClean;
1049    i_invL2;
1050  }
1051
1052  transition({I_M, I_O, S_M, S_O, E_M, E_O}, L2_Repl) {
1053    zz_recycleRequestQueue;
1054  }
1055
1056  transition({O_M, O_O, O_E, M_M, M_O, M_E, M_S}, L2_Repl) {
1057    zz_recycleRequestQueue;
1058  }
1059
1060  transition({I_E, I_S, S_E, S_S, E_E, E_S}, L2_Repl) {
1061    zz_recycleRequestQueue;
1062  }
1063
1064  transition({M, O}, PrbInvData, I){TagArrayRead, TagArrayWrite} {
1065    pd_sendProbeResponseData;
1066    i_invL2;
1067    pp_popProbeQueue;
1068  }
1069
1070  transition(I, PrbInvData){TagArrayRead, TagArrayWrite}  {
1071    pi_sendProbeResponseInv;
1072    pp_popProbeQueue;
1073  }
1074
1075  transition({E, S}, PrbInvData, I){TagArrayRead, TagArrayWrite}  {
1076    pd_sendProbeResponseData;
1077    i_invL2;
1078    pp_popProbeQueue;
1079  }
1080
1081  transition({M, O, E, S, I}, PrbInv, I){TagArrayRead, TagArrayWrite}  {
1082    pi_sendProbeResponseInv;
1083    i_invL2; // nothing will happen in I
1084    pp_popProbeQueue;
1085  }
1086
1087  transition({M, O}, PrbShrData, O){TagArrayRead, TagArrayWrite}  {
1088    pd_sendProbeResponseData;
1089    pp_popProbeQueue;
1090  }
1091
1092  transition({E, S}, PrbShrData, S){TagArrayRead, TagArrayWrite}  {
1093    pd_sendProbeResponseData;
1094    pp_popProbeQueue;
1095  }
1096
1097  transition(I, PrbShrData){TagArrayRead}  {
1098    pm_sendProbeResponseMiss;
1099    pp_popProbeQueue;
1100  }
1101
1102  transition(MO_I, PrbInvData, I_C) {
1103    pdt_sendProbeResponseDataFromTBE;
1104    pp_popProbeQueue;
1105  }
1106
1107  transition(ES_I, PrbInvData, I_C) {
1108    pi_sendProbeResponseInv;
1109    pp_popProbeQueue;
1110  }
1111
1112  transition({ES_I,MO_I}, PrbInv, I_C) {
1113    pi_sendProbeResponseInv;
1114    pp_popProbeQueue;
1115  }
1116
1117  transition({ES_I, MO_I}, PrbShrData) {
1118    pdt_sendProbeResponseDataFromTBE;
1119    pp_popProbeQueue;
1120  }
1121
1122  transition(I_C, {PrbInvData, PrbInv}) {
1123    pi_sendProbeResponseInv;
1124    pp_popProbeQueue;
1125  }
1126
1127  transition(I_C, PrbShrData) {
1128    pm_sendProbeResponseMiss;
1129    pp_popProbeQueue;
1130  }
1131
1132  transition(MOD_I, WBAck, D_I) {
1133    pn_popTDResponseQueue;
1134  }
1135
1136  transition(MO_I, WBAck, I){TagArrayWrite} {
1137    dt_deallocateTBE;
1138    pn_popTDResponseQueue;
1139  }
1140
1141  // this can only be a spurious CPUData from a shared block.
1142  transition(MO_I, CPUData) {
1143    pr_popResponseQueue;
1144  }
1145
1146  transition(ES_I, WBAck, I){TagArrayWrite} {
1147    dt_deallocateTBE;
1148    pn_popTDResponseQueue;
1149  }
1150
1151  transition(I_C, {WBAck}, I){TagArrayWrite} {
1152    dt_deallocateTBE;
1153    pn_popTDResponseQueue;
1154  }
1155
1156  transition({I_M, I_O, I_E, I_S}, StaleWB, I){TagArrayWrite} {
1157    un_sendUnblockNotValid;
1158    dt_deallocateTBE;
1159    i_invL2;
1160    pr_popResponseQueue;
1161  }
1162
1163  transition({S_S, S_O, S_M, S_E}, StaleWB, S){TagArrayWrite} {
1164    us_sendUnblockSharer;
1165    dt_deallocateTBE;
1166    pr_popResponseQueue;
1167  }
1168
1169  transition({E_M, E_O, E_E, E_S}, StaleWB, E){TagArrayWrite} {
1170    uo_sendUnblockOwner;
1171    dt_deallocateTBE;
1172    pr_popResponseQueue;
1173  }
1174
1175  transition({O_M, O_O, O_E}, StaleWB, O){TagArrayWrite} {
1176    uo_sendUnblockOwner;
1177    dt_deallocateTBE;
1178    pr_popResponseQueue;
1179  }
1180
1181  transition({M_M, M_O, M_E, M_S}, StaleWB, M){TagArrayWrite} {
1182    uo_sendUnblockOwner;
1183    dt_deallocateTBE;
1184    pr_popResponseQueue;
1185  }
1186
1187  transition(D_I, StaleWB, I) {TagArrayWrite}{
1188    un_sendUnblockNotValid;
1189    dt_deallocateTBE;
1190    pr_popResponseQueue;
1191  }
1192
1193  transition(MOD_I, StaleWB, MO_I) {
1194    un_sendUnblockNotValid;
1195    rf_resetFrom;
1196    pr_popResponseQueue;
1197  }
1198
1199}
1200