Ruby: Add support for functional accesses
[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", vnet_type="request"; // this L2 bank -> Memory
44 MessageBuffer L1RequestFromL2Cache, network="To", virtual_network="0", ordered="false", vnet_type="request"; // this L2 bank -> a local L1
45 MessageBuffer responseFromL2Cache, network="To", virtual_network="1", ordered="false", vnet_type="response"; // 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", vnet_type="unblock"; // a local L1 || Memory -> this L2 bank
49 MessageBuffer L1RequestToL2Cache, network="From", virtual_network="0", ordered="false", vnet_type="request"; // a local L1 -> this L2 bank
50 MessageBuffer responseToL2Cache, network="From", virtual_network="1", ordered="false", vnet_type="response"; // a local L1 || Memory -> this L2 bank
51 // MessageBuffer unblockToL2Cache, network="From", virtual_network="4", ordered="false", vnet_type="unblock"; // a local L1 || Memory -> this L2 bank
52
53 // STATES
54 state_declaration(State, desc="L2 Cache states", default="L2Cache_State_NP") {
55 // Base states
56 NP, AccessPermission:Invalid, desc="Not present in either cache";
57 SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s";
58 M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b";
59 MT, AccessPermission:Maybe_Stale, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
60
61 // L2 replacement
62 M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
63 MT_I, AccessPermission:Busy, desc="L2 cache replacing, getting data from exclusive";
64 MCT_I, AccessPermission:Busy, desc="L2 cache replacing, clean in L2, getting data or ack from exclusive";
65 I_I, AccessPermission:Busy, desc="L2 replacing clean data, need to inv sharers and then drop data";
66 S_I, AccessPermission:Busy, desc="L2 replacing dirty data, collecting acks from L1s";
67
68 // Transient States for fetching data from memory
69 ISS, AccessPermission:Busy, desc="L2 idle, got single L1_GETS, issued memory fetch, have not seen response yet";
70 IS, AccessPermission:Busy, desc="L2 idle, got L1_GET_INSTR or multiple L1_GETS, issued memory fetch, have not seen response yet";
71 IM, AccessPermission:Busy, desc="L2 idle, got L1_GETX, issued memory fetch, have not seen response(s) yet";
72
73 // Blocking states
74 SS_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from SS";
75 MT_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from MT";
76 M_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from M";
77
78 MT_IIB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, waiting for unblock and data";
79 MT_IB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got unblock, waiting for data";
80 MT_SB, AccessPermission:Busy, 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 structure(TBETable, external="yes") {
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 void setState(TBE tbe, Entry cache_entry, Address addr, State state) {
206
207 // MUST CHANGE
208 if (is_valid(tbe)) {
209 tbe.TBEState := state;
210 }
211
212 if (is_valid(cache_entry)) {
213 cache_entry.CacheState := state;
214 }
215 }
216
217 AccessPermission getAccessPermission(Address addr) {
218 TBE tbe := L2_TBEs[addr];
219 if(is_valid(tbe)) {
220 DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
221 return L2Cache_State_to_permission(tbe.TBEState);
222 }
223
224 Entry cache_entry := getCacheEntry(addr);
225 if(is_valid(cache_entry)) {
226 DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
227 return L2Cache_State_to_permission(cache_entry.CacheState);
228 }
229
230 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
231 return AccessPermission:NotPresent;
232 }
233
234 DataBlock getDataBlock(Address addr), return_by_ref="yes" {
235 return getCacheEntry(addr).DataBlk;
236 }
237
238 void setAccessPermission(Entry cache_entry, Address addr, State state) {
239 if (is_valid(cache_entry)) {
240 cache_entry.changePermission(L2Cache_State_to_permission(state));
241 }
242 }
243
244 Event L1Cache_request_type_to_event(CoherenceRequestType type, Address addr,
245 MachineID requestor, Entry cache_entry) {
246 if(type == CoherenceRequestType:GETS) {
247 return Event:L1_GETS;
248 } else if(type == CoherenceRequestType:GET_INSTR) {
249 return Event:L1_GET_INSTR;
250 } else if (type == CoherenceRequestType:GETX) {
251 return Event:L1_GETX;
252 } else if (type == CoherenceRequestType:UPGRADE) {
253 if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) {
254 return Event:L1_UPGRADE;
255 } else {
256 return Event:L1_GETX;
257 }
258 } else if (type == CoherenceRequestType:PUTX) {
259 if (isSharer(addr, requestor, cache_entry)) {
260 return Event:L1_PUTX;
261 } else {
262 return Event:L1_PUTX_old;
263 }
264 } else {
265 DPRINTF(RubySlicc, "address: %s, Request Type: %s\n", addr, type);
266 error("Invalid L1 forwarded request type");
267 }
268 }
269
270 int getPendingAcks(TBE tbe) {
271 return tbe.pendingAcks;
272 }
273
274 bool isDirty(Entry cache_entry) {
275 assert(is_valid(cache_entry));
276 return cache_entry.Dirty;
277 }
278
279 // ** OUT_PORTS **
280
281 out_port(L1RequestIntraChipL2Network_out, RequestMsg, L1RequestFromL2Cache);
282 out_port(DirRequestIntraChipL2Network_out, RequestMsg, DirRequestFromL2Cache);
283 out_port(responseIntraChipL2Network_out, ResponseMsg, responseFromL2Cache);
284
285
286 in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache) {
287 if(L1unblockNetwork_in.isReady()) {
288 peek(L1unblockNetwork_in, ResponseMsg) {
289 Entry cache_entry := getCacheEntry(in_msg.Address);
290 TBE tbe := L2_TBEs[in_msg.Address];
291 DPRINTF(RubySlicc, "Addr: %s State: %s Sender: %s Type: %s Dest: %s\n",
292 in_msg.Address, getState(tbe, cache_entry, in_msg.Address),
293 in_msg.Sender, in_msg.Type, in_msg.Destination);
294
295 assert(in_msg.Destination.isElement(machineID));
296 if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) {
297 trigger(Event:Exclusive_Unblock, in_msg.Address, cache_entry, tbe);
298 } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
299 trigger(Event:Unblock, in_msg.Address, cache_entry, tbe);
300 } else {
301 error("unknown unblock message");
302 }
303 }
304 }
305 }
306
307 // Response IntraChip L2 Network - response msg to this particular L2 bank
308 in_port(responseIntraChipL2Network_in, ResponseMsg, responseToL2Cache) {
309 if (responseIntraChipL2Network_in.isReady()) {
310 peek(responseIntraChipL2Network_in, ResponseMsg) {
311 // test wether it's from a local L1 or an off chip source
312 assert(in_msg.Destination.isElement(machineID));
313 Entry cache_entry := getCacheEntry(in_msg.Address);
314 TBE tbe := L2_TBEs[in_msg.Address];
315
316 if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
317 if(in_msg.Type == CoherenceResponseType:DATA) {
318 if (in_msg.Dirty) {
319 trigger(Event:WB_Data, in_msg.Address, cache_entry, tbe);
320 } else {
321 trigger(Event:WB_Data_clean, in_msg.Address, cache_entry, tbe);
322 }
323 } else if (in_msg.Type == CoherenceResponseType:ACK) {
324 if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) {
325 trigger(Event:Ack_all, in_msg.Address, cache_entry, tbe);
326 } else {
327 trigger(Event:Ack, in_msg.Address, cache_entry, tbe);
328 }
329 } else {
330 error("unknown message type");
331 }
332
333 } else { // external message
334 if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
335 // L2 now has data and all off-chip acks
336 trigger(Event:Mem_Data, in_msg.Address, cache_entry, tbe);
337 } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) {
338 // L2 now has data and all off-chip acks
339 trigger(Event:Mem_Ack, in_msg.Address, cache_entry, tbe);
340 } else if(in_msg.Type == CoherenceResponseType:INV) {
341 // L2 now has data and all off-chip acks
342 trigger(Event:MEM_Inv, in_msg.Address, cache_entry, tbe);
343 } else {
344 error("unknown message type");
345 }
346 }
347 }
348 } // if not ready, do nothing
349 }
350
351 // L1 Request
352 in_port(L1RequestIntraChipL2Network_in, RequestMsg, L1RequestToL2Cache) {
353 if(L1RequestIntraChipL2Network_in.isReady()) {
354 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
355 Entry cache_entry := getCacheEntry(in_msg.Address);
356 TBE tbe := L2_TBEs[in_msg.Address];
357
358 DPRINTF(RubySlicc, "Addr: %s State: %s Req: %s Type: %s Dest: %s\n",
359 in_msg.Address, getState(tbe, cache_entry, in_msg.Address),
360 in_msg.Requestor, in_msg.Type, in_msg.Destination);
361
362 assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache);
363 assert(in_msg.Destination.isElement(machineID));
364
365 if (is_valid(cache_entry)) {
366 // The L2 contains the block, so proceeded with handling the request
367 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address,
368 in_msg.Requestor, cache_entry),
369 in_msg.Address, cache_entry, tbe);
370 } else {
371 if (L2cacheMemory.cacheAvail(in_msg.Address)) {
372 // L2 does't have the line, but we have space for it in the L2
373 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address,
374 in_msg.Requestor, cache_entry),
375 in_msg.Address, cache_entry, tbe);
376 } else {
377 // No room in the L2, so we need to make room before handling the request
378 Entry L2cache_entry := getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address));
379 if (isDirty(L2cache_entry)) {
380 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address),
381 L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]);
382 } else {
383 trigger(Event:L2_Replacement_clean, L2cacheMemory.cacheProbe(in_msg.Address),
384 L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]);
385 }
386 }
387 }
388 }
389 }
390 }
391
392
393 // ACTIONS
394
395 action(a_issueFetchToMemory, "a", desc="fetch data from memory") {
396 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
397 enqueue(DirRequestIntraChipL2Network_out, RequestMsg, latency=l2_request_latency) {
398 out_msg.Address := address;
399 out_msg.Type := CoherenceRequestType:GETS;
400 out_msg.Requestor := machineID;
401 out_msg.Destination.add(map_Address_to_Directory(address));
402 out_msg.MessageSize := MessageSizeType:Control;
403 }
404 }
405 }
406
407 action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") {
408 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
409 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
410 assert(is_valid(cache_entry));
411 out_msg.Address := address;
412 out_msg.Type := in_msg.Type;
413 out_msg.Requestor := in_msg.Requestor;
414 out_msg.Destination.add(cache_entry.Exclusive);
415 out_msg.MessageSize := MessageSizeType:Request_Control;
416 }
417 }
418 }
419
420 action(c_exclusiveReplacement, "c", desc="Send data to memory") {
421 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
422 assert(is_valid(cache_entry));
423 out_msg.Address := address;
424 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
425 out_msg.Sender := machineID;
426 out_msg.Destination.add(map_Address_to_Directory(address));
427 out_msg.DataBlk := cache_entry.DataBlk;
428 out_msg.Dirty := cache_entry.Dirty;
429 out_msg.MessageSize := MessageSizeType:Response_Data;
430 }
431 }
432
433 action(c_exclusiveCleanReplacement, "cc", desc="Send ack to memory for clean replacement") {
434 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
435 out_msg.Address := address;
436 out_msg.Type := CoherenceResponseType:ACK;
437 out_msg.Sender := machineID;
438 out_msg.Destination.add(map_Address_to_Directory(address));
439 out_msg.MessageSize := MessageSizeType:Response_Control;
440 }
441 }
442
443 action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") {
444 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
445 assert(is_valid(tbe));
446 out_msg.Address := address;
447 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
448 out_msg.Sender := machineID;
449 out_msg.Destination.add(map_Address_to_Directory(address));
450 out_msg.DataBlk := tbe.DataBlk;
451 out_msg.Dirty := tbe.Dirty;
452 out_msg.MessageSize := MessageSizeType:Response_Data;
453 }
454 }
455
456 action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") {
457 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
458 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
459 assert(is_valid(cache_entry));
460 out_msg.Address := address;
461 out_msg.Type := CoherenceResponseType:DATA;
462 out_msg.Sender := machineID;
463 out_msg.Destination.add(in_msg.Requestor);
464 out_msg.DataBlk := cache_entry.DataBlk;
465 out_msg.Dirty := cache_entry.Dirty;
466 out_msg.MessageSize := MessageSizeType:Response_Data;
467
468 out_msg.AckCount := 0 - cache_entry.Sharers.count();
469 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
470 out_msg.AckCount := out_msg.AckCount + 1;
471 }
472 }
473 }
474 }
475
476 action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") {
477 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
478 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
479 assert(is_valid(cache_entry));
480 out_msg.Address := address;
481 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
482 out_msg.Sender := machineID;
483 out_msg.Destination.add(in_msg.Requestor);
484 out_msg.DataBlk := cache_entry.DataBlk;
485 out_msg.Dirty := cache_entry.Dirty;
486 out_msg.MessageSize := MessageSizeType:Response_Data;
487
488 out_msg.AckCount := 0 - cache_entry.Sharers.count();
489 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
490 out_msg.AckCount := out_msg.AckCount + 1;
491 }
492 }
493 }
494 }
495
496 action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") {
497 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
498 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) {
499 assert(is_valid(cache_entry));
500 out_msg.Address := address;
501 out_msg.Type := CoherenceResponseType:DATA;
502 out_msg.Sender := machineID;
503 out_msg.Destination.add(in_msg.Requestor);
504 out_msg.DataBlk := cache_entry.DataBlk;
505 out_msg.Dirty := cache_entry.Dirty;
506 out_msg.MessageSize := MessageSizeType:Response_Data;
507 out_msg.AckCount := 0;
508 }
509 }
510 }
511
512 action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") {
513 assert(is_valid(tbe));
514 assert(tbe.L1_GetS_IDs.count() > 0);
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;
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(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") {
528 assert(is_valid(tbe));
529 assert(tbe.L1_GetS_IDs.count() == 1);
530 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
531 assert(is_valid(cache_entry));
532 out_msg.Address := address;
533 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
534 out_msg.Sender := machineID;
535 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
536 out_msg.DataBlk := cache_entry.DataBlk;
537 out_msg.Dirty := cache_entry.Dirty;
538 out_msg.MessageSize := MessageSizeType:Response_Data;
539 }
540 }
541
542 action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") {
543 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
544 assert(is_valid(tbe));
545 assert(is_valid(cache_entry));
546 out_msg.Address := address;
547 out_msg.Type := CoherenceResponseType:DATA;
548 out_msg.Sender := machineID;
549 out_msg.Destination.add(tbe.L1_GetX_ID);
550 DPRINTF(RubySlicc, "%s\n", out_msg.Destination);
551 out_msg.DataBlk := cache_entry.DataBlk;
552 out_msg.Dirty := cache_entry.Dirty;
553 DPRINTF(RubySlicc, "Address: %s, Destination: %s, DataBlock: %s\n",
554 out_msg.Address, out_msg.Destination, out_msg.DataBlk);
555 out_msg.MessageSize := MessageSizeType:Response_Data;
556 }
557 }
558
559 action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") {
560 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
561 assert(is_valid(cache_entry));
562 out_msg.Address := address;
563 out_msg.Type := CoherenceRequestType:INV;
564 out_msg.Requestor := machineID;
565 out_msg.Destination := cache_entry.Sharers;
566 out_msg.MessageSize := MessageSizeType:Request_Control;
567 }
568 }
569
570 action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") {
571 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
572 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
573 assert(is_valid(cache_entry));
574 out_msg.Address := address;
575 out_msg.Type := CoherenceRequestType:INV;
576 out_msg.Requestor := in_msg.Requestor;
577 out_msg.Destination := cache_entry.Sharers;
578 out_msg.MessageSize := MessageSizeType:Request_Control;
579 }
580 }
581 }
582
583 action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") {
584 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
585 enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) {
586 assert(is_valid(cache_entry));
587 out_msg.Address := address;
588 out_msg.Type := CoherenceRequestType:INV;
589 out_msg.Requestor := in_msg.Requestor;
590 out_msg.Destination := cache_entry.Sharers;
591 out_msg.Destination.remove(in_msg.Requestor);
592 out_msg.MessageSize := MessageSizeType:Request_Control;
593 }
594 }
595 }
596
597 // OTHER ACTIONS
598 action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") {
599 check_allocate(L2_TBEs);
600 assert(is_valid(cache_entry));
601 L2_TBEs.allocate(address);
602 set_tbe(L2_TBEs[address]);
603 tbe.L1_GetS_IDs.clear();
604 tbe.DataBlk := cache_entry.DataBlk;
605 tbe.Dirty := cache_entry.Dirty;
606 tbe.pendingAcks := cache_entry.Sharers.count();
607 }
608
609 action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
610 L2_TBEs.deallocate(address);
611 unset_tbe();
612 }
613
614 action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
615 profileMsgDelay(0, L1RequestIntraChipL2Network_in.dequeue_getDelayCycles());
616 }
617
618 action(k_popUnblockQueue, "k", desc="Pop incoming unblock queue") {
619 profileMsgDelay(0, L1unblockNetwork_in.dequeue_getDelayCycles());
620 }
621
622 action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
623 profileMsgDelay(3, responseIntraChipL2Network_in.dequeue_getDelayCycles());
624 }
625
626 action(m_writeDataToCache, "m", desc="Write data from response queue to cache") {
627 peek(responseIntraChipL2Network_in, ResponseMsg) {
628 assert(is_valid(cache_entry));
629 cache_entry.DataBlk := in_msg.DataBlk;
630 cache_entry.Dirty := in_msg.Dirty;
631 }
632 }
633
634 action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") {
635 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
636 assert(is_valid(cache_entry));
637 cache_entry.DataBlk := in_msg.DataBlk;
638 cache_entry.Dirty := in_msg.Dirty;
639 }
640 }
641
642 action(q_updateAck, "q", desc="update pending ack count") {
643 peek(responseIntraChipL2Network_in, ResponseMsg) {
644 assert(is_valid(tbe));
645 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
646 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
647 APPEND_TRANSITION_COMMENT(" p: ");
648 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
649 }
650 }
651
652 action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") {
653 peek(responseIntraChipL2Network_in, ResponseMsg) {
654 assert(is_valid(tbe));
655 tbe.DataBlk := in_msg.DataBlk;
656 tbe.Dirty := in_msg.Dirty;
657 }
658 }
659
660 action(z_stall, "z", desc="Stall") {
661 }
662
663 action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") {
664 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
665 assert(is_valid(tbe));
666 tbe.L1_GetS_IDs.add(in_msg.Requestor);
667 }
668 }
669
670 action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
671 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
672 assert(is_valid(tbe));
673 tbe.L1_GetX_ID := in_msg.Requestor;
674 }
675 }
676
677 action(set_setMRU, "\set", desc="set the MRU entry") {
678 L2cacheMemory.setMRU(address);
679 }
680
681 action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
682 if (is_invalid(cache_entry)) {
683 set_cache_entry(L2cacheMemory.allocate(address, new Entry));
684 }
685 }
686
687 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
688 L2cacheMemory.deallocate(address);
689 unset_cache_entry();
690 }
691
692 action(t_sendWBAck, "t", desc="Send writeback ACK") {
693 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
694 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
695 out_msg.Address := address;
696 out_msg.Type := CoherenceResponseType:WB_ACK;
697 out_msg.Sender := machineID;
698 out_msg.Destination.add(in_msg.Requestor);
699 out_msg.MessageSize := MessageSizeType:Response_Control;
700 }
701 }
702 }
703
704 action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") {
705 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
706 enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) {
707 assert(is_valid(cache_entry));
708 out_msg.Address := address;
709 out_msg.Type := CoherenceResponseType:ACK;
710 out_msg.Sender := machineID;
711 out_msg.Destination.add(in_msg.Requestor);
712 out_msg.MessageSize := MessageSizeType:Response_Control;
713 // upgrader doesn't get ack from itself, hence the + 1
714 out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1;
715 }
716 }
717 }
718
719 action(uu_profileMiss, "\u", desc="Profile the demand miss") {
720 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
721 //profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, L1CacheMachIDToProcessorNum(in_msg.Requestor));
722 }
723 }
724
725 action(ww_profileMissNoDir, "\w", desc="Profile this transition at the L2 because Dir won't see the request") {
726 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
727 // profile_request(in_msg.L1CacheStateStr, getStateStr(address), "NA", getCoherenceRequestTypeStr(in_msg.Type));
728 }
729 }
730
731 action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
732 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
733 assert(is_valid(cache_entry));
734 addSharer(address, in_msg.Requestor, cache_entry);
735 APPEND_TRANSITION_COMMENT( cache_entry.Sharers );
736 }
737 }
738
739 action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") {
740 peek(L1unblockNetwork_in, ResponseMsg) {
741 assert(is_valid(cache_entry));
742 addSharer(address, in_msg.Sender, cache_entry);
743 }
744 }
745
746 action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
747 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
748 assert(is_valid(cache_entry));
749 cache_entry.Sharers.remove(in_msg.Requestor);
750 }
751 }
752
753 action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
754 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
755 assert(is_valid(cache_entry));
756 cache_entry.Sharers.clear();
757 }
758 }
759
760 action(mm_markExclusive, "\m", desc="set the exclusive owner") {
761 peek(L1RequestIntraChipL2Network_in, RequestMsg) {
762 assert(is_valid(cache_entry));
763 cache_entry.Sharers.clear();
764 cache_entry.Exclusive := in_msg.Requestor;
765 addSharer(address, in_msg.Requestor, cache_entry);
766 }
767 }
768
769 action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") {
770 peek(L1unblockNetwork_in, ResponseMsg) {
771 assert(is_valid(cache_entry));
772 cache_entry.Sharers.clear();
773 cache_entry.Exclusive := in_msg.Sender;
774 addSharer(address, in_msg.Sender, cache_entry);
775 }
776 }
777
778 action(zz_recycleL1RequestQueue, "zz", desc="recycle L1 request queue") {
779 L1RequestIntraChipL2Network_in.recycle();
780 }
781
782 action(zn_recycleResponseNetwork, "zn", desc="recycle memory request") {
783 responseIntraChipL2Network_in.recycle();
784 }
785
786
787 //*****************************************************
788 // TRANSITIONS
789 //*****************************************************
790
791
792 //===============================================
793 // BASE STATE - I
794
795 // Transitions from I (Idle)
796 transition({NP, IS, ISS, IM, SS, M, M_I, I_I, S_I, M_MB, MT_IB, MT_SB}, L1_PUTX) {
797 t_sendWBAck;
798 jj_popL1RequestQueue;
799 }
800
801 transition({NP, SS, M, MT, M_I, I_I, S_I, IS, ISS, IM, M_MB, MT_IB, MT_SB}, L1_PUTX_old) {
802 t_sendWBAck;
803 jj_popL1RequestQueue;
804 }
805
806 transition({IM, IS, ISS, SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L2_Replacement, L2_Replacement_clean}) {
807 zz_recycleL1RequestQueue;
808 }
809
810 transition({IM, IS, ISS, SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, MEM_Inv) {
811 zn_recycleResponseNetwork;
812 }
813
814 transition({S_I, M_I, MT_I}, MEM_Inv) {
815 o_popIncomingResponseQueue;
816 }
817
818
819 transition({SS_MB, M_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE}) {
820 zz_recycleL1RequestQueue;
821 }
822
823
824 transition(NP, L1_GETS, ISS) {
825 qq_allocateL2CacheBlock;
826 ll_clearSharers;
827 nn_addSharer;
828 i_allocateTBE;
829 ss_recordGetSL1ID;
830 a_issueFetchToMemory;
831 uu_profileMiss;
832 jj_popL1RequestQueue;
833 }
834
835 transition(NP, L1_GET_INSTR, IS) {
836 qq_allocateL2CacheBlock;
837 ll_clearSharers;
838 nn_addSharer;
839 i_allocateTBE;
840 ss_recordGetSL1ID;
841 a_issueFetchToMemory;
842 uu_profileMiss;
843 jj_popL1RequestQueue;
844 }
845
846 transition(NP, L1_GETX, IM) {
847 qq_allocateL2CacheBlock;
848 ll_clearSharers;
849 // nn_addSharer;
850 i_allocateTBE;
851 xx_recordGetXL1ID;
852 a_issueFetchToMemory;
853 uu_profileMiss;
854 jj_popL1RequestQueue;
855 }
856
857
858 // transitions from IS/IM
859
860 transition(ISS, Mem_Data, MT_MB) {
861 m_writeDataToCache;
862 ex_sendExclusiveDataToGetSRequestors;
863 s_deallocateTBE;
864 o_popIncomingResponseQueue;
865 }
866
867 transition(IS, Mem_Data, SS) {
868 m_writeDataToCache;
869 e_sendDataToGetSRequestors;
870 s_deallocateTBE;
871 o_popIncomingResponseQueue;
872 }
873
874 transition(IM, Mem_Data, MT_MB) {
875 m_writeDataToCache;
876 ee_sendDataToGetXRequestor;
877 s_deallocateTBE;
878 o_popIncomingResponseQueue;
879 }
880
881 transition({IS, ISS}, {L1_GETS, L1_GET_INSTR}, IS) {
882 nn_addSharer;
883 ss_recordGetSL1ID;
884 uu_profileMiss;
885 jj_popL1RequestQueue;
886 }
887
888 transition({IS, ISS}, L1_GETX) {
889 zz_recycleL1RequestQueue;
890 }
891
892 transition(IM, {L1_GETX, L1_GETS, L1_GET_INSTR}) {
893 zz_recycleL1RequestQueue;
894 }
895
896 // transitions from SS
897 transition(SS, {L1_GETS, L1_GET_INSTR}) {
898 ds_sendSharedDataToRequestor;
899 nn_addSharer;
900 uu_profileMiss;
901 set_setMRU;
902 jj_popL1RequestQueue;
903 }
904
905
906 transition(SS, L1_GETX, SS_MB) {
907 d_sendDataToRequestor;
908 // fw_sendFwdInvToSharers;
909 fwm_sendFwdInvToSharersMinusRequestor;
910 uu_profileMiss;
911 set_setMRU;
912 jj_popL1RequestQueue;
913 }
914
915 transition(SS, L1_UPGRADE, SS_MB) {
916 fwm_sendFwdInvToSharersMinusRequestor;
917 ts_sendInvAckToUpgrader;
918 uu_profileMiss;
919 set_setMRU;
920 jj_popL1RequestQueue;
921 }
922
923 transition(SS, L2_Replacement_clean, I_I) {
924 i_allocateTBE;
925 f_sendInvToSharers;
926 rr_deallocateL2CacheBlock;
927 }
928
929 transition(SS, {L2_Replacement, MEM_Inv}, S_I) {
930 i_allocateTBE;
931 f_sendInvToSharers;
932 rr_deallocateL2CacheBlock;
933 }
934
935
936 transition(M, L1_GETX, MT_MB) {
937 d_sendDataToRequestor;
938 uu_profileMiss;
939 set_setMRU;
940 jj_popL1RequestQueue;
941 }
942
943 transition(M, L1_GET_INSTR, SS) {
944 d_sendDataToRequestor;
945 nn_addSharer;
946 uu_profileMiss;
947 set_setMRU;
948 jj_popL1RequestQueue;
949 }
950
951 transition(M, L1_GETS, MT_MB) {
952 dd_sendExclusiveDataToRequestor;
953 uu_profileMiss;
954 set_setMRU;
955 jj_popL1RequestQueue;
956 }
957
958 transition(M, {L2_Replacement, MEM_Inv}, M_I) {
959 i_allocateTBE;
960 c_exclusiveReplacement;
961 rr_deallocateL2CacheBlock;
962 }
963
964 transition(M, L2_Replacement_clean, M_I) {
965 i_allocateTBE;
966 c_exclusiveCleanReplacement;
967 rr_deallocateL2CacheBlock;
968 }
969
970
971 // transitions from MT
972
973 transition(MT, L1_GETX, MT_MB) {
974 b_forwardRequestToExclusive;
975 uu_profileMiss;
976 set_setMRU;
977 jj_popL1RequestQueue;
978 }
979
980
981 transition(MT, {L1_GETS, L1_GET_INSTR}, MT_IIB) {
982 b_forwardRequestToExclusive;
983 uu_profileMiss;
984 set_setMRU;
985 jj_popL1RequestQueue;
986 }
987
988 transition(MT, {L2_Replacement, MEM_Inv}, MT_I) {
989 i_allocateTBE;
990 f_sendInvToSharers;
991 rr_deallocateL2CacheBlock;
992 }
993
994 transition(MT, L2_Replacement_clean, MCT_I) {
995 i_allocateTBE;
996 f_sendInvToSharers;
997 rr_deallocateL2CacheBlock;
998 }
999
1000 transition(MT, L1_PUTX, M) {
1001 ll_clearSharers;
1002 mr_writeDataToCacheFromRequest;
1003 t_sendWBAck;
1004 jj_popL1RequestQueue;
1005 }
1006
1007
1008 // transitions from blocking states
1009 transition(SS_MB, Unblock_Cancel, SS) {
1010 k_popUnblockQueue;
1011 }
1012
1013 transition(MT_MB, Unblock_Cancel, MT) {
1014 k_popUnblockQueue;
1015 }
1016
1017 transition(MT_IB, Unblock_Cancel, MT) {
1018 k_popUnblockQueue;
1019 }
1020
1021 transition(SS_MB, Exclusive_Unblock, MT) {
1022 // update actual directory
1023 mmu_markExclusiveFromUnblock;
1024 k_popUnblockQueue;
1025 }
1026
1027 transition({M_MB, MT_MB}, Exclusive_Unblock, MT) {
1028 // update actual directory
1029 mmu_markExclusiveFromUnblock;
1030 k_popUnblockQueue;
1031 }
1032
1033 transition(MT_IIB, {L1_PUTX, L1_PUTX_old}){
1034 zz_recycleL1RequestQueue;
1035 }
1036
1037 transition(MT_IIB, Unblock, MT_IB) {
1038 nnu_addSharerFromUnblock;
1039 k_popUnblockQueue;
1040 }
1041
1042 transition(MT_IIB, {WB_Data, WB_Data_clean}, MT_SB) {
1043 m_writeDataToCache;
1044 o_popIncomingResponseQueue;
1045 }
1046
1047 transition(MT_IB, {WB_Data, WB_Data_clean}, SS) {
1048 m_writeDataToCache;
1049 o_popIncomingResponseQueue;
1050 }
1051
1052 transition(MT_SB, Unblock, SS) {
1053 nnu_addSharerFromUnblock;
1054 k_popUnblockQueue;
1055 }
1056
1057 // writeback states
1058 transition({I_I, S_I, MT_I, MCT_I, M_I}, {L1_GETX, L1_UPGRADE, L1_GETS, L1_GET_INSTR}) {
1059 zz_recycleL1RequestQueue;
1060 }
1061
1062 transition(I_I, Ack) {
1063 q_updateAck;
1064 o_popIncomingResponseQueue;
1065 }
1066
1067 transition(I_I, Ack_all, M_I) {
1068 c_exclusiveCleanReplacement;
1069 o_popIncomingResponseQueue;
1070 }
1071
1072 transition({MT_I, MCT_I}, WB_Data, M_I) {
1073 qq_writeDataToTBE;
1074 ct_exclusiveReplacementFromTBE;
1075 o_popIncomingResponseQueue;
1076 }
1077
1078 transition(MCT_I, {WB_Data_clean, Ack_all}, M_I) {
1079 c_exclusiveCleanReplacement;
1080 o_popIncomingResponseQueue;
1081 }
1082
1083 transition(MCT_I, {L1_PUTX, L1_PUTX_old}){
1084 zz_recycleL1RequestQueue;
1085 }
1086
1087 // L1 never changed Dirty data
1088 transition(MT_I, Ack_all, M_I) {
1089 ct_exclusiveReplacementFromTBE;
1090 o_popIncomingResponseQueue;
1091 }
1092
1093 transition(MT_I, {L1_PUTX, L1_PUTX_old}){
1094 zz_recycleL1RequestQueue;
1095 }
1096
1097 // possible race between unblock and immediate replacement
1098 transition({MT_MB,SS_MB}, {L1_PUTX, L1_PUTX_old}) {
1099 zz_recycleL1RequestQueue;
1100 }
1101
1102 transition(MT_I, WB_Data_clean, NP) {
1103 s_deallocateTBE;
1104 o_popIncomingResponseQueue;
1105 }
1106
1107 transition(S_I, Ack) {
1108 q_updateAck;
1109 o_popIncomingResponseQueue;
1110 }
1111
1112 transition(S_I, Ack_all, M_I) {
1113 ct_exclusiveReplacementFromTBE;
1114 o_popIncomingResponseQueue;
1115 }
1116
1117 transition(M_I, Mem_Ack, NP) {
1118 s_deallocateTBE;
1119 o_popIncomingResponseQueue;
1120 }
1121 }