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