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