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