lsq_impl.hh revision 10573:3b405d11d6dc
14486Sbinkertn@umich.edu/* 27897Shestness@cs.utexas.edu * Copyright (c) 2011-2012, 2014 ARM Limited 34486Sbinkertn@umich.edu * Copyright (c) 2013 Advanced Micro Devices, Inc. 44486Sbinkertn@umich.edu * All rights reserved 54486Sbinkertn@umich.edu * 64486Sbinkertn@umich.edu * The license below extends only to copyright in the software and shall 74486Sbinkertn@umich.edu * not be construed as granting a license to any other intellectual 84486Sbinkertn@umich.edu * property including but not limited to intellectual property relating 94486Sbinkertn@umich.edu * to a hardware implementation of the functionality of the software 104486Sbinkertn@umich.edu * licensed hereunder. You may use the software subject to the license 114486Sbinkertn@umich.edu * terms below provided that you ensure that this notice is replicated 124486Sbinkertn@umich.edu * unmodified and in its entirety in all distributions of the software, 134486Sbinkertn@umich.edu * modified or unmodified, in source code or in binary form. 144486Sbinkertn@umich.edu * 154486Sbinkertn@umich.edu * Copyright (c) 2005-2006 The Regents of The University of Michigan 164486Sbinkertn@umich.edu * All rights reserved. 174486Sbinkertn@umich.edu * 184486Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without 194486Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are 204486Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright 214486Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer; 224486Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright 234486Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the 244486Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution; 254486Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its 264486Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from 274486Sbinkertn@umich.edu * this software without specific prior written permission. 284486Sbinkertn@umich.edu * 297897Shestness@cs.utexas.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 304486Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3111988Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3211839SCurtis.Dunham@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 333102SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 343102SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 356654Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3610249Sstephan.diestelhorst@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 378931Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382212SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 399524SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 409524SAndreas.Sandberg@ARM.com * 412902SN/A * Authors: Korey Sewell 428703Sandreas.hansson@arm.com */ 431783SN/A 449338SAndreas.Sandberg@arm.com#ifndef __CPU_O3_LSQ_IMPL_HH__ 458839Sandreas.hansson@arm.com#define __CPU_O3_LSQ_IMPL_HH__ 467673Snate@binkert.org 4711988Sandreas.sandberg@arm.com#include <algorithm> 4811988Sandreas.sandberg@arm.com#include <list> 4911988Sandreas.sandberg@arm.com#include <string> 5011988Sandreas.sandberg@arm.com 514859Snate@binkert.org#include "cpu/o3/lsq.hh" 528931Sandreas.hansson@arm.com#include "debug/Drain.hh" 538931Sandreas.hansson@arm.com#include "debug/Fetch.hh" 542902SN/A#include "debug/LSQ.hh" 559408Sandreas.hansson@arm.com#include "debug/Writeback.hh" 5611420Sdavid.guillen@arm.com#include "params/DerivO3CPU.hh" 5711420Sdavid.guillen@arm.com 5811420Sdavid.guillen@arm.comusing namespace std; 5911420Sdavid.guillen@arm.com 6010700Sandreas.hansson@arm.comtemplate <class Impl> 6110700Sandreas.hansson@arm.comLSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) 6211838SCurtis.Dunham@arm.com : cpu(cpu_ptr), iewStage(iew_ptr), 6310700Sandreas.hansson@arm.com LQEntries(params->LQEntries), 6410700Sandreas.hansson@arm.com SQEntries(params->SQEntries), 6510700Sandreas.hansson@arm.com numThreads(params->numThreads) 6610700Sandreas.hansson@arm.com{ 679408Sandreas.hansson@arm.com assert(numThreads > 0 && numThreads <= Impl::MaxThreads); 689408Sandreas.hansson@arm.com 699408Sandreas.hansson@arm.com //**********************************************/ 709408Sandreas.hansson@arm.com //************ Handle SMT Parameters ***********/ 719408Sandreas.hansson@arm.com //**********************************************/ 729814Sandreas.hansson@arm.com std::string policy = params->smtLSQPolicy; 739814Sandreas.hansson@arm.com 7411273Sandreas.sandberg@arm.com //Convert string to lowercase 7511270Sandreas.sandberg@arm.com std::transform(policy.begin(), policy.end(), policy.begin(), 767914SBrad.Beckmann@amd.com (int(*)(int)) tolower); 778666SPrakash.Ramrakhyani@arm.com 787914SBrad.Beckmann@amd.com //Figure out fetch policy 797914SBrad.Beckmann@amd.com if (policy == "dynamic") { 807914SBrad.Beckmann@amd.com lsqPolicy = Dynamic; 817914SBrad.Beckmann@amd.com 827914SBrad.Beckmann@amd.com maxLQEntries = LQEntries; 837914SBrad.Beckmann@amd.com maxSQEntries = SQEntries; 847914SBrad.Beckmann@amd.com 857914SBrad.Beckmann@amd.com DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); 867914SBrad.Beckmann@amd.com } else if (policy == "partitioned") { 877914SBrad.Beckmann@amd.com lsqPolicy = Partitioned; 887914SBrad.Beckmann@amd.com 897914SBrad.Beckmann@amd.com //@todo:make work if part_amt doesnt divide evenly. 907914SBrad.Beckmann@amd.com maxLQEntries = LQEntries / numThreads; 918769Sgblack@eecs.umich.edu maxSQEntries = SQEntries / numThreads; 928769Sgblack@eecs.umich.edu 938769Sgblack@eecs.umich.edu DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " 9410282Sdam.sunwoo@arm.com "%i entries per LQ | %i entries per SQ\n", 9510282Sdam.sunwoo@arm.com maxLQEntries,maxSQEntries); 9612262Sandreas.sandberg@arm.com } else if (policy == "threshold") { 978769Sgblack@eecs.umich.edu lsqPolicy = Threshold; 988769Sgblack@eecs.umich.edu 998769Sgblack@eecs.umich.edu assert(params->smtLSQThreshold > LQEntries); 10010037SARM gem5 Developers assert(params->smtLSQThreshold > SQEntries); 10110037SARM gem5 Developers 10210249Sstephan.diestelhorst@arm.com //Divide up by threshold amount 10311146Smitch.hayenga@arm.com //@todo: Should threads check the max and the total 10411146Smitch.hayenga@arm.com //amount of the LSQ 10511146Smitch.hayenga@arm.com maxLQEntries = params->smtLSQThreshold; 10610249Sstephan.diestelhorst@arm.com maxSQEntries = params->smtLSQThreshold; 10710249Sstephan.diestelhorst@arm.com 10810249Sstephan.diestelhorst@arm.com DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " 10911839SCurtis.Dunham@arm.com "%i entries per LQ | %i entries per SQ\n", 11011839SCurtis.Dunham@arm.com maxLQEntries,maxSQEntries); 11111839SCurtis.Dunham@arm.com } else { 112 assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic," 113 "Partitioned, Threshold}"); 114 } 115 116 //Initialize LSQs 117 thread = new LSQUnit[numThreads]; 118 for (ThreadID tid = 0; tid < numThreads; tid++) { 119 thread[tid].init(cpu, iew_ptr, params, this, 120 maxLQEntries, maxSQEntries, tid); 121 thread[tid].setDcachePort(&cpu_ptr->getDataPort()); 122 } 123} 124 125 126template<class Impl> 127std::string 128LSQ<Impl>::name() const 129{ 130 return iewStage->name() + ".lsq"; 131} 132 133template<class Impl> 134void 135LSQ<Impl>::regStats() 136{ 137 //Initialize LSQs 138 for (ThreadID tid = 0; tid < numThreads; tid++) { 139 thread[tid].regStats(); 140 } 141} 142 143template<class Impl> 144void 145LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr) 146{ 147 activeThreads = at_ptr; 148 assert(activeThreads != 0); 149} 150 151template <class Impl> 152void 153LSQ<Impl>::drainSanityCheck() const 154{ 155 assert(isDrained()); 156 157 for (ThreadID tid = 0; tid < numThreads; tid++) 158 thread[tid].drainSanityCheck(); 159} 160 161template <class Impl> 162bool 163LSQ<Impl>::isDrained() const 164{ 165 bool drained(true); 166 167 if (!lqEmpty()) { 168 DPRINTF(Drain, "Not drained, LQ not empty.\n"); 169 drained = false; 170 } 171 172 if (!sqEmpty()) { 173 DPRINTF(Drain, "Not drained, SQ not empty.\n"); 174 drained = false; 175 } 176 177 return drained; 178} 179 180template <class Impl> 181void 182LSQ<Impl>::takeOverFrom() 183{ 184 for (ThreadID tid = 0; tid < numThreads; tid++) { 185 thread[tid].takeOverFrom(); 186 } 187} 188 189template <class Impl> 190int 191LSQ<Impl>::entryAmount(ThreadID num_threads) 192{ 193 if (lsqPolicy == Partitioned) { 194 return LQEntries / num_threads; 195 } else { 196 return 0; 197 } 198} 199 200template <class Impl> 201void 202LSQ<Impl>::resetEntries() 203{ 204 if (lsqPolicy != Dynamic || numThreads > 1) { 205 int active_threads = activeThreads->size(); 206 207 int maxEntries; 208 209 if (lsqPolicy == Partitioned) { 210 maxEntries = LQEntries / active_threads; 211 } else if (lsqPolicy == Threshold && active_threads == 1) { 212 maxEntries = LQEntries; 213 } else { 214 maxEntries = LQEntries; 215 } 216 217 list<ThreadID>::iterator threads = activeThreads->begin(); 218 list<ThreadID>::iterator end = activeThreads->end(); 219 220 while (threads != end) { 221 ThreadID tid = *threads++; 222 223 resizeEntries(maxEntries, tid); 224 } 225 } 226} 227 228template<class Impl> 229void 230LSQ<Impl>::removeEntries(ThreadID tid) 231{ 232 thread[tid].clearLQ(); 233 thread[tid].clearSQ(); 234} 235 236template<class Impl> 237void 238LSQ<Impl>::resizeEntries(unsigned size, ThreadID tid) 239{ 240 thread[tid].resizeLQ(size); 241 thread[tid].resizeSQ(size); 242} 243 244template<class Impl> 245void 246LSQ<Impl>::tick() 247{ 248 list<ThreadID>::iterator threads = activeThreads->begin(); 249 list<ThreadID>::iterator end = activeThreads->end(); 250 251 while (threads != end) { 252 ThreadID tid = *threads++; 253 254 thread[tid].tick(); 255 } 256} 257 258template<class Impl> 259void 260LSQ<Impl>::insertLoad(DynInstPtr &load_inst) 261{ 262 ThreadID tid = load_inst->threadNumber; 263 264 thread[tid].insertLoad(load_inst); 265} 266 267template<class Impl> 268void 269LSQ<Impl>::insertStore(DynInstPtr &store_inst) 270{ 271 ThreadID tid = store_inst->threadNumber; 272 273 thread[tid].insertStore(store_inst); 274} 275 276template<class Impl> 277Fault 278LSQ<Impl>::executeLoad(DynInstPtr &inst) 279{ 280 ThreadID tid = inst->threadNumber; 281 282 return thread[tid].executeLoad(inst); 283} 284 285template<class Impl> 286Fault 287LSQ<Impl>::executeStore(DynInstPtr &inst) 288{ 289 ThreadID tid = inst->threadNumber; 290 291 return thread[tid].executeStore(inst); 292} 293 294template<class Impl> 295void 296LSQ<Impl>::writebackStores() 297{ 298 list<ThreadID>::iterator threads = activeThreads->begin(); 299 list<ThreadID>::iterator end = activeThreads->end(); 300 301 while (threads != end) { 302 ThreadID tid = *threads++; 303 304 if (numStoresToWB(tid) > 0) { 305 DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores " 306 "available for Writeback.\n", tid, numStoresToWB(tid)); 307 } 308 309 thread[tid].writebackStores(); 310 } 311} 312 313template<class Impl> 314bool 315LSQ<Impl>::violation() 316{ 317 /* Answers: Does Anybody Have a Violation?*/ 318 list<ThreadID>::iterator threads = activeThreads->begin(); 319 list<ThreadID>::iterator end = activeThreads->end(); 320 321 while (threads != end) { 322 ThreadID tid = *threads++; 323 324 if (thread[tid].violation()) 325 return true; 326 } 327 328 return false; 329} 330 331template <class Impl> 332void 333LSQ<Impl>::recvRetry() 334{ 335 iewStage->cacheUnblocked(); 336 337 for (ThreadID tid : *activeThreads) { 338 thread[tid].recvRetry(); 339 } 340} 341 342template <class Impl> 343bool 344LSQ<Impl>::recvTimingResp(PacketPtr pkt) 345{ 346 if (pkt->isError()) 347 DPRINTF(LSQ, "Got error packet back for address: %#X\n", 348 pkt->getAddr()); 349 thread[pkt->req->threadId()].completeDataAccess(pkt); 350 delete pkt->req; 351 delete pkt; 352 return true; 353} 354 355template <class Impl> 356void 357LSQ<Impl>::recvTimingSnoopReq(PacketPtr pkt) 358{ 359 DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(), 360 pkt->cmdString()); 361 362 // must be a snoop 363 if (pkt->isInvalidate()) { 364 DPRINTF(LSQ, "received invalidation for addr:%#x\n", 365 pkt->getAddr()); 366 for (ThreadID tid = 0; tid < numThreads; tid++) { 367 thread[tid].checkSnoop(pkt); 368 } 369 } 370} 371 372template<class Impl> 373int 374LSQ<Impl>::getCount() 375{ 376 unsigned total = 0; 377 378 list<ThreadID>::iterator threads = activeThreads->begin(); 379 list<ThreadID>::iterator end = activeThreads->end(); 380 381 while (threads != end) { 382 ThreadID tid = *threads++; 383 384 total += getCount(tid); 385 } 386 387 return total; 388} 389 390template<class Impl> 391int 392LSQ<Impl>::numLoads() 393{ 394 unsigned total = 0; 395 396 list<ThreadID>::iterator threads = activeThreads->begin(); 397 list<ThreadID>::iterator end = activeThreads->end(); 398 399 while (threads != end) { 400 ThreadID tid = *threads++; 401 402 total += numLoads(tid); 403 } 404 405 return total; 406} 407 408template<class Impl> 409int 410LSQ<Impl>::numStores() 411{ 412 unsigned total = 0; 413 414 list<ThreadID>::iterator threads = activeThreads->begin(); 415 list<ThreadID>::iterator end = activeThreads->end(); 416 417 while (threads != end) { 418 ThreadID tid = *threads++; 419 420 total += thread[tid].numStores(); 421 } 422 423 return total; 424} 425 426template<class Impl> 427unsigned 428LSQ<Impl>::numFreeLoadEntries() 429{ 430 unsigned total = 0; 431 432 list<ThreadID>::iterator threads = activeThreads->begin(); 433 list<ThreadID>::iterator end = activeThreads->end(); 434 435 while (threads != end) { 436 ThreadID tid = *threads++; 437 438 total += thread[tid].numFreeLoadEntries(); 439 } 440 441 return total; 442} 443 444template<class Impl> 445unsigned 446LSQ<Impl>::numFreeStoreEntries() 447{ 448 unsigned total = 0; 449 450 list<ThreadID>::iterator threads = activeThreads->begin(); 451 list<ThreadID>::iterator end = activeThreads->end(); 452 453 while (threads != end) { 454 ThreadID tid = *threads++; 455 456 total += thread[tid].numFreeStoreEntries(); 457 } 458 459 return total; 460} 461 462template<class Impl> 463unsigned 464LSQ<Impl>::numFreeLoadEntries(ThreadID tid) 465{ 466 return thread[tid].numFreeLoadEntries(); 467} 468 469template<class Impl> 470unsigned 471LSQ<Impl>::numFreeStoreEntries(ThreadID tid) 472{ 473 return thread[tid].numFreeStoreEntries(); 474} 475 476template<class Impl> 477bool 478LSQ<Impl>::isFull() 479{ 480 list<ThreadID>::iterator threads = activeThreads->begin(); 481 list<ThreadID>::iterator end = activeThreads->end(); 482 483 while (threads != end) { 484 ThreadID tid = *threads++; 485 486 if (!(thread[tid].lqFull() || thread[tid].sqFull())) 487 return false; 488 } 489 490 return true; 491} 492 493template<class Impl> 494bool 495LSQ<Impl>::isFull(ThreadID tid) 496{ 497 //@todo: Change to Calculate All Entries for 498 //Dynamic Policy 499 if (lsqPolicy == Dynamic) 500 return isFull(); 501 else 502 return thread[tid].lqFull() || thread[tid].sqFull(); 503} 504 505template<class Impl> 506bool 507LSQ<Impl>::isEmpty() const 508{ 509 return lqEmpty() && sqEmpty(); 510} 511 512template<class Impl> 513bool 514LSQ<Impl>::lqEmpty() const 515{ 516 list<ThreadID>::const_iterator threads = activeThreads->begin(); 517 list<ThreadID>::const_iterator end = activeThreads->end(); 518 519 while (threads != end) { 520 ThreadID tid = *threads++; 521 522 if (!thread[tid].lqEmpty()) 523 return false; 524 } 525 526 return true; 527} 528 529template<class Impl> 530bool 531LSQ<Impl>::sqEmpty() const 532{ 533 list<ThreadID>::const_iterator threads = activeThreads->begin(); 534 list<ThreadID>::const_iterator end = activeThreads->end(); 535 536 while (threads != end) { 537 ThreadID tid = *threads++; 538 539 if (!thread[tid].sqEmpty()) 540 return false; 541 } 542 543 return true; 544} 545 546template<class Impl> 547bool 548LSQ<Impl>::lqFull() 549{ 550 list<ThreadID>::iterator threads = activeThreads->begin(); 551 list<ThreadID>::iterator end = activeThreads->end(); 552 553 while (threads != end) { 554 ThreadID tid = *threads++; 555 556 if (!thread[tid].lqFull()) 557 return false; 558 } 559 560 return true; 561} 562 563template<class Impl> 564bool 565LSQ<Impl>::lqFull(ThreadID tid) 566{ 567 //@todo: Change to Calculate All Entries for 568 //Dynamic Policy 569 if (lsqPolicy == Dynamic) 570 return lqFull(); 571 else 572 return thread[tid].lqFull(); 573} 574 575template<class Impl> 576bool 577LSQ<Impl>::sqFull() 578{ 579 list<ThreadID>::iterator threads = activeThreads->begin(); 580 list<ThreadID>::iterator end = activeThreads->end(); 581 582 while (threads != end) { 583 ThreadID tid = *threads++; 584 585 if (!sqFull(tid)) 586 return false; 587 } 588 589 return true; 590} 591 592template<class Impl> 593bool 594LSQ<Impl>::sqFull(ThreadID tid) 595{ 596 //@todo: Change to Calculate All Entries for 597 //Dynamic Policy 598 if (lsqPolicy == Dynamic) 599 return sqFull(); 600 else 601 return thread[tid].sqFull(); 602} 603 604template<class Impl> 605bool 606LSQ<Impl>::isStalled() 607{ 608 list<ThreadID>::iterator threads = activeThreads->begin(); 609 list<ThreadID>::iterator end = activeThreads->end(); 610 611 while (threads != end) { 612 ThreadID tid = *threads++; 613 614 if (!thread[tid].isStalled()) 615 return false; 616 } 617 618 return true; 619} 620 621template<class Impl> 622bool 623LSQ<Impl>::isStalled(ThreadID tid) 624{ 625 if (lsqPolicy == Dynamic) 626 return isStalled(); 627 else 628 return thread[tid].isStalled(); 629} 630 631template<class Impl> 632bool 633LSQ<Impl>::hasStoresToWB() 634{ 635 list<ThreadID>::iterator threads = activeThreads->begin(); 636 list<ThreadID>::iterator end = activeThreads->end(); 637 638 while (threads != end) { 639 ThreadID tid = *threads++; 640 641 if (hasStoresToWB(tid)) 642 return true; 643 } 644 645 return false; 646} 647 648template<class Impl> 649bool 650LSQ<Impl>::willWB() 651{ 652 list<ThreadID>::iterator threads = activeThreads->begin(); 653 list<ThreadID>::iterator end = activeThreads->end(); 654 655 while (threads != end) { 656 ThreadID tid = *threads++; 657 658 if (willWB(tid)) 659 return true; 660 } 661 662 return false; 663} 664 665template<class Impl> 666void 667LSQ<Impl>::dumpInsts() const 668{ 669 list<ThreadID>::const_iterator threads = activeThreads->begin(); 670 list<ThreadID>::const_iterator end = activeThreads->end(); 671 672 while (threads != end) { 673 ThreadID tid = *threads++; 674 675 thread[tid].dumpInsts(); 676 } 677} 678 679#endif//__CPU_O3_LSQ_IMPL_HH__ 680