2 * Copyright (c) 2019 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 machine(MachineType:L1Cache, "L1 cache protocol")
42 : Sequencer * sequencer;
43 CacheMemory * L1Icache;
44 CacheMemory * L1Dcache;
45 Cycles request_latency := 1;
46 Cycles response_latency := 1;
47 Cycles use_timeout_latency := 50;
51 // From this node's L1 cache TO the network
52 // a local L1 -> this L2 bank, currently ordered with directory forwarded requests
53 MessageBuffer * requestFromL1Cache, network="To", virtual_network="0",
55 // a local L1 -> this L2 bank
56 MessageBuffer * responseFromL1Cache, network="To", virtual_network="2",
59 // To this node's L1 cache FROM the network
60 // a L2 bank -> this L1
61 MessageBuffer * requestToL1Cache, network="From", virtual_network="0",
63 // a L2 bank -> this L1
64 MessageBuffer * responseToL1Cache, network="From", virtual_network="2",
67 MessageBuffer * triggerQueue;
69 MessageBuffer * mandatoryQueue;
72 state_declaration(State, desc="Cache states", default="L1Cache_State_I") {
74 I, AccessPermission:Invalid, desc="Idle";
75 S, AccessPermission:Read_Only, desc="Shared";
76 O, AccessPermission:Read_Only, desc="Owned";
77 M, AccessPermission:Read_Only, desc="Modified (dirty)";
78 M_W, AccessPermission:Read_Only, desc="Modified (dirty)";
79 MM, AccessPermission:Read_Write, desc="Modified (dirty and locally modified)";
80 MM_W, AccessPermission:Read_Write, desc="Modified (dirty and locally modified)";
83 IM, AccessPermission:Busy, "IM", desc="Issued GetX";
84 SM, AccessPermission:Read_Only, "SM", desc="Issued GetX, we still have an old copy of the line";
85 OM, AccessPermission:Read_Only, "SM", desc="Issued GetX, received data";
86 IS, AccessPermission:Busy, "IS", desc="Issued GetS";
87 SI, AccessPermission:Busy, "OI", desc="Issued PutS, waiting for ack";
88 OI, AccessPermission:Busy, "OI", desc="Issued PutO, waiting for ack";
89 MI, AccessPermission:Busy, "MI", desc="Issued PutX, waiting for ack";
90 II, AccessPermission:Busy, "II", desc="Issued PutX/O, saw Fwd_GETS or Fwd_GETX, waiting for ack";
94 enumeration(Event, desc="Cache events") {
95 Load, desc="Load request from the processor";
96 Ifetch, desc="I-fetch request from the processor";
97 Store, desc="Store request from the processor";
98 L1_Replacement, desc="Replacement";
101 Own_GETX, desc="We observe our own GetX forwarded back to us";
102 Fwd_GETX, desc="A GetX from another processor";
103 Fwd_GETS, desc="A GetS from another processor";
104 Fwd_DMA, desc="A GetS from another processor";
105 Inv, desc="Invalidations from the directory";
108 Ack, desc="Received an ack message";
109 Data, desc="Received a data message, responder has a shared copy";
110 Exclusive_Data, desc="Received a data message";
112 Writeback_Ack, desc="Writeback O.K. from directory";
113 Writeback_Ack_Data, desc="Writeback O.K. from directory";
114 Writeback_Nack, desc="Writeback not O.K. from directory";
117 All_acks, desc="Received all required data and message acks";
120 Use_Timeout, desc="lockout period ended";
126 structure(Entry, desc="...", interface="AbstractCacheEntry") {
127 State CacheState, desc="cache state";
128 bool Dirty, desc="Is the data dirty (different than memory)?";
129 DataBlock DataBlk, desc="data for the block";
133 structure(TBE, desc="...") {
134 Addr addr, desc="Physical address for this TBE";
135 State TBEState, desc="Transient state";
136 DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
137 bool Dirty, desc="Is the data dirty (different than memory)?";
138 int NumPendingMsgs, default="0", desc="Number of acks/data messages that this processor is waiting for";
141 structure(TBETable, external ="yes") {
144 void deallocate(Addr);
145 bool isPresent(Addr);
149 Tick cyclesToTicks(Cycles c);
150 void set_cache_entry(AbstractCacheEntry b);
151 void unset_cache_entry();
154 MachineID mapAddressToMachine(Addr addr, MachineType mtype);
156 TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
157 TimerTable useTimerTable;
159 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
160 Entry L1Dcache_entry := static_cast(Entry, "pointer", L1Dcache.lookup(addr));
161 if(is_valid(L1Dcache_entry)) {
162 return L1Dcache_entry;
165 Entry L1Icache_entry := static_cast(Entry, "pointer", L1Icache.lookup(addr));
166 return L1Icache_entry;
169 Entry getL1DCacheEntry(Addr addr), return_by_pointer="yes" {
170 return static_cast(Entry, "pointer", L1Dcache.lookup(addr));
173 Entry getL1ICacheEntry(Addr addr), return_by_pointer="yes" {
174 return static_cast(Entry, "pointer", L1Icache.lookup(addr));
177 State getState(TBE tbe, Entry cache_entry, Addr addr) {
180 } else if (is_valid(cache_entry)) {
181 return cache_entry.CacheState;
187 Cycles mandatoryQueueLatency(RubyRequestType type) {
188 if (type == RubyRequestType:IFETCH) {
189 return L1Icache.getTagLatency();
191 return L1Dcache.getTagLatency();
195 // Latency for responses that fetch data from cache
196 Cycles cacheResponseLatency() {
197 if (L1Dcache.getTagLatency() > response_latency) {
198 return L1Dcache.getTagLatency();
200 return response_latency;
204 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
205 assert((L1Dcache.isTagPresent(addr) && L1Icache.isTagPresent(addr)) == false);
208 tbe.TBEState := state;
211 if (is_valid(cache_entry)) {
212 if ( ((cache_entry.CacheState != State:M) && (state == State:M)) ||
213 ((cache_entry.CacheState != State:MM) && (state == State:MM)) ||
214 ((cache_entry.CacheState != State:S) && (state == State:S)) ||
215 ((cache_entry.CacheState != State:O) && (state == State:O)) ) {
217 cache_entry.CacheState := state;
218 sequencer.checkCoherence(addr);
221 cache_entry.CacheState := state;
226 AccessPermission getAccessPermission(Addr addr) {
227 TBE tbe := TBEs[addr];
229 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
230 return L1Cache_State_to_permission(tbe.TBEState);
233 Entry cache_entry := getCacheEntry(addr);
234 if(is_valid(cache_entry)) {
235 DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
236 return L1Cache_State_to_permission(cache_entry.CacheState);
239 DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
240 return AccessPermission:NotPresent;
243 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
244 if (is_valid(cache_entry)) {
245 cache_entry.changePermission(L1Cache_State_to_permission(state));
249 void functionalRead(Addr addr, Packet *pkt) {
250 Entry cache_entry := getCacheEntry(addr);
251 if(is_valid(cache_entry)) {
252 testAndRead(addr, cache_entry.DataBlk, pkt);
254 TBE tbe := TBEs[addr];
256 testAndRead(addr, tbe.DataBlk, pkt);
258 error("Data block missing!");
263 int functionalWrite(Addr addr, Packet *pkt) {
264 int num_functional_writes := 0;
266 Entry cache_entry := getCacheEntry(addr);
267 if(is_valid(cache_entry)) {
268 num_functional_writes := num_functional_writes +
269 testAndWrite(addr, cache_entry.DataBlk, pkt);
270 return num_functional_writes;
273 TBE tbe := TBEs[addr];
274 num_functional_writes := num_functional_writes +
275 testAndWrite(addr, tbe.DataBlk, pkt);
276 return num_functional_writes;
279 Event mandatory_request_type_to_event(RubyRequestType type) {
280 if (type == RubyRequestType:LD) {
282 } else if (type == RubyRequestType:IFETCH) {
284 } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
287 error("Invalid RubyRequestType");
293 out_port(requestNetwork_out, RequestMsg, requestFromL1Cache);
294 out_port(responseNetwork_out, ResponseMsg, responseFromL1Cache);
295 out_port(triggerQueue_out, TriggerMsg, triggerQueue);
300 in_port(useTimerTable_in, Addr, useTimerTable, rank=4) {
301 if (useTimerTable_in.isReady(clockEdge())) {
302 Addr readyAddress := useTimerTable.nextAddress();
303 trigger(Event:Use_Timeout, readyAddress, getCacheEntry(readyAddress),
304 TBEs.lookup(readyAddress));
309 in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=3) {
310 if (triggerQueue_in.isReady(clockEdge())) {
311 peek(triggerQueue_in, TriggerMsg) {
312 if (in_msg.Type == TriggerType:ALL_ACKS) {
313 trigger(Event:All_acks, in_msg.addr,
314 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
316 error("Unexpected message");
323 in_port(responseToL1Cache_in, ResponseMsg, responseToL1Cache, rank=2) {
324 if (responseToL1Cache_in.isReady(clockEdge())) {
325 peek(responseToL1Cache_in, ResponseMsg, block_on="addr") {
326 if (in_msg.Type == CoherenceResponseType:ACK) {
327 trigger(Event:Ack, in_msg.addr,
328 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
329 } else if (in_msg.Type == CoherenceResponseType:DATA) {
330 trigger(Event:Data, in_msg.addr,
331 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
332 } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
333 trigger(Event:Exclusive_Data, in_msg.addr,
334 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
335 } else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
336 trigger(Event:Writeback_Ack, in_msg.addr,
337 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
338 } else if (in_msg.Type == CoherenceResponseType:WB_ACK_DATA) {
339 trigger(Event:Writeback_Ack_Data, in_msg.addr,
340 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
341 } else if (in_msg.Type == CoherenceResponseType:WB_NACK) {
342 trigger(Event:Writeback_Nack, in_msg.addr,
343 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
345 error("Unexpected message");
353 in_port(requestNetwork_in, RequestMsg, requestToL1Cache, rank=1) {
354 if (requestNetwork_in.isReady(clockEdge())) {
355 peek(requestNetwork_in, RequestMsg, block_on="addr") {
356 assert(in_msg.Destination.isElement(machineID));
357 DPRINTF(RubySlicc, "L1 received: %s\n", in_msg.Type);
359 if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:DMA_WRITE) {
360 if (in_msg.Requestor == machineID && in_msg.RequestorMachine == MachineType:L1Cache) {
361 trigger(Event:Own_GETX, in_msg.addr,
362 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
364 trigger(Event:Fwd_GETX, in_msg.addr,
365 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
367 } else if (in_msg.Type == CoherenceRequestType:GETS) {
368 trigger(Event:Fwd_GETS, in_msg.addr,
369 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
370 } else if (in_msg.Type == CoherenceRequestType:DMA_READ) {
371 trigger(Event:Fwd_DMA, in_msg.addr,
372 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
373 } else if (in_msg.Type == CoherenceRequestType:INV) {
374 trigger(Event:Inv, in_msg.addr,
375 getCacheEntry(in_msg.addr), TBEs[in_msg.addr]);
377 error("Unexpected message");
383 // Mandatory Queue betweens Node's CPU and it's L1 caches
384 in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, rank=0) {
385 if (mandatoryQueue_in.isReady(clockEdge())) {
386 peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
388 // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
390 if (in_msg.Type == RubyRequestType:IFETCH) {
391 // ** INSTRUCTION ACCESS ***
393 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
394 if (is_valid(L1Icache_entry)) {
395 // The tag matches for the L1, so the L1 asks the L2 for it.
396 trigger(mandatory_request_type_to_event(in_msg.Type),
397 in_msg.LineAddress, L1Icache_entry,
398 TBEs[in_msg.LineAddress]);
401 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
402 // Check to see if it is in the OTHER L1
403 if (is_valid(L1Dcache_entry)) {
404 // The block is in the wrong L1, put the request on the queue to the shared L2
405 trigger(Event:L1_Replacement, in_msg.LineAddress, L1Dcache_entry,
406 TBEs[in_msg.LineAddress]);
408 if (L1Icache.cacheAvail(in_msg.LineAddress)) {
409 // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
410 trigger(mandatory_request_type_to_event(in_msg.Type),
411 in_msg.LineAddress, L1Icache_entry,
412 TBEs[in_msg.LineAddress]);
414 // No room in the L1, so we need to make room in the L1
415 // Check if the line we want to evict is not locked
416 Addr addr := L1Icache.cacheProbe(in_msg.LineAddress);
417 check_on_cache_probe(mandatoryQueue_in, addr);
418 trigger(Event:L1_Replacement,
420 getL1ICacheEntry(addr),
425 // *** DATA ACCESS ***
427 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress);
428 if (is_valid(L1Dcache_entry)) {
429 // The tag matches for the L1, so the L1 ask the L2 for it
430 trigger(mandatory_request_type_to_event(in_msg.Type),
431 in_msg.LineAddress, L1Dcache_entry,
432 TBEs[in_msg.LineAddress]);
435 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress);
436 // Check to see if it is in the OTHER L1
437 if (is_valid(L1Icache_entry)) {
438 // The block is in the wrong L1, put the request on the queue to the shared L2
439 trigger(Event:L1_Replacement, in_msg.LineAddress,
440 L1Icache_entry, TBEs[in_msg.LineAddress]);
442 if (L1Dcache.cacheAvail(in_msg.LineAddress)) {
443 // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
444 trigger(mandatory_request_type_to_event(in_msg.Type),
445 in_msg.LineAddress, L1Dcache_entry,
446 TBEs[in_msg.LineAddress]);
448 // No room in the L1, so we need to make room in the L1
449 // Check if the line we want to evict is not locked
450 Addr addr := L1Dcache.cacheProbe(in_msg.LineAddress);
451 check_on_cache_probe(mandatoryQueue_in, addr);
452 trigger(Event:L1_Replacement,
454 getL1DCacheEntry(addr),
466 action(a_issueGETS, "a", desc="Issue GETS") {
467 peek(mandatoryQueue_in, RubyRequest) {
468 enqueue(requestNetwork_out, RequestMsg, request_latency) {
469 out_msg.addr := address;
470 out_msg.Type := CoherenceRequestType:GETS;
471 out_msg.Requestor := machineID;
472 out_msg.RequestorMachine := MachineType:L1Cache;
473 out_msg.Destination.add(mapAddressToMachine(address,
474 MachineType:L2Cache));
475 out_msg.MessageSize := MessageSizeType:Request_Control;
476 out_msg.AccessMode := in_msg.AccessMode;
477 out_msg.Prefetch := in_msg.Prefetch;
482 action(b_issueGETX, "b", desc="Issue GETX") {
483 peek(mandatoryQueue_in, RubyRequest) {
484 enqueue(requestNetwork_out, RequestMsg, request_latency) {
485 out_msg.addr := address;
486 out_msg.Type := CoherenceRequestType:GETX;
487 out_msg.Requestor := machineID;
488 out_msg.RequestorMachine := MachineType:L1Cache;
489 out_msg.Destination.add(mapAddressToMachine(address,
490 MachineType:L2Cache));
491 out_msg.MessageSize := MessageSizeType:Request_Control;
492 out_msg.AccessMode := in_msg.AccessMode;
493 out_msg.Prefetch := in_msg.Prefetch;
498 action(d_issuePUTX, "d", desc="Issue PUTX") {
499 enqueue(requestNetwork_out, RequestMsg, request_latency) {
500 out_msg.addr := address;
501 out_msg.Type := CoherenceRequestType:PUTX;
502 out_msg.Requestor := machineID;
503 out_msg.RequestorMachine := MachineType:L1Cache;
504 out_msg.Destination.add(mapAddressToMachine(address,
505 MachineType:L2Cache));
506 out_msg.MessageSize := MessageSizeType:Writeback_Control;
510 action(dd_issuePUTO, "\d", desc="Issue PUTO") {
511 enqueue(requestNetwork_out, RequestMsg, request_latency) {
512 out_msg.addr := address;
513 out_msg.Type := CoherenceRequestType:PUTO;
514 out_msg.Requestor := machineID;
515 out_msg.RequestorMachine := MachineType:L1Cache;
516 out_msg.Destination.add(mapAddressToMachine(address,
517 MachineType:L2Cache));
518 out_msg.MessageSize := MessageSizeType:Writeback_Control;
522 action(dd_issuePUTS, "\ds", desc="Issue PUTS") {
523 enqueue(requestNetwork_out, RequestMsg, request_latency) {
524 out_msg.addr := address;
525 out_msg.Type := CoherenceRequestType:PUTS;
526 out_msg.Requestor := machineID;
527 out_msg.RequestorMachine := MachineType:L1Cache;
528 out_msg.Destination.add(mapAddressToMachine(address,
529 MachineType:L2Cache));
530 out_msg.MessageSize := MessageSizeType:Writeback_Control;
534 action(e_sendData, "e", desc="Send data from cache to requestor") {
535 peek(requestNetwork_in, RequestMsg) {
536 assert(is_valid(cache_entry));
537 if (in_msg.RequestorMachine == MachineType:L2Cache) {
538 enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
539 out_msg.addr := address;
540 out_msg.Type := CoherenceResponseType:DATA;
541 out_msg.Sender := machineID;
542 out_msg.SenderMachine := MachineType:L1Cache;
543 out_msg.Destination.add(mapAddressToMachine(address,
544 MachineType:L2Cache));
545 out_msg.DataBlk := cache_entry.DataBlk;
546 // out_msg.Dirty := cache_entry.Dirty;
547 out_msg.Dirty := false;
548 out_msg.Acks := in_msg.Acks;
549 out_msg.MessageSize := MessageSizeType:Response_Data;
551 DPRINTF(RubySlicc, "Sending data to L2: %#x\n", in_msg.addr);
554 enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
555 out_msg.addr := address;
556 out_msg.Type := CoherenceResponseType:DATA;
557 out_msg.Sender := machineID;
558 out_msg.SenderMachine := MachineType:L1Cache;
559 out_msg.Destination.add(in_msg.Requestor);
560 out_msg.DataBlk := cache_entry.DataBlk;
561 // out_msg.Dirty := cache_entry.Dirty;
562 out_msg.Dirty := false;
563 out_msg.Acks := in_msg.Acks;
564 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
566 DPRINTF(RubySlicc, "Sending data to L1\n");
571 action(ee_sendDataExclusive, "\e", desc="Send data from cache to requestor, don't keep a shared copy") {
572 peek(requestNetwork_in, RequestMsg) {
573 assert(is_valid(cache_entry));
574 if (in_msg.RequestorMachine == MachineType:L2Cache) {
575 enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
576 out_msg.addr := address;
577 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
578 out_msg.Sender := machineID;
579 out_msg.SenderMachine := MachineType:L1Cache;
580 out_msg.Destination.add(mapAddressToMachine(address,
581 MachineType:L2Cache));
582 out_msg.DataBlk := cache_entry.DataBlk;
583 out_msg.Dirty := cache_entry.Dirty;
584 out_msg.Acks := in_msg.Acks;
585 out_msg.MessageSize := MessageSizeType:Response_Data;
587 DPRINTF(RubySlicc, "Sending exclusive data to L2\n");
590 enqueue(responseNetwork_out, ResponseMsg, cacheResponseLatency()) {
591 out_msg.addr := address;
592 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
593 out_msg.Sender := machineID;
594 out_msg.SenderMachine := MachineType:L1Cache;
595 out_msg.Destination.add(in_msg.Requestor);
596 out_msg.DataBlk := cache_entry.DataBlk;
597 out_msg.Dirty := cache_entry.Dirty;
598 out_msg.Acks := in_msg.Acks;
599 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
601 DPRINTF(RubySlicc, "Sending exclusive data to L1\n");
606 action(f_sendAck, "f", desc="Send ack from cache to requestor") {
607 peek(requestNetwork_in, RequestMsg) {
608 if (in_msg.RequestorMachine == MachineType:L1Cache) {
609 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
610 out_msg.addr := address;
611 out_msg.Type := CoherenceResponseType:ACK;
612 out_msg.Sender := machineID;
613 out_msg.SenderMachine := MachineType:L1Cache;
614 out_msg.Destination.add(in_msg.Requestor);
615 out_msg.Acks := 0 - 1; // -1
616 out_msg.MessageSize := MessageSizeType:Response_Control;
620 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
621 out_msg.addr := address;
622 out_msg.Type := CoherenceResponseType:ACK;
623 out_msg.Sender := machineID;
624 out_msg.SenderMachine := MachineType:L1Cache;
625 out_msg.Destination.add(mapAddressToMachine(address,
626 MachineType:L2Cache));
627 out_msg.Acks := 0 - 1; // -1
628 out_msg.MessageSize := MessageSizeType:Response_Control;
634 action(g_sendUnblock, "g", desc="Send unblock to memory") {
635 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
636 out_msg.addr := address;
637 out_msg.Type := CoherenceResponseType:UNBLOCK;
638 out_msg.Sender := machineID;
639 out_msg.SenderMachine := MachineType:L1Cache;
640 out_msg.Destination.add(mapAddressToMachine(address,
641 MachineType:L2Cache));
642 out_msg.MessageSize := MessageSizeType:Unblock_Control;
646 action(gg_sendUnblockExclusive, "\g", desc="Send unblock exclusive to memory") {
647 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
648 out_msg.addr := address;
649 out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE;
650 out_msg.Sender := machineID;
651 out_msg.SenderMachine := MachineType:L1Cache;
652 out_msg.Destination.add(mapAddressToMachine(address,
653 MachineType:L2Cache));
654 out_msg.MessageSize := MessageSizeType:Unblock_Control;
658 action(h_load_hit, "hd", desc="Notify sequencer the load completed.") {
659 assert(is_valid(cache_entry));
660 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
661 L1Dcache.setMRU(cache_entry);
662 sequencer.readCallback(address, cache_entry.DataBlk);
665 action(h_ifetch_hit, "hi", desc="Notify the sequencer about ifetch completion.") {
666 assert(is_valid(cache_entry));
667 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
668 L1Icache.setMRU(cache_entry);
669 sequencer.readCallback(address, cache_entry.DataBlk);
672 action(hx_load_hit, "hx", desc="Notify sequencer the load completed.") {
673 assert(is_valid(cache_entry));
674 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
675 L1Icache.setMRU(address);
676 L1Dcache.setMRU(address);
677 sequencer.readCallback(address, cache_entry.DataBlk, true);
680 action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
681 assert(is_valid(cache_entry));
682 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
683 L1Dcache.setMRU(cache_entry);
684 sequencer.writeCallback(address, cache_entry.DataBlk);
685 cache_entry.Dirty := true;
688 action(xx_store_hit, "\xx", desc="Notify sequencer that store completed.") {
689 assert(is_valid(cache_entry));
690 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
691 L1Icache.setMRU(address);
692 L1Dcache.setMRU(address);
693 sequencer.writeCallback(address, cache_entry.DataBlk, true);
694 cache_entry.Dirty := true;
697 action(i_allocateTBE, "i", desc="Allocate TBE") {
698 check_allocate(TBEs);
699 TBEs.allocate(address);
700 set_tbe(TBEs[address]);
701 assert(is_valid(cache_entry));
702 tbe.DataBlk := cache_entry.DataBlk; // Data only used for writebacks
703 tbe.Dirty := cache_entry.Dirty;
706 action(j_popTriggerQueue, "j", desc="Pop trigger queue.") {
707 triggerQueue_in.dequeue(clockEdge());
710 action(jj_unsetUseTimer, "\jj", desc="Unset use timer.") {
711 useTimerTable.unset(address);
714 action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
715 mandatoryQueue_in.dequeue(clockEdge());
718 action(l_popForwardQueue, "l", desc="Pop forwarded request queue.") {
719 requestNetwork_in.dequeue(clockEdge());
722 action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") {
723 peek(responseToL1Cache_in, ResponseMsg) {
724 assert(is_valid(tbe));
725 DPRINTF(RubySlicc, "L1 decrementNumberOfMessages: %d\n", in_msg.Acks);
726 tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks;
730 action(mm_decrementNumberOfMessages, "\m", desc="Decrement the number of messages for which we're waiting") {
731 peek(requestNetwork_in, RequestMsg) {
732 assert(is_valid(tbe));
733 tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks;
737 action(n_popResponseQueue, "n", desc="Pop response queue") {
738 responseToL1Cache_in.dequeue(clockEdge());
741 action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
742 assert(is_valid(tbe));
743 if (tbe.NumPendingMsgs == 0) {
744 enqueue(triggerQueue_out, TriggerMsg) {
745 out_msg.addr := address;
746 out_msg.Type := TriggerType:ALL_ACKS;
751 action(o_scheduleUseTimeout, "oo", desc="Schedule a use timeout.") {
752 useTimerTable.set(address,
753 clockEdge() + cyclesToTicks(use_timeout_latency));
756 action(ub_dmaUnblockL2Cache, "ub", desc="Send dma ack to l2 cache") {
757 peek(requestNetwork_in, RequestMsg) {
758 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
759 out_msg.addr := address;
760 out_msg.Type := CoherenceResponseType:DMA_ACK;
761 out_msg.Sender := machineID;
762 out_msg.SenderMachine := MachineType:L1Cache;
763 out_msg.Destination.add(mapAddressToMachine(address,
764 MachineType:L2Cache));
765 out_msg.Dirty := false;
767 out_msg.MessageSize := MessageSizeType:Response_Control;
772 action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") {
773 peek(requestNetwork_in, RequestMsg) {
774 assert(is_valid(tbe));
775 if (in_msg.RequestorMachine == MachineType:L1Cache ||
776 in_msg.RequestorMachine == MachineType:DMA) {
777 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
778 out_msg.addr := address;
779 out_msg.Type := CoherenceResponseType:DATA;
780 out_msg.Sender := machineID;
781 out_msg.SenderMachine := MachineType:L1Cache;
782 out_msg.Destination.add(in_msg.Requestor);
783 out_msg.DataBlk := tbe.DataBlk;
784 // out_msg.Dirty := tbe.Dirty;
785 out_msg.Dirty := false;
786 out_msg.Acks := in_msg.Acks;
787 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
791 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
792 out_msg.addr := address;
793 out_msg.Type := CoherenceResponseType:DATA;
794 out_msg.Sender := machineID;
795 out_msg.SenderMachine := MachineType:L1Cache;
796 out_msg.Destination.add(mapAddressToMachine(address,
797 MachineType:L2Cache));
798 out_msg.DataBlk := tbe.DataBlk;
799 // out_msg.Dirty := tbe.Dirty;
800 out_msg.Dirty := false;
801 out_msg.Acks := in_msg.Acks;
802 out_msg.MessageSize := MessageSizeType:Response_Data;
808 action(q_sendExclusiveDataFromTBEToCache, "qq", desc="Send data from TBE to cache") {
809 peek(requestNetwork_in, RequestMsg) {
810 assert(is_valid(tbe));
811 if (in_msg.RequestorMachine == MachineType:L1Cache) {
812 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
813 out_msg.addr := address;
814 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
815 out_msg.Sender := machineID;
816 out_msg.SenderMachine := MachineType:L1Cache;
817 out_msg.Destination.add(in_msg.Requestor);
818 out_msg.DataBlk := tbe.DataBlk;
819 out_msg.Dirty := tbe.Dirty;
820 out_msg.Acks := in_msg.Acks;
821 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
825 enqueue(responseNetwork_out, ResponseMsg, response_latency) {
826 out_msg.addr := address;
827 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
828 out_msg.Sender := machineID;
829 out_msg.SenderMachine := MachineType:L1Cache;
830 out_msg.Destination.add(mapAddressToMachine(address,
831 MachineType:L2Cache));
832 out_msg.DataBlk := tbe.DataBlk;
833 out_msg.Dirty := tbe.Dirty;
834 out_msg.Acks := in_msg.Acks;
835 out_msg.MessageSize := MessageSizeType:Response_Data;
841 // L2 will usually request data for a writeback
842 action(qq_sendWBDataFromTBEToL2, "\q", desc="Send data from TBE to L2") {
843 enqueue(requestNetwork_out, RequestMsg, request_latency) {
844 assert(is_valid(tbe));
845 out_msg.addr := address;
846 out_msg.Requestor := machineID;
847 out_msg.RequestorMachine := MachineType:L1Cache;
848 out_msg.Destination.add(mapAddressToMachine(address,
849 MachineType:L2Cache));
851 out_msg.Type := CoherenceRequestType:WRITEBACK_DIRTY_DATA;
853 out_msg.Type := CoherenceRequestType:WRITEBACK_CLEAN_DATA;
855 out_msg.DataBlk := tbe.DataBlk;
856 out_msg.MessageSize := MessageSizeType:Writeback_Data;
860 action(s_deallocateTBE, "s", desc="Deallocate TBE") {
861 TBEs.deallocate(address);
865 action(u_writeDataToCache, "u", desc="Write data to cache") {
866 peek(responseToL1Cache_in, ResponseMsg) {
867 assert(is_valid(cache_entry));
868 cache_entry.DataBlk := in_msg.DataBlk;
869 cache_entry.Dirty := in_msg.Dirty;
871 if (in_msg.Type == CoherenceResponseType:DATA) {
872 //assert(in_msg.Dirty == false);
877 action(kk_deallocateL1CacheBlock, "\k", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
878 if (L1Dcache.isTagPresent(address)) {
879 L1Dcache.deallocate(address);
881 L1Icache.deallocate(address);
886 action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
887 if ((is_invalid(cache_entry))) {
888 set_cache_entry(L1Dcache.allocate(address, new Entry));
892 action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") {
893 if ((is_invalid(cache_entry))) {
894 set_cache_entry(L1Icache.allocate(address, new Entry));
898 action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
899 if (send_evictions) {
900 DPRINTF(RubySlicc, "Sending invalidation for %#x to the CPU\n", address);
901 sequencer.evictionCallback(address);
905 action(uu_profileInstMiss, "\uim", desc="Profile the demand miss") {
906 ++L1Icache.demand_misses;
909 action(uu_profileInstHit, "\uih", desc="Profile the demand hit") {
910 ++L1Icache.demand_hits;
913 action(uu_profileDataMiss, "\udm", desc="Profile the demand miss") {
914 ++L1Dcache.demand_misses;
917 action(uu_profileDataHit, "\udh", desc="Profile the demand hit") {
918 ++L1Dcache.demand_hits;
921 action(z_recycleRequestQueue, "z", desc="Send the head of the mandatory queue to the back of the queue.") {
922 requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
925 action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
926 mandatoryQueue_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
929 //*****************************************************
931 //*****************************************************
933 // Transitions for Load/Store/L2_Replacement from transient states
934 transition({IM, SM, OM, IS, OI, SI, MI, II}, {Store, L1_Replacement}) {
935 zz_recycleMandatoryQueue;
938 transition({M_W, MM_W}, L1_Replacement) {
939 zz_recycleMandatoryQueue;
942 transition({M_W, MM_W}, {Fwd_GETS, Fwd_DMA, Fwd_GETX, Own_GETX, Inv}) {
943 z_recycleRequestQueue;
946 transition({IM, IS, OI, MI, SI, II}, {Load, Ifetch}) {
947 zz_recycleMandatoryQueue;
950 // Transitions from Idle
951 transition(I, Load, IS) {
952 ii_allocateL1DCacheBlock;
959 transition(I, Ifetch, IS) {
960 jj_allocateL1ICacheBlock;
967 transition(I, Store, IM) {
968 ii_allocateL1DCacheBlock;
975 transition(I, L1_Replacement) {
976 kk_deallocateL1CacheBlock;
984 transition({S, SM, O, OM, MM, MM_W, M, M_W}, Load) {
990 transition({S, SM, O, OM, MM, MM_W, M, M_W}, Ifetch) {
996 // Transitions from Shared
997 transition(S, Store, SM) {
1001 k_popMandatoryQueue;
1004 transition(S, L1_Replacement, SI) {
1007 forward_eviction_to_cpu;
1008 kk_deallocateL1CacheBlock;
1011 transition(S, Inv, I) {
1013 forward_eviction_to_cpu;
1017 transition(S, Fwd_GETS) {
1022 transition(S, Fwd_DMA) {
1024 ub_dmaUnblockL2Cache;
1028 // Transitions from Owned
1029 transition(O, Store, OM) {
1033 k_popMandatoryQueue;
1036 transition(O, L1_Replacement, OI) {
1039 forward_eviction_to_cpu;
1040 kk_deallocateL1CacheBlock;
1043 transition(O, Fwd_GETX, I) {
1044 ee_sendDataExclusive;
1045 forward_eviction_to_cpu;
1049 transition(O, Fwd_GETS) {
1054 transition(O, Fwd_DMA) {
1056 ub_dmaUnblockL2Cache;
1060 // Transitions from MM
1061 transition({MM, MM_W}, Store) {
1064 k_popMandatoryQueue;
1067 transition(MM, L1_Replacement, MI) {
1070 forward_eviction_to_cpu;
1071 kk_deallocateL1CacheBlock;
1074 transition(MM, Fwd_GETX, I) {
1075 ee_sendDataExclusive;
1076 forward_eviction_to_cpu;
1080 transition(MM, Fwd_GETS, I) {
1081 ee_sendDataExclusive;
1082 forward_eviction_to_cpu;
1086 transition(MM, Fwd_DMA, MM) {
1088 ub_dmaUnblockL2Cache;
1092 // Transitions from M
1093 transition(M, Store, MM) {
1096 k_popMandatoryQueue;
1099 transition(M_W, Store, MM_W) {
1102 k_popMandatoryQueue;
1105 transition(M, L1_Replacement, MI) {
1108 forward_eviction_to_cpu;
1109 kk_deallocateL1CacheBlock;
1112 transition(M, Fwd_GETX, I) {
1114 ee_sendDataExclusive;
1115 forward_eviction_to_cpu;
1119 transition(M, Fwd_GETS, O) {
1124 transition(M, Fwd_DMA) {
1126 ub_dmaUnblockL2Cache;
1130 // Transitions from IM
1132 transition(IM, Inv) {
1137 transition(IM, Ack) {
1138 m_decrementNumberOfMessages;
1139 o_checkForCompletion;
1143 transition(IM, {Exclusive_Data, Data}, OM) {
1145 m_decrementNumberOfMessages;
1146 o_checkForCompletion;
1150 // Transitions from SM
1151 transition(SM, Inv, IM) {
1153 forward_eviction_to_cpu;
1157 transition(SM, Ack) {
1158 m_decrementNumberOfMessages;
1159 o_checkForCompletion;
1163 transition(SM, {Data, Exclusive_Data}, OM) {
1164 // v_writeDataToCacheVerify;
1165 m_decrementNumberOfMessages;
1166 o_checkForCompletion;
1170 transition(SM, Fwd_GETS) {
1175 transition(SM, Fwd_DMA) {
1177 ub_dmaUnblockL2Cache;
1181 // Transitions from OM
1182 transition(OM, Own_GETX) {
1183 mm_decrementNumberOfMessages;
1184 o_checkForCompletion;
1189 // transition(OM, Fwd_GETX, OMF) {
1190 transition(OM, Fwd_GETX, IM) {
1191 ee_sendDataExclusive;
1195 transition(OM, Fwd_GETS) {
1200 transition(OM, Fwd_DMA) {
1202 ub_dmaUnblockL2Cache;
1206 //transition({OM, OMF}, Ack) {
1207 transition(OM, Ack) {
1208 m_decrementNumberOfMessages;
1209 o_checkForCompletion;
1213 transition(OM, All_acks, MM_W) {
1215 gg_sendUnblockExclusive;
1217 o_scheduleUseTimeout;
1221 transition(MM_W, Use_Timeout, MM) {
1225 // Transitions from IS
1227 transition(IS, Inv) {
1232 transition(IS, Data, S) {
1234 m_decrementNumberOfMessages;
1241 transition(IS, Exclusive_Data, M_W) {
1243 m_decrementNumberOfMessages;
1245 gg_sendUnblockExclusive;
1246 o_scheduleUseTimeout;
1251 transition(M_W, Use_Timeout, M) {
1255 // Transitions from OI/MI
1257 transition(MI, Fwd_GETS, OI) {
1258 q_sendDataFromTBEToCache;
1262 transition(MI, Fwd_DMA) {
1263 q_sendDataFromTBEToCache;
1264 ub_dmaUnblockL2Cache;
1268 transition(MI, Fwd_GETX, II) {
1269 q_sendExclusiveDataFromTBEToCache;
1273 transition({SI, OI}, Fwd_GETS) {
1274 q_sendDataFromTBEToCache;
1278 transition({SI, OI}, Fwd_DMA) {
1279 q_sendDataFromTBEToCache;
1280 ub_dmaUnblockL2Cache;
1284 transition(OI, Fwd_GETX, II) {
1285 q_sendExclusiveDataFromTBEToCache;
1289 transition({SI, OI, MI}, Writeback_Ack_Data, I) {
1290 qq_sendWBDataFromTBEToL2; // always send data
1295 transition({SI, OI, MI}, Writeback_Ack, I) {
1301 transition({MI, OI}, Writeback_Nack, OI) {
1302 // FIXME: This might cause deadlock by re-using the writeback
1303 // channel, we should handle this case differently.
1308 // Transitions from II
1309 transition(II, {Writeback_Ack, Writeback_Ack_Data}, I) {
1315 // transition({II, SI}, Writeback_Nack, I) {
1316 transition(II, Writeback_Nack, I) {
1321 transition(SI, Writeback_Nack) {
1326 transition(II, Inv) {
1331 transition(SI, Inv, II) {