1/*
2 * Copyright (c) 2011-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:SQC, "GPU SQC (L1 I Cache)")
37 : Sequencer* sequencer;
38   CacheMemory * L1cache;
39   int TCC_select_num_bits;
40   Cycles issue_latency := 80;  // time to send data down to TCC
41   Cycles l2_hit_latency := 18;
42
43  MessageBuffer * requestFromSQC, network="To", virtual_network="1", vnet_type="request";
44  MessageBuffer * responseFromSQC, network="To", virtual_network="3", vnet_type="response";
45  MessageBuffer * unblockFromCore, network="To", virtual_network="5", vnet_type="unblock";
46
47  MessageBuffer * probeToSQC, network="From", virtual_network="1", vnet_type="request";
48  MessageBuffer * responseToSQC, network="From", virtual_network="3", vnet_type="response";
49
50  MessageBuffer * mandatoryQueue;
51{
52  state_declaration(State, desc="SQC Cache States", default="SQC_State_I") {
53    I, AccessPermission:Invalid, desc="Invalid";
54    S, AccessPermission:Read_Only, desc="Shared";
55
56    I_S, AccessPermission:Busy, desc="Invalid, issued RdBlkS, have not seen response yet";
57    S_I, AccessPermission:Read_Only, desc="L1 replacement, waiting for clean WB ack";
58    I_C, AccessPermission:Invalid, desc="Invalid, waiting for WBAck from TCCdir for canceled WB";
59  }
60
61  enumeration(Event, desc="SQC Events") {
62    // Core initiated
63    Fetch,          desc="Fetch";
64
65    //TCC initiated
66    TCC_AckS,        desc="TCC Ack to Core Request";
67    TCC_AckWB,       desc="TCC Ack for WB";
68    TCC_NackWB,       desc="TCC Nack for WB";
69
70    // Mem sys initiated
71    Repl,           desc="Replacing block from cache";
72
73    // Probe Events
74    PrbInvData,         desc="probe, return M data";
75    PrbInv,             desc="probe, no need for data";
76    PrbShrData,         desc="probe downgrade, return data";
77  }
78
79  enumeration(RequestType, desc="To communicate stats from transitions to recordStats") {
80    DataArrayRead,    desc="Read the data array";
81    DataArrayWrite,   desc="Write the data array";
82    TagArrayRead,     desc="Read the data array";
83    TagArrayWrite,    desc="Write the data array";
84  }
85
86
87  structure(Entry, desc="...", interface="AbstractCacheEntry") {
88    State CacheState,           desc="cache state";
89    bool Dirty,                 desc="Is the data dirty (diff than memory)?";
90    DataBlock DataBlk,          desc="data for the block";
91    bool FromL2, default="false", desc="block just moved from L2";
92  }
93
94  structure(TBE, desc="...") {
95    State TBEState,             desc="Transient state";
96    DataBlock DataBlk,       desc="data for the block, required for concurrent writebacks";
97    bool Dirty,              desc="Is the data dirty (different than memory)?";
98    int NumPendingMsgs,      desc="Number of acks/data messages that this processor is waiting for";
99    bool Shared,             desc="Victim hit by shared probe";
100   }
101
102  structure(TBETable, external="yes") {
103    TBE lookup(Addr);
104    void allocate(Addr);
105    void deallocate(Addr);
106    bool isPresent(Addr);
107  }
108
109  TBETable TBEs, template="<SQC_TBE>", constructor="m_number_of_TBEs";
110  int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()";
111
112  Tick clockEdge();
113  Tick cyclesToTicks(Cycles c);
114
115  void set_cache_entry(AbstractCacheEntry b);
116  void unset_cache_entry();
117  void set_tbe(TBE b);
118  void unset_tbe();
119  void wakeUpAllBuffers();
120  void wakeUpBuffers(Addr a);
121  Cycles curCycle();
122
123  // Internal functions
124  Entry getCacheEntry(Addr address), return_by_pointer="yes" {
125    Entry cache_entry := static_cast(Entry, "pointer", L1cache.lookup(address));
126    return cache_entry;
127  }
128
129  DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
130    TBE tbe := TBEs.lookup(addr);
131    if(is_valid(tbe)) {
132      return tbe.DataBlk;
133    } else {
134      return getCacheEntry(addr).DataBlk;
135    }
136  }
137
138  State getState(TBE tbe, Entry cache_entry, Addr addr) {
139    if(is_valid(tbe)) {
140      return tbe.TBEState;
141    } else if (is_valid(cache_entry)) {
142      return cache_entry.CacheState;
143    }
144    return State:I;
145  }
146
147  void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
148    if (is_valid(tbe)) {
149      tbe.TBEState := state;
150    }
151
152    if (is_valid(cache_entry)) {
153      cache_entry.CacheState := state;
154    }
155  }
156
157  AccessPermission getAccessPermission(Addr addr) {
158    TBE tbe := TBEs.lookup(addr);
159    if(is_valid(tbe)) {
160      return SQC_State_to_permission(tbe.TBEState);
161    }
162
163    Entry cache_entry := getCacheEntry(addr);
164    if(is_valid(cache_entry)) {
165      return SQC_State_to_permission(cache_entry.CacheState);
166    }
167
168    return AccessPermission:NotPresent;
169  }
170
171  void setAccessPermission(Entry cache_entry, Addr addr, State state) {
172    if (is_valid(cache_entry)) {
173      cache_entry.changePermission(SQC_State_to_permission(state));
174    }
175  }
176
177  void functionalRead(Addr addr, Packet *pkt) {
178    TBE tbe := TBEs.lookup(addr);
179    if(is_valid(tbe)) {
180      testAndRead(addr, tbe.DataBlk, pkt);
181    } else {
182      functionalMemoryRead(pkt);
183    }
184  }
185
186  int functionalWrite(Addr addr, Packet *pkt) {
187    int num_functional_writes := 0;
188
189    TBE tbe := TBEs.lookup(addr);
190    if(is_valid(tbe)) {
191      num_functional_writes := num_functional_writes +
192            testAndWrite(addr, tbe.DataBlk, pkt);
193    }
194
195    num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
196    return num_functional_writes;
197  }
198
199  void recordRequestType(RequestType request_type, Addr addr) {
200    if (request_type == RequestType:DataArrayRead) {
201        L1cache.recordRequestType(CacheRequestType:DataArrayRead, addr);
202    } else if (request_type == RequestType:DataArrayWrite) {
203        L1cache.recordRequestType(CacheRequestType:DataArrayWrite, addr);
204    } else if (request_type == RequestType:TagArrayRead) {
205        L1cache.recordRequestType(CacheRequestType:TagArrayRead, addr);
206    } else if (request_type == RequestType:TagArrayWrite) {
207        L1cache.recordRequestType(CacheRequestType:TagArrayWrite, addr);
208    }
209  }
210
211  bool checkResourceAvailable(RequestType request_type, Addr addr) {
212    if (request_type == RequestType:DataArrayRead) {
213      return L1cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
214    } else if (request_type == RequestType:DataArrayWrite) {
215      return L1cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
216    } else if (request_type == RequestType:TagArrayRead) {
217      return L1cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
218    } else if (request_type == RequestType:TagArrayWrite) {
219      return L1cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
220    } else {
221      error("Invalid RequestType type in checkResourceAvailable");
222      return true;
223    }
224  }
225
226  // Out Ports
227
228  out_port(requestNetwork_out, CPURequestMsg, requestFromSQC);
229  out_port(responseNetwork_out, ResponseMsg, responseFromSQC);
230  out_port(unblockNetwork_out, UnblockMsg, unblockFromCore);
231
232  // In Ports
233
234  in_port(probeNetwork_in, TDProbeRequestMsg, probeToSQC) {
235    if (probeNetwork_in.isReady(clockEdge())) {
236      peek(probeNetwork_in, TDProbeRequestMsg, block_on="addr") {
237        Entry cache_entry := getCacheEntry(in_msg.addr);
238        TBE tbe := TBEs.lookup(in_msg.addr);
239
240        if (in_msg.Type == ProbeRequestType:PrbInv) {
241          if (in_msg.ReturnData) {
242            trigger(Event:PrbInvData, in_msg.addr, cache_entry, tbe);
243          } else {
244            trigger(Event:PrbInv, in_msg.addr, cache_entry, tbe);
245          }
246        } else if (in_msg.Type == ProbeRequestType:PrbDowngrade) {
247          assert(in_msg.ReturnData);
248          trigger(Event:PrbShrData, in_msg.addr, cache_entry, tbe);
249        }
250      }
251    }
252  }
253
254  in_port(responseToSQC_in, ResponseMsg, responseToSQC) {
255    if (responseToSQC_in.isReady(clockEdge())) {
256      peek(responseToSQC_in, ResponseMsg, block_on="addr") {
257
258        Entry cache_entry := getCacheEntry(in_msg.addr);
259        TBE tbe := TBEs.lookup(in_msg.addr);
260
261        if (in_msg.Type == CoherenceResponseType:TDSysResp) {
262          if (in_msg.State == CoherenceState:Shared) {
263            trigger(Event:TCC_AckS, in_msg.addr, cache_entry, tbe);
264          } else {
265            error("SQC should not receive TDSysResp other than CoherenceState:Shared");
266          }
267        } else if (in_msg.Type == CoherenceResponseType:TDSysWBAck) {
268          trigger(Event:TCC_AckWB, in_msg.addr, cache_entry, tbe);
269        } else if (in_msg.Type == CoherenceResponseType:TDSysWBNack) {
270          trigger(Event:TCC_NackWB, in_msg.addr, cache_entry, tbe);
271        } else {
272          error("Unexpected Response Message to Core");
273        }
274      }
275    }
276  }
277
278  in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...") {
279    if (mandatoryQueue_in.isReady(clockEdge())) {
280      peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
281        Entry cache_entry := getCacheEntry(in_msg.LineAddress);
282        TBE tbe := TBEs.lookup(in_msg.LineAddress);
283
284        assert(in_msg.Type == RubyRequestType:IFETCH);
285        if (is_valid(cache_entry) || L1cache.cacheAvail(in_msg.LineAddress)) {
286          trigger(Event:Fetch, in_msg.LineAddress, cache_entry, tbe);
287        } else {
288          Addr victim := L1cache.cacheProbe(in_msg.LineAddress);
289          trigger(Event:Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
290        }
291      }
292    }
293  }
294
295  // Actions
296
297  action(ic_invCache, "ic", desc="invalidate cache") {
298    if(is_valid(cache_entry)) {
299      L1cache.deallocate(address);
300    }
301    unset_cache_entry();
302  }
303
304  action(nS_issueRdBlkS, "nS", desc="Issue RdBlkS") {
305    enqueue(requestNetwork_out, CPURequestMsg, issue_latency) {
306      out_msg.addr := address;
307      out_msg.Type := CoherenceRequestType:RdBlkS;
308      out_msg.Requestor := machineID;
309      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
310                              TCC_select_low_bit, TCC_select_num_bits));
311      out_msg.MessageSize := MessageSizeType:Request_Control;
312      out_msg.InitialRequestTime := curCycle();
313    }
314  }
315
316  action(vc_victim, "vc", desc="Victimize E/S Data") {
317    enqueue(requestNetwork_out, CPURequestMsg, issue_latency) {
318      out_msg.addr := address;
319      out_msg.Requestor := machineID;
320      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
321                              TCC_select_low_bit, TCC_select_num_bits));
322      out_msg.MessageSize := MessageSizeType:Request_Control;
323      out_msg.Type := CoherenceRequestType:VicClean;
324      out_msg.InitialRequestTime := curCycle();
325      if (cache_entry.CacheState == State:S) {
326        out_msg.Shared := true;
327      } else {
328        out_msg.Shared := false;
329      }
330      out_msg.InitialRequestTime := curCycle();
331    }
332  }
333
334  action(a_allocate, "a", desc="allocate block") {
335    if (is_invalid(cache_entry)) {
336      set_cache_entry(L1cache.allocate(address, new Entry));
337    }
338  }
339
340  action(t_allocateTBE, "t", desc="allocate TBE Entry") {
341    check_allocate(TBEs);
342    assert(is_valid(cache_entry));
343    TBEs.allocate(address);
344    set_tbe(TBEs.lookup(address));
345    tbe.DataBlk := cache_entry.DataBlk;  // Data only used for WBs
346    tbe.Dirty := cache_entry.Dirty;
347    tbe.Shared := false;
348  }
349
350  action(d_deallocateTBE, "d", desc="Deallocate TBE") {
351    TBEs.deallocate(address);
352    unset_tbe();
353  }
354
355  action(p_popMandatoryQueue, "pm", desc="Pop Mandatory Queue") {
356    mandatoryQueue_in.dequeue(clockEdge());
357  }
358
359  action(pr_popResponseQueue, "pr", desc="Pop Response Queue") {
360    responseToSQC_in.dequeue(clockEdge());
361  }
362
363  action(pp_popProbeQueue, "pp", desc="pop probe queue") {
364    probeNetwork_in.dequeue(clockEdge());
365  }
366
367  action(l_loadDone, "l", desc="local load done") {
368    assert(is_valid(cache_entry));
369    sequencer.readCallback(address, cache_entry.DataBlk,
370                           false, MachineType:L1Cache);
371    APPEND_TRANSITION_COMMENT(cache_entry.DataBlk);
372  }
373
374  action(xl_loadDone, "xl", desc="remote load done") {
375    peek(responseToSQC_in, ResponseMsg) {
376      assert(is_valid(cache_entry));
377      sequencer.readCallback(address,
378                             cache_entry.DataBlk,
379                             false,
380                             machineIDToMachineType(in_msg.Sender),
381                             in_msg.InitialRequestTime,
382                             in_msg.ForwardRequestTime,
383                             in_msg.ProbeRequestStartTime);
384      APPEND_TRANSITION_COMMENT(cache_entry.DataBlk);
385    }
386  }
387
388  action(w_writeCache, "w", desc="write data to cache") {
389    peek(responseToSQC_in, ResponseMsg) {
390      assert(is_valid(cache_entry));
391      cache_entry.DataBlk := in_msg.DataBlk;
392      cache_entry.Dirty := in_msg.Dirty;
393    }
394  }
395
396  action(ss_sendStaleNotification, "ss", desc="stale data; nothing to writeback") {
397    peek(responseToSQC_in, ResponseMsg) {
398      enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
399        out_msg.addr := address;
400        out_msg.Type := CoherenceResponseType:StaleNotif;
401        out_msg.Sender := machineID;
402        out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
403                                TCC_select_low_bit, TCC_select_num_bits));
404        out_msg.MessageSize := MessageSizeType:Response_Control;
405        DPRINTF(RubySlicc, "%s\n", out_msg);
406      }
407    }
408  }
409
410  action(wb_data, "wb", desc="write back data") {
411    peek(responseToSQC_in, ResponseMsg) {
412      enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
413        out_msg.addr := address;
414        out_msg.Type := CoherenceResponseType:CPUData;
415        out_msg.Sender := machineID;
416        out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
417                                TCC_select_low_bit, TCC_select_num_bits));
418        out_msg.DataBlk := tbe.DataBlk;
419        out_msg.Dirty := tbe.Dirty;
420        if (tbe.Shared) {
421          out_msg.NbReqShared := true;
422        } else {
423          out_msg.NbReqShared := false;
424        }
425        out_msg.State := CoherenceState:Shared; // faux info
426        out_msg.MessageSize := MessageSizeType:Writeback_Data;
427        DPRINTF(RubySlicc, "%s\n", out_msg);
428      }
429    }
430  }
431
432  action(pi_sendProbeResponseInv, "pi", desc="send probe ack inv, no data") {
433    enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
434      out_msg.addr := address;
435      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // L3 and CPUs respond in same way to probes
436      out_msg.Sender := machineID;
437      // will this always be ok? probably not for multisocket
438      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
439                              TCC_select_low_bit, TCC_select_num_bits));
440      out_msg.Dirty := false;
441      out_msg.Hit := false;
442      out_msg.Ntsl := true;
443      out_msg.State := CoherenceState:NA;
444      out_msg.MessageSize := MessageSizeType:Response_Control;
445    }
446  }
447
448  action(pim_sendProbeResponseInvMs, "pim", desc="send probe ack inv, no data") {
449    enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
450      out_msg.addr := address;
451      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // L3 and CPUs respond in same way to probes
452      out_msg.Sender := machineID;
453      // will this always be ok? probably not for multisocket
454      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
455                              TCC_select_low_bit, TCC_select_num_bits));
456      out_msg.Dirty := false;
457      out_msg.Ntsl := true;
458      out_msg.Hit := false;
459      out_msg.State := CoherenceState:NA;
460      out_msg.MessageSize := MessageSizeType:Response_Control;
461    }
462  }
463
464  action(prm_sendProbeResponseMiss, "prm", desc="send probe ack PrbShrData, no data") {
465    enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
466      out_msg.addr := address;
467      out_msg.Type := CoherenceResponseType:CPUPrbResp;  // L3 and CPUs respond in same way to probes
468      out_msg.Sender := machineID;
469      // will this always be ok? probably not for multisocket
470      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
471                              TCC_select_low_bit, TCC_select_num_bits));
472      out_msg.Dirty := false;  // only true if sending back data i think
473      out_msg.Hit := false;
474      out_msg.Ntsl := false;
475      out_msg.State := CoherenceState:NA;
476      out_msg.MessageSize := MessageSizeType:Response_Control;
477    }
478  }
479
480  action(pd_sendProbeResponseData, "pd", desc="send probe ack, with data") {
481    enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
482      assert(is_valid(cache_entry) || is_valid(tbe));
483      out_msg.addr := address;
484      out_msg.Type := CoherenceResponseType:CPUPrbResp;
485      out_msg.Sender := machineID;
486      // will this always be ok? probably not for multisocket
487      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
488                              TCC_select_low_bit, TCC_select_num_bits));
489      out_msg.DataBlk := getDataBlock(address);
490      if (is_valid(tbe)) {
491        out_msg.Dirty := tbe.Dirty;
492      } else {
493        out_msg.Dirty := cache_entry.Dirty;
494      }
495      out_msg.Hit := true;
496      out_msg.State := CoherenceState:NA;
497      out_msg.MessageSize := MessageSizeType:Response_Data;
498    }
499  }
500
501  action(pdm_sendProbeResponseDataMs, "pdm", desc="send probe ack, with data") {
502    enqueue(responseNetwork_out, ResponseMsg, issue_latency) {
503      assert(is_valid(cache_entry) || is_valid(tbe));
504      assert(is_valid(cache_entry));
505      out_msg.addr := address;
506      out_msg.Type := CoherenceResponseType:CPUPrbResp;
507      out_msg.Sender := machineID;
508      // will this always be ok? probably not for multisocket
509      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
510                              TCC_select_low_bit, TCC_select_num_bits));
511      out_msg.DataBlk := getDataBlock(address);
512      if (is_valid(tbe)) {
513        out_msg.Dirty := tbe.Dirty;
514      } else {
515        out_msg.Dirty := cache_entry.Dirty;
516      }
517      out_msg.Hit := true;
518      out_msg.State := CoherenceState:NA;
519      out_msg.MessageSize := MessageSizeType:Response_Data;
520    }
521  }
522
523  action(sf_setSharedFlip, "sf", desc="hit by shared probe, status may be different") {
524    assert(is_valid(tbe));
525    tbe.Shared := true;
526  }
527
528  action(uu_sendUnblock, "uu", desc="state changed, unblock") {
529    enqueue(unblockNetwork_out, UnblockMsg, issue_latency) {
530      out_msg.addr := address;
531      out_msg.Sender := machineID;
532      out_msg.Destination.add(mapAddressToRange(address,MachineType:TCCdir,
533                              TCC_select_low_bit, TCC_select_num_bits));
534      out_msg.MessageSize := MessageSizeType:Unblock_Control;
535      DPRINTF(RubySlicc, "%s\n", out_msg);
536    }
537  }
538
539  action(yy_recycleProbeQueue, "yy", desc="recycle probe queue") {
540    probeNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
541  }
542
543  action(zz_recycleMandatoryQueue, "\z", desc="recycle mandatory queue") {
544    mandatoryQueue_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
545  }
546
547  // Transitions
548
549  // transitions from base
550  transition(I, Fetch, I_S) {TagArrayRead, TagArrayWrite} {
551    a_allocate;
552    nS_issueRdBlkS;
553    p_popMandatoryQueue;
554  }
555
556  // simple hit transitions
557  transition(S, Fetch) {TagArrayRead, DataArrayRead} {
558    l_loadDone;
559    p_popMandatoryQueue;
560  }
561
562  // recycles from transients
563  transition({I_S, S_I, I_C}, {Fetch, Repl}) {} {
564    zz_recycleMandatoryQueue;
565  }
566
567  transition(S, Repl, S_I) {TagArrayRead} {
568    t_allocateTBE;
569    vc_victim;
570    ic_invCache;
571  }
572
573  // TCC event
574  transition(I_S, TCC_AckS, S) {DataArrayRead, DataArrayWrite} {
575    w_writeCache;
576    xl_loadDone;
577    uu_sendUnblock;
578    pr_popResponseQueue;
579  }
580
581  transition(S_I, TCC_NackWB, I){TagArrayWrite} {
582    d_deallocateTBE;
583    pr_popResponseQueue;
584  }
585
586  transition(S_I, TCC_AckWB, I) {TagArrayWrite} {
587    wb_data;
588    d_deallocateTBE;
589    pr_popResponseQueue;
590  }
591
592  transition(I_C, TCC_AckWB, I){TagArrayWrite} {
593    ss_sendStaleNotification;
594    d_deallocateTBE;
595    pr_popResponseQueue;
596  }
597
598  transition(I_C, TCC_NackWB, I) {TagArrayWrite} {
599    d_deallocateTBE;
600    pr_popResponseQueue;
601  }
602
603  // Probe transitions
604  transition({S, I}, PrbInvData, I) {TagArrayRead, TagArrayWrite} {
605    pd_sendProbeResponseData;
606    ic_invCache;
607    pp_popProbeQueue;
608  }
609
610  transition(I_C, PrbInvData, I_C) {
611    pi_sendProbeResponseInv;
612    ic_invCache;
613    pp_popProbeQueue;
614  }
615
616  transition({S, I}, PrbInv, I) {TagArrayRead, TagArrayWrite} {
617    pi_sendProbeResponseInv;
618    ic_invCache;
619    pp_popProbeQueue;
620  }
621
622  transition({S}, PrbShrData, S) {DataArrayRead} {
623    pd_sendProbeResponseData;
624    pp_popProbeQueue;
625  }
626
627  transition({I, I_C}, PrbShrData) {TagArrayRead} {
628    prm_sendProbeResponseMiss;
629    pp_popProbeQueue;
630  }
631
632  transition(I_C, PrbInv, I_C){
633    pi_sendProbeResponseInv;
634    ic_invCache;
635    pp_popProbeQueue;
636  }
637
638  transition(I_S, {PrbInv, PrbInvData}) {} {
639    pi_sendProbeResponseInv;
640    ic_invCache;
641    a_allocate;  // but make sure there is room for incoming data when it arrives
642    pp_popProbeQueue;
643  }
644
645  transition(I_S, PrbShrData) {} {
646    prm_sendProbeResponseMiss;
647    pp_popProbeQueue;
648  }
649
650  transition(S_I, PrbInvData, I_C) {TagArrayWrite} {
651    pi_sendProbeResponseInv;
652    ic_invCache;
653    pp_popProbeQueue;
654  }
655
656  transition(S_I, PrbInv, I_C) {TagArrayWrite} {
657    pi_sendProbeResponseInv;
658    ic_invCache;
659    pp_popProbeQueue;
660  }
661
662  transition(S_I, PrbShrData) {DataArrayRead} {
663    pd_sendProbeResponseData;
664    sf_setSharedFlip;
665    pp_popProbeQueue;
666  }
667}
668