2 * Copyright (c) 2019-2020 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-2008 Mark D. Hill and David A. Wood
15 * Copyright (c) 2013 Advanced Micro Devices, Inc.
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include "mem/ruby/system/Sequencer.hh"
44 #include "arch/x86/ldstflags.hh"
45 #include "base/logging.hh"
46 #include "base/str.hh"
47 #include "cpu/testers/rubytest/RubyTester.hh"
48 #include "debug/LLSC.hh"
49 #include "debug/MemoryAccess.hh"
50 #include "debug/ProtocolTrace.hh"
51 #include "debug/RubySequencer.hh"
52 #include "debug/RubyStats.hh"
53 #include "mem/packet.hh"
54 #include "mem/ruby/profiler/Profiler.hh"
55 #include "mem/ruby/protocol/PrefetchBit.hh"
56 #include "mem/ruby/protocol/RubyAccessMode.hh"
57 #include "mem/ruby/slicc_interface/RubyRequest.hh"
58 #include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
59 #include "mem/ruby/system/RubySystem.hh"
60 #include "sim/system.hh"
64 Sequencer::Sequencer(const Params
&p
)
65 : RubyPort(p
), m_IncompleteTimes(MachineType_NUM
),
66 deadlockCheckEvent([this]{ wakeup(); }, "Sequencer deadlock check")
68 m_outstanding_count
= 0;
70 m_dataCache_ptr
= p
.dcache
;
71 m_max_outstanding_requests
= p
.max_outstanding_requests
;
72 m_deadlock_threshold
= p
.deadlock_threshold
;
74 m_coreId
= p
.coreid
; // for tracking the two CorePair sequencers
75 assert(m_max_outstanding_requests
> 0);
76 assert(m_deadlock_threshold
> 0);
78 m_runningGarnetStandalone
= p
.garnet_standalone
;
81 Sequencer::~Sequencer()
86 Sequencer::llscLoadLinked(const Addr claddr
)
88 fatal_if(m_dataCache_ptr
== NULL
,
89 "%s must have a dcache object to support LLSC requests.", name());
90 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
92 line
->setLocked(m_version
);
93 DPRINTF(LLSC
, "LLSC Monitor - inserting load linked - "
94 "addr=0x%lx - cpu=%u\n", claddr
, m_version
);
99 Sequencer::llscClearMonitor(const Addr claddr
)
101 // clear monitor is called for all stores and evictions
102 if (m_dataCache_ptr
== NULL
)
104 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
105 if (line
&& line
->isLocked(m_version
)) {
107 DPRINTF(LLSC
, "LLSC Monitor - clearing due to store - "
108 "addr=0x%lx - cpu=%u\n", claddr
, m_version
);
113 Sequencer::llscStoreConditional(const Addr claddr
)
115 fatal_if(m_dataCache_ptr
== NULL
,
116 "%s must have a dcache object to support LLSC requests.", name());
117 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
121 DPRINTF(LLSC
, "LLSC Monitor - clearing due to "
122 "store conditional - "
123 "addr=0x%lx - cpu=%u\n",
126 if (line
->isLocked(m_version
)) {
136 Sequencer::llscCheckMonitor(const Addr address
)
138 assert(m_dataCache_ptr
!= NULL
);
139 const Addr claddr
= makeLineAddress(address
);
140 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
144 if (line
->isLocked(m_version
)) {
152 Sequencer::llscClearLocalMonitor()
154 m_dataCache_ptr
->clearLockedAll(m_version
);
160 assert(drainState() != DrainState::Draining
);
162 // Check for deadlock of any of the requests
163 Cycles current_time
= curCycle();
165 // Check across all outstanding requests
166 int total_outstanding
= 0;
168 for (const auto &table_entry
: m_RequestTable
) {
169 for (const auto &seq_req
: table_entry
.second
) {
170 if (current_time
- seq_req
.issue_time
< m_deadlock_threshold
)
173 panic("Possible Deadlock detected. Aborting!\n version: %d "
174 "request.paddr: 0x%x m_readRequestTable: %d current time: "
175 "%u issue_time: %d difference: %d\n", m_version
,
176 seq_req
.pkt
->getAddr(), table_entry
.second
.size(),
177 current_time
* clockPeriod(), seq_req
.issue_time
178 * clockPeriod(), (current_time
* clockPeriod())
179 - (seq_req
.issue_time
* clockPeriod()));
181 total_outstanding
+= table_entry
.second
.size();
184 assert(m_outstanding_count
== total_outstanding
);
186 if (m_outstanding_count
> 0) {
187 // If there are still outstanding requests, keep checking
188 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
193 Sequencer::functionalWrite(Packet
*func_pkt
)
195 int num_written
= RubyPort::functionalWrite(func_pkt
);
197 for (const auto &table_entry
: m_RequestTable
) {
198 for (const auto& seq_req
: table_entry
.second
) {
199 if (seq_req
.functionalWrite(func_pkt
))
207 void Sequencer::resetStats()
209 m_outstandReqHist
.reset();
210 m_latencyHist
.reset();
211 m_hitLatencyHist
.reset();
212 m_missLatencyHist
.reset();
213 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
214 m_typeLatencyHist
[i
]->reset();
215 m_hitTypeLatencyHist
[i
]->reset();
216 m_missTypeLatencyHist
[i
]->reset();
217 for (int j
= 0; j
< MachineType_NUM
; j
++) {
218 m_hitTypeMachLatencyHist
[i
][j
]->reset();
219 m_missTypeMachLatencyHist
[i
][j
]->reset();
223 for (int i
= 0; i
< MachineType_NUM
; i
++) {
224 m_missMachLatencyHist
[i
]->reset();
225 m_hitMachLatencyHist
[i
]->reset();
227 m_IssueToInitialDelayHist
[i
]->reset();
228 m_InitialToForwardDelayHist
[i
]->reset();
229 m_ForwardToFirstResponseDelayHist
[i
]->reset();
230 m_FirstResponseToCompletionDelayHist
[i
]->reset();
232 m_IncompleteTimes
[i
] = 0;
236 // Insert the request in the request table. Return RequestStatus_Aliased
237 // if the entry was already present.
239 Sequencer::insertRequest(PacketPtr pkt
, RubyRequestType primary_type
,
240 RubyRequestType secondary_type
)
242 // See if we should schedule a deadlock check
243 if (!deadlockCheckEvent
.scheduled() &&
244 drainState() != DrainState::Draining
) {
245 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
248 Addr line_addr
= makeLineAddress(pkt
->getAddr());
249 // Check if there is any outstanding request for the same cache line.
250 auto &seq_req_list
= m_RequestTable
[line_addr
];
251 // Create a default entry
252 seq_req_list
.emplace_back(pkt
, primary_type
,
253 secondary_type
, curCycle());
254 m_outstanding_count
++;
256 if (seq_req_list
.size() > 1) {
257 return RequestStatus_Aliased
;
260 m_outstandReqHist
.sample(m_outstanding_count
);
262 return RequestStatus_Ready
;
266 Sequencer::markRemoved()
268 m_outstanding_count
--;
272 Sequencer::recordMissLatency(SequencerRequest
* srequest
, bool llscSuccess
,
273 const MachineType respondingMach
,
274 bool isExternalHit
, Cycles initialRequestTime
,
275 Cycles forwardRequestTime
,
276 Cycles firstResponseTime
)
278 RubyRequestType type
= srequest
->m_type
;
279 Cycles issued_time
= srequest
->issue_time
;
280 Cycles completion_time
= curCycle();
282 assert(curCycle() >= issued_time
);
283 Cycles total_lat
= completion_time
- issued_time
;
285 if (initialRequestTime
< issued_time
) {
286 // if the request was combined in the protocol with an earlier request
287 // for the same address, it is possible that it will return an
288 // initialRequestTime corresponding the earlier request. Since Cycles
289 // is unsigned, we can't let this request get profiled below.
291 total_lat
= Cycles(0);
294 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
295 curTick(), m_version
, "Seq", llscSuccess
? "Done" : "SC_Failed",
296 "", "", printAddress(srequest
->pkt
->getAddr()), total_lat
);
298 m_latencyHist
.sample(total_lat
);
299 m_typeLatencyHist
[type
]->sample(total_lat
);
302 m_missLatencyHist
.sample(total_lat
);
303 m_missTypeLatencyHist
[type
]->sample(total_lat
);
305 if (respondingMach
!= MachineType_NUM
) {
306 m_missMachLatencyHist
[respondingMach
]->sample(total_lat
);
307 m_missTypeMachLatencyHist
[type
][respondingMach
]->sample(total_lat
);
309 if ((issued_time
<= initialRequestTime
) &&
310 (initialRequestTime
<= forwardRequestTime
) &&
311 (forwardRequestTime
<= firstResponseTime
) &&
312 (firstResponseTime
<= completion_time
)) {
314 m_IssueToInitialDelayHist
[respondingMach
]->sample(
315 initialRequestTime
- issued_time
);
316 m_InitialToForwardDelayHist
[respondingMach
]->sample(
317 forwardRequestTime
- initialRequestTime
);
318 m_ForwardToFirstResponseDelayHist
[respondingMach
]->sample(
319 firstResponseTime
- forwardRequestTime
);
320 m_FirstResponseToCompletionDelayHist
[respondingMach
]->sample(
321 completion_time
- firstResponseTime
);
323 m_IncompleteTimes
[respondingMach
]++;
327 m_hitLatencyHist
.sample(total_lat
);
328 m_hitTypeLatencyHist
[type
]->sample(total_lat
);
330 if (respondingMach
!= MachineType_NUM
) {
331 m_hitMachLatencyHist
[respondingMach
]->sample(total_lat
);
332 m_hitTypeMachLatencyHist
[type
][respondingMach
]->sample(total_lat
);
338 Sequencer::writeCallbackScFail(Addr address
, DataBlock
& data
)
340 llscClearMonitor(address
);
341 writeCallback(address
, data
);
345 Sequencer::writeCallback(Addr address
, DataBlock
& data
,
346 const bool externalHit
, const MachineType mach
,
347 const Cycles initialRequestTime
,
348 const Cycles forwardRequestTime
,
349 const Cycles firstResponseTime
,
353 // Free the whole list as we assume we have had the exclusive access
354 // to this cache line when response for the write comes back
356 assert(address
== makeLineAddress(address
));
357 assert(m_RequestTable
.find(address
) != m_RequestTable
.end());
358 auto &seq_req_list
= m_RequestTable
[address
];
360 // Perform hitCallback on every cpu request made to this cache block while
361 // ruby request was outstanding. Since only 1 ruby request was made,
362 // profile the ruby latency once.
363 bool ruby_request
= true;
364 int aliased_stores
= 0;
365 int aliased_loads
= 0;
366 while (!seq_req_list
.empty()) {
367 SequencerRequest
&seq_req
= seq_req_list
.front();
369 if (noCoales
&& !ruby_request
) {
370 // Do not process follow-up requests
371 // (e.g. if full line no present)
372 // Reissue to the cache hierarchy
373 issueRequest(seq_req
.pkt
, seq_req
.m_second_type
);
378 assert(seq_req
.m_type
!= RubyRequestType_LD
);
379 assert(seq_req
.m_type
!= RubyRequestType_Load_Linked
);
380 assert(seq_req
.m_type
!= RubyRequestType_IFETCH
);
383 // handle write request
384 if ((seq_req
.m_type
!= RubyRequestType_LD
) &&
385 (seq_req
.m_type
!= RubyRequestType_Load_Linked
) &&
386 (seq_req
.m_type
!= RubyRequestType_IFETCH
)) {
387 // LL/SC support (tested with ARMv8)
390 if (seq_req
.m_type
!= RubyRequestType_Store_Conditional
) {
391 // Regular stores to addresses being monitored
392 // will fail (remove) the monitor entry.
393 llscClearMonitor(address
);
395 // Store conditionals must first check the monitor
396 // if they will succeed or not
397 success
= llscStoreConditional(address
);
398 seq_req
.pkt
->req
->setExtraData(success
? 1 : 0);
401 // Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the
402 // address variable here is assumed to be a line address, so when
403 // blocking buffers, must check line addresses.
404 if (seq_req
.m_type
== RubyRequestType_Locked_RMW_Read
) {
405 // blockOnQueue blocks all first-level cache controller queues
406 // waiting on memory accesses for the specified address that go
407 // to the specified queue. In this case, a Locked_RMW_Write must
408 // go to the mandatory_q before unblocking the first-level
409 // controller. This will block standard loads, stores, ifetches,
411 m_controller
->blockOnQueue(address
, m_mandatory_q_ptr
);
412 } else if (seq_req
.m_type
== RubyRequestType_Locked_RMW_Write
) {
413 m_controller
->unblock(address
);
417 recordMissLatency(&seq_req
, success
, mach
, externalHit
,
418 initialRequestTime
, forwardRequestTime
,
424 ruby_request
= false;
425 hitCallback(&seq_req
, data
, success
, mach
, externalHit
,
426 initialRequestTime
, forwardRequestTime
,
429 // handle read request
430 assert(!ruby_request
);
432 ruby_request
= false;
434 hitCallback(&seq_req
, data
, true, mach
, externalHit
,
435 initialRequestTime
, forwardRequestTime
,
438 seq_req_list
.pop_front();
441 // free all outstanding requests corresponding to this address
442 if (seq_req_list
.empty()) {
443 m_RequestTable
.erase(address
);
448 Sequencer::readCallback(Addr address
, DataBlock
& data
,
449 bool externalHit
, const MachineType mach
,
450 Cycles initialRequestTime
,
451 Cycles forwardRequestTime
,
452 Cycles firstResponseTime
)
455 // Free up read requests until we hit the first Write request
456 // or end of the corresponding list.
458 assert(address
== makeLineAddress(address
));
459 assert(m_RequestTable
.find(address
) != m_RequestTable
.end());
460 auto &seq_req_list
= m_RequestTable
[address
];
462 // Perform hitCallback on every cpu request made to this cache block while
463 // ruby request was outstanding. Since only 1 ruby request was made,
464 // profile the ruby latency once.
465 bool ruby_request
= true;
466 int aliased_loads
= 0;
467 while (!seq_req_list
.empty()) {
468 SequencerRequest
&seq_req
= seq_req_list
.front();
470 assert((seq_req
.m_type
== RubyRequestType_LD
) ||
471 (seq_req
.m_type
== RubyRequestType_Load_Linked
) ||
472 (seq_req
.m_type
== RubyRequestType_IFETCH
));
476 if ((seq_req
.m_type
!= RubyRequestType_LD
) &&
477 (seq_req
.m_type
!= RubyRequestType_Load_Linked
) &&
478 (seq_req
.m_type
!= RubyRequestType_IFETCH
)) {
479 // Write request: reissue request to the cache hierarchy
480 issueRequest(seq_req
.pkt
, seq_req
.m_second_type
);
484 recordMissLatency(&seq_req
, true, mach
, externalHit
,
485 initialRequestTime
, forwardRequestTime
,
489 ruby_request
= false;
490 hitCallback(&seq_req
, data
, true, mach
, externalHit
,
491 initialRequestTime
, forwardRequestTime
,
493 seq_req_list
.pop_front();
496 // free all outstanding requests corresponding to this address
497 if (seq_req_list
.empty()) {
498 m_RequestTable
.erase(address
);
503 Sequencer::hitCallback(SequencerRequest
* srequest
, DataBlock
& data
,
505 const MachineType mach
, const bool externalHit
,
506 const Cycles initialRequestTime
,
507 const Cycles forwardRequestTime
,
508 const Cycles firstResponseTime
)
510 warn_once("Replacement policy updates recently became the responsibility "
511 "of SLICC state machines. Make sure to setMRU() near callbacks "
514 PacketPtr pkt
= srequest
->pkt
;
515 Addr
request_address(pkt
->getAddr());
516 RubyRequestType type
= srequest
->m_type
;
518 // Load-linked handling
519 if (type
== RubyRequestType_Load_Linked
) {
520 Addr line_addr
= makeLineAddress(request_address
);
521 llscLoadLinked(line_addr
);
524 // update the data unless it is a non-data-carrying flush
525 if (RubySystem::getWarmupEnabled()) {
526 data
.setData(pkt
->getConstPtr
<uint8_t>(),
527 getOffset(request_address
), pkt
->getSize());
528 } else if (!pkt
->isFlush()) {
529 if ((type
== RubyRequestType_LD
) ||
530 (type
== RubyRequestType_IFETCH
) ||
531 (type
== RubyRequestType_RMW_Read
) ||
532 (type
== RubyRequestType_Locked_RMW_Read
) ||
533 (type
== RubyRequestType_Load_Linked
)) {
535 data
.getData(getOffset(request_address
), pkt
->getSize()));
536 DPRINTF(RubySequencer
, "read data %s\n", data
);
537 } else if (pkt
->req
->isSwap()) {
538 std::vector
<uint8_t> overwrite_val(pkt
->getSize());
539 pkt
->writeData(&overwrite_val
[0]);
541 data
.getData(getOffset(request_address
), pkt
->getSize()));
542 data
.setData(&overwrite_val
[0],
543 getOffset(request_address
), pkt
->getSize());
544 DPRINTF(RubySequencer
, "swap data %s\n", data
);
545 } else if (type
!= RubyRequestType_Store_Conditional
|| llscSuccess
) {
546 // Types of stores set the actual data here, apart from
547 // failed Store Conditional requests
548 data
.setData(pkt
->getConstPtr
<uint8_t>(),
549 getOffset(request_address
), pkt
->getSize());
550 DPRINTF(RubySequencer
, "set data %s\n", data
);
554 // If using the RubyTester, update the RubyTester sender state's
555 // subBlock with the recieved data. The tester will later access
557 if (m_usingRubyTester
) {
558 DPRINTF(RubySequencer
, "hitCallback %s 0x%x using RubyTester\n",
559 pkt
->cmdString(), pkt
->getAddr());
560 RubyTester::SenderState
* testerSenderState
=
561 pkt
->findNextSenderState
<RubyTester::SenderState
>();
562 assert(testerSenderState
);
563 testerSenderState
->subBlock
.mergeFrom(data
);
566 RubySystem
*rs
= m_ruby_system
;
567 if (RubySystem::getWarmupEnabled()) {
570 rs
->m_cache_recorder
->enqueueNextFetchRequest();
571 } else if (RubySystem::getCooldownEnabled()) {
573 rs
->m_cache_recorder
->enqueueNextFlushRequest();
575 ruby_hit_callback(pkt
);
581 Sequencer::empty() const
583 return m_RequestTable
.empty();
587 Sequencer::makeRequest(PacketPtr pkt
)
589 // HTM abort signals must be allowed to reach the Sequencer
590 // the same cycle they are issued. They cannot be retried.
591 if ((m_outstanding_count
>= m_max_outstanding_requests
) &&
592 !pkt
->req
->isHTMAbort()) {
593 return RequestStatus_BufferFull
;
596 RubyRequestType primary_type
= RubyRequestType_NULL
;
597 RubyRequestType secondary_type
= RubyRequestType_NULL
;
600 // LL/SC instructions need to be handled carefully by the cache
601 // coherence protocol to ensure they follow the proper semantics. In
602 // particular, by identifying the operations as atomic, the protocol
603 // should understand that migratory sharing optimizations should not
604 // be performed (i.e. a load between the LL and SC should not steal
605 // away exclusive permission).
607 // The following logic works correctly with the semantics
608 // of armV8 LDEX/STEX instructions.
610 if (pkt
->isWrite()) {
611 DPRINTF(RubySequencer
, "Issuing SC\n");
612 primary_type
= RubyRequestType_Store_Conditional
;
613 #if defined (PROTOCOL_MESI_Three_Level) || defined (PROTOCOL_MESI_Three_Level_HTM)
614 secondary_type
= RubyRequestType_Store_Conditional
;
616 secondary_type
= RubyRequestType_ST
;
619 DPRINTF(RubySequencer
, "Issuing LL\n");
620 assert(pkt
->isRead());
621 primary_type
= RubyRequestType_Load_Linked
;
622 secondary_type
= RubyRequestType_LD
;
624 } else if (pkt
->req
->isLockedRMW()) {
626 // x86 locked instructions are translated to store cache coherence
627 // requests because these requests should always be treated as read
628 // exclusive operations and should leverage any migratory sharing
629 // optimization built into the protocol.
631 if (pkt
->isWrite()) {
632 DPRINTF(RubySequencer
, "Issuing Locked RMW Write\n");
633 primary_type
= RubyRequestType_Locked_RMW_Write
;
635 DPRINTF(RubySequencer
, "Issuing Locked RMW Read\n");
636 assert(pkt
->isRead());
637 primary_type
= RubyRequestType_Locked_RMW_Read
;
639 secondary_type
= RubyRequestType_ST
;
642 // To support SwapReq, we need to check isWrite() first: a SwapReq
643 // should always be treated like a write, but since a SwapReq implies
644 // both isWrite() and isRead() are true, check isWrite() first here.
646 if (pkt
->isWrite()) {
648 // Note: M5 packets do not differentiate ST from RMW_Write
650 primary_type
= secondary_type
= RubyRequestType_ST
;
651 } else if (pkt
->isRead()) {
652 // hardware transactional memory commands
653 if (pkt
->req
->isHTMCmd()) {
654 primary_type
= secondary_type
= htmCmdToRubyRequestType(pkt
);
655 } else if (pkt
->req
->isInstFetch()) {
656 primary_type
= secondary_type
= RubyRequestType_IFETCH
;
658 bool storeCheck
= false;
659 // only X86 need the store check
660 if (system
->getArch() == Arch::X86ISA
) {
661 uint32_t flags
= pkt
->req
->getFlags();
663 (X86ISA::StoreCheck
<< X86ISA::FlagShift
);
666 primary_type
= RubyRequestType_RMW_Read
;
667 secondary_type
= RubyRequestType_ST
;
669 primary_type
= secondary_type
= RubyRequestType_LD
;
672 } else if (pkt
->isFlush()) {
673 primary_type
= secondary_type
= RubyRequestType_FLUSH
;
675 panic("Unsupported ruby packet type\n");
679 // Check if the line is blocked for a Locked_RMW
680 if (m_controller
->isBlocked(makeLineAddress(pkt
->getAddr())) &&
681 (primary_type
!= RubyRequestType_Locked_RMW_Write
)) {
682 // Return that this request's cache line address aliases with
683 // a prior request that locked the cache line. The request cannot
684 // proceed until the cache line is unlocked by a Locked_RMW_Write
685 return RequestStatus_Aliased
;
688 RequestStatus status
= insertRequest(pkt
, primary_type
, secondary_type
);
690 // It is OK to receive RequestStatus_Aliased, it can be considered Issued
691 if (status
!= RequestStatus_Ready
&& status
!= RequestStatus_Aliased
)
693 // non-aliased with any existing request in the request table, just issue
695 if (status
!= RequestStatus_Aliased
)
696 issueRequest(pkt
, secondary_type
);
698 // TODO: issue hardware prefetches here
699 return RequestStatus_Issued
;
703 Sequencer::issueRequest(PacketPtr pkt
, RubyRequestType secondary_type
)
706 ContextID proc_id
= pkt
->req
->hasContextId() ?
707 pkt
->req
->contextId() : InvalidContextID
;
709 ContextID core_id
= coreId();
711 // If valid, copy the pc to the ruby request
713 if (pkt
->req
->hasPC()) {
714 pc
= pkt
->req
->getPC();
717 // check if the packet has data as for example prefetch and flush
719 std::shared_ptr
<RubyRequest
> msg
=
720 std::make_shared
<RubyRequest
>(clockEdge(), pkt
->getAddr(),
722 nullptr : pkt
->getPtr
<uint8_t>(),
723 pkt
->getSize(), pc
, secondary_type
,
724 RubyAccessMode_Supervisor
, pkt
,
725 PrefetchBit_No
, proc_id
, core_id
);
727 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %#x %s\n",
728 curTick(), m_version
, "Seq", "Begin", "", "",
729 printAddress(msg
->getPhysicalAddress()),
730 RubyRequestType_to_string(secondary_type
));
732 // hardware transactional memory
733 // If the request originates in a transaction,
734 // then mark the Ruby message as such.
735 if (pkt
->isHtmTransactional()) {
736 msg
->m_htmFromTransaction
= true;
737 msg
->m_htmTransactionUid
= pkt
->getHtmTransactionUid();
740 Tick latency
= cyclesToTicks(
741 m_controller
->mandatoryQueueLatency(secondary_type
));
744 assert(m_mandatory_q_ptr
!= NULL
);
745 m_mandatory_q_ptr
->enqueue(msg
, clockEdge(), latency
);
748 template <class KEY
, class VALUE
>
750 operator<<(ostream
&out
, const std::unordered_map
<KEY
, VALUE
> &map
)
752 for (const auto &table_entry
: map
) {
753 out
<< "[ " << table_entry
.first
<< " =";
754 for (const auto &seq_req
: table_entry
.second
) {
755 out
<< " " << RubyRequestType_to_string(seq_req
.m_second_type
);
764 Sequencer::print(ostream
& out
) const
766 out
<< "[Sequencer: " << m_version
767 << ", outstanding requests: " << m_outstanding_count
768 << ", request table: " << m_RequestTable
773 Sequencer::recordRequestType(SequencerRequestType requestType
) {
774 DPRINTF(RubyStats
, "Recorded statistic: %s\n",
775 SequencerRequestType_to_string(requestType
));
779 Sequencer::evictionCallback(Addr address
)
781 llscClearMonitor(address
);
782 ruby_eviction_callback(address
);
786 Sequencer::regStats()
788 RubyPort::regStats();
790 // These statistical variables are not for display.
791 // The profiler will collate these across different
792 // sequencers and display those collated statistics.
793 m_outstandReqHist
.init(10);
794 m_latencyHist
.init(10);
795 m_hitLatencyHist
.init(10);
796 m_missLatencyHist
.init(10);
798 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
799 m_typeLatencyHist
.push_back(new Stats::Histogram());
800 m_typeLatencyHist
[i
]->init(10);
802 m_hitTypeLatencyHist
.push_back(new Stats::Histogram());
803 m_hitTypeLatencyHist
[i
]->init(10);
805 m_missTypeLatencyHist
.push_back(new Stats::Histogram());
806 m_missTypeLatencyHist
[i
]->init(10);
809 for (int i
= 0; i
< MachineType_NUM
; i
++) {
810 m_hitMachLatencyHist
.push_back(new Stats::Histogram());
811 m_hitMachLatencyHist
[i
]->init(10);
813 m_missMachLatencyHist
.push_back(new Stats::Histogram());
814 m_missMachLatencyHist
[i
]->init(10);
816 m_IssueToInitialDelayHist
.push_back(new Stats::Histogram());
817 m_IssueToInitialDelayHist
[i
]->init(10);
819 m_InitialToForwardDelayHist
.push_back(new Stats::Histogram());
820 m_InitialToForwardDelayHist
[i
]->init(10);
822 m_ForwardToFirstResponseDelayHist
.push_back(new Stats::Histogram());
823 m_ForwardToFirstResponseDelayHist
[i
]->init(10);
825 m_FirstResponseToCompletionDelayHist
.push_back(new Stats::Histogram());
826 m_FirstResponseToCompletionDelayHist
[i
]->init(10);
829 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
830 m_hitTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
831 m_missTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
833 for (int j
= 0; j
< MachineType_NUM
; j
++) {
834 m_hitTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
835 m_hitTypeMachLatencyHist
[i
][j
]->init(10);
837 m_missTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
838 m_missTypeMachLatencyHist
[i
][j
]->init(10);