mem-ruby: MESI_Three_Level discriminate L0 invalidation reason
[gem5.git] / src / mem / ruby / protocol / MESI_Three_Level-L1cache.sm
1 /*
2 * Copyright (c) 2020 ARM Limited
3 * All rights reserved
4 *
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.
13 *
14 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
15 * All rights reserved.
16 *
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.
27 *
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.
39 */
40
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;
47
48 // Message Buffers between the L1 and the L0 Cache
49 // From the L1 cache to the L0 cache
50 MessageBuffer * bufferToL0, network="To";
51
52 // From the L0 cache to the L1 cache
53 MessageBuffer * bufferFromL0, network="From";
54
55 // Message queue from this L1 cache TO the network / L2
56 MessageBuffer * requestToL2, network="To", virtual_network="0",
57 vnet_type="request";
58
59 MessageBuffer * responseToL2, network="To", virtual_network="1",
60 vnet_type="response";
61 MessageBuffer * unblockToL2, network="To", virtual_network="2",
62 vnet_type="unblock";
63
64 // To this L1 cache FROM the network / L2
65 MessageBuffer * requestFromL2, network="From", virtual_network="2",
66 vnet_type="request";
67 MessageBuffer * responseFromL2, network="From", virtual_network="1",
68 vnet_type="response";
69
70 {
71 // STATES
72 state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
73 // Base states
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";
81
82 // Transient States
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";
89
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";
98 }
99
100 // EVENTS
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";
106
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";
111
112 Inv, desc="Invalidate request from L2 bank";
113
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";
118
119 // other requests
120 Fwd_GETX, desc="GETX from other processor";
121 Fwd_GETS, desc="GETS from other processor";
122
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";
127
128 L0_Ack, desc="Ack for processor";
129 Ack, desc="Ack for processor";
130 Ack_all, desc="Last ack for processor";
131
132 WB_Ack, desc="Ack for replacement";
133 }
134
135 // TYPES
136
137 // CacheEntry
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";
142 }
143
144 // TBE fields
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";
151 }
152
153 structure(TBETable, external="yes") {
154 TBE lookup(Addr);
155 void allocate(Addr);
156 void deallocate(Addr);
157 bool isPresent(Addr);
158 }
159
160 TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
161
162 int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
163
164 Tick clockEdge();
165 Cycles ticksToCycles(Tick t);
166 void set_cache_entry(AbstractCacheEntry a);
167 void unset_cache_entry();
168 void set_tbe(TBE a);
169 void unset_tbe();
170 void wakeUpBuffers(Addr a);
171 void wakeUpAllBuffers(Addr a);
172 void profileMsgDelay(int virtualNetworkType, Cycles c);
173
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]);
177 return cache_entry;
178 }
179
180 State getState(TBE tbe, Entry cache_entry, Addr addr) {
181 if(is_valid(tbe)) {
182 return tbe.TBEState;
183 } else if (is_valid(cache_entry)) {
184 return cache_entry.CacheState;
185 }
186 return State:I;
187 }
188
189 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
190 // MUST CHANGE
191 if(is_valid(tbe)) {
192 tbe.TBEState := state;
193 }
194
195 if (is_valid(cache_entry)) {
196 cache_entry.CacheState := state;
197 }
198 }
199
200 AccessPermission getAccessPermission(Addr addr) {
201 TBE tbe := TBEs[addr];
202 if(is_valid(tbe)) {
203 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
204 return L1Cache_State_to_permission(tbe.TBEState);
205 }
206
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);
211 }
212
213 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
214 return AccessPermission:NotPresent;
215 }
216
217 void functionalRead(Addr addr, Packet *pkt) {
218 TBE tbe := TBEs[addr];
219 if(is_valid(tbe)) {
220 testAndRead(addr, tbe.DataBlk, pkt);
221 } else {
222 testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
223 }
224 }
225
226 int functionalWrite(Addr addr, Packet *pkt) {
227 int num_functional_writes := 0;
228
229 TBE tbe := TBEs[addr];
230 if(is_valid(tbe)) {
231 num_functional_writes := num_functional_writes +
232 testAndWrite(addr, tbe.DataBlk, pkt);
233 return num_functional_writes;
234 }
235
236 num_functional_writes := num_functional_writes +
237 testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
238 return num_functional_writes;
239 }
240
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));
244 }
245 }
246
247 Event mandatory_request_type_to_event(CoherenceClass type) {
248 if (type == CoherenceClass:GETS) {
249 return Event:Load;
250 } else if ((type == CoherenceClass:GETX) ||
251 (type == CoherenceClass:UPGRADE)) {
252 return Event:Store;
253 } else if (type == CoherenceClass:PUTX) {
254 return Event:WriteBack;
255 } else {
256 error("Invalid RequestType");
257 }
258 }
259
260 int getPendingAcks(TBE tbe) {
261 return tbe.pendingAcks;
262 }
263
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) {
268 return true;
269 }
270
271 return false;
272 }
273
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);
278
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));
284
285 Entry cache_entry := getCacheEntry(in_msg.addr);
286 TBE tbe := TBEs[in_msg.addr];
287
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) {
294
295 trigger(Event:DataS_fromL1, in_msg.addr, cache_entry, tbe);
296
297 } else if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
298 trigger(Event:Data_all_Acks, in_msg.addr, cache_entry, tbe);
299 } else {
300 trigger(Event:Data, in_msg.addr, cache_entry, tbe);
301 }
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);
305 } else {
306 trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
307 }
308 } else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
309 trigger(Event:WB_Ack, in_msg.addr, cache_entry, tbe);
310 } else {
311 error("Invalid L1 response type");
312 }
313 }
314 }
315 }
316
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];
324
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,
328 cache_entry, tbe);
329 } else {
330 trigger(Event:Inv, in_msg.addr, cache_entry, tbe);
331 }
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,
336 cache_entry, tbe);
337 } else {
338 trigger(Event:Fwd_GETX, in_msg.addr, cache_entry, tbe);
339 }
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,
343 cache_entry, tbe);
344 } else {
345 trigger(Event:Fwd_GETS, in_msg.addr, cache_entry, tbe);
346 }
347 } else {
348 error("Invalid forwarded request type");
349 }
350 }
351 }
352 }
353
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];
360
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);
365 } else {
366 if (is_valid(cache_entry)) {
367 trigger(mandatory_request_type_to_event(in_msg.Class),
368 in_msg.addr, cache_entry, tbe);
369 } else {
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);
375 } else {
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];
380
381 if (is_valid(victim_entry) && inL0Cache(victim_entry.CacheState)) {
382 trigger(Event:L0_Invalidate_Own,
383 victim, victim_entry, victim_tbe);
384 } else {
385 trigger(Event:L1_Replacement,
386 victim, victim_entry, victim_tbe);
387 }
388 }
389 }
390 }
391 }
392 }
393 }
394
395 // ACTIONS
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;
408 }
409 }
410 }
411
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;
425 }
426 }
427 }
428
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;
441 }
442 }
443 }
444
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;
456 }
457 }
458 }
459
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;
471 }
472 }
473
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;
485 }
486 }
487 }
488
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;
500 }
501 }
502
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;
511 }
512 }
513 }
514
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;
526 }
527 }
528
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;
540 }
541 }
542
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;
552 }
553 }
554 }
555
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;
563 }
564 }
565
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;
573 }
574 }
575
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;
588 } else {
589 out_msg.MessageSize := MessageSizeType:Writeback_Control;
590 }
591 }
592 }
593
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);
603 }
604 }
605
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);
615
616 }
617 }
618
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));
622
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;
629 }
630
631 cache.setMRU(address);
632 }
633
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));
637
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;
645
646 //cache_entry.Dirty := true;
647 }
648
649 cache.setMRU(address);
650 }
651
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));
655
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;
663 }
664 }
665
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;
673 }
674
675 action(k_popL0RequestQueue, "k", desc="Pop mandatory queue.") {
676 messageBufferFromL0_in.dequeue(clockEdge());
677 }
678
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));
683 }
684
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));
689 }
690
691 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
692 TBEs.deallocate(address);
693 unset_tbe();
694 }
695
696 action(u_writeDataFromL0Request, "ureql0", desc="Write data to cache") {
697 peek(messageBufferFromL0_in, CoherenceMsg) {
698 assert(is_valid(cache_entry));
699 if (in_msg.Dirty) {
700 cache_entry.DataBlk := in_msg.DataBlk;
701 cache_entry.Dirty := in_msg.Dirty;
702 }
703 }
704 }
705
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;
710 }
711 }
712
713 action(u_writeDataFromL0Response, "uresl0", desc="Write data to cache") {
714 peek(messageBufferFromL0_in, CoherenceMsg) {
715 assert(is_valid(cache_entry));
716 if (in_msg.Dirty) {
717 cache_entry.DataBlk := in_msg.DataBlk;
718 cache_entry.Dirty := in_msg.Dirty;
719 }
720 }
721 }
722
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);
730 }
731 }
732
733 action(ff_deallocateCacheBlock, "\f",
734 desc="Deallocate L1 cache block.") {
735 if (cache.isTagPresent(address)) {
736 cache.deallocate(address);
737 }
738 unset_cache_entry();
739 }
740
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));
744 }
745 }
746
747 action(z0_stallAndWaitL0Queue, "\z0", desc="recycle L0 request queue") {
748 stall_and_wait(messageBufferFromL0_in, address);
749 }
750
751 action(z2_stallAndWaitL2Queue, "\z2", desc="recycle L2 request queue") {
752 stall_and_wait(requestNetwork_in, address);
753 }
754
755 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
756 wakeUpAllBuffers(address);
757 }
758
759 action(uu_profileMiss, "\um", desc="Profile the demand miss") {
760 ++cache.demand_misses;
761 }
762
763 action(uu_profileHit, "\uh", desc="Profile the demand hit") {
764 ++cache.demand_hits;
765 }
766
767
768 //*****************************************************
769 // TRANSITIONS
770 //*****************************************************
771
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;
776 }
777
778 transition(I, Load, IS) {
779 oo_allocateCacheBlock;
780 i_allocateTBE;
781 a_issueGETS;
782 uu_profileMiss;
783 k_popL0RequestQueue;
784 }
785
786 transition(I, Store, IM) {
787 oo_allocateCacheBlock;
788 i_allocateTBE;
789 b_issueGETX;
790 uu_profileMiss;
791 k_popL0RequestQueue;
792 }
793
794 transition(I, Inv) {
795 fi_sendInvAck;
796 l_popL2RequestQueue;
797 }
798
799 // Transitions from Shared
800 transition({S,SS}, Load, S) {
801 h_data_to_l0;
802 uu_profileHit;
803 k_popL0RequestQueue;
804 }
805
806 transition(EE, Load, E) {
807 hh_xdata_to_l0;
808 uu_profileHit;
809 k_popL0RequestQueue;
810 }
811
812 transition(MM, Load, M) {
813 hh_xdata_to_l0;
814 uu_profileHit;
815 k_popL0RequestQueue;
816 }
817
818 transition({S,SS}, Store, SM) {
819 i_allocateTBE;
820 c_issueUPGRADE;
821 uu_profileMiss;
822 k_popL0RequestQueue;
823 }
824
825 transition(SS, L1_Replacement, I) {
826 ff_deallocateCacheBlock;
827 }
828
829 transition(S, L0_Invalidate_Own, S_IL0) {
830 forward_eviction_to_L0_own;
831 }
832
833 transition(S, L0_Invalidate_Else, S_IL0) {
834 forward_eviction_to_L0_else;
835 }
836
837 transition(SS, Inv, I) {
838 fi_sendInvAck;
839 ff_deallocateCacheBlock;
840 l_popL2RequestQueue;
841 }
842
843 // Transitions from Exclusive
844
845 transition({EE,MM}, Store, M) {
846 hh_xdata_to_l0;
847 uu_profileHit;
848 k_popL0RequestQueue;
849 }
850
851 transition(EE, L1_Replacement, M_I) {
852 // silent E replacement??
853 i_allocateTBE;
854 g_issuePUTX; // send data, but hold in case forwarded request
855 ff_deallocateCacheBlock;
856 }
857
858 transition(EE, Inv, I) {
859 // don't send data
860 fi_sendInvAck;
861 ff_deallocateCacheBlock;
862 l_popL2RequestQueue;
863 }
864
865 transition(EE, Fwd_GETX, I) {
866 d_sendDataToRequestor;
867 ff_deallocateCacheBlock;
868 l_popL2RequestQueue;
869 }
870
871 transition(EE, Fwd_GETS, SS) {
872 d_sendDataToRequestor;
873 d2_sendDataToL2;
874 l_popL2RequestQueue;
875 }
876
877 transition(E, L0_Invalidate_Own, E_IL0) {
878 forward_eviction_to_L0_own;
879 }
880
881 transition(E, L0_Invalidate_Else, E_IL0) {
882 forward_eviction_to_L0_else;
883 }
884
885 // Transitions from Modified
886 transition(MM, L1_Replacement, M_I) {
887 i_allocateTBE;
888 g_issuePUTX; // send data, but hold in case forwarded request
889 ff_deallocateCacheBlock;
890 }
891
892 transition({M,E}, WriteBack, MM) {
893 u_writeDataFromL0Request;
894 k_popL0RequestQueue;
895 }
896
897 transition(M_I, WB_Ack, I) {
898 s_deallocateTBE;
899 o_popL2ResponseQueue;
900 ff_deallocateCacheBlock;
901 kd_wakeUpDependents;
902 }
903
904 transition(MM, Inv, I) {
905 f_sendDataToL2;
906 ff_deallocateCacheBlock;
907 l_popL2RequestQueue;
908 }
909
910 transition(M_I, Inv, SINK_WB_ACK) {
911 ft_sendDataToL2_fromTBE;
912 l_popL2RequestQueue;
913 }
914
915 transition(MM, Fwd_GETX, I) {
916 d_sendDataToRequestor;
917 ff_deallocateCacheBlock;
918 l_popL2RequestQueue;
919 }
920
921 transition(MM, Fwd_GETS, SS) {
922 d_sendDataToRequestor;
923 d2_sendDataToL2;
924 l_popL2RequestQueue;
925 }
926
927 transition(M, L0_Invalidate_Own, M_IL0) {
928 forward_eviction_to_L0_own;
929 }
930
931 transition(M, L0_Invalidate_Else, M_IL0) {
932 forward_eviction_to_L0_else;
933 }
934
935 transition(M_I, Fwd_GETX, SINK_WB_ACK) {
936 dt_sendDataToRequestor_fromTBE;
937 l_popL2RequestQueue;
938 }
939
940 transition(M_I, Fwd_GETS, SINK_WB_ACK) {
941 dt_sendDataToRequestor_fromTBE;
942 d2t_sendDataToL2_fromTBE;
943 l_popL2RequestQueue;
944 }
945
946 // Transitions from IS
947 transition({IS,IS_I}, Inv, IS_I) {
948 fi_sendInvAck;
949 l_popL2RequestQueue;
950 }
951
952 transition(IS, Data_all_Acks, S) {
953 u_writeDataFromL2Response;
954 h_data_to_l0;
955 s_deallocateTBE;
956 o_popL2ResponseQueue;
957 kd_wakeUpDependents;
958 }
959
960 transition(IS_I, Data_all_Acks, I) {
961 u_writeDataFromL2Response;
962 h_stale_data_to_l0;
963 s_deallocateTBE;
964 ff_deallocateCacheBlock;
965 o_popL2ResponseQueue;
966 kd_wakeUpDependents;
967 }
968
969 transition(IS, DataS_fromL1, S) {
970 u_writeDataFromL2Response;
971 j_sendUnblock;
972 h_data_to_l0;
973 s_deallocateTBE;
974 o_popL2ResponseQueue;
975 kd_wakeUpDependents;
976 }
977
978 transition(IS_I, DataS_fromL1, I) {
979 u_writeDataFromL2Response;
980 j_sendUnblock;
981 h_stale_data_to_l0;
982 s_deallocateTBE;
983 ff_deallocateCacheBlock;
984 o_popL2ResponseQueue;
985 kd_wakeUpDependents;
986 }
987
988 // directory is blocked when sending exclusive data
989 transition({IS,IS_I}, Data_Exclusive, E) {
990 u_writeDataFromL2Response;
991 hh_xdata_to_l0;
992 jj_sendExclusiveUnblock;
993 s_deallocateTBE;
994 o_popL2ResponseQueue;
995 kd_wakeUpDependents;
996 }
997
998 // Transitions from IM
999 transition({IM,SM}, Inv, IM) {
1000 fi_sendInvAck;
1001 l_popL2RequestQueue;
1002 }
1003
1004 transition(IM, Data, SM) {
1005 u_writeDataFromL2Response;
1006 q_updateAckCount;
1007 o_popL2ResponseQueue;
1008 }
1009
1010 transition(IM, Data_all_Acks, M) {
1011 u_writeDataFromL2Response;
1012 hh_xdata_to_l0;
1013 jj_sendExclusiveUnblock;
1014 s_deallocateTBE;
1015 o_popL2ResponseQueue;
1016 kd_wakeUpDependents;
1017 }
1018
1019 transition({SM, IM}, Ack) {
1020 q_updateAckCount;
1021 o_popL2ResponseQueue;
1022 }
1023
1024 transition(SM, Ack_all, M) {
1025 jj_sendExclusiveUnblock;
1026 hh_xdata_to_l0;
1027 s_deallocateTBE;
1028 o_popL2ResponseQueue;
1029 kd_wakeUpDependents;
1030 }
1031
1032 transition(SM, L0_Invalidate_Else, SM_IL0) {
1033 forward_eviction_to_L0_else;
1034 }
1035
1036 transition(SINK_WB_ACK, Inv){
1037 fi_sendInvAck;
1038 l_popL2RequestQueue;
1039 }
1040
1041 transition(SINK_WB_ACK, WB_Ack, I){
1042 s_deallocateTBE;
1043 o_popL2ResponseQueue;
1044 ff_deallocateCacheBlock;
1045 kd_wakeUpDependents;
1046 }
1047
1048 transition({M_IL0, E_IL0}, WriteBack, MM_IL0) {
1049 u_writeDataFromL0Request;
1050 k_popL0RequestQueue;
1051 kd_wakeUpDependents;
1052 }
1053
1054 transition({M_IL0, E_IL0}, L0_DataAck, MM) {
1055 u_writeDataFromL0Response;
1056 k_popL0RequestQueue;
1057 kd_wakeUpDependents;
1058 }
1059
1060 transition({M_IL0, MM_IL0}, L0_Ack, MM) {
1061 k_popL0RequestQueue;
1062 kd_wakeUpDependents;
1063 }
1064
1065 transition(E_IL0, L0_Ack, EE) {
1066 k_popL0RequestQueue;
1067 kd_wakeUpDependents;
1068 }
1069
1070 transition(S_IL0, L0_Ack, SS) {
1071 k_popL0RequestQueue;
1072 kd_wakeUpDependents;
1073 }
1074
1075 transition(SM_IL0, L0_Ack, IM) {
1076 k_popL0RequestQueue;
1077 kd_wakeUpDependents;
1078 }
1079
1080 transition({S_IL0, M_IL0, E_IL0, SM_IL0, SM}, L0_Invalidate_Own) {
1081 z0_stallAndWaitL0Queue;
1082 }
1083
1084 transition({S_IL0, M_IL0, E_IL0, SM_IL0}, L0_Invalidate_Else) {
1085 z2_stallAndWaitL2Queue;
1086 }
1087
1088 transition({S_IL0, M_IL0, E_IL0, MM_IL0}, {Inv, Fwd_GETX, Fwd_GETS}) {
1089 z2_stallAndWaitL2Queue;
1090 }
1091 }