211 schedule(deadlockCheckEvent, 212 g_system_ptr->clockPeriod() * m_deadlock_threshold + curTick()); 213 } 214 215 Address line_addr(pkt->getAddr()); 216 line_addr.makeLineAddress(); 217 // Create a default entry, mapping the address to NULL, the cast is 218 // there to make gcc 4.4 happy 219 RequestTable::value_type default_entry(line_addr, 220 (SequencerRequest*) NULL); 221 222 if ((request_type == RubyRequestType_ST) || 223 (request_type == RubyRequestType_RMW_Read) || 224 (request_type == RubyRequestType_RMW_Write) || 225 (request_type == RubyRequestType_Load_Linked) || 226 (request_type == RubyRequestType_Store_Conditional) || 227 (request_type == RubyRequestType_Locked_RMW_Read) || 228 (request_type == RubyRequestType_Locked_RMW_Write) || 229 (request_type == RubyRequestType_FLUSH)) { 230 231 // Check if there is any outstanding read request for the same 232 // cache line. 233 if (m_readRequestTable.count(line_addr) > 0) { 234 m_store_waiting_on_load_cycles++; 235 return RequestStatus_Aliased; 236 } 237 238 pair<RequestTable::iterator, bool> r = 239 m_writeRequestTable.insert(default_entry); 240 if (r.second) { 241 RequestTable::iterator i = r.first; 242 i->second = new SequencerRequest(pkt, request_type, 243 g_system_ptr->getTime()); 244 m_outstanding_count++; 245 } else { 246 // There is an outstanding write request for the cache line 247 m_store_waiting_on_store_cycles++; 248 return RequestStatus_Aliased; 249 } 250 } else { 251 // Check if there is any outstanding write request for the same 252 // cache line. 253 if (m_writeRequestTable.count(line_addr) > 0) { 254 m_load_waiting_on_store_cycles++; 255 return RequestStatus_Aliased; 256 } 257 258 pair<RequestTable::iterator, bool> r = 259 m_readRequestTable.insert(default_entry); 260 261 if (r.second) { 262 RequestTable::iterator i = r.first; 263 i->second = new SequencerRequest(pkt, request_type, 264 g_system_ptr->getTime()); 265 m_outstanding_count++; 266 } else { 267 // There is an outstanding read request for the cache line 268 m_load_waiting_on_load_cycles++; 269 return RequestStatus_Aliased; 270 } 271 } 272 273 g_system_ptr->getProfiler()->sequencerRequests(m_outstanding_count); 274 assert(m_outstanding_count == 275 (m_writeRequestTable.size() + m_readRequestTable.size())); 276 277 return RequestStatus_Ready; 278} 279 280void 281Sequencer::markRemoved() 282{ 283 m_outstanding_count--; 284 assert(m_outstanding_count == 285 m_writeRequestTable.size() + m_readRequestTable.size()); 286} 287 288void 289Sequencer::removeRequest(SequencerRequest* srequest) 290{ 291 assert(m_outstanding_count == 292 m_writeRequestTable.size() + m_readRequestTable.size()); 293 294 Address line_addr(srequest->pkt->getAddr()); 295 line_addr.makeLineAddress(); 296 if ((srequest->m_type == RubyRequestType_ST) || 297 (srequest->m_type == RubyRequestType_RMW_Read) || 298 (srequest->m_type == RubyRequestType_RMW_Write) || 299 (srequest->m_type == RubyRequestType_Load_Linked) || 300 (srequest->m_type == RubyRequestType_Store_Conditional) || 301 (srequest->m_type == RubyRequestType_Locked_RMW_Read) || 302 (srequest->m_type == RubyRequestType_Locked_RMW_Write)) { 303 m_writeRequestTable.erase(line_addr); 304 } else { 305 m_readRequestTable.erase(line_addr); 306 } 307 308 markRemoved(); 309} 310 311bool 312Sequencer::handleLlsc(const Address& address, SequencerRequest* request) 313{ 314 // 315 // The success flag indicates whether the LLSC operation was successful. 316 // LL ops will always succeed, but SC may fail if the cache line is no 317 // longer locked. 318 // 319 bool success = true; 320 if (request->m_type == RubyRequestType_Store_Conditional) { 321 if (!m_dataCache_ptr->isLocked(address, m_version)) { 322 // 323 // For failed SC requests, indicate the failure to the cpu by 324 // setting the extra data to zero. 325 // 326 request->pkt->req->setExtraData(0); 327 success = false; 328 } else { 329 // 330 // For successful SC requests, indicate the success to the cpu by 331 // setting the extra data to one. 332 // 333 request->pkt->req->setExtraData(1); 334 } 335 // 336 // Independent of success, all SC operations must clear the lock 337 // 338 m_dataCache_ptr->clearLocked(address); 339 } else if (request->m_type == RubyRequestType_Load_Linked) { 340 // 341 // Note: To fully follow Alpha LLSC semantics, should the LL clear any 342 // previously locked cache lines? 343 // 344 m_dataCache_ptr->setLocked(address, m_version); 345 } else if ((m_dataCache_ptr->isTagPresent(address)) && 346 (m_dataCache_ptr->isLocked(address, m_version))) { 347 // 348 // Normal writes should clear the locked address 349 // 350 m_dataCache_ptr->clearLocked(address); 351 } 352 return success; 353} 354 355void 356Sequencer::writeCallback(const Address& address, DataBlock& data) 357{ 358 writeCallback(address, GenericMachineType_NULL, data); 359} 360 361void 362Sequencer::writeCallback(const Address& address, 363 GenericMachineType mach, 364 DataBlock& data) 365{ 366 writeCallback(address, mach, data, 0, 0, 0); 367} 368 369void 370Sequencer::writeCallback(const Address& address, 371 GenericMachineType mach, 372 DataBlock& data, 373 Time initialRequestTime, 374 Time forwardRequestTime, 375 Time firstResponseTime) 376{ 377 assert(address == line_address(address)); 378 assert(m_writeRequestTable.count(line_address(address))); 379 380 RequestTable::iterator i = m_writeRequestTable.find(address); 381 assert(i != m_writeRequestTable.end()); 382 SequencerRequest* request = i->second; 383 384 m_writeRequestTable.erase(i); 385 markRemoved(); 386 387 assert((request->m_type == RubyRequestType_ST) || 388 (request->m_type == RubyRequestType_ATOMIC) || 389 (request->m_type == RubyRequestType_RMW_Read) || 390 (request->m_type == RubyRequestType_RMW_Write) || 391 (request->m_type == RubyRequestType_Load_Linked) || 392 (request->m_type == RubyRequestType_Store_Conditional) || 393 (request->m_type == RubyRequestType_Locked_RMW_Read) || 394 (request->m_type == RubyRequestType_Locked_RMW_Write) || 395 (request->m_type == RubyRequestType_FLUSH)); 396 397 398 // 399 // For Alpha, properly handle LL, SC, and write requests with respect to 400 // locked cache blocks. 401 // 402 // Not valid for Network_test protocl 403 // 404 bool success = true; 405 if(!m_usingNetworkTester) 406 success = handleLlsc(address, request); 407 408 if (request->m_type == RubyRequestType_Locked_RMW_Read) { 409 m_controller->blockOnQueue(address, m_mandatory_q_ptr); 410 } else if (request->m_type == RubyRequestType_Locked_RMW_Write) { 411 m_controller->unblock(address); 412 } 413 414 hitCallback(request, mach, data, success, 415 initialRequestTime, forwardRequestTime, firstResponseTime); 416} 417 418void 419Sequencer::readCallback(const Address& address, DataBlock& data) 420{ 421 readCallback(address, GenericMachineType_NULL, data); 422} 423 424void 425Sequencer::readCallback(const Address& address, 426 GenericMachineType mach, 427 DataBlock& data) 428{ 429 readCallback(address, mach, data, 0, 0, 0); 430} 431 432void 433Sequencer::readCallback(const Address& address, 434 GenericMachineType mach, 435 DataBlock& data, 436 Time initialRequestTime, 437 Time forwardRequestTime, 438 Time firstResponseTime) 439{ 440 assert(address == line_address(address)); 441 assert(m_readRequestTable.count(line_address(address))); 442 443 RequestTable::iterator i = m_readRequestTable.find(address); 444 assert(i != m_readRequestTable.end()); 445 SequencerRequest* request = i->second; 446 447 m_readRequestTable.erase(i); 448 markRemoved(); 449 450 assert((request->m_type == RubyRequestType_LD) || 451 (request->m_type == RubyRequestType_IFETCH)); 452 453 hitCallback(request, mach, data, true, 454 initialRequestTime, forwardRequestTime, firstResponseTime); 455} 456 457void 458Sequencer::hitCallback(SequencerRequest* srequest, 459 GenericMachineType mach, 460 DataBlock& data, 461 bool success, 462 Time initialRequestTime, 463 Time forwardRequestTime, 464 Time firstResponseTime) 465{ 466 PacketPtr pkt = srequest->pkt; 467 Address request_address(pkt->getAddr()); 468 Address request_line_address(pkt->getAddr()); 469 request_line_address.makeLineAddress(); 470 RubyRequestType type = srequest->m_type; 471 Time issued_time = srequest->issue_time; 472 473 // Set this cache entry to the most recently used 474 if (type == RubyRequestType_IFETCH) { 475 m_instCache_ptr->setMRU(request_line_address); 476 } else { 477 m_dataCache_ptr->setMRU(request_line_address); 478 } 479 480 assert(g_system_ptr->getTime() >= issued_time); 481 Time miss_latency = g_system_ptr->getTime() - issued_time; 482 483 // Profile the miss latency for all non-zero demand misses 484 if (miss_latency != 0) { 485 g_system_ptr->getProfiler()->missLatency(miss_latency, type, mach); 486 487 if (mach == GenericMachineType_L1Cache_wCC) { 488 g_system_ptr->getProfiler()->missLatencyWcc(issued_time, 489 initialRequestTime, 490 forwardRequestTime, 491 firstResponseTime, 492 g_system_ptr->getTime()); 493 } 494 495 if (mach == GenericMachineType_Directory) { 496 g_system_ptr->getProfiler()->missLatencyDir(issued_time, 497 initialRequestTime, 498 forwardRequestTime, 499 firstResponseTime, 500 g_system_ptr->getTime()); 501 } 502 503 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n", 504 curTick(), m_version, "Seq", 505 success ? "Done" : "SC_Failed", "", "", 506 request_address, miss_latency); 507 } 508 509 // update the data 510 if (g_system_ptr->m_warmup_enabled) { 511 assert(pkt->getPtr<uint8_t>(false) != NULL); 512 data.setData(pkt->getPtr<uint8_t>(false), 513 request_address.getOffset(), pkt->getSize()); 514 } else if (pkt->getPtr<uint8_t>(true) != NULL) { 515 if ((type == RubyRequestType_LD) || 516 (type == RubyRequestType_IFETCH) || 517 (type == RubyRequestType_RMW_Read) || 518 (type == RubyRequestType_Locked_RMW_Read) || 519 (type == RubyRequestType_Load_Linked)) { 520 memcpy(pkt->getPtr<uint8_t>(true), 521 data.getData(request_address.getOffset(), pkt->getSize()), 522 pkt->getSize()); 523 } else { 524 data.setData(pkt->getPtr<uint8_t>(true), 525 request_address.getOffset(), pkt->getSize()); 526 } 527 } else { 528 DPRINTF(MemoryAccess, 529 "WARNING. Data not transfered from Ruby to M5 for type %s\n", 530 RubyRequestType_to_string(type)); 531 } 532 533 // If using the RubyTester, update the RubyTester sender state's 534 // subBlock with the recieved data. The tester will later access 535 // this state. 536 // Note: RubyPort will access it's sender state before the 537 // RubyTester. 538 if (m_usingRubyTester) { 539 RubyPort::SenderState *requestSenderState = 540 safe_cast<RubyPort::SenderState*>(pkt->senderState); 541 RubyTester::SenderState* testerSenderState = 542 safe_cast<RubyTester::SenderState*>(requestSenderState->saved); 543 testerSenderState->subBlock->mergeFrom(data); 544 } 545 546 delete srequest; 547 548 if (g_system_ptr->m_warmup_enabled) { 549 delete pkt; 550 g_system_ptr->m_cache_recorder->enqueueNextFetchRequest(); 551 } else if (g_system_ptr->m_cooldown_enabled) { 552 delete pkt; 553 g_system_ptr->m_cache_recorder->enqueueNextFlushRequest(); 554 } else { 555 ruby_hit_callback(pkt); 556 } 557} 558 559bool 560Sequencer::empty() const 561{ 562 return m_writeRequestTable.empty() && m_readRequestTable.empty(); 563} 564 565RequestStatus 566Sequencer::makeRequest(PacketPtr pkt) 567{ 568 if (m_outstanding_count >= m_max_outstanding_requests) { 569 return RequestStatus_BufferFull; 570 } 571 572 RubyRequestType primary_type = RubyRequestType_NULL; 573 RubyRequestType secondary_type = RubyRequestType_NULL; 574 575 if (pkt->isLLSC()) { 576 // 577 // Alpha LL/SC instructions need to be handled carefully by the cache 578 // coherence protocol to ensure they follow the proper semantics. In 579 // particular, by identifying the operations as atomic, the protocol 580 // should understand that migratory sharing optimizations should not 581 // be performed (i.e. a load between the LL and SC should not steal 582 // away exclusive permission). 583 // 584 if (pkt->isWrite()) { 585 DPRINTF(RubySequencer, "Issuing SC\n"); 586 primary_type = RubyRequestType_Store_Conditional; 587 } else { 588 DPRINTF(RubySequencer, "Issuing LL\n"); 589 assert(pkt->isRead()); 590 primary_type = RubyRequestType_Load_Linked; 591 } 592 secondary_type = RubyRequestType_ATOMIC; 593 } else if (pkt->req->isLocked()) { 594 // 595 // x86 locked instructions are translated to store cache coherence 596 // requests because these requests should always be treated as read 597 // exclusive operations and should leverage any migratory sharing 598 // optimization built into the protocol. 599 // 600 if (pkt->isWrite()) { 601 DPRINTF(RubySequencer, "Issuing Locked RMW Write\n"); 602 primary_type = RubyRequestType_Locked_RMW_Write; 603 } else { 604 DPRINTF(RubySequencer, "Issuing Locked RMW Read\n"); 605 assert(pkt->isRead()); 606 primary_type = RubyRequestType_Locked_RMW_Read; 607 } 608 secondary_type = RubyRequestType_ST; 609 } else { 610 if (pkt->isRead()) { 611 if (pkt->req->isInstFetch()) { 612 primary_type = secondary_type = RubyRequestType_IFETCH; 613 } else { 614#if THE_ISA == X86_ISA 615 uint32_t flags = pkt->req->getFlags(); 616 bool storeCheck = flags & 617 (TheISA::StoreCheck << TheISA::FlagShift); 618#else 619 bool storeCheck = false; 620#endif // X86_ISA 621 if (storeCheck) { 622 primary_type = RubyRequestType_RMW_Read; 623 secondary_type = RubyRequestType_ST; 624 } else { 625 primary_type = secondary_type = RubyRequestType_LD; 626 } 627 } 628 } else if (pkt->isWrite()) { 629 // 630 // Note: M5 packets do not differentiate ST from RMW_Write 631 // 632 primary_type = secondary_type = RubyRequestType_ST; 633 } else if (pkt->isFlush()) { 634 primary_type = secondary_type = RubyRequestType_FLUSH; 635 } else { 636 panic("Unsupported ruby packet type\n"); 637 } 638 } 639 640 RequestStatus status = insertRequest(pkt, primary_type); 641 if (status != RequestStatus_Ready) 642 return status; 643 644 issueRequest(pkt, secondary_type); 645 646 // TODO: issue hardware prefetches here 647 return RequestStatus_Issued; 648} 649 650void 651Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type) 652{ 653 assert(pkt != NULL); 654 int proc_id = -1; 655 if (pkt->req->hasContextId()) { 656 proc_id = pkt->req->contextId(); 657 } 658 659 // If valid, copy the pc to the ruby request 660 Addr pc = 0; 661 if (pkt->req->hasPC()) { 662 pc = pkt->req->getPC(); 663 } 664 665 RubyRequest *msg = new RubyRequest(pkt->getAddr(), 666 pkt->getPtr<uint8_t>(true), 667 pkt->getSize(), pc, secondary_type, 668 RubyAccessMode_Supervisor, pkt, 669 PrefetchBit_No, proc_id); 670 671 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\n", 672 curTick(), m_version, "Seq", "Begin", "", "", 673 msg->getPhysicalAddress(), 674 RubyRequestType_to_string(secondary_type)); 675 676 Time latency = 0; // initialzed to an null value 677 678 if (secondary_type == RubyRequestType_IFETCH) 679 latency = m_instCache_ptr->getLatency(); 680 else 681 latency = m_dataCache_ptr->getLatency(); 682 683 // Send the message to the cache controller 684 assert(latency > 0); 685 686 assert(m_mandatory_q_ptr != NULL); 687 m_mandatory_q_ptr->enqueue(msg, latency); 688} 689 690template <class KEY, class VALUE> 691std::ostream & 692operator<<(ostream &out, const m5::hash_map<KEY, VALUE> &map) 693{ 694 typename m5::hash_map<KEY, VALUE>::const_iterator i = map.begin(); 695 typename m5::hash_map<KEY, VALUE>::const_iterator end = map.end(); 696 697 out << "["; 698 for (; i != end; ++i) 699 out << " " << i->first << "=" << i->second; 700 out << " ]"; 701 702 return out; 703} 704 705void 706Sequencer::print(ostream& out) const 707{ 708 out << "[Sequencer: " << m_version 709 << ", outstanding requests: " << m_outstanding_count 710 << ", read request table: " << m_readRequestTable 711 << ", write request table: " << m_writeRequestTable 712 << "]"; 713} 714 715// this can be called from setState whenever coherence permissions are 716// upgraded when invoked, coherence violations will be checked for the 717// given block 718void 719Sequencer::checkCoherence(const Address& addr) 720{ 721#ifdef CHECK_COHERENCE 722 g_system_ptr->checkGlobalCoherenceInvariant(addr); 723#endif 724} 725 726void 727Sequencer::recordRequestType(SequencerRequestType requestType) { 728 DPRINTF(RubyStats, "Recorded statistic: %s\n", 729 SequencerRequestType_to_string(requestType)); 730} 731 732 733void 734Sequencer::evictionCallback(const Address& address) 735{ 736 ruby_eviction_callback(address); 737}
| 213 schedule(deadlockCheckEvent, 214 g_system_ptr->clockPeriod() * m_deadlock_threshold + curTick()); 215 } 216 217 Address line_addr(pkt->getAddr()); 218 line_addr.makeLineAddress(); 219 // Create a default entry, mapping the address to NULL, the cast is 220 // there to make gcc 4.4 happy 221 RequestTable::value_type default_entry(line_addr, 222 (SequencerRequest*) NULL); 223 224 if ((request_type == RubyRequestType_ST) || 225 (request_type == RubyRequestType_RMW_Read) || 226 (request_type == RubyRequestType_RMW_Write) || 227 (request_type == RubyRequestType_Load_Linked) || 228 (request_type == RubyRequestType_Store_Conditional) || 229 (request_type == RubyRequestType_Locked_RMW_Read) || 230 (request_type == RubyRequestType_Locked_RMW_Write) || 231 (request_type == RubyRequestType_FLUSH)) { 232 233 // Check if there is any outstanding read request for the same 234 // cache line. 235 if (m_readRequestTable.count(line_addr) > 0) { 236 m_store_waiting_on_load_cycles++; 237 return RequestStatus_Aliased; 238 } 239 240 pair<RequestTable::iterator, bool> r = 241 m_writeRequestTable.insert(default_entry); 242 if (r.second) { 243 RequestTable::iterator i = r.first; 244 i->second = new SequencerRequest(pkt, request_type, 245 g_system_ptr->getTime()); 246 m_outstanding_count++; 247 } else { 248 // There is an outstanding write request for the cache line 249 m_store_waiting_on_store_cycles++; 250 return RequestStatus_Aliased; 251 } 252 } else { 253 // Check if there is any outstanding write request for the same 254 // cache line. 255 if (m_writeRequestTable.count(line_addr) > 0) { 256 m_load_waiting_on_store_cycles++; 257 return RequestStatus_Aliased; 258 } 259 260 pair<RequestTable::iterator, bool> r = 261 m_readRequestTable.insert(default_entry); 262 263 if (r.second) { 264 RequestTable::iterator i = r.first; 265 i->second = new SequencerRequest(pkt, request_type, 266 g_system_ptr->getTime()); 267 m_outstanding_count++; 268 } else { 269 // There is an outstanding read request for the cache line 270 m_load_waiting_on_load_cycles++; 271 return RequestStatus_Aliased; 272 } 273 } 274 275 g_system_ptr->getProfiler()->sequencerRequests(m_outstanding_count); 276 assert(m_outstanding_count == 277 (m_writeRequestTable.size() + m_readRequestTable.size())); 278 279 return RequestStatus_Ready; 280} 281 282void 283Sequencer::markRemoved() 284{ 285 m_outstanding_count--; 286 assert(m_outstanding_count == 287 m_writeRequestTable.size() + m_readRequestTable.size()); 288} 289 290void 291Sequencer::removeRequest(SequencerRequest* srequest) 292{ 293 assert(m_outstanding_count == 294 m_writeRequestTable.size() + m_readRequestTable.size()); 295 296 Address line_addr(srequest->pkt->getAddr()); 297 line_addr.makeLineAddress(); 298 if ((srequest->m_type == RubyRequestType_ST) || 299 (srequest->m_type == RubyRequestType_RMW_Read) || 300 (srequest->m_type == RubyRequestType_RMW_Write) || 301 (srequest->m_type == RubyRequestType_Load_Linked) || 302 (srequest->m_type == RubyRequestType_Store_Conditional) || 303 (srequest->m_type == RubyRequestType_Locked_RMW_Read) || 304 (srequest->m_type == RubyRequestType_Locked_RMW_Write)) { 305 m_writeRequestTable.erase(line_addr); 306 } else { 307 m_readRequestTable.erase(line_addr); 308 } 309 310 markRemoved(); 311} 312 313bool 314Sequencer::handleLlsc(const Address& address, SequencerRequest* request) 315{ 316 // 317 // The success flag indicates whether the LLSC operation was successful. 318 // LL ops will always succeed, but SC may fail if the cache line is no 319 // longer locked. 320 // 321 bool success = true; 322 if (request->m_type == RubyRequestType_Store_Conditional) { 323 if (!m_dataCache_ptr->isLocked(address, m_version)) { 324 // 325 // For failed SC requests, indicate the failure to the cpu by 326 // setting the extra data to zero. 327 // 328 request->pkt->req->setExtraData(0); 329 success = false; 330 } else { 331 // 332 // For successful SC requests, indicate the success to the cpu by 333 // setting the extra data to one. 334 // 335 request->pkt->req->setExtraData(1); 336 } 337 // 338 // Independent of success, all SC operations must clear the lock 339 // 340 m_dataCache_ptr->clearLocked(address); 341 } else if (request->m_type == RubyRequestType_Load_Linked) { 342 // 343 // Note: To fully follow Alpha LLSC semantics, should the LL clear any 344 // previously locked cache lines? 345 // 346 m_dataCache_ptr->setLocked(address, m_version); 347 } else if ((m_dataCache_ptr->isTagPresent(address)) && 348 (m_dataCache_ptr->isLocked(address, m_version))) { 349 // 350 // Normal writes should clear the locked address 351 // 352 m_dataCache_ptr->clearLocked(address); 353 } 354 return success; 355} 356 357void 358Sequencer::writeCallback(const Address& address, DataBlock& data) 359{ 360 writeCallback(address, GenericMachineType_NULL, data); 361} 362 363void 364Sequencer::writeCallback(const Address& address, 365 GenericMachineType mach, 366 DataBlock& data) 367{ 368 writeCallback(address, mach, data, 0, 0, 0); 369} 370 371void 372Sequencer::writeCallback(const Address& address, 373 GenericMachineType mach, 374 DataBlock& data, 375 Time initialRequestTime, 376 Time forwardRequestTime, 377 Time firstResponseTime) 378{ 379 assert(address == line_address(address)); 380 assert(m_writeRequestTable.count(line_address(address))); 381 382 RequestTable::iterator i = m_writeRequestTable.find(address); 383 assert(i != m_writeRequestTable.end()); 384 SequencerRequest* request = i->second; 385 386 m_writeRequestTable.erase(i); 387 markRemoved(); 388 389 assert((request->m_type == RubyRequestType_ST) || 390 (request->m_type == RubyRequestType_ATOMIC) || 391 (request->m_type == RubyRequestType_RMW_Read) || 392 (request->m_type == RubyRequestType_RMW_Write) || 393 (request->m_type == RubyRequestType_Load_Linked) || 394 (request->m_type == RubyRequestType_Store_Conditional) || 395 (request->m_type == RubyRequestType_Locked_RMW_Read) || 396 (request->m_type == RubyRequestType_Locked_RMW_Write) || 397 (request->m_type == RubyRequestType_FLUSH)); 398 399 400 // 401 // For Alpha, properly handle LL, SC, and write requests with respect to 402 // locked cache blocks. 403 // 404 // Not valid for Network_test protocl 405 // 406 bool success = true; 407 if(!m_usingNetworkTester) 408 success = handleLlsc(address, request); 409 410 if (request->m_type == RubyRequestType_Locked_RMW_Read) { 411 m_controller->blockOnQueue(address, m_mandatory_q_ptr); 412 } else if (request->m_type == RubyRequestType_Locked_RMW_Write) { 413 m_controller->unblock(address); 414 } 415 416 hitCallback(request, mach, data, success, 417 initialRequestTime, forwardRequestTime, firstResponseTime); 418} 419 420void 421Sequencer::readCallback(const Address& address, DataBlock& data) 422{ 423 readCallback(address, GenericMachineType_NULL, data); 424} 425 426void 427Sequencer::readCallback(const Address& address, 428 GenericMachineType mach, 429 DataBlock& data) 430{ 431 readCallback(address, mach, data, 0, 0, 0); 432} 433 434void 435Sequencer::readCallback(const Address& address, 436 GenericMachineType mach, 437 DataBlock& data, 438 Time initialRequestTime, 439 Time forwardRequestTime, 440 Time firstResponseTime) 441{ 442 assert(address == line_address(address)); 443 assert(m_readRequestTable.count(line_address(address))); 444 445 RequestTable::iterator i = m_readRequestTable.find(address); 446 assert(i != m_readRequestTable.end()); 447 SequencerRequest* request = i->second; 448 449 m_readRequestTable.erase(i); 450 markRemoved(); 451 452 assert((request->m_type == RubyRequestType_LD) || 453 (request->m_type == RubyRequestType_IFETCH)); 454 455 hitCallback(request, mach, data, true, 456 initialRequestTime, forwardRequestTime, firstResponseTime); 457} 458 459void 460Sequencer::hitCallback(SequencerRequest* srequest, 461 GenericMachineType mach, 462 DataBlock& data, 463 bool success, 464 Time initialRequestTime, 465 Time forwardRequestTime, 466 Time firstResponseTime) 467{ 468 PacketPtr pkt = srequest->pkt; 469 Address request_address(pkt->getAddr()); 470 Address request_line_address(pkt->getAddr()); 471 request_line_address.makeLineAddress(); 472 RubyRequestType type = srequest->m_type; 473 Time issued_time = srequest->issue_time; 474 475 // Set this cache entry to the most recently used 476 if (type == RubyRequestType_IFETCH) { 477 m_instCache_ptr->setMRU(request_line_address); 478 } else { 479 m_dataCache_ptr->setMRU(request_line_address); 480 } 481 482 assert(g_system_ptr->getTime() >= issued_time); 483 Time miss_latency = g_system_ptr->getTime() - issued_time; 484 485 // Profile the miss latency for all non-zero demand misses 486 if (miss_latency != 0) { 487 g_system_ptr->getProfiler()->missLatency(miss_latency, type, mach); 488 489 if (mach == GenericMachineType_L1Cache_wCC) { 490 g_system_ptr->getProfiler()->missLatencyWcc(issued_time, 491 initialRequestTime, 492 forwardRequestTime, 493 firstResponseTime, 494 g_system_ptr->getTime()); 495 } 496 497 if (mach == GenericMachineType_Directory) { 498 g_system_ptr->getProfiler()->missLatencyDir(issued_time, 499 initialRequestTime, 500 forwardRequestTime, 501 firstResponseTime, 502 g_system_ptr->getTime()); 503 } 504 505 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n", 506 curTick(), m_version, "Seq", 507 success ? "Done" : "SC_Failed", "", "", 508 request_address, miss_latency); 509 } 510 511 // update the data 512 if (g_system_ptr->m_warmup_enabled) { 513 assert(pkt->getPtr<uint8_t>(false) != NULL); 514 data.setData(pkt->getPtr<uint8_t>(false), 515 request_address.getOffset(), pkt->getSize()); 516 } else if (pkt->getPtr<uint8_t>(true) != NULL) { 517 if ((type == RubyRequestType_LD) || 518 (type == RubyRequestType_IFETCH) || 519 (type == RubyRequestType_RMW_Read) || 520 (type == RubyRequestType_Locked_RMW_Read) || 521 (type == RubyRequestType_Load_Linked)) { 522 memcpy(pkt->getPtr<uint8_t>(true), 523 data.getData(request_address.getOffset(), pkt->getSize()), 524 pkt->getSize()); 525 } else { 526 data.setData(pkt->getPtr<uint8_t>(true), 527 request_address.getOffset(), pkt->getSize()); 528 } 529 } else { 530 DPRINTF(MemoryAccess, 531 "WARNING. Data not transfered from Ruby to M5 for type %s\n", 532 RubyRequestType_to_string(type)); 533 } 534 535 // If using the RubyTester, update the RubyTester sender state's 536 // subBlock with the recieved data. The tester will later access 537 // this state. 538 // Note: RubyPort will access it's sender state before the 539 // RubyTester. 540 if (m_usingRubyTester) { 541 RubyPort::SenderState *requestSenderState = 542 safe_cast<RubyPort::SenderState*>(pkt->senderState); 543 RubyTester::SenderState* testerSenderState = 544 safe_cast<RubyTester::SenderState*>(requestSenderState->saved); 545 testerSenderState->subBlock->mergeFrom(data); 546 } 547 548 delete srequest; 549 550 if (g_system_ptr->m_warmup_enabled) { 551 delete pkt; 552 g_system_ptr->m_cache_recorder->enqueueNextFetchRequest(); 553 } else if (g_system_ptr->m_cooldown_enabled) { 554 delete pkt; 555 g_system_ptr->m_cache_recorder->enqueueNextFlushRequest(); 556 } else { 557 ruby_hit_callback(pkt); 558 } 559} 560 561bool 562Sequencer::empty() const 563{ 564 return m_writeRequestTable.empty() && m_readRequestTable.empty(); 565} 566 567RequestStatus 568Sequencer::makeRequest(PacketPtr pkt) 569{ 570 if (m_outstanding_count >= m_max_outstanding_requests) { 571 return RequestStatus_BufferFull; 572 } 573 574 RubyRequestType primary_type = RubyRequestType_NULL; 575 RubyRequestType secondary_type = RubyRequestType_NULL; 576 577 if (pkt->isLLSC()) { 578 // 579 // Alpha LL/SC instructions need to be handled carefully by the cache 580 // coherence protocol to ensure they follow the proper semantics. In 581 // particular, by identifying the operations as atomic, the protocol 582 // should understand that migratory sharing optimizations should not 583 // be performed (i.e. a load between the LL and SC should not steal 584 // away exclusive permission). 585 // 586 if (pkt->isWrite()) { 587 DPRINTF(RubySequencer, "Issuing SC\n"); 588 primary_type = RubyRequestType_Store_Conditional; 589 } else { 590 DPRINTF(RubySequencer, "Issuing LL\n"); 591 assert(pkt->isRead()); 592 primary_type = RubyRequestType_Load_Linked; 593 } 594 secondary_type = RubyRequestType_ATOMIC; 595 } else if (pkt->req->isLocked()) { 596 // 597 // x86 locked instructions are translated to store cache coherence 598 // requests because these requests should always be treated as read 599 // exclusive operations and should leverage any migratory sharing 600 // optimization built into the protocol. 601 // 602 if (pkt->isWrite()) { 603 DPRINTF(RubySequencer, "Issuing Locked RMW Write\n"); 604 primary_type = RubyRequestType_Locked_RMW_Write; 605 } else { 606 DPRINTF(RubySequencer, "Issuing Locked RMW Read\n"); 607 assert(pkt->isRead()); 608 primary_type = RubyRequestType_Locked_RMW_Read; 609 } 610 secondary_type = RubyRequestType_ST; 611 } else { 612 if (pkt->isRead()) { 613 if (pkt->req->isInstFetch()) { 614 primary_type = secondary_type = RubyRequestType_IFETCH; 615 } else { 616#if THE_ISA == X86_ISA 617 uint32_t flags = pkt->req->getFlags(); 618 bool storeCheck = flags & 619 (TheISA::StoreCheck << TheISA::FlagShift); 620#else 621 bool storeCheck = false; 622#endif // X86_ISA 623 if (storeCheck) { 624 primary_type = RubyRequestType_RMW_Read; 625 secondary_type = RubyRequestType_ST; 626 } else { 627 primary_type = secondary_type = RubyRequestType_LD; 628 } 629 } 630 } else if (pkt->isWrite()) { 631 // 632 // Note: M5 packets do not differentiate ST from RMW_Write 633 // 634 primary_type = secondary_type = RubyRequestType_ST; 635 } else if (pkt->isFlush()) { 636 primary_type = secondary_type = RubyRequestType_FLUSH; 637 } else { 638 panic("Unsupported ruby packet type\n"); 639 } 640 } 641 642 RequestStatus status = insertRequest(pkt, primary_type); 643 if (status != RequestStatus_Ready) 644 return status; 645 646 issueRequest(pkt, secondary_type); 647 648 // TODO: issue hardware prefetches here 649 return RequestStatus_Issued; 650} 651 652void 653Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type) 654{ 655 assert(pkt != NULL); 656 int proc_id = -1; 657 if (pkt->req->hasContextId()) { 658 proc_id = pkt->req->contextId(); 659 } 660 661 // If valid, copy the pc to the ruby request 662 Addr pc = 0; 663 if (pkt->req->hasPC()) { 664 pc = pkt->req->getPC(); 665 } 666 667 RubyRequest *msg = new RubyRequest(pkt->getAddr(), 668 pkt->getPtr<uint8_t>(true), 669 pkt->getSize(), pc, secondary_type, 670 RubyAccessMode_Supervisor, pkt, 671 PrefetchBit_No, proc_id); 672 673 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\n", 674 curTick(), m_version, "Seq", "Begin", "", "", 675 msg->getPhysicalAddress(), 676 RubyRequestType_to_string(secondary_type)); 677 678 Time latency = 0; // initialzed to an null value 679 680 if (secondary_type == RubyRequestType_IFETCH) 681 latency = m_instCache_ptr->getLatency(); 682 else 683 latency = m_dataCache_ptr->getLatency(); 684 685 // Send the message to the cache controller 686 assert(latency > 0); 687 688 assert(m_mandatory_q_ptr != NULL); 689 m_mandatory_q_ptr->enqueue(msg, latency); 690} 691 692template <class KEY, class VALUE> 693std::ostream & 694operator<<(ostream &out, const m5::hash_map<KEY, VALUE> &map) 695{ 696 typename m5::hash_map<KEY, VALUE>::const_iterator i = map.begin(); 697 typename m5::hash_map<KEY, VALUE>::const_iterator end = map.end(); 698 699 out << "["; 700 for (; i != end; ++i) 701 out << " " << i->first << "=" << i->second; 702 out << " ]"; 703 704 return out; 705} 706 707void 708Sequencer::print(ostream& out) const 709{ 710 out << "[Sequencer: " << m_version 711 << ", outstanding requests: " << m_outstanding_count 712 << ", read request table: " << m_readRequestTable 713 << ", write request table: " << m_writeRequestTable 714 << "]"; 715} 716 717// this can be called from setState whenever coherence permissions are 718// upgraded when invoked, coherence violations will be checked for the 719// given block 720void 721Sequencer::checkCoherence(const Address& addr) 722{ 723#ifdef CHECK_COHERENCE 724 g_system_ptr->checkGlobalCoherenceInvariant(addr); 725#endif 726} 727 728void 729Sequencer::recordRequestType(SequencerRequestType requestType) { 730 DPRINTF(RubyStats, "Recorded statistic: %s\n", 731 SequencerRequestType_to_string(requestType)); 732} 733 734 735void 736Sequencer::evictionCallback(const Address& address) 737{ 738 ruby_eviction_callback(address); 739}
|