3 * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
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.
31 * $Id: MSI_MOSI_CMP_directory-L2cache.sm 1.12 05/01/19 15:55:40-06:00 beckmann@s0-28.cs.wisc.edu $
35 machine(L2Cache, "MESI Directory L2 Cache CMP")
36 : CacheMemory * L2cacheMemory,
37 int l2_request_latency = 2,
38 int l2_response_latency = 2,
42 // From local bank of L2 cache TO the network
43 MessageBuffer DirRequestFromL2Cache, network="To", virtual_network="0", ordered="false"; // this L2 bank -> Memory
44 MessageBuffer L1RequestFromL2Cache, network="To", virtual_network="0", ordered="false"; // this L2 bank -> a local L1
45 MessageBuffer responseFromL2Cache, network="To", virtual_network="1", ordered="false"; // this L2 bank -> a local L1 || Memory
47 // FROM the network to this local bank of L2 cache
48 MessageBuffer unblockToL2Cache, network="From", virtual_network="2", ordered="false"; // a local L1 || Memory -> this L2 bank
49 MessageBuffer L1RequestToL2Cache, network="From", virtual_network="0", ordered="false"; // a local L1 -> this L2 bank
50 MessageBuffer responseToL2Cache, network="From", virtual_network="1", ordered="false"; // a local L1 || Memory -> this L2 bank
51 // MessageBuffer unblockToL2Cache, network="From", virtual_network="4", ordered="false"; // a local L1 || Memory -> this L2 bank
54 enumeration(State, desc="L2 Cache states", default="L2Cache_State_NP") {
56 NP, desc="Not present in either cache";
57 SS, desc="L2 cache entry Shared, also present in one or more L1s";
58 M, desc="L2 cache entry Modified, not present in any L1s", format="!b";
59 MT, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
62 M_I, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
63 MT_I, desc="L2 cache replacing, getting data from exclusive";
64 MCT_I, desc="L2 cache replacing, clean in L2, getting data or ack from exclusive";
65 I_I, desc="L2 replacing clean data, need to inv sharers and then drop data";
66 S_I, desc="L2 replacing dirty data, collecting acks from L1s";
68 // Transient States for fetching data from memory
69 ISS, desc="L2 idle, got single L1_GETS, issued memory fetch, have not seen response yet";
70 IS, desc="L2 idle, got L1_GET_INSTR or multiple L1_GETS, issued memory fetch, have not seen response yet";
71 IM, desc="L2 idle, got L1_GETX, issued memory fetch, have not seen response(s) yet";
74 SS_MB, desc="Blocked for L1_GETX from SS";
75 MT_MB, desc="Blocked for L1_GETX from MT";
76 M_MB, desc="Blocked for L1_GETX from M";
78 MT_IIB, desc="Blocked for L1_GETS from MT, waiting for unblock and data";
79 MT_IB, desc="Blocked for L1_GETS from MT, got unblock, waiting for data";
80 MT_SB, desc="Blocked for L1_GETS from MT, got data, waiting for unblock";
85 enumeration(Event, desc="L2 Cache events") {
88 // events initiated by the local L1s
89 L1_GET_INSTR, desc="a L1I GET INSTR request for a block maped to us";
90 L1_GETS, desc="a L1D GETS request for a block maped to us";
91 L1_GETX, desc="a L1D GETX request for a block maped to us";
92 L1_UPGRADE, desc="a L1D GETX request for a block maped to us";
94 L1_PUTX, desc="L1 replacing data";
95 L1_PUTX_old, desc="L1 replacing data, but no longer sharer";
97 Fwd_L1_GETX, desc="L1 did not have data, so we supply";
98 Fwd_L1_GETS, desc="L1 did not have data, so we supply";
99 Fwd_L1_GET_INSTR, desc="L1 did not have data, so we supply";
101 // events initiated by this L2
102 L2_Replacement, desc="L2 Replacement", format="!r";
103 L2_Replacement_clean, desc="L2 Replacement, but data is clean", format="!r";
105 // events from memory controller
106 Mem_Data, desc="data from memory", format="!r";
107 Mem_Ack, desc="ack from memory", format="!r";
109 // M->S data writeback
110 WB_Data, desc="data from L1";
111 WB_Data_clean, desc="clean data from L1";
112 Ack, desc="writeback ack";
113 Ack_all, desc="writeback ack";
115 Unblock, desc="Unblock from L1 requestor";
116 Unblock_Cancel, desc="Unblock from L1 requestor (FOR XACT MEMORY)";
117 Exclusive_Unblock, desc="Unblock from L1 requestor";
119 MEM_Inv, desc="Invalidation from directory";
126 structure(Entry, desc="...", interface="AbstractCacheEntry") {
127 State CacheState, desc="cache state";
128 NetDest Sharers, desc="tracks the L1 shares on-chip";
129 MachineID Exclusive, desc="Exclusive holder of block";
130 DataBlock DataBlk, desc="data for the block";
131 bool Dirty, default="false", desc="data is dirty";
135 structure(TBE, desc="...") {
136 Address Address, desc="Physical address for this TBE";
137 State TBEState, desc="Transient state";
138 DataBlock DataBlk, desc="Buffer for the data block";
139 bool Dirty, default="false", desc="Data is Dirty";
141 NetDest L1_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
142 MachineID L1_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
143 bool isPrefetch, desc="Set if this was caused by a prefetch";
145 int pendingAcks, desc="number of pending acks for invalidates during writeback";
148 external_type(TBETable) {
150 void allocate(Address);
151 void deallocate(Address);
152 bool isPresent(Address);
155 TBETable L2_TBEs, template_hack="<L2Cache_TBE>";
157 void set_cache_entry(AbstractCacheEntry a);
158 void unset_cache_entry();
162 // inclusive cache, returns L2 entries only
163 Entry getCacheEntry(Address addr), return_by_pointer="yes" {
164 return static_cast(Entry, "pointer", L2cacheMemory[addr]);
167 std::string getCoherenceRequestTypeStr(CoherenceRequestType type) {
168 return CoherenceRequestType_to_string(type);
171 bool isOneSharerLeft(Address addr, MachineID requestor, Entry cache_entry) {
172 assert(is_valid(cache_entry));
173 assert(cache_entry.Sharers.isElement(requestor));
174 return (cache_entry.Sharers.count() == 1);
177 bool isSharer(Address addr, MachineID requestor, Entry cache_entry) {
178 if (is_valid(cache_entry)) {
179 return cache_entry.Sharers.isElement(requestor);
185 void addSharer(Address addr, MachineID requestor, Entry cache_entry) {
186 assert(is_valid(cache_entry));
187 DPRINTF(RubySlicc, "machineID: %s, requestor: %s, address: %s\n",
188 machineID, requestor, addr);
189 cache_entry.Sharers.add(requestor);
192 State getState(TBE tbe, Entry cache_entry, Address addr) {
195 } else if (is_valid(cache_entry)) {
196 return cache_entry.CacheState;
201 std::string getStateStr(TBE tbe, Entry cache_entry, Address addr) {
202 return L2Cache_State_to_string(getState(tbe, cache_entry, addr));
205 // when is this called
206 void setState(TBE tbe, Entry cache_entry, Address addr, State state) {
210 tbe.TBEState := state;
213 if (is_valid(cache_entry)) {
214 cache_entry.CacheState := state;
217 if (state == State:SS ) {
218 cache_entry.changePermission(AccessPermission:Read_Only);
219 } else if (state == State:M) {
220 cache_entry.changePermission(AccessPermission:Read_Write);
221 } else if (state == State:MT) {
222 cache_entry.changePermission(AccessPermission:Stale);
224 cache_entry.changePermission(AccessPermission:Busy);
229 Event L1Cache_request_type_to_event(CoherenceRequestType type, Address addr,
230 MachineID requestor, Entry cache_entry) {
231 if(type == CoherenceRequestType:GETS) {
232 return Event:L1_GETS;
233 } else if(type == CoherenceRequestType:GET_INSTR) {
234 return Event:L1_GET_INSTR;
235 } else if (type == CoherenceRequestType:GETX) {
236 return Event:L1_GETX;
237 } else if (type == CoherenceRequestType:UPGRADE) {
238 if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) {
239 return Event:L1_UPGRADE;
241 return Event:L1_GETX;
243 } else if (type == CoherenceRequestType:PUTX) {
244 if (isSharer(addr, requestor, cache_entry)) {
245 return Event:L1_PUTX;
247 return Event:L1_PUTX_old;
250 DPRINTF(RubySlicc, "address: %s, Request Type: %s\n", addr, type);
251 error("Invalid L1 forwarded request type");
255 int getPendingAcks(TBE tbe) {
256 return tbe.pendingAcks;
259 bool isDirty(Entry cache_entry) {
260 assert(is_valid(cache_entry));
261 return cache_entry.Dirty;
266 out_port(L1RequestIntraChipL2Network_out, RequestMsg, L1RequestFromL2Cache);
267 out_port(DirRequestIntraChipL2Network_out, RequestMsg, DirRequestFromL2Cache);
268 out_port(responseIntraChipL2Network_out, ResponseMsg, responseFromL2Cache);
271 in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache) {
272 if(L1unblockNetwork_in.isReady()) {
273 peek(L1unblockNetwork_in, ResponseMsg) {
274 Entry cache_entry := getCacheEntry(in_msg.Address);
275 TBE tbe := L2_TBEs[in_msg.Address];
276 DPRINTF(RubySlicc, "Addr: %s State: %s Sender: %s Type: %s Dest: %s\n",
277 in_msg.Address, getState(tbe, cache_entry, in_msg.Address),
278 in_msg.Sender, in_msg.Type, in_msg.Destination);
280 assert(in_msg.Destination.isElement(machineID));
281 if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) {
282 trigger(Event:Exclusive_Unblock, in_msg.Address, cache_entry, tbe);
283 } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
284 trigger(Event:Unblock, in_msg.Address, cache_entry, tbe);
286 error("unknown unblock message");
292 // Response IntraChip L2 Network - response msg to this particular L2 bank
293 in_port(responseIntraChipL2Network_in, ResponseMsg, responseToL2Cache) {
294 if (responseIntraChipL2Network_in.isReady()) {
295 peek(responseIntraChipL2Network_in, ResponseMsg) {
296 // test wether it's from a local L1 or an off chip source
297 assert(in_msg.Destination.isElement(machineID));
298 Entry cache_entry := getCacheEntry(in_msg.Address);
299 TBE tbe := L2_TBEs[in_msg.Address];
301 if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
302 if(in_msg.Type == CoherenceResponseType:DATA) {
304 trigger(Event:WB_Data, in_msg.Address, cache_entry, tbe);
306 trigger(Event:WB_Data_clean, in_msg.Address, cache_entry, tbe);
308 } else if (in_msg.Type == CoherenceResponseType:ACK) {
309 if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) {
310 trigger(Event:Ack_all, in_msg.Address, cache_entry, tbe);
312 trigger(Event:Ack, in_msg.Address, cache_entry, tbe);
315 error("unknown message type");
318 } else { // external message
319 if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
320 // L2 now has data and all off-chip acks
321 trigger(Event:Mem_Data, in_msg.Address, cache_entry, tbe);
322 } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) {
323 // L2 now has data and all off-chip acks
324 trigger(Event:Mem_Ack, in_msg.Address, cache_entry, tbe);
325 } else if(in_msg.Type == CoherenceResponseType:INV) {
326 // L2 now has data and all off-chip acks
327 trigger(Event:MEM_Inv, in_msg.Address, cache_entry, tbe);
329 error("unknown message type");
333 } // if not ready, do nothing
337 in_port(L1RequestIntraChipL2Network_in, RequestMsg, L1RequestToL2Cache) {
338 if(L1RequestIntraChipL2Network_in.isReady()) {
339 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
340 Entry cache_entry := getCacheEntry(in_msg.Address);
341 TBE tbe := L2_TBEs[in_msg.Address];
343 DPRINTF(RubySlicc, "Addr: %s State: %s Req: %s Type: %s Dest: %s\n",
344 in_msg.Address, getState(tbe, cache_entry, in_msg.Address),
345 in_msg.Requestor, in_msg.Type, in_msg.Destination);
347 assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache);
348 assert(in_msg.Destination.isElement(machineID));
350 if (is_valid(cache_entry)) {
351 // The L2 contains the block, so proceeded with handling the request
352 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address,
353 in_msg.Requestor, cache_entry),
354 in_msg.Address, cache_entry, tbe);
356 if (L2cacheMemory.cacheAvail(in_msg.Address)) {
357 // L2 does't have the line, but we have space for it in the L2
358 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address,
359 in_msg.Requestor, cache_entry),
360 in_msg.Address, cache_entry, tbe);
362 // No room in the L2, so we need to make room before handling the request
363 Entry L2cache_entry := getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address));
364 if (isDirty(L2cache_entry)) {
365 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address),
366 L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]);
368 trigger(Event:L2_Replacement_clean, L2cacheMemory.cacheProbe(in_msg.Address),
369 L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]);
380 action(a_issueFetchToMemory, "a", desc="fetch data from memory") {
381 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
382 enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency=l2_request_latency) {
383 out_msg.Address := address;
384 out_msg.Type := CoherenceRequestType:GETS;
385 out_msg.Requestor := machineID;
386 out_msg.Destination.add(map_Address_to_Directory(address));
387 out_msg.MessageSize := MessageSizeType:Control;
392 action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") {
393 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
394 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
395 assert(is_valid(cache_entry));
396 out_msg.Address := address;
397 out_msg.Type := in_msg.Type;
398 out_msg.Requestor := in_msg.Requestor;
399 out_msg.Destination.add(cache_entry.Exclusive);
400 out_msg.MessageSize := MessageSizeType:Request_Control;
405 action(c_exclusiveReplacement, "c", desc="Send data to memory") {
406 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
407 assert(is_valid(cache_entry));
408 out_msg.Address := address;
409 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
410 out_msg.Sender := machineID;
411 out_msg.Destination.add(map_Address_to_Directory(address));
412 out_msg.DataBlk := cache_entry.DataBlk;
413 out_msg.Dirty := cache_entry.Dirty;
414 out_msg.MessageSize := MessageSizeType:Response_Data;
418 action(c_exclusiveCleanReplacement, "cc", desc="Send ack to memory for clean replacement") {
419 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
420 out_msg.Address := address;
421 out_msg.Type := CoherenceResponseType:ACK;
422 out_msg.Sender := machineID;
423 out_msg.Destination.add(map_Address_to_Directory(address));
424 out_msg.MessageSize := MessageSizeType:Response_Control;
428 action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") {
429 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
430 assert(is_valid(tbe));
431 out_msg.Address := address;
432 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
433 out_msg.Sender := machineID;
434 out_msg.Destination.add(map_Address_to_Directory(address));
435 out_msg.DataBlk := tbe.DataBlk;
436 out_msg.Dirty := tbe.Dirty;
437 out_msg.MessageSize := MessageSizeType:Response_Data;
441 action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") {
442 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
443 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
444 assert(is_valid(cache_entry));
445 out_msg.Address := address;
446 out_msg.Type := CoherenceResponseType:DATA;
447 out_msg.Sender := machineID;
448 out_msg.Destination.add(in_msg.Requestor);
449 out_msg.DataBlk := cache_entry.DataBlk;
450 out_msg.Dirty := cache_entry.Dirty;
451 out_msg.MessageSize := MessageSizeType:Response_Data;
453 out_msg.AckCount := 0 - cache_entry.Sharers.count();
454 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
455 out_msg.AckCount := out_msg.AckCount + 1;
461 action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") {
462 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
463 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
464 assert(is_valid(cache_entry));
465 out_msg.Address := address;
466 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
467 out_msg.Sender := machineID;
468 out_msg.Destination.add(in_msg.Requestor);
469 out_msg.DataBlk := cache_entry.DataBlk;
470 out_msg.Dirty := cache_entry.Dirty;
471 out_msg.MessageSize := MessageSizeType:Response_Data;
473 out_msg.AckCount := 0 - cache_entry.Sharers.count();
474 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
475 out_msg.AckCount := out_msg.AckCount + 1;
481 action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") {
482 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
483 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
484 assert(is_valid(cache_entry));
485 out_msg.Address := address;
486 out_msg.Type := CoherenceResponseType:DATA;
487 out_msg.Sender := machineID;
488 out_msg.Destination.add(in_msg.Requestor);
489 out_msg.DataBlk := cache_entry.DataBlk;
490 out_msg.Dirty := cache_entry.Dirty;
491 out_msg.MessageSize := MessageSizeType:Response_Data;
492 out_msg.AckCount := 0;
497 action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") {
498 assert(is_valid(tbe));
499 assert(tbe.L1_GetS_IDs.count() > 0);
500 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
501 assert(is_valid(cache_entry));
502 out_msg.Address := address;
503 out_msg.Type := CoherenceResponseType:DATA;
504 out_msg.Sender := machineID;
505 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
506 out_msg.DataBlk := cache_entry.DataBlk;
507 out_msg.Dirty := cache_entry.Dirty;
508 out_msg.MessageSize := MessageSizeType:Response_Data;
512 action(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") {
513 assert(is_valid(tbe));
514 assert(tbe.L1_GetS_IDs.count() == 1);
515 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
516 assert(is_valid(cache_entry));
517 out_msg.Address := address;
518 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
519 out_msg.Sender := machineID;
520 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
521 out_msg.DataBlk := cache_entry.DataBlk;
522 out_msg.Dirty := cache_entry.Dirty;
523 out_msg.MessageSize := MessageSizeType:Response_Data;
527 action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") {
528 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
529 assert(is_valid(tbe));
530 assert(is_valid(cache_entry));
531 out_msg.Address := address;
532 out_msg.Type := CoherenceResponseType:DATA;
533 out_msg.Sender := machineID;
534 out_msg.Destination.add(tbe.L1_GetX_ID);
535 DPRINTF(RubySlicc, "%s\n", out_msg.Destination);
536 out_msg.DataBlk := cache_entry.DataBlk;
537 out_msg.Dirty := cache_entry.Dirty;
538 DPRINTF(RubySlicc, "Address: %s, Destination: %s, DataBlock: %s\n",
539 out_msg.Address, out_msg.Destination, out_msg.DataBlk);
540 out_msg.MessageSize := MessageSizeType:Response_Data;
544 action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") {
545 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
546 assert(is_valid(cache_entry));
547 out_msg.Address := address;
548 out_msg.Type := CoherenceRequestType:INV;
549 out_msg.Requestor := machineID;
550 out_msg.Destination := cache_entry.Sharers;
551 out_msg.MessageSize := MessageSizeType:Request_Control;
555 action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") {
556 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
557 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
558 assert(is_valid(cache_entry));
559 out_msg.Address := address;
560 out_msg.Type := CoherenceRequestType:INV;
561 out_msg.Requestor := in_msg.Requestor;
562 out_msg.Destination := cache_entry.Sharers;
563 out_msg.MessageSize := MessageSizeType:Request_Control;
568 action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") {
569 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
570 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
571 assert(is_valid(cache_entry));
572 out_msg.Address := address;
573 out_msg.Type := CoherenceRequestType:INV;
574 out_msg.Requestor := in_msg.Requestor;
575 out_msg.Destination := cache_entry.Sharers;
576 out_msg.Destination.remove(in_msg.Requestor);
577 out_msg.MessageSize := MessageSizeType:Request_Control;
583 action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") {
584 check_allocate(L2_TBEs);
585 assert(is_valid(cache_entry));
586 L2_TBEs.allocate(address);
587 set_tbe(L2_TBEs[address]);
588 tbe.L1_GetS_IDs.clear();
589 tbe.DataBlk := cache_entry.DataBlk;
590 tbe.Dirty := cache_entry.Dirty;
591 tbe.pendingAcks := cache_entry.Sharers.count();
594 action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
595 L2_TBEs.deallocate(address);
598 action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
599 profileMsgDelay(0, L1RequestIntraChipL2Network_in.dequeue_getDelayCycles());
602 action(k_popUnblockQueue, "k", desc="Pop incoming unblock queue") {
603 profileMsgDelay(0, L1unblockNetwork_in.dequeue_getDelayCycles());
606 action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
607 profileMsgDelay(3, responseIntraChipL2Network_in.dequeue_getDelayCycles());
610 action(m_writeDataToCache, "m", desc="Write data from response queue to cache") {
611 peek(responseIntraChipL2Network_in, ResponseMsg) {
612 assert(is_valid(cache_entry));
613 cache_entry.DataBlk := in_msg.DataBlk;
614 cache_entry.Dirty := in_msg.Dirty;
618 action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") {
619 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
620 assert(is_valid(cache_entry));
621 cache_entry.DataBlk := in_msg.DataBlk;
622 cache_entry.Dirty := in_msg.Dirty;
626 action(q_updateAck, "q", desc="update pending ack count") {
627 peek(responseIntraChipL2Network_in, ResponseMsg) {
628 assert(is_valid(tbe));
629 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
630 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
631 APPEND_TRANSITION_COMMENT(" p: ");
632 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
636 action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") {
637 peek(responseIntraChipL2Network_in, ResponseMsg) {
638 assert(is_valid(tbe));
639 tbe.DataBlk := in_msg.DataBlk;
640 tbe.Dirty := in_msg.Dirty;
644 action(z_stall, "z", desc="Stall") {
647 action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") {
648 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
649 assert(is_valid(tbe));
650 tbe.L1_GetS_IDs.add(in_msg.Requestor);
654 action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
655 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
656 assert(is_valid(tbe));
657 tbe.L1_GetX_ID := in_msg.Requestor;
661 action(set_setMRU, "\set", desc="set the MRU entry") {
662 L2cacheMemory.setMRU(address);
665 action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
666 if (is_invalid(cache_entry)) {
667 set_cache_entry(L2cacheMemory.allocate(address, new Entry));
671 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
672 L2cacheMemory.deallocate(address);
676 action(t_sendWBAck, "t", desc="Send writeback ACK") {
677 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
678 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
679 out_msg.Address := address;
680 out_msg.Type := CoherenceResponseType:WB_ACK;
681 out_msg.Sender := machineID;
682 out_msg.Destination.add(in_msg.Requestor);
683 out_msg.MessageSize := MessageSizeType:Response_Control;
688 action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") {
689 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
690 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
691 assert(is_valid(cache_entry));
692 out_msg.Address := address;
693 out_msg.Type := CoherenceResponseType:ACK;
694 out_msg.Sender := machineID;
695 out_msg.Destination.add(in_msg.Requestor);
696 out_msg.MessageSize := MessageSizeType:Response_Control;
697 // upgrader doesn't get ack from itself, hence the + 1
698 out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1;
703 action(uu_profileMiss, "\u", desc="Profile the demand miss") {
704 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
705 //profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, L1CacheMachIDToProcessorNum(in_msg.Requestor));
709 action(ww_profileMissNoDir, "\w", desc="Profile this transition at the L2 because Dir won't see the request") {
710 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
711 // profile_request(in_msg.L1CacheStateStr, getStateStr(address), "NA", getCoherenceRequestTypeStr(in_msg.Type));
715 action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
716 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
717 assert(is_valid(cache_entry));
718 addSharer(address, in_msg.Requestor, cache_entry);
719 APPEND_TRANSITION_COMMENT( cache_entry.Sharers );
723 action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") {
724 peek(L1unblockNetwork_in, ResponseMsg) {
725 assert(is_valid(cache_entry));
726 addSharer(address, in_msg.Sender, cache_entry);
730 action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
731 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
732 assert(is_valid(cache_entry));
733 cache_entry.Sharers.remove(in_msg.Requestor);
737 action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
738 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
739 assert(is_valid(cache_entry));
740 cache_entry.Sharers.clear();
744 action(mm_markExclusive, "\m", desc="set the exclusive owner") {
745 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
746 assert(is_valid(cache_entry));
747 cache_entry.Sharers.clear();
748 cache_entry.Exclusive := in_msg.Requestor;
749 addSharer(address, in_msg.Requestor, cache_entry);
753 action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") {
754 peek(L1unblockNetwork_in, ResponseMsg) {
755 assert(is_valid(cache_entry));
756 cache_entry.Sharers.clear();
757 cache_entry.Exclusive := in_msg.Sender;
758 addSharer(address, in_msg.Sender, cache_entry);
762 action(zz_recycleL1RequestQueue, "zz", desc="recycle L1 request queue") {
763 L1RequestIntraChipL2Network_in.recycle();
766 action(zn_recycleResponseNetwork, "zn", desc="recycle memory request") {
767 responseIntraChipL2Network_in.recycle();
771 //*****************************************************
773 //*****************************************************
776 //===============================================
779 // Transitions from I (Idle)
780 transition({NP, IS, ISS, IM, SS, M, M_I, I_I, S_I, M_MB, MT_IB, MT_SB}, L1_PUTX) {
782 jj_popL1RequestQueue;
785 transition({NP, SS, M, MT, M_I, I_I, S_I, IS, ISS, IM, M_MB, MT_IB, MT_SB}, L1_PUTX_old) {
787 jj_popL1RequestQueue;
790 transition({IM, IS, ISS, SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L2_Replacement, L2_Replacement_clean}) {
791 zz_recycleL1RequestQueue;
794 transition({IM, IS, ISS, SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, MEM_Inv) {
795 zn_recycleResponseNetwork;
798 transition({S_I, M_I, MT_I}, MEM_Inv) {
799 o_popIncomingResponseQueue;
803 transition({SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE}) {
804 zz_recycleL1RequestQueue;
808 transition(NP, L1_GETS, ISS) {
809 qq_allocateL2CacheBlock;
814 a_issueFetchToMemory;
816 jj_popL1RequestQueue;
819 transition(NP, L1_GET_INSTR, IS) {
820 qq_allocateL2CacheBlock;
825 a_issueFetchToMemory;
827 jj_popL1RequestQueue;
830 transition(NP, L1_GETX, IM) {
831 qq_allocateL2CacheBlock;
836 a_issueFetchToMemory;
838 jj_popL1RequestQueue;
842 // transitions from IS/IM
844 transition(ISS, Mem_Data, MT_MB) {
846 ex_sendExclusiveDataToGetSRequestors;
848 o_popIncomingResponseQueue;
851 transition(IS, Mem_Data, SS) {
853 e_sendDataToGetSRequestors;
855 o_popIncomingResponseQueue;
858 transition(IM, Mem_Data, MT_MB) {
860 ee_sendDataToGetXRequestor;
862 o_popIncomingResponseQueue;
865 transition({IS, ISS}, {L1_GETS, L1_GET_INSTR}, IS) {
869 jj_popL1RequestQueue;
872 transition({IS, ISS}, L1_GETX) {
873 zz_recycleL1RequestQueue;
876 transition(IM, {L1_GETX, L1_GETS, L1_GET_INSTR}) {
877 zz_recycleL1RequestQueue;
880 // transitions from SS
881 transition(SS, {L1_GETS, L1_GET_INSTR}) {
882 ds_sendSharedDataToRequestor;
886 jj_popL1RequestQueue;
890 transition(SS, L1_GETX, SS_MB) {
891 d_sendDataToRequestor;
892 // fw_sendFwdInvToSharers;
893 fwm_sendFwdInvToSharersMinusRequestor;
896 jj_popL1RequestQueue;
899 transition(SS, L1_UPGRADE, SS_MB) {
900 fwm_sendFwdInvToSharersMinusRequestor;
901 ts_sendInvAckToUpgrader;
904 jj_popL1RequestQueue;
907 transition(SS, L2_Replacement_clean, I_I) {
910 rr_deallocateL2CacheBlock;
913 transition(SS, {L2_Replacement, MEM_Inv}, S_I) {
916 rr_deallocateL2CacheBlock;
920 transition(M, L1_GETX, MT_MB) {
921 d_sendDataToRequestor;
924 jj_popL1RequestQueue;
927 transition(M, L1_GET_INSTR, SS) {
928 d_sendDataToRequestor;
932 jj_popL1RequestQueue;
935 transition(M, L1_GETS, MT_MB) {
936 dd_sendExclusiveDataToRequestor;
939 jj_popL1RequestQueue;
942 transition(M, {L2_Replacement, MEM_Inv}, M_I) {
944 c_exclusiveReplacement;
945 rr_deallocateL2CacheBlock;
948 transition(M, L2_Replacement_clean, M_I) {
950 c_exclusiveCleanReplacement;
951 rr_deallocateL2CacheBlock;
955 // transitions from MT
957 transition(MT, L1_GETX, MT_MB) {
958 b_forwardRequestToExclusive;
961 jj_popL1RequestQueue;
965 transition(MT, {L1_GETS, L1_GET_INSTR}, MT_IIB) {
966 b_forwardRequestToExclusive;
969 jj_popL1RequestQueue;
972 transition(MT, {L2_Replacement, MEM_Inv}, MT_I) {
975 rr_deallocateL2CacheBlock;
978 transition(MT, L2_Replacement_clean, MCT_I) {
981 rr_deallocateL2CacheBlock;
984 transition(MT, L1_PUTX, M) {
986 mr_writeDataToCacheFromRequest;
988 jj_popL1RequestQueue;
992 // transitions from blocking states
993 transition(SS_MB, Unblock_Cancel, SS) {
997 transition(MT_MB, Unblock_Cancel, MT) {
1001 transition(MT_IB, Unblock_Cancel, MT) {
1005 transition(SS_MB, Exclusive_Unblock, MT) {
1006 // update actual directory
1007 mmu_markExclusiveFromUnblock;
1011 transition({M_MB, MT_MB}, Exclusive_Unblock, MT) {
1012 // update actual directory
1013 mmu_markExclusiveFromUnblock;
1017 transition(MT_IIB, {L1_PUTX, L1_PUTX_old}){
1018 zz_recycleL1RequestQueue;
1021 transition(MT_IIB, Unblock, MT_IB) {
1022 nnu_addSharerFromUnblock;
1026 transition(MT_IIB, {WB_Data, WB_Data_clean}, MT_SB) {
1028 o_popIncomingResponseQueue;
1031 transition(MT_IB, {WB_Data, WB_Data_clean}, SS) {
1033 o_popIncomingResponseQueue;
1036 transition(MT_SB, Unblock, SS) {
1037 nnu_addSharerFromUnblock;
1042 transition({I_I, S_I, MT_I, MCT_I, M_I}, {L1_GETX, L1_UPGRADE, L1_GETS, L1_GET_INSTR}) {
1043 zz_recycleL1RequestQueue;
1046 transition(I_I, Ack) {
1048 o_popIncomingResponseQueue;
1051 transition(I_I, Ack_all, M_I) {
1052 c_exclusiveCleanReplacement;
1053 o_popIncomingResponseQueue;
1056 transition({MT_I, MCT_I}, WB_Data, M_I) {
1058 ct_exclusiveReplacementFromTBE;
1059 o_popIncomingResponseQueue;
1062 transition(MCT_I, {WB_Data_clean, Ack_all}, M_I) {
1063 c_exclusiveCleanReplacement;
1064 o_popIncomingResponseQueue;
1067 transition(MCT_I, {L1_PUTX, L1_PUTX_old}){
1068 zz_recycleL1RequestQueue;
1071 // L1 never changed Dirty data
1072 transition(MT_I, Ack_all, M_I) {
1073 ct_exclusiveReplacementFromTBE;
1074 o_popIncomingResponseQueue;
1077 transition(MT_I, {L1_PUTX, L1_PUTX_old}){
1078 zz_recycleL1RequestQueue;
1081 // possible race between unblock and immediate replacement
1082 transition({MT_MB,SS_MB}, {L1_PUTX, L1_PUTX_old}) {
1083 zz_recycleL1RequestQueue;
1086 transition(MT_I, WB_Data_clean, NP) {
1088 o_popIncomingResponseQueue;
1091 transition(S_I, Ack) {
1093 o_popIncomingResponseQueue;
1096 transition(S_I, Ack_all, M_I) {
1097 ct_exclusiveReplacementFromTBE;
1098 o_popIncomingResponseQueue;
1101 transition(M_I, Mem_Ack, NP) {
1103 o_popIncomingResponseQueue;