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 "arch/x86/ldstflags.hh"
30 #include "base/misc.hh"
31 #include "base/str.hh"
32 #include "cpu/testers/rubytest/RubyTester.hh"
33 #include "debug/MemoryAccess.hh"
34 #include "debug/ProtocolTrace.hh"
35 #include "debug/RubySequencer.hh"
36 #include "debug/RubyStats.hh"
37 #include "mem/protocol/PrefetchBit.hh"
38 #include "mem/protocol/RubyAccessMode.hh"
39 #include "mem/ruby/profiler/Profiler.hh"
40 #include "mem/ruby/slicc_interface/RubyRequest.hh"
41 #include "mem/ruby/system/Sequencer.hh"
42 #include "mem/ruby/system/System.hh"
43 #include "mem/packet.hh"
44 #include "sim/system.hh"
49 RubySequencerParams::create()
51 return new Sequencer(this);
54 Sequencer::Sequencer(const Params
*p
)
55 : RubyPort(p
), m_IncompleteTimes(MachineType_NUM
), deadlockCheckEvent(this)
57 m_outstanding_count
= 0;
59 m_instCache_ptr
= p
->icache
;
60 m_dataCache_ptr
= p
->dcache
;
61 m_max_outstanding_requests
= p
->max_outstanding_requests
;
62 m_deadlock_threshold
= p
->deadlock_threshold
;
64 assert(m_max_outstanding_requests
> 0);
65 assert(m_deadlock_threshold
> 0);
66 assert(m_instCache_ptr
!= NULL
);
67 assert(m_dataCache_ptr
!= NULL
);
69 m_usingNetworkTester
= p
->using_network_tester
;
72 Sequencer::~Sequencer()
79 assert(drainState() != DrainState::Draining
);
81 // Check for deadlock of any of the requests
82 Cycles current_time
= curCycle();
84 // Check across all outstanding requests
85 int total_outstanding
= 0;
87 RequestTable::iterator read
= m_readRequestTable
.begin();
88 RequestTable::iterator read_end
= m_readRequestTable
.end();
89 for (; read
!= read_end
; ++read
) {
90 SequencerRequest
* request
= read
->second
;
91 if (current_time
- request
->issue_time
< m_deadlock_threshold
)
94 panic("Possible Deadlock detected. Aborting!\n"
95 "version: %d request.paddr: 0x%x m_readRequestTable: %d "
96 "current time: %u issue_time: %d difference: %d\n", m_version
,
97 Address(request
->pkt
->getAddr()), m_readRequestTable
.size(),
98 current_time
* clockPeriod(), request
->issue_time
* clockPeriod(),
99 (current_time
* clockPeriod()) - (request
->issue_time
* clockPeriod()));
102 RequestTable::iterator write
= m_writeRequestTable
.begin();
103 RequestTable::iterator write_end
= m_writeRequestTable
.end();
104 for (; write
!= write_end
; ++write
) {
105 SequencerRequest
* request
= write
->second
;
106 if (current_time
- request
->issue_time
< m_deadlock_threshold
)
109 panic("Possible Deadlock detected. Aborting!\n"
110 "version: %d request.paddr: 0x%x m_writeRequestTable: %d "
111 "current time: %u issue_time: %d difference: %d\n", m_version
,
112 Address(request
->pkt
->getAddr()), m_writeRequestTable
.size(),
113 current_time
* clockPeriod(), request
->issue_time
* clockPeriod(),
114 (current_time
* clockPeriod()) - (request
->issue_time
* clockPeriod()));
117 total_outstanding
+= m_writeRequestTable
.size();
118 total_outstanding
+= m_readRequestTable
.size();
120 assert(m_outstanding_count
== total_outstanding
);
122 if (m_outstanding_count
> 0) {
123 // If there are still outstanding requests, keep checking
124 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
128 void Sequencer::resetStats()
130 m_latencyHist
.reset();
131 m_hitLatencyHist
.reset();
132 m_missLatencyHist
.reset();
133 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
134 m_typeLatencyHist
[i
]->reset();
135 m_hitTypeLatencyHist
[i
]->reset();
136 m_missTypeLatencyHist
[i
]->reset();
137 for (int j
= 0; j
< MachineType_NUM
; j
++) {
138 m_hitTypeMachLatencyHist
[i
][j
]->reset();
139 m_missTypeMachLatencyHist
[i
][j
]->reset();
143 for (int i
= 0; i
< MachineType_NUM
; i
++) {
144 m_missMachLatencyHist
[i
]->reset();
145 m_hitMachLatencyHist
[i
]->reset();
147 m_IssueToInitialDelayHist
[i
]->reset();
148 m_InitialToForwardDelayHist
[i
]->reset();
149 m_ForwardToFirstResponseDelayHist
[i
]->reset();
150 m_FirstResponseToCompletionDelayHist
[i
]->reset();
152 m_IncompleteTimes
[i
] = 0;
157 Sequencer::printProgress(ostream
& out
) const
160 int total_demand
= 0;
161 out
<< "Sequencer Stats Version " << m_version
<< endl
;
162 out
<< "Current time = " << m_ruby_system
->getTime() << endl
;
163 out
<< "---------------" << endl
;
164 out
<< "outstanding requests" << endl
;
166 out
<< "proc " << m_Read
167 << " version Requests = " << m_readRequestTable
.size() << endl
;
169 // print the request table
170 RequestTable::iterator read
= m_readRequestTable
.begin();
171 RequestTable::iterator read_end
= m_readRequestTable
.end();
172 for (; read
!= read_end
; ++read
) {
173 SequencerRequest
* request
= read
->second
;
174 out
<< "\tRequest[ " << i
<< " ] = " << request
->type
175 << " Address " << rkeys
[i
]
176 << " Posted " << request
->issue_time
177 << " PF " << PrefetchBit_No
<< endl
;
181 out
<< "proc " << m_version
182 << " Write Requests = " << m_writeRequestTable
.size
<< endl
;
184 // print the request table
185 RequestTable::iterator write
= m_writeRequestTable
.begin();
186 RequestTable::iterator write_end
= m_writeRequestTable
.end();
187 for (; write
!= write_end
; ++write
) {
188 SequencerRequest
* request
= write
->second
;
189 out
<< "\tRequest[ " << i
<< " ] = " << request
.getType()
190 << " Address " << wkeys
[i
]
191 << " Posted " << request
.getTime()
192 << " PF " << request
.getPrefetch() << endl
;
193 if (request
.getPrefetch() == PrefetchBit_No
) {
200 out
<< "Total Number Outstanding: " << m_outstanding_count
<< endl
201 << "Total Number Demand : " << total_demand
<< endl
202 << "Total Number Prefetches : " << m_outstanding_count
- total_demand
203 << endl
<< endl
<< endl
;
207 // Insert the request on the correct request table. Return true if
208 // the entry was already present.
210 Sequencer::insertRequest(PacketPtr pkt
, RubyRequestType request_type
)
212 assert(m_outstanding_count
==
213 (m_writeRequestTable
.size() + m_readRequestTable
.size()));
215 // See if we should schedule a deadlock check
216 if (!deadlockCheckEvent
.scheduled() &&
217 drainState() != DrainState::Draining
) {
218 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
221 Address
line_addr(pkt
->getAddr());
222 line_addr
.makeLineAddress();
223 // Create a default entry, mapping the address to NULL, the cast is
224 // there to make gcc 4.4 happy
225 RequestTable::value_type
default_entry(line_addr
,
226 (SequencerRequest
*) NULL
);
228 if ((request_type
== RubyRequestType_ST
) ||
229 (request_type
== RubyRequestType_RMW_Read
) ||
230 (request_type
== RubyRequestType_RMW_Write
) ||
231 (request_type
== RubyRequestType_Load_Linked
) ||
232 (request_type
== RubyRequestType_Store_Conditional
) ||
233 (request_type
== RubyRequestType_Locked_RMW_Read
) ||
234 (request_type
== RubyRequestType_Locked_RMW_Write
) ||
235 (request_type
== RubyRequestType_FLUSH
)) {
237 // Check if there is any outstanding read request for the same
239 if (m_readRequestTable
.count(line_addr
) > 0) {
240 m_store_waiting_on_load
++;
241 return RequestStatus_Aliased
;
244 pair
<RequestTable::iterator
, bool> r
=
245 m_writeRequestTable
.insert(default_entry
);
247 RequestTable::iterator i
= r
.first
;
248 i
->second
= new SequencerRequest(pkt
, request_type
, curCycle());
249 m_outstanding_count
++;
251 // There is an outstanding write request for the cache line
252 m_store_waiting_on_store
++;
253 return RequestStatus_Aliased
;
256 // Check if there is any outstanding write request for the same
258 if (m_writeRequestTable
.count(line_addr
) > 0) {
259 m_load_waiting_on_store
++;
260 return RequestStatus_Aliased
;
263 pair
<RequestTable::iterator
, bool> r
=
264 m_readRequestTable
.insert(default_entry
);
267 RequestTable::iterator i
= r
.first
;
268 i
->second
= new SequencerRequest(pkt
, request_type
, curCycle());
269 m_outstanding_count
++;
271 // There is an outstanding read request for the cache line
272 m_load_waiting_on_load
++;
273 return RequestStatus_Aliased
;
277 m_outstandReqHist
.sample(m_outstanding_count
);
278 assert(m_outstanding_count
==
279 (m_writeRequestTable
.size() + m_readRequestTable
.size()));
281 return RequestStatus_Ready
;
285 Sequencer::markRemoved()
287 m_outstanding_count
--;
288 assert(m_outstanding_count
==
289 m_writeRequestTable
.size() + m_readRequestTable
.size());
293 Sequencer::removeRequest(SequencerRequest
* srequest
)
295 assert(m_outstanding_count
==
296 m_writeRequestTable
.size() + m_readRequestTable
.size());
298 Address
line_addr(srequest
->pkt
->getAddr());
299 line_addr
.makeLineAddress();
300 if ((srequest
->m_type
== RubyRequestType_ST
) ||
301 (srequest
->m_type
== RubyRequestType_RMW_Read
) ||
302 (srequest
->m_type
== RubyRequestType_RMW_Write
) ||
303 (srequest
->m_type
== RubyRequestType_Load_Linked
) ||
304 (srequest
->m_type
== RubyRequestType_Store_Conditional
) ||
305 (srequest
->m_type
== RubyRequestType_Locked_RMW_Read
) ||
306 (srequest
->m_type
== RubyRequestType_Locked_RMW_Write
)) {
307 m_writeRequestTable
.erase(line_addr
);
309 m_readRequestTable
.erase(line_addr
);
316 Sequencer::invalidateSC(const Address
& address
)
318 RequestTable::iterator i
= m_writeRequestTable
.find(address
);
319 if (i
!= m_writeRequestTable
.end()) {
320 SequencerRequest
* request
= i
->second
;
321 // The controller has lost the coherence permissions, hence the lock
322 // on the cache line maintained by the cache should be cleared.
323 if (request
->m_type
== RubyRequestType_Store_Conditional
) {
324 m_dataCache_ptr
->clearLocked(address
);
330 Sequencer::handleLlsc(const Address
& address
, SequencerRequest
* request
)
333 // The success flag indicates whether the LLSC operation was successful.
334 // LL ops will always succeed, but SC may fail if the cache line is no
338 if (request
->m_type
== RubyRequestType_Store_Conditional
) {
339 if (!m_dataCache_ptr
->isLocked(address
, m_version
)) {
341 // For failed SC requests, indicate the failure to the cpu by
342 // setting the extra data to zero.
344 request
->pkt
->req
->setExtraData(0);
348 // For successful SC requests, indicate the success to the cpu by
349 // setting the extra data to one.
351 request
->pkt
->req
->setExtraData(1);
354 // Independent of success, all SC operations must clear the lock
356 m_dataCache_ptr
->clearLocked(address
);
357 } else if (request
->m_type
== RubyRequestType_Load_Linked
) {
359 // Note: To fully follow Alpha LLSC semantics, should the LL clear any
360 // previously locked cache lines?
362 m_dataCache_ptr
->setLocked(address
, m_version
);
363 } else if ((m_dataCache_ptr
->isTagPresent(address
)) &&
364 (m_dataCache_ptr
->isLocked(address
, m_version
))) {
366 // Normal writes should clear the locked address
368 m_dataCache_ptr
->clearLocked(address
);
374 Sequencer::recordMissLatency(const Cycles cycles
, const RubyRequestType type
,
375 const MachineType respondingMach
,
376 bool isExternalHit
, Cycles issuedTime
,
377 Cycles initialRequestTime
,
378 Cycles forwardRequestTime
,
379 Cycles firstResponseTime
, Cycles completionTime
)
381 m_latencyHist
.sample(cycles
);
382 m_typeLatencyHist
[type
]->sample(cycles
);
385 m_missLatencyHist
.sample(cycles
);
386 m_missTypeLatencyHist
[type
]->sample(cycles
);
388 if (respondingMach
!= MachineType_NUM
) {
389 m_missMachLatencyHist
[respondingMach
]->sample(cycles
);
390 m_missTypeMachLatencyHist
[type
][respondingMach
]->sample(cycles
);
392 if ((issuedTime
<= initialRequestTime
) &&
393 (initialRequestTime
<= forwardRequestTime
) &&
394 (forwardRequestTime
<= firstResponseTime
) &&
395 (firstResponseTime
<= completionTime
)) {
397 m_IssueToInitialDelayHist
[respondingMach
]->sample(
398 initialRequestTime
- issuedTime
);
399 m_InitialToForwardDelayHist
[respondingMach
]->sample(
400 forwardRequestTime
- initialRequestTime
);
401 m_ForwardToFirstResponseDelayHist
[respondingMach
]->sample(
402 firstResponseTime
- forwardRequestTime
);
403 m_FirstResponseToCompletionDelayHist
[respondingMach
]->sample(
404 completionTime
- firstResponseTime
);
406 m_IncompleteTimes
[respondingMach
]++;
410 m_hitLatencyHist
.sample(cycles
);
411 m_hitTypeLatencyHist
[type
]->sample(cycles
);
413 if (respondingMach
!= MachineType_NUM
) {
414 m_hitMachLatencyHist
[respondingMach
]->sample(cycles
);
415 m_hitTypeMachLatencyHist
[type
][respondingMach
]->sample(cycles
);
421 Sequencer::writeCallback(const Address
& address
, DataBlock
& data
,
422 const bool externalHit
, const MachineType mach
,
423 const Cycles initialRequestTime
,
424 const Cycles forwardRequestTime
,
425 const Cycles firstResponseTime
)
427 assert(address
== line_address(address
));
428 assert(m_writeRequestTable
.count(line_address(address
)));
430 RequestTable::iterator i
= m_writeRequestTable
.find(address
);
431 assert(i
!= m_writeRequestTable
.end());
432 SequencerRequest
* request
= i
->second
;
434 m_writeRequestTable
.erase(i
);
437 assert((request
->m_type
== RubyRequestType_ST
) ||
438 (request
->m_type
== RubyRequestType_ATOMIC
) ||
439 (request
->m_type
== RubyRequestType_RMW_Read
) ||
440 (request
->m_type
== RubyRequestType_RMW_Write
) ||
441 (request
->m_type
== RubyRequestType_Load_Linked
) ||
442 (request
->m_type
== RubyRequestType_Store_Conditional
) ||
443 (request
->m_type
== RubyRequestType_Locked_RMW_Read
) ||
444 (request
->m_type
== RubyRequestType_Locked_RMW_Write
) ||
445 (request
->m_type
== RubyRequestType_FLUSH
));
448 // For Alpha, properly handle LL, SC, and write requests with respect to
449 // locked cache blocks.
451 // Not valid for Network_test protocl
454 if(!m_usingNetworkTester
)
455 success
= handleLlsc(address
, request
);
457 if (request
->m_type
== RubyRequestType_Locked_RMW_Read
) {
458 m_controller
->blockOnQueue(address
, m_mandatory_q_ptr
);
459 } else if (request
->m_type
== RubyRequestType_Locked_RMW_Write
) {
460 m_controller
->unblock(address
);
463 hitCallback(request
, data
, success
, mach
, externalHit
,
464 initialRequestTime
, forwardRequestTime
, firstResponseTime
);
468 Sequencer::readCallback(const Address
& address
, DataBlock
& data
,
469 bool externalHit
, const MachineType mach
,
470 Cycles initialRequestTime
,
471 Cycles forwardRequestTime
,
472 Cycles firstResponseTime
)
474 assert(address
== line_address(address
));
475 assert(m_readRequestTable
.count(line_address(address
)));
477 RequestTable::iterator i
= m_readRequestTable
.find(address
);
478 assert(i
!= m_readRequestTable
.end());
479 SequencerRequest
* request
= i
->second
;
481 m_readRequestTable
.erase(i
);
484 assert((request
->m_type
== RubyRequestType_LD
) ||
485 (request
->m_type
== RubyRequestType_IFETCH
));
487 hitCallback(request
, data
, true, mach
, externalHit
,
488 initialRequestTime
, forwardRequestTime
, firstResponseTime
);
492 Sequencer::hitCallback(SequencerRequest
* srequest
, DataBlock
& data
,
494 const MachineType mach
, const bool externalHit
,
495 const Cycles initialRequestTime
,
496 const Cycles forwardRequestTime
,
497 const Cycles firstResponseTime
)
499 PacketPtr pkt
= srequest
->pkt
;
500 Address
request_address(pkt
->getAddr());
501 Address
request_line_address(pkt
->getAddr());
502 request_line_address
.makeLineAddress();
503 RubyRequestType type
= srequest
->m_type
;
504 Cycles issued_time
= srequest
->issue_time
;
506 // Set this cache entry to the most recently used
507 if (type
== RubyRequestType_IFETCH
) {
508 m_instCache_ptr
->setMRU(request_line_address
);
510 m_dataCache_ptr
->setMRU(request_line_address
);
513 assert(curCycle() >= issued_time
);
514 Cycles total_latency
= curCycle() - issued_time
;
516 // Profile the latency for all demand accesses.
517 recordMissLatency(total_latency
, type
, mach
, externalHit
, issued_time
,
518 initialRequestTime
, forwardRequestTime
,
519 firstResponseTime
, curCycle());
521 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
522 curTick(), m_version
, "Seq",
523 llscSuccess
? "Done" : "SC_Failed", "", "",
524 request_address
, total_latency
);
526 // update the data unless it is a non-data-carrying flush
527 if (RubySystem::getWarmupEnabled()) {
528 data
.setData(pkt
->getConstPtr
<uint8_t>(),
529 request_address
.getOffset(), pkt
->getSize());
530 } else if (!pkt
->isFlush()) {
531 if ((type
== RubyRequestType_LD
) ||
532 (type
== RubyRequestType_IFETCH
) ||
533 (type
== RubyRequestType_RMW_Read
) ||
534 (type
== RubyRequestType_Locked_RMW_Read
) ||
535 (type
== RubyRequestType_Load_Linked
)) {
536 memcpy(pkt
->getPtr
<uint8_t>(),
537 data
.getData(request_address
.getOffset(), pkt
->getSize()),
539 DPRINTF(RubySequencer
, "read data %s\n", data
);
541 data
.setData(pkt
->getConstPtr
<uint8_t>(),
542 request_address
.getOffset(), pkt
->getSize());
543 DPRINTF(RubySequencer
, "set data %s\n", data
);
547 // If using the RubyTester, update the RubyTester sender state's
548 // subBlock with the recieved data. The tester will later access
550 if (m_usingRubyTester
) {
551 DPRINTF(RubySequencer
, "hitCallback %s 0x%x using RubyTester\n",
552 pkt
->cmdString(), pkt
->getAddr());
553 RubyTester::SenderState
* testerSenderState
=
554 pkt
->findNextSenderState
<RubyTester::SenderState
>();
555 assert(testerSenderState
);
556 testerSenderState
->subBlock
.mergeFrom(data
);
561 RubySystem
*rs
= m_ruby_system
;
562 if (RubySystem::getWarmupEnabled()) {
566 rs
->m_cache_recorder
->enqueueNextFetchRequest();
567 } else if (RubySystem::getCooldownEnabled()) {
569 rs
->m_cache_recorder
->enqueueNextFlushRequest();
571 ruby_hit_callback(pkt
);
576 Sequencer::empty() const
578 return m_writeRequestTable
.empty() && m_readRequestTable
.empty();
582 Sequencer::makeRequest(PacketPtr pkt
)
584 if (m_outstanding_count
>= m_max_outstanding_requests
) {
585 return RequestStatus_BufferFull
;
588 RubyRequestType primary_type
= RubyRequestType_NULL
;
589 RubyRequestType secondary_type
= RubyRequestType_NULL
;
593 // Alpha LL/SC instructions need to be handled carefully by the cache
594 // coherence protocol to ensure they follow the proper semantics. In
595 // particular, by identifying the operations as atomic, the protocol
596 // should understand that migratory sharing optimizations should not
597 // be performed (i.e. a load between the LL and SC should not steal
598 // away exclusive permission).
600 if (pkt
->isWrite()) {
601 DPRINTF(RubySequencer
, "Issuing SC\n");
602 primary_type
= RubyRequestType_Store_Conditional
;
604 DPRINTF(RubySequencer
, "Issuing LL\n");
605 assert(pkt
->isRead());
606 primary_type
= RubyRequestType_Load_Linked
;
608 secondary_type
= RubyRequestType_ATOMIC
;
609 } else if (pkt
->req
->isLockedRMW()) {
611 // x86 locked instructions are translated to store cache coherence
612 // requests because these requests should always be treated as read
613 // exclusive operations and should leverage any migratory sharing
614 // optimization built into the protocol.
616 if (pkt
->isWrite()) {
617 DPRINTF(RubySequencer
, "Issuing Locked RMW Write\n");
618 primary_type
= RubyRequestType_Locked_RMW_Write
;
620 DPRINTF(RubySequencer
, "Issuing Locked RMW Read\n");
621 assert(pkt
->isRead());
622 primary_type
= RubyRequestType_Locked_RMW_Read
;
624 secondary_type
= RubyRequestType_ST
;
627 if (pkt
->req
->isInstFetch()) {
628 primary_type
= secondary_type
= RubyRequestType_IFETCH
;
630 bool storeCheck
= false;
631 // only X86 need the store check
632 if (system
->getArch() == Arch::X86ISA
) {
633 uint32_t flags
= pkt
->req
->getFlags();
635 (X86ISA::StoreCheck
<< X86ISA::FlagShift
);
638 primary_type
= RubyRequestType_RMW_Read
;
639 secondary_type
= RubyRequestType_ST
;
641 primary_type
= secondary_type
= RubyRequestType_LD
;
644 } else if (pkt
->isWrite()) {
646 // Note: M5 packets do not differentiate ST from RMW_Write
648 primary_type
= secondary_type
= RubyRequestType_ST
;
649 } else if (pkt
->isFlush()) {
650 primary_type
= secondary_type
= RubyRequestType_FLUSH
;
652 panic("Unsupported ruby packet type\n");
656 RequestStatus status
= insertRequest(pkt
, primary_type
);
657 if (status
!= RequestStatus_Ready
)
660 issueRequest(pkt
, secondary_type
);
662 // TODO: issue hardware prefetches here
663 return RequestStatus_Issued
;
667 Sequencer::issueRequest(PacketPtr pkt
, RubyRequestType secondary_type
)
671 if (pkt
->req
->hasContextId()) {
672 proc_id
= pkt
->req
->contextId();
675 // If valid, copy the pc to the ruby request
677 if (pkt
->req
->hasPC()) {
678 pc
= pkt
->req
->getPC();
681 // check if the packet has data as for example prefetch and flush
683 std::shared_ptr
<RubyRequest
> msg
=
684 std::make_shared
<RubyRequest
>(clockEdge(), pkt
->getAddr(),
686 nullptr : pkt
->getPtr
<uint8_t>(),
687 pkt
->getSize(), pc
, secondary_type
,
688 RubyAccessMode_Supervisor
, pkt
,
689 PrefetchBit_No
, proc_id
);
691 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %s %s\n",
692 curTick(), m_version
, "Seq", "Begin", "", "",
693 msg
->getPhysicalAddress(),
694 RubyRequestType_to_string(secondary_type
));
696 Cycles
latency(0); // initialzed to an null value
698 if (secondary_type
== RubyRequestType_IFETCH
)
699 latency
= m_instCache_ptr
->getLatency();
701 latency
= m_dataCache_ptr
->getLatency();
703 // Send the message to the cache controller
706 assert(m_mandatory_q_ptr
!= NULL
);
707 m_mandatory_q_ptr
->enqueue(msg
, latency
);
710 template <class KEY
, class VALUE
>
712 operator<<(ostream
&out
, const m5::hash_map
<KEY
, VALUE
> &map
)
714 typename
m5::hash_map
<KEY
, VALUE
>::const_iterator i
= map
.begin();
715 typename
m5::hash_map
<KEY
, VALUE
>::const_iterator end
= map
.end();
718 for (; i
!= end
; ++i
)
719 out
<< " " << i
->first
<< "=" << i
->second
;
726 Sequencer::print(ostream
& out
) const
728 out
<< "[Sequencer: " << m_version
729 << ", outstanding requests: " << m_outstanding_count
730 << ", read request table: " << m_readRequestTable
731 << ", write request table: " << m_writeRequestTable
735 // this can be called from setState whenever coherence permissions are
736 // upgraded when invoked, coherence violations will be checked for the
739 Sequencer::checkCoherence(const Address
& addr
)
741 #ifdef CHECK_COHERENCE
742 m_ruby_system
->checkGlobalCoherenceInvariant(addr
);
747 Sequencer::recordRequestType(SequencerRequestType requestType
) {
748 DPRINTF(RubyStats
, "Recorded statistic: %s\n",
749 SequencerRequestType_to_string(requestType
));
754 Sequencer::evictionCallback(const Address
& address
)
756 ruby_eviction_callback(address
);
760 Sequencer::regStats()
762 m_store_waiting_on_load
763 .name(name() + ".store_waiting_on_load")
764 .desc("Number of times a store aliased with a pending load")
765 .flags(Stats::nozero
);
766 m_store_waiting_on_store
767 .name(name() + ".store_waiting_on_store")
768 .desc("Number of times a store aliased with a pending store")
769 .flags(Stats::nozero
);
770 m_load_waiting_on_load
771 .name(name() + ".load_waiting_on_load")
772 .desc("Number of times a load aliased with a pending load")
773 .flags(Stats::nozero
);
774 m_load_waiting_on_store
775 .name(name() + ".load_waiting_on_store")
776 .desc("Number of times a load aliased with a pending store")
777 .flags(Stats::nozero
);
779 // These statistical variables are not for display.
780 // The profiler will collate these across different
781 // sequencers and display those collated statistics.
782 m_outstandReqHist
.init(10);
783 m_latencyHist
.init(10);
784 m_hitLatencyHist
.init(10);
785 m_missLatencyHist
.init(10);
787 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
788 m_typeLatencyHist
.push_back(new Stats::Histogram());
789 m_typeLatencyHist
[i
]->init(10);
791 m_hitTypeLatencyHist
.push_back(new Stats::Histogram());
792 m_hitTypeLatencyHist
[i
]->init(10);
794 m_missTypeLatencyHist
.push_back(new Stats::Histogram());
795 m_missTypeLatencyHist
[i
]->init(10);
798 for (int i
= 0; i
< MachineType_NUM
; i
++) {
799 m_hitMachLatencyHist
.push_back(new Stats::Histogram());
800 m_hitMachLatencyHist
[i
]->init(10);
802 m_missMachLatencyHist
.push_back(new Stats::Histogram());
803 m_missMachLatencyHist
[i
]->init(10);
805 m_IssueToInitialDelayHist
.push_back(new Stats::Histogram());
806 m_IssueToInitialDelayHist
[i
]->init(10);
808 m_InitialToForwardDelayHist
.push_back(new Stats::Histogram());
809 m_InitialToForwardDelayHist
[i
]->init(10);
811 m_ForwardToFirstResponseDelayHist
.push_back(new Stats::Histogram());
812 m_ForwardToFirstResponseDelayHist
[i
]->init(10);
814 m_FirstResponseToCompletionDelayHist
.push_back(new Stats::Histogram());
815 m_FirstResponseToCompletionDelayHist
[i
]->init(10);
818 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
819 m_hitTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
820 m_missTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
822 for (int j
= 0; j
< MachineType_NUM
; j
++) {
823 m_hitTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
824 m_hitTypeMachLatencyHist
[i
][j
]->init(10);
826 m_missTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
827 m_missTypeMachLatencyHist
[i
][j
]->init(10);