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