lsq_unit_impl.hh revision 2310
11689SN/A/* 27783SGiacomo.Gabrielli@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37783SGiacomo.Gabrielli@arm.com * All rights reserved. 47783SGiacomo.Gabrielli@arm.com * 57783SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 67783SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are 77783SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright 87783SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer; 97783SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright 107783SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the 117783SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution; 127783SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its 137783SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from 142316SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271689SN/A */ 281689SN/A 291689SN/A#include "cpu/o3/lsq_unit.hh" 301689SN/A#include "base/str.hh" 311689SN/A 321689SN/Atemplate <class Impl> 331689SN/ALSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, 341689SN/A Event *wb_event, 351689SN/A LSQUnit<Impl> *lsq_ptr) 361689SN/A : Event(&mainEventQueue), 371689SN/A storeIdx(store_idx), 381689SN/A wbEvent(wb_event), 392665SN/A lsqPtr(lsq_ptr) 402665SN/A{ 411689SN/A this->setFlags(Event::AutoDelete); 421061SN/A} 435953Ssaidi@eecs.umich.edu 445596Sgblack@eecs.umich.edutemplate <class Impl> 451061SN/Avoid 461061SN/ALSQUnit<Impl>::StoreCompletionEvent::process() 475596Sgblack@eecs.umich.edu{ 488502Sgblack@eecs.umich.edu DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx); 497720Sgblack@eecs.umich.edu DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx); 505596Sgblack@eecs.umich.edu 518502Sgblack@eecs.umich.edu //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); 524637SN/A 534637SN/A if (lsqPtr->isSwitchedOut()) 544637SN/A return; 554637SN/A 564637SN/A lsqPtr->cpu->wakeCPU(); 578502Sgblack@eecs.umich.edu if (wbEvent) 588502Sgblack@eecs.umich.edu wbEvent->process(); 598502Sgblack@eecs.umich.edu lsqPtr->completeStore(storeIdx); 601061SN/A} 612292SN/A 622292SN/Atemplate <class Impl> 632292SN/Aconst char * 642292SN/ALSQUnit<Impl>::StoreCompletionEvent::description() 652292SN/A{ 665596Sgblack@eecs.umich.edu return "LSQ store completion event"; 672292SN/A} 681464SN/A 691464SN/Atemplate <class Impl> 701464SN/ALSQUnit<Impl>::LSQUnit() 712292SN/A : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), 723782SN/A loadBlockedHandled(false) 731464SN/A{ 741464SN/A} 752292SN/A 763782SN/Atemplate<class Impl> 772292SN/Avoid 781464SN/ALSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, 797783SGiacomo.Gabrielli@arm.com unsigned maxSQEntries, unsigned id) 807783SGiacomo.Gabrielli@arm.com 818471SGiacomo.Gabrielli@arm.com{ 828471SGiacomo.Gabrielli@arm.com DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); 838471SGiacomo.Gabrielli@arm.com 848471SGiacomo.Gabrielli@arm.com switchedOut = false; 858471SGiacomo.Gabrielli@arm.com 868471SGiacomo.Gabrielli@arm.com lsqID = id; 878471SGiacomo.Gabrielli@arm.com 888471SGiacomo.Gabrielli@arm.com LQEntries = maxLQEntries; 898471SGiacomo.Gabrielli@arm.com SQEntries = maxSQEntries; 901061SN/A 911061SN/A loadQueue.resize(LQEntries); 922292SN/A storeQueue.resize(SQEntries); 932292SN/A 945596Sgblack@eecs.umich.edu 952292SN/A // May want to initialize these entries to NULL 962348SN/A 972680SN/A loadHead = loadTail = 0; 982348SN/A 992680SN/A storeHead = storeWBIdx = storeTail = 0; 1002292SN/A 1012292SN/A usedPorts = 0; 1022292SN/A cachePorts = params->cachePorts; 1032292SN/A 1042292SN/A dcacheInterface = params->dcacheInterface; 1052292SN/A 1062292SN/A loadFaultInst = storeFaultInst = memDepViolator = NULL; 1072292SN/A 1082292SN/A blockedLoadSeqNum = 0; 1092292SN/A} 1102292SN/A 1112292SN/Atemplate<class Impl> 1125596Sgblack@eecs.umich.edustd::string 1132292SN/ALSQUnit<Impl>::name() const 1142348SN/A{ 1152680SN/A if (Impl::MaxThreads == 1) { 1162348SN/A return iewStage->name() + ".lsq"; 1172680SN/A } else { 1182292SN/A return iewStage->name() + ".lsq.thread." + to_string(lsqID); 1192292SN/A } 1202292SN/A} 1212292SN/A 1222292SN/Atemplate<class Impl> 1232292SN/Avoid 1242292SN/ALSQUnit<Impl>::clearLQ() 1252292SN/A{ 1262292SN/A loadQueue.clear(); 1272292SN/A} 1282292SN/A 1292292SN/Atemplate<class Impl> 1305596Sgblack@eecs.umich.eduvoid 1312292SN/ALSQUnit<Impl>::clearSQ() 1327758Sminkyu.jeong@arm.com{ 1337758Sminkyu.jeong@arm.com storeQueue.clear(); 1347758Sminkyu.jeong@arm.com} 1357758Sminkyu.jeong@arm.com 1367758Sminkyu.jeong@arm.com#if 0 1377758Sminkyu.jeong@arm.comtemplate<class Impl> 1387758Sminkyu.jeong@arm.comvoid 1392790SN/ALSQUnit<Impl>::setPageTable(PageTable *pt_ptr) 1402292SN/A{ 1417758Sminkyu.jeong@arm.com DPRINTF(LSQUnit, "Setting the page table pointer.\n"); 1427758Sminkyu.jeong@arm.com pTable = pt_ptr; 1432292SN/A} 1442292SN/A#endif 1452292SN/A 1461858SN/Atemplate<class Impl> 1471061SN/Avoid 1485702Ssaidi@eecs.umich.eduLSQUnit<Impl>::switchOut() 1495702Ssaidi@eecs.umich.edu{ 1505702Ssaidi@eecs.umich.edu switchedOut = true; 1515702Ssaidi@eecs.umich.edu for (int i = 0; i < loadQueue.size(); ++i) 1525702Ssaidi@eecs.umich.edu loadQueue[i] = NULL; 1537720Sgblack@eecs.umich.edu 1545702Ssaidi@eecs.umich.edu while (storesToWB > 0 && 1555702Ssaidi@eecs.umich.edu storeWBIdx != storeTail && 1565702Ssaidi@eecs.umich.edu storeQueue[storeWBIdx].inst && 1577720Sgblack@eecs.umich.edu storeQueue[storeWBIdx].canWB) { 1587720Sgblack@eecs.umich.edu 1597720Sgblack@eecs.umich.edu if (storeQueue[storeWBIdx].size == 0 || 1607720Sgblack@eecs.umich.edu storeQueue[storeWBIdx].inst->isDataPrefetch() || 1615953Ssaidi@eecs.umich.edu storeQueue[storeWBIdx].committed || 1625953Ssaidi@eecs.umich.edu storeQueue[storeWBIdx].req->flags & LOCKED) { 1637720Sgblack@eecs.umich.edu incrStIdx(storeWBIdx); 1645953Ssaidi@eecs.umich.edu 1655702Ssaidi@eecs.umich.edu continue; 1665702Ssaidi@eecs.umich.edu } 1675702Ssaidi@eecs.umich.edu 1685702Ssaidi@eecs.umich.edu assert(storeQueue[storeWBIdx].req); 1695702Ssaidi@eecs.umich.edu assert(!storeQueue[storeWBIdx].committed); 1705702Ssaidi@eecs.umich.edu 1715702Ssaidi@eecs.umich.edu MemReqPtr req = storeQueue[storeWBIdx].req; 1725702Ssaidi@eecs.umich.edu storeQueue[storeWBIdx].committed = true; 1735702Ssaidi@eecs.umich.edu 1745702Ssaidi@eecs.umich.edu req->cmd = Write; 1755702Ssaidi@eecs.umich.edu req->completionEvent = NULL; 1761061SN/A req->time = curTick; 1775596Sgblack@eecs.umich.edu assert(!req->data); 1781061SN/A req->data = new uint8_t[64]; 1797684Sgblack@eecs.umich.edu memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 1801061SN/A 1815702Ssaidi@eecs.umich.edu DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 1825702Ssaidi@eecs.umich.edu "to Addr:%#x, data:%#x [sn:%lli]\n", 1835702Ssaidi@eecs.umich.edu storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 1845702Ssaidi@eecs.umich.edu req->paddr, *(req->data), 1855702Ssaidi@eecs.umich.edu storeQueue[storeWBIdx].inst->seqNum); 1865702Ssaidi@eecs.umich.edu 1875702Ssaidi@eecs.umich.edu switch(storeQueue[storeWBIdx].size) { 1885702Ssaidi@eecs.umich.edu case 1: 1895702Ssaidi@eecs.umich.edu cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 1905702Ssaidi@eecs.umich.edu break; 1918557Sgblack@eecs.umich.edu case 2: 1928557Sgblack@eecs.umich.edu cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 1931061SN/A break; 1941061SN/A case 4: 1955596Sgblack@eecs.umich.edu cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 1961061SN/A break; 1978557Sgblack@eecs.umich.edu case 8: 1988557Sgblack@eecs.umich.edu cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 1998557Sgblack@eecs.umich.edu break; 2005556SN/A default: 2015556SN/A panic("Unexpected store size!\n"); 2025556SN/A } 2037720Sgblack@eecs.umich.edu incrStIdx(storeWBIdx); 2042669SN/A } 2057720Sgblack@eecs.umich.edu} 2067720Sgblack@eecs.umich.edu 2077720Sgblack@eecs.umich.edutemplate<class Impl> 2085556SN/Avoid 2098557Sgblack@eecs.umich.eduLSQUnit<Impl>::takeOverFrom() 2101061SN/A{ 2111061SN/A switchedOut = false; 212 loads = stores = storesToWB = 0; 213 214 loadHead = loadTail = 0; 215 216 storeHead = storeWBIdx = storeTail = 0; 217 218 usedPorts = 0; 219 220 loadFaultInst = storeFaultInst = memDepViolator = NULL; 221 222 blockedLoadSeqNum = 0; 223 224 stalled = false; 225 isLoadBlocked = false; 226 loadBlockedHandled = false; 227} 228 229template<class Impl> 230void 231LSQUnit<Impl>::resizeLQ(unsigned size) 232{ 233 assert( size >= LQEntries); 234 235 if (size > LQEntries) { 236 while (size > loadQueue.size()) { 237 DynInstPtr dummy; 238 loadQueue.push_back(dummy); 239 LQEntries++; 240 } 241 } else { 242 LQEntries = size; 243 } 244 245} 246 247template<class Impl> 248void 249LSQUnit<Impl>::resizeSQ(unsigned size) 250{ 251 if (size > SQEntries) { 252 while (size > storeQueue.size()) { 253 SQEntry dummy; 254 storeQueue.push_back(dummy); 255 SQEntries++; 256 } 257 } else { 258 SQEntries = size; 259 } 260} 261 262template <class Impl> 263void 264LSQUnit<Impl>::insert(DynInstPtr &inst) 265{ 266 // Make sure we really have a memory reference. 267 assert(inst->isMemRef()); 268 269 // Make sure it's one of the two classes of memory references. 270 assert(inst->isLoad() || inst->isStore()); 271 272 if (inst->isLoad()) { 273 insertLoad(inst); 274 } else { 275 insertStore(inst); 276 } 277 278 inst->setInLSQ(); 279} 280 281template <class Impl> 282void 283LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) 284{ 285 assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries); 286 287 DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", 288 load_inst->readPC(), loadTail, load_inst->seqNum); 289 290 load_inst->lqIdx = loadTail; 291 292 if (stores == 0) { 293 load_inst->sqIdx = -1; 294 } else { 295 load_inst->sqIdx = storeTail; 296 } 297 298 loadQueue[loadTail] = load_inst; 299 300 incrLdIdx(loadTail); 301 302 ++loads; 303} 304 305template <class Impl> 306void 307LSQUnit<Impl>::insertStore(DynInstPtr &store_inst) 308{ 309 // Make sure it is not full before inserting an instruction. 310 assert((storeTail + 1) % SQEntries != storeHead); 311 assert(stores < SQEntries); 312 313 DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", 314 store_inst->readPC(), storeTail, store_inst->seqNum); 315 316 store_inst->sqIdx = storeTail; 317 store_inst->lqIdx = loadTail; 318 319 storeQueue[storeTail] = SQEntry(store_inst); 320 321 incrStIdx(storeTail); 322 323 ++stores; 324 325} 326 327template <class Impl> 328typename Impl::DynInstPtr 329LSQUnit<Impl>::getMemDepViolator() 330{ 331 DynInstPtr temp = memDepViolator; 332 333 memDepViolator = NULL; 334 335 return temp; 336} 337 338template <class Impl> 339unsigned 340LSQUnit<Impl>::numFreeEntries() 341{ 342 unsigned free_lq_entries = LQEntries - loads; 343 unsigned free_sq_entries = SQEntries - stores; 344 345 // Both the LQ and SQ entries have an extra dummy entry to differentiate 346 // empty/full conditions. Subtract 1 from the free entries. 347 if (free_lq_entries < free_sq_entries) { 348 return free_lq_entries - 1; 349 } else { 350 return free_sq_entries - 1; 351 } 352} 353 354template <class Impl> 355int 356LSQUnit<Impl>::numLoadsReady() 357{ 358 int load_idx = loadHead; 359 int retval = 0; 360 361 while (load_idx != loadTail) { 362 assert(loadQueue[load_idx]); 363 364 if (loadQueue[load_idx]->readyToIssue()) { 365 ++retval; 366 } 367 } 368 369 return retval; 370} 371 372#if 0 373template <class Impl> 374Fault 375LSQUnit<Impl>::executeLoad() 376{ 377 Fault load_fault = NoFault; 378 DynInstPtr load_inst; 379 380 assert(readyLoads.size() != 0); 381 382 // Execute a ready load. 383 LdMapIt ready_it = readyLoads.begin(); 384 385 load_inst = (*ready_it).second; 386 387 // Execute the instruction, which is held in the data portion of the 388 // iterator. 389 load_fault = load_inst->execute(); 390 391 // If it executed successfully, then switch it over to the executed 392 // loads list. 393 if (load_fault == NoFault) { 394 executedLoads[load_inst->seqNum] = load_inst; 395 396 readyLoads.erase(ready_it); 397 } else { 398 loadFaultInst = load_inst; 399 } 400 401 return load_fault; 402} 403#endif 404 405template <class Impl> 406Fault 407LSQUnit<Impl>::executeLoad(DynInstPtr &inst) 408{ 409 // Execute a specific load. 410 Fault load_fault = NoFault; 411 412 DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", 413 inst->readPC(),inst->seqNum); 414 415 // Make sure it's really in the list. 416 // Normally it should always be in the list. However, 417 /* due to a syscall it may not be the list. 418#ifdef DEBUG 419 int i = loadHead; 420 while (1) { 421 if (i == loadTail && !find(inst)) { 422 assert(0 && "Load not in the queue!"); 423 } else if (loadQueue[i] == inst) { 424 break; 425 } 426 427 i = i + 1; 428 if (i >= LQEntries) { 429 i = 0; 430 } 431 } 432#endif // DEBUG*/ 433 434// load_fault = inst->initiateAcc(); 435 load_fault = inst->execute(); 436 437 // If the instruction faulted, then we need to send it along to commit 438 // without the instruction completing. 439 if (load_fault != NoFault) { 440 // Maybe just set it as can commit here, although that might cause 441 // some other problems with sending traps to the ROB too quickly. 442 iewStage->instToCommit(inst); 443 iewStage->activityThisCycle(); 444 } 445 446 return load_fault; 447} 448 449template <class Impl> 450Fault 451LSQUnit<Impl>::executeLoad(int lq_idx) 452{ 453 // Very hackish. Not sure the best way to check that this 454 // instruction is at the head of the ROB. I should have some sort 455 // of extra information here so that I'm not overloading the 456 // canCommit signal for 15 different things. 457 loadQueue[lq_idx]->setCanCommit(); 458 Fault ret_fault = executeLoad(loadQueue[lq_idx]); 459 loadQueue[lq_idx]->clearCanCommit(); 460 return ret_fault; 461} 462 463template <class Impl> 464Fault 465LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) 466{ 467 using namespace TheISA; 468 // Make sure that a store exists. 469 assert(stores != 0); 470 471 int store_idx = store_inst->sqIdx; 472 473 DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", 474 store_inst->readPC(), store_inst->seqNum); 475 476 // Check the recently completed loads to see if any match this store's 477 // address. If so, then we have a memory ordering violation. 478 int load_idx = store_inst->lqIdx; 479 480 Fault store_fault = store_inst->initiateAcc(); 481// Fault store_fault = store_inst->execute(); 482 483 // Store size should now be available. Use it to get proper offset for 484 // addr comparisons. 485 int size = storeQueue[store_idx].size; 486 487 if (size == 0) { 488 DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", 489 store_inst->readPC(),store_inst->seqNum); 490 491 return store_fault; 492 } 493 494 assert(store_fault == NoFault); 495 496 if (!storeFaultInst) { 497 if (store_fault != NoFault) { 498 panic("Fault in a store instruction!"); 499 storeFaultInst = store_inst; 500 } else if (store_inst->isNonSpeculative()) { 501 // Nonspeculative accesses (namely store conditionals) 502 // need to set themselves as able to writeback if we 503 // haven't had a fault by here. 504 storeQueue[store_idx].canWB = true; 505 506 ++storesToWB; 507 } 508 } 509 510 if (!memDepViolator) { 511 while (load_idx != loadTail) { 512 // Actually should only check loads that have actually executed 513 // Might be safe because effAddr is set to InvalAddr when the 514 // dyn inst is created. 515 516 // Must actually check all addrs in the proper size range 517 // Which is more correct than needs to be. What if for now we just 518 // assume all loads are quad-word loads, and do the addr based 519 // on that. 520 // @todo: Fix this, magic number being used here 521 if ((loadQueue[load_idx]->effAddr >> 8) == 522 (store_inst->effAddr >> 8)) { 523 // A load incorrectly passed this store. Squash and refetch. 524 // For now return a fault to show that it was unsuccessful. 525 memDepViolator = loadQueue[load_idx]; 526 527 return genMachineCheckFault(); 528 } 529 530 incrLdIdx(load_idx); 531 } 532 533 // If we've reached this point, there was no violation. 534 memDepViolator = NULL; 535 } 536 537 return store_fault; 538} 539 540template <class Impl> 541void 542LSQUnit<Impl>::commitLoad() 543{ 544 assert(loadQueue[loadHead]); 545 546 DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 547 loadQueue[loadHead]->readPC()); 548 549 550 loadQueue[loadHead] = NULL; 551 552 incrLdIdx(loadHead); 553 554 --loads; 555} 556 557template <class Impl> 558void 559LSQUnit<Impl>::commitLoad(InstSeqNum &inst) 560{ 561 // Hopefully I don't use this function too much 562 panic("Don't use this function!"); 563 564 int i = loadHead; 565 while (1) { 566 if (i == loadTail) { 567 assert(0 && "Load not in the queue!"); 568 } else if (loadQueue[i]->seqNum == inst) { 569 break; 570 } 571 572 ++i; 573 if (i >= LQEntries) { 574 i = 0; 575 } 576 } 577 578 loadQueue[i]->removeInLSQ(); 579 loadQueue[i] = NULL; 580 --loads; 581} 582 583template <class Impl> 584void 585LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 586{ 587 assert(loads == 0 || loadQueue[loadHead]); 588 589 while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { 590 commitLoad(); 591 } 592} 593 594template <class Impl> 595void 596LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) 597{ 598 assert(stores == 0 || storeQueue[storeHead].inst); 599 600 int store_idx = storeHead; 601 602 while (store_idx != storeTail) { 603 assert(storeQueue[store_idx].inst); 604 if (!storeQueue[store_idx].canWB) { 605 if (storeQueue[store_idx].inst->seqNum > youngest_inst) { 606 break; 607 } 608 DPRINTF(LSQUnit, "Marking store as able to write back, PC " 609 "%#x [sn:%lli]\n", 610 storeQueue[store_idx].inst->readPC(), 611 storeQueue[store_idx].inst->seqNum); 612 613 storeQueue[store_idx].canWB = true; 614 615// --stores; 616 ++storesToWB; 617 } 618 619 incrStIdx(store_idx); 620 } 621} 622 623template <class Impl> 624void 625LSQUnit<Impl>::writebackStores() 626{ 627 while (storesToWB > 0 && 628 storeWBIdx != storeTail && 629 storeQueue[storeWBIdx].inst && 630 storeQueue[storeWBIdx].canWB && 631 usedPorts < cachePorts) { 632 633 if (storeQueue[storeWBIdx].size == 0) { 634 completeStore(storeWBIdx); 635 636 incrStIdx(storeWBIdx); 637 638 continue; 639 } 640 641 if (dcacheInterface && dcacheInterface->isBlocked()) { 642 DPRINTF(LSQUnit, "Unable to write back any more stores, cache" 643 " is blocked!\n"); 644 break; 645 } 646 647 ++usedPorts; 648 649 if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { 650 incrStIdx(storeWBIdx); 651 652 continue; 653 } 654 655 assert(storeQueue[storeWBIdx].req); 656 assert(!storeQueue[storeWBIdx].committed); 657 658 MemReqPtr req = storeQueue[storeWBIdx].req; 659 storeQueue[storeWBIdx].committed = true; 660 661// Fault fault = cpu->translateDataWriteReq(req); 662 req->cmd = Write; 663 req->completionEvent = NULL; 664 req->time = curTick; 665 assert(!req->data); 666 req->data = new uint8_t[64]; 667 memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 668 669 DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 670 "to Addr:%#x, data:%#x [sn:%lli]\n", 671 storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 672 req->paddr, *(req->data), 673 storeQueue[storeWBIdx].inst->seqNum); 674 675 switch(storeQueue[storeWBIdx].size) { 676 case 1: 677 cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 678 break; 679 case 2: 680 cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 681 break; 682 case 4: 683 cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 684 break; 685 case 8: 686 cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 687 break; 688 default: 689 panic("Unexpected store size!\n"); 690 } 691 if (!(req->flags & LOCKED)) { 692 storeQueue[storeWBIdx].inst->setCompleted(); 693 } 694 695 if (dcacheInterface) { 696 assert(!req->completionEvent); 697 StoreCompletionEvent *store_event = new 698 StoreCompletionEvent(storeWBIdx, NULL, this); 699 req->completionEvent = store_event; 700 701 MemAccessResult result = dcacheInterface->access(req); 702 703 if (isStalled() && 704 storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { 705 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 706 "load idx:%i\n", 707 stallingStoreIsn, stallingLoadIdx); 708 stalled = false; 709 stallingStoreIsn = 0; 710 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 711 } 712 713 if (result != MA_HIT && dcacheInterface->doEvents()) { 714 typename IEW::LdWritebackEvent *wb = NULL; 715 if (req->flags & LOCKED) { 716 // Stx_C should not generate a system port transaction, 717 // but that might be hard to accomplish. 718 wb = new typename 719 IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 720 iewStage); 721 store_event->wbEvent = wb; 722 } 723 724 DPRINTF(LSQUnit,"D-Cache Write Miss!\n"); 725 726 DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", 727 storeQueue[storeWBIdx].inst->seqNum); 728 729 lastDcacheStall = curTick; 730 731// _status = DcacheMissStall; 732 733 //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); 734 735 //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); 736 737 // Increment stat here or something 738 } else { 739 DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", 740 storeWBIdx); 741 742 DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", 743 storeQueue[storeWBIdx].inst->seqNum); 744 745 746 if (req->flags & LOCKED) { 747 // Stx_C does not generate a system port transaction. 748/* 749 if (req->flags & UNCACHEABLE) { 750 req->result = 2; 751 } else { 752 if (cpu->lockFlag && cpu->lockAddr == req->paddr) { 753 req->result=1; 754 } else { 755 req->result = 0; 756 } 757 } 758*/ 759 typename IEW::LdWritebackEvent *wb = 760 new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 761 iewStage); 762 store_event->wbEvent = wb; 763 } 764 } 765 766 incrStIdx(storeWBIdx); 767 } else { 768 panic("Must HAVE DCACHE!!!!!\n"); 769 } 770 } 771 772 // Not sure this should set it to 0. 773 usedPorts = 0; 774 775 assert(stores >= 0 && storesToWB >= 0); 776} 777 778/*template <class Impl> 779void 780LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) 781{ 782 list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), 783 mshrSeqNums.end(), 784 seqNum); 785 786 if (mshr_it != mshrSeqNums.end()) { 787 mshrSeqNums.erase(mshr_it); 788 DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); 789 } 790}*/ 791 792template <class Impl> 793void 794LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) 795{ 796 DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" 797 "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); 798 799 int load_idx = loadTail; 800 decrLdIdx(load_idx); 801 802 while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { 803 804 // Clear the smart pointer to make sure it is decremented. 805 DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " 806 "[sn:%lli]\n", 807 loadQueue[load_idx]->readPC(), 808 loadQueue[load_idx]->seqNum); 809 810 if (isStalled() && load_idx == stallingLoadIdx) { 811 stalled = false; 812 stallingStoreIsn = 0; 813 stallingLoadIdx = 0; 814 } 815 816 loadQueue[load_idx]->squashed = true; 817 loadQueue[load_idx] = NULL; 818 --loads; 819 820 // Inefficient! 821 loadTail = load_idx; 822 823 decrLdIdx(load_idx); 824 } 825 826 if (isLoadBlocked) { 827 if (squashed_num < blockedLoadSeqNum) { 828 isLoadBlocked = false; 829 loadBlockedHandled = false; 830 blockedLoadSeqNum = 0; 831 } 832 } 833 834 int store_idx = storeTail; 835 decrStIdx(store_idx); 836 837 while (stores != 0 && 838 storeQueue[store_idx].inst->seqNum > squashed_num) { 839 840 if (storeQueue[store_idx].canWB) { 841 break; 842 } 843 844 // Clear the smart pointer to make sure it is decremented. 845 DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " 846 "idx:%i [sn:%lli]\n", 847 storeQueue[store_idx].inst->readPC(), 848 store_idx, storeQueue[store_idx].inst->seqNum); 849 850 // I don't think this can happen. It should have been cleared by the 851 // stalling load. 852 if (isStalled() && 853 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 854 panic("Is stalled should have been cleared by stalling load!\n"); 855 stalled = false; 856 stallingStoreIsn = 0; 857 } 858 859 storeQueue[store_idx].inst->squashed = true; 860 storeQueue[store_idx].inst = NULL; 861 storeQueue[store_idx].canWB = 0; 862 863 if (storeQueue[store_idx].req) { 864 assert(!storeQueue[store_idx].req->completionEvent); 865 } 866 storeQueue[store_idx].req = NULL; 867 --stores; 868 869 // Inefficient! 870 storeTail = store_idx; 871 872 decrStIdx(store_idx); 873 } 874} 875 876template <class Impl> 877void 878LSQUnit<Impl>::dumpInsts() 879{ 880 cprintf("Load store queue: Dumping instructions.\n"); 881 cprintf("Load queue size: %i\n", loads); 882 cprintf("Load queue: "); 883 884 int load_idx = loadHead; 885 886 while (load_idx != loadTail && loadQueue[load_idx]) { 887 cprintf("%#x ", loadQueue[load_idx]->readPC()); 888 889 incrLdIdx(load_idx); 890 } 891 892 cprintf("Store queue size: %i\n", stores); 893 cprintf("Store queue: "); 894 895 int store_idx = storeHead; 896 897 while (store_idx != storeTail && storeQueue[store_idx].inst) { 898 cprintf("%#x ", storeQueue[store_idx].inst->readPC()); 899 900 incrStIdx(store_idx); 901 } 902 903 cprintf("\n"); 904} 905 906template <class Impl> 907void 908LSQUnit<Impl>::completeStore(int store_idx) 909{ 910 assert(storeQueue[store_idx].inst); 911 storeQueue[store_idx].completed = true; 912 --storesToWB; 913 // A bit conservative because a store completion may not free up entries, 914 // but hopefully avoids two store completions in one cycle from making 915 // the CPU tick twice. 916 cpu->activityThisCycle(); 917 918 if (store_idx == storeHead) { 919 do { 920 incrStIdx(storeHead); 921 922 --stores; 923 } while (storeQueue[storeHead].completed && 924 storeHead != storeTail); 925 926 iewStage->updateLSQNextCycle = true; 927 } 928 929 DPRINTF(LSQUnit, "Store head idx:%i\n", storeHead); 930 931 if (isStalled() && 932 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 933 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 934 "load idx:%i\n", 935 stallingStoreIsn, stallingLoadIdx); 936 stalled = false; 937 stallingStoreIsn = 0; 938 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 939 } 940} 941 942template <class Impl> 943inline void 944LSQUnit<Impl>::incrStIdx(int &store_idx) 945{ 946 if (++store_idx >= SQEntries) 947 store_idx = 0; 948} 949 950template <class Impl> 951inline void 952LSQUnit<Impl>::decrStIdx(int &store_idx) 953{ 954 if (--store_idx < 0) 955 store_idx += SQEntries; 956} 957 958template <class Impl> 959inline void 960LSQUnit<Impl>::incrLdIdx(int &load_idx) 961{ 962 if (++load_idx >= LQEntries) 963 load_idx = 0; 964} 965 966template <class Impl> 967inline void 968LSQUnit<Impl>::decrLdIdx(int &load_idx) 969{ 970 if (--load_idx < 0) 971 load_idx += LQEntries; 972} 973