#ifndef __ROB_IMPL_HH__ #define __ROB_IMPL_HH__ #include "cpu/beta_cpu/rob.hh" template ROB::ROB(unsigned _numEntries, unsigned _squashWidth) : numEntries(_numEntries), squashWidth(_squashWidth), numInstsInROB(0), squashedSeqNum(0) { doneSquashing = true; } template void ROB::setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; tail = cpu->instList.begin(); squashIt = cpu->instList.end(); } template int ROB::countInsts() { /* int return_val = 0; // Iterate through the ROB from the head to the tail, counting the // entries. for (InstIt i = cpu->instList.begin(); i != tail; i++) { assert(i != cpu->instList.end()); return_val++; } return return_val; */ // Because the head won't be tracked properly until the ROB gets the // first instruction, and any time that the ROB is empty and has not // yet gotten the instruction, this function doesn't work. return numInstsInROB; } template void ROB::insertInst(DynInst *inst) { // Make sure we have the right number of instructions. assert(numInstsInROB == countInsts()); // Make sure the instruction is valid. assert(inst); DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC()); // If the ROB is full then exit. assert(numInstsInROB != numEntries); ++numInstsInROB; // Increment the tail iterator, moving it one instruction back. // There is a special case if the ROB was empty prior to this insertion, // in which case the tail will be pointing at instList.end(). If that // happens, then reset the tail to the beginning of the list. if (tail != cpu->instList.end()) { tail++; } else { tail = cpu->instList.begin(); } // Make sure the tail iterator is actually pointing at the instruction // added. assert((*tail) == inst); DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB); } // Whatever calls this function needs to ensure that it properly frees up // registers prior to this function. template void ROB::retireHead() { assert(numInstsInROB == countInsts()); DynInst *head_inst; // Get the head ROB instruction. head_inst = cpu->instList.front(); // Make certain this can retire. assert(head_inst->readyToCommit()); DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, " "instruction PC %#x, seq num %i\n", head_inst->readPC(), head_inst->seqNum); // Keep track of how many instructions are in the ROB. --numInstsInROB; // Tell CPU to remove the instruction from the list of instructions. // A special case is needed if the instruction being retired is the // only instruction in the ROB; otherwise the tail iterator will become // invalidated. if (tail == cpu->instList.begin()) { cpu->removeFrontInst(head_inst); tail = cpu->instList.end(); } else { cpu->removeFrontInst(head_inst); } } template bool ROB::isHeadReady() { if (numInstsInROB != 0) { DynInst *head_inst = cpu->instList.front(); return head_inst->readyToCommit(); } return false; } template unsigned ROB::numFreeEntries() { assert(numInstsInROB == countInsts()); return numEntries - numInstsInROB; } template void ROB::doSquash() { DPRINTF(ROB, "ROB: Squashing instructions.\n"); assert(squashIt != cpu->instList.end()); for (int numSquashed = 0; numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum; ++numSquashed) { // Ensure that the instruction is younger. assert((*squashIt)->seqNum > squashedSeqNum); DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n", (*squashIt)->readPC(), (*squashIt)->seqNum); // Mark the instruction as squashed, and ready to commit so that // it can drain out of the pipeline. (*squashIt)->setSquashed(); (*squashIt)->setCanCommit(); #ifndef FULL_SYSTEM if (squashIt == cpu->instList.begin()) { DPRINTF(ROB, "ROB: Reached head of instruction list while " "squashing.\n"); squashIt = cpu->instList.end(); doneSquashing = true; return; } #endif // Move the tail iterator to the next instruction. squashIt--; } // Check if ROB is done squashing. if ((*squashIt)->seqNum == squashedSeqNum) { DPRINTF(ROB, "ROB: Done squashing instructions.\n"); squashIt = cpu->instList.end(); doneSquashing = true; } } template void ROB::squash(InstSeqNum squash_num) { DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n"); doneSquashing = false; squashedSeqNum = squash_num; assert(tail != cpu->instList.end()); squashIt = tail; doSquash(); } template uint64_t ROB::readHeadPC() { assert(numInstsInROB == countInsts()); DynInst *head_inst = cpu->instList.front(); return head_inst->readPC(); } template uint64_t ROB::readHeadNextPC() { assert(numInstsInROB == countInsts()); DynInst *head_inst = cpu->instList.front(); return head_inst->readNextPC(); } template InstSeqNum ROB::readHeadSeqNum() { // Return the last sequence number that has not been squashed. Other // stages can use it to squash any instructions younger than the current // tail. DynInst *head_inst = cpu->instList.front(); return head_inst->seqNum; } template uint64_t ROB::readTailPC() { assert(numInstsInROB == countInsts()); assert(tail != cpu->instList.end()); return (*tail)->readPC(); } template InstSeqNum ROB::readTailSeqNum() { // Return the last sequence number that has not been squashed. Other // stages can use it to squash any instructions younger than the current // tail. return (*tail)->seqNum; } #endif // __ROB_IMPL_HH__