lsq_unit_impl.hh revision 2336
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->isStoreConditional()) { 428 // Store conditionals need to set themselves as able to 429 // writeback if we haven't had a fault by here. 430 storeQueue[store_idx].canWB = true; 431 432 ++storesToWB; 433 } 434 435 if (!memDepViolator) { 436 while (load_idx != loadTail) { 437 // Really only need to check loads that have actually executed 438 // It's safe to check all loads because effAddr is set to 439 // InvalAddr when the dyn inst is created. 440 441 // @todo: For now this is extra conservative, detecting a 442 // violation if the addresses match assuming all accesses 443 // are quad word accesses. 444 445 // @todo: Fix this, magic number being used here 446 if ((loadQueue[load_idx]->effAddr >> 8) == 447 (store_inst->effAddr >> 8)) { 448 // A load incorrectly passed this store. Squash and refetch. 449 // For now return a fault to show that it was unsuccessful. 450 memDepViolator = loadQueue[load_idx]; 451 452 return genMachineCheckFault(); 453 } 454 455 incrLdIdx(load_idx); 456 } 457 458 // If we've reached this point, there was no violation. 459 memDepViolator = NULL; 460 } 461 462 return store_fault; 463} 464 465template <class Impl> 466void 467LSQUnit<Impl>::commitLoad() 468{ 469 assert(loadQueue[loadHead]); 470 471 DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 472 loadQueue[loadHead]->readPC()); 473 474 475 loadQueue[loadHead] = NULL; 476 477 incrLdIdx(loadHead); 478 479 --loads; 480} 481 482template <class Impl> 483void 484LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 485{ 486 assert(loads == 0 || loadQueue[loadHead]); 487 488 while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { 489 commitLoad(); 490 } 491} 492 493template <class Impl> 494void 495LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) 496{ 497 assert(stores == 0 || storeQueue[storeHead].inst); 498 499 int store_idx = storeHead; 500 501 while (store_idx != storeTail) { 502 assert(storeQueue[store_idx].inst); 503 // Mark any stores that are now committed and have not yet 504 // been marked as able to write back. 505 if (!storeQueue[store_idx].canWB) { 506 if (storeQueue[store_idx].inst->seqNum > youngest_inst) { 507 break; 508 } 509 DPRINTF(LSQUnit, "Marking store as able to write back, PC " 510 "%#x [sn:%lli]\n", 511 storeQueue[store_idx].inst->readPC(), 512 storeQueue[store_idx].inst->seqNum); 513 514 storeQueue[store_idx].canWB = true; 515 516 ++storesToWB; 517 } 518 519 incrStIdx(store_idx); 520 } 521} 522 523template <class Impl> 524void 525LSQUnit<Impl>::writebackStores() 526{ 527 while (storesToWB > 0 && 528 storeWBIdx != storeTail && 529 storeQueue[storeWBIdx].inst && 530 storeQueue[storeWBIdx].canWB && 531 usedPorts < cachePorts) { 532 533 // Store didn't write any data so no need to write it back to 534 // memory. 535 if (storeQueue[storeWBIdx].size == 0) { 536 completeStore(storeWBIdx); 537 538 incrStIdx(storeWBIdx); 539 540 continue; 541 } 542 543 if (dcacheInterface && dcacheInterface->isBlocked()) { 544 DPRINTF(LSQUnit, "Unable to write back any more stores, cache" 545 " is blocked!\n"); 546 break; 547 } 548 549 ++usedPorts; 550 551 if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { 552 incrStIdx(storeWBIdx); 553 554 continue; 555 } 556 557 assert(storeQueue[storeWBIdx].req); 558 assert(!storeQueue[storeWBIdx].committed); 559 560 MemReqPtr req = storeQueue[storeWBIdx].req; 561 storeQueue[storeWBIdx].committed = true; 562 563 req->cmd = Write; 564 req->completionEvent = NULL; 565 req->time = curTick; 566 assert(!req->data); 567 req->data = new uint8_t[64]; 568 memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 569 570 DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 571 "to Addr:%#x, data:%#x [sn:%lli]\n", 572 storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 573 req->paddr, *(req->data), 574 storeQueue[storeWBIdx].inst->seqNum); 575 576 switch(storeQueue[storeWBIdx].size) { 577 case 1: 578 cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 579 break; 580 case 2: 581 cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 582 break; 583 case 4: 584 cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 585 break; 586 case 8: 587 cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 588 break; 589 default: 590 panic("Unexpected store size!\n"); 591 } 592 593 // Stores other than store conditionals are completed at this 594 // time. Mark them as completed and, if we have a checker, 595 // tell it that the instruction is completed. 596 // @todo: Figure out what time I can say stores are complete in 597 // the timing memory. 598 if (!(req->flags & LOCKED)) { 599 storeQueue[storeWBIdx].inst->setCompleted(); 600 if (cpu->checker) { 601 cpu->checker->tick(storeQueue[storeWBIdx].inst); 602 } 603 } 604 605 if (dcacheInterface) { 606 assert(!req->completionEvent); 607 StoreCompletionEvent *store_event = new 608 StoreCompletionEvent(storeWBIdx, NULL, this); 609 req->completionEvent = store_event; 610 611 MemAccessResult result = dcacheInterface->access(req); 612 613 if (isStalled() && 614 storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { 615 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 616 "load idx:%i\n", 617 stallingStoreIsn, stallingLoadIdx); 618 stalled = false; 619 stallingStoreIsn = 0; 620 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 621 } 622 623 typename IEW::LdWritebackEvent *wb = NULL; 624 if (req->flags & LOCKED) { 625 // Stx_C should not generate a system port transaction 626 // if it misses in the cache, but that might be hard 627 // to accomplish without explicit cache support. 628 wb = new typename 629 IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 630 iewStage); 631 store_event->wbEvent = wb; 632 } 633 634 if (result != MA_HIT && dcacheInterface->doEvents()) { 635 DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n", 636 storeWBIdx); 637 638 DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", 639 storeQueue[storeWBIdx].inst->seqNum); 640 641 //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); 642 643 //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); 644 645 // @todo: Increment stat here. 646 } else { 647 DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", 648 storeWBIdx); 649 650 DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", 651 storeQueue[storeWBIdx].inst->seqNum); 652 } 653 654 incrStIdx(storeWBIdx); 655 } else { 656 panic("Must HAVE DCACHE!!!!!\n"); 657 } 658 } 659 660 // Not sure this should set it to 0. 661 usedPorts = 0; 662 663 assert(stores >= 0 && storesToWB >= 0); 664} 665 666/*template <class Impl> 667void 668LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) 669{ 670 list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), 671 mshrSeqNums.end(), 672 seqNum); 673 674 if (mshr_it != mshrSeqNums.end()) { 675 mshrSeqNums.erase(mshr_it); 676 DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); 677 } 678}*/ 679 680template <class Impl> 681void 682LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) 683{ 684 DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" 685 "(Loads:%i Stores:%i)\n", squashed_num, loads, stores); 686 687 int load_idx = loadTail; 688 decrLdIdx(load_idx); 689 690 while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { 691 DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " 692 "[sn:%lli]\n", 693 loadQueue[load_idx]->readPC(), 694 loadQueue[load_idx]->seqNum); 695 696 if (isStalled() && load_idx == stallingLoadIdx) { 697 stalled = false; 698 stallingStoreIsn = 0; 699 stallingLoadIdx = 0; 700 } 701 702 // Clear the smart pointer to make sure it is decremented. 703 loadQueue[load_idx]->squashed = true; 704 loadQueue[load_idx] = NULL; 705 --loads; 706 707 // Inefficient! 708 loadTail = load_idx; 709 710 decrLdIdx(load_idx); 711 } 712 713 if (isLoadBlocked) { 714 if (squashed_num < blockedLoadSeqNum) { 715 isLoadBlocked = false; 716 loadBlockedHandled = false; 717 blockedLoadSeqNum = 0; 718 } 719 } 720 721 int store_idx = storeTail; 722 decrStIdx(store_idx); 723 724 while (stores != 0 && 725 storeQueue[store_idx].inst->seqNum > squashed_num) { 726 // Instructions marked as can WB are already committed. 727 if (storeQueue[store_idx].canWB) { 728 break; 729 } 730 731 DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " 732 "idx:%i [sn:%lli]\n", 733 storeQueue[store_idx].inst->readPC(), 734 store_idx, storeQueue[store_idx].inst->seqNum); 735 736 // I don't think this can happen. It should have been cleared 737 // by the stalling load. 738 if (isStalled() && 739 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 740 panic("Is stalled should have been cleared by stalling load!\n"); 741 stalled = false; 742 stallingStoreIsn = 0; 743 } 744 745 // Clear the smart pointer to make sure it is decremented. 746 storeQueue[store_idx].inst->squashed = true; 747 storeQueue[store_idx].inst = NULL; 748 storeQueue[store_idx].canWB = 0; 749 750 if (storeQueue[store_idx].req) { 751 // There should not be a completion event if the store has 752 // not yet committed. 753 assert(!storeQueue[store_idx].req->completionEvent); 754 } 755 756 storeQueue[store_idx].req = NULL; 757 --stores; 758 759 // Inefficient! 760 storeTail = store_idx; 761 762 decrStIdx(store_idx); 763 } 764} 765 766template <class Impl> 767void 768LSQUnit<Impl>::completeStore(int store_idx) 769{ 770 assert(storeQueue[store_idx].inst); 771 storeQueue[store_idx].completed = true; 772 --storesToWB; 773 // A bit conservative because a store completion may not free up entries, 774 // but hopefully avoids two store completions in one cycle from making 775 // the CPU tick twice. 776 cpu->activityThisCycle(); 777 778 if (store_idx == storeHead) { 779 do { 780 incrStIdx(storeHead); 781 782 --stores; 783 } while (storeQueue[storeHead].completed && 784 storeHead != storeTail); 785 786 iewStage->updateLSQNextCycle = true; 787 } 788 789 DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head " 790 "idx:%i\n", 791 storeQueue[store_idx].inst->seqNum, store_idx, storeHead); 792 793 if (isStalled() && 794 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 795 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 796 "load idx:%i\n", 797 stallingStoreIsn, stallingLoadIdx); 798 stalled = false; 799 stallingStoreIsn = 0; 800 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 801 } 802 803 storeQueue[store_idx].inst->setCompleted(); 804 805 // Tell the checker we've completed this instruction. Some stores 806 // may get reported twice to the checker, but the checker can 807 // handle that case. 808 if (cpu->checker) { 809 cpu->checker->tick(storeQueue[store_idx].inst); 810 } 811} 812 813template <class Impl> 814inline void 815LSQUnit<Impl>::incrStIdx(int &store_idx) 816{ 817 if (++store_idx >= SQEntries) 818 store_idx = 0; 819} 820 821template <class Impl> 822inline void 823LSQUnit<Impl>::decrStIdx(int &store_idx) 824{ 825 if (--store_idx < 0) 826 store_idx += SQEntries; 827} 828 829template <class Impl> 830inline void 831LSQUnit<Impl>::incrLdIdx(int &load_idx) 832{ 833 if (++load_idx >= LQEntries) 834 load_idx = 0; 835} 836 837template <class Impl> 838inline void 839LSQUnit<Impl>::decrLdIdx(int &load_idx) 840{ 841 if (--load_idx < 0) 842 load_idx += LQEntries; 843} 844 845template <class Impl> 846void 847LSQUnit<Impl>::dumpInsts() 848{ 849 cprintf("Load store queue: Dumping instructions.\n"); 850 cprintf("Load queue size: %i\n", loads); 851 cprintf("Load queue: "); 852 853 int load_idx = loadHead; 854 855 while (load_idx != loadTail && loadQueue[load_idx]) { 856 cprintf("%#x ", loadQueue[load_idx]->readPC()); 857 858 incrLdIdx(load_idx); 859 } 860 861 cprintf("Store queue size: %i\n", stores); 862 cprintf("Store queue: "); 863 864 int store_idx = storeHead; 865 866 while (store_idx != storeTail && storeQueue[store_idx].inst) { 867 cprintf("%#x ", storeQueue[store_idx].inst->readPC()); 868 869 incrStIdx(store_idx); 870 } 871 872 cprintf("\n"); 873} 874