2 * Copyright (c) 2020 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 machine(MachineType:L1Cache, "MESI Directory L1 Cache CMP")
42 : CacheMemory * cache;
43 int l2_select_num_bits;
44 Cycles l1_request_latency := 2;
45 Cycles l1_response_latency := 2;
46 Cycles to_l2_latency := 1;
48 // Message Buffers between the L1 and the L0 Cache
49 // From the L1 cache to the L0 cache
50 MessageBuffer * bufferToL0, network="To";
52 // From the L0 cache to the L1 cache
53 MessageBuffer * bufferFromL0, network="From";
55 // Message queue from this L1 cache TO the network / L2
56 MessageBuffer * requestToL2, network="To", virtual_network="0",
59 MessageBuffer * responseToL2, network="To", virtual_network="1",
61 MessageBuffer * unblockToL2, network="To", virtual_network="2",
64 // To this L1 cache FROM the network / L2
65 MessageBuffer * requestFromL2, network="From", virtual_network="2",
67 MessageBuffer * responseFromL2, network="From", virtual_network="1",
72 state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
74 I, AccessPermission:Invalid, desc="L1 cache entry Idle";
75 S, AccessPermission:Read_Only, desc="Line is present in shared state in L1 and L0";
76 SS, AccessPermission:Read_Only, desc="Line is present in shared state in L1 but not L0";
77 E, AccessPermission:Read_Only, desc="Line is present in exclusive state in L1 and L0";
78 EE, AccessPermission:Read_Write, desc="Line is present in exclusive state in L1 but not L0";
79 M, AccessPermission:Maybe_Stale, desc="Line is present in modified state in L1 and present in L0", format="!b";
80 MM, AccessPermission:Read_Write, desc="Line is present in modified state in L1 but not present in L0", format="!b";
83 IS, AccessPermission:Busy, desc="L1 idle, issued GETS, have not seen response yet";
84 IM, AccessPermission:Busy, desc="L1 idle, issued GETX, have not seen response yet";
85 SM, AccessPermission:Read_Only, desc="L1 idle, issued GETX, have not seen response yet";
86 IS_I, AccessPermission:Busy, desc="L1 idle, issued GETS, saw Inv before data because directory doesn't block on GETS hit";
87 M_I, AccessPermission:Busy, desc="L1 replacing, waiting for ACK";
88 SINK_WB_ACK, AccessPermission:Busy, desc="This is to sink WB_Acks from L2";
90 // For all of the following states, invalidate
91 // message has been sent to L0 cache. The response
92 // from the L0 cache has not been seen yet.
93 S_IL0, AccessPermission:Busy, desc="Shared in L1, invalidation sent to L0, have not seen response yet";
94 E_IL0, AccessPermission:Busy, desc="Exclusive in L1, invalidation sent to L0, have not seen response yet";
95 M_IL0, AccessPermission:Busy, desc="Modified in L1, invalidation sent to L0, have not seen response yet";
96 MM_IL0, AccessPermission:Read_Write, desc="Invalidation sent to L0, have not seen response yet";
97 SM_IL0, AccessPermission:Busy, desc="Invalidation sent to L0, have not seen response yet";
101 enumeration(Event, desc="Cache events") {
102 // Requests from the L0 cache
103 Load, desc="Load request";
104 Store, desc="Store request";
105 WriteBack, desc="Writeback request";
107 // Responses from the L0 Cache
108 // L0 cache received the invalidation message
109 // and has sent the data.
110 L0_DataAck, desc="L0 received INV message";
112 Inv, desc="Invalidate request from L2 bank";
114 // internally generated requests:
115 L0_Invalidate_Own, desc="Invalidate line in L0, due to this cache's (L1) requirements";
116 L0_Invalidate_Else, desc="Invalidate line in L0, due to another cache's requirements";
117 L1_Replacement, desc="Invalidate line in this cache (L1), due to another cache's requirements";
120 Fwd_GETX, desc="GETX from other processor";
121 Fwd_GETS, desc="GETS from other processor";
123 Data, desc="Data for processor";
124 Data_Exclusive, desc="Data for processor";
125 DataS_fromL1, desc="data for GETS request, need to unblock directory";
126 Data_all_Acks, desc="Data for processor, all acks";
128 L0_Ack, desc="Ack for processor";
129 Ack, desc="Ack for processor";
130 Ack_all, desc="Last ack for processor";
132 WB_Ack, desc="Ack for replacement";
138 structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
139 State CacheState, desc="cache state";
140 DataBlock DataBlk, desc="data for the block";
141 bool Dirty, default="false", desc="data is dirty";
145 structure(TBE, desc="...") {
146 Addr addr, desc="Physical address for this TBE";
147 State TBEState, desc="Transient state";
148 DataBlock DataBlk, desc="Buffer for the data block";
149 bool Dirty, default="false", desc="data is dirty";
150 int pendingAcks, default="0", desc="number of pending acks";
153 structure(TBETable, external="yes") {
156 void deallocate(Addr);
157 bool isPresent(Addr);
160 TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
162 int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
165 Cycles ticksToCycles(Tick t);
166 void set_cache_entry(AbstractCacheEntry a);
167 void unset_cache_entry();
170 void wakeUpBuffers(Addr a);
171 void wakeUpAllBuffers(Addr a);
172 void profileMsgDelay(int virtualNetworkType, Cycles c);
174 // inclusive cache returns L1 entries only
175 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
176 Entry cache_entry := static_cast(Entry, "pointer", cache[addr]);
180 State getState(TBE tbe, Entry cache_entry, Addr addr) {
183 } else if (is_valid(cache_entry)) {
184 return cache_entry.CacheState;
189 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
192 tbe.TBEState := state;
195 if (is_valid(cache_entry)) {
196 cache_entry.CacheState := state;
200 AccessPermission getAccessPermission(Addr addr) {
201 TBE tbe := TBEs[addr];
203 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
204 return L1Cache_State_to_permission(tbe.TBEState);
207 Entry cache_entry := getCacheEntry(addr);
208 if(is_valid(cache_entry)) {
209 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
210 return L1Cache_State_to_permission(cache_entry.CacheState);
213 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
214 return AccessPermission:NotPresent;
217 void functionalRead(Addr addr, Packet *pkt) {
218 TBE tbe := TBEs[addr];
220 testAndRead(addr, tbe.DataBlk, pkt);
222 testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
226 int functionalWrite(Addr addr, Packet *pkt) {
227 int num_functional_writes := 0;
229 TBE tbe := TBEs[addr];
231 num_functional_writes := num_functional_writes +
232 testAndWrite(addr, tbe.DataBlk, pkt);
233 return num_functional_writes;
236 num_functional_writes := num_functional_writes +
237 testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
238 return num_functional_writes;
241 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
242 if (is_valid(cache_entry)) {
243 cache_entry.changePermission(L1Cache_State_to_permission(state));
247 Event mandatory_request_type_to_event(CoherenceClass type) {
248 if (type == CoherenceClass:GETS) {
250 } else if ((type == CoherenceClass:GETX) ||
251 (type == CoherenceClass:UPGRADE)) {
253 } else if (type == CoherenceClass:PUTX) {
254 return Event:WriteBack;
256 error("Invalid RequestType");
260 int getPendingAcks(TBE tbe) {
261 return tbe.pendingAcks;
264 bool inL0Cache(State state) {
265 if (state == State:S || state == State:E || state == State:M ||
266 state == State:S_IL0 || state == State:E_IL0 ||
267 state == State:M_IL0 || state == State:SM_IL0) {
274 out_port(requestNetwork_out, RequestMsg, requestToL2);
275 out_port(responseNetwork_out, ResponseMsg, responseToL2);
276 out_port(unblockNetwork_out, ResponseMsg, unblockToL2);
277 out_port(bufferToL0_out, CoherenceMsg, bufferToL0);
279 // Response From the L2 Cache to this L1 cache
280 in_port(responseNetwork_in, ResponseMsg, responseFromL2, rank = 2) {
281 if (responseNetwork_in.isReady(clockEdge())) {
282 peek(responseNetwork_in, ResponseMsg) {
283 assert(in_msg.Destination.isElement(machineID));
285 Entry cache_entry := getCacheEntry(in_msg.addr);
286 TBE tbe := TBEs[in_msg.addr];
288 if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
289 trigger(Event:Data_Exclusive, in_msg.addr, cache_entry, tbe);
290 } else if(in_msg.Type == CoherenceResponseType:DATA) {
291 if ((getState(tbe, cache_entry, in_msg.addr) == State:IS ||
292 getState(tbe, cache_entry, in_msg.addr) == State:IS_I) &&
293 machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
295 trigger(Event:DataS_fromL1, in_msg.addr, cache_entry, tbe);
297 } else if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
298 trigger(Event:Data_all_Acks, in_msg.addr, cache_entry, tbe);
300 trigger(Event:Data, in_msg.addr, cache_entry, tbe);
302 } else if (in_msg.Type == CoherenceResponseType:ACK) {
303 if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
304 trigger(Event:Ack_all, in_msg.addr, cache_entry, tbe);
306 trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
308 } else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
309 trigger(Event:WB_Ack, in_msg.addr, cache_entry, tbe);
311 error("Invalid L1 response type");
317 // Request to this L1 cache from the shared L2
318 in_port(requestNetwork_in, RequestMsg, requestFromL2, rank = 1) {
319 if(requestNetwork_in.isReady(clockEdge())) {
320 peek(requestNetwork_in, RequestMsg) {
321 assert(in_msg.Destination.isElement(machineID));
322 Entry cache_entry := getCacheEntry(in_msg.addr);
323 TBE tbe := TBEs[in_msg.addr];
325 if (in_msg.Type == CoherenceRequestType:INV) {
326 if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
327 trigger(Event:L0_Invalidate_Else, in_msg.addr,
330 trigger(Event:Inv, in_msg.addr, cache_entry, tbe);
332 } else if (in_msg.Type == CoherenceRequestType:GETX ||
333 in_msg.Type == CoherenceRequestType:UPGRADE) {
334 if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
335 trigger(Event:L0_Invalidate_Else, in_msg.addr,
338 trigger(Event:Fwd_GETX, in_msg.addr, cache_entry, tbe);
340 } else if (in_msg.Type == CoherenceRequestType:GETS) {
341 if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
342 trigger(Event:L0_Invalidate_Else, in_msg.addr,
345 trigger(Event:Fwd_GETS, in_msg.addr, cache_entry, tbe);
348 error("Invalid forwarded request type");
354 // Requests to this L1 cache from the L0 cache.
355 in_port(messageBufferFromL0_in, CoherenceMsg, bufferFromL0, rank = 0) {
356 if (messageBufferFromL0_in.isReady(clockEdge())) {
357 peek(messageBufferFromL0_in, CoherenceMsg) {
358 Entry cache_entry := getCacheEntry(in_msg.addr);
359 TBE tbe := TBEs[in_msg.addr];
361 if(in_msg.Class == CoherenceClass:INV_DATA) {
362 trigger(Event:L0_DataAck, in_msg.addr, cache_entry, tbe);
363 } else if (in_msg.Class == CoherenceClass:INV_ACK) {
364 trigger(Event:L0_Ack, in_msg.addr, cache_entry, tbe);
366 if (is_valid(cache_entry)) {
367 trigger(mandatory_request_type_to_event(in_msg.Class),
368 in_msg.addr, cache_entry, tbe);
370 if (cache.cacheAvail(in_msg.addr)) {
371 // L1 does't have the line, but we have space for it
372 // in the L1 let's see if the L2 has it
373 trigger(mandatory_request_type_to_event(in_msg.Class),
374 in_msg.addr, cache_entry, tbe);
376 // No room in the L1, so we need to make room in the L1
377 Addr victim := cache.cacheProbe(in_msg.addr);
378 Entry victim_entry := getCacheEntry(victim);
379 TBE victim_tbe := TBEs[victim];
381 if (is_valid(victim_entry) && inL0Cache(victim_entry.CacheState)) {
382 trigger(Event:L0_Invalidate_Own,
383 victim, victim_entry, victim_tbe);
385 trigger(Event:L1_Replacement,
386 victim, victim_entry, victim_tbe);
396 action(a_issueGETS, "a", desc="Issue GETS") {
397 peek(messageBufferFromL0_in, CoherenceMsg) {
398 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
399 out_msg.addr := address;
400 out_msg.Type := CoherenceRequestType:GETS;
401 out_msg.Requestor := machineID;
402 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
403 l2_select_low_bit, l2_select_num_bits, clusterID));
404 DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
405 address, out_msg.Destination);
406 out_msg.MessageSize := MessageSizeType:Control;
407 out_msg.AccessMode := in_msg.AccessMode;
412 action(b_issueGETX, "b", desc="Issue GETX") {
413 peek(messageBufferFromL0_in, CoherenceMsg) {
414 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
415 out_msg.addr := address;
416 out_msg.Type := CoherenceRequestType:GETX;
417 out_msg.Requestor := machineID;
418 DPRINTF(RubySlicc, "%s\n", machineID);
419 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
420 l2_select_low_bit, l2_select_num_bits, clusterID));
421 DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
422 address, out_msg.Destination);
423 out_msg.MessageSize := MessageSizeType:Control;
424 out_msg.AccessMode := in_msg.AccessMode;
429 action(c_issueUPGRADE, "c", desc="Issue GETX") {
430 peek(messageBufferFromL0_in, CoherenceMsg) {
431 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
432 out_msg.addr := address;
433 out_msg.Type := CoherenceRequestType:UPGRADE;
434 out_msg.Requestor := machineID;
435 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
436 l2_select_low_bit, l2_select_num_bits, clusterID));
437 DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
438 address, out_msg.Destination);
439 out_msg.MessageSize := MessageSizeType:Control;
440 out_msg.AccessMode := in_msg.AccessMode;
445 action(d_sendDataToRequestor, "d", desc="send data to requestor") {
446 peek(requestNetwork_in, RequestMsg) {
447 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
448 assert(is_valid(cache_entry));
449 out_msg.addr := address;
450 out_msg.Type := CoherenceResponseType:DATA;
451 out_msg.DataBlk := cache_entry.DataBlk;
452 out_msg.Dirty := cache_entry.Dirty;
453 out_msg.Sender := machineID;
454 out_msg.Destination.add(in_msg.Requestor);
455 out_msg.MessageSize := MessageSizeType:Response_Data;
460 action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") {
461 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
462 assert(is_valid(cache_entry));
463 out_msg.addr := address;
464 out_msg.Type := CoherenceResponseType:DATA;
465 out_msg.DataBlk := cache_entry.DataBlk;
466 out_msg.Dirty := cache_entry.Dirty;
467 out_msg.Sender := machineID;
468 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
469 l2_select_low_bit, l2_select_num_bits, clusterID));
470 out_msg.MessageSize := MessageSizeType:Response_Data;
474 action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") {
475 peek(requestNetwork_in, RequestMsg) {
476 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
477 assert(is_valid(tbe));
478 out_msg.addr := address;
479 out_msg.Type := CoherenceResponseType:DATA;
480 out_msg.DataBlk := tbe.DataBlk;
481 out_msg.Dirty := tbe.Dirty;
482 out_msg.Sender := machineID;
483 out_msg.Destination.add(in_msg.Requestor);
484 out_msg.MessageSize := MessageSizeType:Response_Data;
489 action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") {
490 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
491 assert(is_valid(tbe));
492 out_msg.addr := address;
493 out_msg.Type := CoherenceResponseType:DATA;
494 out_msg.DataBlk := tbe.DataBlk;
495 out_msg.Dirty := tbe.Dirty;
496 out_msg.Sender := machineID;
497 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
498 l2_select_low_bit, l2_select_num_bits, clusterID));
499 out_msg.MessageSize := MessageSizeType:Response_Data;
503 action(e_sendAckToRequestor, "e", desc="send invalidate ack to requestor (could be L2 or L1)") {
504 peek(requestNetwork_in, RequestMsg) {
505 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
506 out_msg.addr := address;
507 out_msg.Type := CoherenceResponseType:ACK;
508 out_msg.Sender := machineID;
509 out_msg.Destination.add(in_msg.Requestor);
510 out_msg.MessageSize := MessageSizeType:Response_Control;
515 action(f_sendDataToL2, "f", desc="send data to the L2 cache") {
516 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
517 assert(is_valid(cache_entry));
518 out_msg.addr := address;
519 out_msg.Type := CoherenceResponseType:DATA;
520 out_msg.DataBlk := cache_entry.DataBlk;
521 out_msg.Dirty := cache_entry.Dirty;
522 out_msg.Sender := machineID;
523 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
524 l2_select_low_bit, l2_select_num_bits, clusterID));
525 out_msg.MessageSize := MessageSizeType:Writeback_Data;
529 action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") {
530 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
531 assert(is_valid(tbe));
532 out_msg.addr := address;
533 out_msg.Type := CoherenceResponseType:DATA;
534 out_msg.DataBlk := tbe.DataBlk;
535 out_msg.Dirty := tbe.Dirty;
536 out_msg.Sender := machineID;
537 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
538 l2_select_low_bit, l2_select_num_bits, clusterID));
539 out_msg.MessageSize := MessageSizeType:Writeback_Data;
543 action(fi_sendInvAck, "fi", desc="send data to the L2 cache") {
544 peek(requestNetwork_in, RequestMsg) {
545 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
546 out_msg.addr := address;
547 out_msg.Type := CoherenceResponseType:ACK;
548 out_msg.Sender := machineID;
549 out_msg.Destination.add(in_msg.Requestor);
550 out_msg.MessageSize := MessageSizeType:Response_Control;
551 out_msg.AckCount := 1;
556 action(forward_eviction_to_L0_own, "\cc", desc="sends (own) eviction information to the processor") {
557 enqueue(bufferToL0_out, CoherenceMsg, l1_request_latency) {
558 out_msg.addr := address;
559 out_msg.Class := CoherenceClass:INV_OWN;
560 out_msg.Sender := machineID;
561 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
562 out_msg.MessageSize := MessageSizeType:Control;
566 action(forward_eviction_to_L0_else, "\cce", desc="sends (else) eviction information to the processor") {
567 enqueue(bufferToL0_out, CoherenceMsg, l1_request_latency) {
568 out_msg.addr := address;
569 out_msg.Class := CoherenceClass:INV_ELSE;
570 out_msg.Sender := machineID;
571 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
572 out_msg.MessageSize := MessageSizeType:Control;
576 action(g_issuePUTX, "g", desc="send data to the L2 cache") {
577 enqueue(requestNetwork_out, RequestMsg, l1_response_latency) {
578 assert(is_valid(cache_entry));
579 out_msg.addr := address;
580 out_msg.Type := CoherenceRequestType:PUTX;
581 out_msg.Dirty := cache_entry.Dirty;
582 out_msg.Requestor:= machineID;
583 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
584 l2_select_low_bit, l2_select_num_bits, clusterID));
585 if (cache_entry.Dirty) {
586 out_msg.MessageSize := MessageSizeType:Writeback_Data;
587 out_msg.DataBlk := cache_entry.DataBlk;
589 out_msg.MessageSize := MessageSizeType:Writeback_Control;
594 action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
595 enqueue(unblockNetwork_out, ResponseMsg, to_l2_latency) {
596 out_msg.addr := address;
597 out_msg.Type := CoherenceResponseType:UNBLOCK;
598 out_msg.Sender := machineID;
599 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
600 l2_select_low_bit, l2_select_num_bits, clusterID));
601 out_msg.MessageSize := MessageSizeType:Response_Control;
602 DPRINTF(RubySlicc, "%#x\n", address);
606 action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
607 enqueue(unblockNetwork_out, ResponseMsg, to_l2_latency) {
608 out_msg.addr := address;
609 out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
610 out_msg.Sender := machineID;
611 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
612 l2_select_low_bit, l2_select_num_bits, clusterID));
613 out_msg.MessageSize := MessageSizeType:Response_Control;
614 DPRINTF(RubySlicc, "%#x\n", address);
619 action(h_data_to_l0, "h", desc="If not prefetch, send data to the L0 cache.") {
620 enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
621 assert(is_valid(cache_entry));
623 out_msg.addr := address;
624 out_msg.Class := CoherenceClass:DATA;
625 out_msg.Sender := machineID;
626 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
627 out_msg.DataBlk := cache_entry.DataBlk;
628 out_msg.MessageSize := MessageSizeType:Response_Data;
631 cache.setMRU(address);
634 action(hh_xdata_to_l0, "\h", desc="If not prefetch, notify sequencer that store completed.") {
635 enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
636 assert(is_valid(cache_entry));
638 out_msg.addr := address;
639 out_msg.Class := CoherenceClass:DATA_EXCLUSIVE;
640 out_msg.Sender := machineID;
641 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
642 out_msg.DataBlk := cache_entry.DataBlk;
643 out_msg.Dirty := cache_entry.Dirty;
644 out_msg.MessageSize := MessageSizeType:Response_Data;
646 //cache_entry.Dirty := true;
649 cache.setMRU(address);
652 action(h_stale_data_to_l0, "hs", desc="If not prefetch, send data to the L0 cache.") {
653 enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
654 assert(is_valid(cache_entry));
656 out_msg.addr := address;
657 out_msg.Class := CoherenceClass:STALE_DATA;
658 out_msg.Sender := machineID;
659 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
660 out_msg.DataBlk := cache_entry.DataBlk;
661 out_msg.Dirty := cache_entry.Dirty;
662 out_msg.MessageSize := MessageSizeType:Response_Data;
666 action(i_allocateTBE, "i", desc="Allocate TBE (number of invalidates=0)") {
667 check_allocate(TBEs);
668 assert(is_valid(cache_entry));
669 TBEs.allocate(address);
670 set_tbe(TBEs[address]);
671 tbe.Dirty := cache_entry.Dirty;
672 tbe.DataBlk := cache_entry.DataBlk;
675 action(k_popL0RequestQueue, "k", desc="Pop mandatory queue.") {
676 messageBufferFromL0_in.dequeue(clockEdge());
679 action(l_popL2RequestQueue, "l",
680 desc="Pop incoming request queue and profile the delay within this virtual network") {
681 Tick delay := requestNetwork_in.dequeue(clockEdge());
682 profileMsgDelay(2, ticksToCycles(delay));
685 action(o_popL2ResponseQueue, "o",
686 desc="Pop Incoming Response queue and profile the delay within this virtual network") {
687 Tick delay := responseNetwork_in.dequeue(clockEdge());
688 profileMsgDelay(1, ticksToCycles(delay));
691 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
692 TBEs.deallocate(address);
696 action(u_writeDataFromL0Request, "ureql0", desc="Write data to cache") {
697 peek(messageBufferFromL0_in, CoherenceMsg) {
698 assert(is_valid(cache_entry));
700 cache_entry.DataBlk := in_msg.DataBlk;
701 cache_entry.Dirty := in_msg.Dirty;
706 action(u_writeDataFromL2Response, "uresl2", desc="Write data to cache") {
707 peek(responseNetwork_in, ResponseMsg) {
708 assert(is_valid(cache_entry));
709 cache_entry.DataBlk := in_msg.DataBlk;
713 action(u_writeDataFromL0Response, "uresl0", desc="Write data to cache") {
714 peek(messageBufferFromL0_in, CoherenceMsg) {
715 assert(is_valid(cache_entry));
717 cache_entry.DataBlk := in_msg.DataBlk;
718 cache_entry.Dirty := in_msg.Dirty;
723 action(q_updateAckCount, "q", desc="Update ack count") {
724 peek(responseNetwork_in, ResponseMsg) {
725 assert(is_valid(tbe));
726 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
727 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
728 APPEND_TRANSITION_COMMENT(" p: ");
729 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
733 action(ff_deallocateCacheBlock, "\f",
734 desc="Deallocate L1 cache block.") {
735 if (cache.isTagPresent(address)) {
736 cache.deallocate(address);
741 action(oo_allocateCacheBlock, "\o", desc="Set cache tag equal to tag of block B.") {
742 if (is_invalid(cache_entry)) {
743 set_cache_entry(cache.allocate(address, new Entry));
747 action(z0_stallAndWaitL0Queue, "\z0", desc="recycle L0 request queue") {
748 stall_and_wait(messageBufferFromL0_in, address);
751 action(z2_stallAndWaitL2Queue, "\z2", desc="recycle L2 request queue") {
752 stall_and_wait(requestNetwork_in, address);
755 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
756 wakeUpAllBuffers(address);
759 action(uu_profileMiss, "\um", desc="Profile the demand miss") {
760 ++cache.demand_misses;
763 action(uu_profileHit, "\uh", desc="Profile the demand hit") {
768 //*****************************************************
770 //*****************************************************
772 // Transitions for Load/Store/Replacement/WriteBack from transient states
773 transition({IS, IM, IS_I, M_I, SM, SINK_WB_ACK, S_IL0, M_IL0, E_IL0, MM_IL0},
774 {Load, Store, L1_Replacement}) {
775 z0_stallAndWaitL0Queue;
778 transition(I, Load, IS) {
779 oo_allocateCacheBlock;
786 transition(I, Store, IM) {
787 oo_allocateCacheBlock;
799 // Transitions from Shared
800 transition({S,SS}, Load, S) {
806 transition(EE, Load, E) {
812 transition(MM, Load, M) {
818 transition({S,SS}, Store, SM) {
825 transition(SS, L1_Replacement, I) {
826 ff_deallocateCacheBlock;
829 transition(S, L0_Invalidate_Own, S_IL0) {
830 forward_eviction_to_L0_own;
833 transition(S, L0_Invalidate_Else, S_IL0) {
834 forward_eviction_to_L0_else;
837 transition(SS, Inv, I) {
839 ff_deallocateCacheBlock;
843 // Transitions from Exclusive
845 transition({EE,MM}, Store, M) {
851 transition(EE, L1_Replacement, M_I) {
852 // silent E replacement??
854 g_issuePUTX; // send data, but hold in case forwarded request
855 ff_deallocateCacheBlock;
858 transition(EE, Inv, I) {
861 ff_deallocateCacheBlock;
865 transition(EE, Fwd_GETX, I) {
866 d_sendDataToRequestor;
867 ff_deallocateCacheBlock;
871 transition(EE, Fwd_GETS, SS) {
872 d_sendDataToRequestor;
877 transition(E, L0_Invalidate_Own, E_IL0) {
878 forward_eviction_to_L0_own;
881 transition(E, L0_Invalidate_Else, E_IL0) {
882 forward_eviction_to_L0_else;
885 // Transitions from Modified
886 transition(MM, L1_Replacement, M_I) {
888 g_issuePUTX; // send data, but hold in case forwarded request
889 ff_deallocateCacheBlock;
892 transition({M,E}, WriteBack, MM) {
893 u_writeDataFromL0Request;
897 transition(M_I, WB_Ack, I) {
899 o_popL2ResponseQueue;
900 ff_deallocateCacheBlock;
904 transition(MM, Inv, I) {
906 ff_deallocateCacheBlock;
910 transition(M_I, Inv, SINK_WB_ACK) {
911 ft_sendDataToL2_fromTBE;
915 transition(MM, Fwd_GETX, I) {
916 d_sendDataToRequestor;
917 ff_deallocateCacheBlock;
921 transition(MM, Fwd_GETS, SS) {
922 d_sendDataToRequestor;
927 transition(M, L0_Invalidate_Own, M_IL0) {
928 forward_eviction_to_L0_own;
931 transition(M, L0_Invalidate_Else, M_IL0) {
932 forward_eviction_to_L0_else;
935 transition(M_I, Fwd_GETX, SINK_WB_ACK) {
936 dt_sendDataToRequestor_fromTBE;
940 transition(M_I, Fwd_GETS, SINK_WB_ACK) {
941 dt_sendDataToRequestor_fromTBE;
942 d2t_sendDataToL2_fromTBE;
946 // Transitions from IS
947 transition({IS,IS_I}, Inv, IS_I) {
952 transition(IS, Data_all_Acks, S) {
953 u_writeDataFromL2Response;
956 o_popL2ResponseQueue;
960 transition(IS_I, Data_all_Acks, I) {
961 u_writeDataFromL2Response;
964 ff_deallocateCacheBlock;
965 o_popL2ResponseQueue;
969 transition(IS, DataS_fromL1, S) {
970 u_writeDataFromL2Response;
974 o_popL2ResponseQueue;
978 transition(IS_I, DataS_fromL1, I) {
979 u_writeDataFromL2Response;
983 ff_deallocateCacheBlock;
984 o_popL2ResponseQueue;
988 // directory is blocked when sending exclusive data
989 transition({IS,IS_I}, Data_Exclusive, E) {
990 u_writeDataFromL2Response;
992 jj_sendExclusiveUnblock;
994 o_popL2ResponseQueue;
998 // Transitions from IM
999 transition({IM,SM}, Inv, IM) {
1001 l_popL2RequestQueue;
1004 transition(IM, Data, SM) {
1005 u_writeDataFromL2Response;
1007 o_popL2ResponseQueue;
1010 transition(IM, Data_all_Acks, M) {
1011 u_writeDataFromL2Response;
1013 jj_sendExclusiveUnblock;
1015 o_popL2ResponseQueue;
1016 kd_wakeUpDependents;
1019 transition({SM, IM}, Ack) {
1021 o_popL2ResponseQueue;
1024 transition(SM, Ack_all, M) {
1025 jj_sendExclusiveUnblock;
1028 o_popL2ResponseQueue;
1029 kd_wakeUpDependents;
1032 transition(SM, L0_Invalidate_Else, SM_IL0) {
1033 forward_eviction_to_L0_else;
1036 transition(SINK_WB_ACK, Inv){
1038 l_popL2RequestQueue;
1041 transition(SINK_WB_ACK, WB_Ack, I){
1043 o_popL2ResponseQueue;
1044 ff_deallocateCacheBlock;
1045 kd_wakeUpDependents;
1048 transition({M_IL0, E_IL0}, WriteBack, MM_IL0) {
1049 u_writeDataFromL0Request;
1050 k_popL0RequestQueue;
1051 kd_wakeUpDependents;
1054 transition({M_IL0, E_IL0}, L0_DataAck, MM) {
1055 u_writeDataFromL0Response;
1056 k_popL0RequestQueue;
1057 kd_wakeUpDependents;
1060 transition({M_IL0, MM_IL0}, L0_Ack, MM) {
1061 k_popL0RequestQueue;
1062 kd_wakeUpDependents;
1065 transition(E_IL0, L0_Ack, EE) {
1066 k_popL0RequestQueue;
1067 kd_wakeUpDependents;
1070 transition(S_IL0, L0_Ack, SS) {
1071 k_popL0RequestQueue;
1072 kd_wakeUpDependents;
1075 transition(SM_IL0, L0_Ack, IM) {
1076 k_popL0RequestQueue;
1077 kd_wakeUpDependents;
1080 transition({S_IL0, M_IL0, E_IL0, SM_IL0, SM}, L0_Invalidate_Own) {
1081 z0_stallAndWaitL0Queue;
1084 transition({S_IL0, M_IL0, E_IL0, SM_IL0}, L0_Invalidate_Else) {
1085 z2_stallAndWaitL2Queue;
1088 transition({S_IL0, M_IL0, E_IL0, MM_IL0}, {Inv, Fwd_GETX, Fwd_GETS}) {
1089 z2_stallAndWaitL2Queue;