lsq_unit_impl.hh revision 2336
111524Sdavid.guillen@arm.com/* 211524Sdavid.guillen@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 311524Sdavid.guillen@arm.com * All rights reserved. 411524Sdavid.guillen@arm.com * 511524Sdavid.guillen@arm.com * Redistribution and use in source and binary forms, with or without 611524Sdavid.guillen@arm.com * modification, are permitted provided that the following conditions are 711524Sdavid.guillen@arm.com * met: redistributions of source code must retain the above copyright 811524Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer; 911524Sdavid.guillen@arm.com * redistributions in binary form must reproduce the above copyright 1011524Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer in the 1111524Sdavid.guillen@arm.com * documentation and/or other materials provided with the distribution; 1211524Sdavid.guillen@arm.com * neither the name of the copyright holders nor the names of its 1311524Sdavid.guillen@arm.com * contributors may be used to endorse or promote products derived from 1411524Sdavid.guillen@arm.com * this software without specific prior written permission. 1511524Sdavid.guillen@arm.com * 1611524Sdavid.guillen@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1711524Sdavid.guillen@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1811524Sdavid.guillen@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1911524Sdavid.guillen@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2011524Sdavid.guillen@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2111524Sdavid.guillen@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2211524Sdavid.guillen@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2311524Sdavid.guillen@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411524Sdavid.guillen@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511524Sdavid.guillen@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611524Sdavid.guillen@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2711524Sdavid.guillen@arm.com */ 2811524Sdavid.guillen@arm.com 2911524Sdavid.guillen@arm.com#include "cpu/checker/cpu.hh" 3011524Sdavid.guillen@arm.com#include "cpu/o3/lsq_unit.hh" 3111524Sdavid.guillen@arm.com#include "base/str.hh" 3211524Sdavid.guillen@arm.com 3311524Sdavid.guillen@arm.comtemplate <class Impl> 3411524Sdavid.guillen@arm.comLSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, 3511524Sdavid.guillen@arm.com Event *wb_event, 3611524Sdavid.guillen@arm.com LSQUnit<Impl> *lsq_ptr) 3711524Sdavid.guillen@arm.com : Event(&mainEventQueue), 3811524Sdavid.guillen@arm.com wbEvent(wb_event), 3911524Sdavid.guillen@arm.com storeIdx(store_idx), 4011524Sdavid.guillen@arm.com lsqPtr(lsq_ptr) 4111524Sdavid.guillen@arm.com{ 4211524Sdavid.guillen@arm.com this->setFlags(Event::AutoDelete); 4311524Sdavid.guillen@arm.com} 4411524Sdavid.guillen@arm.com 4511524Sdavid.guillen@arm.comtemplate <class Impl> 4611524Sdavid.guillen@arm.comvoid 4711524Sdavid.guillen@arm.comLSQUnit<Impl>::StoreCompletionEvent::process() 4811524Sdavid.guillen@arm.com{ 4911524Sdavid.guillen@arm.com DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx); 5011524Sdavid.guillen@arm.com DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx); 5111524Sdavid.guillen@arm.com 5211524Sdavid.guillen@arm.com //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); 5311524Sdavid.guillen@arm.com 5411524Sdavid.guillen@arm.com if (lsqPtr->isSwitchedOut()) 5511524Sdavid.guillen@arm.com return; 5611524Sdavid.guillen@arm.com 5711524Sdavid.guillen@arm.com lsqPtr->cpu->wakeCPU(); 5811524Sdavid.guillen@arm.com if (wbEvent) 5911524Sdavid.guillen@arm.com wbEvent->process(); 6011524Sdavid.guillen@arm.com lsqPtr->completeStore(storeIdx); 6111524Sdavid.guillen@arm.com} 6211524Sdavid.guillen@arm.com 6311524Sdavid.guillen@arm.comtemplate <class Impl> 6411524Sdavid.guillen@arm.comconst char * 6511524Sdavid.guillen@arm.comLSQUnit<Impl>::StoreCompletionEvent::description() 6611524Sdavid.guillen@arm.com{ 6711524Sdavid.guillen@arm.com return "LSQ store completion event"; 6811524Sdavid.guillen@arm.com} 6911524Sdavid.guillen@arm.com 7011524Sdavid.guillen@arm.comtemplate <class Impl> 7111524Sdavid.guillen@arm.comLSQUnit<Impl>::LSQUnit() 7211524Sdavid.guillen@arm.com : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), 7311524Sdavid.guillen@arm.com loadBlockedHandled(false) 7411524Sdavid.guillen@arm.com{ 7511524Sdavid.guillen@arm.com} 7611524Sdavid.guillen@arm.com 7711524Sdavid.guillen@arm.comtemplate<class Impl> 7811524Sdavid.guillen@arm.comvoid 7911524Sdavid.guillen@arm.comLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, 8011524Sdavid.guillen@arm.com unsigned maxSQEntries, unsigned id) 8111524Sdavid.guillen@arm.com 8211524Sdavid.guillen@arm.com{ 8311524Sdavid.guillen@arm.com DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); 8411524Sdavid.guillen@arm.com 8511524Sdavid.guillen@arm.com switchedOut = false; 8611524Sdavid.guillen@arm.com 8711524Sdavid.guillen@arm.com lsqID = id; 8811524Sdavid.guillen@arm.com 8911524Sdavid.guillen@arm.com // Add 1 for the sentinel entry (they are circular queues). 9011524Sdavid.guillen@arm.com LQEntries = maxLQEntries + 1; 9111524Sdavid.guillen@arm.com SQEntries = maxSQEntries + 1; 9211524Sdavid.guillen@arm.com 9311524Sdavid.guillen@arm.com loadQueue.resize(LQEntries); 9411524Sdavid.guillen@arm.com storeQueue.resize(SQEntries); 9511524Sdavid.guillen@arm.com 9611524Sdavid.guillen@arm.com loadHead = loadTail = 0; 9711524Sdavid.guillen@arm.com 9811524Sdavid.guillen@arm.com storeHead = storeWBIdx = storeTail = 0; 9911524Sdavid.guillen@arm.com 10011524Sdavid.guillen@arm.com usedPorts = 0; 10111524Sdavid.guillen@arm.com cachePorts = params->cachePorts; 10211524Sdavid.guillen@arm.com 10311524Sdavid.guillen@arm.com dcacheInterface = params->dcacheInterface; 10411524Sdavid.guillen@arm.com 10511524Sdavid.guillen@arm.com memDepViolator = NULL; 10611524Sdavid.guillen@arm.com 10711524Sdavid.guillen@arm.com blockedLoadSeqNum = 0; 10811524Sdavid.guillen@arm.com} 10911524Sdavid.guillen@arm.com 11011524Sdavid.guillen@arm.comtemplate<class Impl> 11111524Sdavid.guillen@arm.comstd::string 11211524Sdavid.guillen@arm.comLSQUnit<Impl>::name() const 11311524Sdavid.guillen@arm.com{ 11411524Sdavid.guillen@arm.com if (Impl::MaxThreads == 1) { 11511524Sdavid.guillen@arm.com return iewStage->name() + ".lsq"; 11611524Sdavid.guillen@arm.com } else { 11711524Sdavid.guillen@arm.com return iewStage->name() + ".lsq.thread." + to_string(lsqID); 11811524Sdavid.guillen@arm.com } 11911524Sdavid.guillen@arm.com} 12011524Sdavid.guillen@arm.com 12111524Sdavid.guillen@arm.comtemplate<class Impl> 12211524Sdavid.guillen@arm.comvoid 12311524Sdavid.guillen@arm.comLSQUnit<Impl>::clearLQ() 12411524Sdavid.guillen@arm.com{ 12511524Sdavid.guillen@arm.com loadQueue.clear(); 12611524Sdavid.guillen@arm.com} 12711524Sdavid.guillen@arm.com 12811524Sdavid.guillen@arm.comtemplate<class Impl> 12911524Sdavid.guillen@arm.comvoid 13011524Sdavid.guillen@arm.comLSQUnit<Impl>::clearSQ() 13111524Sdavid.guillen@arm.com{ 13211524Sdavid.guillen@arm.com storeQueue.clear(); 13311524Sdavid.guillen@arm.com} 13411524Sdavid.guillen@arm.com 13511524Sdavid.guillen@arm.com#if 0 13611524Sdavid.guillen@arm.comtemplate<class Impl> 13711524Sdavid.guillen@arm.comvoid 13811524Sdavid.guillen@arm.comLSQUnit<Impl>::setPageTable(PageTable *pt_ptr) 13911524Sdavid.guillen@arm.com{ 14011524Sdavid.guillen@arm.com DPRINTF(LSQUnit, "Setting the page table pointer.\n"); 14111524Sdavid.guillen@arm.com pTable = pt_ptr; 14211524Sdavid.guillen@arm.com} 14311524Sdavid.guillen@arm.com#endif 14411524Sdavid.guillen@arm.com 14511525Sandreas.sandberg@arm.comtemplate<class Impl> 14611524Sdavid.guillen@arm.comvoid 14711524Sdavid.guillen@arm.comLSQUnit<Impl>::switchOut() 14811524Sdavid.guillen@arm.com{ 14911524Sdavid.guillen@arm.com switchedOut = true; 15011524Sdavid.guillen@arm.com for (int i = 0; i < loadQueue.size(); ++i) 15111524Sdavid.guillen@arm.com loadQueue[i] = NULL; 15211524Sdavid.guillen@arm.com 15311524Sdavid.guillen@arm.com assert(storesToWB == 0); 15411524Sdavid.guillen@arm.com 15511525Sandreas.sandberg@arm.com while (storesToWB > 0 && 15611524Sdavid.guillen@arm.com storeWBIdx != storeTail && 15711524Sdavid.guillen@arm.com storeQueue[storeWBIdx].inst && 15811524Sdavid.guillen@arm.com storeQueue[storeWBIdx].canWB) { 15911524Sdavid.guillen@arm.com 16011524Sdavid.guillen@arm.com if (storeQueue[storeWBIdx].size == 0 || 16111524Sdavid.guillen@arm.com storeQueue[storeWBIdx].inst->isDataPrefetch() || 16211525Sandreas.sandberg@arm.com storeQueue[storeWBIdx].committed || 16311524Sdavid.guillen@arm.com storeQueue[storeWBIdx].req->flags & LOCKED) { 16411524Sdavid.guillen@arm.com incrStIdx(storeWBIdx); 16511524Sdavid.guillen@arm.com 16611524Sdavid.guillen@arm.com continue; 16711524Sdavid.guillen@arm.com } 16811524Sdavid.guillen@arm.com 16911524Sdavid.guillen@arm.com assert(storeQueue[storeWBIdx].req); 17011524Sdavid.guillen@arm.com assert(!storeQueue[storeWBIdx].committed); 17111524Sdavid.guillen@arm.com 17211524Sdavid.guillen@arm.com MemReqPtr req = storeQueue[storeWBIdx].req; 17311524Sdavid.guillen@arm.com storeQueue[storeWBIdx].committed = true; 17411524Sdavid.guillen@arm.com 17511524Sdavid.guillen@arm.com req->cmd = Write; 17611524Sdavid.guillen@arm.com req->completionEvent = NULL; 17711524Sdavid.guillen@arm.com req->time = curTick; 17811524Sdavid.guillen@arm.com assert(!req->data); 17911524Sdavid.guillen@arm.com 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