lsq_unit_impl.hh revision 2367
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 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 "cpu/checker/cpu.hh" 30#include "cpu/o3/lsq_unit.hh" 31#include "base/str.hh" 32 33template <class Impl> 34LSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, 35 Event *wb_event, 36 LSQUnit<Impl> *lsq_ptr) 37 : Event(&mainEventQueue), 38 wbEvent(wb_event), 39 storeIdx(store_idx), 40 lsqPtr(lsq_ptr) 41{ 42 this->setFlags(Event::AutoDelete); 43} 44 45template <class Impl> 46void 47LSQUnit<Impl>::StoreCompletionEvent::process() 48{ 49 DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx); 50 DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx); 51 52 //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); 53 54 if (lsqPtr->isSwitchedOut()) { 55 if (wbEvent) 56 delete wbEvent; 57 58 return; 59 } 60 61 lsqPtr->cpu->wakeCPU(); 62 if (wbEvent) { 63 wbEvent->process(); 64 delete wbEvent; 65 } 66 lsqPtr->completeStore(storeIdx); 67} 68 69template <class Impl> 70const char * 71LSQUnit<Impl>::StoreCompletionEvent::description() 72{ 73 return "LSQ store completion event"; 74} 75 76template <class Impl> 77LSQUnit<Impl>::LSQUnit() 78 : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), 79 loadBlockedHandled(false) 80{ 81} 82 83template<class Impl> 84void 85LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, 86 unsigned maxSQEntries, unsigned id) 87 88{ 89 DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); 90 91 switchedOut = false; 92 93 lsqID = id; 94 95 // Add 1 for the sentinel entry (they are circular queues). 96 LQEntries = maxLQEntries + 1; 97 SQEntries = maxSQEntries + 1; 98 99 loadQueue.resize(LQEntries); 100 storeQueue.resize(SQEntries); 101 102 loadHead = loadTail = 0; 103 104 storeHead = storeWBIdx = storeTail = 0; 105 106 usedPorts = 0; 107 cachePorts = params->cachePorts; 108 109 dcacheInterface = params->dcacheInterface; 110 111 memDepViolator = NULL; 112 113 blockedLoadSeqNum = 0; 114} 115 116template<class Impl> 117std::string 118LSQUnit<Impl>::name() const 119{ 120 if (Impl::MaxThreads == 1) { 121 return iewStage->name() + ".lsq"; 122 } else { 123 return iewStage->name() + ".lsq.thread." + to_string(lsqID); 124 } 125} 126 127template<class Impl> 128void 129LSQUnit<Impl>::regStats() 130{ 131 lsqForwLoads 132 .name(name() + ".forwLoads") 133 .desc("Number of loads that had data forwarded from stores"); 134 135 invAddrLoads 136 .name(name() + ".invAddrLoads") 137 .desc("Number of loads ignored due to an invalid address"); 138 139 lsqSquashedLoads 140 .name(name() + ".squashedLoads") 141 .desc("Number of loads squashed"); 142 143 lsqIgnoredResponses 144 .name(name() + ".ignoredResponses") 145 .desc("Number of memory responses ignored because the instruction is squashed"); 146 147 lsqMemOrderViolation 148 .name(name() + ".memOrderViolation") 149 .desc("Number of memory ordering violations"); 150 151 lsqSquashedStores 152 .name(name() + ".squashedStores") 153 .desc("Number of stores squashed"); 154 155 invAddrSwpfs 156 .name(name() + ".invAddrSwpfs") 157 .desc("Number of software prefetches ignored due to an invalid address"); 158 159 lsqBlockedLoads 160 .name(name() + ".blockedLoads") 161 .desc("Number of blocked loads due to partial load-store forwarding"); 162 163 lsqRescheduledLoads 164 .name(name() + ".rescheduledLoads") 165 .desc("Number of loads that were rescheduled"); 166 167 lsqCacheBlocked 168 .name(name() + ".cacheBlocked") 169 .desc("Number of times an access to memory failed due to the cache being blocked"); 170} 171 172template<class Impl> 173void 174LSQUnit<Impl>::clearLQ() 175{ 176 loadQueue.clear(); 177} 178 179template<class Impl> 180void 181LSQUnit<Impl>::clearSQ() 182{ 183 storeQueue.clear(); 184} 185 186#if 0 187template<class Impl> 188void 189LSQUnit<Impl>::setPageTable(PageTable *pt_ptr) 190{ 191 DPRINTF(LSQUnit, "Setting the page table pointer.\n"); 192 pTable = pt_ptr; 193} 194#endif 195 196template<class Impl> 197void 198LSQUnit<Impl>::switchOut() 199{ 200 switchedOut = true; 201 for (int i = 0; i < loadQueue.size(); ++i) { 202 assert(!loadQueue[i]); 203 loadQueue[i] = NULL; 204 } 205 206 assert(storesToWB == 0); 207} 208 209template<class Impl> 210void 211LSQUnit<Impl>::takeOverFrom() 212{ 213 switchedOut = false; 214 loads = stores = storesToWB = 0; 215 216 loadHead = loadTail = 0; 217 218 storeHead = storeWBIdx = storeTail = 0; 219 220 usedPorts = 0; 221 222 memDepViolator = NULL; 223 224 blockedLoadSeqNum = 0; 225 226 stalled = false; 227 isLoadBlocked = false; 228 loadBlockedHandled = false; 229} 230 231template<class Impl> 232void 233LSQUnit<Impl>::resizeLQ(unsigned size) 234{ 235 unsigned size_plus_sentinel = size + 1; 236 assert(size_plus_sentinel >= LQEntries); 237 238 if (size_plus_sentinel > LQEntries) { 239 while (size_plus_sentinel > loadQueue.size()) { 240 DynInstPtr dummy; 241 loadQueue.push_back(dummy); 242 LQEntries++; 243 } 244 } else { 245 LQEntries = size_plus_sentinel; 246 } 247 248} 249 250template<class Impl> 251void 252LSQUnit<Impl>::resizeSQ(unsigned size) 253{ 254 unsigned size_plus_sentinel = size + 1; 255 if (size_plus_sentinel > SQEntries) { 256 while (size_plus_sentinel > storeQueue.size()) { 257 SQEntry dummy; 258 storeQueue.push_back(dummy); 259 SQEntries++; 260 } 261 } else { 262 SQEntries = size_plus_sentinel; 263 } 264} 265 266template <class Impl> 267void 268LSQUnit<Impl>::insert(DynInstPtr &inst) 269{ 270 assert(inst->isMemRef()); 271 272 assert(inst->isLoad() || inst->isStore()); 273 274 if (inst->isLoad()) { 275 insertLoad(inst); 276 } else { 277 insertStore(inst); 278 } 279 280 inst->setInLSQ(); 281} 282 283template <class Impl> 284void 285LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) 286{ 287 assert((loadTail + 1) % LQEntries != loadHead); 288 assert(loads < LQEntries); 289 290 DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", 291 load_inst->readPC(), loadTail, load_inst->seqNum); 292 293 load_inst->lqIdx = loadTail; 294 295 if (stores == 0) { 296 load_inst->sqIdx = -1; 297 } else { 298 load_inst->sqIdx = storeTail; 299 } 300 301 loadQueue[loadTail] = load_inst; 302 303 incrLdIdx(loadTail); 304 305 ++loads; 306} 307 308template <class Impl> 309void 310LSQUnit<Impl>::insertStore(DynInstPtr &store_inst) 311{ 312 // Make sure it is not full before inserting an instruction. 313 assert((storeTail + 1) % SQEntries != storeHead); 314 assert(stores < SQEntries); 315 316 DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", 317 store_inst->readPC(), storeTail, store_inst->seqNum); 318 319 store_inst->sqIdx = storeTail; 320 store_inst->lqIdx = loadTail; 321 322 storeQueue[storeTail] = SQEntry(store_inst); 323 324 incrStIdx(storeTail); 325 326 ++stores; 327} 328 329template <class Impl> 330typename Impl::DynInstPtr 331LSQUnit<Impl>::getMemDepViolator() 332{ 333 DynInstPtr temp = memDepViolator; 334 335 memDepViolator = NULL; 336 337 return temp; 338} 339 340template <class Impl> 341unsigned 342LSQUnit<Impl>::numFreeEntries() 343{ 344 unsigned free_lq_entries = LQEntries - loads; 345 unsigned free_sq_entries = SQEntries - stores; 346 347 // Both the LQ and SQ entries have an extra dummy entry to differentiate 348 // empty/full conditions. Subtract 1 from the free entries. 349 if (free_lq_entries < free_sq_entries) { 350 return free_lq_entries - 1; 351 } else { 352 return free_sq_entries - 1; 353 } 354} 355 356template <class Impl> 357int 358LSQUnit<Impl>::numLoadsReady() 359{ 360 int load_idx = loadHead; 361 int retval = 0; 362 363 while (load_idx != loadTail) { 364 assert(loadQueue[load_idx]); 365 366 if (loadQueue[load_idx]->readyToIssue()) { 367 ++retval; 368 } 369 } 370 371 return retval; 372} 373 374template <class Impl> 375Fault 376LSQUnit<Impl>::executeLoad(DynInstPtr &inst) 377{ 378 // Execute a specific load. 379 Fault load_fault = NoFault; 380 381 DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", 382 inst->readPC(),inst->seqNum); 383 384// load_fault = inst->initiateAcc(); 385 load_fault = inst->execute(); 386 387 // If the instruction faulted, then we need to send it along to commit 388 // without the instruction completing. 389 if (load_fault != NoFault) { 390 // Send this instruction to commit, also make sure iew stage 391 // realizes there is activity. 392 // Mark it as executed unless it is an uncached load that 393 // needs to hit the head of commit. 394 if (!(inst->req->flags & UNCACHEABLE) || inst->isAtCommit()) { 395 inst->setExecuted(); 396 } 397 iewStage->instToCommit(inst); 398 iewStage->activityThisCycle(); 399 } 400 401 return load_fault; 402} 403 404template <class Impl> 405Fault 406LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) 407{ 408 using namespace TheISA; 409 // Make sure that a store exists. 410 assert(stores != 0); 411 412 int store_idx = store_inst->sqIdx; 413 414 DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", 415 store_inst->readPC(), store_inst->seqNum); 416 417 // Check the recently completed loads to see if any match this store's 418 // address. If so, then we have a memory ordering violation. 419 int load_idx = store_inst->lqIdx; 420 421 Fault store_fault = store_inst->initiateAcc(); 422// Fault store_fault = store_inst->execute(); 423 424 if (storeQueue[store_idx].size == 0) { 425 DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", 426 store_inst->readPC(),store_inst->seqNum); 427 428 return store_fault; 429 } 430 431 assert(store_fault == NoFault); 432 433 if (store_inst->isStoreConditional()) { 434 // Store conditionals need to set themselves as able to 435 // writeback if we haven't had a fault by here. 436 storeQueue[store_idx].canWB = true; 437 438 ++storesToWB; 439 } 440 441 if (!memDepViolator) { 442 while (load_idx != loadTail) { 443 // Really only need to check loads that have actually executed 444 // It's safe to check all loads because effAddr is set to 445 // InvalAddr when the dyn inst is created. 446 447 // @todo: For now this is extra conservative, detecting a 448 // violation if the addresses match assuming all accesses 449 // are quad word accesses. 450 451 // @todo: Fix this, magic number being used here 452 if ((loadQueue[load_idx]->effAddr >> 8) == 453 (store_inst->effAddr >> 8)) { 454 // A load incorrectly passed this store. Squash and refetch. 455 // For now return a fault to show that it was unsuccessful. 456 memDepViolator = loadQueue[load_idx]; 457 ++lsqMemOrderViolation; 458 459 return genMachineCheckFault(); 460 } 461 462 incrLdIdx(load_idx); 463 } 464 465 // If we've reached this point, there was no violation. 466 memDepViolator = NULL; 467 } 468 469 return store_fault; 470} 471 472template <class Impl> 473void 474LSQUnit<Impl>::commitLoad() 475{ 476 assert(loadQueue[loadHead]); 477 478 DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 479 loadQueue[loadHead]->readPC()); 480 481 loadQueue[loadHead] = NULL; 482 483 incrLdIdx(loadHead); 484 485 --loads; 486} 487 488template <class Impl> 489void 490LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 491{ 492 assert(loads == 0 || loadQueue[loadHead]); 493 494 while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { 495 commitLoad(); 496 } 497} 498 499template <class Impl> 500void 501LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) 502{ 503 assert(stores == 0 || storeQueue[storeHead].inst); 504 505 int store_idx = storeHead; 506 507 while (store_idx != storeTail) { 508 assert(storeQueue[store_idx].inst); 509 // Mark any stores that are now committed and have not yet 510 // been marked as able to write back. 511 if (!storeQueue[store_idx].canWB) { 512 if (storeQueue[store_idx].inst->seqNum > youngest_inst) { 513 break; 514 } 515 DPRINTF(LSQUnit, "Marking store as able to write back, PC " 516 "%#x [sn:%lli]\n", 517 storeQueue[store_idx].inst->readPC(), 518 storeQueue[store_idx].inst->seqNum); 519 520 storeQueue[store_idx].canWB = true; 521 522 ++storesToWB; 523 } 524 525 incrStIdx(store_idx); 526 } 527} 528 529template <class Impl> 530void 531LSQUnit<Impl>::writebackStores() 532{ 533 while (storesToWB > 0 && 534 storeWBIdx != storeTail && 535 storeQueue[storeWBIdx].inst && 536 storeQueue[storeWBIdx].canWB && 537 usedPorts < cachePorts) { 538 539 // Store didn't write any data so no need to write it back to 540 // memory. 541 if (storeQueue[storeWBIdx].size == 0) { 542 completeStore(storeWBIdx); 543 544 incrStIdx(storeWBIdx); 545 546 continue; 547 } 548 549 if (dcacheInterface && dcacheInterface->isBlocked()) { 550 DPRINTF(LSQUnit, "Unable to write back any more stores, cache" 551 " is blocked!\n"); 552 ++lsqCacheBlocked; 553 break; 554 } 555 556 ++usedPorts; 557 558 if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { 559 incrStIdx(storeWBIdx); 560 561 continue; 562 } 563 564 assert(storeQueue[storeWBIdx].req); 565 assert(!storeQueue[storeWBIdx].committed); 566 567 MemReqPtr req = storeQueue[storeWBIdx].req; 568 storeQueue[storeWBIdx].committed = true; 569 570 req->cmd = Write; 571 req->completionEvent = NULL; 572 req->time = curTick; 573 assert(!req->data); 574 req->data = new uint8_t[64]; 575 memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 576 577 DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 578 "to Addr:%#x, data:%#x [sn:%lli]\n", 579 storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 580 req->paddr, *(req->data), 581 storeQueue[storeWBIdx].inst->seqNum); 582 583 switch(storeQueue[storeWBIdx].size) { 584 case 1: 585 cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 586 break; 587 case 2: 588 cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 589 break; 590 case 4: 591 cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 592 break; 593 case 8: 594 cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 595 break; 596 default: 597 panic("Unexpected store size!\n"); 598 } 599 600 // Stores other than store conditionals are completed at this 601 // time. Mark them as completed and, if we have a checker, 602 // tell it that the instruction is completed. 603 // @todo: Figure out what time I can say stores are complete in 604 // the timing memory. 605 if (!(req->flags & LOCKED)) { 606 storeQueue[storeWBIdx].inst->setCompleted(); 607 if (cpu->checker) { 608 cpu->checker->tick(storeQueue[storeWBIdx].inst); 609 } 610 } 611 612 if (dcacheInterface) { 613 assert(!req->completionEvent); 614 StoreCompletionEvent *store_event = new 615 StoreCompletionEvent(storeWBIdx, NULL, this); 616 req->completionEvent = store_event; 617 618 MemAccessResult result = dcacheInterface->access(req); 619 620 if (isStalled() && 621 storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { 622 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 623 "load idx:%i\n", 624 stallingStoreIsn, stallingLoadIdx); 625 stalled = false; 626 stallingStoreIsn = 0; 627 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 628 } 629 630 typename IEW::LdWritebackEvent *wb = NULL; 631 if (req->flags & LOCKED) { 632 // Stx_C should not generate a system port transaction 633 // if it misses in the cache, but that might be hard 634 // to accomplish without explicit cache support. 635 wb = new typename 636 IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 637 iewStage); 638 store_event->wbEvent = wb; 639 } 640 641 if (result != MA_HIT && dcacheInterface->doEvents()) { 642 DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n", 643 storeWBIdx); 644 645 DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", 646 storeQueue[storeWBIdx].inst->seqNum); 647 648 //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); 649 650 //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); 651 652 // @todo: Increment stat here. 653 } else { 654 DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", 655 storeWBIdx); 656 657 DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", 658 storeQueue[storeWBIdx].inst->seqNum); 659 } 660 661 incrStIdx(storeWBIdx); 662 } else { 663 panic("Must HAVE DCACHE!!!!!\n"); 664 } 665 } 666 667 // Not sure this should set it to 0. 668 usedPorts = 0; 669 670 assert(stores >= 0 && storesToWB >= 0); 671} 672 673/*template <class Impl> 674void 675LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) 676{ 677 list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), 678 mshrSeqNums.end(), 679 seqNum); 680 681 if (mshr_it != mshrSeqNums.end()) { 682 mshrSeqNums.erase(mshr_it); 683 DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); 684 } 685}*/ 686 687template <class Impl> 688void 689LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) 690{ 691 DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" 692 "(Loads:%i Stores:%i)\n", squashed_num, loads, stores); 693 694 int load_idx = loadTail; 695 decrLdIdx(load_idx); 696 697 while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { 698 DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " 699 "[sn:%lli]\n", 700 loadQueue[load_idx]->readPC(), 701 loadQueue[load_idx]->seqNum); 702 703 if (isStalled() && load_idx == stallingLoadIdx) { 704 stalled = false; 705 stallingStoreIsn = 0; 706 stallingLoadIdx = 0; 707 } 708 709 // Clear the smart pointer to make sure it is decremented. 710 loadQueue[load_idx]->setSquashed(); 711 loadQueue[load_idx] = NULL; 712 --loads; 713 714 // Inefficient! 715 loadTail = load_idx; 716 717 decrLdIdx(load_idx); 718 } 719 720 if (isLoadBlocked) { 721 if (squashed_num < blockedLoadSeqNum) { 722 isLoadBlocked = false; 723 loadBlockedHandled = false; 724 blockedLoadSeqNum = 0; 725 } 726 } 727 728 int store_idx = storeTail; 729 decrStIdx(store_idx); 730 731 while (stores != 0 && 732 storeQueue[store_idx].inst->seqNum > squashed_num) { 733 // Instructions marked as can WB are already committed. 734 if (storeQueue[store_idx].canWB) { 735 break; 736 } 737 738 DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " 739 "idx:%i [sn:%lli]\n", 740 storeQueue[store_idx].inst->readPC(), 741 store_idx, storeQueue[store_idx].inst->seqNum); 742 743 // I don't think this can happen. It should have been cleared 744 // by the stalling load. 745 if (isStalled() && 746 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 747 panic("Is stalled should have been cleared by stalling load!\n"); 748 stalled = false; 749 stallingStoreIsn = 0; 750 } 751 752 // Clear the smart pointer to make sure it is decremented. 753 storeQueue[store_idx].inst->setSquashed(); 754 storeQueue[store_idx].inst = NULL; 755 storeQueue[store_idx].canWB = 0; 756 757 if (storeQueue[store_idx].req) { 758 // There should not be a completion event if the store has 759 // not yet committed. 760 assert(!storeQueue[store_idx].req->completionEvent); 761 } 762 763 storeQueue[store_idx].req = NULL; 764 --stores; 765 766 // Inefficient! 767 storeTail = store_idx; 768 769 decrStIdx(store_idx); 770 ++lsqSquashedStores; 771 } 772} 773 774template <class Impl> 775void 776LSQUnit<Impl>::completeStore(int store_idx) 777{ 778 assert(storeQueue[store_idx].inst); 779 storeQueue[store_idx].completed = true; 780 --storesToWB; 781 // A bit conservative because a store completion may not free up entries, 782 // but hopefully avoids two store completions in one cycle from making 783 // the CPU tick twice. 784 cpu->activityThisCycle(); 785 786 if (store_idx == storeHead) { 787 do { 788 incrStIdx(storeHead); 789 790 --stores; 791 } while (storeQueue[storeHead].completed && 792 storeHead != storeTail); 793 794 iewStage->updateLSQNextCycle = true; 795 } 796 797 DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head " 798 "idx:%i\n", 799 storeQueue[store_idx].inst->seqNum, store_idx, storeHead); 800 801 if (isStalled() && 802 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 803 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 804 "load idx:%i\n", 805 stallingStoreIsn, stallingLoadIdx); 806 stalled = false; 807 stallingStoreIsn = 0; 808 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 809 } 810 811 storeQueue[store_idx].inst->setCompleted(); 812 813 // Tell the checker we've completed this instruction. Some stores 814 // may get reported twice to the checker, but the checker can 815 // handle that case. 816 if (cpu->checker) { 817 cpu->checker->tick(storeQueue[store_idx].inst); 818 } 819} 820 821template <class Impl> 822inline void 823LSQUnit<Impl>::incrStIdx(int &store_idx) 824{ 825 if (++store_idx >= SQEntries) 826 store_idx = 0; 827} 828 829template <class Impl> 830inline void 831LSQUnit<Impl>::decrStIdx(int &store_idx) 832{ 833 if (--store_idx < 0) 834 store_idx += SQEntries; 835} 836 837template <class Impl> 838inline void 839LSQUnit<Impl>::incrLdIdx(int &load_idx) 840{ 841 if (++load_idx >= LQEntries) 842 load_idx = 0; 843} 844 845template <class Impl> 846inline void 847LSQUnit<Impl>::decrLdIdx(int &load_idx) 848{ 849 if (--load_idx < 0) 850 load_idx += LQEntries; 851} 852 853template <class Impl> 854void 855LSQUnit<Impl>::dumpInsts() 856{ 857 cprintf("Load store queue: Dumping instructions.\n"); 858 cprintf("Load queue size: %i\n", loads); 859 cprintf("Load queue: "); 860 861 int load_idx = loadHead; 862 863 while (load_idx != loadTail && loadQueue[load_idx]) { 864 cprintf("%#x ", loadQueue[load_idx]->readPC()); 865 866 incrLdIdx(load_idx); 867 } 868 869 cprintf("Store queue size: %i\n", stores); 870 cprintf("Store queue: "); 871 872 int store_idx = storeHead; 873 874 while (store_idx != storeTail && storeQueue[store_idx].inst) { 875 cprintf("%#x ", storeQueue[store_idx].inst->readPC()); 876 877 incrStIdx(store_idx); 878 } 879 880 cprintf("\n"); 881} 882