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