lsq_impl.hh revision 9444:ab47fe7f03f0
12SN/A/* 27760SGiacomo.Gabrielli@arm.com * Copyright (c) 2011-2012 ARM Limited 37760SGiacomo.Gabrielli@arm.com * All rights reserved 47760SGiacomo.Gabrielli@arm.com * 57760SGiacomo.Gabrielli@arm.com * The license below extends only to copyright in the software and shall 67760SGiacomo.Gabrielli@arm.com * not be construed as granting a license to any other intellectual 77760SGiacomo.Gabrielli@arm.com * property including but not limited to intellectual property relating 87760SGiacomo.Gabrielli@arm.com * to a hardware implementation of the functionality of the software 97760SGiacomo.Gabrielli@arm.com * licensed hereunder. You may use the software subject to the license 107760SGiacomo.Gabrielli@arm.com * terms below provided that you ensure that this notice is replicated 117760SGiacomo.Gabrielli@arm.com * unmodified and in its entirety in all distributions of the software, 127760SGiacomo.Gabrielli@arm.com * modified or unmodified, in source code or in binary form. 137760SGiacomo.Gabrielli@arm.com * 141762SN/A * Copyright (c) 2005-2006 The Regents of The University of Michigan 152SN/A * All rights reserved. 162SN/A * 172SN/A * Redistribution and use in source and binary forms, with or without 182SN/A * modification, are permitted provided that the following conditions are 192SN/A * met: redistributions of source code must retain the above copyright 202SN/A * notice, this list of conditions and the following disclaimer; 212SN/A * redistributions in binary form must reproduce the above copyright 222SN/A * notice, this list of conditions and the following disclaimer in the 232SN/A * documentation and/or other materials provided with the distribution; 242SN/A * neither the name of the copyright holders nor the names of its 252SN/A * contributors may be used to endorse or promote products derived from 262SN/A * this software without specific prior written permission. 272SN/A * 282SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665Ssaidi@eecs.umich.edu * 404762Snate@binkert.org * Authors: Korey Sewell 412SN/A */ 422SN/A 432410SN/A#include <algorithm> 442410SN/A#include <list> 452SN/A#include <string> 464762Snate@binkert.org 474762Snate@binkert.org#include "cpu/o3/lsq.hh" 484762Snate@binkert.org#include "debug/Drain.hh" 494762Snate@binkert.org#include "debug/Fetch.hh" 504762Snate@binkert.org#include "debug/LSQ.hh" 512SN/A#include "debug/Writeback.hh" 524762Snate@binkert.org#include "params/DerivO3CPU.hh" 534762Snate@binkert.org 544762Snate@binkert.orgusing namespace std; 552SN/A 564762Snate@binkert.orgtemplate <class Impl> 574762Snate@binkert.orgLSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) 584762Snate@binkert.org : cpu(cpu_ptr), iewStage(iew_ptr), 594762Snate@binkert.org LQEntries(params->LQEntries), 604762Snate@binkert.org SQEntries(params->SQEntries), 614762Snate@binkert.org numThreads(params->numThreads), 624762Snate@binkert.org retryTid(-1) 634762Snate@binkert.org{ 644762Snate@binkert.org //**********************************************/ 657760SGiacomo.Gabrielli@arm.com //************ Handle SMT Parameters ***********/ 667760SGiacomo.Gabrielli@arm.com //**********************************************/ 677760SGiacomo.Gabrielli@arm.com std::string policy = params->smtLSQPolicy; 687760SGiacomo.Gabrielli@arm.com 697760SGiacomo.Gabrielli@arm.com //Convert string to lowercase 707760SGiacomo.Gabrielli@arm.com std::transform(policy.begin(), policy.end(), policy.begin(), 717760SGiacomo.Gabrielli@arm.com (int(*)(int)) tolower); 727760SGiacomo.Gabrielli@arm.com 737760SGiacomo.Gabrielli@arm.com //Figure out fetch policy 747760SGiacomo.Gabrielli@arm.com if (policy == "dynamic") { 757760SGiacomo.Gabrielli@arm.com lsqPolicy = Dynamic; 767760SGiacomo.Gabrielli@arm.com 777760SGiacomo.Gabrielli@arm.com maxLQEntries = LQEntries; 787760SGiacomo.Gabrielli@arm.com maxSQEntries = SQEntries; 797760SGiacomo.Gabrielli@arm.com 807760SGiacomo.Gabrielli@arm.com DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); 817760SGiacomo.Gabrielli@arm.com } else if (policy == "partitioned") { 827760SGiacomo.Gabrielli@arm.com lsqPolicy = Partitioned; 837760SGiacomo.Gabrielli@arm.com 847760SGiacomo.Gabrielli@arm.com //@todo:make work if part_amt doesnt divide evenly. 854762Snate@binkert.org maxLQEntries = LQEntries / numThreads; 864762Snate@binkert.org maxSQEntries = SQEntries / numThreads; 874762Snate@binkert.org 884762Snate@binkert.org DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " 894762Snate@binkert.org "%i entries per LQ | %i entries per SQ\n", 902SN/A maxLQEntries,maxSQEntries); 912410SN/A } else if (policy == "threshold") { 92 lsqPolicy = Threshold; 93 94 assert(params->smtLSQThreshold > LQEntries); 95 assert(params->smtLSQThreshold > SQEntries); 96 97 //Divide up by threshold amount 98 //@todo: Should threads check the max and the total 99 //amount of the LSQ 100 maxLQEntries = params->smtLSQThreshold; 101 maxSQEntries = params->smtLSQThreshold; 102 103 DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " 104 "%i entries per LQ | %i entries per SQ\n", 105 maxLQEntries,maxSQEntries); 106 } else { 107 assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic," 108 "Partitioned, Threshold}"); 109 } 110 111 //Initialize LSQs 112 for (ThreadID tid = 0; tid < numThreads; tid++) { 113 thread[tid].init(cpu, iew_ptr, params, this, 114 maxLQEntries, maxSQEntries, tid); 115 thread[tid].setDcachePort(&cpu_ptr->getDataPort()); 116 } 117} 118 119 120template<class Impl> 121std::string 122LSQ<Impl>::name() const 123{ 124 return iewStage->name() + ".lsq"; 125} 126 127template<class Impl> 128void 129LSQ<Impl>::regStats() 130{ 131 //Initialize LSQs 132 for (ThreadID tid = 0; tid < numThreads; tid++) { 133 thread[tid].regStats(); 134 } 135} 136 137template<class Impl> 138void 139LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr) 140{ 141 activeThreads = at_ptr; 142 assert(activeThreads != 0); 143} 144 145template <class Impl> 146void 147LSQ<Impl>::drainSanityCheck() const 148{ 149 assert(isDrained()); 150 151 for (ThreadID tid = 0; tid < numThreads; tid++) 152 thread[tid].drainSanityCheck(); 153} 154 155template <class Impl> 156bool 157LSQ<Impl>::isDrained() const 158{ 159 bool drained(true); 160 161 if (!lqEmpty()) { 162 DPRINTF(Drain, "Not drained, LQ not empty.\n"); 163 drained = false; 164 } 165 166 if (!sqEmpty()) { 167 DPRINTF(Drain, "Not drained, SQ not empty.\n"); 168 drained = false; 169 } 170 171 if (retryTid != InvalidThreadID) { 172 DPRINTF(Drain, "Not drained, the LSQ has blocked the caches.\n"); 173 drained = false; 174 } 175 176 return drained; 177} 178 179template <class Impl> 180void 181LSQ<Impl>::takeOverFrom() 182{ 183 for (ThreadID tid = 0; tid < numThreads; tid++) { 184 thread[tid].takeOverFrom(); 185 } 186} 187 188template <class Impl> 189int 190LSQ<Impl>::entryAmount(ThreadID num_threads) 191{ 192 if (lsqPolicy == Partitioned) { 193 return LQEntries / num_threads; 194 } else { 195 return 0; 196 } 197} 198 199template <class Impl> 200void 201LSQ<Impl>::resetEntries() 202{ 203 if (lsqPolicy != Dynamic || numThreads > 1) { 204 int active_threads = activeThreads->size(); 205 206 int maxEntries; 207 208 if (lsqPolicy == Partitioned) { 209 maxEntries = LQEntries / active_threads; 210 } else if (lsqPolicy == Threshold && active_threads == 1) { 211 maxEntries = LQEntries; 212 } else { 213 maxEntries = LQEntries; 214 } 215 216 list<ThreadID>::iterator threads = activeThreads->begin(); 217 list<ThreadID>::iterator end = activeThreads->end(); 218 219 while (threads != end) { 220 ThreadID tid = *threads++; 221 222 resizeEntries(maxEntries, tid); 223 } 224 } 225} 226 227template<class Impl> 228void 229LSQ<Impl>::removeEntries(ThreadID tid) 230{ 231 thread[tid].clearLQ(); 232 thread[tid].clearSQ(); 233} 234 235template<class Impl> 236void 237LSQ<Impl>::resizeEntries(unsigned size, ThreadID tid) 238{ 239 thread[tid].resizeLQ(size); 240 thread[tid].resizeSQ(size); 241} 242 243template<class Impl> 244void 245LSQ<Impl>::tick() 246{ 247 list<ThreadID>::iterator threads = activeThreads->begin(); 248 list<ThreadID>::iterator end = activeThreads->end(); 249 250 while (threads != end) { 251 ThreadID tid = *threads++; 252 253 thread[tid].tick(); 254 } 255} 256 257template<class Impl> 258void 259LSQ<Impl>::insertLoad(DynInstPtr &load_inst) 260{ 261 ThreadID tid = load_inst->threadNumber; 262 263 thread[tid].insertLoad(load_inst); 264} 265 266template<class Impl> 267void 268LSQ<Impl>::insertStore(DynInstPtr &store_inst) 269{ 270 ThreadID tid = store_inst->threadNumber; 271 272 thread[tid].insertStore(store_inst); 273} 274 275template<class Impl> 276Fault 277LSQ<Impl>::executeLoad(DynInstPtr &inst) 278{ 279 ThreadID tid = inst->threadNumber; 280 281 return thread[tid].executeLoad(inst); 282} 283 284template<class Impl> 285Fault 286LSQ<Impl>::executeStore(DynInstPtr &inst) 287{ 288 ThreadID tid = inst->threadNumber; 289 290 return thread[tid].executeStore(inst); 291} 292 293template<class Impl> 294void 295LSQ<Impl>::writebackStores() 296{ 297 list<ThreadID>::iterator threads = activeThreads->begin(); 298 list<ThreadID>::iterator end = activeThreads->end(); 299 300 while (threads != end) { 301 ThreadID tid = *threads++; 302 303 if (numStoresToWB(tid) > 0) { 304 DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores " 305 "available for Writeback.\n", tid, numStoresToWB(tid)); 306 } 307 308 thread[tid].writebackStores(); 309 } 310} 311 312template<class Impl> 313bool 314LSQ<Impl>::violation() 315{ 316 /* Answers: Does Anybody Have a Violation?*/ 317 list<ThreadID>::iterator threads = activeThreads->begin(); 318 list<ThreadID>::iterator end = activeThreads->end(); 319 320 while (threads != end) { 321 ThreadID tid = *threads++; 322 323 if (thread[tid].violation()) 324 return true; 325 } 326 327 return false; 328} 329 330template <class Impl> 331void 332LSQ<Impl>::recvRetry() 333{ 334 if (retryTid == InvalidThreadID) 335 { 336 //Squashed, so drop it 337 return; 338 } 339 int curr_retry_tid = retryTid; 340 // Speculatively clear the retry Tid. This will get set again if 341 // the LSQUnit was unable to complete its access. 342 retryTid = -1; 343 thread[curr_retry_tid].recvRetry(); 344} 345 346template <class Impl> 347bool 348LSQ<Impl>::recvTimingResp(PacketPtr pkt) 349{ 350 if (pkt->isError()) 351 DPRINTF(LSQ, "Got error packet back for address: %#X\n", 352 pkt->getAddr()); 353 thread[pkt->req->threadId()].completeDataAccess(pkt); 354 return true; 355} 356 357template <class Impl> 358void 359LSQ<Impl>::recvTimingSnoopReq(PacketPtr pkt) 360{ 361 DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(), 362 pkt->cmdString()); 363 364 // must be a snoop 365 if (pkt->isInvalidate()) { 366 DPRINTF(LSQ, "received invalidation for addr:%#x\n", 367 pkt->getAddr()); 368 for (ThreadID tid = 0; tid < numThreads; tid++) { 369 thread[tid].checkSnoop(pkt); 370 } 371 } 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> 429unsigned 430LSQ<Impl>::numFreeEntries() 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].numFreeEntries(); 441 } 442 443 return total; 444} 445 446template<class Impl> 447unsigned 448LSQ<Impl>::numFreeEntries(ThreadID tid) 449{ 450 //if (lsqPolicy == Dynamic) 451 //return numFreeEntries(); 452 //else 453 return thread[tid].numFreeEntries(); 454} 455 456template<class Impl> 457bool 458LSQ<Impl>::isFull() 459{ 460 list<ThreadID>::iterator threads = activeThreads->begin(); 461 list<ThreadID>::iterator end = activeThreads->end(); 462 463 while (threads != end) { 464 ThreadID tid = *threads++; 465 466 if (!(thread[tid].lqFull() || thread[tid].sqFull())) 467 return false; 468 } 469 470 return true; 471} 472 473template<class Impl> 474bool 475LSQ<Impl>::isFull(ThreadID tid) 476{ 477 //@todo: Change to Calculate All Entries for 478 //Dynamic Policy 479 if (lsqPolicy == Dynamic) 480 return isFull(); 481 else 482 return thread[tid].lqFull() || thread[tid].sqFull(); 483} 484 485template<class Impl> 486bool 487LSQ<Impl>::isEmpty() const 488{ 489 return lqEmpty() && sqEmpty(); 490} 491 492template<class Impl> 493bool 494LSQ<Impl>::lqEmpty() const 495{ 496 list<ThreadID>::const_iterator threads = activeThreads->begin(); 497 list<ThreadID>::const_iterator end = activeThreads->end(); 498 499 while (threads != end) { 500 ThreadID tid = *threads++; 501 502 if (!thread[tid].lqEmpty()) 503 return false; 504 } 505 506 return true; 507} 508 509template<class Impl> 510bool 511LSQ<Impl>::sqEmpty() const 512{ 513 list<ThreadID>::const_iterator threads = activeThreads->begin(); 514 list<ThreadID>::const_iterator end = activeThreads->end(); 515 516 while (threads != end) { 517 ThreadID tid = *threads++; 518 519 if (!thread[tid].sqEmpty()) 520 return false; 521 } 522 523 return true; 524} 525 526template<class Impl> 527bool 528LSQ<Impl>::lqFull() 529{ 530 list<ThreadID>::iterator threads = activeThreads->begin(); 531 list<ThreadID>::iterator end = activeThreads->end(); 532 533 while (threads != end) { 534 ThreadID tid = *threads++; 535 536 if (!thread[tid].lqFull()) 537 return false; 538 } 539 540 return true; 541} 542 543template<class Impl> 544bool 545LSQ<Impl>::lqFull(ThreadID tid) 546{ 547 //@todo: Change to Calculate All Entries for 548 //Dynamic Policy 549 if (lsqPolicy == Dynamic) 550 return lqFull(); 551 else 552 return thread[tid].lqFull(); 553} 554 555template<class Impl> 556bool 557LSQ<Impl>::sqFull() 558{ 559 list<ThreadID>::iterator threads = activeThreads->begin(); 560 list<ThreadID>::iterator end = activeThreads->end(); 561 562 while (threads != end) { 563 ThreadID tid = *threads++; 564 565 if (!sqFull(tid)) 566 return false; 567 } 568 569 return true; 570} 571 572template<class Impl> 573bool 574LSQ<Impl>::sqFull(ThreadID tid) 575{ 576 //@todo: Change to Calculate All Entries for 577 //Dynamic Policy 578 if (lsqPolicy == Dynamic) 579 return sqFull(); 580 else 581 return thread[tid].sqFull(); 582} 583 584template<class Impl> 585bool 586LSQ<Impl>::isStalled() 587{ 588 list<ThreadID>::iterator threads = activeThreads->begin(); 589 list<ThreadID>::iterator end = activeThreads->end(); 590 591 while (threads != end) { 592 ThreadID tid = *threads++; 593 594 if (!thread[tid].isStalled()) 595 return false; 596 } 597 598 return true; 599} 600 601template<class Impl> 602bool 603LSQ<Impl>::isStalled(ThreadID tid) 604{ 605 if (lsqPolicy == Dynamic) 606 return isStalled(); 607 else 608 return thread[tid].isStalled(); 609} 610 611template<class Impl> 612bool 613LSQ<Impl>::hasStoresToWB() 614{ 615 list<ThreadID>::iterator threads = activeThreads->begin(); 616 list<ThreadID>::iterator end = activeThreads->end(); 617 618 while (threads != end) { 619 ThreadID tid = *threads++; 620 621 if (hasStoresToWB(tid)) 622 return true; 623 } 624 625 return false; 626} 627 628template<class Impl> 629bool 630LSQ<Impl>::willWB() 631{ 632 list<ThreadID>::iterator threads = activeThreads->begin(); 633 list<ThreadID>::iterator end = activeThreads->end(); 634 635 while (threads != end) { 636 ThreadID tid = *threads++; 637 638 if (willWB(tid)) 639 return true; 640 } 641 642 return false; 643} 644 645template<class Impl> 646void 647LSQ<Impl>::dumpInsts() const 648{ 649 list<ThreadID>::const_iterator threads = activeThreads->begin(); 650 list<ThreadID>::const_iterator end = activeThreads->end(); 651 652 while (threads != end) { 653 ThreadID tid = *threads++; 654 655 thread[tid].dumpInsts(); 656 } 657} 658