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