inst_queue_impl.hh revision 1061
111988Sandreas.sandberg@arm.com#ifndef __INST_QUEUE_IMPL_HH__ 211988Sandreas.sandberg@arm.com#define __INST_QUEUE_IMPL_HH__ 311988Sandreas.sandberg@arm.com 411988Sandreas.sandberg@arm.com// Todo: 511988Sandreas.sandberg@arm.com// Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake 611988Sandreas.sandberg@arm.com// it; either do in reverse order, or have added instructions put into a 711988Sandreas.sandberg@arm.com// different ready queue that, in scheduleRreadyInsts(), gets put onto the 811988Sandreas.sandberg@arm.com// normal ready queue. This would however give only a one cycle delay, 911988Sandreas.sandberg@arm.com// but probably is more flexible to actually add in a delay parameter than 1011988Sandreas.sandberg@arm.com// just running it backwards. 1111988Sandreas.sandberg@arm.com 1211988Sandreas.sandberg@arm.com#include <vector> 1311988Sandreas.sandberg@arm.com 1411988Sandreas.sandberg@arm.com#include "sim/universe.hh" 1511988Sandreas.sandberg@arm.com#include "cpu/beta_cpu/inst_queue.hh" 1611988Sandreas.sandberg@arm.com 1711988Sandreas.sandberg@arm.com// Either compile error or max int due to sign extension. 1811988Sandreas.sandberg@arm.com// Blatant hack to avoid compile warnings. 1911988Sandreas.sandberg@arm.comconst InstSeqNum MaxInstSeqNum = 0 - 1; 2011988Sandreas.sandberg@arm.com 2111988Sandreas.sandberg@arm.comtemplate <class Impl> 2211988Sandreas.sandberg@arm.comInstructionQueue<Impl>::InstructionQueue(Params ¶ms) 2311988Sandreas.sandberg@arm.com : memDepUnit(params), 2411988Sandreas.sandberg@arm.com numEntries(params.numIQEntries), 2511988Sandreas.sandberg@arm.com intWidth(params.executeIntWidth), 2611988Sandreas.sandberg@arm.com floatWidth(params.executeFloatWidth), 2711988Sandreas.sandberg@arm.com totalWidth(params.issueWidth), 2811988Sandreas.sandberg@arm.com numPhysIntRegs(params.numPhysIntRegs), 2911988Sandreas.sandberg@arm.com numPhysFloatRegs(params.numPhysFloatRegs), 3011988Sandreas.sandberg@arm.com commitToIEWDelay(params.commitToIEWDelay) 3111988Sandreas.sandberg@arm.com{ 3211988Sandreas.sandberg@arm.com // HACK: HARDCODED NUMBER. REMOVE LATER AND ADD TO PARAMETER. 3311988Sandreas.sandberg@arm.com branchWidth = 1; 3411988Sandreas.sandberg@arm.com memoryWidth = 1; 3511988Sandreas.sandberg@arm.com 3611988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Int width is %i.\n", params.executeIntWidth); 3711988Sandreas.sandberg@arm.com 3811988Sandreas.sandberg@arm.com // Initialize the number of free IQ entries. 3911988Sandreas.sandberg@arm.com freeEntries = numEntries; 4011988Sandreas.sandberg@arm.com 4111988Sandreas.sandberg@arm.com // Set the number of physical registers as the number of int + float 4211988Sandreas.sandberg@arm.com numPhysRegs = numPhysIntRegs + numPhysFloatRegs; 4311988Sandreas.sandberg@arm.com 4411988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs); 4511988Sandreas.sandberg@arm.com 4611988Sandreas.sandberg@arm.com //Create an entry for each physical register within the 4711988Sandreas.sandberg@arm.com //dependency graph. 4811988Sandreas.sandberg@arm.com dependGraph = new DependencyEntry[numPhysRegs]; 4912035Sandreas.sandberg@arm.com 5012035Sandreas.sandberg@arm.com // Resize the register scoreboard. 5111988Sandreas.sandberg@arm.com regScoreboard.resize(numPhysRegs); 5211988Sandreas.sandberg@arm.com 5311988Sandreas.sandberg@arm.com // Initialize all the head pointers to point to NULL, and all the 5411988Sandreas.sandberg@arm.com // entries as unready. 5511988Sandreas.sandberg@arm.com // Note that in actuality, the registers corresponding to the logical 5611988Sandreas.sandberg@arm.com // registers start off as ready. However this doesn't matter for the 5711988Sandreas.sandberg@arm.com // IQ as the instruction should have been correctly told if those 5811988Sandreas.sandberg@arm.com // registers are ready in rename. Thus it can all be initialized as 5911988Sandreas.sandberg@arm.com // unready. 6011988Sandreas.sandberg@arm.com for (int i = 0; i < numPhysRegs; ++i) 6111988Sandreas.sandberg@arm.com { 6211988Sandreas.sandberg@arm.com dependGraph[i].next = NULL; 6311988Sandreas.sandberg@arm.com dependGraph[i].inst = NULL; 6411988Sandreas.sandberg@arm.com regScoreboard[i] = false; 6511988Sandreas.sandberg@arm.com } 6611988Sandreas.sandberg@arm.com 6711988Sandreas.sandberg@arm.com} 6811988Sandreas.sandberg@arm.com 6911988Sandreas.sandberg@arm.comtemplate <class Impl> 7011988Sandreas.sandberg@arm.comvoid 7111988Sandreas.sandberg@arm.comInstructionQueue<Impl>::setCPU(FullCPU *cpu_ptr) 7211988Sandreas.sandberg@arm.com{ 7311988Sandreas.sandberg@arm.com cpu = cpu_ptr; 7411988Sandreas.sandberg@arm.com 7511988Sandreas.sandberg@arm.com tail = cpu->instList.begin(); 7611988Sandreas.sandberg@arm.com} 7711988Sandreas.sandberg@arm.com 7811988Sandreas.sandberg@arm.comtemplate <class Impl> 7911988Sandreas.sandberg@arm.comvoid 8011988Sandreas.sandberg@arm.comInstructionQueue<Impl>::setIssueToExecuteQueue( 8111988Sandreas.sandberg@arm.com TimeBuffer<IssueStruct> *i2e_ptr) 8211988Sandreas.sandberg@arm.com{ 8311988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Set the issue to execute queue.\n"); 8411988Sandreas.sandberg@arm.com issueToExecuteQueue = i2e_ptr; 8511988Sandreas.sandberg@arm.com} 8611988Sandreas.sandberg@arm.com 8711988Sandreas.sandberg@arm.comtemplate <class Impl> 8811988Sandreas.sandberg@arm.comvoid 8911988Sandreas.sandberg@arm.comInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 9011988Sandreas.sandberg@arm.com{ 9111988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Set the time buffer.\n"); 9211988Sandreas.sandberg@arm.com timeBuffer = tb_ptr; 9311988Sandreas.sandberg@arm.com 9411988Sandreas.sandberg@arm.com fromCommit = timeBuffer->getWire(-commitToIEWDelay); 9511988Sandreas.sandberg@arm.com} 9611988Sandreas.sandberg@arm.com 9711988Sandreas.sandberg@arm.com// Might want to do something more complex if it knows how many instructions 9811988Sandreas.sandberg@arm.com// will be issued this cycle. 9911988Sandreas.sandberg@arm.comtemplate <class Impl> 10011988Sandreas.sandberg@arm.combool 10111988Sandreas.sandberg@arm.comInstructionQueue<Impl>::isFull() 10211988Sandreas.sandberg@arm.com{ 10311988Sandreas.sandberg@arm.com if (freeEntries == 0) { 10411988Sandreas.sandberg@arm.com return(true); 10511988Sandreas.sandberg@arm.com } else { 10611988Sandreas.sandberg@arm.com return(false); 10711988Sandreas.sandberg@arm.com } 10811988Sandreas.sandberg@arm.com} 10911988Sandreas.sandberg@arm.com 11011988Sandreas.sandberg@arm.comtemplate <class Impl> 11111988Sandreas.sandberg@arm.comunsigned 11211988Sandreas.sandberg@arm.comInstructionQueue<Impl>::numFreeEntries() 11311988Sandreas.sandberg@arm.com{ 11411988Sandreas.sandberg@arm.com return freeEntries; 11511988Sandreas.sandberg@arm.com} 11611988Sandreas.sandberg@arm.com 11711988Sandreas.sandberg@arm.comtemplate <class Impl> 11811988Sandreas.sandberg@arm.comvoid 11911988Sandreas.sandberg@arm.comInstructionQueue<Impl>::insert(DynInstPtr &new_inst) 12011988Sandreas.sandberg@arm.com{ 12111988Sandreas.sandberg@arm.com // Make sure the instruction is valid 12211988Sandreas.sandberg@arm.com assert(new_inst); 12311988Sandreas.sandberg@arm.com 12411988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n", 12511988Sandreas.sandberg@arm.com new_inst->readPC()); 12611988Sandreas.sandberg@arm.com 12711988Sandreas.sandberg@arm.com // Check if there are any free entries. Panic if there are none. 12811988Sandreas.sandberg@arm.com // Might want to have this return a fault in the future instead of 12911988Sandreas.sandberg@arm.com // panicing. 13011988Sandreas.sandberg@arm.com assert(freeEntries != 0); 13111988Sandreas.sandberg@arm.com 13211988Sandreas.sandberg@arm.com // If the IQ currently has nothing in it, then there's a possibility 13311988Sandreas.sandberg@arm.com // that the tail iterator is invalid (might have been pointing at an 13411988Sandreas.sandberg@arm.com // instruction that was retired). Reset the tail iterator. 13512036Sandreas.sandberg@arm.com if (freeEntries == numEntries) { 13612036Sandreas.sandberg@arm.com tail = cpu->instList.begin(); 13711988Sandreas.sandberg@arm.com } 13811988Sandreas.sandberg@arm.com 13911988Sandreas.sandberg@arm.com // Move the tail iterator. Instructions may not have been issued 14011988Sandreas.sandberg@arm.com // to the IQ, so we may have to increment the iterator more than once. 14111988Sandreas.sandberg@arm.com while ((*tail) != new_inst) { 14211988Sandreas.sandberg@arm.com tail++; 14311988Sandreas.sandberg@arm.com 14411988Sandreas.sandberg@arm.com // Make sure the tail iterator points at something legal. 14511988Sandreas.sandberg@arm.com assert(tail != cpu->instList.end()); 14611988Sandreas.sandberg@arm.com } 14711988Sandreas.sandberg@arm.com 14811988Sandreas.sandberg@arm.com 14911988Sandreas.sandberg@arm.com // Decrease the number of free entries. 15011988Sandreas.sandberg@arm.com --freeEntries; 15111988Sandreas.sandberg@arm.com 15211988Sandreas.sandberg@arm.com // Look through its source registers (physical regs), and mark any 15311988Sandreas.sandberg@arm.com // dependencies. 15411988Sandreas.sandberg@arm.com addToDependents(new_inst); 15511988Sandreas.sandberg@arm.com 15611988Sandreas.sandberg@arm.com // Have this instruction set itself as the producer of its destination 15711988Sandreas.sandberg@arm.com // register(s). 15811988Sandreas.sandberg@arm.com createDependency(new_inst); 15911988Sandreas.sandberg@arm.com 16011988Sandreas.sandberg@arm.com // If it's a memory instruction, add it to the memory dependency 16111988Sandreas.sandberg@arm.com // unit. 16211988Sandreas.sandberg@arm.com if (new_inst->isMemRef()) { 16311988Sandreas.sandberg@arm.com memDepUnit.insert(new_inst); 16411988Sandreas.sandberg@arm.com } 16511988Sandreas.sandberg@arm.com 16611988Sandreas.sandberg@arm.com // If the instruction is ready then add it to the ready list. 16711988Sandreas.sandberg@arm.com addIfReady(new_inst); 16811988Sandreas.sandberg@arm.com 16912036Sandreas.sandberg@arm.com assert(freeEntries == (numEntries - countInsts())); 17012035Sandreas.sandberg@arm.com} 17112035Sandreas.sandberg@arm.com 17212035Sandreas.sandberg@arm.comtemplate <class Impl> 17311988Sandreas.sandberg@arm.comvoid 17411988Sandreas.sandberg@arm.comInstructionQueue<Impl>::insertNonSpec(DynInstPtr &inst) 17511988Sandreas.sandberg@arm.com{ 17611988Sandreas.sandberg@arm.com nonSpecInsts[inst->seqNum] = inst; 17711988Sandreas.sandberg@arm.com 17811988Sandreas.sandberg@arm.com // @todo: Clean up this code; can do it by setting inst as unable 17911988Sandreas.sandberg@arm.com // to issue, then calling normal insert on the inst. 18011988Sandreas.sandberg@arm.com 18111988Sandreas.sandberg@arm.com // Make sure the instruction is valid 18211988Sandreas.sandberg@arm.com assert(inst); 18311988Sandreas.sandberg@arm.com 18411988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n", 18511988Sandreas.sandberg@arm.com inst->readPC()); 18611988Sandreas.sandberg@arm.com 18711988Sandreas.sandberg@arm.com // Check if there are any free entries. Panic if there are none. 18811988Sandreas.sandberg@arm.com // Might want to have this return a fault in the future instead of 18911988Sandreas.sandberg@arm.com // panicing. 19011988Sandreas.sandberg@arm.com assert(freeEntries != 0); 19111988Sandreas.sandberg@arm.com 19211988Sandreas.sandberg@arm.com // If the IQ currently has nothing in it, then there's a possibility 19311988Sandreas.sandberg@arm.com // that the tail iterator is invalid (might have been pointing at an 19411988Sandreas.sandberg@arm.com // instruction that was retired). Reset the tail iterator. 19511988Sandreas.sandberg@arm.com if (freeEntries == numEntries) { 19611988Sandreas.sandberg@arm.com tail = cpu->instList.begin(); 19711988Sandreas.sandberg@arm.com } 19811988Sandreas.sandberg@arm.com 19911988Sandreas.sandberg@arm.com // Move the tail iterator. Instructions may not have been issued 20011988Sandreas.sandberg@arm.com // to the IQ, so we may have to increment the iterator more than once. 20111988Sandreas.sandberg@arm.com while ((*tail) != inst) { 20211988Sandreas.sandberg@arm.com tail++; 20311988Sandreas.sandberg@arm.com 20411988Sandreas.sandberg@arm.com // Make sure the tail iterator points at something legal. 20511988Sandreas.sandberg@arm.com assert(tail != cpu->instList.end()); 20611988Sandreas.sandberg@arm.com } 20711988Sandreas.sandberg@arm.com 20811988Sandreas.sandberg@arm.com // Decrease the number of free entries. 20911988Sandreas.sandberg@arm.com --freeEntries; 21011988Sandreas.sandberg@arm.com 21111988Sandreas.sandberg@arm.com // Look through its source registers (physical regs), and mark any 21211988Sandreas.sandberg@arm.com // dependencies. 21311988Sandreas.sandberg@arm.com// addToDependents(inst); 21411988Sandreas.sandberg@arm.com 21511988Sandreas.sandberg@arm.com // Have this instruction set itself as the producer of its destination 21611988Sandreas.sandberg@arm.com // register(s). 21711988Sandreas.sandberg@arm.com createDependency(inst); 21811988Sandreas.sandberg@arm.com 21911988Sandreas.sandberg@arm.com // If it's a memory instruction, add it to the memory dependency 22011988Sandreas.sandberg@arm.com // unit. 22111988Sandreas.sandberg@arm.com if (inst->isMemRef()) { 22211988Sandreas.sandberg@arm.com memDepUnit.insert(inst); 22311988Sandreas.sandberg@arm.com } 22411988Sandreas.sandberg@arm.com} 22511988Sandreas.sandberg@arm.com 22611988Sandreas.sandberg@arm.com// Slightly hack function to advance the tail iterator in the case that 22711988Sandreas.sandberg@arm.com// the IEW stage issues an instruction that is not added to the IQ. This 22811988Sandreas.sandberg@arm.com// is needed in case a long chain of such instructions occurs. 22911988Sandreas.sandberg@arm.comtemplate <class Impl> 23011988Sandreas.sandberg@arm.comvoid 23111988Sandreas.sandberg@arm.comInstructionQueue<Impl>::advanceTail(DynInstPtr &inst) 23211988Sandreas.sandberg@arm.com{ 23311988Sandreas.sandberg@arm.com // Make sure the instruction is valid 23411988Sandreas.sandberg@arm.com assert(inst); 23511988Sandreas.sandberg@arm.com 23611988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n", 23711988Sandreas.sandberg@arm.com inst->readPC()); 23811988Sandreas.sandberg@arm.com 23911988Sandreas.sandberg@arm.com // Check if there are any free entries. Panic if there are none. 24011988Sandreas.sandberg@arm.com // Might want to have this return a fault in the future instead of 24111988Sandreas.sandberg@arm.com // panicing. 24211988Sandreas.sandberg@arm.com assert(freeEntries != 0); 24311988Sandreas.sandberg@arm.com 24412011Sgabeblack@google.com // If the IQ currently has nothing in it, then there's a possibility 24511988Sandreas.sandberg@arm.com // that the tail iterator is invalid (might have been pointing at an 24611988Sandreas.sandberg@arm.com // instruction that was retired). Reset the tail iterator. 24711988Sandreas.sandberg@arm.com if (freeEntries == numEntries) { 24811988Sandreas.sandberg@arm.com tail = cpu->instList.begin(); 24911988Sandreas.sandberg@arm.com } 25011988Sandreas.sandberg@arm.com 25111988Sandreas.sandberg@arm.com // Move the tail iterator. Instructions may not have been issued 25211988Sandreas.sandberg@arm.com // to the IQ, so we may have to increment the iterator more than once. 25311988Sandreas.sandberg@arm.com while ((*tail) != inst) { 25411988Sandreas.sandberg@arm.com tail++; 25511988Sandreas.sandberg@arm.com 25611988Sandreas.sandberg@arm.com // Make sure the tail iterator points at something legal. 25711988Sandreas.sandberg@arm.com assert(tail != cpu->instList.end()); 25811988Sandreas.sandberg@arm.com } 25911988Sandreas.sandberg@arm.com 26011988Sandreas.sandberg@arm.com assert(freeEntries <= numEntries); 26111988Sandreas.sandberg@arm.com 26211988Sandreas.sandberg@arm.com // Have this instruction set itself as the producer of its destination 26311988Sandreas.sandberg@arm.com // register(s). 26411988Sandreas.sandberg@arm.com createDependency(inst); 26511988Sandreas.sandberg@arm.com} 26611988Sandreas.sandberg@arm.com 26711988Sandreas.sandberg@arm.com// Need to make sure the number of float and integer instructions 26811988Sandreas.sandberg@arm.com// issued does not exceed the total issue bandwidth. 26911988Sandreas.sandberg@arm.com// @todo: Figure out a better way to remove the squashed items from the 27011988Sandreas.sandberg@arm.com// lists. Checking the top item of each list to see if it's squashed 27111988Sandreas.sandberg@arm.com// wastes time and forces jumps. 27211988Sandreas.sandberg@arm.comtemplate <class Impl> 27311988Sandreas.sandberg@arm.comvoid 27411988Sandreas.sandberg@arm.comInstructionQueue<Impl>::scheduleReadyInsts() 27511988Sandreas.sandberg@arm.com{ 27611988Sandreas.sandberg@arm.com DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from " 27711988Sandreas.sandberg@arm.com "the IQ.\n"); 27811988Sandreas.sandberg@arm.com 27911988Sandreas.sandberg@arm.com int int_issued = 0; 28011988Sandreas.sandberg@arm.com int float_issued = 0; 281 int branch_issued = 0; 282 int memory_issued = 0; 283 int squashed_issued = 0; 284 int total_issued = 0; 285 286 IssueStruct *i2e_info = issueToExecuteQueue->access(0); 287 288 bool insts_available = !readyBranchInsts.empty() || 289 !readyIntInsts.empty() || 290 !readyFloatInsts.empty() || 291 !readyMemInsts.empty() || 292 !readyMiscInsts.empty() || 293 !squashedInsts.empty(); 294 295 // Note: Requires a globally defined constant. 296 InstSeqNum oldest_inst = MaxInstSeqNum; 297 InstList list_with_oldest = None; 298 299 // Temporary values. 300 DynInstPtr int_head_inst; 301 DynInstPtr float_head_inst; 302 DynInstPtr branch_head_inst; 303 DynInstPtr mem_head_inst; 304 DynInstPtr misc_head_inst; 305 DynInstPtr squashed_head_inst; 306 307 // Somewhat nasty code to look at all of the lists where issuable 308 // instructions are located, and choose the oldest instruction among 309 // those lists. Consider a rewrite in the future. 310 while (insts_available && total_issued < totalWidth) 311 { 312 // Set this to false. Each if-block is required to set it to true 313 // if there were instructions available this check. This will cause 314 // this loop to run once more than necessary, but avoids extra calls. 315 insts_available = false; 316 317 oldest_inst = MaxInstSeqNum; 318 319 list_with_oldest = None; 320 321 if (!readyIntInsts.empty() && 322 int_issued < intWidth) { 323 324 insts_available = true; 325 326 int_head_inst = readyIntInsts.top(); 327 328 if (int_head_inst->isSquashed()) { 329 readyIntInsts.pop(); 330 continue; 331 } 332 333 oldest_inst = int_head_inst->seqNum; 334 335 list_with_oldest = Int; 336 } 337 338 if (!readyFloatInsts.empty() && 339 float_issued < floatWidth) { 340 341 insts_available = true; 342 343 float_head_inst = readyFloatInsts.top(); 344 345 if (float_head_inst->isSquashed()) { 346 readyFloatInsts.pop(); 347 continue; 348 } else if (float_head_inst->seqNum < oldest_inst) { 349 oldest_inst = float_head_inst->seqNum; 350 351 list_with_oldest = Float; 352 } 353 } 354 355 if (!readyBranchInsts.empty() && 356 branch_issued < branchWidth) { 357 358 insts_available = true; 359 360 branch_head_inst = readyBranchInsts.top(); 361 362 if (branch_head_inst->isSquashed()) { 363 readyBranchInsts.pop(); 364 continue; 365 } else if (branch_head_inst->seqNum < oldest_inst) { 366 oldest_inst = branch_head_inst->seqNum; 367 368 list_with_oldest = Branch; 369 } 370 371 } 372 373 if (!readyMemInsts.empty() && 374 memory_issued < memoryWidth) { 375 376 insts_available = true; 377 378 mem_head_inst = readyMemInsts.top(); 379 380 if (mem_head_inst->isSquashed()) { 381 readyMemInsts.pop(); 382 continue; 383 } else if (mem_head_inst->seqNum < oldest_inst) { 384 oldest_inst = mem_head_inst->seqNum; 385 386 list_with_oldest = Memory; 387 } 388 } 389 390 if (!readyMiscInsts.empty()) { 391 392 insts_available = true; 393 394 misc_head_inst = readyMiscInsts.top(); 395 396 if (misc_head_inst->isSquashed()) { 397 readyMiscInsts.pop(); 398 continue; 399 } else if (misc_head_inst->seqNum < oldest_inst) { 400 oldest_inst = misc_head_inst->seqNum; 401 402 list_with_oldest = Misc; 403 } 404 } 405 406 if (!squashedInsts.empty()) { 407 408 insts_available = true; 409 410 squashed_head_inst = squashedInsts.top(); 411 412 if (squashed_head_inst->seqNum < oldest_inst) { 413 list_with_oldest = Squashed; 414 } 415 416 } 417 418 DynInstPtr issuing_inst = NULL; 419 420 switch (list_with_oldest) { 421 case None: 422 DPRINTF(IQ, "IQ: Not able to schedule any instructions. Issuing " 423 "inst is %#x.\n", issuing_inst); 424 break; 425 426 case Int: 427 issuing_inst = int_head_inst; 428 readyIntInsts.pop(); 429 ++int_issued; 430 DPRINTF(IQ, "IQ: Issuing integer instruction PC %#x.\n", 431 issuing_inst->readPC()); 432 break; 433 434 case Float: 435 issuing_inst = float_head_inst; 436 readyFloatInsts.pop(); 437 ++float_issued; 438 DPRINTF(IQ, "IQ: Issuing float instruction PC %#x.\n", 439 issuing_inst->readPC()); 440 break; 441 442 case Branch: 443 issuing_inst = branch_head_inst; 444 readyBranchInsts.pop(); 445 ++branch_issued; 446 DPRINTF(IQ, "IQ: Issuing branch instruction PC %#x.\n", 447 issuing_inst->readPC()); 448 break; 449 450 case Memory: 451 issuing_inst = mem_head_inst; 452 453 memDepUnit.issue(mem_head_inst); 454 455 readyMemInsts.pop(); 456 ++memory_issued; 457 DPRINTF(IQ, "IQ: Issuing memory instruction PC %#x.\n", 458 issuing_inst->readPC()); 459 break; 460 461 case Misc: 462 issuing_inst = misc_head_inst; 463 readyMiscInsts.pop(); 464 DPRINTF(IQ, "IQ: Issuing a miscellaneous instruction PC %#x.\n", 465 issuing_inst->readPC()); 466 break; 467 468 case Squashed: 469 issuing_inst = squashed_head_inst; 470 squashedInsts.pop(); 471 ++squashed_issued; 472 DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n", 473 issuing_inst->readPC()); 474 break; 475 } 476 477 if (list_with_oldest != None) { 478 i2e_info->insts[total_issued] = issuing_inst; 479 480 issuing_inst->setIssued(); 481 482 ++freeEntries; 483 ++total_issued; 484 } 485 486 assert(freeEntries == (numEntries - countInsts())); 487 } 488} 489 490template <class Impl> 491void 492InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) 493{ 494 non_spec_it_t inst_it = nonSpecInsts.find(inst); 495 496 assert(inst_it != nonSpecInsts.end()); 497 498 // Mark this instruction as ready to issue. 499 (*inst_it).second->setCanIssue(); 500 501 // Now schedule the instruction. 502 addIfReady((*inst_it).second); 503 504 nonSpecInsts.erase(inst_it); 505} 506 507template <class Impl> 508void 509InstructionQueue<Impl>::violation(DynInstPtr &store, 510 DynInstPtr &faulting_load) 511{ 512 memDepUnit.violation(store, faulting_load); 513} 514 515template <class Impl> 516void 517InstructionQueue<Impl>::squash() 518{ 519 DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n"); 520 521 // Read instruction sequence number of last instruction out of the 522 // time buffer. 523 squashedSeqNum = fromCommit->commitInfo.doneSeqNum; 524 525 // Setup the squash iterator to point to the tail. 526 squashIt = tail; 527 528 // Call doSquash. 529 doSquash(); 530 531 // Also tell the memory dependence unit to squash. 532 memDepUnit.squash(squashedSeqNum); 533} 534 535template <class Impl> 536void 537InstructionQueue<Impl>::doSquash() 538{ 539 // Make sure the squash iterator isn't pointing to nothing. 540 assert(squashIt != cpu->instList.end()); 541 // Make sure the squashed sequence number is valid. 542 assert(squashedSeqNum != 0); 543 544 DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n"); 545 546 // Squash any instructions younger than the squashed sequence number 547 // given. 548 while ((*squashIt)->seqNum > squashedSeqNum) { 549 DynInstPtr squashed_inst = (*squashIt); 550 551 // Only handle the instruction if it actually is in the IQ and 552 // hasn't already been squashed in the IQ. 553 if (!squashed_inst->isIssued() && 554 !squashed_inst->isSquashedInIQ()) { 555 // Remove the instruction from the dependency list. 556 // Hack for now: These below don't add themselves to the 557 // dependency list, so don't try to remove them. 558 if (!squashed_inst->isNonSpeculative() && 559 !squashed_inst->isStore()) { 560 int8_t total_src_regs = squashed_inst->numSrcRegs(); 561 562 for (int src_reg_idx = 0; 563 src_reg_idx < total_src_regs; 564 src_reg_idx++) 565 { 566 PhysRegIndex src_reg = 567 squashed_inst->renamedSrcRegIdx(src_reg_idx); 568 569 // Only remove it from the dependency graph if it was 570 // placed there in the first place. 571 // HACK: This assumes that instructions woken up from the 572 // dependency chain aren't informed that a specific src 573 // register has become ready. This may not always be true 574 // in the future. 575 if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && 576 src_reg < numPhysRegs) { 577 dependGraph[src_reg].remove(squashed_inst); 578 } 579 } 580 } 581 582 // Might want to also clear out the head of the dependency graph. 583 584 // Mark it as squashed within the IQ. 585 squashed_inst->setSquashedInIQ(); 586 587 squashedInsts.push(squashed_inst); 588 589 DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n", 590 squashed_inst->readPC()); 591 } 592 593 if (squashed_inst->isNonSpeculative() || squashed_inst->isStore()) { 594 nonSpecInsts.erase(squashed_inst->seqNum); 595 } 596 597 --squashIt; 598 } 599} 600 601template <class Impl> 602void 603InstructionQueue<Impl>::stopSquash() 604{ 605 // Clear up the squash variables to ensure that squashing doesn't 606 // get called improperly. 607 squashedSeqNum = 0; 608 609 squashIt = cpu->instList.end(); 610} 611 612template <class Impl> 613void 614InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) 615{ 616 DPRINTF(IQ, "IQ: Waking dependents of completed instruction.\n"); 617 //Look at the physical destination register of the DynInst 618 //and look it up on the dependency graph. Then mark as ready 619 //any instructions within the instruction queue. 620 int8_t total_dest_regs = completed_inst->numDestRegs(); 621 622 DependencyEntry *curr; 623 624 // Tell the memory dependence unit to wake any dependents on this 625 // instruction if it is a memory instruction. 626 627 if (completed_inst->isMemRef()) { 628 memDepUnit.wakeDependents(completed_inst); 629 } 630 631 for (int dest_reg_idx = 0; 632 dest_reg_idx < total_dest_regs; 633 dest_reg_idx++) 634 { 635 PhysRegIndex dest_reg = 636 completed_inst->renamedDestRegIdx(dest_reg_idx); 637 638 // Special case of uniq or control registers. They are not 639 // handled by the IQ and thus have no dependency graph entry. 640 // @todo Figure out a cleaner way to handle thie. 641 if (dest_reg >= numPhysRegs) { 642 continue; 643 } 644 645 DPRINTF(IQ, "IQ: Waking any dependents on register %i.\n", 646 (int) dest_reg); 647 648 //Maybe abstract this part into a function. 649 //Go through the dependency chain, marking the registers as ready 650 //within the waiting instructions. 651 while (dependGraph[dest_reg].next) { 652 653 curr = dependGraph[dest_reg].next; 654 655 DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n", 656 curr->inst->readPC()); 657 658 // Might want to give more information to the instruction 659 // so that it knows which of its source registers is ready. 660 // However that would mean that the dependency graph entries 661 // would need to hold the src_reg_idx. 662 curr->inst->markSrcRegReady(); 663 664 addIfReady(curr->inst); 665 666 dependGraph[dest_reg].next = curr->next; 667 668 delete curr; 669 } 670 671 // Reset the head node now that all of its dependents have been woken 672 // up. 673 dependGraph[dest_reg].next = NULL; 674 dependGraph[dest_reg].inst = NULL; 675 676 // Mark the scoreboard as having that register ready. 677 regScoreboard[dest_reg] = true; 678 } 679} 680 681template <class Impl> 682bool 683InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst) 684{ 685 // Loop through the instruction's source registers, adding 686 // them to the dependency list if they are not ready. 687 int8_t total_src_regs = new_inst->numSrcRegs(); 688 bool return_val = false; 689 690 for (int src_reg_idx = 0; 691 src_reg_idx < total_src_regs; 692 src_reg_idx++) 693 { 694 // Only add it to the dependency graph if it's not ready. 695 if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { 696 PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); 697 698 // Check the IQ's scoreboard to make sure the register 699 // hasn't become ready while the instruction was in flight 700 // between stages. Only if it really isn't ready should 701 // it be added to the dependency graph. 702 if (src_reg >= numPhysRegs) { 703 continue; 704 } else if (regScoreboard[src_reg] == false) { 705 DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that " 706 "is being added to the dependency chain.\n", 707 new_inst->readPC(), src_reg); 708 709 dependGraph[src_reg].insert(new_inst); 710 711 // Change the return value to indicate that something 712 // was added to the dependency graph. 713 return_val = true; 714 } else { 715 DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that " 716 "became ready before it reached the IQ.\n", 717 new_inst->readPC(), src_reg); 718 // Mark a register ready within the instruction. 719 new_inst->markSrcRegReady(); 720 } 721 } 722 } 723 724 return return_val; 725} 726 727template <class Impl> 728void 729InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst) 730{ 731 //Actually nothing really needs to be marked when an 732 //instruction becomes the producer of a register's value, 733 //but for convenience a ptr to the producing instruction will 734 //be placed in the head node of the dependency links. 735 int8_t total_dest_regs = new_inst->numDestRegs(); 736 737 for (int dest_reg_idx = 0; 738 dest_reg_idx < total_dest_regs; 739 dest_reg_idx++) 740 { 741 PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); 742 743 // Instructions that use the misc regs will have a reg number 744 // higher than the normal physical registers. In this case these 745 // registers are not renamed, and there is no need to track 746 // dependencies as these instructions must be executed at commit. 747 if (dest_reg >= numPhysRegs) { 748 continue; 749 } 750 751 dependGraph[dest_reg].inst = new_inst; 752#if 0 753 if (dependGraph[dest_reg].next) { 754 panic("Dependency chain of dest reg %i is not empty.\n", 755 dest_reg); 756 } 757#endif 758 assert(!dependGraph[dest_reg].next); 759 // Mark the scoreboard to say it's not yet ready. 760 regScoreboard[dest_reg] = false; 761 } 762} 763 764template <class Impl> 765void 766InstructionQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst) 767{ 768 //Add this new, dependent instruction at the head of the dependency 769 //chain. 770 771 // First create the entry that will be added to the head of the 772 // dependency chain. 773 DependencyEntry *new_entry = new DependencyEntry; 774 new_entry->next = this->next; 775 new_entry->inst = new_inst; 776 777 // Then actually add it to the chain. 778 this->next = new_entry; 779} 780 781template <class Impl> 782void 783InstructionQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove) 784{ 785 DependencyEntry *prev = this; 786 DependencyEntry *curr = this->next; 787 788 // Make sure curr isn't NULL. Because this instruction is being 789 // removed from a dependency list, it must have been placed there at 790 // an earlier time. The dependency chain should not be empty, 791 // unless the instruction dependent upon it is already ready. 792 if (curr == NULL) { 793 return; 794 } 795 796 // Find the instruction to remove within the dependency linked list. 797 while(curr->inst != inst_to_remove) 798 { 799 prev = curr; 800 curr = curr->next; 801 802 assert(curr != NULL); 803 } 804 805 // Now remove this instruction from the list. 806 prev->next = curr->next; 807 808 delete curr; 809} 810 811template <class Impl> 812void 813InstructionQueue<Impl>::dumpDependGraph() 814{ 815 DependencyEntry *curr; 816 817 for (int i = 0; i < numPhysRegs; ++i) 818 { 819 curr = &dependGraph[i]; 820 821 if (curr->inst) { 822 cprintf("dependGraph[%i]: producer: %#x consumer: ", i, 823 curr->inst->readPC()); 824 } else { 825 cprintf("dependGraph[%i]: No producer. consumer: ", i); 826 } 827 828 while (curr->next != NULL) { 829 curr = curr->next; 830 831 cprintf("%#x ", curr->inst->readPC()); 832 } 833 834 cprintf("\n"); 835 } 836} 837 838template <class Impl> 839void 840InstructionQueue<Impl>::addIfReady(DynInstPtr &inst) 841{ 842 //If the instruction now has all of its source registers 843 // available, then add it to the list of ready instructions. 844 if (inst->readyToIssue()) { 845 846 //Add the instruction to the proper ready list. 847 if (inst->isControl()) { 848 849 DPRINTF(IQ, "IQ: Branch instruction is ready to issue, " 850 "putting it onto the ready list, PC %#x.\n", 851 inst->readPC()); 852 readyBranchInsts.push(inst); 853 854 } else if (inst->isMemRef()) { 855 856 DPRINTF(IQ, "IQ: Checking if memory instruction can issue.\n"); 857 858 if (memDepUnit.readyToIssue(inst)) { 859 DPRINTF(IQ, "IQ: Memory instruction is ready to issue, " 860 "putting it onto the ready list, PC %#x.\n", 861 inst->readPC()); 862 readyMemInsts.push(inst); 863 } 864 865 } else if (inst->isInteger()) { 866 867 DPRINTF(IQ, "IQ: Integer instruction is ready to issue, " 868 "putting it onto the ready list, PC %#x.\n", 869 inst->readPC()); 870 readyIntInsts.push(inst); 871 872 } else if (inst->isFloating()) { 873 874 DPRINTF(IQ, "IQ: Floating instruction is ready to issue, " 875 "putting it onto the ready list, PC %#x.\n", 876 inst->readPC()); 877 readyFloatInsts.push(inst); 878 879 } else { 880 DPRINTF(IQ, "IQ: Miscellaneous instruction is ready to issue, " 881 "putting it onto the ready list, PC %#x..\n", 882 inst->readPC()); 883 884 readyMiscInsts.push(inst); 885 } 886 } 887} 888 889template <class Impl> 890int 891InstructionQueue<Impl>::countInsts() 892{ 893 ListIt count_it = cpu->instList.begin(); 894 int total_insts = 0; 895 896 while (count_it != tail) { 897 if (!(*count_it)->isIssued()) { 898 ++total_insts; 899 } 900 901 ++count_it; 902 903 assert(count_it != cpu->instList.end()); 904 } 905 906 // Need to count the tail iterator as well. 907 if (count_it != cpu->instList.end() && 908 (*count_it) && 909 !(*count_it)->isIssued()) { 910 ++total_insts; 911 } 912 913 return total_insts; 914} 915 916template <class Impl> 917void 918InstructionQueue<Impl>::dumpLists() 919{ 920 cprintf("Ready integer list size: %i\n", readyIntInsts.size()); 921 922 cprintf("Ready float list size: %i\n", readyFloatInsts.size()); 923 924 cprintf("Ready branch list size: %i\n", readyBranchInsts.size()); 925 926 cprintf("Ready memory list size: %i\n", readyMemInsts.size()); 927 928 cprintf("Ready misc list size: %i\n", readyMiscInsts.size()); 929 930 cprintf("Squashed list size: %i\n", squashedInsts.size()); 931 932 cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); 933 934 non_spec_it_t non_spec_it = nonSpecInsts.begin(); 935 936 cprintf("Non speculative list: "); 937 938 while (non_spec_it != nonSpecInsts.end()) { 939 cprintf("%#x ", (*non_spec_it).second->readPC()); 940 ++non_spec_it; 941 } 942 943 cprintf("\n"); 944 945} 946 947#endif // __INST_QUEUE_IMPL_HH__ 948