misc: Updated the RELEASE-NOTES and version number
[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 // hardware transactional memory
135 L0_DataCopy, desc="Data Block from L0. Should remain in M state.";
136
137 // L0 cache received the invalidation message and has
138 // sent a NAK (because of htm abort) saying that the data
139 // in L1 is the latest value.
140 L0_DataNak, desc="L0 received INV message, specifies its data is also stale";
141 }
142
143 // TYPES
144
145 // CacheEntry
146 structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
147 State CacheState, desc="cache state";
148 DataBlock DataBlk, desc="data for the block";
149 bool Dirty, default="false", desc="data is dirty";
150 }
151
152 // TBE fields
153 structure(TBE, desc="...") {
154 Addr addr, desc="Physical address for this TBE";
155 State TBEState, desc="Transient state";
156 DataBlock DataBlk, desc="Buffer for the data block";
157 bool Dirty, default="false", desc="data is dirty";
158 int pendingAcks, default="0", desc="number of pending acks";
159 }
160
161 structure(TBETable, external="yes") {
162 TBE lookup(Addr);
163 void allocate(Addr);
164 void deallocate(Addr);
165 bool isPresent(Addr);
166 }
167
168 TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
169
170 int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
171
172 Tick clockEdge();
173 Cycles ticksToCycles(Tick t);
174 void set_cache_entry(AbstractCacheEntry a);
175 void unset_cache_entry();
176 void set_tbe(TBE a);
177 void unset_tbe();
178 void wakeUpBuffers(Addr a);
179 void wakeUpAllBuffers(Addr a);
180 void profileMsgDelay(int virtualNetworkType, Cycles c);
181
182 // inclusive cache returns L1 entries only
183 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
184 Entry cache_entry := static_cast(Entry, "pointer", cache[addr]);
185 return cache_entry;
186 }
187
188 State getState(TBE tbe, Entry cache_entry, Addr addr) {
189 if(is_valid(tbe)) {
190 return tbe.TBEState;
191 } else if (is_valid(cache_entry)) {
192 return cache_entry.CacheState;
193 }
194 return State:I;
195 }
196
197 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
198 // MUST CHANGE
199 if(is_valid(tbe)) {
200 tbe.TBEState := state;
201 }
202
203 if (is_valid(cache_entry)) {
204 cache_entry.CacheState := state;
205 }
206 }
207
208 AccessPermission getAccessPermission(Addr addr) {
209 TBE tbe := TBEs[addr];
210 if(is_valid(tbe)) {
211 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
212 return L1Cache_State_to_permission(tbe.TBEState);
213 }
214
215 Entry cache_entry := getCacheEntry(addr);
216 if(is_valid(cache_entry)) {
217 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
218 return L1Cache_State_to_permission(cache_entry.CacheState);
219 }
220
221 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
222 return AccessPermission:NotPresent;
223 }
224
225 void functionalRead(Addr addr, Packet *pkt) {
226 TBE tbe := TBEs[addr];
227 if(is_valid(tbe)) {
228 testAndRead(addr, tbe.DataBlk, pkt);
229 } else {
230 testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
231 }
232 }
233
234 int functionalWrite(Addr addr, Packet *pkt) {
235 int num_functional_writes := 0;
236
237 TBE tbe := TBEs[addr];
238 if(is_valid(tbe)) {
239 num_functional_writes := num_functional_writes +
240 testAndWrite(addr, tbe.DataBlk, pkt);
241 return num_functional_writes;
242 }
243
244 num_functional_writes := num_functional_writes +
245 testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
246 return num_functional_writes;
247 }
248
249 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
250 if (is_valid(cache_entry)) {
251 cache_entry.changePermission(L1Cache_State_to_permission(state));
252 }
253 }
254
255 Event mandatory_request_type_to_event(CoherenceClass type) {
256 if (type == CoherenceClass:GETS) {
257 return Event:Load;
258 } else if ((type == CoherenceClass:GETX) ||
259 (type == CoherenceClass:UPGRADE)) {
260 return Event:Store;
261 } else if (type == CoherenceClass:PUTX) {
262 return Event:WriteBack;
263 } else {
264 error("Invalid RequestType");
265 }
266 }
267
268 int getPendingAcks(TBE tbe) {
269 return tbe.pendingAcks;
270 }
271
272 bool inL0Cache(State state) {
273 if (state == State:S || state == State:E ||
274 state == State:M || state == State:SM ||
275 state == State:S_IL0 || state == State:E_IL0 ||
276 state == State:M_IL0 || state == State:SM_IL0) {
277 return true;
278 }
279
280 return false;
281 }
282
283 out_port(requestNetwork_out, RequestMsg, requestToL2);
284 out_port(responseNetwork_out, ResponseMsg, responseToL2);
285 out_port(unblockNetwork_out, ResponseMsg, unblockToL2);
286 out_port(bufferToL0_out, CoherenceMsg, bufferToL0);
287
288 // Response From the L2 Cache to this L1 cache
289 in_port(responseNetwork_in, ResponseMsg, responseFromL2, rank = 2) {
290 if (responseNetwork_in.isReady(clockEdge())) {
291 peek(responseNetwork_in, ResponseMsg) {
292 assert(in_msg.Destination.isElement(machineID));
293
294 Entry cache_entry := getCacheEntry(in_msg.addr);
295 TBE tbe := TBEs[in_msg.addr];
296
297 if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
298 trigger(Event:Data_Exclusive, in_msg.addr, cache_entry, tbe);
299 } else if(in_msg.Type == CoherenceResponseType:DATA) {
300 if ((getState(tbe, cache_entry, in_msg.addr) == State:IS ||
301 getState(tbe, cache_entry, in_msg.addr) == State:IS_I) &&
302 machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
303
304 trigger(Event:DataS_fromL1, in_msg.addr, cache_entry, tbe);
305
306 } else if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
307 trigger(Event:Data_all_Acks, in_msg.addr, cache_entry, tbe);
308 } else {
309 trigger(Event:Data, in_msg.addr, cache_entry, tbe);
310 }
311 } else if (in_msg.Type == CoherenceResponseType:ACK) {
312 if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
313 trigger(Event:Ack_all, in_msg.addr, cache_entry, tbe);
314 } else {
315 trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
316 }
317 } else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
318 trigger(Event:WB_Ack, in_msg.addr, cache_entry, tbe);
319 } else {
320 error("Invalid L1 response type");
321 }
322 }
323 }
324 }
325
326 // Request to this L1 cache from the shared L2
327 in_port(requestNetwork_in, RequestMsg, requestFromL2, rank = 1) {
328 if(requestNetwork_in.isReady(clockEdge())) {
329 peek(requestNetwork_in, RequestMsg) {
330 assert(in_msg.Destination.isElement(machineID));
331 Entry cache_entry := getCacheEntry(in_msg.addr);
332 TBE tbe := TBEs[in_msg.addr];
333
334 if (in_msg.Type == CoherenceRequestType:INV) {
335 if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
336 trigger(Event:L0_Invalidate_Else, in_msg.addr,
337 cache_entry, tbe);
338 } else {
339 trigger(Event:Inv, in_msg.addr, cache_entry, tbe);
340 }
341 } else if (in_msg.Type == CoherenceRequestType:GETX ||
342 in_msg.Type == CoherenceRequestType:UPGRADE) {
343 if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
344 trigger(Event:L0_Invalidate_Else, in_msg.addr,
345 cache_entry, tbe);
346 } else {
347 trigger(Event:Fwd_GETX, in_msg.addr, cache_entry, tbe);
348 }
349 } else if (in_msg.Type == CoherenceRequestType:GETS) {
350 if (is_valid(cache_entry) && inL0Cache(cache_entry.CacheState)) {
351 trigger(Event:L0_Invalidate_Else, in_msg.addr,
352 cache_entry, tbe);
353 } else {
354 trigger(Event:Fwd_GETS, in_msg.addr, cache_entry, tbe);
355 }
356 } else {
357 error("Invalid forwarded request type");
358 }
359 }
360 }
361 }
362
363 // Requests to this L1 cache from the L0 cache.
364 in_port(messageBufferFromL0_in, CoherenceMsg, bufferFromL0, rank = 0) {
365 if (messageBufferFromL0_in.isReady(clockEdge())) {
366 peek(messageBufferFromL0_in, CoherenceMsg) {
367 Entry cache_entry := getCacheEntry(in_msg.addr);
368 TBE tbe := TBEs[in_msg.addr];
369
370 if(in_msg.Class == CoherenceClass:INV_DATA) {
371 trigger(Event:L0_DataAck, in_msg.addr, cache_entry, tbe);
372 } else if (in_msg.Class == CoherenceClass:NAK) {
373 trigger(Event:L0_DataNak, in_msg.addr, cache_entry, tbe);
374 } else if (in_msg.Class == CoherenceClass:PUTX_COPY) {
375 trigger(Event:L0_DataCopy, in_msg.addr, cache_entry, tbe);
376 } else if (in_msg.Class == CoherenceClass:INV_ACK) {
377 trigger(Event:L0_Ack, in_msg.addr, cache_entry, tbe);
378 } else {
379 if (is_valid(cache_entry)) {
380 trigger(mandatory_request_type_to_event(in_msg.Class),
381 in_msg.addr, cache_entry, tbe);
382 } else {
383 if (cache.cacheAvail(in_msg.addr)) {
384 // L1 does't have the line, but we have space for it
385 // in the L1 let's see if the L2 has it
386 trigger(mandatory_request_type_to_event(in_msg.Class),
387 in_msg.addr, cache_entry, tbe);
388 } else {
389 // No room in the L1, so we need to make room in the L1
390 Addr victim := cache.cacheProbe(in_msg.addr);
391 Entry victim_entry := getCacheEntry(victim);
392 TBE victim_tbe := TBEs[victim];
393
394 if (is_valid(victim_entry) && inL0Cache(victim_entry.CacheState)) {
395 trigger(Event:L0_Invalidate_Own,
396 victim, victim_entry, victim_tbe);
397 } else {
398 trigger(Event:L1_Replacement,
399 victim, victim_entry, victim_tbe);
400 }
401 }
402 }
403 }
404 }
405 }
406 }
407
408 // ACTIONS
409 action(a_issueGETS, "a", desc="Issue GETS") {
410 peek(messageBufferFromL0_in, CoherenceMsg) {
411 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
412 out_msg.addr := address;
413 out_msg.Type := CoherenceRequestType:GETS;
414 out_msg.Requestor := machineID;
415 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
416 l2_select_low_bit, l2_select_num_bits, clusterID));
417 DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
418 address, out_msg.Destination);
419 out_msg.MessageSize := MessageSizeType:Control;
420 out_msg.AccessMode := in_msg.AccessMode;
421 out_msg.Prefetch := in_msg.Prefetch;
422 }
423 }
424 }
425
426 action(b_issueGETX, "b", desc="Issue GETX") {
427 peek(messageBufferFromL0_in, CoherenceMsg) {
428 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
429 out_msg.addr := address;
430 out_msg.Type := CoherenceRequestType:GETX;
431 out_msg.Requestor := machineID;
432 DPRINTF(RubySlicc, "%s\n", machineID);
433 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
434 l2_select_low_bit, l2_select_num_bits, clusterID));
435 DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
436 address, out_msg.Destination);
437 out_msg.MessageSize := MessageSizeType:Control;
438 out_msg.AccessMode := in_msg.AccessMode;
439 out_msg.Prefetch := in_msg.Prefetch;
440 }
441 }
442 }
443
444 action(c_issueUPGRADE, "c", desc="Issue GETX") {
445 peek(messageBufferFromL0_in, CoherenceMsg) {
446 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) {
447 out_msg.addr := address;
448 out_msg.Type := CoherenceRequestType:UPGRADE;
449 out_msg.Requestor := machineID;
450 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
451 l2_select_low_bit, l2_select_num_bits, clusterID));
452 DPRINTF(RubySlicc, "address: %#x, destination: %s\n",
453 address, out_msg.Destination);
454 out_msg.MessageSize := MessageSizeType:Control;
455 out_msg.AccessMode := in_msg.AccessMode;
456 out_msg.Prefetch := in_msg.Prefetch;
457 }
458 }
459 }
460
461 action(d_sendDataToRequestor, "d", desc="send data to requestor") {
462 peek(requestNetwork_in, RequestMsg) {
463 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
464 assert(is_valid(cache_entry));
465 out_msg.addr := address;
466 out_msg.Type := CoherenceResponseType:DATA;
467 out_msg.DataBlk := cache_entry.DataBlk;
468 out_msg.Dirty := cache_entry.Dirty;
469 out_msg.Sender := machineID;
470 out_msg.Destination.add(in_msg.Requestor);
471 out_msg.MessageSize := MessageSizeType:Response_Data;
472 }
473 }
474 }
475
476 action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") {
477 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
478 assert(is_valid(cache_entry));
479 out_msg.addr := address;
480 out_msg.Type := CoherenceResponseType:DATA;
481 out_msg.DataBlk := cache_entry.DataBlk;
482 out_msg.Dirty := cache_entry.Dirty;
483 out_msg.Sender := machineID;
484 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
485 l2_select_low_bit, l2_select_num_bits, clusterID));
486 out_msg.MessageSize := MessageSizeType:Response_Data;
487 }
488 }
489
490 action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") {
491 peek(requestNetwork_in, RequestMsg) {
492 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
493 assert(is_valid(tbe));
494 out_msg.addr := address;
495 out_msg.Type := CoherenceResponseType:DATA;
496 out_msg.DataBlk := tbe.DataBlk;
497 out_msg.Dirty := tbe.Dirty;
498 out_msg.Sender := machineID;
499 out_msg.Destination.add(in_msg.Requestor);
500 out_msg.MessageSize := MessageSizeType:Response_Data;
501 }
502 }
503 }
504
505 action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") {
506 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
507 assert(is_valid(tbe));
508 out_msg.addr := address;
509 out_msg.Type := CoherenceResponseType:DATA;
510 out_msg.DataBlk := tbe.DataBlk;
511 out_msg.Dirty := tbe.Dirty;
512 out_msg.Sender := machineID;
513 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
514 l2_select_low_bit, l2_select_num_bits, clusterID));
515 out_msg.MessageSize := MessageSizeType:Response_Data;
516 }
517 }
518
519 action(e_sendAckToRequestor, "e", desc="send invalidate ack to requestor (could be L2 or L1)") {
520 peek(requestNetwork_in, RequestMsg) {
521 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
522 out_msg.addr := address;
523 out_msg.Type := CoherenceResponseType:ACK;
524 out_msg.Sender := machineID;
525 out_msg.Destination.add(in_msg.Requestor);
526 out_msg.MessageSize := MessageSizeType:Response_Control;
527 }
528 }
529 }
530
531 action(f_sendDataToL2, "f", desc="send data to the L2 cache") {
532 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
533 assert(is_valid(cache_entry));
534 out_msg.addr := address;
535 out_msg.Type := CoherenceResponseType:DATA;
536 out_msg.DataBlk := cache_entry.DataBlk;
537 out_msg.Dirty := cache_entry.Dirty;
538 out_msg.Sender := machineID;
539 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
540 l2_select_low_bit, l2_select_num_bits, clusterID));
541 out_msg.MessageSize := MessageSizeType:Writeback_Data;
542 }
543 }
544
545 action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") {
546 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
547 assert(is_valid(tbe));
548 out_msg.addr := address;
549 out_msg.Type := CoherenceResponseType:DATA;
550 out_msg.DataBlk := tbe.DataBlk;
551 out_msg.Dirty := tbe.Dirty;
552 out_msg.Sender := machineID;
553 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
554 l2_select_low_bit, l2_select_num_bits, clusterID));
555 out_msg.MessageSize := MessageSizeType:Writeback_Data;
556 }
557 }
558
559 action(fi_sendInvAck, "fi", desc="send data to the L2 cache") {
560 peek(requestNetwork_in, RequestMsg) {
561 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) {
562 out_msg.addr := address;
563 out_msg.Type := CoherenceResponseType:ACK;
564 out_msg.Sender := machineID;
565 out_msg.Destination.add(in_msg.Requestor);
566 out_msg.MessageSize := MessageSizeType:Response_Control;
567 out_msg.AckCount := 1;
568 }
569 }
570 }
571
572 action(forward_eviction_to_L0_own, "\cc", desc="sends (own) eviction information to the processor") {
573 enqueue(bufferToL0_out, CoherenceMsg, l1_request_latency) {
574 out_msg.addr := address;
575 out_msg.Class := CoherenceClass:INV_OWN;
576 out_msg.Sender := machineID;
577 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
578 out_msg.MessageSize := MessageSizeType:Control;
579 }
580 }
581
582 action(forward_eviction_to_L0_else, "\cce", desc="sends (else) eviction information to the processor") {
583 enqueue(bufferToL0_out, CoherenceMsg, l1_request_latency) {
584 out_msg.addr := address;
585 out_msg.Class := CoherenceClass:INV_ELSE;
586 out_msg.Sender := machineID;
587 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
588 out_msg.MessageSize := MessageSizeType:Control;
589 }
590 }
591
592 action(g_issuePUTX, "g", desc="send data to the L2 cache") {
593 enqueue(requestNetwork_out, RequestMsg, l1_response_latency) {
594 assert(is_valid(cache_entry));
595 out_msg.addr := address;
596 out_msg.Type := CoherenceRequestType:PUTX;
597 out_msg.Dirty := cache_entry.Dirty;
598 out_msg.Requestor:= machineID;
599 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
600 l2_select_low_bit, l2_select_num_bits, clusterID));
601 if (cache_entry.Dirty) {
602 out_msg.MessageSize := MessageSizeType:Writeback_Data;
603 out_msg.DataBlk := cache_entry.DataBlk;
604 } else {
605 out_msg.MessageSize := MessageSizeType:Writeback_Control;
606 }
607 }
608 }
609
610 action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
611 enqueue(unblockNetwork_out, ResponseMsg, to_l2_latency) {
612 out_msg.addr := address;
613 out_msg.Type := CoherenceResponseType:UNBLOCK;
614 out_msg.Sender := machineID;
615 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
616 l2_select_low_bit, l2_select_num_bits, clusterID));
617 out_msg.MessageSize := MessageSizeType:Response_Control;
618 DPRINTF(RubySlicc, "%#x\n", address);
619 }
620 }
621
622 action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
623 enqueue(unblockNetwork_out, ResponseMsg, to_l2_latency) {
624 out_msg.addr := address;
625 out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
626 out_msg.Sender := machineID;
627 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
628 l2_select_low_bit, l2_select_num_bits, clusterID));
629 out_msg.MessageSize := MessageSizeType:Response_Control;
630 DPRINTF(RubySlicc, "%#x\n", address);
631
632 }
633 }
634
635 action(h_data_to_l0, "h", desc="If not prefetch, send data to the L0 cache.") {
636 enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
637 assert(is_valid(cache_entry));
638
639 out_msg.addr := address;
640 out_msg.Class := CoherenceClass:DATA;
641 out_msg.Sender := machineID;
642 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
643 out_msg.DataBlk := cache_entry.DataBlk;
644 out_msg.MessageSize := MessageSizeType:Response_Data;
645 }
646
647 cache.setMRU(address);
648 }
649
650 action(hh_xdata_to_l0, "\h", desc="If not prefetch, notify sequencer that store completed.") {
651 enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
652 assert(is_valid(cache_entry));
653
654 out_msg.addr := address;
655 out_msg.Class := CoherenceClass:DATA_EXCLUSIVE;
656 out_msg.Sender := machineID;
657 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
658 out_msg.DataBlk := cache_entry.DataBlk;
659 out_msg.Dirty := cache_entry.Dirty;
660 out_msg.MessageSize := MessageSizeType:Response_Data;
661
662 //cache_entry.Dirty := true;
663 }
664
665 cache.setMRU(address);
666 }
667
668 action(h_stale_data_to_l0, "hs", desc="If not prefetch, send data to the L0 cache.") {
669 enqueue(bufferToL0_out, CoherenceMsg, l1_response_latency) {
670 assert(is_valid(cache_entry));
671
672 out_msg.addr := address;
673 out_msg.Class := CoherenceClass:STALE_DATA;
674 out_msg.Sender := machineID;
675 out_msg.Dest := createMachineID(MachineType:L0Cache, version);
676 out_msg.DataBlk := cache_entry.DataBlk;
677 out_msg.Dirty := cache_entry.Dirty;
678 out_msg.MessageSize := MessageSizeType:Response_Data;
679 }
680 }
681
682 action(i_allocateTBE, "i", desc="Allocate TBE (number of invalidates=0)") {
683 check_allocate(TBEs);
684 assert(is_valid(cache_entry));
685 TBEs.allocate(address);
686 set_tbe(TBEs[address]);
687 tbe.Dirty := cache_entry.Dirty;
688 tbe.DataBlk := cache_entry.DataBlk;
689 }
690
691 action(k_popL0RequestQueue, "k", desc="Pop mandatory queue.") {
692 messageBufferFromL0_in.dequeue(clockEdge());
693 }
694
695 action(l_popL2RequestQueue, "l",
696 desc="Pop incoming request queue and profile the delay within this virtual network") {
697 Tick delay := requestNetwork_in.dequeue(clockEdge());
698 profileMsgDelay(2, ticksToCycles(delay));
699 }
700
701 action(o_popL2ResponseQueue, "o",
702 desc="Pop Incoming Response queue and profile the delay within this virtual network") {
703 Tick delay := responseNetwork_in.dequeue(clockEdge());
704 profileMsgDelay(1, ticksToCycles(delay));
705 }
706
707 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
708 TBEs.deallocate(address);
709 unset_tbe();
710 }
711
712 action(u_writeDataFromL0Request, "ureql0", desc="Write data to cache") {
713 peek(messageBufferFromL0_in, CoherenceMsg) {
714 assert(is_valid(cache_entry));
715 if (in_msg.Dirty) {
716 cache_entry.DataBlk := in_msg.DataBlk;
717 cache_entry.Dirty := in_msg.Dirty;
718 }
719 }
720 }
721
722 action(u_writeDataFromL2Response, "uresl2", desc="Write data to cache") {
723 peek(responseNetwork_in, ResponseMsg) {
724 assert(is_valid(cache_entry));
725 cache_entry.DataBlk := in_msg.DataBlk;
726 cache_entry.Dirty := in_msg.Dirty;
727 }
728 }
729
730 action(u_writeDataFromL0Response, "uresl0", desc="Write data to cache") {
731 peek(messageBufferFromL0_in, CoherenceMsg) {
732 assert(is_valid(cache_entry));
733 if (in_msg.Dirty) {
734 cache_entry.DataBlk := in_msg.DataBlk;
735 cache_entry.Dirty := in_msg.Dirty;
736 }
737 }
738 }
739
740 action(q_updateAckCount, "q", desc="Update ack count") {
741 peek(responseNetwork_in, ResponseMsg) {
742 assert(is_valid(tbe));
743 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
744 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
745 APPEND_TRANSITION_COMMENT(" p: ");
746 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
747 }
748 }
749
750 action(ff_deallocateCacheBlock, "\f",
751 desc="Deallocate L1 cache block.") {
752 if (cache.isTagPresent(address)) {
753 cache.deallocate(address);
754 }
755 unset_cache_entry();
756 }
757
758 action(oo_allocateCacheBlock, "\o", desc="Set cache tag equal to tag of block B.") {
759 if (is_invalid(cache_entry)) {
760 set_cache_entry(cache.allocate(address, new Entry));
761 }
762 }
763
764 action(z0_stallAndWaitL0Queue, "\z0", desc="recycle L0 request queue") {
765 stall_and_wait(messageBufferFromL0_in, address);
766 }
767
768 action(z2_stallAndWaitL2Queue, "\z2", desc="recycle L2 request queue") {
769 stall_and_wait(requestNetwork_in, address);
770 }
771
772 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
773 wakeUpAllBuffers(address);
774 }
775
776 action(uu_profileMiss, "\um", desc="Profile the demand miss") {
777 ++cache.demand_misses;
778 }
779
780 action(uu_profileHit, "\uh", desc="Profile the demand hit") {
781 ++cache.demand_hits;
782 }
783
784
785 //*****************************************************
786 // TRANSITIONS
787 //*****************************************************
788
789 // Transitions for Load/Store/Replacement/WriteBack from transient states
790 transition({IS, IM, IS_I, M_I, SM, SINK_WB_ACK, S_IL0, M_IL0, E_IL0, MM_IL0},
791 {Load, Store, L1_Replacement}) {
792 z0_stallAndWaitL0Queue;
793 }
794
795 transition(I, Load, IS) {
796 oo_allocateCacheBlock;
797 i_allocateTBE;
798 a_issueGETS;
799 uu_profileMiss;
800 k_popL0RequestQueue;
801 }
802
803 transition(I, Store, IM) {
804 oo_allocateCacheBlock;
805 i_allocateTBE;
806 b_issueGETX;
807 uu_profileMiss;
808 k_popL0RequestQueue;
809 }
810
811 transition(I, Inv) {
812 fi_sendInvAck;
813 l_popL2RequestQueue;
814 }
815
816 // Transitions from Shared
817 transition({S,SS}, Load, S) {
818 h_data_to_l0;
819 uu_profileHit;
820 k_popL0RequestQueue;
821 }
822
823 transition({S,SS}, Store, SM) {
824 i_allocateTBE;
825 c_issueUPGRADE;
826 uu_profileMiss;
827 k_popL0RequestQueue;
828 }
829
830 transition(SS, L1_Replacement, I) {
831 ff_deallocateCacheBlock;
832 }
833
834 transition(S, L0_Invalidate_Own, S_IL0) {
835 forward_eviction_to_L0_own;
836 }
837
838 transition(S, L0_Invalidate_Else, S_IL0) {
839 forward_eviction_to_L0_else;
840 }
841
842 transition(SS, Inv, I) {
843 fi_sendInvAck;
844 ff_deallocateCacheBlock;
845 l_popL2RequestQueue;
846 }
847
848 // Transitions from Exclusive
849
850 transition({EE,MM}, Store, M) {
851 hh_xdata_to_l0;
852 uu_profileHit;
853 k_popL0RequestQueue;
854 }
855
856 transition(EE, L1_Replacement, M_I) {
857 // silent E replacement??
858 i_allocateTBE;
859 g_issuePUTX; // send data, but hold in case forwarded request
860 ff_deallocateCacheBlock;
861 }
862
863 transition(EE, Inv, I) {
864 // don't send data
865 fi_sendInvAck;
866 ff_deallocateCacheBlock;
867 l_popL2RequestQueue;
868 }
869
870 transition(EE, Fwd_GETX, I) {
871 d_sendDataToRequestor;
872 ff_deallocateCacheBlock;
873 l_popL2RequestQueue;
874 }
875
876 transition(EE, Fwd_GETS, SS) {
877 d_sendDataToRequestor;
878 d2_sendDataToL2;
879 l_popL2RequestQueue;
880 }
881
882 transition(E, L0_Invalidate_Own, E_IL0) {
883 forward_eviction_to_L0_own;
884 }
885
886 transition(E, L0_Invalidate_Else, E_IL0) {
887 forward_eviction_to_L0_else;
888 }
889
890 // Transitions from Modified
891 transition(MM, L1_Replacement, M_I) {
892 i_allocateTBE;
893 g_issuePUTX; // send data, but hold in case forwarded request
894 ff_deallocateCacheBlock;
895 }
896
897 transition({M,E}, WriteBack, MM) {
898 u_writeDataFromL0Request;
899 k_popL0RequestQueue;
900 }
901
902 transition(M_I, WB_Ack, I) {
903 s_deallocateTBE;
904 o_popL2ResponseQueue;
905 ff_deallocateCacheBlock;
906 kd_wakeUpDependents;
907 }
908
909 transition(MM, Inv, I) {
910 f_sendDataToL2;
911 ff_deallocateCacheBlock;
912 l_popL2RequestQueue;
913 }
914
915 transition(M_I, Inv, SINK_WB_ACK) {
916 ft_sendDataToL2_fromTBE;
917 l_popL2RequestQueue;
918 }
919
920 transition(MM, Fwd_GETX, I) {
921 d_sendDataToRequestor;
922 ff_deallocateCacheBlock;
923 l_popL2RequestQueue;
924 }
925
926 transition(MM, Fwd_GETS, SS) {
927 d_sendDataToRequestor;
928 d2_sendDataToL2;
929 l_popL2RequestQueue;
930 }
931
932 transition(M, L0_Invalidate_Own, M_IL0) {
933 forward_eviction_to_L0_own;
934 }
935
936 transition(M, L0_Invalidate_Else, M_IL0) {
937 forward_eviction_to_L0_else;
938 }
939
940 transition(M_I, Fwd_GETX, SINK_WB_ACK) {
941 dt_sendDataToRequestor_fromTBE;
942 l_popL2RequestQueue;
943 }
944
945 transition(M_I, Fwd_GETS, SINK_WB_ACK) {
946 dt_sendDataToRequestor_fromTBE;
947 d2t_sendDataToL2_fromTBE;
948 l_popL2RequestQueue;
949 }
950
951 // Transitions from IS
952 transition({IS,IS_I}, Inv, IS_I) {
953 fi_sendInvAck;
954 l_popL2RequestQueue;
955 }
956
957 transition(IS, Data_all_Acks, S) {
958 u_writeDataFromL2Response;
959 h_data_to_l0;
960 s_deallocateTBE;
961 o_popL2ResponseQueue;
962 kd_wakeUpDependents;
963 }
964
965 transition(IS_I, Data_all_Acks, I) {
966 u_writeDataFromL2Response;
967 h_stale_data_to_l0;
968 s_deallocateTBE;
969 ff_deallocateCacheBlock;
970 o_popL2ResponseQueue;
971 kd_wakeUpDependents;
972 }
973
974 transition(IS, DataS_fromL1, S) {
975 u_writeDataFromL2Response;
976 j_sendUnblock;
977 h_data_to_l0;
978 s_deallocateTBE;
979 o_popL2ResponseQueue;
980 kd_wakeUpDependents;
981 }
982
983 transition(IS_I, DataS_fromL1, I) {
984 u_writeDataFromL2Response;
985 j_sendUnblock;
986 h_stale_data_to_l0;
987 s_deallocateTBE;
988 ff_deallocateCacheBlock;
989 o_popL2ResponseQueue;
990 kd_wakeUpDependents;
991 }
992
993 // directory is blocked when sending exclusive data
994 transition({IS,IS_I}, Data_Exclusive, E) {
995 u_writeDataFromL2Response;
996 hh_xdata_to_l0;
997 jj_sendExclusiveUnblock;
998 s_deallocateTBE;
999 o_popL2ResponseQueue;
1000 kd_wakeUpDependents;
1001 }
1002
1003 // Transitions from IM
1004 transition(IM, Inv, IM) {
1005 fi_sendInvAck;
1006 l_popL2RequestQueue;
1007 }
1008
1009 transition(IM, Data, SM) {
1010 u_writeDataFromL2Response;
1011 q_updateAckCount;
1012 o_popL2ResponseQueue;
1013 }
1014
1015 transition(IM, Data_all_Acks, M) {
1016 u_writeDataFromL2Response;
1017 hh_xdata_to_l0;
1018 jj_sendExclusiveUnblock;
1019 s_deallocateTBE;
1020 o_popL2ResponseQueue;
1021 kd_wakeUpDependents;
1022 }
1023
1024 transition({SM, IM}, Ack) {
1025 q_updateAckCount;
1026 o_popL2ResponseQueue;
1027 }
1028
1029 transition(SM, Ack_all, M) {
1030 jj_sendExclusiveUnblock;
1031 hh_xdata_to_l0;
1032 s_deallocateTBE;
1033 o_popL2ResponseQueue;
1034 kd_wakeUpDependents;
1035 }
1036
1037 transition(SM, {Inv,L0_Invalidate_Else}, SM_IL0) {
1038 forward_eviction_to_L0_else;
1039 }
1040
1041 transition(SINK_WB_ACK, Inv){
1042 fi_sendInvAck;
1043 l_popL2RequestQueue;
1044 }
1045
1046 transition(SINK_WB_ACK, WB_Ack, I){
1047 s_deallocateTBE;
1048 o_popL2ResponseQueue;
1049 ff_deallocateCacheBlock;
1050 kd_wakeUpDependents;
1051 }
1052
1053 transition({M_IL0, E_IL0}, WriteBack, MM_IL0) {
1054 u_writeDataFromL0Request;
1055 k_popL0RequestQueue;
1056 kd_wakeUpDependents;
1057 }
1058
1059 transition({M_IL0, E_IL0}, L0_DataAck, MM) {
1060 u_writeDataFromL0Response;
1061 k_popL0RequestQueue;
1062 kd_wakeUpDependents;
1063 }
1064
1065 transition({M_IL0, MM_IL0}, L0_Ack, MM) {
1066 k_popL0RequestQueue;
1067 kd_wakeUpDependents;
1068 }
1069
1070 transition(E_IL0, L0_Ack, EE) {
1071 k_popL0RequestQueue;
1072 kd_wakeUpDependents;
1073 }
1074
1075 transition(S_IL0, L0_Ack, SS) {
1076 k_popL0RequestQueue;
1077 kd_wakeUpDependents;
1078 }
1079
1080 transition(SM_IL0, L0_Ack, IM) {
1081 k_popL0RequestQueue;
1082 kd_wakeUpDependents;
1083 }
1084
1085 transition({S_IL0, M_IL0, E_IL0, SM_IL0, SM}, L0_Invalidate_Own) {
1086 z0_stallAndWaitL0Queue;
1087 }
1088
1089 transition({S_IL0, M_IL0, E_IL0, SM_IL0}, L0_Invalidate_Else) {
1090 z2_stallAndWaitL2Queue;
1091 }
1092
1093 transition({S_IL0, M_IL0, E_IL0, MM_IL0}, {Inv, Fwd_GETX, Fwd_GETS}) {
1094 z2_stallAndWaitL2Queue;
1095 }
1096
1097 // hardware transactional memory
1098
1099 // If a transaction has aborted, the L0 could re-request
1100 // data which is in E or EE state in L1.
1101 transition({EE,E}, Load, E) {
1102 hh_xdata_to_l0;
1103 uu_profileHit;
1104 k_popL0RequestQueue;
1105 }
1106
1107 // If a transaction has aborted, the L0 could re-request
1108 // data which is in M or MM state in L1.
1109 transition({MM,M}, Load, M) {
1110 hh_xdata_to_l0;
1111 uu_profileHit;
1112 k_popL0RequestQueue;
1113 }
1114
1115 // If a transaction has aborted, the L0 could re-request
1116 // data which is in M state in L1.
1117 transition({E,M}, Store, M) {
1118 hh_xdata_to_l0;
1119 uu_profileHit;
1120 k_popL0RequestQueue;
1121 }
1122
1123 // A transaction may have tried to modify a cache block in M state with
1124 // non-speculative (pre-transactional) data. This needs to be copied
1125 // to the L1 before any further modifications occur at the L0.
1126 transition({M,E}, L0_DataCopy, M) {
1127 u_writeDataFromL0Request;
1128 k_popL0RequestQueue;
1129 }
1130
1131 transition({M_IL0, E_IL0}, L0_DataCopy, M_IL0) {
1132 u_writeDataFromL0Request;
1133 k_popL0RequestQueue;
1134 }
1135
1136 // A NAK from the L0 means that the L0 invalidated its
1137 // modified line (due to an abort) so it is therefore necessary
1138 // to use the L1's correct version instead
1139 transition({M_IL0, E_IL0}, L0_DataNak, MM) {
1140 k_popL0RequestQueue;
1141 kd_wakeUpDependents;
1142 }
1143
1144 transition(I, L1_Replacement) {
1145 ff_deallocateCacheBlock;
1146 }
1147 }