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