Sequencer.cc (10089:bc3126a05a7f) Sequencer.cc (10467:dcf27c8220ac)
1/*
2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
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.
15 *
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.
27 */
28
1/*
2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
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.
15 *
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.
27 */
28
29#include "arch/x86/ldstflags.hh"
29#include "base/misc.hh"
30#include "base/str.hh"
30#include "base/misc.hh"
31#include "base/str.hh"
31#include "config/the_isa.hh"
32#if THE_ISA == X86_ISA
33#include "arch/x86/insts/microldstop.hh"
34#endif // X86_ISA
35#include "cpu/testers/rubytest/RubyTester.hh"
36#include "debug/MemoryAccess.hh"
37#include "debug/ProtocolTrace.hh"
38#include "debug/RubySequencer.hh"
39#include "debug/RubyStats.hh"
40#include "mem/protocol/PrefetchBit.hh"
41#include "mem/protocol/RubyAccessMode.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/Sequencer.hh"
46#include "mem/ruby/system/System.hh"
47#include "mem/packet.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/common/Global.hh"
40#include "mem/ruby/profiler/Profiler.hh"
41#include "mem/ruby/slicc_interface/RubyRequest.hh"
42#include "mem/ruby/system/Sequencer.hh"
43#include "mem/ruby/system/System.hh"
44#include "mem/packet.hh"
45#include "sim/system.hh"
48
49using namespace std;
50
51Sequencer *
52RubySequencerParams::create()
53{
54 return new Sequencer(this);
55}
56
57Sequencer::Sequencer(const Params *p)
58 : RubyPort(p), m_IncompleteTimes(MachineType_NUM), deadlockCheckEvent(this)
59{
60 m_outstanding_count = 0;
61
62 m_instCache_ptr = p->icache;
63 m_dataCache_ptr = p->dcache;
64 m_max_outstanding_requests = p->max_outstanding_requests;
65 m_deadlock_threshold = p->deadlock_threshold;
66
67 assert(m_max_outstanding_requests > 0);
68 assert(m_deadlock_threshold > 0);
69 assert(m_instCache_ptr != NULL);
70 assert(m_dataCache_ptr != NULL);
71
72 m_usingNetworkTester = p->using_network_tester;
73}
74
75Sequencer::~Sequencer()
76{
77}
78
79void
80Sequencer::wakeup()
81{
82 assert(getDrainState() != Drainable::Draining);
83
84 // Check for deadlock of any of the requests
85 Cycles current_time = curCycle();
86
87 // Check across all outstanding requests
88 int total_outstanding = 0;
89
90 RequestTable::iterator read = m_readRequestTable.begin();
91 RequestTable::iterator read_end = m_readRequestTable.end();
92 for (; read != read_end; ++read) {
93 SequencerRequest* request = read->second;
94 if (current_time - request->issue_time < m_deadlock_threshold)
95 continue;
96
97 panic("Possible Deadlock detected. Aborting!\n"
98 "version: %d request.paddr: 0x%x m_readRequestTable: %d "
99 "current time: %u issue_time: %d difference: %d\n", m_version,
100 Address(request->pkt->getAddr()), m_readRequestTable.size(),
101 current_time * clockPeriod(), request->issue_time * clockPeriod(),
102 (current_time * clockPeriod()) - (request->issue_time * clockPeriod()));
103 }
104
105 RequestTable::iterator write = m_writeRequestTable.begin();
106 RequestTable::iterator write_end = m_writeRequestTable.end();
107 for (; write != write_end; ++write) {
108 SequencerRequest* request = write->second;
109 if (current_time - request->issue_time < m_deadlock_threshold)
110 continue;
111
112 panic("Possible Deadlock detected. Aborting!\n"
113 "version: %d request.paddr: 0x%x m_writeRequestTable: %d "
114 "current time: %u issue_time: %d difference: %d\n", m_version,
115 Address(request->pkt->getAddr()), m_writeRequestTable.size(),
116 current_time * clockPeriod(), request->issue_time * clockPeriod(),
117 (current_time * clockPeriod()) - (request->issue_time * clockPeriod()));
118 }
119
120 total_outstanding += m_writeRequestTable.size();
121 total_outstanding += m_readRequestTable.size();
122
123 assert(m_outstanding_count == total_outstanding);
124
125 if (m_outstanding_count > 0) {
126 // If there are still outstanding requests, keep checking
127 schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
128 }
129}
130
131void Sequencer::resetStats()
132{
133 m_latencyHist.reset();
134 m_hitLatencyHist.reset();
135 m_missLatencyHist.reset();
136 for (int i = 0; i < RubyRequestType_NUM; i++) {
137 m_typeLatencyHist[i]->reset();
138 m_hitTypeLatencyHist[i]->reset();
139 m_missTypeLatencyHist[i]->reset();
140 for (int j = 0; j < MachineType_NUM; j++) {
141 m_hitTypeMachLatencyHist[i][j]->reset();
142 m_missTypeMachLatencyHist[i][j]->reset();
143 }
144 }
145
146 for (int i = 0; i < MachineType_NUM; i++) {
147 m_missMachLatencyHist[i]->reset();
148 m_hitMachLatencyHist[i]->reset();
149
150 m_IssueToInitialDelayHist[i]->reset();
151 m_InitialToForwardDelayHist[i]->reset();
152 m_ForwardToFirstResponseDelayHist[i]->reset();
153 m_FirstResponseToCompletionDelayHist[i]->reset();
154
155 m_IncompleteTimes[i] = 0;
156 }
157}
158
159void
160Sequencer::printProgress(ostream& out) const
161{
162#if 0
163 int total_demand = 0;
164 out << "Sequencer Stats Version " << m_version << endl;
165 out << "Current time = " << g_system_ptr->getTime() << endl;
166 out << "---------------" << endl;
167 out << "outstanding requests" << endl;
168
169 out << "proc " << m_Read
170 << " version Requests = " << m_readRequestTable.size() << endl;
171
172 // print the request table
173 RequestTable::iterator read = m_readRequestTable.begin();
174 RequestTable::iterator read_end = m_readRequestTable.end();
175 for (; read != read_end; ++read) {
176 SequencerRequest* request = read->second;
177 out << "\tRequest[ " << i << " ] = " << request->type
178 << " Address " << rkeys[i]
179 << " Posted " << request->issue_time
180 << " PF " << PrefetchBit_No << endl;
181 total_demand++;
182 }
183
184 out << "proc " << m_version
185 << " Write Requests = " << m_writeRequestTable.size << endl;
186
187 // print the request table
188 RequestTable::iterator write = m_writeRequestTable.begin();
189 RequestTable::iterator write_end = m_writeRequestTable.end();
190 for (; write != write_end; ++write) {
191 SequencerRequest* request = write->second;
192 out << "\tRequest[ " << i << " ] = " << request.getType()
193 << " Address " << wkeys[i]
194 << " Posted " << request.getTime()
195 << " PF " << request.getPrefetch() << endl;
196 if (request.getPrefetch() == PrefetchBit_No) {
197 total_demand++;
198 }
199 }
200
201 out << endl;
202
203 out << "Total Number Outstanding: " << m_outstanding_count << endl
204 << "Total Number Demand : " << total_demand << endl
205 << "Total Number Prefetches : " << m_outstanding_count - total_demand
206 << endl << endl << endl;
207#endif
208}
209
210// Insert the request on the correct request table. Return true if
211// the entry was already present.
212RequestStatus
213Sequencer::insertRequest(PacketPtr pkt, RubyRequestType request_type)
214{
215 assert(m_outstanding_count ==
216 (m_writeRequestTable.size() + m_readRequestTable.size()));
217
218 // See if we should schedule a deadlock check
219 if (!deadlockCheckEvent.scheduled() &&
220 getDrainState() != Drainable::Draining) {
221 schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
222 }
223
224 Address line_addr(pkt->getAddr());
225 line_addr.makeLineAddress();
226 // Create a default entry, mapping the address to NULL, the cast is
227 // there to make gcc 4.4 happy
228 RequestTable::value_type default_entry(line_addr,
229 (SequencerRequest*) NULL);
230
231 if ((request_type == RubyRequestType_ST) ||
232 (request_type == RubyRequestType_RMW_Read) ||
233 (request_type == RubyRequestType_RMW_Write) ||
234 (request_type == RubyRequestType_Load_Linked) ||
235 (request_type == RubyRequestType_Store_Conditional) ||
236 (request_type == RubyRequestType_Locked_RMW_Read) ||
237 (request_type == RubyRequestType_Locked_RMW_Write) ||
238 (request_type == RubyRequestType_FLUSH)) {
239
240 // Check if there is any outstanding read request for the same
241 // cache line.
242 if (m_readRequestTable.count(line_addr) > 0) {
243 m_store_waiting_on_load++;
244 return RequestStatus_Aliased;
245 }
246
247 pair<RequestTable::iterator, bool> r =
248 m_writeRequestTable.insert(default_entry);
249 if (r.second) {
250 RequestTable::iterator i = r.first;
251 i->second = new SequencerRequest(pkt, request_type, curCycle());
252 m_outstanding_count++;
253 } else {
254 // There is an outstanding write request for the cache line
255 m_store_waiting_on_store++;
256 return RequestStatus_Aliased;
257 }
258 } else {
259 // Check if there is any outstanding write request for the same
260 // cache line.
261 if (m_writeRequestTable.count(line_addr) > 0) {
262 m_load_waiting_on_store++;
263 return RequestStatus_Aliased;
264 }
265
266 pair<RequestTable::iterator, bool> r =
267 m_readRequestTable.insert(default_entry);
268
269 if (r.second) {
270 RequestTable::iterator i = r.first;
271 i->second = new SequencerRequest(pkt, request_type, curCycle());
272 m_outstanding_count++;
273 } else {
274 // There is an outstanding read request for the cache line
275 m_load_waiting_on_load++;
276 return RequestStatus_Aliased;
277 }
278 }
279
280 m_outstandReqHist.sample(m_outstanding_count);
281 assert(m_outstanding_count ==
282 (m_writeRequestTable.size() + m_readRequestTable.size()));
283
284 return RequestStatus_Ready;
285}
286
287void
288Sequencer::markRemoved()
289{
290 m_outstanding_count--;
291 assert(m_outstanding_count ==
292 m_writeRequestTable.size() + m_readRequestTable.size());
293}
294
295void
296Sequencer::removeRequest(SequencerRequest* srequest)
297{
298 assert(m_outstanding_count ==
299 m_writeRequestTable.size() + m_readRequestTable.size());
300
301 Address line_addr(srequest->pkt->getAddr());
302 line_addr.makeLineAddress();
303 if ((srequest->m_type == RubyRequestType_ST) ||
304 (srequest->m_type == RubyRequestType_RMW_Read) ||
305 (srequest->m_type == RubyRequestType_RMW_Write) ||
306 (srequest->m_type == RubyRequestType_Load_Linked) ||
307 (srequest->m_type == RubyRequestType_Store_Conditional) ||
308 (srequest->m_type == RubyRequestType_Locked_RMW_Read) ||
309 (srequest->m_type == RubyRequestType_Locked_RMW_Write)) {
310 m_writeRequestTable.erase(line_addr);
311 } else {
312 m_readRequestTable.erase(line_addr);
313 }
314
315 markRemoved();
316}
317
318void
319Sequencer::invalidateSC(const Address& address)
320{
321 RequestTable::iterator i = m_writeRequestTable.find(address);
322 if (i != m_writeRequestTable.end()) {
323 SequencerRequest* request = i->second;
324 // The controller has lost the coherence permissions, hence the lock
325 // on the cache line maintained by the cache should be cleared.
326 if (request->m_type == RubyRequestType_Store_Conditional) {
327 m_dataCache_ptr->clearLocked(address);
328 }
329 }
330}
331
332bool
333Sequencer::handleLlsc(const Address& address, SequencerRequest* request)
334{
335 //
336 // The success flag indicates whether the LLSC operation was successful.
337 // LL ops will always succeed, but SC may fail if the cache line is no
338 // longer locked.
339 //
340 bool success = true;
341 if (request->m_type == RubyRequestType_Store_Conditional) {
342 if (!m_dataCache_ptr->isLocked(address, m_version)) {
343 //
344 // For failed SC requests, indicate the failure to the cpu by
345 // setting the extra data to zero.
346 //
347 request->pkt->req->setExtraData(0);
348 success = false;
349 } else {
350 //
351 // For successful SC requests, indicate the success to the cpu by
352 // setting the extra data to one.
353 //
354 request->pkt->req->setExtraData(1);
355 }
356 //
357 // Independent of success, all SC operations must clear the lock
358 //
359 m_dataCache_ptr->clearLocked(address);
360 } else if (request->m_type == RubyRequestType_Load_Linked) {
361 //
362 // Note: To fully follow Alpha LLSC semantics, should the LL clear any
363 // previously locked cache lines?
364 //
365 m_dataCache_ptr->setLocked(address, m_version);
366 } else if ((m_dataCache_ptr->isTagPresent(address)) &&
367 (m_dataCache_ptr->isLocked(address, m_version))) {
368 //
369 // Normal writes should clear the locked address
370 //
371 m_dataCache_ptr->clearLocked(address);
372 }
373 return success;
374}
375
376void
377Sequencer::recordMissLatency(const Cycles cycles, const RubyRequestType type,
378 const MachineType respondingMach,
379 bool isExternalHit, Cycles issuedTime,
380 Cycles initialRequestTime,
381 Cycles forwardRequestTime,
382 Cycles firstResponseTime, Cycles completionTime)
383{
384 m_latencyHist.sample(cycles);
385 m_typeLatencyHist[type]->sample(cycles);
386
387 if (isExternalHit) {
388 m_missLatencyHist.sample(cycles);
389 m_missTypeLatencyHist[type]->sample(cycles);
390
391 if (respondingMach != MachineType_NUM) {
392 m_missMachLatencyHist[respondingMach]->sample(cycles);
393 m_missTypeMachLatencyHist[type][respondingMach]->sample(cycles);
394
395 if ((issuedTime <= initialRequestTime) &&
396 (initialRequestTime <= forwardRequestTime) &&
397 (forwardRequestTime <= firstResponseTime) &&
398 (firstResponseTime <= completionTime)) {
399
400 m_IssueToInitialDelayHist[respondingMach]->sample(
401 initialRequestTime - issuedTime);
402 m_InitialToForwardDelayHist[respondingMach]->sample(
403 forwardRequestTime - initialRequestTime);
404 m_ForwardToFirstResponseDelayHist[respondingMach]->sample(
405 firstResponseTime - forwardRequestTime);
406 m_FirstResponseToCompletionDelayHist[respondingMach]->sample(
407 completionTime - firstResponseTime);
408 } else {
409 m_IncompleteTimes[respondingMach]++;
410 }
411 }
412 } else {
413 m_hitLatencyHist.sample(cycles);
414 m_hitTypeLatencyHist[type]->sample(cycles);
415
416 if (respondingMach != MachineType_NUM) {
417 m_hitMachLatencyHist[respondingMach]->sample(cycles);
418 m_hitTypeMachLatencyHist[type][respondingMach]->sample(cycles);
419 }
420 }
421}
422
423void
424Sequencer::writeCallback(const Address& address, DataBlock& data,
425 const bool externalHit, const MachineType mach,
426 const Cycles initialRequestTime,
427 const Cycles forwardRequestTime,
428 const Cycles firstResponseTime)
429{
430 assert(address == line_address(address));
431 assert(m_writeRequestTable.count(line_address(address)));
432
433 RequestTable::iterator i = m_writeRequestTable.find(address);
434 assert(i != m_writeRequestTable.end());
435 SequencerRequest* request = i->second;
436
437 m_writeRequestTable.erase(i);
438 markRemoved();
439
440 assert((request->m_type == RubyRequestType_ST) ||
441 (request->m_type == RubyRequestType_ATOMIC) ||
442 (request->m_type == RubyRequestType_RMW_Read) ||
443 (request->m_type == RubyRequestType_RMW_Write) ||
444 (request->m_type == RubyRequestType_Load_Linked) ||
445 (request->m_type == RubyRequestType_Store_Conditional) ||
446 (request->m_type == RubyRequestType_Locked_RMW_Read) ||
447 (request->m_type == RubyRequestType_Locked_RMW_Write) ||
448 (request->m_type == RubyRequestType_FLUSH));
449
450 //
451 // For Alpha, properly handle LL, SC, and write requests with respect to
452 // locked cache blocks.
453 //
454 // Not valid for Network_test protocl
455 //
456 bool success = true;
457 if(!m_usingNetworkTester)
458 success = handleLlsc(address, request);
459
460 if (request->m_type == RubyRequestType_Locked_RMW_Read) {
461 m_controller->blockOnQueue(address, m_mandatory_q_ptr);
462 } else if (request->m_type == RubyRequestType_Locked_RMW_Write) {
463 m_controller->unblock(address);
464 }
465
466 hitCallback(request, data, success, mach, externalHit,
467 initialRequestTime, forwardRequestTime, firstResponseTime);
468}
469
470void
471Sequencer::readCallback(const Address& address, DataBlock& data,
472 bool externalHit, const MachineType mach,
473 Cycles initialRequestTime,
474 Cycles forwardRequestTime,
475 Cycles firstResponseTime)
476{
477 assert(address == line_address(address));
478 assert(m_readRequestTable.count(line_address(address)));
479
480 RequestTable::iterator i = m_readRequestTable.find(address);
481 assert(i != m_readRequestTable.end());
482 SequencerRequest* request = i->second;
483
484 m_readRequestTable.erase(i);
485 markRemoved();
486
487 assert((request->m_type == RubyRequestType_LD) ||
488 (request->m_type == RubyRequestType_IFETCH));
489
490 hitCallback(request, data, true, mach, externalHit,
491 initialRequestTime, forwardRequestTime, firstResponseTime);
492}
493
494void
495Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data,
496 bool llscSuccess,
497 const MachineType mach, const bool externalHit,
498 const Cycles initialRequestTime,
499 const Cycles forwardRequestTime,
500 const Cycles firstResponseTime)
501{
502 PacketPtr pkt = srequest->pkt;
503 Address request_address(pkt->getAddr());
504 Address request_line_address(pkt->getAddr());
505 request_line_address.makeLineAddress();
506 RubyRequestType type = srequest->m_type;
507 Cycles issued_time = srequest->issue_time;
508
509 // Set this cache entry to the most recently used
510 if (type == RubyRequestType_IFETCH) {
511 m_instCache_ptr->setMRU(request_line_address);
512 } else {
513 m_dataCache_ptr->setMRU(request_line_address);
514 }
515
516 assert(curCycle() >= issued_time);
517 Cycles total_latency = curCycle() - issued_time;
518
519 // Profile the latency for all demand accesses.
520 recordMissLatency(total_latency, type, mach, externalHit, issued_time,
521 initialRequestTime, forwardRequestTime,
522 firstResponseTime, curCycle());
523
524 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
525 curTick(), m_version, "Seq",
526 llscSuccess ? "Done" : "SC_Failed", "", "",
527 request_address, total_latency);
528
529 // update the data
530 if (g_system_ptr->m_warmup_enabled) {
531 assert(pkt->getPtr<uint8_t>(false) != NULL);
532 data.setData(pkt->getPtr<uint8_t>(false),
533 request_address.getOffset(), pkt->getSize());
534 } else if (pkt->getPtr<uint8_t>(true) != NULL) {
535 if ((type == RubyRequestType_LD) ||
536 (type == RubyRequestType_IFETCH) ||
537 (type == RubyRequestType_RMW_Read) ||
538 (type == RubyRequestType_Locked_RMW_Read) ||
539 (type == RubyRequestType_Load_Linked)) {
540 memcpy(pkt->getPtr<uint8_t>(true),
541 data.getData(request_address.getOffset(), pkt->getSize()),
542 pkt->getSize());
543 } else {
544 data.setData(pkt->getPtr<uint8_t>(true),
545 request_address.getOffset(), pkt->getSize());
546 }
547 } else {
548 DPRINTF(MemoryAccess,
549 "WARNING. Data not transfered from Ruby to M5 for type %s\n",
550 RubyRequestType_to_string(type));
551 }
552
553 // If using the RubyTester, update the RubyTester sender state's
554 // subBlock with the recieved data. The tester will later access
555 // this state.
556 if (m_usingRubyTester) {
557 RubyTester::SenderState* testerSenderState =
558 pkt->findNextSenderState<RubyTester::SenderState>();
559 assert(testerSenderState);
560 testerSenderState->subBlock.mergeFrom(data);
561 }
562
563 delete srequest;
564
565 if (g_system_ptr->m_warmup_enabled) {
566 assert(pkt->req);
567 delete pkt->req;
568 delete pkt;
569 g_system_ptr->m_cache_recorder->enqueueNextFetchRequest();
570 } else if (g_system_ptr->m_cooldown_enabled) {
571 delete pkt;
572 g_system_ptr->m_cache_recorder->enqueueNextFlushRequest();
573 } else {
574 ruby_hit_callback(pkt);
575 }
576}
577
578bool
579Sequencer::empty() const
580{
581 return m_writeRequestTable.empty() && m_readRequestTable.empty();
582}
583
584RequestStatus
585Sequencer::makeRequest(PacketPtr pkt)
586{
587 if (m_outstanding_count >= m_max_outstanding_requests) {
588 return RequestStatus_BufferFull;
589 }
590
591 RubyRequestType primary_type = RubyRequestType_NULL;
592 RubyRequestType secondary_type = RubyRequestType_NULL;
593
594 if (pkt->isLLSC()) {
595 //
596 // Alpha LL/SC instructions need to be handled carefully by the cache
597 // coherence protocol to ensure they follow the proper semantics. In
598 // particular, by identifying the operations as atomic, the protocol
599 // should understand that migratory sharing optimizations should not
600 // be performed (i.e. a load between the LL and SC should not steal
601 // away exclusive permission).
602 //
603 if (pkt->isWrite()) {
604 DPRINTF(RubySequencer, "Issuing SC\n");
605 primary_type = RubyRequestType_Store_Conditional;
606 } else {
607 DPRINTF(RubySequencer, "Issuing LL\n");
608 assert(pkt->isRead());
609 primary_type = RubyRequestType_Load_Linked;
610 }
611 secondary_type = RubyRequestType_ATOMIC;
612 } else if (pkt->req->isLocked()) {
613 //
614 // x86 locked instructions are translated to store cache coherence
615 // requests because these requests should always be treated as read
616 // exclusive operations and should leverage any migratory sharing
617 // optimization built into the protocol.
618 //
619 if (pkt->isWrite()) {
620 DPRINTF(RubySequencer, "Issuing Locked RMW Write\n");
621 primary_type = RubyRequestType_Locked_RMW_Write;
622 } else {
623 DPRINTF(RubySequencer, "Issuing Locked RMW Read\n");
624 assert(pkt->isRead());
625 primary_type = RubyRequestType_Locked_RMW_Read;
626 }
627 secondary_type = RubyRequestType_ST;
628 } else {
629 if (pkt->isRead()) {
630 if (pkt->req->isInstFetch()) {
631 primary_type = secondary_type = RubyRequestType_IFETCH;
632 } else {
46
47using namespace std;
48
49Sequencer *
50RubySequencerParams::create()
51{
52 return new Sequencer(this);
53}
54
55Sequencer::Sequencer(const Params *p)
56 : RubyPort(p), m_IncompleteTimes(MachineType_NUM), deadlockCheckEvent(this)
57{
58 m_outstanding_count = 0;
59
60 m_instCache_ptr = p->icache;
61 m_dataCache_ptr = p->dcache;
62 m_max_outstanding_requests = p->max_outstanding_requests;
63 m_deadlock_threshold = p->deadlock_threshold;
64
65 assert(m_max_outstanding_requests > 0);
66 assert(m_deadlock_threshold > 0);
67 assert(m_instCache_ptr != NULL);
68 assert(m_dataCache_ptr != NULL);
69
70 m_usingNetworkTester = p->using_network_tester;
71}
72
73Sequencer::~Sequencer()
74{
75}
76
77void
78Sequencer::wakeup()
79{
80 assert(getDrainState() != Drainable::Draining);
81
82 // Check for deadlock of any of the requests
83 Cycles current_time = curCycle();
84
85 // Check across all outstanding requests
86 int total_outstanding = 0;
87
88 RequestTable::iterator read = m_readRequestTable.begin();
89 RequestTable::iterator read_end = m_readRequestTable.end();
90 for (; read != read_end; ++read) {
91 SequencerRequest* request = read->second;
92 if (current_time - request->issue_time < m_deadlock_threshold)
93 continue;
94
95 panic("Possible Deadlock detected. Aborting!\n"
96 "version: %d request.paddr: 0x%x m_readRequestTable: %d "
97 "current time: %u issue_time: %d difference: %d\n", m_version,
98 Address(request->pkt->getAddr()), m_readRequestTable.size(),
99 current_time * clockPeriod(), request->issue_time * clockPeriod(),
100 (current_time * clockPeriod()) - (request->issue_time * clockPeriod()));
101 }
102
103 RequestTable::iterator write = m_writeRequestTable.begin();
104 RequestTable::iterator write_end = m_writeRequestTable.end();
105 for (; write != write_end; ++write) {
106 SequencerRequest* request = write->second;
107 if (current_time - request->issue_time < m_deadlock_threshold)
108 continue;
109
110 panic("Possible Deadlock detected. Aborting!\n"
111 "version: %d request.paddr: 0x%x m_writeRequestTable: %d "
112 "current time: %u issue_time: %d difference: %d\n", m_version,
113 Address(request->pkt->getAddr()), m_writeRequestTable.size(),
114 current_time * clockPeriod(), request->issue_time * clockPeriod(),
115 (current_time * clockPeriod()) - (request->issue_time * clockPeriod()));
116 }
117
118 total_outstanding += m_writeRequestTable.size();
119 total_outstanding += m_readRequestTable.size();
120
121 assert(m_outstanding_count == total_outstanding);
122
123 if (m_outstanding_count > 0) {
124 // If there are still outstanding requests, keep checking
125 schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
126 }
127}
128
129void Sequencer::resetStats()
130{
131 m_latencyHist.reset();
132 m_hitLatencyHist.reset();
133 m_missLatencyHist.reset();
134 for (int i = 0; i < RubyRequestType_NUM; i++) {
135 m_typeLatencyHist[i]->reset();
136 m_hitTypeLatencyHist[i]->reset();
137 m_missTypeLatencyHist[i]->reset();
138 for (int j = 0; j < MachineType_NUM; j++) {
139 m_hitTypeMachLatencyHist[i][j]->reset();
140 m_missTypeMachLatencyHist[i][j]->reset();
141 }
142 }
143
144 for (int i = 0; i < MachineType_NUM; i++) {
145 m_missMachLatencyHist[i]->reset();
146 m_hitMachLatencyHist[i]->reset();
147
148 m_IssueToInitialDelayHist[i]->reset();
149 m_InitialToForwardDelayHist[i]->reset();
150 m_ForwardToFirstResponseDelayHist[i]->reset();
151 m_FirstResponseToCompletionDelayHist[i]->reset();
152
153 m_IncompleteTimes[i] = 0;
154 }
155}
156
157void
158Sequencer::printProgress(ostream& out) const
159{
160#if 0
161 int total_demand = 0;
162 out << "Sequencer Stats Version " << m_version << endl;
163 out << "Current time = " << g_system_ptr->getTime() << endl;
164 out << "---------------" << endl;
165 out << "outstanding requests" << endl;
166
167 out << "proc " << m_Read
168 << " version Requests = " << m_readRequestTable.size() << endl;
169
170 // print the request table
171 RequestTable::iterator read = m_readRequestTable.begin();
172 RequestTable::iterator read_end = m_readRequestTable.end();
173 for (; read != read_end; ++read) {
174 SequencerRequest* request = read->second;
175 out << "\tRequest[ " << i << " ] = " << request->type
176 << " Address " << rkeys[i]
177 << " Posted " << request->issue_time
178 << " PF " << PrefetchBit_No << endl;
179 total_demand++;
180 }
181
182 out << "proc " << m_version
183 << " Write Requests = " << m_writeRequestTable.size << endl;
184
185 // print the request table
186 RequestTable::iterator write = m_writeRequestTable.begin();
187 RequestTable::iterator write_end = m_writeRequestTable.end();
188 for (; write != write_end; ++write) {
189 SequencerRequest* request = write->second;
190 out << "\tRequest[ " << i << " ] = " << request.getType()
191 << " Address " << wkeys[i]
192 << " Posted " << request.getTime()
193 << " PF " << request.getPrefetch() << endl;
194 if (request.getPrefetch() == PrefetchBit_No) {
195 total_demand++;
196 }
197 }
198
199 out << endl;
200
201 out << "Total Number Outstanding: " << m_outstanding_count << endl
202 << "Total Number Demand : " << total_demand << endl
203 << "Total Number Prefetches : " << m_outstanding_count - total_demand
204 << endl << endl << endl;
205#endif
206}
207
208// Insert the request on the correct request table. Return true if
209// the entry was already present.
210RequestStatus
211Sequencer::insertRequest(PacketPtr pkt, RubyRequestType request_type)
212{
213 assert(m_outstanding_count ==
214 (m_writeRequestTable.size() + m_readRequestTable.size()));
215
216 // See if we should schedule a deadlock check
217 if (!deadlockCheckEvent.scheduled() &&
218 getDrainState() != Drainable::Draining) {
219 schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
220 }
221
222 Address line_addr(pkt->getAddr());
223 line_addr.makeLineAddress();
224 // Create a default entry, mapping the address to NULL, the cast is
225 // there to make gcc 4.4 happy
226 RequestTable::value_type default_entry(line_addr,
227 (SequencerRequest*) NULL);
228
229 if ((request_type == RubyRequestType_ST) ||
230 (request_type == RubyRequestType_RMW_Read) ||
231 (request_type == RubyRequestType_RMW_Write) ||
232 (request_type == RubyRequestType_Load_Linked) ||
233 (request_type == RubyRequestType_Store_Conditional) ||
234 (request_type == RubyRequestType_Locked_RMW_Read) ||
235 (request_type == RubyRequestType_Locked_RMW_Write) ||
236 (request_type == RubyRequestType_FLUSH)) {
237
238 // Check if there is any outstanding read request for the same
239 // cache line.
240 if (m_readRequestTable.count(line_addr) > 0) {
241 m_store_waiting_on_load++;
242 return RequestStatus_Aliased;
243 }
244
245 pair<RequestTable::iterator, bool> r =
246 m_writeRequestTable.insert(default_entry);
247 if (r.second) {
248 RequestTable::iterator i = r.first;
249 i->second = new SequencerRequest(pkt, request_type, curCycle());
250 m_outstanding_count++;
251 } else {
252 // There is an outstanding write request for the cache line
253 m_store_waiting_on_store++;
254 return RequestStatus_Aliased;
255 }
256 } else {
257 // Check if there is any outstanding write request for the same
258 // cache line.
259 if (m_writeRequestTable.count(line_addr) > 0) {
260 m_load_waiting_on_store++;
261 return RequestStatus_Aliased;
262 }
263
264 pair<RequestTable::iterator, bool> r =
265 m_readRequestTable.insert(default_entry);
266
267 if (r.second) {
268 RequestTable::iterator i = r.first;
269 i->second = new SequencerRequest(pkt, request_type, curCycle());
270 m_outstanding_count++;
271 } else {
272 // There is an outstanding read request for the cache line
273 m_load_waiting_on_load++;
274 return RequestStatus_Aliased;
275 }
276 }
277
278 m_outstandReqHist.sample(m_outstanding_count);
279 assert(m_outstanding_count ==
280 (m_writeRequestTable.size() + m_readRequestTable.size()));
281
282 return RequestStatus_Ready;
283}
284
285void
286Sequencer::markRemoved()
287{
288 m_outstanding_count--;
289 assert(m_outstanding_count ==
290 m_writeRequestTable.size() + m_readRequestTable.size());
291}
292
293void
294Sequencer::removeRequest(SequencerRequest* srequest)
295{
296 assert(m_outstanding_count ==
297 m_writeRequestTable.size() + m_readRequestTable.size());
298
299 Address line_addr(srequest->pkt->getAddr());
300 line_addr.makeLineAddress();
301 if ((srequest->m_type == RubyRequestType_ST) ||
302 (srequest->m_type == RubyRequestType_RMW_Read) ||
303 (srequest->m_type == RubyRequestType_RMW_Write) ||
304 (srequest->m_type == RubyRequestType_Load_Linked) ||
305 (srequest->m_type == RubyRequestType_Store_Conditional) ||
306 (srequest->m_type == RubyRequestType_Locked_RMW_Read) ||
307 (srequest->m_type == RubyRequestType_Locked_RMW_Write)) {
308 m_writeRequestTable.erase(line_addr);
309 } else {
310 m_readRequestTable.erase(line_addr);
311 }
312
313 markRemoved();
314}
315
316void
317Sequencer::invalidateSC(const Address& address)
318{
319 RequestTable::iterator i = m_writeRequestTable.find(address);
320 if (i != m_writeRequestTable.end()) {
321 SequencerRequest* request = i->second;
322 // The controller has lost the coherence permissions, hence the lock
323 // on the cache line maintained by the cache should be cleared.
324 if (request->m_type == RubyRequestType_Store_Conditional) {
325 m_dataCache_ptr->clearLocked(address);
326 }
327 }
328}
329
330bool
331Sequencer::handleLlsc(const Address& address, SequencerRequest* request)
332{
333 //
334 // The success flag indicates whether the LLSC operation was successful.
335 // LL ops will always succeed, but SC may fail if the cache line is no
336 // longer locked.
337 //
338 bool success = true;
339 if (request->m_type == RubyRequestType_Store_Conditional) {
340 if (!m_dataCache_ptr->isLocked(address, m_version)) {
341 //
342 // For failed SC requests, indicate the failure to the cpu by
343 // setting the extra data to zero.
344 //
345 request->pkt->req->setExtraData(0);
346 success = false;
347 } else {
348 //
349 // For successful SC requests, indicate the success to the cpu by
350 // setting the extra data to one.
351 //
352 request->pkt->req->setExtraData(1);
353 }
354 //
355 // Independent of success, all SC operations must clear the lock
356 //
357 m_dataCache_ptr->clearLocked(address);
358 } else if (request->m_type == RubyRequestType_Load_Linked) {
359 //
360 // Note: To fully follow Alpha LLSC semantics, should the LL clear any
361 // previously locked cache lines?
362 //
363 m_dataCache_ptr->setLocked(address, m_version);
364 } else if ((m_dataCache_ptr->isTagPresent(address)) &&
365 (m_dataCache_ptr->isLocked(address, m_version))) {
366 //
367 // Normal writes should clear the locked address
368 //
369 m_dataCache_ptr->clearLocked(address);
370 }
371 return success;
372}
373
374void
375Sequencer::recordMissLatency(const Cycles cycles, const RubyRequestType type,
376 const MachineType respondingMach,
377 bool isExternalHit, Cycles issuedTime,
378 Cycles initialRequestTime,
379 Cycles forwardRequestTime,
380 Cycles firstResponseTime, Cycles completionTime)
381{
382 m_latencyHist.sample(cycles);
383 m_typeLatencyHist[type]->sample(cycles);
384
385 if (isExternalHit) {
386 m_missLatencyHist.sample(cycles);
387 m_missTypeLatencyHist[type]->sample(cycles);
388
389 if (respondingMach != MachineType_NUM) {
390 m_missMachLatencyHist[respondingMach]->sample(cycles);
391 m_missTypeMachLatencyHist[type][respondingMach]->sample(cycles);
392
393 if ((issuedTime <= initialRequestTime) &&
394 (initialRequestTime <= forwardRequestTime) &&
395 (forwardRequestTime <= firstResponseTime) &&
396 (firstResponseTime <= completionTime)) {
397
398 m_IssueToInitialDelayHist[respondingMach]->sample(
399 initialRequestTime - issuedTime);
400 m_InitialToForwardDelayHist[respondingMach]->sample(
401 forwardRequestTime - initialRequestTime);
402 m_ForwardToFirstResponseDelayHist[respondingMach]->sample(
403 firstResponseTime - forwardRequestTime);
404 m_FirstResponseToCompletionDelayHist[respondingMach]->sample(
405 completionTime - firstResponseTime);
406 } else {
407 m_IncompleteTimes[respondingMach]++;
408 }
409 }
410 } else {
411 m_hitLatencyHist.sample(cycles);
412 m_hitTypeLatencyHist[type]->sample(cycles);
413
414 if (respondingMach != MachineType_NUM) {
415 m_hitMachLatencyHist[respondingMach]->sample(cycles);
416 m_hitTypeMachLatencyHist[type][respondingMach]->sample(cycles);
417 }
418 }
419}
420
421void
422Sequencer::writeCallback(const Address& address, DataBlock& data,
423 const bool externalHit, const MachineType mach,
424 const Cycles initialRequestTime,
425 const Cycles forwardRequestTime,
426 const Cycles firstResponseTime)
427{
428 assert(address == line_address(address));
429 assert(m_writeRequestTable.count(line_address(address)));
430
431 RequestTable::iterator i = m_writeRequestTable.find(address);
432 assert(i != m_writeRequestTable.end());
433 SequencerRequest* request = i->second;
434
435 m_writeRequestTable.erase(i);
436 markRemoved();
437
438 assert((request->m_type == RubyRequestType_ST) ||
439 (request->m_type == RubyRequestType_ATOMIC) ||
440 (request->m_type == RubyRequestType_RMW_Read) ||
441 (request->m_type == RubyRequestType_RMW_Write) ||
442 (request->m_type == RubyRequestType_Load_Linked) ||
443 (request->m_type == RubyRequestType_Store_Conditional) ||
444 (request->m_type == RubyRequestType_Locked_RMW_Read) ||
445 (request->m_type == RubyRequestType_Locked_RMW_Write) ||
446 (request->m_type == RubyRequestType_FLUSH));
447
448 //
449 // For Alpha, properly handle LL, SC, and write requests with respect to
450 // locked cache blocks.
451 //
452 // Not valid for Network_test protocl
453 //
454 bool success = true;
455 if(!m_usingNetworkTester)
456 success = handleLlsc(address, request);
457
458 if (request->m_type == RubyRequestType_Locked_RMW_Read) {
459 m_controller->blockOnQueue(address, m_mandatory_q_ptr);
460 } else if (request->m_type == RubyRequestType_Locked_RMW_Write) {
461 m_controller->unblock(address);
462 }
463
464 hitCallback(request, data, success, mach, externalHit,
465 initialRequestTime, forwardRequestTime, firstResponseTime);
466}
467
468void
469Sequencer::readCallback(const Address& address, DataBlock& data,
470 bool externalHit, const MachineType mach,
471 Cycles initialRequestTime,
472 Cycles forwardRequestTime,
473 Cycles firstResponseTime)
474{
475 assert(address == line_address(address));
476 assert(m_readRequestTable.count(line_address(address)));
477
478 RequestTable::iterator i = m_readRequestTable.find(address);
479 assert(i != m_readRequestTable.end());
480 SequencerRequest* request = i->second;
481
482 m_readRequestTable.erase(i);
483 markRemoved();
484
485 assert((request->m_type == RubyRequestType_LD) ||
486 (request->m_type == RubyRequestType_IFETCH));
487
488 hitCallback(request, data, true, mach, externalHit,
489 initialRequestTime, forwardRequestTime, firstResponseTime);
490}
491
492void
493Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data,
494 bool llscSuccess,
495 const MachineType mach, const bool externalHit,
496 const Cycles initialRequestTime,
497 const Cycles forwardRequestTime,
498 const Cycles firstResponseTime)
499{
500 PacketPtr pkt = srequest->pkt;
501 Address request_address(pkt->getAddr());
502 Address request_line_address(pkt->getAddr());
503 request_line_address.makeLineAddress();
504 RubyRequestType type = srequest->m_type;
505 Cycles issued_time = srequest->issue_time;
506
507 // Set this cache entry to the most recently used
508 if (type == RubyRequestType_IFETCH) {
509 m_instCache_ptr->setMRU(request_line_address);
510 } else {
511 m_dataCache_ptr->setMRU(request_line_address);
512 }
513
514 assert(curCycle() >= issued_time);
515 Cycles total_latency = curCycle() - issued_time;
516
517 // Profile the latency for all demand accesses.
518 recordMissLatency(total_latency, type, mach, externalHit, issued_time,
519 initialRequestTime, forwardRequestTime,
520 firstResponseTime, curCycle());
521
522 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
523 curTick(), m_version, "Seq",
524 llscSuccess ? "Done" : "SC_Failed", "", "",
525 request_address, total_latency);
526
527 // update the data
528 if (g_system_ptr->m_warmup_enabled) {
529 assert(pkt->getPtr<uint8_t>(false) != NULL);
530 data.setData(pkt->getPtr<uint8_t>(false),
531 request_address.getOffset(), pkt->getSize());
532 } else if (pkt->getPtr<uint8_t>(true) != NULL) {
533 if ((type == RubyRequestType_LD) ||
534 (type == RubyRequestType_IFETCH) ||
535 (type == RubyRequestType_RMW_Read) ||
536 (type == RubyRequestType_Locked_RMW_Read) ||
537 (type == RubyRequestType_Load_Linked)) {
538 memcpy(pkt->getPtr<uint8_t>(true),
539 data.getData(request_address.getOffset(), pkt->getSize()),
540 pkt->getSize());
541 } else {
542 data.setData(pkt->getPtr<uint8_t>(true),
543 request_address.getOffset(), pkt->getSize());
544 }
545 } else {
546 DPRINTF(MemoryAccess,
547 "WARNING. Data not transfered from Ruby to M5 for type %s\n",
548 RubyRequestType_to_string(type));
549 }
550
551 // If using the RubyTester, update the RubyTester sender state's
552 // subBlock with the recieved data. The tester will later access
553 // this state.
554 if (m_usingRubyTester) {
555 RubyTester::SenderState* testerSenderState =
556 pkt->findNextSenderState<RubyTester::SenderState>();
557 assert(testerSenderState);
558 testerSenderState->subBlock.mergeFrom(data);
559 }
560
561 delete srequest;
562
563 if (g_system_ptr->m_warmup_enabled) {
564 assert(pkt->req);
565 delete pkt->req;
566 delete pkt;
567 g_system_ptr->m_cache_recorder->enqueueNextFetchRequest();
568 } else if (g_system_ptr->m_cooldown_enabled) {
569 delete pkt;
570 g_system_ptr->m_cache_recorder->enqueueNextFlushRequest();
571 } else {
572 ruby_hit_callback(pkt);
573 }
574}
575
576bool
577Sequencer::empty() const
578{
579 return m_writeRequestTable.empty() && m_readRequestTable.empty();
580}
581
582RequestStatus
583Sequencer::makeRequest(PacketPtr pkt)
584{
585 if (m_outstanding_count >= m_max_outstanding_requests) {
586 return RequestStatus_BufferFull;
587 }
588
589 RubyRequestType primary_type = RubyRequestType_NULL;
590 RubyRequestType secondary_type = RubyRequestType_NULL;
591
592 if (pkt->isLLSC()) {
593 //
594 // Alpha LL/SC instructions need to be handled carefully by the cache
595 // coherence protocol to ensure they follow the proper semantics. In
596 // particular, by identifying the operations as atomic, the protocol
597 // should understand that migratory sharing optimizations should not
598 // be performed (i.e. a load between the LL and SC should not steal
599 // away exclusive permission).
600 //
601 if (pkt->isWrite()) {
602 DPRINTF(RubySequencer, "Issuing SC\n");
603 primary_type = RubyRequestType_Store_Conditional;
604 } else {
605 DPRINTF(RubySequencer, "Issuing LL\n");
606 assert(pkt->isRead());
607 primary_type = RubyRequestType_Load_Linked;
608 }
609 secondary_type = RubyRequestType_ATOMIC;
610 } else if (pkt->req->isLocked()) {
611 //
612 // x86 locked instructions are translated to store cache coherence
613 // requests because these requests should always be treated as read
614 // exclusive operations and should leverage any migratory sharing
615 // optimization built into the protocol.
616 //
617 if (pkt->isWrite()) {
618 DPRINTF(RubySequencer, "Issuing Locked RMW Write\n");
619 primary_type = RubyRequestType_Locked_RMW_Write;
620 } else {
621 DPRINTF(RubySequencer, "Issuing Locked RMW Read\n");
622 assert(pkt->isRead());
623 primary_type = RubyRequestType_Locked_RMW_Read;
624 }
625 secondary_type = RubyRequestType_ST;
626 } else {
627 if (pkt->isRead()) {
628 if (pkt->req->isInstFetch()) {
629 primary_type = secondary_type = RubyRequestType_IFETCH;
630 } else {
633#if THE_ISA == X86_ISA
634 uint32_t flags = pkt->req->getFlags();
635 bool storeCheck = flags &
636 (TheISA::StoreCheck << TheISA::FlagShift);
637#else
638 bool storeCheck = false;
631 bool storeCheck = false;
639#endif // X86_ISA
632 // only X86 need the store check
633 if (system->getArch() == Arch::X86ISA) {
634 uint32_t flags = pkt->req->getFlags();
635 storeCheck = flags &
636 (X86ISA::StoreCheck << X86ISA::FlagShift);
637 }
640 if (storeCheck) {
641 primary_type = RubyRequestType_RMW_Read;
642 secondary_type = RubyRequestType_ST;
643 } else {
644 primary_type = secondary_type = RubyRequestType_LD;
645 }
646 }
647 } else if (pkt->isWrite()) {
648 //
649 // Note: M5 packets do not differentiate ST from RMW_Write
650 //
651 primary_type = secondary_type = RubyRequestType_ST;
652 } else if (pkt->isFlush()) {
653 primary_type = secondary_type = RubyRequestType_FLUSH;
654 } else {
655 panic("Unsupported ruby packet type\n");
656 }
657 }
658
659 RequestStatus status = insertRequest(pkt, primary_type);
660 if (status != RequestStatus_Ready)
661 return status;
662
663 issueRequest(pkt, secondary_type);
664
665 // TODO: issue hardware prefetches here
666 return RequestStatus_Issued;
667}
668
669void
670Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type)
671{
672 assert(pkt != NULL);
673 int proc_id = -1;
674 if (pkt->req->hasContextId()) {
675 proc_id = pkt->req->contextId();
676 }
677
678 // If valid, copy the pc to the ruby request
679 Addr pc = 0;
680 if (pkt->req->hasPC()) {
681 pc = pkt->req->getPC();
682 }
683
684 RubyRequest *msg = new RubyRequest(clockEdge(), pkt->getAddr(),
685 pkt->getPtr<uint8_t>(true),
686 pkt->getSize(), pc, secondary_type,
687 RubyAccessMode_Supervisor, pkt,
688 PrefetchBit_No, proc_id);
689
690 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\n",
691 curTick(), m_version, "Seq", "Begin", "", "",
692 msg->getPhysicalAddress(),
693 RubyRequestType_to_string(secondary_type));
694
695 Cycles latency(0); // initialzed to an null value
696
697 if (secondary_type == RubyRequestType_IFETCH)
698 latency = m_instCache_ptr->getLatency();
699 else
700 latency = m_dataCache_ptr->getLatency();
701
702 // Send the message to the cache controller
703 assert(latency > 0);
704
705 assert(m_mandatory_q_ptr != NULL);
706 m_mandatory_q_ptr->enqueue(msg, latency);
707}
708
709template <class KEY, class VALUE>
710std::ostream &
711operator<<(ostream &out, const m5::hash_map<KEY, VALUE> &map)
712{
713 typename m5::hash_map<KEY, VALUE>::const_iterator i = map.begin();
714 typename m5::hash_map<KEY, VALUE>::const_iterator end = map.end();
715
716 out << "[";
717 for (; i != end; ++i)
718 out << " " << i->first << "=" << i->second;
719 out << " ]";
720
721 return out;
722}
723
724void
725Sequencer::print(ostream& out) const
726{
727 out << "[Sequencer: " << m_version
728 << ", outstanding requests: " << m_outstanding_count
729 << ", read request table: " << m_readRequestTable
730 << ", write request table: " << m_writeRequestTable
731 << "]";
732}
733
734// this can be called from setState whenever coherence permissions are
735// upgraded when invoked, coherence violations will be checked for the
736// given block
737void
738Sequencer::checkCoherence(const Address& addr)
739{
740#ifdef CHECK_COHERENCE
741 g_system_ptr->checkGlobalCoherenceInvariant(addr);
742#endif
743}
744
745void
746Sequencer::recordRequestType(SequencerRequestType requestType) {
747 DPRINTF(RubyStats, "Recorded statistic: %s\n",
748 SequencerRequestType_to_string(requestType));
749}
750
751
752void
753Sequencer::evictionCallback(const Address& address)
754{
755 ruby_eviction_callback(address);
756}
757
758void
759Sequencer::regStats()
760{
761 m_store_waiting_on_load
762 .name(name() + ".store_waiting_on_load")
763 .desc("Number of times a store aliased with a pending load")
764 .flags(Stats::nozero);
765 m_store_waiting_on_store
766 .name(name() + ".store_waiting_on_store")
767 .desc("Number of times a store aliased with a pending store")
768 .flags(Stats::nozero);
769 m_load_waiting_on_load
770 .name(name() + ".load_waiting_on_load")
771 .desc("Number of times a load aliased with a pending load")
772 .flags(Stats::nozero);
773 m_load_waiting_on_store
774 .name(name() + ".load_waiting_on_store")
775 .desc("Number of times a load aliased with a pending store")
776 .flags(Stats::nozero);
777
778 // These statistical variables are not for display.
779 // The profiler will collate these across different
780 // sequencers and display those collated statistics.
781 m_outstandReqHist.init(10);
782 m_latencyHist.init(10);
783 m_hitLatencyHist.init(10);
784 m_missLatencyHist.init(10);
785
786 for (int i = 0; i < RubyRequestType_NUM; i++) {
787 m_typeLatencyHist.push_back(new Stats::Histogram());
788 m_typeLatencyHist[i]->init(10);
789
790 m_hitTypeLatencyHist.push_back(new Stats::Histogram());
791 m_hitTypeLatencyHist[i]->init(10);
792
793 m_missTypeLatencyHist.push_back(new Stats::Histogram());
794 m_missTypeLatencyHist[i]->init(10);
795 }
796
797 for (int i = 0; i < MachineType_NUM; i++) {
798 m_hitMachLatencyHist.push_back(new Stats::Histogram());
799 m_hitMachLatencyHist[i]->init(10);
800
801 m_missMachLatencyHist.push_back(new Stats::Histogram());
802 m_missMachLatencyHist[i]->init(10);
803
804 m_IssueToInitialDelayHist.push_back(new Stats::Histogram());
805 m_IssueToInitialDelayHist[i]->init(10);
806
807 m_InitialToForwardDelayHist.push_back(new Stats::Histogram());
808 m_InitialToForwardDelayHist[i]->init(10);
809
810 m_ForwardToFirstResponseDelayHist.push_back(new Stats::Histogram());
811 m_ForwardToFirstResponseDelayHist[i]->init(10);
812
813 m_FirstResponseToCompletionDelayHist.push_back(new Stats::Histogram());
814 m_FirstResponseToCompletionDelayHist[i]->init(10);
815 }
816
817 for (int i = 0; i < RubyRequestType_NUM; i++) {
818 m_hitTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
819 m_missTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
820
821 for (int j = 0; j < MachineType_NUM; j++) {
822 m_hitTypeMachLatencyHist[i].push_back(new Stats::Histogram());
823 m_hitTypeMachLatencyHist[i][j]->init(10);
824
825 m_missTypeMachLatencyHist[i].push_back(new Stats::Histogram());
826 m_missTypeMachLatencyHist[i][j]->init(10);
827 }
828 }
829}
638 if (storeCheck) {
639 primary_type = RubyRequestType_RMW_Read;
640 secondary_type = RubyRequestType_ST;
641 } else {
642 primary_type = secondary_type = RubyRequestType_LD;
643 }
644 }
645 } else if (pkt->isWrite()) {
646 //
647 // Note: M5 packets do not differentiate ST from RMW_Write
648 //
649 primary_type = secondary_type = RubyRequestType_ST;
650 } else if (pkt->isFlush()) {
651 primary_type = secondary_type = RubyRequestType_FLUSH;
652 } else {
653 panic("Unsupported ruby packet type\n");
654 }
655 }
656
657 RequestStatus status = insertRequest(pkt, primary_type);
658 if (status != RequestStatus_Ready)
659 return status;
660
661 issueRequest(pkt, secondary_type);
662
663 // TODO: issue hardware prefetches here
664 return RequestStatus_Issued;
665}
666
667void
668Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type)
669{
670 assert(pkt != NULL);
671 int proc_id = -1;
672 if (pkt->req->hasContextId()) {
673 proc_id = pkt->req->contextId();
674 }
675
676 // If valid, copy the pc to the ruby request
677 Addr pc = 0;
678 if (pkt->req->hasPC()) {
679 pc = pkt->req->getPC();
680 }
681
682 RubyRequest *msg = new RubyRequest(clockEdge(), pkt->getAddr(),
683 pkt->getPtr<uint8_t>(true),
684 pkt->getSize(), pc, secondary_type,
685 RubyAccessMode_Supervisor, pkt,
686 PrefetchBit_No, proc_id);
687
688 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\n",
689 curTick(), m_version, "Seq", "Begin", "", "",
690 msg->getPhysicalAddress(),
691 RubyRequestType_to_string(secondary_type));
692
693 Cycles latency(0); // initialzed to an null value
694
695 if (secondary_type == RubyRequestType_IFETCH)
696 latency = m_instCache_ptr->getLatency();
697 else
698 latency = m_dataCache_ptr->getLatency();
699
700 // Send the message to the cache controller
701 assert(latency > 0);
702
703 assert(m_mandatory_q_ptr != NULL);
704 m_mandatory_q_ptr->enqueue(msg, latency);
705}
706
707template <class KEY, class VALUE>
708std::ostream &
709operator<<(ostream &out, const m5::hash_map<KEY, VALUE> &map)
710{
711 typename m5::hash_map<KEY, VALUE>::const_iterator i = map.begin();
712 typename m5::hash_map<KEY, VALUE>::const_iterator end = map.end();
713
714 out << "[";
715 for (; i != end; ++i)
716 out << " " << i->first << "=" << i->second;
717 out << " ]";
718
719 return out;
720}
721
722void
723Sequencer::print(ostream& out) const
724{
725 out << "[Sequencer: " << m_version
726 << ", outstanding requests: " << m_outstanding_count
727 << ", read request table: " << m_readRequestTable
728 << ", write request table: " << m_writeRequestTable
729 << "]";
730}
731
732// this can be called from setState whenever coherence permissions are
733// upgraded when invoked, coherence violations will be checked for the
734// given block
735void
736Sequencer::checkCoherence(const Address& addr)
737{
738#ifdef CHECK_COHERENCE
739 g_system_ptr->checkGlobalCoherenceInvariant(addr);
740#endif
741}
742
743void
744Sequencer::recordRequestType(SequencerRequestType requestType) {
745 DPRINTF(RubyStats, "Recorded statistic: %s\n",
746 SequencerRequestType_to_string(requestType));
747}
748
749
750void
751Sequencer::evictionCallback(const Address& address)
752{
753 ruby_eviction_callback(address);
754}
755
756void
757Sequencer::regStats()
758{
759 m_store_waiting_on_load
760 .name(name() + ".store_waiting_on_load")
761 .desc("Number of times a store aliased with a pending load")
762 .flags(Stats::nozero);
763 m_store_waiting_on_store
764 .name(name() + ".store_waiting_on_store")
765 .desc("Number of times a store aliased with a pending store")
766 .flags(Stats::nozero);
767 m_load_waiting_on_load
768 .name(name() + ".load_waiting_on_load")
769 .desc("Number of times a load aliased with a pending load")
770 .flags(Stats::nozero);
771 m_load_waiting_on_store
772 .name(name() + ".load_waiting_on_store")
773 .desc("Number of times a load aliased with a pending store")
774 .flags(Stats::nozero);
775
776 // These statistical variables are not for display.
777 // The profiler will collate these across different
778 // sequencers and display those collated statistics.
779 m_outstandReqHist.init(10);
780 m_latencyHist.init(10);
781 m_hitLatencyHist.init(10);
782 m_missLatencyHist.init(10);
783
784 for (int i = 0; i < RubyRequestType_NUM; i++) {
785 m_typeLatencyHist.push_back(new Stats::Histogram());
786 m_typeLatencyHist[i]->init(10);
787
788 m_hitTypeLatencyHist.push_back(new Stats::Histogram());
789 m_hitTypeLatencyHist[i]->init(10);
790
791 m_missTypeLatencyHist.push_back(new Stats::Histogram());
792 m_missTypeLatencyHist[i]->init(10);
793 }
794
795 for (int i = 0; i < MachineType_NUM; i++) {
796 m_hitMachLatencyHist.push_back(new Stats::Histogram());
797 m_hitMachLatencyHist[i]->init(10);
798
799 m_missMachLatencyHist.push_back(new Stats::Histogram());
800 m_missMachLatencyHist[i]->init(10);
801
802 m_IssueToInitialDelayHist.push_back(new Stats::Histogram());
803 m_IssueToInitialDelayHist[i]->init(10);
804
805 m_InitialToForwardDelayHist.push_back(new Stats::Histogram());
806 m_InitialToForwardDelayHist[i]->init(10);
807
808 m_ForwardToFirstResponseDelayHist.push_back(new Stats::Histogram());
809 m_ForwardToFirstResponseDelayHist[i]->init(10);
810
811 m_FirstResponseToCompletionDelayHist.push_back(new Stats::Histogram());
812 m_FirstResponseToCompletionDelayHist[i]->init(10);
813 }
814
815 for (int i = 0; i < RubyRequestType_NUM; i++) {
816 m_hitTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
817 m_missTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
818
819 for (int j = 0; j < MachineType_NUM; j++) {
820 m_hitTypeMachLatencyHist[i].push_back(new Stats::Histogram());
821 m_hitTypeMachLatencyHist[i][j]->init(10);
822
823 m_missTypeMachLatencyHist[i].push_back(new Stats::Histogram());
824 m_missTypeMachLatencyHist[i][j]->init(10);
825 }
826 }
827}