ruby: add stdio header in SRAM.hh
[gem5.git] / src / mem / protocol / MESI_CMP_directory-L2cache.sm
1
2 /*
3 * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * $Id: MSI_MOSI_CMP_directory-L2cache.sm 1.12 05/01/19 15:55:40-06:00 beckmann@s0-28.cs.wisc.edu $
32 *
33 */
34
35 machine(L2Cache, "MESI Directory L2 Cache CMP")
36 : CacheMemory * L2cacheMemory,
37 int l2_request_latency = 2,
38 int l2_response_latency = 2,
39 int to_l1_latency = 1
40 {
41 // L2 BANK QUEUES
42 // From local bank of L2 cache TO the network
43 MessageBuffer DirRequestFromL2Cache, network="To", virtual_network="0", ordered="false"; // this L2 bank -> Memory
44 MessageBuffer L1RequestFromL2Cache, network="To", virtual_network="0", ordered="false"; // this L2 bank -> a local L1
45 MessageBuffer responseFromL2Cache, network="To", virtual_network="1", ordered="false"; // this L2 bank -> a local L1 || Memory
46
47 // FROM the network to this local bank of L2 cache
48 MessageBuffer unblockToL2Cache, network="From", virtual_network="2", ordered="false"; // a local L1 || Memory -> this L2 bank
49 MessageBuffer L1RequestToL2Cache, network="From", virtual_network="0", ordered="false"; // a local L1 -> this L2 bank
50 MessageBuffer responseToL2Cache, network="From", virtual_network="1", ordered="false"; // a local L1 || Memory -> this L2 bank
51 // MessageBuffer unblockToL2Cache, network="From", virtual_network="4", ordered="false"; // a local L1 || Memory -> this L2 bank
52
53 // STATES
54 enumeration(State, desc="L2 Cache states", default="L2Cache_State_NP") {
55 // Base states
56 NP, desc="Not present in either cache";
57 SS, desc="L2 cache entry Shared, also present in one or more L1s";
58 M, desc="L2 cache entry Modified, not present in any L1s", format="!b";
59 MT, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
60
61 // L2 replacement
62 M_I, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
63 MT_I, desc="L2 cache replacing, getting data from exclusive";
64 MCT_I, desc="L2 cache replacing, clean in L2, getting data or ack from exclusive";
65 I_I, desc="L2 replacing clean data, need to inv sharers and then drop data";
66 S_I, desc="L2 replacing dirty data, collecting acks from L1s";
67
68 // Transient States for fetching data from memory
69 ISS, desc="L2 idle, got single L1_GETS, issued memory fetch, have not seen response yet";
70 IS, desc="L2 idle, got L1_GET_INSTR or multiple L1_GETS, issued memory fetch, have not seen response yet";
71 IM, desc="L2 idle, got L1_GETX, issued memory fetch, have not seen response(s) yet";
72
73 // Blocking states
74 SS_MB, desc="Blocked for L1_GETX from SS";
75 MT_MB, desc="Blocked for L1_GETX from MT";
76 M_MB, desc="Blocked for L1_GETX from M";
77
78 MT_IIB, desc="Blocked for L1_GETS from MT, waiting for unblock and data";
79 MT_IB, desc="Blocked for L1_GETS from MT, got unblock, waiting for data";
80 MT_SB, desc="Blocked for L1_GETS from MT, got data, waiting for unblock";
81
82 }
83
84 // EVENTS
85 enumeration(Event, desc="L2 Cache events") {
86 // L2 events
87
88 // events initiated by the local L1s
89 L1_GET_INSTR, desc="a L1I GET INSTR request for a block maped to us";
90 L1_GETS, desc="a L1D GETS request for a block maped to us";
91 L1_GETX, desc="a L1D GETX request for a block maped to us";
92 L1_UPGRADE, desc="a L1D GETX request for a block maped to us";
93
94 L1_PUTX, desc="L1 replacing data";
95 L1_PUTX_old, desc="L1 replacing data, but no longer sharer";
96
97 Fwd_L1_GETX, desc="L1 did not have data, so we supply";
98 Fwd_L1_GETS, desc="L1 did not have data, so we supply";
99 Fwd_L1_GET_INSTR, desc="L1 did not have data, so we supply";
100
101 // events initiated by this L2
102 L2_Replacement, desc="L2 Replacement", format="!r";
103 L2_Replacement_clean, desc="L2 Replacement, but data is clean", format="!r";
104
105 // events from memory controller
106 Mem_Data, desc="data from memory", format="!r";
107 Mem_Ack, desc="ack from memory", format="!r";
108
109 // M->S data writeback
110 WB_Data, desc="data from L1";
111 WB_Data_clean, desc="clean data from L1";
112 Ack, desc="writeback ack";
113 Ack_all, desc="writeback ack";
114
115 Unblock, desc="Unblock from L1 requestor";
116 Unblock_Cancel, desc="Unblock from L1 requestor (FOR XACT MEMORY)";
117 Exclusive_Unblock, desc="Unblock from L1 requestor";
118
119 MEM_Inv, desc="Invalidation from directory";
120
121 }
122
123 // TYPES
124
125 // CacheEntry
126 structure(Entry, desc="...", interface="AbstractCacheEntry") {
127 State CacheState, desc="cache state";
128 NetDest Sharers, desc="tracks the L1 shares on-chip";
129 MachineID Exclusive, desc="Exclusive holder of block";
130 DataBlock DataBlk, desc="data for the block";
131 bool Dirty, default="false", desc="data is dirty";
132 }
133
134 // TBE fields
135 structure(TBE, desc="...") {
136 Address Address, desc="Physical address for this TBE";
137 State TBEState, desc="Transient state";
138 DataBlock DataBlk, desc="Buffer for the data block";
139 bool Dirty, default="false", desc="Data is Dirty";
140
141 NetDest L1_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
142 MachineID L1_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
143 bool isPrefetch, desc="Set if this was caused by a prefetch";
144
145 int pendingAcks, desc="number of pending acks for invalidates during writeback";
146 }
147
148 external_type(TBETable) {
149 TBE lookup(Address);
150 void allocate(Address);
151 void deallocate(Address);
152 bool isPresent(Address);
153 }
154
155 TBETable L2_TBEs, template_hack="<L2Cache_TBE>";
156
157 void set_cache_entry(AbstractCacheEntry a);
158 void unset_cache_entry();
159 void set_tbe(TBE a);
160 void unset_tbe();
161
162 // inclusive cache, returns L2 entries only
163 Entry getCacheEntry(Address addr), return_by_pointer="yes" {
164 return static_cast(Entry, "pointer", L2cacheMemory[addr]);
165 }
166
167 std::string getCoherenceRequestTypeStr(CoherenceRequestType type) {
168 return CoherenceRequestType_to_string(type);
169 }
170
171 bool isOneSharerLeft(Address addr, MachineID requestor, Entry cache_entry) {
172 assert(is_valid(cache_entry));
173 assert(cache_entry.Sharers.isElement(requestor));
174 return (cache_entry.Sharers.count() == 1);
175 }
176
177 bool isSharer(Address addr, MachineID requestor, Entry cache_entry) {
178 if (is_valid(cache_entry)) {
179 return cache_entry.Sharers.isElement(requestor);
180 } else {
181 return false;
182 }
183 }
184
185 void addSharer(Address addr, MachineID requestor, Entry cache_entry) {
186 assert(is_valid(cache_entry));
187 DPRINTF(RubySlicc, "machineID: %s, requestor: %s, address: %s\n",
188 machineID, requestor, addr);
189 cache_entry.Sharers.add(requestor);
190 }
191
192 State getState(TBE tbe, Entry cache_entry, Address addr) {
193 if(is_valid(tbe)) {
194 return tbe.TBEState;
195 } else if (is_valid(cache_entry)) {
196 return cache_entry.CacheState;
197 }
198 return State:NP;
199 }
200
201 std::string getStateStr(TBE tbe, Entry cache_entry, Address addr) {
202 return L2Cache_State_to_string(getState(tbe, cache_entry, addr));
203 }
204
205 // when is this called
206 void setState(TBE tbe, Entry cache_entry, Address addr, State state) {
207
208 // MUST CHANGE
209 if (is_valid(tbe)) {
210 tbe.TBEState := state;
211 }
212
213 if (is_valid(cache_entry)) {
214 cache_entry.CacheState := state;
215
216 // Set permission
217 if (state == State:SS ) {
218 cache_entry.changePermission(AccessPermission:Read_Only);
219 } else if (state == State:M) {
220 cache_entry.changePermission(AccessPermission:Read_Write);
221 } else if (state == State:MT) {
222 cache_entry.changePermission(AccessPermission:Stale);
223 } else {
224 cache_entry.changePermission(AccessPermission:Busy);
225 }
226 }
227 }
228
229 Event L1Cache_request_type_to_event(CoherenceRequestType type, Address addr,
230 MachineID requestor, Entry cache_entry) {
231 if(type == CoherenceRequestType:GETS) {
232 return Event:L1_GETS;
233 } else if(type == CoherenceRequestType:GET_INSTR) {
234 return Event:L1_GET_INSTR;
235 } else if (type == CoherenceRequestType:GETX) {
236 return Event:L1_GETX;
237 } else if (type == CoherenceRequestType:UPGRADE) {
238 if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) {
239 return Event:L1_UPGRADE;
240 } else {
241 return Event:L1_GETX;
242 }
243 } else if (type == CoherenceRequestType:PUTX) {
244 if (isSharer(addr, requestor, cache_entry)) {
245 return Event:L1_PUTX;
246 } else {
247 return Event:L1_PUTX_old;
248 }
249 } else {
250 DPRINTF(RubySlicc, "address: %s, Request Type: %s\n", addr, type);
251 error("Invalid L1 forwarded request type");
252 }
253 }
254
255 int getPendingAcks(TBE tbe) {
256 return tbe.pendingAcks;
257 }
258
259 bool isDirty(Entry cache_entry) {
260 assert(is_valid(cache_entry));
261 return cache_entry.Dirty;
262 }
263
264 // ** OUT_PORTS **
265
266 out_port(L1RequestIntraChipL2Network_out, RequestMsg, L1RequestFromL2Cache);
267 out_port(DirRequestIntraChipL2Network_out, RequestMsg, DirRequestFromL2Cache);
268 out_port(responseIntraChipL2Network_out, ResponseMsg, responseFromL2Cache);
269
270
271 in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache) {
272 if(L1unblockNetwork_in.isReady()) {
273 peek(L1unblockNetwork_in, ResponseMsg) {
274 Entry cache_entry := getCacheEntry(in_msg.Address);
275 TBE tbe := L2_TBEs[in_msg.Address];
276 DPRINTF(RubySlicc, "Addr: %s State: %s Sender: %s Type: %s Dest: %s\n",
277 in_msg.Address, getState(tbe, cache_entry, in_msg.Address),
278 in_msg.Sender, in_msg.Type, in_msg.Destination);
279
280 assert(in_msg.Destination.isElement(machineID));
281 if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) {
282 trigger(Event:Exclusive_Unblock, in_msg.Address, cache_entry, tbe);
283 } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
284 trigger(Event:Unblock, in_msg.Address, cache_entry, tbe);
285 } else {
286 error("unknown unblock message");
287 }
288 }
289 }
290 }
291
292 // Response IntraChip L2 Network - response msg to this particular L2 bank
293 in_port(responseIntraChipL2Network_in, ResponseMsg, responseToL2Cache) {
294 if (responseIntraChipL2Network_in.isReady()) {
295 peek(responseIntraChipL2Network_in, ResponseMsg) {
296 // test wether it's from a local L1 or an off chip source
297 assert(in_msg.Destination.isElement(machineID));
298 Entry cache_entry := getCacheEntry(in_msg.Address);
299 TBE tbe := L2_TBEs[in_msg.Address];
300
301 if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
302 if(in_msg.Type == CoherenceResponseType:DATA) {
303 if (in_msg.Dirty) {
304 trigger(Event:WB_Data, in_msg.Address, cache_entry, tbe);
305 } else {
306 trigger(Event:WB_Data_clean, in_msg.Address, cache_entry, tbe);
307 }
308 } else if (in_msg.Type == CoherenceResponseType:ACK) {
309 if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) {
310 trigger(Event:Ack_all, in_msg.Address, cache_entry, tbe);
311 } else {
312 trigger(Event:Ack, in_msg.Address, cache_entry, tbe);
313 }
314 } else {
315 error("unknown message type");
316 }
317
318 } else { // external message
319 if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
320 // L2 now has data and all off-chip acks
321 trigger(Event:Mem_Data, in_msg.Address, cache_entry, tbe);
322 } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) {
323 // L2 now has data and all off-chip acks
324 trigger(Event:Mem_Ack, in_msg.Address, cache_entry, tbe);
325 } else if(in_msg.Type == CoherenceResponseType:INV) {
326 // L2 now has data and all off-chip acks
327 trigger(Event:MEM_Inv, in_msg.Address, cache_entry, tbe);
328 } else {
329 error("unknown message type");
330 }
331 }
332 }
333 } // if not ready, do nothing
334 }
335
336 // L1 Request
337 in_port(L1RequestIntraChipL2Network_in, RequestMsg, L1RequestToL2Cache) {
338 if(L1RequestIntraChipL2Network_in.isReady()) {
339 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
340 Entry cache_entry := getCacheEntry(in_msg.Address);
341 TBE tbe := L2_TBEs[in_msg.Address];
342
343 DPRINTF(RubySlicc, "Addr: %s State: %s Req: %s Type: %s Dest: %s\n",
344 in_msg.Address, getState(tbe, cache_entry, in_msg.Address),
345 in_msg.Requestor, in_msg.Type, in_msg.Destination);
346
347 assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache);
348 assert(in_msg.Destination.isElement(machineID));
349
350 if (is_valid(cache_entry)) {
351 // The L2 contains the block, so proceeded with handling the request
352 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address,
353 in_msg.Requestor, cache_entry),
354 in_msg.Address, cache_entry, tbe);
355 } else {
356 if (L2cacheMemory.cacheAvail(in_msg.Address)) {
357 // L2 does't have the line, but we have space for it in the L2
358 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address,
359 in_msg.Requestor, cache_entry),
360 in_msg.Address, cache_entry, tbe);
361 } else {
362 // No room in the L2, so we need to make room before handling the request
363 Entry L2cache_entry := getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address));
364 if (isDirty(L2cache_entry)) {
365 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address),
366 L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]);
367 } else {
368 trigger(Event:L2_Replacement_clean, L2cacheMemory.cacheProbe(in_msg.Address),
369 L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]);
370 }
371 }
372 }
373 }
374 }
375 }
376
377
378 // ACTIONS
379
380 action(a_issueFetchToMemory, "a", desc="fetch data from memory") {
381 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
382 enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency=l2_request_latency) {
383 out_msg.Address := address;
384 out_msg.Type := CoherenceRequestType:GETS;
385 out_msg.Requestor := machineID;
386 out_msg.Destination.add(map_Address_to_Directory(address));
387 out_msg.MessageSize := MessageSizeType:Control;
388 }
389 }
390 }
391
392 action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") {
393 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
394 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
395 assert(is_valid(cache_entry));
396 out_msg.Address := address;
397 out_msg.Type := in_msg.Type;
398 out_msg.Requestor := in_msg.Requestor;
399 out_msg.Destination.add(cache_entry.Exclusive);
400 out_msg.MessageSize := MessageSizeType:Request_Control;
401 }
402 }
403 }
404
405 action(c_exclusiveReplacement, "c", desc="Send data to memory") {
406 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
407 assert(is_valid(cache_entry));
408 out_msg.Address := address;
409 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
410 out_msg.Sender := machineID;
411 out_msg.Destination.add(map_Address_to_Directory(address));
412 out_msg.DataBlk := cache_entry.DataBlk;
413 out_msg.Dirty := cache_entry.Dirty;
414 out_msg.MessageSize := MessageSizeType:Response_Data;
415 }
416 }
417
418 action(c_exclusiveCleanReplacement, "cc", desc="Send ack to memory for clean replacement") {
419 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
420 out_msg.Address := address;
421 out_msg.Type := CoherenceResponseType:ACK;
422 out_msg.Sender := machineID;
423 out_msg.Destination.add(map_Address_to_Directory(address));
424 out_msg.MessageSize := MessageSizeType:Response_Control;
425 }
426 }
427
428 action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") {
429 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
430 assert(is_valid(tbe));
431 out_msg.Address := address;
432 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
433 out_msg.Sender := machineID;
434 out_msg.Destination.add(map_Address_to_Directory(address));
435 out_msg.DataBlk := tbe.DataBlk;
436 out_msg.Dirty := tbe.Dirty;
437 out_msg.MessageSize := MessageSizeType:Response_Data;
438 }
439 }
440
441 action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") {
442 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
443 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
444 assert(is_valid(cache_entry));
445 out_msg.Address := address;
446 out_msg.Type := CoherenceResponseType:DATA;
447 out_msg.Sender := machineID;
448 out_msg.Destination.add(in_msg.Requestor);
449 out_msg.DataBlk := cache_entry.DataBlk;
450 out_msg.Dirty := cache_entry.Dirty;
451 out_msg.MessageSize := MessageSizeType:Response_Data;
452
453 out_msg.AckCount := 0 - cache_entry.Sharers.count();
454 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
455 out_msg.AckCount := out_msg.AckCount + 1;
456 }
457 }
458 }
459 }
460
461 action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") {
462 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
463 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
464 assert(is_valid(cache_entry));
465 out_msg.Address := address;
466 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
467 out_msg.Sender := machineID;
468 out_msg.Destination.add(in_msg.Requestor);
469 out_msg.DataBlk := cache_entry.DataBlk;
470 out_msg.Dirty := cache_entry.Dirty;
471 out_msg.MessageSize := MessageSizeType:Response_Data;
472
473 out_msg.AckCount := 0 - cache_entry.Sharers.count();
474 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
475 out_msg.AckCount := out_msg.AckCount + 1;
476 }
477 }
478 }
479 }
480
481 action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") {
482 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
483 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
484 assert(is_valid(cache_entry));
485 out_msg.Address := address;
486 out_msg.Type := CoherenceResponseType:DATA;
487 out_msg.Sender := machineID;
488 out_msg.Destination.add(in_msg.Requestor);
489 out_msg.DataBlk := cache_entry.DataBlk;
490 out_msg.Dirty := cache_entry.Dirty;
491 out_msg.MessageSize := MessageSizeType:Response_Data;
492 out_msg.AckCount := 0;
493 }
494 }
495 }
496
497 action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") {
498 assert(is_valid(tbe));
499 assert(tbe.L1_GetS_IDs.count() > 0);
500 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
501 assert(is_valid(cache_entry));
502 out_msg.Address := address;
503 out_msg.Type := CoherenceResponseType:DATA;
504 out_msg.Sender := machineID;
505 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
506 out_msg.DataBlk := cache_entry.DataBlk;
507 out_msg.Dirty := cache_entry.Dirty;
508 out_msg.MessageSize := MessageSizeType:Response_Data;
509 }
510 }
511
512 action(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") {
513 assert(is_valid(tbe));
514 assert(tbe.L1_GetS_IDs.count() == 1);
515 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
516 assert(is_valid(cache_entry));
517 out_msg.Address := address;
518 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
519 out_msg.Sender := machineID;
520 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
521 out_msg.DataBlk := cache_entry.DataBlk;
522 out_msg.Dirty := cache_entry.Dirty;
523 out_msg.MessageSize := MessageSizeType:Response_Data;
524 }
525 }
526
527 action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") {
528 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
529 assert(is_valid(tbe));
530 assert(is_valid(cache_entry));
531 out_msg.Address := address;
532 out_msg.Type := CoherenceResponseType:DATA;
533 out_msg.Sender := machineID;
534 out_msg.Destination.add(tbe.L1_GetX_ID);
535 DPRINTF(RubySlicc, "%s\n", out_msg.Destination);
536 out_msg.DataBlk := cache_entry.DataBlk;
537 out_msg.Dirty := cache_entry.Dirty;
538 DPRINTF(RubySlicc, "Address: %s, Destination: %s, DataBlock: %s\n",
539 out_msg.Address, out_msg.Destination, out_msg.DataBlk);
540 out_msg.MessageSize := MessageSizeType:Response_Data;
541 }
542 }
543
544 action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") {
545 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
546 assert(is_valid(cache_entry));
547 out_msg.Address := address;
548 out_msg.Type := CoherenceRequestType:INV;
549 out_msg.Requestor := machineID;
550 out_msg.Destination := cache_entry.Sharers;
551 out_msg.MessageSize := MessageSizeType:Request_Control;
552 }
553 }
554
555 action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") {
556 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
557 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
558 assert(is_valid(cache_entry));
559 out_msg.Address := address;
560 out_msg.Type := CoherenceRequestType:INV;
561 out_msg.Requestor := in_msg.Requestor;
562 out_msg.Destination := cache_entry.Sharers;
563 out_msg.MessageSize := MessageSizeType:Request_Control;
564 }
565 }
566 }
567
568 action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") {
569 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
570 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
571 assert(is_valid(cache_entry));
572 out_msg.Address := address;
573 out_msg.Type := CoherenceRequestType:INV;
574 out_msg.Requestor := in_msg.Requestor;
575 out_msg.Destination := cache_entry.Sharers;
576 out_msg.Destination.remove(in_msg.Requestor);
577 out_msg.MessageSize := MessageSizeType:Request_Control;
578 }
579 }
580 }
581
582 // OTHER ACTIONS
583 action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") {
584 check_allocate(L2_TBEs);
585 assert(is_valid(cache_entry));
586 L2_TBEs.allocate(address);
587 set_tbe(L2_TBEs[address]);
588 tbe.L1_GetS_IDs.clear();
589 tbe.DataBlk := cache_entry.DataBlk;
590 tbe.Dirty := cache_entry.Dirty;
591 tbe.pendingAcks := cache_entry.Sharers.count();
592 }
593
594 action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
595 L2_TBEs.deallocate(address);
596 }
597
598 action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
599 profileMsgDelay(0, L1RequestIntraChipL2Network_in.dequeue_getDelayCycles());
600 }
601
602 action(k_popUnblockQueue, "k", desc="Pop incoming unblock queue") {
603 profileMsgDelay(0, L1unblockNetwork_in.dequeue_getDelayCycles());
604 }
605
606 action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
607 profileMsgDelay(3, responseIntraChipL2Network_in.dequeue_getDelayCycles());
608 }
609
610 action(m_writeDataToCache, "m", desc="Write data from response queue to cache") {
611 peek(responseIntraChipL2Network_in, ResponseMsg) {
612 assert(is_valid(cache_entry));
613 cache_entry.DataBlk := in_msg.DataBlk;
614 cache_entry.Dirty := in_msg.Dirty;
615 }
616 }
617
618 action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") {
619 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
620 assert(is_valid(cache_entry));
621 cache_entry.DataBlk := in_msg.DataBlk;
622 cache_entry.Dirty := in_msg.Dirty;
623 }
624 }
625
626 action(q_updateAck, "q", desc="update pending ack count") {
627 peek(responseIntraChipL2Network_in, ResponseMsg) {
628 assert(is_valid(tbe));
629 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
630 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
631 APPEND_TRANSITION_COMMENT(" p: ");
632 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
633 }
634 }
635
636 action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") {
637 peek(responseIntraChipL2Network_in, ResponseMsg) {
638 assert(is_valid(tbe));
639 tbe.DataBlk := in_msg.DataBlk;
640 tbe.Dirty := in_msg.Dirty;
641 }
642 }
643
644 action(z_stall, "z", desc="Stall") {
645 }
646
647 action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") {
648 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
649 assert(is_valid(tbe));
650 tbe.L1_GetS_IDs.add(in_msg.Requestor);
651 }
652 }
653
654 action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
655 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
656 assert(is_valid(tbe));
657 tbe.L1_GetX_ID := in_msg.Requestor;
658 }
659 }
660
661 action(set_setMRU, "\set", desc="set the MRU entry") {
662 L2cacheMemory.setMRU(address);
663 }
664
665 action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
666 if (is_invalid(cache_entry)) {
667 set_cache_entry(L2cacheMemory.allocate(address, new Entry));
668 }
669 }
670
671 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
672 L2cacheMemory.deallocate(address);
673 unset_cache_entry();
674 }
675
676 action(t_sendWBAck, "t", desc="Send writeback ACK") {
677 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
678 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
679 out_msg.Address := address;
680 out_msg.Type := CoherenceResponseType:WB_ACK;
681 out_msg.Sender := machineID;
682 out_msg.Destination.add(in_msg.Requestor);
683 out_msg.MessageSize := MessageSizeType:Response_Control;
684 }
685 }
686 }
687
688 action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") {
689 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
690 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
691 assert(is_valid(cache_entry));
692 out_msg.Address := address;
693 out_msg.Type := CoherenceResponseType:ACK;
694 out_msg.Sender := machineID;
695 out_msg.Destination.add(in_msg.Requestor);
696 out_msg.MessageSize := MessageSizeType:Response_Control;
697 // upgrader doesn't get ack from itself, hence the + 1
698 out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1;
699 }
700 }
701 }
702
703 action(uu_profileMiss, "\u", desc="Profile the demand miss") {
704 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
705 //profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, L1CacheMachIDToProcessorNum(in_msg.Requestor));
706 }
707 }
708
709 action(ww_profileMissNoDir, "\w", desc="Profile this transition at the L2 because Dir won't see the request") {
710 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
711 // profile_request(in_msg.L1CacheStateStr, getStateStr(address), "NA", getCoherenceRequestTypeStr(in_msg.Type));
712 }
713 }
714
715 action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
716 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
717 assert(is_valid(cache_entry));
718 addSharer(address, in_msg.Requestor, cache_entry);
719 APPEND_TRANSITION_COMMENT( cache_entry.Sharers );
720 }
721 }
722
723 action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") {
724 peek(L1unblockNetwork_in, ResponseMsg) {
725 assert(is_valid(cache_entry));
726 addSharer(address, in_msg.Sender, cache_entry);
727 }
728 }
729
730 action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
731 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
732 assert(is_valid(cache_entry));
733 cache_entry.Sharers.remove(in_msg.Requestor);
734 }
735 }
736
737 action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
738 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
739 assert(is_valid(cache_entry));
740 cache_entry.Sharers.clear();
741 }
742 }
743
744 action(mm_markExclusive, "\m", desc="set the exclusive owner") {
745 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
746 assert(is_valid(cache_entry));
747 cache_entry.Sharers.clear();
748 cache_entry.Exclusive := in_msg.Requestor;
749 addSharer(address, in_msg.Requestor, cache_entry);
750 }
751 }
752
753 action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") {
754 peek(L1unblockNetwork_in, ResponseMsg) {
755 assert(is_valid(cache_entry));
756 cache_entry.Sharers.clear();
757 cache_entry.Exclusive := in_msg.Sender;
758 addSharer(address, in_msg.Sender, cache_entry);
759 }
760 }
761
762 action(zz_recycleL1RequestQueue, "zz", desc="recycle L1 request queue") {
763 L1RequestIntraChipL2Network_in.recycle();
764 }
765
766 action(zn_recycleResponseNetwork, "zn", desc="recycle memory request") {
767 responseIntraChipL2Network_in.recycle();
768 }
769
770
771 //*****************************************************
772 // TRANSITIONS
773 //*****************************************************
774
775
776 //===============================================
777 // BASE STATE - I
778
779 // Transitions from I (Idle)
780 transition({NP, IS, ISS, IM, SS, M, M_I, I_I, S_I, M_MB, MT_IB, MT_SB}, L1_PUTX) {
781 t_sendWBAck;
782 jj_popL1RequestQueue;
783 }
784
785 transition({NP, SS, M, MT, M_I, I_I, S_I, IS, ISS, IM, M_MB, MT_IB, MT_SB}, L1_PUTX_old) {
786 t_sendWBAck;
787 jj_popL1RequestQueue;
788 }
789
790 transition({IM, IS, ISS, SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L2_Replacement, L2_Replacement_clean}) {
791 zz_recycleL1RequestQueue;
792 }
793
794 transition({IM, IS, ISS, SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, MEM_Inv) {
795 zn_recycleResponseNetwork;
796 }
797
798 transition({S_I, M_I, MT_I}, MEM_Inv) {
799 o_popIncomingResponseQueue;
800 }
801
802
803 transition({SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE}) {
804 zz_recycleL1RequestQueue;
805 }
806
807
808 transition(NP, L1_GETS, ISS) {
809 qq_allocateL2CacheBlock;
810 ll_clearSharers;
811 nn_addSharer;
812 i_allocateTBE;
813 ss_recordGetSL1ID;
814 a_issueFetchToMemory;
815 uu_profileMiss;
816 jj_popL1RequestQueue;
817 }
818
819 transition(NP, L1_GET_INSTR, IS) {
820 qq_allocateL2CacheBlock;
821 ll_clearSharers;
822 nn_addSharer;
823 i_allocateTBE;
824 ss_recordGetSL1ID;
825 a_issueFetchToMemory;
826 uu_profileMiss;
827 jj_popL1RequestQueue;
828 }
829
830 transition(NP, L1_GETX, IM) {
831 qq_allocateL2CacheBlock;
832 ll_clearSharers;
833 // nn_addSharer;
834 i_allocateTBE;
835 xx_recordGetXL1ID;
836 a_issueFetchToMemory;
837 uu_profileMiss;
838 jj_popL1RequestQueue;
839 }
840
841
842 // transitions from IS/IM
843
844 transition(ISS, Mem_Data, MT_MB) {
845 m_writeDataToCache;
846 ex_sendExclusiveDataToGetSRequestors;
847 s_deallocateTBE;
848 o_popIncomingResponseQueue;
849 }
850
851 transition(IS, Mem_Data, SS) {
852 m_writeDataToCache;
853 e_sendDataToGetSRequestors;
854 s_deallocateTBE;
855 o_popIncomingResponseQueue;
856 }
857
858 transition(IM, Mem_Data, MT_MB) {
859 m_writeDataToCache;
860 ee_sendDataToGetXRequestor;
861 s_deallocateTBE;
862 o_popIncomingResponseQueue;
863 }
864
865 transition({IS, ISS}, {L1_GETS, L1_GET_INSTR}, IS) {
866 nn_addSharer;
867 ss_recordGetSL1ID;
868 uu_profileMiss;
869 jj_popL1RequestQueue;
870 }
871
872 transition({IS, ISS}, L1_GETX) {
873 zz_recycleL1RequestQueue;
874 }
875
876 transition(IM, {L1_GETX, L1_GETS, L1_GET_INSTR}) {
877 zz_recycleL1RequestQueue;
878 }
879
880 // transitions from SS
881 transition(SS, {L1_GETS, L1_GET_INSTR}) {
882 ds_sendSharedDataToRequestor;
883 nn_addSharer;
884 uu_profileMiss;
885 set_setMRU;
886 jj_popL1RequestQueue;
887 }
888
889
890 transition(SS, L1_GETX, SS_MB) {
891 d_sendDataToRequestor;
892 // fw_sendFwdInvToSharers;
893 fwm_sendFwdInvToSharersMinusRequestor;
894 uu_profileMiss;
895 set_setMRU;
896 jj_popL1RequestQueue;
897 }
898
899 transition(SS, L1_UPGRADE, SS_MB) {
900 fwm_sendFwdInvToSharersMinusRequestor;
901 ts_sendInvAckToUpgrader;
902 uu_profileMiss;
903 set_setMRU;
904 jj_popL1RequestQueue;
905 }
906
907 transition(SS, L2_Replacement_clean, I_I) {
908 i_allocateTBE;
909 f_sendInvToSharers;
910 rr_deallocateL2CacheBlock;
911 }
912
913 transition(SS, {L2_Replacement, MEM_Inv}, S_I) {
914 i_allocateTBE;
915 f_sendInvToSharers;
916 rr_deallocateL2CacheBlock;
917 }
918
919
920 transition(M, L1_GETX, MT_MB) {
921 d_sendDataToRequestor;
922 uu_profileMiss;
923 set_setMRU;
924 jj_popL1RequestQueue;
925 }
926
927 transition(M, L1_GET_INSTR, SS) {
928 d_sendDataToRequestor;
929 nn_addSharer;
930 uu_profileMiss;
931 set_setMRU;
932 jj_popL1RequestQueue;
933 }
934
935 transition(M, L1_GETS, MT_MB) {
936 dd_sendExclusiveDataToRequestor;
937 uu_profileMiss;
938 set_setMRU;
939 jj_popL1RequestQueue;
940 }
941
942 transition(M, {L2_Replacement, MEM_Inv}, M_I) {
943 i_allocateTBE;
944 c_exclusiveReplacement;
945 rr_deallocateL2CacheBlock;
946 }
947
948 transition(M, L2_Replacement_clean, M_I) {
949 i_allocateTBE;
950 c_exclusiveCleanReplacement;
951 rr_deallocateL2CacheBlock;
952 }
953
954
955 // transitions from MT
956
957 transition(MT, L1_GETX, MT_MB) {
958 b_forwardRequestToExclusive;
959 uu_profileMiss;
960 set_setMRU;
961 jj_popL1RequestQueue;
962 }
963
964
965 transition(MT, {L1_GETS, L1_GET_INSTR}, MT_IIB) {
966 b_forwardRequestToExclusive;
967 uu_profileMiss;
968 set_setMRU;
969 jj_popL1RequestQueue;
970 }
971
972 transition(MT, {L2_Replacement, MEM_Inv}, MT_I) {
973 i_allocateTBE;
974 f_sendInvToSharers;
975 rr_deallocateL2CacheBlock;
976 }
977
978 transition(MT, L2_Replacement_clean, MCT_I) {
979 i_allocateTBE;
980 f_sendInvToSharers;
981 rr_deallocateL2CacheBlock;
982 }
983
984 transition(MT, L1_PUTX, M) {
985 ll_clearSharers;
986 mr_writeDataToCacheFromRequest;
987 t_sendWBAck;
988 jj_popL1RequestQueue;
989 }
990
991
992 // transitions from blocking states
993 transition(SS_MB, Unblock_Cancel, SS) {
994 k_popUnblockQueue;
995 }
996
997 transition(MT_MB, Unblock_Cancel, MT) {
998 k_popUnblockQueue;
999 }
1000
1001 transition(MT_IB, Unblock_Cancel, MT) {
1002 k_popUnblockQueue;
1003 }
1004
1005 transition(SS_MB, Exclusive_Unblock, MT) {
1006 // update actual directory
1007 mmu_markExclusiveFromUnblock;
1008 k_popUnblockQueue;
1009 }
1010
1011 transition({M_MB, MT_MB}, Exclusive_Unblock, MT) {
1012 // update actual directory
1013 mmu_markExclusiveFromUnblock;
1014 k_popUnblockQueue;
1015 }
1016
1017 transition(MT_IIB, {L1_PUTX, L1_PUTX_old}){
1018 zz_recycleL1RequestQueue;
1019 }
1020
1021 transition(MT_IIB, Unblock, MT_IB) {
1022 nnu_addSharerFromUnblock;
1023 k_popUnblockQueue;
1024 }
1025
1026 transition(MT_IIB, {WB_Data, WB_Data_clean}, MT_SB) {
1027 m_writeDataToCache;
1028 o_popIncomingResponseQueue;
1029 }
1030
1031 transition(MT_IB, {WB_Data, WB_Data_clean}, SS) {
1032 m_writeDataToCache;
1033 o_popIncomingResponseQueue;
1034 }
1035
1036 transition(MT_SB, Unblock, SS) {
1037 nnu_addSharerFromUnblock;
1038 k_popUnblockQueue;
1039 }
1040
1041 // writeback states
1042 transition({I_I, S_I, MT_I, MCT_I, M_I}, {L1_GETX, L1_UPGRADE, L1_GETS, L1_GET_INSTR}) {
1043 zz_recycleL1RequestQueue;
1044 }
1045
1046 transition(I_I, Ack) {
1047 q_updateAck;
1048 o_popIncomingResponseQueue;
1049 }
1050
1051 transition(I_I, Ack_all, M_I) {
1052 c_exclusiveCleanReplacement;
1053 o_popIncomingResponseQueue;
1054 }
1055
1056 transition({MT_I, MCT_I}, WB_Data, M_I) {
1057 qq_writeDataToTBE;
1058 ct_exclusiveReplacementFromTBE;
1059 o_popIncomingResponseQueue;
1060 }
1061
1062 transition(MCT_I, {WB_Data_clean, Ack_all}, M_I) {
1063 c_exclusiveCleanReplacement;
1064 o_popIncomingResponseQueue;
1065 }
1066
1067 transition(MCT_I, {L1_PUTX, L1_PUTX_old}){
1068 zz_recycleL1RequestQueue;
1069 }
1070
1071 // L1 never changed Dirty data
1072 transition(MT_I, Ack_all, M_I) {
1073 ct_exclusiveReplacementFromTBE;
1074 o_popIncomingResponseQueue;
1075 }
1076
1077 transition(MT_I, {L1_PUTX, L1_PUTX_old}){
1078 zz_recycleL1RequestQueue;
1079 }
1080
1081 // possible race between unblock and immediate replacement
1082 transition({MT_MB,SS_MB}, {L1_PUTX, L1_PUTX_old}) {
1083 zz_recycleL1RequestQueue;
1084 }
1085
1086 transition(MT_I, WB_Data_clean, NP) {
1087 s_deallocateTBE;
1088 o_popIncomingResponseQueue;
1089 }
1090
1091 transition(S_I, Ack) {
1092 q_updateAck;
1093 o_popIncomingResponseQueue;
1094 }
1095
1096 transition(S_I, Ack_all, M_I) {
1097 ct_exclusiveReplacementFromTBE;
1098 o_popIncomingResponseQueue;
1099 }
1100
1101 transition(M_I, Mem_Ack, NP) {
1102 s_deallocateTBE;
1103 o_popIncomingResponseQueue;
1104 }
1105 }