lsq_unit_impl.hh revision 2316
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 storeIdx(store_idx), 39 wbEvent(wb_event), 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 LQEntries = maxLQEntries; 90 SQEntries = maxSQEntries; 91 92 loadQueue.resize(LQEntries); 93 storeQueue.resize(SQEntries); 94 95 96 // May want to initialize these entries to NULL 97 98 loadHead = loadTail = 0; 99 100 storeHead = storeWBIdx = storeTail = 0; 101 102 usedPorts = 0; 103 cachePorts = params->cachePorts; 104 105 dcacheInterface = params->dcacheInterface; 106 107 loadFaultInst = storeFaultInst = memDepViolator = NULL; 108 109 blockedLoadSeqNum = 0; 110} 111 112template<class Impl> 113std::string 114LSQUnit<Impl>::name() const 115{ 116 if (Impl::MaxThreads == 1) { 117 return iewStage->name() + ".lsq"; 118 } else { 119 return iewStage->name() + ".lsq.thread." + to_string(lsqID); 120 } 121} 122 123template<class Impl> 124void 125LSQUnit<Impl>::clearLQ() 126{ 127 loadQueue.clear(); 128} 129 130template<class Impl> 131void 132LSQUnit<Impl>::clearSQ() 133{ 134 storeQueue.clear(); 135} 136 137#if 0 138template<class Impl> 139void 140LSQUnit<Impl>::setPageTable(PageTable *pt_ptr) 141{ 142 DPRINTF(LSQUnit, "Setting the page table pointer.\n"); 143 pTable = pt_ptr; 144} 145#endif 146 147template<class Impl> 148void 149LSQUnit<Impl>::switchOut() 150{ 151 switchedOut = true; 152 for (int i = 0; i < loadQueue.size(); ++i) 153 loadQueue[i] = NULL; 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 loadFaultInst = storeFaultInst = 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 assert( size >= LQEntries); 235 236 if (size > LQEntries) { 237 while (size > loadQueue.size()) { 238 DynInstPtr dummy; 239 loadQueue.push_back(dummy); 240 LQEntries++; 241 } 242 } else { 243 LQEntries = size; 244 } 245 246} 247 248template<class Impl> 249void 250LSQUnit<Impl>::resizeSQ(unsigned size) 251{ 252 if (size > SQEntries) { 253 while (size > storeQueue.size()) { 254 SQEntry dummy; 255 storeQueue.push_back(dummy); 256 SQEntries++; 257 } 258 } else { 259 SQEntries = size; 260 } 261} 262 263template <class Impl> 264void 265LSQUnit<Impl>::insert(DynInstPtr &inst) 266{ 267 // Make sure we really have a memory reference. 268 assert(inst->isMemRef()); 269 270 // Make sure it's one of the two classes of memory references. 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 && loads < LQEntries); 287 288 DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", 289 load_inst->readPC(), loadTail, load_inst->seqNum); 290 291 load_inst->lqIdx = loadTail; 292 293 if (stores == 0) { 294 load_inst->sqIdx = -1; 295 } else { 296 load_inst->sqIdx = storeTail; 297 } 298 299 loadQueue[loadTail] = load_inst; 300 301 incrLdIdx(loadTail); 302 303 ++loads; 304} 305 306template <class Impl> 307void 308LSQUnit<Impl>::insertStore(DynInstPtr &store_inst) 309{ 310 // Make sure it is not full before inserting an instruction. 311 assert((storeTail + 1) % SQEntries != storeHead); 312 assert(stores < SQEntries); 313 314 DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", 315 store_inst->readPC(), storeTail, store_inst->seqNum); 316 317 store_inst->sqIdx = storeTail; 318 store_inst->lqIdx = loadTail; 319 320 storeQueue[storeTail] = SQEntry(store_inst); 321 322 incrStIdx(storeTail); 323 324 ++stores; 325 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 373#if 0 374template <class Impl> 375Fault 376LSQUnit<Impl>::executeLoad() 377{ 378 Fault load_fault = NoFault; 379 DynInstPtr load_inst; 380 381 assert(readyLoads.size() != 0); 382 383 // Execute a ready load. 384 LdMapIt ready_it = readyLoads.begin(); 385 386 load_inst = (*ready_it).second; 387 388 // Execute the instruction, which is held in the data portion of the 389 // iterator. 390 load_fault = load_inst->execute(); 391 392 // If it executed successfully, then switch it over to the executed 393 // loads list. 394 if (load_fault == NoFault) { 395 executedLoads[load_inst->seqNum] = load_inst; 396 397 readyLoads.erase(ready_it); 398 } else { 399 loadFaultInst = load_inst; 400 } 401 402 return load_fault; 403} 404#endif 405 406template <class Impl> 407Fault 408LSQUnit<Impl>::executeLoad(DynInstPtr &inst) 409{ 410 // Execute a specific load. 411 Fault load_fault = NoFault; 412 413 DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", 414 inst->readPC(),inst->seqNum); 415 416 // Make sure it's really in the list. 417 // Normally it should always be in the list. However, 418 /* due to a syscall it may not be the list. 419#ifdef DEBUG 420 int i = loadHead; 421 while (1) { 422 if (i == loadTail && !find(inst)) { 423 assert(0 && "Load not in the queue!"); 424 } else if (loadQueue[i] == inst) { 425 break; 426 } 427 428 i = i + 1; 429 if (i >= LQEntries) { 430 i = 0; 431 } 432 } 433#endif // DEBUG*/ 434 435// load_fault = inst->initiateAcc(); 436 load_fault = inst->execute(); 437 438 // If the instruction faulted, then we need to send it along to commit 439 // without the instruction completing. 440 if (load_fault != NoFault) { 441 // Maybe just set it as can commit here, although that might cause 442 // some other problems with sending traps to the ROB too quickly. 443 iewStage->instToCommit(inst); 444 iewStage->activityThisCycle(); 445 } 446 447 return load_fault; 448} 449 450template <class Impl> 451Fault 452LSQUnit<Impl>::executeLoad(int lq_idx) 453{ 454 // Very hackish. Not sure the best way to check that this 455 // instruction is at the head of the ROB. I should have some sort 456 // of extra information here so that I'm not overloading the 457 // canCommit signal for 15 different things. 458 loadQueue[lq_idx]->setCanCommit(); 459 Fault ret_fault = executeLoad(loadQueue[lq_idx]); 460 loadQueue[lq_idx]->clearCanCommit(); 461 return ret_fault; 462} 463 464template <class Impl> 465Fault 466LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) 467{ 468 using namespace TheISA; 469 // Make sure that a store exists. 470 assert(stores != 0); 471 472 int store_idx = store_inst->sqIdx; 473 474 DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", 475 store_inst->readPC(), store_inst->seqNum); 476 477 // Check the recently completed loads to see if any match this store's 478 // address. If so, then we have a memory ordering violation. 479 int load_idx = store_inst->lqIdx; 480 481 Fault store_fault = store_inst->initiateAcc(); 482// Fault store_fault = store_inst->execute(); 483 484 // Store size should now be available. Use it to get proper offset for 485 // addr comparisons. 486 int size = storeQueue[store_idx].size; 487 488 if (size == 0) { 489 DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", 490 store_inst->readPC(),store_inst->seqNum); 491 492 return store_fault; 493 } 494 495 assert(store_fault == NoFault); 496 497 if (!storeFaultInst) { 498 if (store_fault != NoFault) { 499 panic("Fault in a store instruction!"); 500 storeFaultInst = store_inst; 501 } else if (store_inst->isNonSpeculative()) { 502 // Nonspeculative accesses (namely store conditionals) 503 // need to set themselves as able to writeback if we 504 // haven't had a fault by here. 505 storeQueue[store_idx].canWB = true; 506 507 ++storesToWB; 508 } 509 } 510 511 if (!memDepViolator) { 512 while (load_idx != loadTail) { 513 // Actually should only check loads that have actually executed 514 // Might be safe because effAddr is set to InvalAddr when the 515 // dyn inst is created. 516 517 // Must actually check all addrs in the proper size range 518 // Which is more correct than needs to be. What if for now we just 519 // assume all loads are quad-word loads, and do the addr based 520 // on that. 521 // @todo: Fix this, magic number being used here 522 if ((loadQueue[load_idx]->effAddr >> 8) == 523 (store_inst->effAddr >> 8)) { 524 // A load incorrectly passed this store. Squash and refetch. 525 // For now return a fault to show that it was unsuccessful. 526 memDepViolator = loadQueue[load_idx]; 527 528 return genMachineCheckFault(); 529 } 530 531 incrLdIdx(load_idx); 532 } 533 534 // If we've reached this point, there was no violation. 535 memDepViolator = NULL; 536 } 537 538 return store_fault; 539} 540 541template <class Impl> 542void 543LSQUnit<Impl>::commitLoad() 544{ 545 assert(loadQueue[loadHead]); 546 547 DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 548 loadQueue[loadHead]->readPC()); 549 550 551 loadQueue[loadHead] = NULL; 552 553 incrLdIdx(loadHead); 554 555 --loads; 556} 557 558template <class Impl> 559void 560LSQUnit<Impl>::commitLoad(InstSeqNum &inst) 561{ 562 // Hopefully I don't use this function too much 563 panic("Don't use this function!"); 564 565 int i = loadHead; 566 while (1) { 567 if (i == loadTail) { 568 assert(0 && "Load not in the queue!"); 569 } else if (loadQueue[i]->seqNum == inst) { 570 break; 571 } 572 573 ++i; 574 if (i >= LQEntries) { 575 i = 0; 576 } 577 } 578 579 loadQueue[i]->removeInLSQ(); 580 loadQueue[i] = NULL; 581 --loads; 582} 583 584template <class Impl> 585void 586LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 587{ 588 assert(loads == 0 || loadQueue[loadHead]); 589 590 while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { 591 commitLoad(); 592 } 593} 594 595template <class Impl> 596void 597LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) 598{ 599 assert(stores == 0 || storeQueue[storeHead].inst); 600 601 int store_idx = storeHead; 602 603 while (store_idx != storeTail) { 604 assert(storeQueue[store_idx].inst); 605 if (!storeQueue[store_idx].canWB) { 606 if (storeQueue[store_idx].inst->seqNum > youngest_inst) { 607 break; 608 } 609 DPRINTF(LSQUnit, "Marking store as able to write back, PC " 610 "%#x [sn:%lli]\n", 611 storeQueue[store_idx].inst->readPC(), 612 storeQueue[store_idx].inst->seqNum); 613 614 storeQueue[store_idx].canWB = true; 615 616// --stores; 617 ++storesToWB; 618 } 619 620 incrStIdx(store_idx); 621 } 622} 623 624template <class Impl> 625void 626LSQUnit<Impl>::writebackStores() 627{ 628 while (storesToWB > 0 && 629 storeWBIdx != storeTail && 630 storeQueue[storeWBIdx].inst && 631 storeQueue[storeWBIdx].canWB && 632 usedPorts < cachePorts) { 633 634 if (storeQueue[storeWBIdx].size == 0) { 635 completeStore(storeWBIdx); 636 637 incrStIdx(storeWBIdx); 638 639 continue; 640 } 641 642 if (dcacheInterface && dcacheInterface->isBlocked()) { 643 DPRINTF(LSQUnit, "Unable to write back any more stores, cache" 644 " is blocked!\n"); 645 break; 646 } 647 648 ++usedPorts; 649 650 if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { 651 incrStIdx(storeWBIdx); 652 653 continue; 654 } 655 656 assert(storeQueue[storeWBIdx].req); 657 assert(!storeQueue[storeWBIdx].committed); 658 659 MemReqPtr req = storeQueue[storeWBIdx].req; 660 storeQueue[storeWBIdx].committed = true; 661 662// Fault fault = cpu->translateDataWriteReq(req); 663 req->cmd = Write; 664 req->completionEvent = NULL; 665 req->time = curTick; 666 assert(!req->data); 667 req->data = new uint8_t[64]; 668 memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 669 670 DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 671 "to Addr:%#x, data:%#x [sn:%lli]\n", 672 storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 673 req->paddr, *(req->data), 674 storeQueue[storeWBIdx].inst->seqNum); 675 676 switch(storeQueue[storeWBIdx].size) { 677 case 1: 678 cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 679 break; 680 case 2: 681 cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 682 break; 683 case 4: 684 cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 685 break; 686 case 8: 687 cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 688 break; 689 default: 690 panic("Unexpected store size!\n"); 691 } 692 if (!(req->flags & LOCKED)) { 693 storeQueue[storeWBIdx].inst->setCompleted(); 694 if (cpu->checker) { 695 cpu->checker->tick(storeQueue[storeWBIdx].inst); 696 } 697 } 698 699 if (dcacheInterface) { 700 assert(!req->completionEvent); 701 StoreCompletionEvent *store_event = new 702 StoreCompletionEvent(storeWBIdx, NULL, this); 703 req->completionEvent = store_event; 704 705 MemAccessResult result = dcacheInterface->access(req); 706 707 if (isStalled() && 708 storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { 709 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 710 "load idx:%i\n", 711 stallingStoreIsn, stallingLoadIdx); 712 stalled = false; 713 stallingStoreIsn = 0; 714 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 715 } 716 717 if (result != MA_HIT && dcacheInterface->doEvents()) { 718 typename IEW::LdWritebackEvent *wb = NULL; 719 if (req->flags & LOCKED) { 720 // Stx_C should not generate a system port transaction, 721 // but that might be hard to accomplish. 722 wb = new typename 723 IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 724 iewStage); 725 store_event->wbEvent = wb; 726 } 727 728 DPRINTF(LSQUnit,"D-Cache Write Miss!\n"); 729 730 DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", 731 storeQueue[storeWBIdx].inst->seqNum); 732 733 lastDcacheStall = curTick; 734 735// _status = DcacheMissStall; 736 737 //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); 738 739 //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); 740 741 // Increment stat here or something 742 } else { 743 DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", 744 storeWBIdx); 745 746 DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", 747 storeQueue[storeWBIdx].inst->seqNum); 748 749 750 if (req->flags & LOCKED) { 751 // Stx_C does not generate a system port transaction. 752/* 753 if (req->flags & UNCACHEABLE) { 754 req->result = 2; 755 } else { 756 if (cpu->lockFlag && cpu->lockAddr == req->paddr) { 757 req->result=1; 758 } else { 759 req->result = 0; 760 } 761 } 762*/ 763 typename IEW::LdWritebackEvent *wb = 764 new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 765 iewStage); 766 store_event->wbEvent = wb; 767 } 768 } 769 770 incrStIdx(storeWBIdx); 771 } else { 772 panic("Must HAVE DCACHE!!!!!\n"); 773 } 774 } 775 776 // Not sure this should set it to 0. 777 usedPorts = 0; 778 779 assert(stores >= 0 && storesToWB >= 0); 780} 781 782/*template <class Impl> 783void 784LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) 785{ 786 list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), 787 mshrSeqNums.end(), 788 seqNum); 789 790 if (mshr_it != mshrSeqNums.end()) { 791 mshrSeqNums.erase(mshr_it); 792 DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); 793 } 794}*/ 795 796template <class Impl> 797void 798LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) 799{ 800 DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" 801 "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); 802 803 int load_idx = loadTail; 804 decrLdIdx(load_idx); 805 806 while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { 807 808 // Clear the smart pointer to make sure it is decremented. 809 DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " 810 "[sn:%lli]\n", 811 loadQueue[load_idx]->readPC(), 812 loadQueue[load_idx]->seqNum); 813 814 if (isStalled() && load_idx == stallingLoadIdx) { 815 stalled = false; 816 stallingStoreIsn = 0; 817 stallingLoadIdx = 0; 818 } 819 820 loadQueue[load_idx]->squashed = true; 821 loadQueue[load_idx] = NULL; 822 --loads; 823 824 // Inefficient! 825 loadTail = load_idx; 826 827 decrLdIdx(load_idx); 828 } 829 830 if (isLoadBlocked) { 831 if (squashed_num < blockedLoadSeqNum) { 832 isLoadBlocked = false; 833 loadBlockedHandled = false; 834 blockedLoadSeqNum = 0; 835 } 836 } 837 838 int store_idx = storeTail; 839 decrStIdx(store_idx); 840 841 while (stores != 0 && 842 storeQueue[store_idx].inst->seqNum > squashed_num) { 843 844 if (storeQueue[store_idx].canWB) { 845 break; 846 } 847 848 // Clear the smart pointer to make sure it is decremented. 849 DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " 850 "idx:%i [sn:%lli]\n", 851 storeQueue[store_idx].inst->readPC(), 852 store_idx, storeQueue[store_idx].inst->seqNum); 853 854 // I don't think this can happen. It should have been cleared by the 855 // stalling load. 856 if (isStalled() && 857 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 858 panic("Is stalled should have been cleared by stalling load!\n"); 859 stalled = false; 860 stallingStoreIsn = 0; 861 } 862 863 storeQueue[store_idx].inst->squashed = true; 864 storeQueue[store_idx].inst = NULL; 865 storeQueue[store_idx].canWB = 0; 866 867 if (storeQueue[store_idx].req) { 868 assert(!storeQueue[store_idx].req->completionEvent); 869 } 870 storeQueue[store_idx].req = NULL; 871 --stores; 872 873 // Inefficient! 874 storeTail = store_idx; 875 876 decrStIdx(store_idx); 877 } 878} 879 880template <class Impl> 881void 882LSQUnit<Impl>::dumpInsts() 883{ 884 cprintf("Load store queue: Dumping instructions.\n"); 885 cprintf("Load queue size: %i\n", loads); 886 cprintf("Load queue: "); 887 888 int load_idx = loadHead; 889 890 while (load_idx != loadTail && loadQueue[load_idx]) { 891 cprintf("%#x ", loadQueue[load_idx]->readPC()); 892 893 incrLdIdx(load_idx); 894 } 895 896 cprintf("Store queue size: %i\n", stores); 897 cprintf("Store queue: "); 898 899 int store_idx = storeHead; 900 901 while (store_idx != storeTail && storeQueue[store_idx].inst) { 902 cprintf("%#x ", storeQueue[store_idx].inst->readPC()); 903 904 incrStIdx(store_idx); 905 } 906 907 cprintf("\n"); 908} 909 910template <class Impl> 911void 912LSQUnit<Impl>::completeStore(int store_idx) 913{ 914 assert(storeQueue[store_idx].inst); 915 storeQueue[store_idx].completed = true; 916 --storesToWB; 917 // A bit conservative because a store completion may not free up entries, 918 // but hopefully avoids two store completions in one cycle from making 919 // the CPU tick twice. 920 cpu->activityThisCycle(); 921 922 if (store_idx == storeHead) { 923 do { 924 incrStIdx(storeHead); 925 926 --stores; 927 } while (storeQueue[storeHead].completed && 928 storeHead != storeTail); 929 930 iewStage->updateLSQNextCycle = true; 931 } 932 933 DPRINTF(LSQUnit, "Store head idx:%i\n", storeHead); 934 935 if (isStalled() && 936 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 937 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 938 "load idx:%i\n", 939 stallingStoreIsn, stallingLoadIdx); 940 stalled = false; 941 stallingStoreIsn = 0; 942 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 943 } 944 945 storeQueue[store_idx].inst->setCompleted(); 946 if (cpu->checker) { 947 cpu->checker->tick(storeQueue[store_idx].inst); 948 } 949} 950 951template <class Impl> 952inline void 953LSQUnit<Impl>::incrStIdx(int &store_idx) 954{ 955 if (++store_idx >= SQEntries) 956 store_idx = 0; 957} 958 959template <class Impl> 960inline void 961LSQUnit<Impl>::decrStIdx(int &store_idx) 962{ 963 if (--store_idx < 0) 964 store_idx += SQEntries; 965} 966 967template <class Impl> 968inline void 969LSQUnit<Impl>::incrLdIdx(int &load_idx) 970{ 971 if (++load_idx >= LQEntries) 972 load_idx = 0; 973} 974 975template <class Impl> 976inline void 977LSQUnit<Impl>::decrLdIdx(int &load_idx) 978{ 979 if (--load_idx < 0) 980 load_idx += LQEntries; 981} 982