2 * Copyright (c) 2010-2015 Advanced Micro Devices, Inc.
5 * For use for simulation and test purposes only
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
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.
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.
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.
36 machine(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;
48 // To the general response network
49 MessageBuffer * responseFromTCC, network="To", virtual_network="3", vnet_type="response";
51 // From the general response network
52 MessageBuffer * responseToTCC, network="From", virtual_network="3", vnet_type="response";
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)";
67 CPUData, desc="WB data from CPU";
68 CPUDataShared, desc="WB data from CPU, NBReqShared 1";
69 StaleWB, desc="Stale WB, No data";
71 L2_Repl, desc="L2 Replacement";
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";
78 // Coming from Memory Controller
79 WBAck, desc="ack from memory";
81 CancelWB, desc="Cancel WB from L2";
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";
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";
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";
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";
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...";
142 structure(TBETable, external="yes") {
145 void deallocate(Addr);
146 bool isPresent(Addr);
149 TBETable TBEs, template="<TCC_TBE>", constructor="m_number_of_TBEs";
150 int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()";
152 void set_cache_entry(AbstractCacheEntry b);
153 void unset_cache_entry();
156 void wakeUpAllBuffers();
157 void wakeUpBuffers(Addr a);
160 // FUNCTION DEFINITIONS
162 Tick cyclesToTicks(Cycles c);
164 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
165 return static_cast(Entry, "pointer", L2cache.lookup(addr));
168 DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
169 return getCacheEntry(addr).DataBlk;
172 bool presentOrAvail(Addr addr) {
173 return L2cache.isTagPresent(addr) || L2cache.cacheAvail(addr);
176 State getState(TBE tbe, Entry cache_entry, Addr addr) {
179 } else if (is_valid(cache_entry)) {
180 return cache_entry.CacheState;
185 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
187 tbe.TBEState := state;
190 if (is_valid(cache_entry)) {
191 cache_entry.CacheState := state;
195 AccessPermission getAccessPermission(Addr addr) {
196 TBE tbe := TBEs.lookup(addr);
198 return TCC_State_to_permission(tbe.TBEState);
201 Entry cache_entry := getCacheEntry(addr);
202 if(is_valid(cache_entry)) {
203 return TCC_State_to_permission(cache_entry.CacheState);
206 return AccessPermission:NotPresent;
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));
215 void functionalRead(Addr addr, Packet *pkt) {
216 TBE tbe := TBEs.lookup(addr);
218 testAndRead(addr, tbe.DataBlk, pkt);
220 functionalMemoryRead(pkt);
224 int functionalWrite(Addr addr, Packet *pkt) {
225 int num_functional_writes := 0;
227 TBE tbe := TBEs.lookup(addr);
229 num_functional_writes := num_functional_writes +
230 testAndWrite(addr, tbe.DataBlk, pkt);
233 num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
234 return num_functional_writes;
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);
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);
259 error("Invalid RequestType type in checkResourceAvailable");
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);
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);
282 DPRINTF(RubySlicc, "%s\n", in_msg);
283 error("Error on TDResponse Type");
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);
299 trigger(Event:CPUData, in_msg.addr, cache_entry, tbe);
301 } else if (in_msg.Type == CoherenceResponseType:StaleNotif) {
302 trigger(Event:StaleWB, in_msg.addr, cache_entry, tbe);
304 DPRINTF(RubySlicc, "%s\n", in_msg);
305 error("Error on TDResponse Type");
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);
321 trigger(Event:PrbInv, in_msg.addr, cache_entry, tbe);
323 } else if (in_msg.Type == ProbeRequestType:PrbDowngrade) {
324 if (in_msg.ReturnData) {
325 trigger(Event:PrbShrData, in_msg.addr, cache_entry, tbe);
327 error("Don't think I should get any of these");
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)) {
350 trigger(Event:ClVicBlkShared, in_msg.addr, cache_entry, tbe);
352 trigger(Event:ClVicBlk, in_msg.addr, cache_entry, tbe);
355 Addr victim := L2cache.cacheProbe(in_msg.addr);
356 trigger(Event:L2_Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
358 } else if (in_msg.Type == CoherenceRequestType:VicDirty) {
359 if (presentOrAvail(in_msg.addr)) {
361 trigger(Event:WrVicBlkShared, in_msg.addr, cache_entry, tbe);
363 trigger(Event:WrVicBlk, in_msg.addr, cache_entry, tbe);
366 Addr victim := L2cache.cacheProbe(in_msg.addr);
367 trigger(Event:L2_Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
370 requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
378 action(i_invL2, "i", desc="invalidate TCC cache block") {
379 if (is_valid(cache_entry)) {
380 L2cache.deallocate(address);
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);
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);
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);
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;
440 tbe.From := machineID;
443 action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") {
444 TBEs.deallocate(address);
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;
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;
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;
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;
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;
510 out_msg.Ntsl := false;
511 out_msg.State := CoherenceState:NA;
512 out_msg.MessageSize := MessageSizeType:Response_Control;
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;
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;
544 out_msg.State := CoherenceState:NA;
545 out_msg.MessageSize := MessageSizeType:Response_Data;
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;
558 out_msg.Dirty := tbe.Dirty;
560 out_msg.MessageSize := MessageSizeType:Response_Data;
561 out_msg.State := CoherenceState:NA;
562 DPRINTF(RubySlicc, "%s\n", out_msg);
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;
577 action(a_allocateBlock, "a", desc="allocate TCC block") {
578 if (is_invalid(cache_entry)) {
579 set_cache_entry(L2cache.allocate(address, new Entry));
583 action(d_writeData, "d", desc="write data to TCC") {
584 peek(responseNetwork_in, ResponseMsg) {
586 cache_entry.Dirty := in_msg.Dirty;
588 cache_entry.DataBlk := in_msg.DataBlk;
589 DPRINTF(RubySlicc, "Writing to TCC: %s\n", in_msg);
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;
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;
606 action(rf_resetFrom, "rf", desc="reset From") {
607 tbe.From := machineID;
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;
620 out_msg.NbReqShared := true;
622 out_msg.NbReqShared := false;
624 out_msg.State := CoherenceState:Shared; // faux info
625 out_msg.MessageSize := MessageSizeType:Writeback_Data;
626 DPRINTF(RubySlicc, "%s\n", out_msg);
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;
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);
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);
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);
676 action(ut_updateTag, "ut", desc="update Tag (i.e. set MRU)") {
677 L2cache.setMRU(address);
680 action(p_popRequestQueue, "p", desc="pop request queue") {
681 requestNetwork_in.dequeue(clockEdge());
684 action(pr_popResponseQueue, "pr", desc="pop response queue") {
685 responseNetwork_in.dequeue(clockEdge());
688 action(pn_popTDResponseQueue, "pn", desc="pop TD response queue") {
689 TDResponse_in.dequeue(clockEdge());
692 action(pp_popProbeQueue, "pp", desc="pop probe queue") {
693 probeNetwork_in.dequeue(clockEdge());
696 action(zz_recycleRequestQueue, "\z", desc="recycle request queue") {
697 requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
705 // transitions from base
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.
714 transition({M, O}, RdBlk, O){TagArrayRead, TagArrayWrite} {
717 // detect 2nd chancing
722 transition({E, S}, RdBlk, S){TagArrayRead, TagArrayWrite} {
725 // detect 2nd chancing
730 transition({M, O}, RdBlkS, O){TagArrayRead, TagArrayWrite} {
733 // detect 2nd chance sharing
738 transition({E, S}, RdBlkS, S){TagArrayRead, TagArrayWrite} {
741 // detect 2nd chance sharing
746 transition(M, RdBlkM, I){TagArrayRead, TagArrayWrite} {
753 transition(E, RdBlkM, I){TagArrayRead, TagArrayWrite} {
760 transition({I}, WrVicBlk, I_M){TagArrayRead} {
768 transition(I_C, {WrVicBlk, WrVicBlkShared, ClVicBlk, ClVicBlkShared}) {
769 zz_recycleRequestQueue;
773 transition({I}, WrVicBlkShared, I_O) {TagArrayRead}{
777 // rd_copyDataFromRequest;
783 transition(S, WrVicBlkShared, S_O){TagArrayRead} {
791 transition(S, WrVicBlk, S_S){TagArrayRead} {
799 transition(E, WrVicBlk, E_E){TagArrayRead} {
807 transition(E, WrVicBlkShared, E_E){TagArrayRead} {
815 transition(O, WrVicBlk, O_O){TagArrayRead} {
823 transition(O, WrVicBlkShared, O_O){TagArrayRead} {
831 transition(M, WrVicBlk, M_M){TagArrayRead} {
839 transition(M, WrVicBlkShared, M_O){TagArrayRead} {
847 transition({I}, ClVicBlk, I_E){TagArrayRead} {
855 transition({I}, ClVicBlkShared, I_S){TagArrayRead} {
864 transition(S, ClVicBlkShared, S_S){TagArrayRead} {
872 transition(E, ClVicBlk, E_E){TagArrayRead} {
880 transition(E, ClVicBlkShared, E_S){TagArrayRead} {
888 transition(O, ClVicBlk, O_O){TagArrayRead} {
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} {
904 transition(M, ClVicBlk, M_E){TagArrayRead} {
912 transition(M, ClVicBlkShared, M_S){TagArrayRead} {
920 transition({MO_I}, {RdBlk, RdBlkS, RdBlkM, CtoD}) {
928 transition(MO_I, {WrVicBlkShared, WrVicBlk, ClVicBlk, ClVicBlkShared}, MOD_I) {
934 transition(I_M, CPUData, M){TagArrayWrite} {
941 transition(I_M, CPUDataShared, O){TagArrayWrite, DataArrayWrite} {
948 transition(I_O, {CPUData, CPUDataShared}, O){TagArrayWrite, DataArrayWrite} {
955 transition(I_E, CPUData, E){TagArrayWrite, DataArrayWrite} {
962 transition(I_E, CPUDataShared, S){TagArrayWrite, DataArrayWrite} {
963 us_sendUnblockSharer;
969 transition(I_S, {CPUData, CPUDataShared}, S){TagArrayWrite, DataArrayWrite} {
970 us_sendUnblockSharer;
976 transition(S_M, CPUDataShared, O){TagArrayWrite, DataArrayWrite} {
980 ut_updateTag; // update tag on writeback hits.
984 transition(S_O, {CPUData, CPUDataShared}, O){TagArrayWrite, DataArrayWrite} {
988 ut_updateTag; // update tag on writeback hits.
992 transition(S_E, CPUDataShared, S){TagArrayWrite, DataArrayWrite} {
993 us_sendUnblockSharer;
996 ut_updateTag; // update tag on writeback hits.
1000 transition(S_S, {CPUData, CPUDataShared}, S){TagArrayWrite, DataArrayWrite} {
1001 us_sendUnblockSharer;
1004 ut_updateTag; // update tag on writeback hits.
1005 pr_popResponseQueue;
1008 transition(O_E, CPUDataShared, O){TagArrayWrite, DataArrayWrite} {
1009 uo_sendUnblockOwner;
1012 ut_updateTag; // update tag on writeback hits.
1013 pr_popResponseQueue;
1016 transition(O_O, {CPUData, CPUDataShared}, O){TagArrayWrite, DataArrayWrite} {
1017 uo_sendUnblockOwner;
1020 ut_updateTag; // update tag on writeback hits.
1021 pr_popResponseQueue;
1024 transition({D_I}, {CPUData, CPUDataShared}, I){TagArrayWrite} {
1025 un_sendUnblockNotValid;
1027 pr_popResponseQueue;
1030 transition(MOD_I, {CPUData, CPUDataShared}, MO_I) {
1031 un_sendUnblockNotValid;
1033 pr_popResponseQueue;
1036 transition({O,S,I}, CPUData) {
1037 pr_popResponseQueue;
1040 transition({M, O}, L2_Repl, MO_I){TagArrayRead, DataArrayRead} {
1046 transition({E, S,}, L2_Repl, ES_I){TagArrayRead, DataArrayRead} {
1052 transition({I_M, I_O, S_M, S_O, E_M, E_O}, L2_Repl) {
1053 zz_recycleRequestQueue;
1056 transition({O_M, O_O, O_E, M_M, M_O, M_E, M_S}, L2_Repl) {
1057 zz_recycleRequestQueue;
1060 transition({I_E, I_S, S_E, S_S, E_E, E_S}, L2_Repl) {
1061 zz_recycleRequestQueue;
1064 transition({M, O}, PrbInvData, I){TagArrayRead, TagArrayWrite} {
1065 pd_sendProbeResponseData;
1070 transition(I, PrbInvData){TagArrayRead, TagArrayWrite} {
1071 pi_sendProbeResponseInv;
1075 transition({E, S}, PrbInvData, I){TagArrayRead, TagArrayWrite} {
1076 pd_sendProbeResponseData;
1081 transition({M, O, E, S, I}, PrbInv, I){TagArrayRead, TagArrayWrite} {
1082 pi_sendProbeResponseInv;
1083 i_invL2; // nothing will happen in I
1087 transition({M, O}, PrbShrData, O){TagArrayRead, TagArrayWrite} {
1088 pd_sendProbeResponseData;
1092 transition({E, S}, PrbShrData, S){TagArrayRead, TagArrayWrite} {
1093 pd_sendProbeResponseData;
1097 transition(I, PrbShrData){TagArrayRead} {
1098 pm_sendProbeResponseMiss;
1102 transition(MO_I, PrbInvData, I_C) {
1103 pdt_sendProbeResponseDataFromTBE;
1107 transition(ES_I, PrbInvData, I_C) {
1108 pi_sendProbeResponseInv;
1112 transition({ES_I,MO_I}, PrbInv, I_C) {
1113 pi_sendProbeResponseInv;
1117 transition({ES_I, MO_I}, PrbShrData) {
1118 pdt_sendProbeResponseDataFromTBE;
1122 transition(I_C, {PrbInvData, PrbInv}) {
1123 pi_sendProbeResponseInv;
1127 transition(I_C, PrbShrData) {
1128 pm_sendProbeResponseMiss;
1132 transition(MOD_I, WBAck, D_I) {
1133 pn_popTDResponseQueue;
1136 transition(MO_I, WBAck, I){TagArrayWrite} {
1138 pn_popTDResponseQueue;
1141 // this can only be a spurious CPUData from a shared block.
1142 transition(MO_I, CPUData) {
1143 pr_popResponseQueue;
1146 transition(ES_I, WBAck, I){TagArrayWrite} {
1148 pn_popTDResponseQueue;
1151 transition(I_C, {WBAck}, I){TagArrayWrite} {
1153 pn_popTDResponseQueue;
1156 transition({I_M, I_O, I_E, I_S}, StaleWB, I){TagArrayWrite} {
1157 un_sendUnblockNotValid;
1160 pr_popResponseQueue;
1163 transition({S_S, S_O, S_M, S_E}, StaleWB, S){TagArrayWrite} {
1164 us_sendUnblockSharer;
1166 pr_popResponseQueue;
1169 transition({E_M, E_O, E_E, E_S}, StaleWB, E){TagArrayWrite} {
1170 uo_sendUnblockOwner;
1172 pr_popResponseQueue;
1175 transition({O_M, O_O, O_E}, StaleWB, O){TagArrayWrite} {
1176 uo_sendUnblockOwner;
1178 pr_popResponseQueue;
1181 transition({M_M, M_O, M_E, M_S}, StaleWB, M){TagArrayWrite} {
1182 uo_sendUnblockOwner;
1184 pr_popResponseQueue;
1187 transition(D_I, StaleWB, I) {TagArrayWrite}{
1188 un_sendUnblockNotValid;
1190 pr_popResponseQueue;
1193 transition(MOD_I, StaleWB, MO_I) {
1194 un_sendUnblockNotValid;
1196 pr_popResponseQueue;