2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "base/misc.hh"
30 #include "base/str.hh"
31 #include "config/the_isa.hh"
32 #if THE_ISA == X86_ISA
33 #include "arch/x86/insts/microldstop.hh"
35 #include "cpu/testers/rubytest/RubyTester.hh"
36 #include "debug/MemoryAccess.hh"
37 #include "debug/ProtocolTrace.hh"
38 #include "debug/RubySequencer.hh"
39 #include "mem/protocol/PrefetchBit.hh"
40 #include "mem/protocol/RubyAccessMode.hh"
41 #include "mem/ruby/buffers/MessageBuffer.hh"
42 #include "mem/ruby/common/Global.hh"
43 #include "mem/ruby/profiler/Profiler.hh"
44 #include "mem/ruby/slicc_interface/RubyRequest.hh"
45 #include "mem/ruby/system/CacheMemory.hh"
46 #include "mem/ruby/system/Sequencer.hh"
47 #include "mem/ruby/system/System.hh"
48 #include "mem/packet.hh"
49 #include "params/RubySequencer.hh"
54 RubySequencerParams::create()
56 return new Sequencer(this);
59 Sequencer::Sequencer(const Params
*p
)
60 : RubyPort(p
), deadlockCheckEvent(this)
62 m_store_waiting_on_load_cycles
= 0;
63 m_store_waiting_on_store_cycles
= 0;
64 m_load_waiting_on_store_cycles
= 0;
65 m_load_waiting_on_load_cycles
= 0;
67 m_outstanding_count
= 0;
69 m_instCache_ptr
= p
->icache
;
70 m_dataCache_ptr
= p
->dcache
;
71 m_max_outstanding_requests
= p
->max_outstanding_requests
;
72 m_deadlock_threshold
= p
->deadlock_threshold
;
74 assert(m_max_outstanding_requests
> 0);
75 assert(m_deadlock_threshold
> 0);
76 assert(m_instCache_ptr
!= NULL
);
77 assert(m_dataCache_ptr
!= NULL
);
79 m_usingNetworkTester
= p
->using_network_tester
;
82 Sequencer::~Sequencer()
89 // Check for deadlock of any of the requests
90 Time current_time
= g_eventQueue_ptr
->getTime();
92 // Check across all outstanding requests
93 int total_outstanding
= 0;
95 RequestTable::iterator read
= m_readRequestTable
.begin();
96 RequestTable::iterator read_end
= m_readRequestTable
.end();
97 for (; read
!= read_end
; ++read
) {
98 SequencerRequest
* request
= read
->second
;
99 if (current_time
- request
->issue_time
< m_deadlock_threshold
)
102 panic("Possible Deadlock detected. Aborting!\n"
103 "version: %d request.paddr: 0x%x m_readRequestTable: %d "
104 "current time: %u issue_time: %d difference: %d\n", m_version
,
105 Address(request
->pkt
->getAddr()), m_readRequestTable
.size(),
106 current_time
, request
->issue_time
,
107 current_time
- request
->issue_time
);
110 RequestTable::iterator write
= m_writeRequestTable
.begin();
111 RequestTable::iterator write_end
= m_writeRequestTable
.end();
112 for (; write
!= write_end
; ++write
) {
113 SequencerRequest
* request
= write
->second
;
114 if (current_time
- request
->issue_time
< m_deadlock_threshold
)
117 panic("Possible Deadlock detected. Aborting!\n"
118 "version: %d request.paddr: 0x%x m_writeRequestTable: %d "
119 "current time: %u issue_time: %d difference: %d\n", m_version
,
120 Address(request
->pkt
->getAddr()), m_writeRequestTable
.size(),
121 current_time
, request
->issue_time
,
122 current_time
- request
->issue_time
);
125 total_outstanding
+= m_writeRequestTable
.size();
126 total_outstanding
+= m_readRequestTable
.size();
128 assert(m_outstanding_count
== total_outstanding
);
130 if (m_outstanding_count
> 0) {
131 // If there are still outstanding requests, keep checking
132 schedule(deadlockCheckEvent
,
133 m_deadlock_threshold
* g_eventQueue_ptr
->getClock() +
139 Sequencer::printStats(ostream
& out
) const
141 out
<< "Sequencer: " << m_name
<< endl
142 << " store_waiting_on_load_cycles: "
143 << m_store_waiting_on_load_cycles
<< endl
144 << " store_waiting_on_store_cycles: "
145 << m_store_waiting_on_store_cycles
<< endl
146 << " load_waiting_on_load_cycles: "
147 << m_load_waiting_on_load_cycles
<< endl
148 << " load_waiting_on_store_cycles: "
149 << m_load_waiting_on_store_cycles
<< endl
;
153 Sequencer::printProgress(ostream
& out
) const
156 int total_demand
= 0;
157 out
<< "Sequencer Stats Version " << m_version
<< endl
;
158 out
<< "Current time = " << g_eventQueue_ptr
->getTime() << endl
;
159 out
<< "---------------" << endl
;
160 out
<< "outstanding requests" << endl
;
162 out
<< "proc " << m_Read
163 << " version Requests = " << m_readRequestTable
.size() << endl
;
165 // print the request table
166 RequestTable::iterator read
= m_readRequestTable
.begin();
167 RequestTable::iterator read_end
= m_readRequestTable
.end();
168 for (; read
!= read_end
; ++read
) {
169 SequencerRequest
* request
= read
->second
;
170 out
<< "\tRequest[ " << i
<< " ] = " << request
->type
171 << " Address " << rkeys
[i
]
172 << " Posted " << request
->issue_time
173 << " PF " << PrefetchBit_No
<< endl
;
177 out
<< "proc " << m_version
178 << " Write Requests = " << m_writeRequestTable
.size
<< endl
;
180 // print the request table
181 RequestTable::iterator write
= m_writeRequestTable
.begin();
182 RequestTable::iterator write_end
= m_writeRequestTable
.end();
183 for (; write
!= write_end
; ++write
) {
184 SequencerRequest
* request
= write
->second
;
185 out
<< "\tRequest[ " << i
<< " ] = " << request
.getType()
186 << " Address " << wkeys
[i
]
187 << " Posted " << request
.getTime()
188 << " PF " << request
.getPrefetch() << endl
;
189 if (request
.getPrefetch() == PrefetchBit_No
) {
196 out
<< "Total Number Outstanding: " << m_outstanding_count
<< endl
197 << "Total Number Demand : " << total_demand
<< endl
198 << "Total Number Prefetches : " << m_outstanding_count
- total_demand
199 << endl
<< endl
<< endl
;
204 Sequencer::printConfig(ostream
& out
) const
206 out
<< "Seqeuncer config: " << m_name
<< endl
207 << " controller: " << m_controller
->getName() << endl
208 << " version: " << m_version
<< endl
209 << " max_outstanding_requests: " << m_max_outstanding_requests
<< endl
210 << " deadlock_threshold: " << m_deadlock_threshold
<< endl
;
213 // Insert the request on the correct request table. Return true if
214 // the entry was already present.
216 Sequencer::insertRequest(PacketPtr pkt
, RubyRequestType request_type
)
218 assert(m_outstanding_count
==
219 (m_writeRequestTable
.size() + m_readRequestTable
.size()));
221 // See if we should schedule a deadlock check
222 if (deadlockCheckEvent
.scheduled() == false) {
223 schedule(deadlockCheckEvent
,
224 m_deadlock_threshold
* g_eventQueue_ptr
->getClock()
228 Address
line_addr(pkt
->getAddr());
229 line_addr
.makeLineAddress();
230 if ((request_type
== RubyRequestType_ST
) ||
231 (request_type
== RubyRequestType_RMW_Read
) ||
232 (request_type
== RubyRequestType_RMW_Write
) ||
233 (request_type
== RubyRequestType_Load_Linked
) ||
234 (request_type
== RubyRequestType_Store_Conditional
) ||
235 (request_type
== RubyRequestType_Locked_RMW_Read
) ||
236 (request_type
== RubyRequestType_Locked_RMW_Write
) ||
237 (request_type
== RubyRequestType_FLUSH
)) {
239 // Check if there is any outstanding read request for the same
241 if (m_readRequestTable
.count(line_addr
) > 0) {
242 m_store_waiting_on_load_cycles
++;
243 return RequestStatus_Aliased
;
246 pair
<RequestTable::iterator
, bool> r
=
247 m_writeRequestTable
.insert(RequestTable::value_type(line_addr
, 0));
249 RequestTable::iterator i
= r
.first
;
250 i
->second
= new SequencerRequest(pkt
, request_type
,
251 g_eventQueue_ptr
->getTime());
252 m_outstanding_count
++;
254 // There is an outstanding write request for the cache line
255 m_store_waiting_on_store_cycles
++;
256 return RequestStatus_Aliased
;
259 // Check if there is any outstanding write request for the same
261 if (m_writeRequestTable
.count(line_addr
) > 0) {
262 m_load_waiting_on_store_cycles
++;
263 return RequestStatus_Aliased
;
266 pair
<RequestTable::iterator
, bool> r
=
267 m_readRequestTable
.insert(RequestTable::value_type(line_addr
, 0));
270 RequestTable::iterator i
= r
.first
;
271 i
->second
= new SequencerRequest(pkt
, request_type
,
272 g_eventQueue_ptr
->getTime());
273 m_outstanding_count
++;
275 // There is an outstanding read request for the cache line
276 m_load_waiting_on_load_cycles
++;
277 return RequestStatus_Aliased
;
281 g_system_ptr
->getProfiler()->sequencerRequests(m_outstanding_count
);
282 assert(m_outstanding_count
==
283 (m_writeRequestTable
.size() + m_readRequestTable
.size()));
285 return RequestStatus_Ready
;
289 Sequencer::markRemoved()
291 m_outstanding_count
--;
292 assert(m_outstanding_count
==
293 m_writeRequestTable
.size() + m_readRequestTable
.size());
297 Sequencer::removeRequest(SequencerRequest
* srequest
)
299 assert(m_outstanding_count
==
300 m_writeRequestTable
.size() + m_readRequestTable
.size());
302 Address
line_addr(srequest
->pkt
->getAddr());
303 line_addr
.makeLineAddress();
304 if ((srequest
->m_type
== RubyRequestType_ST
) ||
305 (srequest
->m_type
== RubyRequestType_RMW_Read
) ||
306 (srequest
->m_type
== RubyRequestType_RMW_Write
) ||
307 (srequest
->m_type
== RubyRequestType_Load_Linked
) ||
308 (srequest
->m_type
== RubyRequestType_Store_Conditional
) ||
309 (srequest
->m_type
== RubyRequestType_Locked_RMW_Read
) ||
310 (srequest
->m_type
== RubyRequestType_Locked_RMW_Write
)) {
311 m_writeRequestTable
.erase(line_addr
);
313 m_readRequestTable
.erase(line_addr
);
320 Sequencer::handleLlsc(const Address
& address
, SequencerRequest
* request
)
323 // The success flag indicates whether the LLSC operation was successful.
324 // LL ops will always succeed, but SC may fail if the cache line is no
328 if (request
->m_type
== RubyRequestType_Store_Conditional
) {
329 if (!m_dataCache_ptr
->isLocked(address
, m_version
)) {
331 // For failed SC requests, indicate the failure to the cpu by
332 // setting the extra data to zero.
334 request
->pkt
->req
->setExtraData(0);
338 // For successful SC requests, indicate the success to the cpu by
339 // setting the extra data to one.
341 request
->pkt
->req
->setExtraData(1);
344 // Independent of success, all SC operations must clear the lock
346 m_dataCache_ptr
->clearLocked(address
);
347 } else if (request
->m_type
== RubyRequestType_Load_Linked
) {
349 // Note: To fully follow Alpha LLSC semantics, should the LL clear any
350 // previously locked cache lines?
352 m_dataCache_ptr
->setLocked(address
, m_version
);
353 } else if ((m_dataCache_ptr
->isTagPresent(address
)) &&
354 (m_dataCache_ptr
->isLocked(address
, m_version
))) {
356 // Normal writes should clear the locked address
358 m_dataCache_ptr
->clearLocked(address
);
364 Sequencer::writeCallback(const Address
& address
, DataBlock
& data
)
366 writeCallback(address
, GenericMachineType_NULL
, data
);
370 Sequencer::writeCallback(const Address
& address
,
371 GenericMachineType mach
,
374 writeCallback(address
, mach
, data
, 0, 0, 0);
378 Sequencer::writeCallback(const Address
& address
,
379 GenericMachineType mach
,
381 Time initialRequestTime
,
382 Time forwardRequestTime
,
383 Time firstResponseTime
)
385 assert(address
== line_address(address
));
386 assert(m_writeRequestTable
.count(line_address(address
)));
388 RequestTable::iterator i
= m_writeRequestTable
.find(address
);
389 assert(i
!= m_writeRequestTable
.end());
390 SequencerRequest
* request
= i
->second
;
392 m_writeRequestTable
.erase(i
);
395 assert((request
->m_type
== RubyRequestType_ST
) ||
396 (request
->m_type
== RubyRequestType_ATOMIC
) ||
397 (request
->m_type
== RubyRequestType_RMW_Read
) ||
398 (request
->m_type
== RubyRequestType_RMW_Write
) ||
399 (request
->m_type
== RubyRequestType_Load_Linked
) ||
400 (request
->m_type
== RubyRequestType_Store_Conditional
) ||
401 (request
->m_type
== RubyRequestType_Locked_RMW_Read
) ||
402 (request
->m_type
== RubyRequestType_Locked_RMW_Write
) ||
403 (request
->m_type
== RubyRequestType_FLUSH
));
407 // For Alpha, properly handle LL, SC, and write requests with respect to
408 // locked cache blocks.
410 // Not valid for Network_test protocl
413 if(!m_usingNetworkTester
)
414 success
= handleLlsc(address
, request
);
416 if (request
->m_type
== RubyRequestType_Locked_RMW_Read
) {
417 m_controller
->blockOnQueue(address
, m_mandatory_q_ptr
);
418 } else if (request
->m_type
== RubyRequestType_Locked_RMW_Write
) {
419 m_controller
->unblock(address
);
422 hitCallback(request
, mach
, data
, success
,
423 initialRequestTime
, forwardRequestTime
, firstResponseTime
);
427 Sequencer::readCallback(const Address
& address
, DataBlock
& data
)
429 readCallback(address
, GenericMachineType_NULL
, data
);
433 Sequencer::readCallback(const Address
& address
,
434 GenericMachineType mach
,
437 readCallback(address
, mach
, data
, 0, 0, 0);
441 Sequencer::readCallback(const Address
& address
,
442 GenericMachineType mach
,
444 Time initialRequestTime
,
445 Time forwardRequestTime
,
446 Time firstResponseTime
)
448 assert(address
== line_address(address
));
449 assert(m_readRequestTable
.count(line_address(address
)));
451 RequestTable::iterator i
= m_readRequestTable
.find(address
);
452 assert(i
!= m_readRequestTable
.end());
453 SequencerRequest
* request
= i
->second
;
455 m_readRequestTable
.erase(i
);
458 assert((request
->m_type
== RubyRequestType_LD
) ||
459 (request
->m_type
== RubyRequestType_IFETCH
));
461 hitCallback(request
, mach
, data
, true,
462 initialRequestTime
, forwardRequestTime
, firstResponseTime
);
466 Sequencer::hitCallback(SequencerRequest
* srequest
,
467 GenericMachineType mach
,
470 Time initialRequestTime
,
471 Time forwardRequestTime
,
472 Time firstResponseTime
)
474 PacketPtr pkt
= srequest
->pkt
;
475 Address
request_address(pkt
->getAddr());
476 Address
request_line_address(pkt
->getAddr());
477 request_line_address
.makeLineAddress();
478 RubyRequestType type
= srequest
->m_type
;
479 Time issued_time
= srequest
->issue_time
;
481 // Set this cache entry to the most recently used
482 if (type
== RubyRequestType_IFETCH
) {
483 m_instCache_ptr
->setMRU(request_line_address
);
485 m_dataCache_ptr
->setMRU(request_line_address
);
488 assert(g_eventQueue_ptr
->getTime() >= issued_time
);
489 Time miss_latency
= g_eventQueue_ptr
->getTime() - issued_time
;
491 // Profile the miss latency for all non-zero demand misses
492 if (miss_latency
!= 0) {
493 g_system_ptr
->getProfiler()->missLatency(miss_latency
, type
, mach
);
495 if (mach
== GenericMachineType_L1Cache_wCC
) {
496 g_system_ptr
->getProfiler()->missLatencyWcc(issued_time
,
500 g_eventQueue_ptr
->getTime());
503 if (mach
== GenericMachineType_Directory
) {
504 g_system_ptr
->getProfiler()->missLatencyDir(issued_time
,
508 g_eventQueue_ptr
->getTime());
511 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
512 curTick(), m_version
, "Seq",
513 success
? "Done" : "SC_Failed", "", "",
514 request_address
, miss_latency
);
518 if (g_system_ptr
->m_warmup_enabled
) {
519 assert(pkt
->getPtr
<uint8_t>(false) != NULL
);
520 data
.setData(pkt
->getPtr
<uint8_t>(false),
521 request_address
.getOffset(), pkt
->getSize());
522 } else if (pkt
->getPtr
<uint8_t>(true) != NULL
) {
523 if ((type
== RubyRequestType_LD
) ||
524 (type
== RubyRequestType_IFETCH
) ||
525 (type
== RubyRequestType_RMW_Read
) ||
526 (type
== RubyRequestType_Locked_RMW_Read
) ||
527 (type
== RubyRequestType_Load_Linked
)) {
528 memcpy(pkt
->getPtr
<uint8_t>(true),
529 data
.getData(request_address
.getOffset(), pkt
->getSize()),
532 data
.setData(pkt
->getPtr
<uint8_t>(true),
533 request_address
.getOffset(), pkt
->getSize());
536 DPRINTF(MemoryAccess
,
537 "WARNING. Data not transfered from Ruby to M5 for type %s\n",
538 RubyRequestType_to_string(type
));
541 // If using the RubyTester, update the RubyTester sender state's
542 // subBlock with the recieved data. The tester will later access
544 // Note: RubyPort will access it's sender state before the
546 if (m_usingRubyTester
) {
547 RubyPort::SenderState
*requestSenderState
=
548 safe_cast
<RubyPort::SenderState
*>(pkt
->senderState
);
549 RubyTester::SenderState
* testerSenderState
=
550 safe_cast
<RubyTester::SenderState
*>(requestSenderState
->saved
);
551 testerSenderState
->subBlock
->mergeFrom(data
);
556 if (g_system_ptr
->m_warmup_enabled
) {
558 g_system_ptr
->m_cache_recorder
->enqueueNextFetchRequest();
559 } else if (g_system_ptr
->m_cooldown_enabled
) {
561 g_system_ptr
->m_cache_recorder
->enqueueNextFlushRequest();
563 ruby_hit_callback(pkt
);
568 Sequencer::empty() const
570 return m_writeRequestTable
.empty() && m_readRequestTable
.empty();
574 Sequencer::makeRequest(PacketPtr pkt
)
576 if (m_outstanding_count
>= m_max_outstanding_requests
) {
577 return RequestStatus_BufferFull
;
580 RubyRequestType primary_type
= RubyRequestType_NULL
;
581 RubyRequestType secondary_type
= RubyRequestType_NULL
;
585 // Alpha LL/SC instructions need to be handled carefully by the cache
586 // coherence protocol to ensure they follow the proper semantics. In
587 // particular, by identifying the operations as atomic, the protocol
588 // should understand that migratory sharing optimizations should not
589 // be performed (i.e. a load between the LL and SC should not steal
590 // away exclusive permission).
592 if (pkt
->isWrite()) {
593 DPRINTF(RubySequencer
, "Issuing SC\n");
594 primary_type
= RubyRequestType_Store_Conditional
;
596 DPRINTF(RubySequencer
, "Issuing LL\n");
597 assert(pkt
->isRead());
598 primary_type
= RubyRequestType_Load_Linked
;
600 secondary_type
= RubyRequestType_ATOMIC
;
601 } else if (pkt
->req
->isLocked()) {
603 // x86 locked instructions are translated to store cache coherence
604 // requests because these requests should always be treated as read
605 // exclusive operations and should leverage any migratory sharing
606 // optimization built into the protocol.
608 if (pkt
->isWrite()) {
609 DPRINTF(RubySequencer
, "Issuing Locked RMW Write\n");
610 primary_type
= RubyRequestType_Locked_RMW_Write
;
612 DPRINTF(RubySequencer
, "Issuing Locked RMW Read\n");
613 assert(pkt
->isRead());
614 primary_type
= RubyRequestType_Locked_RMW_Read
;
616 secondary_type
= RubyRequestType_ST
;
619 if (pkt
->req
->isInstFetch()) {
620 primary_type
= secondary_type
= RubyRequestType_IFETCH
;
622 #if THE_ISA == X86_ISA
623 uint32_t flags
= pkt
->req
->getFlags();
624 bool storeCheck
= flags
&
625 (TheISA::StoreCheck
<< TheISA::FlagShift
);
627 bool storeCheck
= false;
630 primary_type
= RubyRequestType_RMW_Read
;
631 secondary_type
= RubyRequestType_ST
;
633 primary_type
= secondary_type
= RubyRequestType_LD
;
636 } else if (pkt
->isWrite()) {
638 // Note: M5 packets do not differentiate ST from RMW_Write
640 primary_type
= secondary_type
= RubyRequestType_ST
;
641 } else if (pkt
->isFlush()) {
642 primary_type
= secondary_type
= RubyRequestType_FLUSH
;
644 panic("Unsupported ruby packet type\n");
648 RequestStatus status
= insertRequest(pkt
, primary_type
);
649 if (status
!= RequestStatus_Ready
)
652 issueRequest(pkt
, secondary_type
);
654 // TODO: issue hardware prefetches here
655 return RequestStatus_Issued
;
659 Sequencer::issueRequest(PacketPtr pkt
, RubyRequestType secondary_type
)
662 if (pkt
!= NULL
&& pkt
->req
->hasContextId()) {
663 proc_id
= pkt
->req
->contextId();
666 // If valid, copy the pc to the ruby request
668 if (pkt
->req
->hasPC()) {
669 pc
= pkt
->req
->getPC();
672 RubyRequest
*msg
= new RubyRequest(pkt
->getAddr(),
673 pkt
->getPtr
<uint8_t>(true),
674 pkt
->getSize(), pc
, secondary_type
,
675 RubyAccessMode_Supervisor
, pkt
,
676 PrefetchBit_No
, proc_id
);
678 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %s %s\n",
679 curTick(), m_version
, "Seq", "Begin", "", "",
680 msg
->getPhysicalAddress(),
681 RubyRequestType_to_string(secondary_type
));
683 Time latency
= 0; // initialzed to an null value
685 if (secondary_type
== RubyRequestType_IFETCH
)
686 latency
= m_instCache_ptr
->getLatency();
688 latency
= m_dataCache_ptr
->getLatency();
690 // Send the message to the cache controller
693 assert(m_mandatory_q_ptr
!= NULL
);
694 m_mandatory_q_ptr
->enqueue(msg
, latency
);
697 template <class KEY
, class VALUE
>
699 operator<<(ostream
&out
, const m5::hash_map
<KEY
, VALUE
> &map
)
701 typename
m5::hash_map
<KEY
, VALUE
>::const_iterator i
= map
.begin();
702 typename
m5::hash_map
<KEY
, VALUE
>::const_iterator end
= map
.end();
705 for (; i
!= end
; ++i
)
706 out
<< " " << i
->first
<< "=" << i
->second
;
713 Sequencer::print(ostream
& out
) const
715 out
<< "[Sequencer: " << m_version
716 << ", outstanding requests: " << m_outstanding_count
717 << ", read request table: " << m_readRequestTable
718 << ", write request table: " << m_writeRequestTable
722 // this can be called from setState whenever coherence permissions are
723 // upgraded when invoked, coherence violations will be checked for the
726 Sequencer::checkCoherence(const Address
& addr
)
728 #ifdef CHECK_COHERENCE
729 g_system_ptr
->checkGlobalCoherenceInvariant(addr
);
734 Sequencer::evictionCallback(const Address
& address
)
736 ruby_eviction_callback(address
);