ruby: Ruby changes required to use the python config system
[gem5.git] / src / mem / protocol / MOESI_hammer-cache.sm
1 /*
2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * Copyright (c) 2009 Advanced Micro Devices, Inc.
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 * AMD's contributions to the MOESI hammer protocol do not constitute an
30 * endorsement of its similarity to any AMD products.
31 *
32 * Authors: Milo Martin
33 * Brad Beckmann
34 */
35
36 machine(L1Cache, "AMD Hammer-like protocol")
37 : Sequencer * sequencer,
38 CacheMemory * L1IcacheMemory,
39 CacheMemory * L1DcacheMemory,
40 CacheMemory * L2cacheMemory,
41 int cache_response_latency = 12,
42 int issue_latency = 2
43 {
44
45 // NETWORK BUFFERS
46 MessageBuffer requestFromCache, network="To", virtual_network="3", ordered="false";
47 MessageBuffer responseFromCache, network="To", virtual_network="1", ordered="false";
48 MessageBuffer unblockFromCache, network="To", virtual_network="0", ordered="false";
49
50 MessageBuffer forwardToCache, network="From", virtual_network="2", ordered="false";
51 MessageBuffer responseToCache, network="From", virtual_network="1", ordered="false";
52
53
54 // STATES
55 enumeration(State, desc="Cache states", default="L1Cache_State_I") {
56 // Base states
57 I, desc="Idle";
58 S, desc="Shared";
59 O, desc="Owned";
60 M, desc="Modified (dirty)";
61 MM, desc="Modified (dirty and locally modified)";
62
63 // Transient States
64 IM, "IM", desc="Issued GetX";
65 SM, "SM", desc="Issued GetX, we still have an old copy of the line";
66 OM, "OM", desc="Issued GetX, received data";
67 ISM, "ISM", desc="Issued GetX, received data, waiting for all acks";
68 M_W, "M^W", desc="Issued GetS, received exclusive data";
69 MM_W, "MM^W", desc="Issued GetX, received exclusive data";
70 IS, "IS", desc="Issued GetS";
71 SS, "SS", desc="Issued GetS, received data, waiting for all acks";
72 OI, "OI", desc="Issued PutO, waiting for ack";
73 MI, "MI", desc="Issued PutX, waiting for ack";
74 II, "II", desc="Issued PutX/O, saw Other_GETS or Other_GETX, waiting for ack";
75 }
76
77 // EVENTS
78 enumeration(Event, desc="Cache events") {
79 Load, desc="Load request from the processor";
80 Ifetch, desc="I-fetch request from the processor";
81 Store, desc="Store request from the processor";
82 L2_Replacement, desc="L2 Replacement";
83 L1_to_L2, desc="L1 to L2 transfer";
84 L2_to_L1D, desc="L2 to L1-Data transfer";
85 L2_to_L1I, desc="L2 to L1-Instruction transfer";
86
87 // Requests
88 Other_GETX, desc="A GetX from another processor";
89 Other_GETS, desc="A GetS from another processor";
90
91 // Responses
92 Ack, desc="Received an ack message";
93 Shared_Ack, desc="Received an ack message, responder has a shared copy";
94 Data, desc="Received a data message";
95 Shared_Data, desc="Received a data message, responder has a shared copy";
96 Exclusive_Data, desc="Received a data message, responder had an exclusive copy, they gave it to us";
97
98 Writeback_Ack, desc="Writeback O.K. from directory";
99 Writeback_Nack, desc="Writeback not O.K. from directory";
100
101 // Triggers
102 All_acks, desc="Received all required data and message acks";
103 All_acks_no_sharers, desc="Received all acks and no other processor has a shared copy";
104 }
105
106 // TYPES
107
108 // STRUCTURE DEFINITIONS
109
110 MessageBuffer mandatoryQueue, ordered="false";
111
112 // CacheEntry
113 structure(Entry, desc="...", interface="AbstractCacheEntry") {
114 State CacheState, desc="cache state";
115 bool Dirty, desc="Is the data dirty (different than memory)?";
116 DataBlock DataBlk, desc="data for the block";
117 }
118
119 // TBE fields
120 structure(TBE, desc="...") {
121 State TBEState, desc="Transient state";
122 DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
123 bool Dirty, desc="Is the data dirty (different than memory)?";
124 int NumPendingMsgs, desc="Number of acks/data messages that this processor is waiting for";
125 bool Sharers, desc="On a GetS, did we find any other sharers in the system";
126 }
127
128 external_type(TBETable) {
129 TBE lookup(Address);
130 void allocate(Address);
131 void deallocate(Address);
132 bool isPresent(Address);
133 }
134
135 TBETable TBEs, template_hack="<L1Cache_TBE>";
136
137 Entry getCacheEntry(Address addr), return_by_ref="yes" {
138 if (L2cacheMemory.isTagPresent(addr)) {
139 return static_cast(Entry, L2cacheMemory[addr]);
140 } else if (L1DcacheMemory.isTagPresent(addr)) {
141 return static_cast(Entry, L1DcacheMemory[addr]);
142 } else {
143 return static_cast(Entry, L1IcacheMemory[addr]);
144 }
145 }
146
147 void changePermission(Address addr, AccessPermission permission) {
148 if (L2cacheMemory.isTagPresent(addr)) {
149 return L2cacheMemory.changePermission(addr, permission);
150 } else if (L1DcacheMemory.isTagPresent(addr)) {
151 return L1DcacheMemory.changePermission(addr, permission);
152 } else {
153 return L1IcacheMemory.changePermission(addr, permission);
154 }
155 }
156
157 bool isCacheTagPresent(Address addr) {
158 return (L2cacheMemory.isTagPresent(addr) || L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
159 }
160
161 State getState(Address addr) {
162 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
163 assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
164 assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
165
166 if(TBEs.isPresent(addr)) {
167 return TBEs[addr].TBEState;
168 } else if (isCacheTagPresent(addr)) {
169 return getCacheEntry(addr).CacheState;
170 }
171 return State:I;
172 }
173
174 void setState(Address addr, State state) {
175 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
176 assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
177 assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
178
179 if (TBEs.isPresent(addr)) {
180 TBEs[addr].TBEState := state;
181 }
182
183 if (isCacheTagPresent(addr)) {
184 getCacheEntry(addr).CacheState := state;
185
186 // Set permission
187 if ((state == State:MM) ||
188 (state == State:MM_W)) {
189 changePermission(addr, AccessPermission:Read_Write);
190 } else if (state == State:S ||
191 state == State:O ||
192 state == State:M ||
193 state == State:M_W ||
194 state == State:SM ||
195 state == State:ISM ||
196 state == State:OM ||
197 state == State:SS) {
198 changePermission(addr, AccessPermission:Read_Only);
199 } else {
200 changePermission(addr, AccessPermission:Invalid);
201 }
202 }
203 }
204
205 Event mandatory_request_type_to_event(CacheRequestType type) {
206 if (type == CacheRequestType:LD) {
207 return Event:Load;
208 } else if (type == CacheRequestType:IFETCH) {
209 return Event:Ifetch;
210 } else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
211 return Event:Store;
212 } else {
213 error("Invalid CacheRequestType");
214 }
215 }
216
217 MessageBuffer triggerQueue, ordered="true";
218
219 // ** OUT_PORTS **
220
221 out_port(requestNetwork_out, RequestMsg, requestFromCache);
222 out_port(responseNetwork_out, ResponseMsg, responseFromCache);
223 out_port(unblockNetwork_out, ResponseMsg, unblockFromCache);
224 out_port(triggerQueue_out, TriggerMsg, triggerQueue);
225
226 // ** IN_PORTS **
227
228 // Trigger Queue
229 in_port(triggerQueue_in, TriggerMsg, triggerQueue) {
230 if (triggerQueue_in.isReady()) {
231 peek(triggerQueue_in, TriggerMsg) {
232 if (in_msg.Type == TriggerType:ALL_ACKS) {
233 trigger(Event:All_acks, in_msg.Address);
234 } else if (in_msg.Type == TriggerType:ALL_ACKS_NO_SHARERS) {
235 trigger(Event:All_acks_no_sharers, in_msg.Address);
236 } else {
237 error("Unexpected message");
238 }
239 }
240 }
241 }
242
243 // Nothing from the request network
244
245 // Forward Network
246 in_port(forwardToCache_in, RequestMsg, forwardToCache) {
247 if (forwardToCache_in.isReady()) {
248 peek(forwardToCache_in, RequestMsg) {
249 if (in_msg.Type == CoherenceRequestType:GETX) {
250 trigger(Event:Other_GETX, in_msg.Address);
251 } else if (in_msg.Type == CoherenceRequestType:GETS) {
252 trigger(Event:Other_GETS, in_msg.Address);
253 } else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
254 trigger(Event:Writeback_Ack, in_msg.Address);
255 } else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
256 trigger(Event:Writeback_Nack, in_msg.Address);
257 } else {
258 error("Unexpected message");
259 }
260 }
261 }
262 }
263
264 // Response Network
265 in_port(responseToCache_in, ResponseMsg, responseToCache) {
266 if (responseToCache_in.isReady()) {
267 peek(responseToCache_in, ResponseMsg) {
268 if (in_msg.Type == CoherenceResponseType:ACK) {
269 trigger(Event:Ack, in_msg.Address);
270 } else if (in_msg.Type == CoherenceResponseType:ACK_SHARED) {
271 trigger(Event:Shared_Ack, in_msg.Address);
272 } else if (in_msg.Type == CoherenceResponseType:DATA) {
273 trigger(Event:Data, in_msg.Address);
274 } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
275 trigger(Event:Shared_Data, in_msg.Address);
276 } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
277 trigger(Event:Exclusive_Data, in_msg.Address);
278 } else {
279 error("Unexpected message");
280 }
281 }
282 }
283 }
284
285 // Nothing from the unblock network
286
287 // Mandatory Queue
288 in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
289 if (mandatoryQueue_in.isReady()) {
290 peek(mandatoryQueue_in, CacheMsg) {
291
292 // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
293
294 if (in_msg.Type == CacheRequestType:IFETCH) {
295 // ** INSTRUCTION ACCESS ***
296
297 // Check to see if it is in the OTHER L1
298 if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
299 // The block is in the wrong L1, try to write it to the L2
300 if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) {
301 trigger(Event:L1_to_L2, in_msg.LineAddress);
302 } else {
303 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.LineAddress));
304 }
305 }
306
307 if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
308 // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
309 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
310 } else {
311 if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) {
312 // L1 does't have the line, but we have space for it in the L1
313 if (L2cacheMemory.isTagPresent(in_msg.LineAddress)) {
314 // L2 has it (maybe not with the right permissions)
315 trigger(Event:L2_to_L1I, in_msg.LineAddress);
316 } else {
317 // We have room, the L2 doesn't have it, so the L1 fetches the line
318 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
319 }
320 } else {
321 // No room in the L1, so we need to make room
322 if (L2cacheMemory.cacheAvail(L1IcacheMemory.cacheProbe(in_msg.LineAddress))) {
323 // The L2 has room, so we move the line from the L1 to the L2
324 trigger(Event:L1_to_L2, L1IcacheMemory.cacheProbe(in_msg.LineAddress));
325 } else {
326 // The L2 does not have room, so we replace a line from the L2
327 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.LineAddress)));
328 }
329 }
330 }
331 } else {
332 // *** DATA ACCESS ***
333
334 // Check to see if it is in the OTHER L1
335 if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
336 // The block is in the wrong L1, try to write it to the L2
337 if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) {
338 trigger(Event:L1_to_L2, in_msg.LineAddress);
339 } else {
340 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.LineAddress));
341 }
342 }
343
344 if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
345 // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
346 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
347 } else {
348 if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) {
349 // L1 does't have the line, but we have space for it in the L1
350 if (L2cacheMemory.isTagPresent(in_msg.LineAddress)) {
351 // L2 has it (maybe not with the right permissions)
352 trigger(Event:L2_to_L1D, in_msg.LineAddress);
353 } else {
354 // We have room, the L2 doesn't have it, so the L1 fetches the line
355 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
356 }
357 } else {
358 // No room in the L1, so we need to make room
359 if (L2cacheMemory.cacheAvail(L1DcacheMemory.cacheProbe(in_msg.LineAddress))) {
360 // The L2 has room, so we move the line from the L1 to the L2
361 trigger(Event:L1_to_L2, L1DcacheMemory.cacheProbe(in_msg.LineAddress));
362 } else {
363 // The L2 does not have room, so we replace a line from the L2
364 trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.LineAddress)));
365 }
366 }
367 }
368 }
369 }
370 }
371 }
372
373 // ACTIONS
374
375 action(a_issueGETS, "a", desc="Issue GETS") {
376 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
377 out_msg.Address := address;
378 out_msg.Type := CoherenceRequestType:GETS;
379 out_msg.Requestor := machineID;
380 out_msg.Destination.add(map_Address_to_Directory(address));
381 out_msg.MessageSize := MessageSizeType:Request_Control;
382 TBEs[address].NumPendingMsgs := getNumberOfLastLevelCaches(); // One from each other cache (n-1) plus the memory (+1)
383 }
384 }
385
386 action(b_issueGETX, "b", desc="Issue GETX") {
387 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
388 out_msg.Address := address;
389 out_msg.Type := CoherenceRequestType:GETX;
390 out_msg.Requestor := machineID;
391 out_msg.Destination.add(map_Address_to_Directory(address));
392 out_msg.MessageSize := MessageSizeType:Request_Control;
393 TBEs[address].NumPendingMsgs := getNumberOfLastLevelCaches(); // One from each other cache (n-1) plus the memory (+1)
394 }
395 }
396
397 action(c_sendExclusiveData, "c", desc="Send exclusive data from cache to requestor") {
398 peek(forwardToCache_in, RequestMsg) {
399 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
400 out_msg.Address := address;
401 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
402 out_msg.Sender := machineID;
403 out_msg.Destination.add(in_msg.Requestor);
404 out_msg.DataBlk := getCacheEntry(address).DataBlk;
405 out_msg.Dirty := getCacheEntry(address).Dirty;
406 out_msg.Acks := 2;
407 out_msg.MessageSize := MessageSizeType:Response_Data;
408 }
409 }
410 }
411
412 action(d_issuePUT, "d", desc="Issue PUT") {
413 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
414 out_msg.Address := address;
415 out_msg.Type := CoherenceRequestType:PUT;
416 out_msg.Requestor := machineID;
417 out_msg.Destination.add(map_Address_to_Directory(address));
418 out_msg.MessageSize := MessageSizeType:Writeback_Control;
419 }
420 }
421
422 action(e_sendData, "e", desc="Send data from cache to requestor") {
423 peek(forwardToCache_in, RequestMsg) {
424 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
425 out_msg.Address := address;
426 out_msg.Type := CoherenceResponseType:DATA;
427 out_msg.Sender := machineID;
428 out_msg.Destination.add(in_msg.Requestor);
429 out_msg.DataBlk := getCacheEntry(address).DataBlk;
430 out_msg.Dirty := getCacheEntry(address).Dirty;
431 out_msg.Acks := 2;
432 out_msg.MessageSize := MessageSizeType:Response_Data;
433 }
434 }
435 }
436
437 action(ee_sendDataShared, "\e", desc="Send data from cache to requestor, keep a shared copy") {
438 peek(forwardToCache_in, RequestMsg) {
439 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
440 out_msg.Address := address;
441 out_msg.Type := CoherenceResponseType:DATA_SHARED;
442 out_msg.Sender := machineID;
443 out_msg.Destination.add(in_msg.Requestor);
444 out_msg.DataBlk := getCacheEntry(address).DataBlk;
445 out_msg.Dirty := getCacheEntry(address).Dirty;
446 out_msg.Acks := 2;
447 out_msg.MessageSize := MessageSizeType:Response_Data;
448 }
449 }
450 }
451
452 action(f_sendAck, "f", desc="Send ack from cache to requestor") {
453 peek(forwardToCache_in, RequestMsg) {
454 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
455 out_msg.Address := address;
456 out_msg.Type := CoherenceResponseType:ACK;
457 out_msg.Sender := machineID;
458 out_msg.Destination.add(in_msg.Requestor);
459 out_msg.Acks := 1;
460 out_msg.MessageSize := MessageSizeType:Response_Control;
461 }
462 }
463 }
464
465 action(ff_sendAckShared, "\f", desc="Send shared ack from cache to requestor") {
466 peek(forwardToCache_in, RequestMsg) {
467 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
468 out_msg.Address := address;
469 out_msg.Type := CoherenceResponseType:ACK_SHARED;
470 out_msg.Sender := machineID;
471 out_msg.Destination.add(in_msg.Requestor);
472 out_msg.Acks := 1;
473 out_msg.MessageSize := MessageSizeType:Response_Control;
474 }
475 }
476 }
477
478 action(g_sendUnblock, "g", desc="Send unblock to memory") {
479 enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) {
480 out_msg.Address := address;
481 out_msg.Type := CoherenceResponseType:UNBLOCK;
482 out_msg.Sender := machineID;
483 out_msg.Destination.add(map_Address_to_Directory(address));
484 out_msg.MessageSize := MessageSizeType:Unblock_Control;
485 }
486 }
487
488 action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
489 DEBUG_EXPR(getCacheEntry(address).DataBlk);
490 sequencer.readCallback(address, getCacheEntry(address).DataBlk);
491 }
492
493 action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
494 DEBUG_EXPR(getCacheEntry(address).DataBlk);
495 sequencer.writeCallback(address, getCacheEntry(address).DataBlk);
496 getCacheEntry(address).Dirty := true;
497 }
498
499 action(i_allocateTBE, "i", desc="Allocate TBE") {
500 check_allocate(TBEs);
501 TBEs.allocate(address);
502 TBEs[address].DataBlk := getCacheEntry(address).DataBlk; // Data only used for writebacks
503 TBEs[address].Dirty := getCacheEntry(address).Dirty;
504 TBEs[address].Sharers := false;
505 }
506
507 action(j_popTriggerQueue, "j", desc="Pop trigger queue.") {
508 triggerQueue_in.dequeue();
509 }
510
511 action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
512 mandatoryQueue_in.dequeue();
513 }
514
515 action(l_popForwardQueue, "l", desc="Pop forwareded request queue.") {
516 forwardToCache_in.dequeue();
517 }
518
519 action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") {
520 peek(responseToCache_in, ResponseMsg) {
521 assert(in_msg.Acks > 0);
522 DEBUG_EXPR(TBEs[address].NumPendingMsgs);
523 TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks;
524 DEBUG_EXPR(TBEs[address].NumPendingMsgs);
525 }
526 }
527
528 action(n_popResponseQueue, "n", desc="Pop response queue") {
529 responseToCache_in.dequeue();
530 }
531
532 action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
533 if (TBEs[address].NumPendingMsgs == 0) {
534 enqueue(triggerQueue_out, TriggerMsg) {
535 out_msg.Address := address;
536 if (TBEs[address].Sharers) {
537 out_msg.Type := TriggerType:ALL_ACKS;
538 } else {
539 out_msg.Type := TriggerType:ALL_ACKS_NO_SHARERS;
540 }
541 }
542 }
543 }
544
545 action(p_decrementNumberOfMessagesByOne, "p", desc="Decrement the number of messages for which we're waiting by one") {
546 TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - 1;
547 }
548
549 action(pp_incrementNumberOfMessagesByOne, "\p", desc="Increment the number of messages for which we're waiting by one") {
550 TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs + 1;
551 }
552
553 action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") {
554 peek(forwardToCache_in, RequestMsg) {
555 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
556 out_msg.Address := address;
557 out_msg.Type := CoherenceResponseType:DATA;
558 out_msg.Sender := machineID;
559 out_msg.Destination.add(in_msg.Requestor);
560 out_msg.DataBlk := TBEs[address].DataBlk;
561 out_msg.Dirty := TBEs[address].Dirty;
562 out_msg.Acks := 2;
563 out_msg.MessageSize := MessageSizeType:Response_Data;
564 }
565 }
566 }
567
568 action(qq_sendDataFromTBEToMemory, "\q", desc="Send data from TBE to memory") {
569 enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) {
570 out_msg.Address := address;
571 out_msg.Sender := machineID;
572 out_msg.Destination.add(map_Address_to_Directory(address));
573 out_msg.Dirty := TBEs[address].Dirty;
574 if (TBEs[address].Dirty) {
575 out_msg.Type := CoherenceResponseType:WB_DIRTY;
576 out_msg.DataBlk := TBEs[address].DataBlk;
577 out_msg.MessageSize := MessageSizeType:Writeback_Data;
578 } else {
579 out_msg.Type := CoherenceResponseType:WB_CLEAN;
580 // NOTE: in a real system this would not send data. We send
581 // data here only so we can check it at the memory
582 out_msg.DataBlk := TBEs[address].DataBlk;
583 out_msg.MessageSize := MessageSizeType:Writeback_Control;
584 }
585 }
586 }
587
588 action(r_setSharerBit, "r", desc="We saw other sharers") {
589 TBEs[address].Sharers := true;
590 }
591
592 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
593 TBEs.deallocate(address);
594 }
595
596 action(t_sendExclusiveDataFromTBEToMemory, "t", desc="Send exclusive data from TBE to memory") {
597 enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) {
598 out_msg.Address := address;
599 out_msg.Sender := machineID;
600 out_msg.Destination.add(map_Address_to_Directory(address));
601 out_msg.DataBlk := TBEs[address].DataBlk;
602 out_msg.Dirty := TBEs[address].Dirty;
603 if (TBEs[address].Dirty) {
604 out_msg.Type := CoherenceResponseType:WB_EXCLUSIVE_DIRTY;
605 out_msg.DataBlk := TBEs[address].DataBlk;
606 out_msg.MessageSize := MessageSizeType:Writeback_Data;
607 } else {
608 out_msg.Type := CoherenceResponseType:WB_EXCLUSIVE_CLEAN;
609 // NOTE: in a real system this would not send data. We send
610 // data here only so we can check it at the memory
611 out_msg.DataBlk := TBEs[address].DataBlk;
612 out_msg.MessageSize := MessageSizeType:Writeback_Control;
613 }
614 }
615 }
616
617 action(u_writeDataToCache, "u", desc="Write data to cache") {
618 peek(responseToCache_in, ResponseMsg) {
619 getCacheEntry(address).DataBlk := in_msg.DataBlk;
620 getCacheEntry(address).Dirty := in_msg.Dirty;
621 }
622 }
623
624 action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") {
625 peek(responseToCache_in, ResponseMsg) {
626 assert(getCacheEntry(address).DataBlk == in_msg.DataBlk);
627 getCacheEntry(address).DataBlk := in_msg.DataBlk;
628 getCacheEntry(address).Dirty := in_msg.Dirty;
629 }
630 }
631
632 action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
633 if (L1DcacheMemory.isTagPresent(address)) {
634 L1DcacheMemory.deallocate(address);
635 } else {
636 L1IcacheMemory.deallocate(address);
637 }
638 }
639
640 action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
641 if (L1DcacheMemory.isTagPresent(address) == false) {
642 L1DcacheMemory.allocate(address, new Entry);
643 }
644 }
645
646 action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") {
647 if (L1IcacheMemory.isTagPresent(address) == false) {
648 L1IcacheMemory.allocate(address, new Entry);
649 }
650 }
651
652 action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
653 L2cacheMemory.allocate(address, new Entry);
654 }
655
656 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
657 L2cacheMemory.deallocate(address);
658 }
659
660 action(ss_copyFromL1toL2, "\s", desc="Copy data block from L1 (I or D) to L2") {
661 if (L1DcacheMemory.isTagPresent(address)) {
662 static_cast(Entry, L2cacheMemory[address]).Dirty := static_cast(Entry, L1DcacheMemory[address]).Dirty;
663 static_cast(Entry, L2cacheMemory[address]).DataBlk := static_cast(Entry, L1DcacheMemory[address]).DataBlk;
664 } else {
665 static_cast(Entry, L2cacheMemory[address]).Dirty := static_cast(Entry, L1IcacheMemory[address]).Dirty;
666 static_cast(Entry, L2cacheMemory[address]).DataBlk := static_cast(Entry, L1IcacheMemory[address]).DataBlk;
667 }
668 }
669
670 action(tt_copyFromL2toL1, "\t", desc="Copy data block from L2 to L1 (I or D)") {
671 if (L1DcacheMemory.isTagPresent(address)) {
672 static_cast(Entry, L1DcacheMemory[address]).Dirty := static_cast(Entry, L2cacheMemory[address]).Dirty;
673 static_cast(Entry, L1DcacheMemory[address]).DataBlk := static_cast(Entry, L2cacheMemory[address]).DataBlk;
674 } else {
675 static_cast(Entry, L1IcacheMemory[address]).Dirty := static_cast(Entry, L2cacheMemory[address]).Dirty;
676 static_cast(Entry, L1IcacheMemory[address]).DataBlk := static_cast(Entry, L2cacheMemory[address]).DataBlk;
677 }
678 }
679
680 action(uu_profileMiss, "\u", desc="Profile the demand miss") {
681 peek(mandatoryQueue_in, CacheMsg) {
682 if (L1IcacheMemory.isTagPresent(address)) {
683 L1IcacheMemory.profileMiss(in_msg);
684 } else if (L1DcacheMemory.isTagPresent(address)) {
685 L1DcacheMemory.profileMiss(in_msg);
686 } else {
687 L2cacheMemory.profileMiss(in_msg);
688 }
689 }
690 }
691
692 action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
693 mandatoryQueue_in.recycle();
694 }
695
696 //*****************************************************
697 // TRANSITIONS
698 //*****************************************************
699
700 // Transitions for Load/Store/L2_Replacement from transient states
701 transition({IM, SM, ISM, OM, IS, SS, OI, MI, II}, {Store, L2_Replacement}) {
702 zz_recycleMandatoryQueue;
703 }
704
705 transition({M_W, MM_W}, {L2_Replacement}) {
706 zz_recycleMandatoryQueue;
707 }
708
709 transition({IM, IS, OI, MI, II}, {Load, Ifetch}) {
710 zz_recycleMandatoryQueue;
711 }
712
713 transition({IM, SM, ISM, OM, IS, SS, MM_W, M_W, OI, MI, II}, L1_to_L2) {
714 zz_recycleMandatoryQueue;
715 }
716
717 // Transitions moving data between the L1 and L2 caches
718 transition({I, S, O, M, MM}, L1_to_L2) {
719 vv_allocateL2CacheBlock;
720 ss_copyFromL1toL2; // Not really needed for state I
721 gg_deallocateL1CacheBlock;
722 }
723
724 transition({I, S, O, M, MM}, L2_to_L1D) {
725 ii_allocateL1DCacheBlock;
726 tt_copyFromL2toL1; // Not really needed for state I
727 rr_deallocateL2CacheBlock;
728 }
729
730 transition({I, S, O, M, MM}, L2_to_L1I) {
731 jj_allocateL1ICacheBlock;
732 tt_copyFromL2toL1; // Not really needed for state I
733 rr_deallocateL2CacheBlock;
734 }
735
736 // Transitions from Idle
737 transition(I, Load, IS) {
738 ii_allocateL1DCacheBlock;
739 i_allocateTBE;
740 a_issueGETS;
741 uu_profileMiss;
742 k_popMandatoryQueue;
743 }
744
745 transition(I, Ifetch, IS) {
746 jj_allocateL1ICacheBlock;
747 i_allocateTBE;
748 a_issueGETS;
749 uu_profileMiss;
750 k_popMandatoryQueue;
751 }
752
753 transition(I, Store, IM) {
754 ii_allocateL1DCacheBlock;
755 i_allocateTBE;
756 b_issueGETX;
757 uu_profileMiss;
758 k_popMandatoryQueue;
759 }
760
761 transition(I, L2_Replacement) {
762 rr_deallocateL2CacheBlock;
763 }
764
765 transition(I, {Other_GETX, Other_GETS}) {
766 f_sendAck;
767 l_popForwardQueue;
768 }
769
770 // Transitions from Shared
771 transition({S, SM, ISM}, {Load, Ifetch}) {
772 h_load_hit;
773 k_popMandatoryQueue;
774 }
775
776 transition(S, Store, SM) {
777 i_allocateTBE;
778 b_issueGETX;
779 uu_profileMiss;
780 k_popMandatoryQueue;
781 }
782
783 transition(S, L2_Replacement, I) {
784 rr_deallocateL2CacheBlock;
785 }
786
787 transition(S, Other_GETX, I) {
788 f_sendAck;
789 l_popForwardQueue;
790 }
791
792 transition(S, Other_GETS) {
793 ff_sendAckShared;
794 l_popForwardQueue;
795 }
796
797 // Transitions from Owned
798 transition({O, OM, SS, MM_W, M_W}, {Load, Ifetch}) {
799 h_load_hit;
800 k_popMandatoryQueue;
801 }
802
803 transition(O, Store, OM) {
804 i_allocateTBE;
805 b_issueGETX;
806 p_decrementNumberOfMessagesByOne;
807 uu_profileMiss;
808 k_popMandatoryQueue;
809 }
810
811 transition(O, L2_Replacement, OI) {
812 i_allocateTBE;
813 d_issuePUT;
814 rr_deallocateL2CacheBlock;
815 }
816
817 transition(O, Other_GETX, I) {
818 e_sendData;
819 l_popForwardQueue;
820 }
821
822 transition(O, Other_GETS) {
823 ee_sendDataShared;
824 l_popForwardQueue;
825 }
826
827 // Transitions from Modified
828 transition(MM, {Load, Ifetch}) {
829 h_load_hit;
830 k_popMandatoryQueue;
831 }
832
833 transition(MM, Store) {
834 hh_store_hit;
835 k_popMandatoryQueue;
836 }
837
838 transition(MM, L2_Replacement, MI) {
839 i_allocateTBE;
840 d_issuePUT;
841 rr_deallocateL2CacheBlock;
842 }
843
844 transition(MM, Other_GETX, I) {
845 c_sendExclusiveData;
846 l_popForwardQueue;
847 }
848
849 transition(MM, Other_GETS, I) {
850 c_sendExclusiveData;
851 l_popForwardQueue;
852 }
853
854 // Transitions from Dirty Exclusive
855 transition(M, {Load, Ifetch}) {
856 h_load_hit;
857 k_popMandatoryQueue;
858 }
859
860 transition(M, Store, MM) {
861 hh_store_hit;
862 k_popMandatoryQueue;
863 }
864
865 transition(M, L2_Replacement, MI) {
866 i_allocateTBE;
867 d_issuePUT;
868 rr_deallocateL2CacheBlock;
869 }
870
871 transition(M, Other_GETX, I) {
872 c_sendExclusiveData;
873 l_popForwardQueue;
874 }
875
876 transition(M, Other_GETS, O) {
877 ee_sendDataShared;
878 l_popForwardQueue;
879 }
880
881 // Transitions from IM
882
883 transition(IM, {Other_GETX, Other_GETS}) {
884 f_sendAck;
885 l_popForwardQueue;
886 }
887
888 transition(IM, Ack) {
889 m_decrementNumberOfMessages;
890 o_checkForCompletion;
891 n_popResponseQueue;
892 }
893
894 transition(IM, Data, ISM) {
895 u_writeDataToCache;
896 m_decrementNumberOfMessages;
897 o_checkForCompletion;
898 n_popResponseQueue;
899 }
900
901 transition(IM, Exclusive_Data, MM_W) {
902 u_writeDataToCache;
903 m_decrementNumberOfMessages;
904 o_checkForCompletion;
905 hh_store_hit;
906 n_popResponseQueue;
907 }
908
909 // Transitions from SM
910 transition(SM, Other_GETS) {
911 ff_sendAckShared;
912 l_popForwardQueue;
913 }
914
915 transition(SM, Other_GETX, IM) {
916 f_sendAck;
917 l_popForwardQueue;
918 }
919
920 transition(SM, Ack) {
921 m_decrementNumberOfMessages;
922 o_checkForCompletion;
923 n_popResponseQueue;
924 }
925
926 transition(SM, Data, ISM) {
927 v_writeDataToCacheVerify;
928 m_decrementNumberOfMessages;
929 o_checkForCompletion;
930 n_popResponseQueue;
931 }
932
933 // Transitions from ISM
934 transition(ISM, Ack) {
935 m_decrementNumberOfMessages;
936 o_checkForCompletion;
937 n_popResponseQueue;
938 }
939
940 transition(ISM, All_acks_no_sharers, MM) {
941 hh_store_hit;
942 g_sendUnblock;
943 s_deallocateTBE;
944 j_popTriggerQueue;
945 }
946
947 // Transitions from OM
948
949 transition(OM, Other_GETX, IM) {
950 e_sendData;
951 pp_incrementNumberOfMessagesByOne;
952 l_popForwardQueue;
953 }
954
955 transition(OM, Other_GETS) {
956 ee_sendDataShared;
957 l_popForwardQueue;
958 }
959
960 transition(OM, Ack) {
961 m_decrementNumberOfMessages;
962 o_checkForCompletion;
963 n_popResponseQueue;
964 }
965
966 transition(OM, {All_acks, All_acks_no_sharers}, MM) {
967 hh_store_hit;
968 g_sendUnblock;
969 s_deallocateTBE;
970 j_popTriggerQueue;
971 }
972
973 // Transitions from IS
974
975 transition(IS, {Other_GETX, Other_GETS}) {
976 f_sendAck;
977 l_popForwardQueue;
978 }
979
980 transition(IS, Ack) {
981 m_decrementNumberOfMessages;
982 o_checkForCompletion;
983 n_popResponseQueue;
984 }
985
986 transition(IS, Shared_Ack) {
987 m_decrementNumberOfMessages;
988 r_setSharerBit;
989 o_checkForCompletion;
990 n_popResponseQueue;
991 }
992
993 transition(IS, Data, SS) {
994 u_writeDataToCache;
995 m_decrementNumberOfMessages;
996 o_checkForCompletion;
997 h_load_hit;
998 n_popResponseQueue;
999 }
1000
1001 transition(IS, Exclusive_Data, M_W) {
1002 u_writeDataToCache;
1003 m_decrementNumberOfMessages;
1004 o_checkForCompletion;
1005 h_load_hit;
1006 n_popResponseQueue;
1007 }
1008
1009 transition(IS, Shared_Data, SS) {
1010 u_writeDataToCache;
1011 r_setSharerBit;
1012 m_decrementNumberOfMessages;
1013 o_checkForCompletion;
1014 h_load_hit;
1015 n_popResponseQueue;
1016 }
1017
1018 // Transitions from SS
1019
1020 transition(SS, Ack) {
1021 m_decrementNumberOfMessages;
1022 o_checkForCompletion;
1023 n_popResponseQueue;
1024 }
1025
1026 transition(SS, Shared_Ack) {
1027 m_decrementNumberOfMessages;
1028 r_setSharerBit;
1029 o_checkForCompletion;
1030 n_popResponseQueue;
1031 }
1032
1033 transition(SS, All_acks, S) {
1034 g_sendUnblock;
1035 s_deallocateTBE;
1036 j_popTriggerQueue;
1037 }
1038
1039 transition(SS, All_acks_no_sharers, S) {
1040 // Note: The directory might still be the owner, so that is why we go to S
1041 g_sendUnblock;
1042 s_deallocateTBE;
1043 j_popTriggerQueue;
1044 }
1045
1046 // Transitions from MM_W
1047
1048 transition(MM_W, Store) {
1049 hh_store_hit;
1050 k_popMandatoryQueue;
1051 }
1052
1053 transition(MM_W, Ack) {
1054 m_decrementNumberOfMessages;
1055 o_checkForCompletion;
1056 n_popResponseQueue;
1057 }
1058
1059 transition(MM_W, All_acks_no_sharers, MM) {
1060 g_sendUnblock;
1061 s_deallocateTBE;
1062 j_popTriggerQueue;
1063 }
1064
1065 // Transitions from M_W
1066
1067 transition(M_W, Store, MM_W) {
1068 hh_store_hit;
1069 k_popMandatoryQueue;
1070 }
1071
1072 transition(M_W, Ack) {
1073 m_decrementNumberOfMessages;
1074 o_checkForCompletion;
1075 n_popResponseQueue;
1076 }
1077
1078 transition(M_W, All_acks_no_sharers, M) {
1079 g_sendUnblock;
1080 s_deallocateTBE;
1081 j_popTriggerQueue;
1082 }
1083
1084 // Transitions from OI/MI
1085
1086 transition({OI, MI}, Other_GETX, II) {
1087 q_sendDataFromTBEToCache;
1088 l_popForwardQueue;
1089 }
1090
1091 transition({OI, MI}, Other_GETS, OI) {
1092 q_sendDataFromTBEToCache;
1093 l_popForwardQueue;
1094 }
1095
1096 transition(MI, Writeback_Ack, I) {
1097 t_sendExclusiveDataFromTBEToMemory;
1098 s_deallocateTBE;
1099 l_popForwardQueue;
1100 }
1101
1102 transition(OI, Writeback_Ack, I) {
1103 qq_sendDataFromTBEToMemory;
1104 s_deallocateTBE;
1105 l_popForwardQueue;
1106 }
1107
1108 // Transitions from II
1109 transition(II, {Other_GETS, Other_GETX}, II) {
1110 f_sendAck;
1111 l_popForwardQueue;
1112 }
1113
1114 transition(II, Writeback_Ack, I) {
1115 g_sendUnblock;
1116 s_deallocateTBE;
1117 l_popForwardQueue;
1118 }
1119
1120 transition(II, Writeback_Nack, I) {
1121 s_deallocateTBE;
1122 l_popForwardQueue;
1123 }
1124 }
1125