MESI: Add queues for stalled requests
[gem5.git] / src / mem / protocol / MESI_CMP_directory-L1cache.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 machine(L1Cache, "MESI Directory L1 Cache CMP")
31 : Sequencer * sequencer,
32 CacheMemory * L1IcacheMemory,
33 CacheMemory * L1DcacheMemory,
34 int l2_select_num_bits,
35 int l1_request_latency = 2,
36 int l1_response_latency = 2,
37 int to_l2_latency = 1,
38 bool send_evictions
39 {
40 // NODE L1 CACHE
41 // From this node's L1 cache TO the network
42 // a local L1 -> this L2 bank, currently ordered with directory forwarded requests
43 MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="false", vnet_type="request";
44 // a local L1 -> this L2 bank
45 MessageBuffer responseFromL1Cache, network="To", virtual_network="1", ordered="false", vnet_type="response";
46 MessageBuffer unblockFromL1Cache, network="To", virtual_network="2", ordered="false", vnet_type="unblock";
47
48
49 // To this node's L1 cache FROM the network
50 // a L2 bank -> this L1
51 MessageBuffer requestToL1Cache, network="From", virtual_network="0", ordered="false", vnet_type="request";
52 // a L2 bank -> this L1
53 MessageBuffer responseToL1Cache, network="From", virtual_network="1", ordered="false", vnet_type="response";
54
55 // STATES
56 state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
57 // Base states
58 NP, AccessPermission:Invalid, desc="Not present in either cache";
59 I, AccessPermission:Invalid, desc="a L1 cache entry Idle";
60 S, AccessPermission:Read_Only, desc="a L1 cache entry Shared";
61 E, AccessPermission:Read_Only, desc="a L1 cache entry Exclusive";
62 M, AccessPermission:Read_Write, desc="a L1 cache entry Modified", format="!b";
63
64 // Transient States
65 IS, AccessPermission:Busy, desc="L1 idle, issued GETS, have not seen response yet";
66 IM, AccessPermission:Busy, desc="L1 idle, issued GETX, have not seen response yet";
67 SM, AccessPermission:Read_Only, desc="L1 idle, issued GETX, have not seen response yet";
68 IS_I, AccessPermission:Busy, desc="L1 idle, issued GETS, saw Inv before data because directory doesn't block on GETS hit";
69
70 M_I, AccessPermission:Busy, desc="L1 replacing, waiting for ACK";
71 SINK_WB_ACK, AccessPermission:Busy, desc="This is to sink WB_Acks from L2";
72
73 }
74
75 // EVENTS
76 enumeration(Event, desc="Cache events") {
77 // L1 events
78 Load, desc="Load request from the home processor";
79 Ifetch, desc="I-fetch request from the home processor";
80 Store, desc="Store request from the home processor";
81
82 Inv, desc="Invalidate request from L2 bank";
83
84 // internal generated request
85 L1_Replacement, desc="L1 Replacement", format="!r";
86
87 // other requests
88 Fwd_GETX, desc="GETX from other processor";
89 Fwd_GETS, desc="GETS from other processor";
90 Fwd_GET_INSTR, desc="GET_INSTR from other processor";
91
92 Data, desc="Data for processor";
93 Data_Exclusive, desc="Data for processor";
94 DataS_fromL1, desc="data for GETS request, need to unblock directory";
95 Data_all_Acks, desc="Data for processor, all acks";
96
97 Ack, desc="Ack for processor";
98 Ack_all, desc="Last ack for processor";
99
100 WB_Ack, desc="Ack for replacement";
101 }
102
103 // TYPES
104
105 // CacheEntry
106 structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
107 State CacheState, desc="cache state";
108 DataBlock DataBlk, desc="data for the block";
109 bool Dirty, default="false", desc="data is dirty";
110 }
111
112 // TBE fields
113 structure(TBE, desc="...") {
114 Address Address, desc="Physical address for this TBE";
115 State TBEState, desc="Transient state";
116 DataBlock DataBlk, desc="Buffer for the data block";
117 bool Dirty, default="false", desc="data is dirty";
118 bool isPrefetch, desc="Set if this was caused by a prefetch";
119 int pendingAcks, default="0", desc="number of pending acks";
120 }
121
122 structure(TBETable, external="yes") {
123 TBE lookup(Address);
124 void allocate(Address);
125 void deallocate(Address);
126 bool isPresent(Address);
127 }
128
129 TBETable L1_TBEs, template_hack="<L1Cache_TBE>";
130
131 MessageBuffer mandatoryQueue, ordered="false";
132
133 int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
134
135 void set_cache_entry(AbstractCacheEntry a);
136 void unset_cache_entry();
137 void set_tbe(TBE a);
138 void unset_tbe();
139 void wakeUpBuffers(Address a);
140
141 // inclusive cache returns L1 entries only
142 Entry getCacheEntry(Address addr), return_by_pointer="yes" {
143 Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory[addr]);
144 if(is_valid(L1Dcache_entry)) {
145 return L1Dcache_entry;
146 }
147
148 Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory[addr]);
149 return L1Icache_entry;
150 }
151
152 Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" {
153 Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory[addr]);
154 return L1Dcache_entry;
155 }
156
157 Entry getL1ICacheEntry(Address addr), return_by_pointer="yes" {
158 Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory[addr]);
159 return L1Icache_entry;
160 }
161
162 State getState(TBE tbe, Entry cache_entry, Address addr) {
163 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
164
165 if(is_valid(tbe)) {
166 return tbe.TBEState;
167 } else if (is_valid(cache_entry)) {
168 return cache_entry.CacheState;
169 }
170 return State:NP;
171 }
172
173 void setState(TBE tbe, Entry cache_entry, Address addr, State state) {
174 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
175
176 // MUST CHANGE
177 if(is_valid(tbe)) {
178 tbe.TBEState := state;
179 }
180
181 if (is_valid(cache_entry)) {
182 cache_entry.CacheState := state;
183 }
184 }
185
186 AccessPermission getAccessPermission(Address addr) {
187 TBE tbe := L1_TBEs[addr];
188 if(is_valid(tbe)) {
189 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
190 return L1Cache_State_to_permission(tbe.TBEState);
191 }
192
193 Entry cache_entry := getCacheEntry(addr);
194 if(is_valid(cache_entry)) {
195 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
196 return L1Cache_State_to_permission(cache_entry.CacheState);
197 }
198
199 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
200 return AccessPermission:NotPresent;
201 }
202
203 DataBlock getDataBlock(Address addr), return_by_ref="yes" {
204 return getCacheEntry(addr).DataBlk;
205 }
206
207 void setAccessPermission(Entry cache_entry, Address addr, State state) {
208 if (is_valid(cache_entry)) {
209 cache_entry.changePermission(L1Cache_State_to_permission(state));
210 }
211 }
212
213 Event mandatory_request_type_to_event(RubyRequestType type) {
214 if (type == RubyRequestType:LD) {
215 return Event:Load;
216 } else if (type == RubyRequestType:IFETCH) {
217 return Event:Ifetch;
218 } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
219 return Event:Store;
220 } else {
221 error("Invalid RubyRequestType");
222 }
223 }
224
225 int getPendingAcks(TBE tbe) {
226 return tbe.pendingAcks;
227 }
228
229 out_port(requestIntraChipL1Network_out, RequestMsg, requestFromL1Cache);
230 out_port(responseIntraChipL1Network_out, ResponseMsg, responseFromL1Cache);
231 out_port(unblockNetwork_out, ResponseMsg, unblockFromL1Cache);
232
233 // Response IntraChip L1 Network - response msg to this L1 cache
234 in_port(responseIntraChipL1Network_in, ResponseMsg, responseToL1Cache, rank = 2) {
235 if (responseIntraChipL1Network_in.isReady()) {
236 peek(responseIntraChipL1Network_in, ResponseMsg, block_on="Address") {
237 assert(in_msg.Destination.isElement(machineID));
238
239 Entry cache_entry := getCacheEntry(in_msg.Address);
240 TBE tbe := L1_TBEs[in_msg.Address];
241
242 if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
243 trigger(Event:Data_Exclusive, in_msg.Address, cache_entry, tbe);
244 } else if(in_msg.Type == CoherenceResponseType:DATA) {
245 if ((getState(tbe, cache_entry, in_msg.Address) == State:IS ||
246 getState(tbe, cache_entry, in_msg.Address) == State:IS_I) &&
247 machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
248
249 trigger(Event:DataS_fromL1, in_msg.Address, cache_entry, tbe);
250
251 } else if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
252 trigger(Event:Data_all_Acks, in_msg.Address, cache_entry, tbe);
253 } else {
254 trigger(Event:Data, in_msg.Address, cache_entry, tbe);
255 }
256 } else if (in_msg.Type == CoherenceResponseType:ACK) {
257 if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) {
258 trigger(Event:Ack_all, in_msg.Address, cache_entry, tbe);
259 } else {
260 trigger(Event:Ack, in_msg.Address, cache_entry, tbe);
261 }
262 } else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
263 trigger(Event:WB_Ack, in_msg.Address, cache_entry, tbe);
264 } else {
265 error("Invalid L1 response type");
266 }
267 }
268 }
269 }
270
271 // Request InterChip network - request from this L1 cache to the shared L2
272 in_port(requestIntraChipL1Network_in, RequestMsg, requestToL1Cache, rank = 1) {
273 if(requestIntraChipL1Network_in.isReady()) {
274 peek(requestIntraChipL1Network_in, RequestMsg, block_on="Address") {
275 assert(in_msg.Destination.isElement(machineID));
276
277 Entry cache_entry := getCacheEntry(in_msg.Address);
278 TBE tbe := L1_TBEs[in_msg.Address];
279
280 if (in_msg.Type == CoherenceRequestType:INV) {
281 trigger(Event:Inv, in_msg.Address, cache_entry, tbe);
282 } else if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:UPGRADE) {
283 // upgrade transforms to GETX due to race
284 trigger(Event:Fwd_GETX, in_msg.Address, cache_entry, tbe);
285 } else if (in_msg.Type == CoherenceRequestType:GETS) {
286 trigger(Event:Fwd_GETS, in_msg.Address, cache_entry, tbe);
287 } else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
288 trigger(Event:Fwd_GET_INSTR, in_msg.Address, cache_entry, tbe);
289 } else {
290 error("Invalid forwarded request type");
291 }
292 }
293 }
294 }
295
296 // Mandatory Queue betweens Node's CPU and it's L1 caches
297 in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...", rank = 0) {
298 if (mandatoryQueue_in.isReady()) {
299 peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
300
301 // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
302
303 if (in_msg.Type == RubyRequestType:IFETCH) {
304 // ** INSTRUCTION ACCESS ***
305
306 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
307 if (is_valid(L1Icache_entry)) {
308 // The tag matches for the L1, so the L1 asks the L2 for it.
309 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
310 L1Icache_entry, L1_TBEs[in_msg.LineAddress]);
311 } else {
312
313 // Check to see if it is in the OTHER L1
314 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
315 if (is_valid(L1Dcache_entry)) {
316 // The block is in the wrong L1, put the request on the queue to the shared L2
317 trigger(Event:L1_Replacement, in_msg.LineAddress,
318 L1Dcache_entry, L1_TBEs[in_msg.LineAddress]);
319 }
320
321 if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) {
322 // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
323 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
324 L1Icache_entry, L1_TBEs[in_msg.LineAddress]);
325 } else {
326 // No room in the L1, so we need to make room in the L1
327 trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress),
328 getL1ICacheEntry(L1IcacheMemory.cacheProbe(in_msg.LineAddress)),
329 L1_TBEs[L1IcacheMemory.cacheProbe(in_msg.LineAddress)]);
330 }
331 }
332 } else {
333
334 // *** DATA ACCESS ***
335 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
336 if (is_valid(L1Dcache_entry)) {
337 // The tag matches for the L1, so the L1 ask the L2 for it
338 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
339 L1Dcache_entry, L1_TBEs[in_msg.LineAddress]);
340 } else {
341
342 // Check to see if it is in the OTHER L1
343 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
344 if (is_valid(L1Icache_entry)) {
345 // The block is in the wrong L1, put the request on the queue to the shared L2
346 trigger(Event:L1_Replacement, in_msg.LineAddress,
347 L1Icache_entry, L1_TBEs[in_msg.LineAddress]);
348 }
349
350 if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) {
351 // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
352 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
353 L1Dcache_entry, L1_TBEs[in_msg.LineAddress]);
354 } else {
355 // No room in the L1, so we need to make room in the L1
356 trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress),
357 getL1DCacheEntry(L1DcacheMemory.cacheProbe(in_msg.LineAddress)),
358 L1_TBEs[L1DcacheMemory.cacheProbe(in_msg.LineAddress)]);
359 }
360 }
361 }
362 }
363 }
364 }
365
366 // ACTIONS
367 action(a_issueGETS, "a", desc="Issue GETS") {
368 peek(mandatoryQueue_in, RubyRequest) {
369 enqueue(requestIntraChipL1Network_out, RequestMsg, latency=l1_request_latency) {
370 out_msg.Address := address;
371 out_msg.Type := CoherenceRequestType:GETS;
372 out_msg.Requestor := machineID;
373 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
374 l2_select_low_bit, l2_select_num_bits));
375 DPRINTF(RubySlicc, "address: %s, destination: %s\n",
376 address, out_msg.Destination);
377 out_msg.MessageSize := MessageSizeType:Control;
378 out_msg.Prefetch := in_msg.Prefetch;
379 out_msg.AccessMode := in_msg.AccessMode;
380 }
381 }
382 }
383
384 action(ai_issueGETINSTR, "ai", desc="Issue GETINSTR") {
385 peek(mandatoryQueue_in, RubyRequest) {
386 enqueue(requestIntraChipL1Network_out, RequestMsg, latency=l1_request_latency) {
387 out_msg.Address := address;
388 out_msg.Type := CoherenceRequestType:GET_INSTR;
389 out_msg.Requestor := machineID;
390 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
391 l2_select_low_bit, l2_select_num_bits));
392 DPRINTF(RubySlicc, "address: %s, destination: %s\n",
393 address, out_msg.Destination);
394 out_msg.MessageSize := MessageSizeType:Control;
395 out_msg.Prefetch := in_msg.Prefetch;
396 out_msg.AccessMode := in_msg.AccessMode;
397 }
398 }
399 }
400
401
402 action(b_issueGETX, "b", desc="Issue GETX") {
403 peek(mandatoryQueue_in, RubyRequest) {
404 enqueue(requestIntraChipL1Network_out, RequestMsg, latency=l1_request_latency) {
405 out_msg.Address := address;
406 out_msg.Type := CoherenceRequestType:GETX;
407 out_msg.Requestor := machineID;
408 DPRINTF(RubySlicc, "%s\n", machineID);
409 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
410 l2_select_low_bit, l2_select_num_bits));
411 DPRINTF(RubySlicc, "address: %s, destination: %s\n",
412 address, out_msg.Destination);
413 out_msg.MessageSize := MessageSizeType:Control;
414 out_msg.Prefetch := in_msg.Prefetch;
415 out_msg.AccessMode := in_msg.AccessMode;
416 }
417 }
418 }
419
420 action(c_issueUPGRADE, "c", desc="Issue GETX") {
421 peek(mandatoryQueue_in, RubyRequest) {
422 enqueue(requestIntraChipL1Network_out, RequestMsg, latency= l1_request_latency) {
423 out_msg.Address := address;
424 out_msg.Type := CoherenceRequestType:UPGRADE;
425 out_msg.Requestor := machineID;
426 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
427 l2_select_low_bit, l2_select_num_bits));
428 DPRINTF(RubySlicc, "address: %s, destination: %s\n",
429 address, out_msg.Destination);
430 out_msg.MessageSize := MessageSizeType:Control;
431 out_msg.Prefetch := in_msg.Prefetch;
432 out_msg.AccessMode := in_msg.AccessMode;
433 }
434 }
435 }
436
437 action(d_sendDataToRequestor, "d", desc="send data to requestor") {
438 peek(requestIntraChipL1Network_in, RequestMsg) {
439 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
440 assert(is_valid(cache_entry));
441 out_msg.Address := address;
442 out_msg.Type := CoherenceResponseType:DATA;
443 out_msg.DataBlk := cache_entry.DataBlk;
444 out_msg.Dirty := cache_entry.Dirty;
445 out_msg.Sender := machineID;
446 out_msg.Destination.add(in_msg.Requestor);
447 out_msg.MessageSize := MessageSizeType:Response_Data;
448 }
449 }
450 }
451
452 action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") {
453 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
454 assert(is_valid(cache_entry));
455 out_msg.Address := address;
456 out_msg.Type := CoherenceResponseType:DATA;
457 out_msg.DataBlk := cache_entry.DataBlk;
458 out_msg.Dirty := cache_entry.Dirty;
459 out_msg.Sender := machineID;
460 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
461 l2_select_low_bit, l2_select_num_bits));
462 out_msg.MessageSize := MessageSizeType:Response_Data;
463 }
464 }
465
466 action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") {
467 peek(requestIntraChipL1Network_in, RequestMsg) {
468 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
469 assert(is_valid(tbe));
470 out_msg.Address := address;
471 out_msg.Type := CoherenceResponseType:DATA;
472 out_msg.DataBlk := tbe.DataBlk;
473 out_msg.Dirty := tbe.Dirty;
474 out_msg.Sender := machineID;
475 out_msg.Destination.add(in_msg.Requestor);
476 out_msg.MessageSize := MessageSizeType:Response_Data;
477 }
478 }
479 }
480
481 action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") {
482 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
483 assert(is_valid(tbe));
484 out_msg.Address := address;
485 out_msg.Type := CoherenceResponseType:DATA;
486 out_msg.DataBlk := tbe.DataBlk;
487 out_msg.Dirty := tbe.Dirty;
488 out_msg.Sender := machineID;
489 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
490 l2_select_low_bit, l2_select_num_bits));
491 out_msg.MessageSize := MessageSizeType:Response_Data;
492 }
493 }
494
495 action(e_sendAckToRequestor, "e", desc="send invalidate ack to requestor (could be L2 or L1)") {
496 peek(requestIntraChipL1Network_in, RequestMsg) {
497 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
498 out_msg.Address := address;
499 out_msg.Type := CoherenceResponseType:ACK;
500 out_msg.Sender := machineID;
501 out_msg.Destination.add(in_msg.Requestor);
502 out_msg.MessageSize := MessageSizeType:Response_Control;
503 }
504 }
505 }
506
507 action(f_sendDataToL2, "f", desc="send data to the L2 cache") {
508 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
509 assert(is_valid(cache_entry));
510 out_msg.Address := address;
511 out_msg.Type := CoherenceResponseType:DATA;
512 out_msg.DataBlk := cache_entry.DataBlk;
513 out_msg.Dirty := cache_entry.Dirty;
514 out_msg.Sender := machineID;
515 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
516 l2_select_low_bit, l2_select_num_bits));
517 out_msg.MessageSize := MessageSizeType:Writeback_Data;
518 }
519 }
520
521 action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") {
522 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
523 assert(is_valid(tbe));
524 out_msg.Address := address;
525 out_msg.Type := CoherenceResponseType:DATA;
526 out_msg.DataBlk := tbe.DataBlk;
527 out_msg.Dirty := tbe.Dirty;
528 out_msg.Sender := machineID;
529 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
530 l2_select_low_bit, l2_select_num_bits));
531 out_msg.MessageSize := MessageSizeType:Writeback_Data;
532 }
533 }
534
535 action(fi_sendInvAck, "fi", desc="send data to the L2 cache") {
536 peek(requestIntraChipL1Network_in, RequestMsg) {
537 enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) {
538 out_msg.Address := address;
539 out_msg.Type := CoherenceResponseType:ACK;
540 out_msg.Sender := machineID;
541 out_msg.Destination.add(in_msg.Requestor);
542 out_msg.MessageSize := MessageSizeType:Response_Control;
543 out_msg.AckCount := 1;
544 }
545 }
546 }
547
548 action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
549 if (send_evictions) {
550 DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
551 sequencer.evictionCallback(address);
552 }
553 }
554
555 action(g_issuePUTX, "g", desc="send data to the L2 cache") {
556 enqueue(requestIntraChipL1Network_out, RequestMsg, latency=l1_response_latency) {
557 assert(is_valid(cache_entry));
558 out_msg.Address := address;
559 out_msg.Type := CoherenceRequestType:PUTX;
560 out_msg.DataBlk := cache_entry.DataBlk;
561 out_msg.Dirty := cache_entry.Dirty;
562 out_msg.Requestor:= machineID;
563 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
564 l2_select_low_bit, l2_select_num_bits));
565 if (cache_entry.Dirty) {
566 out_msg.MessageSize := MessageSizeType:Writeback_Data;
567 } else {
568 out_msg.MessageSize := MessageSizeType:Writeback_Control;
569 }
570 }
571 }
572
573 action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
574 enqueue(unblockNetwork_out, ResponseMsg, latency=to_l2_latency) {
575 out_msg.Address := address;
576 out_msg.Type := CoherenceResponseType:UNBLOCK;
577 out_msg.Sender := machineID;
578 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
579 l2_select_low_bit, l2_select_num_bits));
580 out_msg.MessageSize := MessageSizeType:Response_Control;
581 DPRINTF(RubySlicc, "%s\n", address);
582
583 }
584 }
585
586 action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
587 enqueue(unblockNetwork_out, ResponseMsg, latency=to_l2_latency) {
588 out_msg.Address := address;
589 out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
590 out_msg.Sender := machineID;
591 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
592 l2_select_low_bit, l2_select_num_bits));
593 out_msg.MessageSize := MessageSizeType:Response_Control;
594 DPRINTF(RubySlicc, "%s\n", address);
595
596 }
597 }
598
599 action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
600 assert(is_valid(cache_entry));
601 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
602 sequencer.readCallback(address, cache_entry.DataBlk);
603 }
604
605 action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
606 assert(is_valid(cache_entry));
607 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
608 sequencer.writeCallback(address, cache_entry.DataBlk);
609 cache_entry.Dirty := true;
610 }
611
612 action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") {
613 check_allocate(L1_TBEs);
614 assert(is_valid(cache_entry));
615 L1_TBEs.allocate(address);
616 set_tbe(L1_TBEs[address]);
617 tbe.isPrefetch := false;
618 tbe.Dirty := cache_entry.Dirty;
619 tbe.DataBlk := cache_entry.DataBlk;
620 }
621
622 action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
623 mandatoryQueue_in.dequeue();
624 }
625
626 action(l_popRequestQueue, "l", desc="Pop incoming request queue and profile the delay within this virtual network") {
627 profileMsgDelay(2, requestIntraChipL1Network_in.dequeue_getDelayCycles());
628 }
629
630 action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue and profile the delay within this virtual network") {
631 profileMsgDelay(3, responseIntraChipL1Network_in.dequeue_getDelayCycles());
632 }
633
634 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
635 L1_TBEs.deallocate(address);
636 unset_tbe();
637 }
638
639 action(u_writeDataToL1Cache, "u", desc="Write data to cache") {
640 peek(responseIntraChipL1Network_in, ResponseMsg) {
641 assert(is_valid(cache_entry));
642 cache_entry.DataBlk := in_msg.DataBlk;
643 cache_entry.Dirty := in_msg.Dirty;
644 }
645 }
646
647 action(q_updateAckCount, "q", desc="Update ack count") {
648 peek(responseIntraChipL1Network_in, ResponseMsg) {
649 assert(is_valid(tbe));
650 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
651 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
652 APPEND_TRANSITION_COMMENT(" p: ");
653 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
654 }
655 }
656
657 action(ff_deallocateL1CacheBlock, "\f", desc="Deallocate L1 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
658 if (L1DcacheMemory.isTagPresent(address)) {
659 L1DcacheMemory.deallocate(address);
660 } else {
661 L1IcacheMemory.deallocate(address);
662 }
663 unset_cache_entry();
664 }
665
666 action(oo_allocateL1DCacheBlock, "\o", desc="Set L1 D-cache tag equal to tag of block B.") {
667 if (is_invalid(cache_entry)) {
668 set_cache_entry(L1DcacheMemory.allocate(address, new Entry));
669 }
670 }
671
672 action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
673 if (is_invalid(cache_entry)) {
674 set_cache_entry(L1IcacheMemory.allocate(address, new Entry));
675 }
676 }
677
678 action(z_stallAndWaitMandatoryQueue, "\z", desc="recycle L1 request queue") {
679 stall_and_wait(mandatoryQueue_in, address);
680 }
681
682 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
683 wakeUpBuffers(address);
684 }
685
686 action(uu_profileInstMiss, "\ui", desc="Profile the demand miss") {
687 peek(mandatoryQueue_in, RubyRequest) {
688 L1IcacheMemory.profileMiss(in_msg);
689 }
690 }
691
692 action(uu_profileDataMiss, "\ud", desc="Profile the demand miss") {
693 peek(mandatoryQueue_in, RubyRequest) {
694 L1DcacheMemory.profileMiss(in_msg);
695 }
696 }
697
698 //*****************************************************
699 // TRANSITIONS
700 //*****************************************************
701
702 // Transitions for Load/Store/Replacement/WriteBack from transient states
703 transition({IS, IM, IS_I, M_I, SM, SINK_WB_ACK}, {Load, Ifetch, Store, L1_Replacement}) {
704 z_stallAndWaitMandatoryQueue;
705 }
706
707 // Transitions from Idle
708 transition({NP,I}, L1_Replacement) {
709 ff_deallocateL1CacheBlock;
710 }
711
712 transition({NP,I}, Load, IS) {
713 oo_allocateL1DCacheBlock;
714 i_allocateTBE;
715 a_issueGETS;
716 uu_profileDataMiss;
717 k_popMandatoryQueue;
718 }
719
720 transition({NP,I}, Ifetch, IS) {
721 pp_allocateL1ICacheBlock;
722 i_allocateTBE;
723 ai_issueGETINSTR;
724 uu_profileInstMiss;
725 k_popMandatoryQueue;
726 }
727
728 transition({NP,I}, Store, IM) {
729 oo_allocateL1DCacheBlock;
730 i_allocateTBE;
731 b_issueGETX;
732 uu_profileDataMiss;
733 k_popMandatoryQueue;
734 }
735
736 transition({NP, I}, Inv) {
737 fi_sendInvAck;
738 l_popRequestQueue;
739 }
740
741 // Transitions from Shared
742 transition(S, {Load,Ifetch}) {
743 h_load_hit;
744 k_popMandatoryQueue;
745 }
746
747 transition(S, Store, SM) {
748 i_allocateTBE;
749 c_issueUPGRADE;
750 uu_profileDataMiss;
751 k_popMandatoryQueue;
752 }
753
754 transition(S, L1_Replacement, I) {
755 forward_eviction_to_cpu;
756 ff_deallocateL1CacheBlock;
757 }
758
759 transition(S, Inv, I) {
760 forward_eviction_to_cpu;
761 fi_sendInvAck;
762 l_popRequestQueue;
763 }
764
765 // Transitions from Exclusive
766
767 transition(E, {Load, Ifetch}) {
768 h_load_hit;
769 k_popMandatoryQueue;
770 }
771
772 transition(E, Store, M) {
773 hh_store_hit;
774 k_popMandatoryQueue;
775 }
776
777 transition(E, L1_Replacement, M_I) {
778 // silent E replacement??
779 forward_eviction_to_cpu;
780 i_allocateTBE;
781 g_issuePUTX; // send data, but hold in case forwarded request
782 ff_deallocateL1CacheBlock;
783 }
784
785 transition(E, Inv, I) {
786 // don't send data
787 forward_eviction_to_cpu;
788 fi_sendInvAck;
789 l_popRequestQueue;
790 }
791
792 transition(E, Fwd_GETX, I) {
793 forward_eviction_to_cpu;
794 d_sendDataToRequestor;
795 l_popRequestQueue;
796 }
797
798 transition(E, {Fwd_GETS, Fwd_GET_INSTR}, S) {
799 d_sendDataToRequestor;
800 d2_sendDataToL2;
801 l_popRequestQueue;
802 }
803
804 // Transitions from Modified
805 transition(M, {Load, Ifetch}) {
806 h_load_hit;
807 k_popMandatoryQueue;
808 }
809
810 transition(M, Store) {
811 hh_store_hit;
812 k_popMandatoryQueue;
813 }
814
815 transition(M, L1_Replacement, M_I) {
816 forward_eviction_to_cpu;
817 i_allocateTBE;
818 g_issuePUTX; // send data, but hold in case forwarded request
819 ff_deallocateL1CacheBlock;
820 }
821
822 transition(M_I, WB_Ack, I) {
823 s_deallocateTBE;
824 o_popIncomingResponseQueue;
825 kd_wakeUpDependents;
826 }
827
828 transition(M, Inv, I) {
829 forward_eviction_to_cpu;
830 f_sendDataToL2;
831 l_popRequestQueue;
832 }
833
834 transition(M_I, Inv, SINK_WB_ACK) {
835 ft_sendDataToL2_fromTBE;
836 l_popRequestQueue;
837 }
838
839 transition(M, Fwd_GETX, I) {
840 forward_eviction_to_cpu;
841 d_sendDataToRequestor;
842 l_popRequestQueue;
843 }
844
845 transition(M, {Fwd_GETS, Fwd_GET_INSTR}, S) {
846 d_sendDataToRequestor;
847 d2_sendDataToL2;
848 l_popRequestQueue;
849 }
850
851 transition(M_I, Fwd_GETX, SINK_WB_ACK) {
852 dt_sendDataToRequestor_fromTBE;
853 l_popRequestQueue;
854 }
855
856 transition(M_I, {Fwd_GETS, Fwd_GET_INSTR}, SINK_WB_ACK) {
857 dt_sendDataToRequestor_fromTBE;
858 d2t_sendDataToL2_fromTBE;
859 l_popRequestQueue;
860 }
861
862 // Transitions from IS
863 transition({IS, IS_I}, Inv, IS_I) {
864 fi_sendInvAck;
865 l_popRequestQueue;
866 }
867
868 transition(IS, Data_all_Acks, S) {
869 u_writeDataToL1Cache;
870 h_load_hit;
871 s_deallocateTBE;
872 o_popIncomingResponseQueue;
873 kd_wakeUpDependents;
874 }
875
876 transition(IS_I, Data_all_Acks, I) {
877 u_writeDataToL1Cache;
878 h_load_hit;
879 s_deallocateTBE;
880 o_popIncomingResponseQueue;
881 kd_wakeUpDependents;
882 }
883
884 transition(IS, DataS_fromL1, S) {
885 u_writeDataToL1Cache;
886 j_sendUnblock;
887 h_load_hit;
888 s_deallocateTBE;
889 o_popIncomingResponseQueue;
890 kd_wakeUpDependents;
891 }
892
893 transition(IS_I, DataS_fromL1, I) {
894 u_writeDataToL1Cache;
895 j_sendUnblock;
896 h_load_hit;
897 s_deallocateTBE;
898 o_popIncomingResponseQueue;
899 kd_wakeUpDependents;
900 }
901
902 // directory is blocked when sending exclusive data
903 transition(IS_I, Data_Exclusive, E) {
904 u_writeDataToL1Cache;
905 h_load_hit;
906 jj_sendExclusiveUnblock;
907 s_deallocateTBE;
908 o_popIncomingResponseQueue;
909 kd_wakeUpDependents;
910 }
911
912 transition(IS, Data_Exclusive, E) {
913 u_writeDataToL1Cache;
914 h_load_hit;
915 jj_sendExclusiveUnblock;
916 s_deallocateTBE;
917 o_popIncomingResponseQueue;
918 kd_wakeUpDependents;
919 }
920
921 // Transitions from IM
922 transition({IM, SM}, Inv, IM) {
923 fi_sendInvAck;
924 l_popRequestQueue;
925 }
926
927 transition(IM, Data, SM) {
928 u_writeDataToL1Cache;
929 q_updateAckCount;
930 o_popIncomingResponseQueue;
931 }
932
933 transition(IM, Data_all_Acks, M) {
934 u_writeDataToL1Cache;
935 hh_store_hit;
936 jj_sendExclusiveUnblock;
937 s_deallocateTBE;
938 o_popIncomingResponseQueue;
939 kd_wakeUpDependents;
940 }
941
942 // transitions from SM
943 transition({SM, IM}, Ack) {
944 q_updateAckCount;
945 o_popIncomingResponseQueue;
946 }
947
948 transition(SM, Ack_all, M) {
949 jj_sendExclusiveUnblock;
950 hh_store_hit;
951 s_deallocateTBE;
952 o_popIncomingResponseQueue;
953 kd_wakeUpDependents;
954 }
955
956 transition(SINK_WB_ACK, Inv){
957 fi_sendInvAck;
958 l_popRequestQueue;
959 }
960
961 transition(SINK_WB_ACK, WB_Ack, I){
962 s_deallocateTBE;
963 o_popIncomingResponseQueue;
964 kd_wakeUpDependents;
965 }
966 }