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 contributors
18 * may be used to endorse or promote products derived from this software
19 * 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.
33 * Author: Blake Hechtman
36 machine(MachineType:TCC, "TCC Cache")
37 : CacheMemory * L2cache;
38 bool WB; /*is this cache Writeback?*/
39 Cycles l2_request_latency := 50;
40 Cycles l2_response_latency := 20;
42 // From the TCPs or SQCs
43 MessageBuffer * requestFromTCP, network="From", virtual_network="1", vnet_type="request";
44 // To the Cores. TCC deals only with TCPs/SQCs.
45 MessageBuffer * responseToCore, network="To", virtual_network="3", vnet_type="response";
47 MessageBuffer * probeFromNB, network="From", virtual_network="0", vnet_type="request";
48 MessageBuffer * responseFromNB, network="From", virtual_network="2", vnet_type="response";
50 MessageBuffer * requestToNB, network="To", virtual_network="0", vnet_type="request";
51 MessageBuffer * responseToNB, network="To", virtual_network="2", vnet_type="response";
52 MessageBuffer * unblockToNB, network="To", virtual_network="4", vnet_type="unblock";
54 MessageBuffer * triggerQueue;
58 enumeration(Event, desc="TCC Events") {
59 // Requests coming from the Cores
60 RdBlk, desc="RdBlk event";
61 WrVicBlk, desc="L1 Write Through";
62 WrVicBlkBack, desc="L1 Write Through(dirty cache)";
63 Atomic, desc="Atomic Op";
64 AtomicDone, desc="AtomicOps Complete";
65 AtomicNotDone, desc="AtomicOps not Complete";
66 Data, desc="data messgae";
67 // Coming from this TCC
68 L2_Repl, desc="L2 Replacement";
70 PrbInv, desc="Invalidating probe";
71 // Coming from Memory Controller
72 WBAck, desc="writethrough ack from memory";
76 state_declaration(State, desc="TCC State", default="TCC_State_I") {
77 M, AccessPermission:Read_Write, desc="Modified(dirty cache only)";
78 W, AccessPermission:Read_Write, desc="Written(dirty cache only)";
79 V, AccessPermission:Read_Only, desc="Valid";
80 I, AccessPermission:Invalid, desc="Invalid";
81 IV, AccessPermission:Busy, desc="Waiting for Data";
82 WI, AccessPermission:Busy, desc="Waiting on Writethrough Ack";
83 A, AccessPermission:Busy, desc="Invalid waiting on atomici Data";
86 enumeration(RequestType, desc="To communicate stats from transitions to recordStats") {
87 DataArrayRead, desc="Read the data array";
88 DataArrayWrite, desc="Write the data array";
89 TagArrayRead, desc="Read the data array";
90 TagArrayWrite, desc="Write the data array";
96 structure(Entry, desc="...", interface="AbstractCacheEntry") {
97 State CacheState, desc="cache state";
98 bool Dirty, desc="Is the data dirty (diff from memory?)";
99 DataBlock DataBlk, desc="Data for the block";
100 WriteMask writeMask, desc="Dirty byte mask";
103 structure(TBE, desc="...") {
104 State TBEState, desc="Transient state";
105 DataBlock DataBlk, desc="data for the block";
106 bool Dirty, desc="Is the data dirty?";
107 bool Shared, desc="Victim hit by shared probe";
108 MachineID From, desc="Waiting for writeback from...";
109 NetDest Destination, desc="Data destination";
110 int numAtomics, desc="number remaining atomics";
113 structure(TBETable, external="yes") {
116 void deallocate(Addr);
117 bool isPresent(Addr);
120 TBETable TBEs, template="<TCC_TBE>", constructor="m_number_of_TBEs";
122 void set_cache_entry(AbstractCacheEntry b);
123 void unset_cache_entry();
126 void wakeUpAllBuffers();
127 void wakeUpBuffers(Addr a);
130 // FUNCTION DEFINITIONS
133 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
134 return static_cast(Entry, "pointer", L2cache.lookup(addr));
137 DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
138 return getCacheEntry(addr).DataBlk;
141 bool presentOrAvail(Addr addr) {
142 return L2cache.isTagPresent(addr) || L2cache.cacheAvail(addr);
145 State getState(TBE tbe, Entry cache_entry, Addr addr) {
148 } else if (is_valid(cache_entry)) {
149 return cache_entry.CacheState;
154 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
156 tbe.TBEState := state;
159 if (is_valid(cache_entry)) {
160 cache_entry.CacheState := state;
164 void functionalRead(Addr addr, Packet *pkt) {
165 TBE tbe := TBEs.lookup(addr);
167 testAndRead(addr, tbe.DataBlk, pkt);
169 functionalMemoryRead(pkt);
173 int functionalWrite(Addr addr, Packet *pkt) {
174 int num_functional_writes := 0;
176 TBE tbe := TBEs.lookup(addr);
178 num_functional_writes := num_functional_writes +
179 testAndWrite(addr, tbe.DataBlk, pkt);
182 num_functional_writes := num_functional_writes +
183 functionalMemoryWrite(pkt);
184 return num_functional_writes;
187 AccessPermission getAccessPermission(Addr addr) {
188 TBE tbe := TBEs.lookup(addr);
190 return TCC_State_to_permission(tbe.TBEState);
193 Entry cache_entry := getCacheEntry(addr);
194 if(is_valid(cache_entry)) {
195 return TCC_State_to_permission(cache_entry.CacheState);
198 return AccessPermission:NotPresent;
201 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
202 if (is_valid(cache_entry)) {
203 cache_entry.changePermission(TCC_State_to_permission(state));
207 void recordRequestType(RequestType request_type, Addr addr) {
208 if (request_type == RequestType:DataArrayRead) {
209 L2cache.recordRequestType(CacheRequestType:DataArrayRead, addr);
210 } else if (request_type == RequestType:DataArrayWrite) {
211 L2cache.recordRequestType(CacheRequestType:DataArrayWrite, addr);
212 } else if (request_type == RequestType:TagArrayRead) {
213 L2cache.recordRequestType(CacheRequestType:TagArrayRead, addr);
214 } else if (request_type == RequestType:TagArrayWrite) {
215 L2cache.recordRequestType(CacheRequestType:TagArrayWrite, addr);
219 bool checkResourceAvailable(RequestType request_type, Addr addr) {
220 if (request_type == RequestType:DataArrayRead) {
221 return L2cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
222 } else if (request_type == RequestType:DataArrayWrite) {
223 return L2cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
224 } else if (request_type == RequestType:TagArrayRead) {
225 return L2cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
226 } else if (request_type == RequestType:TagArrayWrite) {
227 return L2cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
229 error("Invalid RequestType type in checkResourceAvailable");
237 // Three classes of ports
238 // Class 1: downward facing network links to NB
239 out_port(requestToNB_out, CPURequestMsg, requestToNB);
240 out_port(responseToNB_out, ResponseMsg, responseToNB);
241 out_port(unblockToNB_out, UnblockMsg, unblockToNB);
243 // Class 2: upward facing ports to GPU cores
244 out_port(responseToCore_out, ResponseMsg, responseToCore);
246 out_port(triggerQueue_out, TriggerMsg, triggerQueue);
248 // request queue going to NB
253 in_port(triggerQueue_in, TiggerMsg, triggerQueue) {
254 if (triggerQueue_in.isReady(clockEdge())) {
255 peek(triggerQueue_in, TriggerMsg) {
256 TBE tbe := TBEs.lookup(in_msg.addr);
257 Entry cache_entry := getCacheEntry(in_msg.addr);
258 if (tbe.numAtomics == 0) {
259 trigger(Event:AtomicDone, in_msg.addr, cache_entry, tbe);
261 trigger(Event:AtomicNotDone, in_msg.addr, cache_entry, tbe);
269 in_port(responseFromNB_in, ResponseMsg, responseFromNB) {
270 if (responseFromNB_in.isReady(clockEdge())) {
271 peek(responseFromNB_in, ResponseMsg, block_on="addr") {
272 TBE tbe := TBEs.lookup(in_msg.addr);
273 Entry cache_entry := getCacheEntry(in_msg.addr);
274 if (in_msg.Type == CoherenceResponseType:NBSysResp) {
275 if(presentOrAvail(in_msg.addr)) {
276 trigger(Event:Data, in_msg.addr, cache_entry, tbe);
278 Addr victim := L2cache.cacheProbe(in_msg.addr);
279 trigger(Event:L2_Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
281 } else if (in_msg.Type == CoherenceResponseType:NBSysWBAck) {
282 trigger(Event:WBAck, in_msg.addr, cache_entry, tbe);
284 error("Unexpected Response Message to Core");
290 // Finally handling incoming requests (from TCP) and probes (from NB).
291 in_port(probeNetwork_in, NBProbeRequestMsg, probeFromNB) {
292 if (probeNetwork_in.isReady(clockEdge())) {
293 peek(probeNetwork_in, NBProbeRequestMsg) {
294 DPRINTF(RubySlicc, "%s\n", in_msg);
295 Entry cache_entry := getCacheEntry(in_msg.addr);
296 TBE tbe := TBEs.lookup(in_msg.addr);
297 trigger(Event:PrbInv, in_msg.addr, cache_entry, tbe);
302 in_port(coreRequestNetwork_in, CPURequestMsg, requestFromTCP, rank=0) {
303 if (coreRequestNetwork_in.isReady(clockEdge())) {
304 peek(coreRequestNetwork_in, CPURequestMsg) {
305 TBE tbe := TBEs.lookup(in_msg.addr);
306 Entry cache_entry := getCacheEntry(in_msg.addr);
307 if (in_msg.Type == CoherenceRequestType:WriteThrough) {
309 if(presentOrAvail(in_msg.addr)) {
310 trigger(Event:WrVicBlkBack, in_msg.addr, cache_entry, tbe);
312 Addr victim := L2cache.cacheProbe(in_msg.addr);
313 trigger(Event:L2_Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
316 trigger(Event:WrVicBlk, in_msg.addr, cache_entry, tbe);
318 } else if (in_msg.Type == CoherenceRequestType:Atomic) {
319 trigger(Event:Atomic, in_msg.addr, cache_entry, tbe);
320 } else if (in_msg.Type == CoherenceRequestType:RdBlk) {
321 trigger(Event:RdBlk, in_msg.addr, cache_entry, tbe);
323 DPRINTF(RubySlicc, "%s\n", in_msg);
324 error("Unexpected Response Message to Core");
331 action(i_invL2, "i", desc="invalidate TCC cache block") {
332 if (is_valid(cache_entry)) {
333 L2cache.deallocate(address);
338 action(sd_sendData, "sd", desc="send Shared response") {
339 peek(coreRequestNetwork_in, CPURequestMsg) {
340 enqueue(responseToCore_out, ResponseMsg, l2_response_latency) {
341 out_msg.addr := address;
342 out_msg.Type := CoherenceResponseType:TDSysResp;
343 out_msg.Sender := machineID;
344 out_msg.Destination.add(in_msg.Requestor);
345 out_msg.DataBlk := cache_entry.DataBlk;
346 out_msg.MessageSize := MessageSizeType:Response_Data;
347 out_msg.Dirty := false;
348 out_msg.State := CoherenceState:Shared;
349 DPRINTF(RubySlicc, "%s\n", out_msg);
355 action(sdr_sendDataResponse, "sdr", desc="send Shared response") {
356 enqueue(responseToCore_out, ResponseMsg, l2_response_latency) {
357 out_msg.addr := address;
358 out_msg.Type := CoherenceResponseType:TDSysResp;
359 out_msg.Sender := machineID;
360 out_msg.Destination := tbe.Destination;
361 out_msg.DataBlk := cache_entry.DataBlk;
362 out_msg.MessageSize := MessageSizeType:Response_Data;
363 out_msg.Dirty := false;
364 out_msg.State := CoherenceState:Shared;
365 DPRINTF(RubySlicc, "%s\n", out_msg);
367 enqueue(unblockToNB_out, UnblockMsg, 1) {
368 out_msg.addr := address;
369 out_msg.Destination.add(map_Address_to_Directory(address));
370 out_msg.MessageSize := MessageSizeType:Unblock_Control;
371 DPRINTF(RubySlicc, "%s\n", out_msg);
376 action(rd_requestData, "r", desc="Miss in L2, pass on") {
377 if(tbe.Destination.count()==1){
378 peek(coreRequestNetwork_in, CPURequestMsg) {
379 enqueue(requestToNB_out, CPURequestMsg, l2_request_latency) {
380 out_msg.addr := address;
381 out_msg.Type := in_msg.Type;
382 out_msg.Requestor := machineID;
383 out_msg.Destination.add(map_Address_to_Directory(address));
384 out_msg.Shared := false; // unneeded for this request
385 out_msg.MessageSize := in_msg.MessageSize;
386 DPRINTF(RubySlicc, "%s\n", out_msg);
392 action(w_sendResponseWBAck, "w", desc="send WB Ack") {
393 peek(responseFromNB_in, ResponseMsg) {
394 enqueue(responseToCore_out, ResponseMsg, l2_response_latency) {
395 out_msg.addr := address;
396 out_msg.Type := CoherenceResponseType:TDSysWBAck;
397 out_msg.Destination.clear();
398 out_msg.Destination.add(in_msg.WTRequestor);
399 out_msg.Sender := machineID;
400 out_msg.MessageSize := MessageSizeType:Writeback_Control;
405 action(swb_sendWBAck, "swb", desc="send WB Ack") {
406 peek(coreRequestNetwork_in, CPURequestMsg) {
407 enqueue(responseToCore_out, ResponseMsg, l2_response_latency) {
408 out_msg.addr := address;
409 out_msg.Type := CoherenceResponseType:TDSysWBAck;
410 out_msg.Destination.clear();
411 out_msg.Destination.add(in_msg.Requestor);
412 out_msg.Sender := machineID;
413 out_msg.MessageSize := MessageSizeType:Writeback_Control;
418 action(ar_sendAtomicResponse, "ar", desc="send Atomic Ack") {
419 peek(responseFromNB_in, ResponseMsg) {
420 enqueue(responseToCore_out, ResponseMsg, l2_response_latency) {
421 out_msg.addr := address;
422 out_msg.Type := CoherenceResponseType:TDSysResp;
423 out_msg.Destination.add(in_msg.WTRequestor);
424 out_msg.Sender := machineID;
425 out_msg.MessageSize := in_msg.MessageSize;
426 out_msg.DataBlk := in_msg.DataBlk;
431 action(a_allocateBlock, "a", desc="allocate TCC block") {
432 if (is_invalid(cache_entry)) {
433 set_cache_entry(L2cache.allocate(address, new Entry));
434 cache_entry.writeMask.clear();
438 action(t_allocateTBE, "t", desc="allocate TBE Entry") {
439 if (is_invalid(tbe)) {
440 check_allocate(TBEs);
441 TBEs.allocate(address);
442 set_tbe(TBEs.lookup(address));
443 tbe.Destination.clear();
446 if (coreRequestNetwork_in.isReady(clockEdge())) {
447 peek(coreRequestNetwork_in, CPURequestMsg) {
448 if(in_msg.Type == CoherenceRequestType:RdBlk || in_msg.Type == CoherenceRequestType:Atomic){
449 tbe.Destination.add(in_msg.Requestor);
455 action(dt_deallocateTBE, "dt", desc="Deallocate TBE entry") {
456 tbe.Destination.clear();
457 TBEs.deallocate(address);
461 action(wcb_writeCacheBlock, "wcb", desc="write data to TCC") {
462 peek(responseFromNB_in, ResponseMsg) {
463 cache_entry.DataBlk := in_msg.DataBlk;
464 DPRINTF(RubySlicc, "Writing to TCC: %s\n", in_msg);
468 action(wdb_writeDirtyBytes, "wdb", desc="write data to TCC") {
469 peek(coreRequestNetwork_in, CPURequestMsg) {
470 cache_entry.DataBlk.copyPartial(in_msg.DataBlk,in_msg.writeMask);
471 cache_entry.writeMask.orMask(in_msg.writeMask);
472 DPRINTF(RubySlicc, "Writing to TCC: %s\n", in_msg);
476 action(wt_writeThrough, "wt", desc="write back data") {
477 peek(coreRequestNetwork_in, CPURequestMsg) {
478 enqueue(requestToNB_out, CPURequestMsg, l2_request_latency) {
479 out_msg.addr := address;
480 out_msg.Requestor := machineID;
481 out_msg.WTRequestor := in_msg.Requestor;
482 out_msg.Destination.add(map_Address_to_Directory(address));
483 out_msg.MessageSize := MessageSizeType:Data;
484 out_msg.Type := CoherenceRequestType:WriteThrough;
485 out_msg.Dirty := true;
486 out_msg.DataBlk := in_msg.DataBlk;
487 out_msg.writeMask.orMask(in_msg.writeMask);
492 action(wb_writeBack, "wb", desc="write back data") {
493 enqueue(requestToNB_out, CPURequestMsg, l2_request_latency) {
494 out_msg.addr := address;
495 out_msg.Requestor := machineID;
496 out_msg.WTRequestor := machineID;
497 out_msg.Destination.add(map_Address_to_Directory(address));
498 out_msg.MessageSize := MessageSizeType:Data;
499 out_msg.Type := CoherenceRequestType:WriteThrough;
500 out_msg.Dirty := true;
501 out_msg.DataBlk := cache_entry.DataBlk;
502 out_msg.writeMask.orMask(cache_entry.writeMask);
506 action(at_atomicThrough, "at", desc="write back data") {
507 peek(coreRequestNetwork_in, CPURequestMsg) {
508 enqueue(requestToNB_out, CPURequestMsg, l2_request_latency) {
509 out_msg.addr := address;
510 out_msg.Requestor := machineID;
511 out_msg.WTRequestor := in_msg.Requestor;
512 out_msg.Destination.add(map_Address_to_Directory(address));
513 out_msg.MessageSize := MessageSizeType:Data;
514 out_msg.Type := CoherenceRequestType:Atomic;
515 out_msg.Dirty := true;
516 out_msg.writeMask.orMask(in_msg.writeMask);
521 action(pi_sendProbeResponseInv, "pi", desc="send probe ack inv, no data") {
522 enqueue(responseToNB_out, ResponseMsg, 1) {
523 out_msg.addr := address;
524 out_msg.Type := CoherenceResponseType:CPUPrbResp; // TCC, L3 respond in same way to probes
525 out_msg.Sender := machineID;
526 out_msg.Destination.add(map_Address_to_Directory(address));
527 out_msg.Dirty := false;
528 out_msg.Hit := false;
529 out_msg.Ntsl := true;
530 out_msg.State := CoherenceState:NA;
531 out_msg.MessageSize := MessageSizeType:Response_Control;
534 action(ut_updateTag, "ut", desc="update Tag (i.e. set MRU)") {
535 L2cache.setMRU(address);
538 action(p_popRequestQueue, "p", desc="pop request queue") {
539 coreRequestNetwork_in.dequeue(clockEdge());
542 action(pr_popResponseQueue, "pr", desc="pop response queue") {
543 responseFromNB_in.dequeue(clockEdge());
546 action(pp_popProbeQueue, "pp", desc="pop probe queue") {
547 probeNetwork_in.dequeue(clockEdge());
550 action(z_stall, "z", desc="stall") {
555 action(ina_incrementNumAtomics, "ina", desc="inc num atomics") {
556 tbe.numAtomics := tbe.numAtomics + 1;
560 action(dna_decrementNumAtomics, "dna", desc="inc num atomics") {
561 tbe.numAtomics := tbe.numAtomics - 1;
562 if (tbe.numAtomics==0) {
563 enqueue(triggerQueue_out, TriggerMsg, 1) {
564 out_msg.addr := address;
565 out_msg.Type := TriggerType:AtomicDone;
570 action(ptr_popTriggerQueue, "ptr", desc="pop Trigger") {
571 triggerQueue_in.dequeue(clockEdge());
577 // transitions from base
578 // Assumptions for ArrayRead/Write
579 // TBE checked before tags
580 // Data Read/Write requires Tag Read
582 // Stalling transitions do NOT check the tag array...and if they do,
583 // they can cause a resource stall deadlock!
585 transition(WI, {RdBlk, WrVicBlk, Atomic, WrVicBlkBack}) { //TagArrayRead} {
588 transition(A, {RdBlk, WrVicBlk, WrVicBlkBack}) { //TagArrayRead} {
591 transition(IV, {WrVicBlk, Atomic, WrVicBlkBack}) { //TagArrayRead} {
594 transition({M, V}, RdBlk) {TagArrayRead, DataArrayRead} {
599 transition(W, RdBlk, WI) {TagArrayRead, DataArrayRead} {
604 transition(I, RdBlk, IV) {TagArrayRead} {
610 transition(IV, RdBlk) {
616 transition({V, I},Atomic, A) {TagArrayRead} {
620 ina_incrementNumAtomics;
624 transition(A, Atomic) {
626 ina_incrementNumAtomics;
630 transition({M, W}, Atomic, WI) {TagArrayRead} {
635 transition(I, WrVicBlk) {TagArrayRead} {
640 transition(V, WrVicBlk) {TagArrayRead, DataArrayWrite} {
647 transition({V, M}, WrVicBlkBack, M) {TagArrayRead, TagArrayWrite, DataArrayWrite} {
654 transition(W, WrVicBlkBack) {TagArrayRead, TagArrayWrite, DataArrayWrite} {
661 transition(I, WrVicBlkBack, W) {TagArrayRead, TagArrayWrite, DataArrayWrite} {
669 transition({W, M}, L2_Repl, WI) {TagArrayRead, DataArrayRead} {
675 transition({I, V}, L2_Repl, I) {TagArrayRead, TagArrayWrite} {
679 transition({A, IV, WI}, L2_Repl) {
683 transition({I, V}, PrbInv, I) {TagArrayRead, TagArrayWrite} {
684 pi_sendProbeResponseInv;
688 transition(M, PrbInv, W) {TagArrayRead, TagArrayWrite} {
689 pi_sendProbeResponseInv;
693 transition(W, PrbInv) {TagArrayRead} {
694 pi_sendProbeResponseInv;
698 transition({A, IV, WI}, PrbInv) {
699 pi_sendProbeResponseInv;
703 transition(IV, Data, V) {TagArrayRead, TagArrayWrite, DataArrayWrite} {
707 sdr_sendDataResponse;
712 transition(A, Data) {TagArrayRead, TagArrayWrite, DataArrayWrite} {
714 ar_sendAtomicResponse;
715 dna_decrementNumAtomics;
719 transition(A, AtomicDone, I) {TagArrayRead, TagArrayWrite} {
724 transition(A, AtomicNotDone) {TagArrayRead} {
728 //M,W should not see WBAck as the cache is in WB mode
729 //WBAcks do not need to check tags
730 transition({I, V, IV, A}, WBAck) {
735 transition(WI, WBAck,I) {