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