lsq_impl.hh revision 8346:ce8b9a250021
1/* 2 * Copyright (c) 2005-2006 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 * Authors: Korey Sewell 29 */ 30 31#include <algorithm> 32#include <list> 33#include <string> 34 35#include "cpu/o3/lsq.hh" 36#include "debug/Fetch.hh" 37#include "debug/LSQ.hh" 38#include "debug/Writeback.hh" 39#include "params/DerivO3CPU.hh" 40 41using namespace std; 42 43template<class Impl> 44void 45LSQ<Impl>::DcachePort::setPeer(Port *port) 46{ 47 Port::setPeer(port); 48 49#if FULL_SYSTEM 50 // Update the ThreadContext's memory ports (Functional/Virtual 51 // Ports) 52 lsq->updateMemPorts(); 53#endif 54} 55 56template <class Impl> 57Tick 58LSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt) 59{ 60 panic("O3CPU model does not work with atomic mode!"); 61 return curTick(); 62} 63 64template <class Impl> 65void 66LSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt) 67{ 68 DPRINTF(LSQ, "LSQ doesn't update things on a recvFunctional.\n"); 69} 70 71template <class Impl> 72void 73LSQ<Impl>::DcachePort::recvStatusChange(Status status) 74{ 75 if (status == RangeChange) { 76 if (!snoopRangeSent) { 77 snoopRangeSent = true; 78 sendStatusChange(Port::RangeChange); 79 } 80 return; 81 } 82 panic("O3CPU doesn't expect recvStatusChange callback!"); 83} 84 85template <class Impl> 86bool 87LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt) 88{ 89 if (pkt->isError()) 90 DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr()); 91 if (pkt->isResponse()) { 92 lsq->thread[pkt->req->threadId()].completeDataAccess(pkt); 93 } 94 else { 95 // must be a snoop 96 97 // @TODO someday may need to process invalidations in LSQ here 98 // to provide stronger consistency model 99 } 100 return true; 101} 102 103template <class Impl> 104void 105LSQ<Impl>::DcachePort::recvRetry() 106{ 107 if (lsq->retryTid == -1) 108 { 109 //Squashed, so drop it 110 return; 111 } 112 int curr_retry_tid = lsq->retryTid; 113 // Speculatively clear the retry Tid. This will get set again if 114 // the LSQUnit was unable to complete its access. 115 lsq->retryTid = -1; 116 lsq->thread[curr_retry_tid].recvRetry(); 117} 118 119template <class Impl> 120LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) 121 : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), 122 LQEntries(params->LQEntries), 123 SQEntries(params->SQEntries), 124 numThreads(params->numThreads), 125 retryTid(-1) 126{ 127 dcachePort.snoopRangeSent = false; 128 129 //**********************************************/ 130 //************ Handle SMT Parameters ***********/ 131 //**********************************************/ 132 std::string policy = params->smtLSQPolicy; 133 134 //Convert string to lowercase 135 std::transform(policy.begin(), policy.end(), policy.begin(), 136 (int(*)(int)) tolower); 137 138 //Figure out fetch policy 139 if (policy == "dynamic") { 140 lsqPolicy = Dynamic; 141 142 maxLQEntries = LQEntries; 143 maxSQEntries = SQEntries; 144 145 DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); 146 } else if (policy == "partitioned") { 147 lsqPolicy = Partitioned; 148 149 //@todo:make work if part_amt doesnt divide evenly. 150 maxLQEntries = LQEntries / numThreads; 151 maxSQEntries = SQEntries / numThreads; 152 153 DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " 154 "%i entries per LQ | %i entries per SQ\n", 155 maxLQEntries,maxSQEntries); 156 } else if (policy == "threshold") { 157 lsqPolicy = Threshold; 158 159 assert(params->smtLSQThreshold > LQEntries); 160 assert(params->smtLSQThreshold > SQEntries); 161 162 //Divide up by threshold amount 163 //@todo: Should threads check the max and the total 164 //amount of the LSQ 165 maxLQEntries = params->smtLSQThreshold; 166 maxSQEntries = params->smtLSQThreshold; 167 168 DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " 169 "%i entries per LQ | %i entries per SQ\n", 170 maxLQEntries,maxSQEntries); 171 } else { 172 assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic," 173 "Partitioned, Threshold}"); 174 } 175 176 //Initialize LSQs 177 for (ThreadID tid = 0; tid < numThreads; tid++) { 178 thread[tid].init(cpu, iew_ptr, params, this, 179 maxLQEntries, maxSQEntries, tid); 180 thread[tid].setDcachePort(&dcachePort); 181 } 182} 183 184 185template<class Impl> 186std::string 187LSQ<Impl>::name() const 188{ 189 return iewStage->name() + ".lsq"; 190} 191 192template<class Impl> 193void 194LSQ<Impl>::regStats() 195{ 196 //Initialize LSQs 197 for (ThreadID tid = 0; tid < numThreads; tid++) { 198 thread[tid].regStats(); 199 } 200} 201 202template<class Impl> 203void 204LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr) 205{ 206 activeThreads = at_ptr; 207 assert(activeThreads != 0); 208} 209 210template <class Impl> 211void 212LSQ<Impl>::switchOut() 213{ 214 for (ThreadID tid = 0; tid < numThreads; tid++) { 215 thread[tid].switchOut(); 216 } 217} 218 219template <class Impl> 220void 221LSQ<Impl>::takeOverFrom() 222{ 223 for (ThreadID tid = 0; tid < numThreads; tid++) { 224 thread[tid].takeOverFrom(); 225 } 226} 227 228template <class Impl> 229int 230LSQ<Impl>::entryAmount(ThreadID num_threads) 231{ 232 if (lsqPolicy == Partitioned) { 233 return LQEntries / num_threads; 234 } else { 235 return 0; 236 } 237} 238 239template <class Impl> 240void 241LSQ<Impl>::resetEntries() 242{ 243 if (lsqPolicy != Dynamic || numThreads > 1) { 244 int active_threads = activeThreads->size(); 245 246 int maxEntries; 247 248 if (lsqPolicy == Partitioned) { 249 maxEntries = LQEntries / active_threads; 250 } else if (lsqPolicy == Threshold && active_threads == 1) { 251 maxEntries = LQEntries; 252 } else { 253 maxEntries = LQEntries; 254 } 255 256 list<ThreadID>::iterator threads = activeThreads->begin(); 257 list<ThreadID>::iterator end = activeThreads->end(); 258 259 while (threads != end) { 260 ThreadID tid = *threads++; 261 262 resizeEntries(maxEntries, tid); 263 } 264 } 265} 266 267template<class Impl> 268void 269LSQ<Impl>::removeEntries(ThreadID tid) 270{ 271 thread[tid].clearLQ(); 272 thread[tid].clearSQ(); 273} 274 275template<class Impl> 276void 277LSQ<Impl>::resizeEntries(unsigned size, ThreadID tid) 278{ 279 thread[tid].resizeLQ(size); 280 thread[tid].resizeSQ(size); 281} 282 283template<class Impl> 284void 285LSQ<Impl>::tick() 286{ 287 list<ThreadID>::iterator threads = activeThreads->begin(); 288 list<ThreadID>::iterator end = activeThreads->end(); 289 290 while (threads != end) { 291 ThreadID tid = *threads++; 292 293 thread[tid].tick(); 294 } 295} 296 297template<class Impl> 298void 299LSQ<Impl>::insertLoad(DynInstPtr &load_inst) 300{ 301 ThreadID tid = load_inst->threadNumber; 302 303 thread[tid].insertLoad(load_inst); 304} 305 306template<class Impl> 307void 308LSQ<Impl>::insertStore(DynInstPtr &store_inst) 309{ 310 ThreadID tid = store_inst->threadNumber; 311 312 thread[tid].insertStore(store_inst); 313} 314 315template<class Impl> 316Fault 317LSQ<Impl>::executeLoad(DynInstPtr &inst) 318{ 319 ThreadID tid = inst->threadNumber; 320 321 return thread[tid].executeLoad(inst); 322} 323 324template<class Impl> 325Fault 326LSQ<Impl>::executeStore(DynInstPtr &inst) 327{ 328 ThreadID tid = inst->threadNumber; 329 330 return thread[tid].executeStore(inst); 331} 332 333template<class Impl> 334void 335LSQ<Impl>::writebackStores() 336{ 337 list<ThreadID>::iterator threads = activeThreads->begin(); 338 list<ThreadID>::iterator end = activeThreads->end(); 339 340 while (threads != end) { 341 ThreadID tid = *threads++; 342 343 if (numStoresToWB(tid) > 0) { 344 DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores " 345 "available for Writeback.\n", tid, numStoresToWB(tid)); 346 } 347 348 thread[tid].writebackStores(); 349 } 350} 351 352template<class Impl> 353bool 354LSQ<Impl>::violation() 355{ 356 /* Answers: Does Anybody Have a Violation?*/ 357 list<ThreadID>::iterator threads = activeThreads->begin(); 358 list<ThreadID>::iterator end = activeThreads->end(); 359 360 while (threads != end) { 361 ThreadID tid = *threads++; 362 363 if (thread[tid].violation()) 364 return true; 365 } 366 367 return false; 368} 369 370template<class Impl> 371int 372LSQ<Impl>::getCount() 373{ 374 unsigned total = 0; 375 376 list<ThreadID>::iterator threads = activeThreads->begin(); 377 list<ThreadID>::iterator end = activeThreads->end(); 378 379 while (threads != end) { 380 ThreadID tid = *threads++; 381 382 total += getCount(tid); 383 } 384 385 return total; 386} 387 388template<class Impl> 389int 390LSQ<Impl>::numLoads() 391{ 392 unsigned total = 0; 393 394 list<ThreadID>::iterator threads = activeThreads->begin(); 395 list<ThreadID>::iterator end = activeThreads->end(); 396 397 while (threads != end) { 398 ThreadID tid = *threads++; 399 400 total += numLoads(tid); 401 } 402 403 return total; 404} 405 406template<class Impl> 407int 408LSQ<Impl>::numStores() 409{ 410 unsigned total = 0; 411 412 list<ThreadID>::iterator threads = activeThreads->begin(); 413 list<ThreadID>::iterator end = activeThreads->end(); 414 415 while (threads != end) { 416 ThreadID tid = *threads++; 417 418 total += thread[tid].numStores(); 419 } 420 421 return total; 422} 423 424template<class Impl> 425int 426LSQ<Impl>::numLoadsReady() 427{ 428 unsigned total = 0; 429 430 list<ThreadID>::iterator threads = activeThreads->begin(); 431 list<ThreadID>::iterator end = activeThreads->end(); 432 433 while (threads != end) { 434 ThreadID tid = *threads++; 435 436 total += thread[tid].numLoadsReady(); 437 } 438 439 return total; 440} 441 442template<class Impl> 443unsigned 444LSQ<Impl>::numFreeEntries() 445{ 446 unsigned total = 0; 447 448 list<ThreadID>::iterator threads = activeThreads->begin(); 449 list<ThreadID>::iterator end = activeThreads->end(); 450 451 while (threads != end) { 452 ThreadID tid = *threads++; 453 454 total += thread[tid].numFreeEntries(); 455 } 456 457 return total; 458} 459 460template<class Impl> 461unsigned 462LSQ<Impl>::numFreeEntries(ThreadID tid) 463{ 464 //if (lsqPolicy == Dynamic) 465 //return numFreeEntries(); 466 //else 467 return thread[tid].numFreeEntries(); 468} 469 470template<class Impl> 471bool 472LSQ<Impl>::isFull() 473{ 474 list<ThreadID>::iterator threads = activeThreads->begin(); 475 list<ThreadID>::iterator end = activeThreads->end(); 476 477 while (threads != end) { 478 ThreadID tid = *threads++; 479 480 if (!(thread[tid].lqFull() || thread[tid].sqFull())) 481 return false; 482 } 483 484 return true; 485} 486 487template<class Impl> 488bool 489LSQ<Impl>::isFull(ThreadID tid) 490{ 491 //@todo: Change to Calculate All Entries for 492 //Dynamic Policy 493 if (lsqPolicy == Dynamic) 494 return isFull(); 495 else 496 return thread[tid].lqFull() || thread[tid].sqFull(); 497} 498 499template<class Impl> 500bool 501LSQ<Impl>::lqFull() 502{ 503 list<ThreadID>::iterator threads = activeThreads->begin(); 504 list<ThreadID>::iterator end = activeThreads->end(); 505 506 while (threads != end) { 507 ThreadID tid = *threads++; 508 509 if (!thread[tid].lqFull()) 510 return false; 511 } 512 513 return true; 514} 515 516template<class Impl> 517bool 518LSQ<Impl>::lqFull(ThreadID tid) 519{ 520 //@todo: Change to Calculate All Entries for 521 //Dynamic Policy 522 if (lsqPolicy == Dynamic) 523 return lqFull(); 524 else 525 return thread[tid].lqFull(); 526} 527 528template<class Impl> 529bool 530LSQ<Impl>::sqFull() 531{ 532 list<ThreadID>::iterator threads = activeThreads->begin(); 533 list<ThreadID>::iterator end = activeThreads->end(); 534 535 while (threads != end) { 536 ThreadID tid = *threads++; 537 538 if (!sqFull(tid)) 539 return false; 540 } 541 542 return true; 543} 544 545template<class Impl> 546bool 547LSQ<Impl>::sqFull(ThreadID tid) 548{ 549 //@todo: Change to Calculate All Entries for 550 //Dynamic Policy 551 if (lsqPolicy == Dynamic) 552 return sqFull(); 553 else 554 return thread[tid].sqFull(); 555} 556 557template<class Impl> 558bool 559LSQ<Impl>::isStalled() 560{ 561 list<ThreadID>::iterator threads = activeThreads->begin(); 562 list<ThreadID>::iterator end = activeThreads->end(); 563 564 while (threads != end) { 565 ThreadID tid = *threads++; 566 567 if (!thread[tid].isStalled()) 568 return false; 569 } 570 571 return true; 572} 573 574template<class Impl> 575bool 576LSQ<Impl>::isStalled(ThreadID tid) 577{ 578 if (lsqPolicy == Dynamic) 579 return isStalled(); 580 else 581 return thread[tid].isStalled(); 582} 583 584template<class Impl> 585bool 586LSQ<Impl>::hasStoresToWB() 587{ 588 list<ThreadID>::iterator threads = activeThreads->begin(); 589 list<ThreadID>::iterator end = activeThreads->end(); 590 591 while (threads != end) { 592 ThreadID tid = *threads++; 593 594 if (hasStoresToWB(tid)) 595 return true; 596 } 597 598 return false; 599} 600 601template<class Impl> 602bool 603LSQ<Impl>::willWB() 604{ 605 list<ThreadID>::iterator threads = activeThreads->begin(); 606 list<ThreadID>::iterator end = activeThreads->end(); 607 608 while (threads != end) { 609 ThreadID tid = *threads++; 610 611 if (willWB(tid)) 612 return true; 613 } 614 615 return false; 616} 617 618template<class Impl> 619void 620LSQ<Impl>::dumpInsts() 621{ 622 list<ThreadID>::iterator threads = activeThreads->begin(); 623 list<ThreadID>::iterator end = activeThreads->end(); 624 625 while (threads != end) { 626 ThreadID tid = *threads++; 627 628 thread[tid].dumpInsts(); 629 } 630} 631