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