2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * Copyright (c) 2009 Advanced Micro Devices, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * AMD's contributions to the MOESI hammer protocol do not constitute an
30 * endorsement of its similarity to any AMD products.
32 * Authors: Milo Martin
36 machine(L1Cache, "AMD Hammer-like protocol")
37 : Sequencer * sequencer,
38 CacheMemory * L1IcacheMemory,
39 CacheMemory * L1DcacheMemory,
40 CacheMemory * L2cacheMemory,
41 int cache_response_latency = 12,
46 MessageBuffer requestFromCache, network="To", virtual_network="3", ordered="false";
47 MessageBuffer responseFromCache, network="To", virtual_network="1", ordered="false";
48 MessageBuffer unblockFromCache, network="To", virtual_network="0", ordered="false";
50 MessageBuffer forwardToCache, network="From", virtual_network="2", ordered="false";
51 MessageBuffer responseToCache, network="From", virtual_network="1", ordered="false";
55 enumeration(State, desc="Cache states", default="L1Cache_State_I") {
60 M, desc="Modified (dirty)";
61 MM, desc="Modified (dirty and locally modified)";
64 IM, "IM", desc="Issued GetX";
65 SM, "SM", desc="Issued GetX, we still have an old copy of the line";
66 OM, "OM", desc="Issued GetX, received data";
67 ISM, "ISM", desc="Issued GetX, received data, waiting for all acks";
68 M_W, "M^W", desc="Issued GetS, received exclusive data";
69 MM_W, "MM^W", desc="Issued GetX, received exclusive data";
70 IS, "IS", desc="Issued GetS";
71 SS, "SS", desc="Issued GetS, received data, waiting for all acks";
72 OI, "OI", desc="Issued PutO, waiting for ack";
73 MI, "MI", desc="Issued PutX, waiting for ack";
74 II, "II", desc="Issued PutX/O, saw Other_GETS or Other_GETX, waiting for ack";
78 enumeration(Event, desc="Cache events") {
79 Load, desc="Load request from the processor";
80 Ifetch, desc="I-fetch request from the processor";
81 Store, desc="Store request from the processor";
82 L2_Replacement, desc="L2 Replacement";
83 L1_to_L2, desc="L1 to L2 transfer";
84 L2_to_L1D, desc="L2 to L1-Data transfer";
85 L2_to_L1I, desc="L2 to L1-Instruction transfer";
88 Other_GETX, desc="A GetX from another processor";
89 Other_GETS, desc="A GetS from another processor";
92 Ack, desc="Received an ack message";
93 Shared_Ack, desc="Received an ack message, responder has a shared copy";
94 Data, desc="Received a data message";
95 Shared_Data, desc="Received a data message, responder has a shared copy";
96 Exclusive_Data, desc="Received a data message, responder had an exclusive copy, they gave it to us";
98 Writeback_Ack, desc="Writeback O.K. from directory";
99 Writeback_Nack, desc="Writeback not O.K. from directory";
102 All_acks, desc="Received all required data and message acks";
103 All_acks_no_sharers, desc="Received all acks and no other processor has a shared copy";
108 // STRUCTURE DEFINITIONS
110 MessageBuffer mandatoryQueue, ordered="false";
113 structure(Entry, desc="...", interface="AbstractCacheEntry") {
114 State CacheState, desc="cache state";
115 bool Dirty, desc="Is the data dirty (different than memory)?";
116 DataBlock DataBlk, desc="data for the block";
120 structure(TBE, desc="...") {
121 State TBEState, desc="Transient state";
122 DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
123 bool Dirty, desc="Is the data dirty (different than memory)?";
124 int NumPendingMsgs, desc="Number of acks/data messages that this processor is waiting for";
125 bool Sharers, desc="On a GetS, did we find any other sharers in the system";
128 external_type(TBETable) {
130 void allocate(Address);
131 void deallocate(Address);
132 bool isPresent(Address);
135 TBETable TBEs, template_hack="<L1Cache_TBE>";
137 Entry getCacheEntry(Address addr), return_by_ref="yes" {
138 if (L2cacheMemory.isTagPresent(addr)) {
139 return static_cast(Entry, L2cacheMemory[addr]);
140 } else if (L1DcacheMemory.isTagPresent(addr)) {
141 return static_cast(Entry, L1DcacheMemory[addr]);
143 return static_cast(Entry, L1IcacheMemory[addr]);
147 void changePermission(Address addr, AccessPermission permission) {
148 if (L2cacheMemory.isTagPresent(addr)) {
149 return L2cacheMemory.changePermission(addr, permission);
150 } else if (L1DcacheMemory.isTagPresent(addr)) {
151 return L1DcacheMemory.changePermission(addr, permission);
153 return L1IcacheMemory.changePermission(addr, permission);
157 bool isCacheTagPresent(Address addr) {
158 return (L2cacheMemory.isTagPresent(addr) || L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
161 State getState(Address addr) {
162 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
163 assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
164 assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
166 if(TBEs.isPresent(addr)) {
167 return TBEs[addr].TBEState;
168 } else if (isCacheTagPresent(addr)) {
169 return getCacheEntry(addr).CacheState;
174 void setState(Address addr, State state) {
175 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
176 assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
177 assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
179 if (TBEs.isPresent(addr)) {
180 TBEs[addr].TBEState := state;
183 if (isCacheTagPresent(addr)) {
184 getCacheEntry(addr).CacheState := state;
187 if ((state == State:MM) ||
188 (state == State:MM_W)) {
189 changePermission(addr, AccessPermission:Read_Write);
190 } else if (state == State:S ||
193 state == State:M_W ||
195 state == State:ISM ||
198 changePermission(addr, AccessPermission:Read_Only);
200 changePermission(addr, AccessPermission:Invalid);
205 Event mandatory_request_type_to_event(CacheRequestType type) {
206 if (type == CacheRequestType:LD) {
208 } else if (type == CacheRequestType:IFETCH) {
210 } else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
213 error("Invalid CacheRequestType");
217 MessageBuffer triggerQueue, ordered="true";
221 out_port(requestNetwork_out, RequestMsg, requestFromCache);
222 out_port(responseNetwork_out, ResponseMsg, responseFromCache);
223 out_port(unblockNetwork_out, ResponseMsg, unblockFromCache);
224 out_port(triggerQueue_out, TriggerMsg, triggerQueue);
229 in_port(triggerQueue_in, TriggerMsg, triggerQueue) {
230 if (triggerQueue_in.isReady()) {
231 peek(triggerQueue_in, TriggerMsg) {
232 if (in_msg.Type == TriggerType:ALL_ACKS) {
233 trigger(Event:All_acks, in_msg.Address);
234 } else if (in_msg.Type == TriggerType:ALL_ACKS_NO_SHARERS) {
235 trigger(Event:All_acks_no_sharers, in_msg.Address);
237 error("Unexpected message");
243 // Nothing from the request network
246 in_port(forwardToCache_in, RequestMsg, forwardToCache) {
247 if (forwardToCache_in.isReady()) {
248 peek(forwardToCache_in, RequestMsg) {
249 if (in_msg.Type == CoherenceRequestType:GETX) {
250 trigger(Event:Other_GETX, in_msg.Address);
251 } else if (in_msg.Type == CoherenceRequestType:GETS) {
252 trigger(Event:Other_GETS, in_msg.Address);
253 } else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
254 trigger(Event:Writeback_Ack, in_msg.Address);
255 } else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
256 trigger(Event:Writeback_Nack, in_msg.Address);
258 error("Unexpected message");
265 in_port(responseToCache_in, ResponseMsg, responseToCache) {
266 if (responseToCache_in.isReady()) {
267 peek(responseToCache_in, ResponseMsg) {
268 if (in_msg.Type == CoherenceResponseType:ACK) {
269 trigger(Event:Ack, in_msg.Address);
270 } else if (in_msg.Type == CoherenceResponseType:ACK_SHARED) {
271 trigger(Event:Shared_Ack, in_msg.Address);
272 } else if (in_msg.Type == CoherenceResponseType:DATA) {
273 trigger(Event:Data, in_msg.Address);
274 } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
275 trigger(Event:Shared_Data, in_msg.Address);
276 } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
277 trigger(Event:Exclusive_Data, in_msg.Address);
279 error("Unexpected message");
285 // Nothing from the unblock network
288 in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
289 if (mandatoryQueue_in.isReady()) {
290 peek(mandatoryQueue_in, CacheMsg) {
292 // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
294 if (in_msg.Type == CacheRequestType:IFETCH) {
295 // ** INSTRUCTION ACCESS ***
297 // Check to see if it is in the OTHER L1
298 if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
299 // The block is in the wrong L1, try to write it to the L2
300 if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) {
301 trigger(Event:L1_to_L2, in_msg.LineAddress);
303 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.LineAddress));
307 if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
308 // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
309 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
311 if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) {
312 // L1 does't have the line, but we have space for it in the L1
313 if (L2cacheMemory.isTagPresent(in_msg.LineAddress)) {
314 // L2 has it (maybe not with the right permissions)
315 trigger(Event:L2_to_L1I, in_msg.LineAddress);
317 // We have room, the L2 doesn't have it, so the L1 fetches the line
318 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
321 // No room in the L1, so we need to make room
322 if (L2cacheMemory.cacheAvail(L1IcacheMemory.cacheProbe(in_msg.LineAddress))) {
323 // The L2 has room, so we move the line from the L1 to the L2
324 trigger(Event:L1_to_L2, L1IcacheMemory.cacheProbe(in_msg.LineAddress));
326 // The L2 does not have room, so we replace a line from the L2
327 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.LineAddress)));
332 // *** DATA ACCESS ***
334 // Check to see if it is in the OTHER L1
335 if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
336 // The block is in the wrong L1, try to write it to the L2
337 if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) {
338 trigger(Event:L1_to_L2, in_msg.LineAddress);
340 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.LineAddress));
344 if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
345 // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
346 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
348 if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) {
349 // L1 does't have the line, but we have space for it in the L1
350 if (L2cacheMemory.isTagPresent(in_msg.LineAddress)) {
351 // L2 has it (maybe not with the right permissions)
352 trigger(Event:L2_to_L1D, in_msg.LineAddress);
354 // We have room, the L2 doesn't have it, so the L1 fetches the line
355 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
358 // No room in the L1, so we need to make room
359 if (L2cacheMemory.cacheAvail(L1DcacheMemory.cacheProbe(in_msg.LineAddress))) {
360 // The L2 has room, so we move the line from the L1 to the L2
361 trigger(Event:L1_to_L2, L1DcacheMemory.cacheProbe(in_msg.LineAddress));
363 // The L2 does not have room, so we replace a line from the L2
364 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.LineAddress)));
375 action(a_issueGETS, "a", desc="Issue GETS") {
376 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
377 out_msg.Address := address;
378 out_msg.Type := CoherenceRequestType:GETS;
379 out_msg.Requestor := machineID;
380 out_msg.Destination.add(map_Address_to_Directory(address));
381 out_msg.MessageSize := MessageSizeType:Request_Control;
382 TBEs[address].NumPendingMsgs := getNumberOfLastLevelCaches(); // One from each other cache (n-1) plus the memory (+1)
386 action(b_issueGETX, "b", desc="Issue GETX") {
387 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
388 out_msg.Address := address;
389 out_msg.Type := CoherenceRequestType:GETX;
390 out_msg.Requestor := machineID;
391 out_msg.Destination.add(map_Address_to_Directory(address));
392 out_msg.MessageSize := MessageSizeType:Request_Control;
393 TBEs[address].NumPendingMsgs := getNumberOfLastLevelCaches(); // One from each other cache (n-1) plus the memory (+1)
397 action(c_sendExclusiveData, "c", desc="Send exclusive data from cache to requestor") {
398 peek(forwardToCache_in, RequestMsg) {
399 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
400 out_msg.Address := address;
401 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
402 out_msg.Sender := machineID;
403 out_msg.Destination.add(in_msg.Requestor);
404 out_msg.DataBlk := getCacheEntry(address).DataBlk;
405 out_msg.Dirty := getCacheEntry(address).Dirty;
407 out_msg.MessageSize := MessageSizeType:Response_Data;
412 action(d_issuePUT, "d", desc="Issue PUT") {
413 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
414 out_msg.Address := address;
415 out_msg.Type := CoherenceRequestType:PUT;
416 out_msg.Requestor := machineID;
417 out_msg.Destination.add(map_Address_to_Directory(address));
418 out_msg.MessageSize := MessageSizeType:Writeback_Control;
422 action(e_sendData, "e", desc="Send data from cache to requestor") {
423 peek(forwardToCache_in, RequestMsg) {
424 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
425 out_msg.Address := address;
426 out_msg.Type := CoherenceResponseType:DATA;
427 out_msg.Sender := machineID;
428 out_msg.Destination.add(in_msg.Requestor);
429 out_msg.DataBlk := getCacheEntry(address).DataBlk;
430 out_msg.Dirty := getCacheEntry(address).Dirty;
432 out_msg.MessageSize := MessageSizeType:Response_Data;
437 action(ee_sendDataShared, "\e", desc="Send data from cache to requestor, keep a shared copy") {
438 peek(forwardToCache_in, RequestMsg) {
439 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
440 out_msg.Address := address;
441 out_msg.Type := CoherenceResponseType:DATA_SHARED;
442 out_msg.Sender := machineID;
443 out_msg.Destination.add(in_msg.Requestor);
444 out_msg.DataBlk := getCacheEntry(address).DataBlk;
445 out_msg.Dirty := getCacheEntry(address).Dirty;
447 out_msg.MessageSize := MessageSizeType:Response_Data;
452 action(f_sendAck, "f", desc="Send ack from cache to requestor") {
453 peek(forwardToCache_in, RequestMsg) {
454 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
455 out_msg.Address := address;
456 out_msg.Type := CoherenceResponseType:ACK;
457 out_msg.Sender := machineID;
458 out_msg.Destination.add(in_msg.Requestor);
460 out_msg.MessageSize := MessageSizeType:Response_Control;
465 action(ff_sendAckShared, "\f", desc="Send shared ack from cache to requestor") {
466 peek(forwardToCache_in, RequestMsg) {
467 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
468 out_msg.Address := address;
469 out_msg.Type := CoherenceResponseType:ACK_SHARED;
470 out_msg.Sender := machineID;
471 out_msg.Destination.add(in_msg.Requestor);
473 out_msg.MessageSize := MessageSizeType:Response_Control;
478 action(g_sendUnblock, "g", desc="Send unblock to memory") {
479 enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) {
480 out_msg.Address := address;
481 out_msg.Type := CoherenceResponseType:UNBLOCK;
482 out_msg.Sender := machineID;
483 out_msg.Destination.add(map_Address_to_Directory(address));
484 out_msg.MessageSize := MessageSizeType:Unblock_Control;
488 action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
489 DEBUG_EXPR(getCacheEntry(address).DataBlk);
490 sequencer.readCallback(address, getCacheEntry(address).DataBlk);
493 action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
494 DEBUG_EXPR(getCacheEntry(address).DataBlk);
495 sequencer.writeCallback(address, getCacheEntry(address).DataBlk);
496 getCacheEntry(address).Dirty := true;
499 action(i_allocateTBE, "i", desc="Allocate TBE") {
500 check_allocate(TBEs);
501 TBEs.allocate(address);
502 TBEs[address].DataBlk := getCacheEntry(address).DataBlk; // Data only used for writebacks
503 TBEs[address].Dirty := getCacheEntry(address).Dirty;
504 TBEs[address].Sharers := false;
507 action(j_popTriggerQueue, "j", desc="Pop trigger queue.") {
508 triggerQueue_in.dequeue();
511 action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
512 mandatoryQueue_in.dequeue();
515 action(l_popForwardQueue, "l", desc="Pop forwareded request queue.") {
516 forwardToCache_in.dequeue();
519 action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") {
520 peek(responseToCache_in, ResponseMsg) {
521 assert(in_msg.Acks > 0);
522 DEBUG_EXPR(TBEs[address].NumPendingMsgs);
523 TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks;
524 DEBUG_EXPR(TBEs[address].NumPendingMsgs);
528 action(n_popResponseQueue, "n", desc="Pop response queue") {
529 responseToCache_in.dequeue();
532 action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
533 if (TBEs[address].NumPendingMsgs == 0) {
534 enqueue(triggerQueue_out, TriggerMsg) {
535 out_msg.Address := address;
536 if (TBEs[address].Sharers) {
537 out_msg.Type := TriggerType:ALL_ACKS;
539 out_msg.Type := TriggerType:ALL_ACKS_NO_SHARERS;
545 action(p_decrementNumberOfMessagesByOne, "p", desc="Decrement the number of messages for which we're waiting by one") {
546 TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - 1;
549 action(pp_incrementNumberOfMessagesByOne, "\p", desc="Increment the number of messages for which we're waiting by one") {
550 TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs + 1;
553 action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") {
554 peek(forwardToCache_in, RequestMsg) {
555 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
556 out_msg.Address := address;
557 out_msg.Type := CoherenceResponseType:DATA;
558 out_msg.Sender := machineID;
559 out_msg.Destination.add(in_msg.Requestor);
560 out_msg.DataBlk := TBEs[address].DataBlk;
561 out_msg.Dirty := TBEs[address].Dirty;
563 out_msg.MessageSize := MessageSizeType:Response_Data;
568 action(qq_sendDataFromTBEToMemory, "\q", desc="Send data from TBE to memory") {
569 enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) {
570 out_msg.Address := address;
571 out_msg.Sender := machineID;
572 out_msg.Destination.add(map_Address_to_Directory(address));
573 out_msg.Dirty := TBEs[address].Dirty;
574 if (TBEs[address].Dirty) {
575 out_msg.Type := CoherenceResponseType:WB_DIRTY;
576 out_msg.DataBlk := TBEs[address].DataBlk;
577 out_msg.MessageSize := MessageSizeType:Writeback_Data;
579 out_msg.Type := CoherenceResponseType:WB_CLEAN;
580 // NOTE: in a real system this would not send data. We send
581 // data here only so we can check it at the memory
582 out_msg.DataBlk := TBEs[address].DataBlk;
583 out_msg.MessageSize := MessageSizeType:Writeback_Control;
588 action(r_setSharerBit, "r", desc="We saw other sharers") {
589 TBEs[address].Sharers := true;
592 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
593 TBEs.deallocate(address);
596 action(t_sendExclusiveDataFromTBEToMemory, "t", desc="Send exclusive data from TBE to memory") {
597 enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) {
598 out_msg.Address := address;
599 out_msg.Sender := machineID;
600 out_msg.Destination.add(map_Address_to_Directory(address));
601 out_msg.DataBlk := TBEs[address].DataBlk;
602 out_msg.Dirty := TBEs[address].Dirty;
603 if (TBEs[address].Dirty) {
604 out_msg.Type := CoherenceResponseType:WB_EXCLUSIVE_DIRTY;
605 out_msg.DataBlk := TBEs[address].DataBlk;
606 out_msg.MessageSize := MessageSizeType:Writeback_Data;
608 out_msg.Type := CoherenceResponseType:WB_EXCLUSIVE_CLEAN;
609 // NOTE: in a real system this would not send data. We send
610 // data here only so we can check it at the memory
611 out_msg.DataBlk := TBEs[address].DataBlk;
612 out_msg.MessageSize := MessageSizeType:Writeback_Control;
617 action(u_writeDataToCache, "u", desc="Write data to cache") {
618 peek(responseToCache_in, ResponseMsg) {
619 getCacheEntry(address).DataBlk := in_msg.DataBlk;
620 getCacheEntry(address).Dirty := in_msg.Dirty;
624 action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") {
625 peek(responseToCache_in, ResponseMsg) {
626 assert(getCacheEntry(address).DataBlk == in_msg.DataBlk);
627 getCacheEntry(address).DataBlk := in_msg.DataBlk;
628 getCacheEntry(address).Dirty := in_msg.Dirty;
632 action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
633 if (L1DcacheMemory.isTagPresent(address)) {
634 L1DcacheMemory.deallocate(address);
636 L1IcacheMemory.deallocate(address);
640 action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
641 if (L1DcacheMemory.isTagPresent(address) == false) {
642 L1DcacheMemory.allocate(address, new Entry);
646 action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") {
647 if (L1IcacheMemory.isTagPresent(address) == false) {
648 L1IcacheMemory.allocate(address, new Entry);
652 action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
653 L2cacheMemory.allocate(address, new Entry);
656 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
657 L2cacheMemory.deallocate(address);
660 action(ss_copyFromL1toL2, "\s", desc="Copy data block from L1 (I or D) to L2") {
661 if (L1DcacheMemory.isTagPresent(address)) {
662 static_cast(Entry, L2cacheMemory[address]).Dirty := static_cast(Entry, L1DcacheMemory[address]).Dirty;
663 static_cast(Entry, L2cacheMemory[address]).DataBlk := static_cast(Entry, L1DcacheMemory[address]).DataBlk;
665 static_cast(Entry, L2cacheMemory[address]).Dirty := static_cast(Entry, L1IcacheMemory[address]).Dirty;
666 static_cast(Entry, L2cacheMemory[address]).DataBlk := static_cast(Entry, L1IcacheMemory[address]).DataBlk;
670 action(tt_copyFromL2toL1, "\t", desc="Copy data block from L2 to L1 (I or D)") {
671 if (L1DcacheMemory.isTagPresent(address)) {
672 static_cast(Entry, L1DcacheMemory[address]).Dirty := static_cast(Entry, L2cacheMemory[address]).Dirty;
673 static_cast(Entry, L1DcacheMemory[address]).DataBlk := static_cast(Entry, L2cacheMemory[address]).DataBlk;
675 static_cast(Entry, L1IcacheMemory[address]).Dirty := static_cast(Entry, L2cacheMemory[address]).Dirty;
676 static_cast(Entry, L1IcacheMemory[address]).DataBlk := static_cast(Entry, L2cacheMemory[address]).DataBlk;
680 action(uu_profileMiss, "\u", desc="Profile the demand miss") {
681 peek(mandatoryQueue_in, CacheMsg) {
682 if (L1IcacheMemory.isTagPresent(address)) {
683 L1IcacheMemory.profileMiss(in_msg);
684 } else if (L1DcacheMemory.isTagPresent(address)) {
685 L1DcacheMemory.profileMiss(in_msg);
687 L2cacheMemory.profileMiss(in_msg);
692 action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
693 mandatoryQueue_in.recycle();
696 //*****************************************************
698 //*****************************************************
700 // Transitions for Load/Store/L2_Replacement from transient states
701 transition({IM, SM, ISM, OM, IS, SS, OI, MI, II}, {Store, L2_Replacement}) {
702 zz_recycleMandatoryQueue;
705 transition({M_W, MM_W}, {L2_Replacement}) {
706 zz_recycleMandatoryQueue;
709 transition({IM, IS, OI, MI, II}, {Load, Ifetch}) {
710 zz_recycleMandatoryQueue;
713 transition({IM, SM, ISM, OM, IS, SS, MM_W, M_W, OI, MI, II}, L1_to_L2) {
714 zz_recycleMandatoryQueue;
717 // Transitions moving data between the L1 and L2 caches
718 transition({I, S, O, M, MM}, L1_to_L2) {
719 vv_allocateL2CacheBlock;
720 ss_copyFromL1toL2; // Not really needed for state I
721 gg_deallocateL1CacheBlock;
724 transition({I, S, O, M, MM}, L2_to_L1D) {
725 ii_allocateL1DCacheBlock;
726 tt_copyFromL2toL1; // Not really needed for state I
727 rr_deallocateL2CacheBlock;
730 transition({I, S, O, M, MM}, L2_to_L1I) {
731 jj_allocateL1ICacheBlock;
732 tt_copyFromL2toL1; // Not really needed for state I
733 rr_deallocateL2CacheBlock;
736 // Transitions from Idle
737 transition(I, Load, IS) {
738 ii_allocateL1DCacheBlock;
745 transition(I, Ifetch, IS) {
746 jj_allocateL1ICacheBlock;
753 transition(I, Store, IM) {
754 ii_allocateL1DCacheBlock;
761 transition(I, L2_Replacement) {
762 rr_deallocateL2CacheBlock;
765 transition(I, {Other_GETX, Other_GETS}) {
770 // Transitions from Shared
771 transition({S, SM, ISM}, {Load, Ifetch}) {
776 transition(S, Store, SM) {
783 transition(S, L2_Replacement, I) {
784 rr_deallocateL2CacheBlock;
787 transition(S, Other_GETX, I) {
792 transition(S, Other_GETS) {
797 // Transitions from Owned
798 transition({O, OM, SS, MM_W, M_W}, {Load, Ifetch}) {
803 transition(O, Store, OM) {
806 p_decrementNumberOfMessagesByOne;
811 transition(O, L2_Replacement, OI) {
814 rr_deallocateL2CacheBlock;
817 transition(O, Other_GETX, I) {
822 transition(O, Other_GETS) {
827 // Transitions from Modified
828 transition(MM, {Load, Ifetch}) {
833 transition(MM, Store) {
838 transition(MM, L2_Replacement, MI) {
841 rr_deallocateL2CacheBlock;
844 transition(MM, Other_GETX, I) {
849 transition(MM, Other_GETS, I) {
854 // Transitions from Dirty Exclusive
855 transition(M, {Load, Ifetch}) {
860 transition(M, Store, MM) {
865 transition(M, L2_Replacement, MI) {
868 rr_deallocateL2CacheBlock;
871 transition(M, Other_GETX, I) {
876 transition(M, Other_GETS, O) {
881 // Transitions from IM
883 transition(IM, {Other_GETX, Other_GETS}) {
888 transition(IM, Ack) {
889 m_decrementNumberOfMessages;
890 o_checkForCompletion;
894 transition(IM, Data, ISM) {
896 m_decrementNumberOfMessages;
897 o_checkForCompletion;
901 transition(IM, Exclusive_Data, MM_W) {
903 m_decrementNumberOfMessages;
904 o_checkForCompletion;
909 // Transitions from SM
910 transition(SM, Other_GETS) {
915 transition(SM, Other_GETX, IM) {
920 transition(SM, Ack) {
921 m_decrementNumberOfMessages;
922 o_checkForCompletion;
926 transition(SM, Data, ISM) {
927 v_writeDataToCacheVerify;
928 m_decrementNumberOfMessages;
929 o_checkForCompletion;
933 // Transitions from ISM
934 transition(ISM, Ack) {
935 m_decrementNumberOfMessages;
936 o_checkForCompletion;
940 transition(ISM, All_acks_no_sharers, MM) {
947 // Transitions from OM
949 transition(OM, Other_GETX, IM) {
951 pp_incrementNumberOfMessagesByOne;
955 transition(OM, Other_GETS) {
960 transition(OM, Ack) {
961 m_decrementNumberOfMessages;
962 o_checkForCompletion;
966 transition(OM, {All_acks, All_acks_no_sharers}, MM) {
973 // Transitions from IS
975 transition(IS, {Other_GETX, Other_GETS}) {
980 transition(IS, Ack) {
981 m_decrementNumberOfMessages;
982 o_checkForCompletion;
986 transition(IS, Shared_Ack) {
987 m_decrementNumberOfMessages;
989 o_checkForCompletion;
993 transition(IS, Data, SS) {
995 m_decrementNumberOfMessages;
996 o_checkForCompletion;
1001 transition(IS, Exclusive_Data, M_W) {
1003 m_decrementNumberOfMessages;
1004 o_checkForCompletion;
1009 transition(IS, Shared_Data, SS) {
1012 m_decrementNumberOfMessages;
1013 o_checkForCompletion;
1018 // Transitions from SS
1020 transition(SS, Ack) {
1021 m_decrementNumberOfMessages;
1022 o_checkForCompletion;
1026 transition(SS, Shared_Ack) {
1027 m_decrementNumberOfMessages;
1029 o_checkForCompletion;
1033 transition(SS, All_acks, S) {
1039 transition(SS, All_acks_no_sharers, S) {
1040 // Note: The directory might still be the owner, so that is why we go to S
1046 // Transitions from MM_W
1048 transition(MM_W, Store) {
1050 k_popMandatoryQueue;
1053 transition(MM_W, Ack) {
1054 m_decrementNumberOfMessages;
1055 o_checkForCompletion;
1059 transition(MM_W, All_acks_no_sharers, MM) {
1065 // Transitions from M_W
1067 transition(M_W, Store, MM_W) {
1069 k_popMandatoryQueue;
1072 transition(M_W, Ack) {
1073 m_decrementNumberOfMessages;
1074 o_checkForCompletion;
1078 transition(M_W, All_acks_no_sharers, M) {
1084 // Transitions from OI/MI
1086 transition({OI, MI}, Other_GETX, II) {
1087 q_sendDataFromTBEToCache;
1091 transition({OI, MI}, Other_GETS, OI) {
1092 q_sendDataFromTBEToCache;
1096 transition(MI, Writeback_Ack, I) {
1097 t_sendExclusiveDataFromTBEToMemory;
1102 transition(OI, Writeback_Ack, I) {
1103 qq_sendDataFromTBEToMemory;
1108 // Transitions from II
1109 transition(II, {Other_GETS, Other_GETX}, II) {
1114 transition(II, Writeback_Ack, I) {
1120 transition(II, Writeback_Nack, I) {