3 * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
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.
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.
35 machine(L1Cache, "Directory protocol")
36 : Sequencer * sequencer,
37 CacheMemory * L1IcacheMemory,
38 CacheMemory * L1DcacheMemory,
39 int l2_select_num_bits,
40 int request_latency = 2,
45 // From this node's L1 cache TO the network
46 // a local L1 -> this L2 bank, currently ordered with directory forwarded requests
47 MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="false", vnet_type="request";
48 // a local L1 -> this L2 bank
49 MessageBuffer responseFromL1Cache, network="To", virtual_network="2", ordered="false", vnet_type="response";
50 // MessageBuffer writebackFromL1Cache, network="To", virtual_network="3", ordered="false", vnet_type="writeback";
53 // To this node's L1 cache FROM the network
54 // a L2 bank -> this L1
55 MessageBuffer requestToL1Cache, network="From", virtual_network="0", ordered="false", vnet_type="request";
56 // a L2 bank -> this L1
57 MessageBuffer responseToL1Cache, network="From", virtual_network="2", ordered="false", vnet_type="response";
62 state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
64 I, AccessPermission:Invalid, desc="Idle";
65 S, AccessPermission:Read_Only, desc="Shared";
66 O, AccessPermission:Read_Only, desc="Owned";
67 M, AccessPermission:Read_Only, desc="Modified (dirty)";
68 M_W, AccessPermission:Read_Only, desc="Modified (dirty)";
69 MM, AccessPermission:Read_Write, desc="Modified (dirty and locally modified)";
70 MM_W, AccessPermission:Read_Write, desc="Modified (dirty and locally modified)";
73 IM, AccessPermission:Busy, "IM", desc="Issued GetX";
74 SM, AccessPermission:Read_Only, "SM", desc="Issued GetX, we still have an old copy of the line";
75 OM, AccessPermission:Read_Only, "SM", desc="Issued GetX, received data";
76 IS, AccessPermission:Busy, "IS", desc="Issued GetS";
77 SI, AccessPermission:Busy, "OI", desc="Issued PutS, waiting for ack";
78 OI, AccessPermission:Busy, "OI", desc="Issued PutO, waiting for ack";
79 MI, AccessPermission:Busy, "MI", desc="Issued PutX, waiting for ack";
80 II, AccessPermission:Busy, "II", desc="Issued PutX/O, saw Fwd_GETS or Fwd_GETX, waiting for ack";
84 enumeration(Event, desc="Cache events") {
85 Load, desc="Load request from the processor";
86 Ifetch, desc="I-fetch request from the processor";
87 Store, desc="Store request from the processor";
88 L1_Replacement, desc="Replacement";
91 Own_GETX, desc="We observe our own GetX forwarded back to us";
92 Fwd_GETX, desc="A GetX from another processor";
93 Fwd_GETS, desc="A GetS from another processor";
94 Fwd_DMA, desc="A GetS from another processor";
95 Inv, desc="Invalidations from the directory";
98 Ack, desc="Received an ack message";
99 Data, desc="Received a data message, responder has a shared copy";
100 Exclusive_Data, desc="Received a data message";
102 Writeback_Ack, desc="Writeback O.K. from directory";
103 Writeback_Ack_Data, desc="Writeback O.K. from directory";
104 Writeback_Nack, desc="Writeback not O.K. from directory";
107 All_acks, desc="Received all required data and message acks";
110 Use_Timeout, desc="lockout period ended";
116 structure(Entry, desc="...", interface="AbstractCacheEntry") {
117 State CacheState, desc="cache state";
118 bool Dirty, desc="Is the data dirty (different than memory)?";
119 DataBlock DataBlk, desc="data for the block";
123 structure(TBE, desc="...") {
124 Address Address, desc="Physical address for this TBE";
125 State TBEState, desc="Transient state";
126 DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
127 bool Dirty, desc="Is the data dirty (different than memory)?";
128 int NumPendingMsgs, default="0", desc="Number of acks/data messages that this processor is waiting for";
131 structure(TBETable, external ="yes") {
133 void allocate(Address);
134 void deallocate(Address);
135 bool isPresent(Address);
138 void set_cache_entry(AbstractCacheEntry b);
139 void unset_cache_entry();
143 MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
145 TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
146 TimerTable useTimerTable;
147 int l2_select_low_bit, default="RubySystem::getBlockSizeBits()";
149 Entry getCacheEntry(Address addr), return_by_pointer="yes" {
150 Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr));
151 if(is_valid(L1Dcache_entry)) {
152 return L1Dcache_entry;
155 Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory.lookup(addr));
156 return L1Icache_entry;
159 Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" {
160 return static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr));
163 Entry getL1ICacheEntry(Address addr), return_by_pointer="yes" {
164 return static_cast(Entry, "pointer", L1IcacheMemory.lookup(addr));
167 State getState(TBE tbe, Entry cache_entry, Address addr) {
170 } else if (is_valid(cache_entry)) {
171 return cache_entry.CacheState;
176 void setState(TBE tbe, Entry cache_entry, Address addr, State state) {
177 assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
180 tbe.TBEState := state;
183 if (is_valid(cache_entry)) {
184 if ( ((cache_entry.CacheState != State:M) && (state == State:M)) ||
185 ((cache_entry.CacheState != State:MM) && (state == State:MM)) ||
186 ((cache_entry.CacheState != State:S) && (state == State:S)) ||
187 ((cache_entry.CacheState != State:O) && (state == State:O)) ) {
189 cache_entry.CacheState := state;
190 sequencer.checkCoherence(addr);
193 cache_entry.CacheState := state;
198 AccessPermission getAccessPermission(Address addr) {
199 TBE tbe := TBEs[addr];
201 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
202 return L1Cache_State_to_permission(tbe.TBEState);
205 Entry cache_entry := getCacheEntry(addr);
206 if(is_valid(cache_entry)) {
207 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
208 return L1Cache_State_to_permission(cache_entry.CacheState);
211 DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
212 return AccessPermission:NotPresent;
215 void setAccessPermission(Entry cache_entry, Address addr, State state) {
216 if (is_valid(cache_entry)) {
217 cache_entry.changePermission(L1Cache_State_to_permission(state));
221 DataBlock getDataBlock(Address addr), return_by_ref="yes" {
222 Entry cache_entry := getCacheEntry(addr);
223 if(is_valid(cache_entry)) {
224 return cache_entry.DataBlk;
227 TBE tbe := TBEs[addr];
232 error("Data block missing!");
235 Event mandatory_request_type_to_event(RubyRequestType type) {
236 if (type == RubyRequestType:LD) {
238 } else if (type == RubyRequestType:IFETCH) {
240 } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
243 error("Invalid RubyRequestType");
247 MessageBuffer triggerQueue, ordered="true";
251 out_port(requestNetwork_out, RequestMsg, requestFromL1Cache);
252 out_port(responseNetwork_out, ResponseMsg, responseFromL1Cache);
253 out_port(triggerQueue_out, TriggerMsg, triggerQueue);
258 in_port(useTimerTable_in, Address, useTimerTable) {
259 if (useTimerTable_in.isReady()) {
260 trigger(Event:Use_Timeout, useTimerTable.readyAddress(),
261 getCacheEntry(useTimerTable.readyAddress()),
262 TBEs[useTimerTable.readyAddress()]);
267 in_port(triggerQueue_in, TriggerMsg, triggerQueue) {
268 if (triggerQueue_in.isReady()) {
269 peek(triggerQueue_in, TriggerMsg) {
270 if (in_msg.Type == TriggerType:ALL_ACKS) {
271 trigger(Event:All_acks, in_msg.Address,
272 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
274 error("Unexpected message");
280 // Nothing from the request network
283 in_port(requestNetwork_in, RequestMsg, requestToL1Cache) {
284 if (requestNetwork_in.isReady()) {
285 peek(requestNetwork_in, RequestMsg, block_on="Address") {
286 assert(in_msg.Destination.isElement(machineID));
287 DPRINTF(RubySlicc, "L1 received: %s\n", in_msg.Type);
289 if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:DMA_WRITE) {
290 if (in_msg.Requestor == machineID && in_msg.RequestorMachine == MachineType:L1Cache) {
291 trigger(Event:Own_GETX, in_msg.Address,
292 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
294 trigger(Event:Fwd_GETX, in_msg.Address,
295 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
297 } else if (in_msg.Type == CoherenceRequestType:GETS) {
298 trigger(Event:Fwd_GETS, in_msg.Address,
299 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
300 } else if (in_msg.Type == CoherenceRequestType:DMA_READ) {
301 trigger(Event:Fwd_DMA, in_msg.Address,
302 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
303 } else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
304 trigger(Event:Writeback_Ack, in_msg.Address,
305 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
306 } else if (in_msg.Type == CoherenceRequestType:WB_ACK_DATA) {
307 trigger(Event:Writeback_Ack_Data, in_msg.Address,
308 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
309 } else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
310 trigger(Event:Writeback_Nack, in_msg.Address,
311 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
312 } else if (in_msg.Type == CoherenceRequestType:INV) {
313 trigger(Event:Inv, in_msg.Address,
314 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
316 error("Unexpected message");
323 in_port(responseToL1Cache_in, ResponseMsg, responseToL1Cache) {
324 if (responseToL1Cache_in.isReady()) {
325 peek(responseToL1Cache_in, ResponseMsg, block_on="Address") {
326 if (in_msg.Type == CoherenceResponseType:ACK) {
327 trigger(Event:Ack, in_msg.Address,
328 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
329 } else if (in_msg.Type == CoherenceResponseType:DATA) {
330 trigger(Event:Data, in_msg.Address,
331 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
332 } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
333 trigger(Event:Exclusive_Data, in_msg.Address,
334 getCacheEntry(in_msg.Address), TBEs[in_msg.Address]);
336 error("Unexpected message");
342 // Nothing from the unblock network
343 // Mandatory Queue betweens Node's CPU and it's L1 caches
344 in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...") {
345 if (mandatoryQueue_in.isReady()) {
346 peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
348 // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
350 if (in_msg.Type == RubyRequestType:IFETCH) {
351 // ** INSTRUCTION ACCESS ***
353 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
354 if (is_valid(L1Icache_entry)) {
355 // The tag matches for the L1, so the L1 asks the L2 for it.
356 trigger(mandatory_request_type_to_event(in_msg.Type),
357 in_msg.LineAddress, L1Icache_entry,
358 TBEs[in_msg.LineAddress]);
361 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
362 // Check to see if it is in the OTHER L1
363 if (is_valid(L1Dcache_entry)) {
364 // The block is in the wrong L1, put the request on the queue to the shared L2
365 trigger(Event:L1_Replacement, in_msg.LineAddress, L1Dcache_entry,
366 TBEs[in_msg.LineAddress]);
368 if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) {
369 // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
370 trigger(mandatory_request_type_to_event(in_msg.Type),
371 in_msg.LineAddress, L1Icache_entry,
372 TBEs[in_msg.LineAddress]);
374 // No room in the L1, so we need to make room in the L1
375 trigger(Event:L1_Replacement,
376 L1IcacheMemory.cacheProbe(in_msg.LineAddress),
377 getL1ICacheEntry(L1IcacheMemory.cacheProbe(in_msg.LineAddress)),
378 TBEs[L1IcacheMemory.cacheProbe(in_msg.LineAddress)]);
382 // *** DATA ACCESS ***
384 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
385 if (is_valid(L1Dcache_entry)) {
386 // The tag matches for the L1, so the L1 ask the L2 for it
387 trigger(mandatory_request_type_to_event(in_msg.Type),
388 in_msg.LineAddress, L1Dcache_entry,
389 TBEs[in_msg.LineAddress]);
392 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
393 // Check to see if it is in the OTHER L1
394 if (is_valid(L1Icache_entry)) {
395 // The block is in the wrong L1, put the request on the queue to the shared L2
396 trigger(Event:L1_Replacement, in_msg.LineAddress,
397 L1Icache_entry, TBEs[in_msg.LineAddress]);
399 if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) {
400 // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
401 trigger(mandatory_request_type_to_event(in_msg.Type),
402 in_msg.LineAddress, L1Dcache_entry,
403 TBEs[in_msg.LineAddress]);
405 // No room in the L1, so we need to make room in the L1
406 trigger(Event:L1_Replacement,
407 L1DcacheMemory.cacheProbe(in_msg.LineAddress),
408 getL1DCacheEntry(L1DcacheMemory.cacheProbe(in_msg.LineAddress)),
409 TBEs[L1DcacheMemory.cacheProbe(in_msg.LineAddress)]);
420 action(a_issueGETS, "a", desc="Issue GETS") {
421 peek(mandatoryQueue_in, RubyRequest) {
422 enqueue(requestNetwork_out, RequestMsg, latency= request_latency) {
423 out_msg.Address := address;
424 out_msg.Type := CoherenceRequestType:GETS;
425 out_msg.Requestor := machineID;
426 out_msg.RequestorMachine := MachineType:L1Cache;
427 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
428 l2_select_low_bit, l2_select_num_bits));
429 out_msg.MessageSize := MessageSizeType:Request_Control;
430 out_msg.AccessMode := in_msg.AccessMode;
431 out_msg.Prefetch := in_msg.Prefetch;
436 action(b_issueGETX, "b", desc="Issue GETX") {
437 peek(mandatoryQueue_in, RubyRequest) {
438 enqueue(requestNetwork_out, RequestMsg, latency=request_latency) {
439 out_msg.Address := address;
440 out_msg.Type := CoherenceRequestType:GETX;
441 out_msg.Requestor := machineID;
442 out_msg.RequestorMachine := MachineType:L1Cache;
443 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
444 l2_select_low_bit, l2_select_num_bits));
445 out_msg.MessageSize := MessageSizeType:Request_Control;
446 out_msg.AccessMode := in_msg.AccessMode;
447 out_msg.Prefetch := in_msg.Prefetch;
452 action(d_issuePUTX, "d", desc="Issue PUTX") {
453 // enqueue(writebackNetwork_out, RequestMsg, latency=request_latency) {
454 enqueue(requestNetwork_out, RequestMsg, latency=request_latency) {
455 out_msg.Address := address;
456 out_msg.Type := CoherenceRequestType:PUTX;
457 out_msg.Requestor := machineID;
458 out_msg.RequestorMachine := MachineType:L1Cache;
459 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
460 l2_select_low_bit, l2_select_num_bits));
461 out_msg.MessageSize := MessageSizeType:Writeback_Control;
465 action(dd_issuePUTO, "\d", desc="Issue PUTO") {
466 // enqueue(writebackNetwork_out, RequestMsg, latency=request_latency) {
467 enqueue(requestNetwork_out, RequestMsg, latency=request_latency) {
468 out_msg.Address := address;
469 out_msg.Type := CoherenceRequestType:PUTO;
470 out_msg.Requestor := machineID;
471 out_msg.RequestorMachine := MachineType:L1Cache;
472 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
473 l2_select_low_bit, l2_select_num_bits));
474 out_msg.MessageSize := MessageSizeType:Writeback_Control;
478 action(dd_issuePUTS, "\ds", desc="Issue PUTS") {
479 // enqueue(writebackNetwork_out, RequestMsg, latency=request_latency) {
480 enqueue(requestNetwork_out, RequestMsg, latency=request_latency) {
481 out_msg.Address := address;
482 out_msg.Type := CoherenceRequestType:PUTS;
483 out_msg.Requestor := machineID;
484 out_msg.RequestorMachine := MachineType:L1Cache;
485 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
486 l2_select_low_bit, l2_select_num_bits));
487 out_msg.MessageSize := MessageSizeType:Writeback_Control;
491 action(e_sendData, "e", desc="Send data from cache to requestor") {
492 peek(requestNetwork_in, RequestMsg) {
493 assert(is_valid(cache_entry));
494 if (in_msg.RequestorMachine == MachineType:L2Cache) {
495 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
496 out_msg.Address := address;
497 out_msg.Type := CoherenceResponseType:DATA;
498 out_msg.Sender := machineID;
499 out_msg.SenderMachine := MachineType:L1Cache;
500 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
501 l2_select_low_bit, l2_select_num_bits));
502 out_msg.DataBlk := cache_entry.DataBlk;
503 // out_msg.Dirty := cache_entry.Dirty;
504 out_msg.Dirty := false;
505 out_msg.Acks := in_msg.Acks;
506 out_msg.MessageSize := MessageSizeType:Response_Data;
508 DPRINTF(RubySlicc, "Sending data to L2: %s\n", in_msg.Address);
511 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
512 out_msg.Address := address;
513 out_msg.Type := CoherenceResponseType:DATA;
514 out_msg.Sender := machineID;
515 out_msg.SenderMachine := MachineType:L1Cache;
516 out_msg.Destination.add(in_msg.Requestor);
517 out_msg.DataBlk := cache_entry.DataBlk;
518 // out_msg.Dirty := cache_entry.Dirty;
519 out_msg.Dirty := false;
520 out_msg.Acks := in_msg.Acks;
521 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
523 DPRINTF(RubySlicc, "Sending data to L1\n");
528 action(e_sendDataToL2, "ee", desc="Send data from cache to requestor") {
529 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
530 assert(is_valid(cache_entry));
531 out_msg.Address := address;
532 out_msg.Type := CoherenceResponseType:DATA;
533 out_msg.Sender := machineID;
534 out_msg.SenderMachine := MachineType:L1Cache;
535 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
536 l2_select_low_bit, l2_select_num_bits));
537 out_msg.DataBlk := cache_entry.DataBlk;
538 out_msg.Dirty := cache_entry.Dirty;
539 out_msg.Acks := 0; // irrelevant
540 out_msg.MessageSize := MessageSizeType:Response_Data;
544 action(ee_sendDataExclusive, "\e", desc="Send data from cache to requestor, don't keep a shared copy") {
545 peek(requestNetwork_in, RequestMsg) {
546 assert(is_valid(cache_entry));
547 if (in_msg.RequestorMachine == MachineType:L2Cache) {
548 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
549 out_msg.Address := address;
550 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
551 out_msg.Sender := machineID;
552 out_msg.SenderMachine := MachineType:L1Cache;
553 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
554 l2_select_low_bit, l2_select_num_bits));
555 out_msg.DataBlk := cache_entry.DataBlk;
556 out_msg.Dirty := cache_entry.Dirty;
557 out_msg.Acks := in_msg.Acks;
558 out_msg.MessageSize := MessageSizeType:Response_Data;
560 DPRINTF(RubySlicc, "Sending exclusive data to L2\n");
563 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
564 out_msg.Address := address;
565 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
566 out_msg.Sender := machineID;
567 out_msg.SenderMachine := MachineType:L1Cache;
568 out_msg.Destination.add(in_msg.Requestor);
569 out_msg.DataBlk := cache_entry.DataBlk;
570 out_msg.Dirty := cache_entry.Dirty;
571 out_msg.Acks := in_msg.Acks;
572 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
574 DPRINTF(RubySlicc, "Sending exclusive data to L1\n");
579 action(f_sendAck, "f", desc="Send ack from cache to requestor") {
580 peek(requestNetwork_in, RequestMsg) {
581 if (in_msg.RequestorMachine == MachineType:L1Cache) {
582 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
583 out_msg.Address := address;
584 out_msg.Type := CoherenceResponseType:ACK;
585 out_msg.Sender := machineID;
586 out_msg.SenderMachine := MachineType:L1Cache;
587 out_msg.Destination.add(in_msg.Requestor);
588 out_msg.Acks := 0 - 1; // -1
589 out_msg.MessageSize := MessageSizeType:Response_Control;
593 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
594 out_msg.Address := address;
595 out_msg.Type := CoherenceResponseType:ACK;
596 out_msg.Sender := machineID;
597 out_msg.SenderMachine := MachineType:L1Cache;
598 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
599 l2_select_low_bit, l2_select_num_bits));
600 out_msg.Acks := 0 - 1; // -1
601 out_msg.MessageSize := MessageSizeType:Response_Control;
607 action(g_sendUnblock, "g", desc="Send unblock to memory") {
608 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
609 out_msg.Address := address;
610 out_msg.Type := CoherenceResponseType:UNBLOCK;
611 out_msg.Sender := machineID;
612 out_msg.SenderMachine := MachineType:L1Cache;
613 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
614 l2_select_low_bit, l2_select_num_bits));
615 out_msg.MessageSize := MessageSizeType:Unblock_Control;
619 action(gg_sendUnblockExclusive, "\g", desc="Send unblock exclusive to memory") {
620 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
621 out_msg.Address := address;
622 out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE;
623 out_msg.Sender := machineID;
624 out_msg.SenderMachine := MachineType:L1Cache;
625 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
626 l2_select_low_bit, l2_select_num_bits));
627 out_msg.MessageSize := MessageSizeType:Unblock_Control;
631 action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
632 assert(is_valid(cache_entry));
633 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
634 sequencer.readCallback(address, cache_entry.DataBlk);
637 action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
638 assert(is_valid(cache_entry));
639 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
640 sequencer.writeCallback(address, cache_entry.DataBlk);
641 cache_entry.Dirty := true;
644 action(i_allocateTBE, "i", desc="Allocate TBE") {
645 check_allocate(TBEs);
646 TBEs.allocate(address);
647 set_tbe(TBEs[address]);
648 assert(is_valid(cache_entry));
649 tbe.DataBlk := cache_entry.DataBlk; // Data only used for writebacks
650 tbe.Dirty := cache_entry.Dirty;
653 action(j_popTriggerQueue, "j", desc="Pop trigger queue.") {
654 triggerQueue_in.dequeue();
657 action(jj_unsetUseTimer, "\jj", desc="Unset use timer.") {
658 useTimerTable.unset(address);
661 action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
662 mandatoryQueue_in.dequeue();
665 action(l_popForwardQueue, "l", desc="Pop forwareded request queue.") {
666 requestNetwork_in.dequeue();
669 action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") {
670 peek(responseToL1Cache_in, ResponseMsg) {
671 assert(is_valid(tbe));
672 DPRINTF(RubySlicc, "L1 decrementNumberOfMessages: %d\n", in_msg.Acks);
673 tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks;
677 action(mm_decrementNumberOfMessages, "\m", desc="Decrement the number of messages for which we're waiting") {
678 peek(requestNetwork_in, RequestMsg) {
679 assert(is_valid(tbe));
680 tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks;
684 action(n_popResponseQueue, "n", desc="Pop response queue") {
685 responseToL1Cache_in.dequeue();
688 action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
689 assert(is_valid(tbe));
690 if (tbe.NumPendingMsgs == 0) {
691 enqueue(triggerQueue_out, TriggerMsg) {
692 out_msg.Address := address;
693 out_msg.Type := TriggerType:ALL_ACKS;
698 action(o_scheduleUseTimeout, "oo", desc="Schedule a use timeout.") {
699 useTimerTable.set(address, 50);
702 action(ub_dmaUnblockL2Cache, "ub", desc="Send dma ack to l2 cache") {
703 peek(requestNetwork_in, RequestMsg) {
704 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
705 out_msg.Address := address;
706 out_msg.Type := CoherenceResponseType:DMA_ACK;
707 out_msg.Sender := machineID;
708 out_msg.SenderMachine := MachineType:L1Cache;
709 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
710 l2_select_low_bit, l2_select_num_bits));
711 out_msg.Dirty := false;
713 out_msg.MessageSize := MessageSizeType:Response_Control;
718 action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") {
719 peek(requestNetwork_in, RequestMsg) {
720 assert(is_valid(tbe));
721 if (in_msg.RequestorMachine == MachineType:L1Cache ||
722 in_msg.RequestorMachine == MachineType:DMA) {
723 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
724 out_msg.Address := address;
725 out_msg.Type := CoherenceResponseType:DATA;
726 out_msg.Sender := machineID;
727 out_msg.SenderMachine := MachineType:L1Cache;
728 out_msg.Destination.add(in_msg.Requestor);
729 out_msg.DataBlk := tbe.DataBlk;
730 // out_msg.Dirty := tbe.Dirty;
731 out_msg.Dirty := false;
732 out_msg.Acks := in_msg.Acks;
733 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
737 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
738 out_msg.Address := address;
739 out_msg.Type := CoherenceResponseType:DATA;
740 out_msg.Sender := machineID;
741 out_msg.SenderMachine := MachineType:L1Cache;
742 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
743 l2_select_low_bit, l2_select_num_bits));
744 out_msg.DataBlk := tbe.DataBlk;
745 // out_msg.Dirty := tbe.Dirty;
746 out_msg.Dirty := false;
747 out_msg.Acks := in_msg.Acks;
748 out_msg.MessageSize := MessageSizeType:Response_Data;
754 action(q_sendExclusiveDataFromTBEToCache, "qq", desc="Send data from TBE to cache") {
755 peek(requestNetwork_in, RequestMsg) {
756 assert(is_valid(tbe));
757 if (in_msg.RequestorMachine == MachineType:L1Cache) {
758 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
759 out_msg.Address := address;
760 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
761 out_msg.Sender := machineID;
762 out_msg.SenderMachine := MachineType:L1Cache;
763 out_msg.Destination.add(in_msg.Requestor);
764 out_msg.DataBlk := tbe.DataBlk;
765 out_msg.Dirty := tbe.Dirty;
766 out_msg.Acks := in_msg.Acks;
767 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
771 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
772 out_msg.Address := address;
773 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
774 out_msg.Sender := machineID;
775 out_msg.SenderMachine := MachineType:L1Cache;
776 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
777 l2_select_low_bit, l2_select_num_bits));
778 out_msg.DataBlk := tbe.DataBlk;
779 out_msg.Dirty := tbe.Dirty;
780 out_msg.Acks := in_msg.Acks;
781 out_msg.MessageSize := MessageSizeType:Response_Data;
787 // L2 will usually request data for a writeback
788 action(qq_sendWBDataFromTBEToL2, "\q", desc="Send data from TBE to L2") {
789 enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
790 assert(is_valid(tbe));
791 out_msg.Address := address;
792 out_msg.Sender := machineID;
793 out_msg.SenderMachine := MachineType:L1Cache;
794 out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
795 l2_select_low_bit, l2_select_num_bits));
796 out_msg.Dirty := tbe.Dirty;
798 out_msg.Type := CoherenceResponseType:WRITEBACK_DIRTY_DATA;
800 out_msg.Type := CoherenceResponseType:WRITEBACK_CLEAN_DATA;
802 out_msg.DataBlk := tbe.DataBlk;
803 out_msg.MessageSize := MessageSizeType:Writeback_Data;
807 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
808 TBEs.deallocate(address);
812 action(u_writeDataToCache, "u", desc="Write data to cache") {
813 peek(responseToL1Cache_in, ResponseMsg) {
814 assert(is_valid(cache_entry));
815 cache_entry.DataBlk := in_msg.DataBlk;
816 cache_entry.Dirty := in_msg.Dirty;
818 if (in_msg.Type == CoherenceResponseType:DATA) {
819 //assert(in_msg.Dirty == false);
824 action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") {
825 peek(responseToL1Cache_in, ResponseMsg) {
826 assert(is_valid(cache_entry));
827 assert(cache_entry.DataBlk == in_msg.DataBlk);
828 cache_entry.DataBlk := in_msg.DataBlk;
829 cache_entry.Dirty := in_msg.Dirty;
833 action(kk_deallocateL1CacheBlock, "\k", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
834 if (L1DcacheMemory.isTagPresent(address)) {
835 L1DcacheMemory.deallocate(address);
837 L1IcacheMemory.deallocate(address);
842 action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
843 if ((is_invalid(cache_entry))) {
844 set_cache_entry(L1DcacheMemory.allocate(address, new Entry));
848 action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") {
849 if ((is_invalid(cache_entry))) {
850 set_cache_entry(L1IcacheMemory.allocate(address, new Entry));
854 action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
855 if (send_evictions) {
856 DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
857 sequencer.evictionCallback(address);
861 action(uu_profileMiss, "\u", desc="Profile the demand miss") {
862 peek(mandatoryQueue_in, RubyRequest) {
863 // profile_miss(in_msg);
867 action(z_recycleRequestQueue, "z", desc="Send the head of the mandatory queue to the back of the queue.") {
868 requestNetwork_in.recycle();
871 action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
872 mandatoryQueue_in.recycle();
875 //*****************************************************
877 //*****************************************************
879 // Transitions for Load/Store/L2_Replacement from transient states
880 transition({IM, SM, OM, IS, OI, SI, MI, II}, {Store, L1_Replacement}) {
881 zz_recycleMandatoryQueue;
884 transition({M_W, MM_W}, L1_Replacement) {
885 zz_recycleMandatoryQueue;
888 transition({M_W, MM_W}, {Fwd_GETS, Fwd_DMA, Fwd_GETX, Own_GETX, Inv}) {
889 z_recycleRequestQueue;
892 transition({IM, IS, OI, MI, SI, II}, {Load, Ifetch}) {
893 zz_recycleMandatoryQueue;
896 // Transitions from Idle
897 transition(I, Load, IS) {
898 ii_allocateL1DCacheBlock;
905 transition(I, Ifetch, IS) {
906 jj_allocateL1ICacheBlock;
913 transition(I, Store, IM) {
914 ii_allocateL1DCacheBlock;
921 transition(I, L1_Replacement) {
922 kk_deallocateL1CacheBlock;
930 // Transitions from Shared
931 transition({S, SM}, {Load, Ifetch}) {
936 transition(S, Store, SM) {
943 transition(S, L1_Replacement, SI) {
946 forward_eviction_to_cpu;
947 kk_deallocateL1CacheBlock;
950 transition(S, Inv, I) {
952 forward_eviction_to_cpu;
956 transition(S, Fwd_GETS) {
961 transition(S, Fwd_DMA) {
963 ub_dmaUnblockL2Cache;
967 // Transitions from Owned
968 transition({O, OM}, {Load, Ifetch}) {
973 transition(O, Store, OM) {
980 transition(O, L1_Replacement, OI) {
983 forward_eviction_to_cpu;
984 kk_deallocateL1CacheBlock;
987 transition(O, Fwd_GETX, I) {
988 ee_sendDataExclusive;
989 forward_eviction_to_cpu;
993 transition(O, Fwd_GETS) {
998 transition(O, Fwd_DMA) {
1000 ub_dmaUnblockL2Cache;
1004 // Transitions from MM
1005 transition({MM, MM_W}, {Load, Ifetch}) {
1007 k_popMandatoryQueue;
1010 transition({MM, MM_W}, Store) {
1012 k_popMandatoryQueue;
1015 transition(MM, L1_Replacement, MI) {
1018 forward_eviction_to_cpu;
1019 kk_deallocateL1CacheBlock;
1022 transition(MM, Fwd_GETX, I) {
1023 ee_sendDataExclusive;
1024 forward_eviction_to_cpu;
1028 transition(MM, Fwd_GETS, I) {
1029 ee_sendDataExclusive;
1030 forward_eviction_to_cpu;
1034 transition(MM, Fwd_DMA, MM) {
1036 ub_dmaUnblockL2Cache;
1040 // Transitions from M
1041 transition({M, M_W}, {Load, Ifetch}) {
1043 k_popMandatoryQueue;
1046 transition(M, Store, MM) {
1048 k_popMandatoryQueue;
1051 transition(M_W, Store, MM_W) {
1053 k_popMandatoryQueue;
1056 transition(M, L1_Replacement, MI) {
1059 forward_eviction_to_cpu;
1060 kk_deallocateL1CacheBlock;
1063 transition(M, Fwd_GETX, I) {
1065 ee_sendDataExclusive;
1066 forward_eviction_to_cpu;
1070 transition(M, Fwd_GETS, O) {
1075 transition(M, Fwd_DMA) {
1077 ub_dmaUnblockL2Cache;
1081 // Transitions from IM
1083 transition(IM, Inv) {
1088 transition(IM, Ack) {
1089 m_decrementNumberOfMessages;
1090 o_checkForCompletion;
1094 transition(IM, {Exclusive_Data, Data}, OM) {
1096 m_decrementNumberOfMessages;
1097 o_checkForCompletion;
1101 // Transitions from SM
1102 transition(SM, Inv, IM) {
1104 forward_eviction_to_cpu;
1108 transition(SM, Ack) {
1109 m_decrementNumberOfMessages;
1110 o_checkForCompletion;
1114 transition(SM, {Data, Exclusive_Data}, OM) {
1115 // v_writeDataToCacheVerify;
1116 m_decrementNumberOfMessages;
1117 o_checkForCompletion;
1121 transition(SM, Fwd_GETS) {
1126 transition(SM, Fwd_DMA) {
1128 ub_dmaUnblockL2Cache;
1132 // Transitions from OM
1133 transition(OM, Own_GETX) {
1134 mm_decrementNumberOfMessages;
1135 o_checkForCompletion;
1140 // transition(OM, Fwd_GETX, OMF) {
1141 transition(OM, Fwd_GETX, IM) {
1142 ee_sendDataExclusive;
1146 transition(OM, Fwd_GETS) {
1151 transition(OM, Fwd_DMA) {
1153 ub_dmaUnblockL2Cache;
1157 //transition({OM, OMF}, Ack) {
1158 transition(OM, Ack) {
1159 m_decrementNumberOfMessages;
1160 o_checkForCompletion;
1164 transition(OM, All_acks, MM_W) {
1166 gg_sendUnblockExclusive;
1168 o_scheduleUseTimeout;
1172 transition(MM_W, Use_Timeout, MM) {
1176 // Transitions from IS
1178 transition(IS, Inv) {
1183 transition(IS, Data, S) {
1185 m_decrementNumberOfMessages;
1192 transition(IS, Exclusive_Data, M_W) {
1194 m_decrementNumberOfMessages;
1196 gg_sendUnblockExclusive;
1197 o_scheduleUseTimeout;
1202 transition(M_W, Use_Timeout, M) {
1206 // Transitions from OI/MI
1208 transition(MI, Fwd_GETS, OI) {
1209 q_sendDataFromTBEToCache;
1213 transition(MI, Fwd_DMA) {
1214 q_sendDataFromTBEToCache;
1215 ub_dmaUnblockL2Cache;
1219 transition(MI, Fwd_GETX, II) {
1220 q_sendExclusiveDataFromTBEToCache;
1224 transition({SI, OI}, Fwd_GETS) {
1225 q_sendDataFromTBEToCache;
1229 transition({SI, OI}, Fwd_DMA) {
1230 q_sendDataFromTBEToCache;
1231 ub_dmaUnblockL2Cache;
1235 transition(OI, Fwd_GETX, II) {
1236 q_sendExclusiveDataFromTBEToCache;
1240 transition({SI, OI, MI}, Writeback_Ack_Data, I) {
1241 qq_sendWBDataFromTBEToL2; // always send data
1246 transition({SI, OI, MI}, Writeback_Ack, I) {
1252 transition({MI, OI}, Writeback_Nack, OI) {
1253 // FIXME: This might cause deadlock by re-using the writeback
1254 // channel, we should handle this case differently.
1259 // Transitions from II
1260 transition(II, {Writeback_Ack, Writeback_Ack_Data}, I) {
1266 // transition({II, SI}, Writeback_Nack, I) {
1267 transition(II, Writeback_Nack, I) {
1272 transition(SI, Writeback_Nack) {
1277 transition(II, Inv) {
1282 transition(SI, Inv, II) {