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