diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index cb954b8eb7..3c421a45a3 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -168,7 +168,7 @@ class DefaultCommit void setRenameMap(UnifiedRenameMap rm_ptr[O3MaxThreads]); /** Sets pointer to the ROB. */ - void setROB(ROB *rob_ptr); + void setROB(ROB *rob_ptr); /** Initializes stage by sending back the number of free entries. */ void startupStage(); @@ -347,7 +347,7 @@ class DefaultCommit public: /** ROB interface. */ - ROB *rob; + ROB *rob; private: /** Pointer to O3CPU. */ diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index 3e7f97f8d8..804611750c 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -324,7 +324,7 @@ DefaultCommit::setRenameMap(UnifiedRenameMap rm_ptr[]) template void -DefaultCommit::setROB(ROB *rob_ptr) +DefaultCommit::setROB(ROB *rob_ptr) { rob = rob_ptr; } diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 7b5fac05fb..2b220024d8 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -521,7 +521,7 @@ class FullO3CPU : public BaseO3CPU UnifiedRenameMap commitRenameMap[O3MaxThreads]; /** The re-order buffer. */ - ROB rob; + ROB rob; /** Active Threads List */ std::list activeThreads; diff --git a/src/cpu/o3/rob.cc b/src/cpu/o3/rob.cc index 6f1af96894..52b55ee357 100644 --- a/src/cpu/o3/rob.cc +++ b/src/cpu/o3/rob.cc @@ -1,5 +1,17 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,8 +38,497 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "cpu/o3/isa_specific.hh" -#include "cpu/o3/rob_impl.hh" +#include "cpu/o3/rob.hh" -// Force instantiation of InstructionQueue. -template class ROB; +#include + +#include "base/logging.hh" +#include "cpu/o3/dyn_inst.hh" +#include "cpu/o3/limits.hh" +#include "debug/Fetch.hh" +#include "debug/ROB.hh" +#include "params/DerivO3CPU.hh" + +ROB::ROB(FullO3CPU *_cpu, const DerivO3CPUParams ¶ms) + : robPolicy(params.smtROBPolicy), + cpu(_cpu), + numEntries(params.numROBEntries), + squashWidth(params.squashWidth), + numInstsInROB(0), + numThreads(params.numThreads), + stats(_cpu) +{ + //Figure out rob policy + if (robPolicy == SMTQueuePolicy::Dynamic) { + //Set Max Entries to Total ROB Capacity + for (ThreadID tid = 0; tid < numThreads; tid++) { + maxEntries[tid] = numEntries; + } + + } else if (robPolicy == SMTQueuePolicy::Partitioned) { + DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n"); + + //@todo:make work if part_amt doesnt divide evenly. + int part_amt = numEntries / numThreads; + + //Divide ROB up evenly + for (ThreadID tid = 0; tid < numThreads; tid++) { + maxEntries[tid] = part_amt; + } + + } else if (robPolicy == SMTQueuePolicy::Threshold) { + DPRINTF(Fetch, "ROB sharing policy set to Threshold\n"); + + int threshold = params.smtROBThreshold;; + + //Divide up by threshold amount + for (ThreadID tid = 0; tid < numThreads; tid++) { + maxEntries[tid] = threshold; + } + } + + for (ThreadID tid = numThreads; tid < O3MaxThreads; tid++) { + maxEntries[tid] = 0; + } + + resetState(); +} + +void +ROB::resetState() +{ + for (ThreadID tid = 0; tid < O3MaxThreads; tid++) { + threadEntries[tid] = 0; + squashIt[tid] = instList[tid].end(); + squashedSeqNum[tid] = 0; + doneSquashing[tid] = true; + } + numInstsInROB = 0; + + // Initialize the "universal" ROB head & tail point to invalid + // pointers + head = instList[0].end(); + tail = instList[0].end(); +} + +std::string +ROB::name() const +{ + return cpu->name() + ".rob"; +} + +void +ROB::setActiveThreads(std::list *at_ptr) +{ + DPRINTF(ROB, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +void +ROB::drainSanityCheck() const +{ + for (ThreadID tid = 0; tid < numThreads; tid++) + assert(instList[tid].empty()); + assert(isEmpty()); +} + +void +ROB::takeOverFrom() +{ + resetState(); +} + +void +ROB::resetEntries() +{ + if (robPolicy != SMTQueuePolicy::Dynamic || numThreads > 1) { + auto active_threads = activeThreads->size(); + + std::list::iterator threads = activeThreads->begin(); + std::list::iterator end = activeThreads->end(); + + while (threads != end) { + ThreadID tid = *threads++; + + if (robPolicy == SMTQueuePolicy::Partitioned) { + maxEntries[tid] = numEntries / active_threads; + } else if (robPolicy == SMTQueuePolicy::Threshold && + active_threads == 1) { + maxEntries[tid] = numEntries; + } + } + } +} + +int +ROB::entryAmount(ThreadID num_threads) +{ + if (robPolicy == SMTQueuePolicy::Partitioned) { + return numEntries / num_threads; + } else { + return 0; + } +} + +int +ROB::countInsts() +{ + int total = 0; + + for (ThreadID tid = 0; tid < numThreads; tid++) + total += countInsts(tid); + + return total; +} + +size_t +ROB::countInsts(ThreadID tid) +{ + return instList[tid].size(); +} + +void +ROB::insertInst(const O3DynInstPtr &inst) +{ + assert(inst); + + stats.writes++; + + DPRINTF(ROB, "Adding inst PC %s to the ROB.\n", inst->pcState()); + + assert(numInstsInROB != numEntries); + + ThreadID tid = inst->threadNumber; + + instList[tid].push_back(inst); + + //Set Up head iterator if this is the 1st instruction in the ROB + if (numInstsInROB == 0) { + head = instList[tid].begin(); + assert((*head) == inst); + } + + //Must Decrement for iterator to actually be valid since __.end() + //actually points to 1 after the last inst + tail = instList[tid].end(); + tail--; + + inst->setInROB(); + + ++numInstsInROB; + ++threadEntries[tid]; + + assert((*tail) == inst); + + DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, + threadEntries[tid]); +} + +void +ROB::retireHead(ThreadID tid) +{ + stats.writes++; + + assert(numInstsInROB > 0); + + // Get the head ROB instruction by copying it and remove it from the list + InstIt head_it = instList[tid].begin(); + + O3DynInstPtr head_inst = std::move(*head_it); + instList[tid].erase(head_it); + + assert(head_inst->readyToCommit()); + + DPRINTF(ROB, "[tid:%i] Retiring head instruction, " + "instruction PC %s, [sn:%llu]\n", tid, head_inst->pcState(), + head_inst->seqNum); + + --numInstsInROB; + --threadEntries[tid]; + + head_inst->clearInROB(); + head_inst->setCommitted(); + + //Update "Global" Head of ROB + updateHead(); + + // @todo: A special case is needed if the instruction being + // retired is the only instruction in the ROB; otherwise the tail + // iterator will become invalidated. + cpu->removeFrontInst(head_inst); +} + +bool +ROB::isHeadReady(ThreadID tid) +{ + stats.reads++; + if (threadEntries[tid] != 0) { + return instList[tid].front()->readyToCommit(); + } + + return false; +} + +bool +ROB::canCommit() +{ + //@todo: set ActiveThreads through ROB or CPU + std::list::iterator threads = activeThreads->begin(); + std::list::iterator end = activeThreads->end(); + + while (threads != end) { + ThreadID tid = *threads++; + + if (isHeadReady(tid)) { + return true; + } + } + + return false; +} + +unsigned +ROB::numFreeEntries() +{ + return numEntries - numInstsInROB; +} + +unsigned +ROB::numFreeEntries(ThreadID tid) +{ + return maxEntries[tid] - threadEntries[tid]; +} + +void +ROB::doSquash(ThreadID tid) +{ + stats.writes++; + DPRINTF(ROB, "[tid:%i] Squashing instructions until [sn:%llu].\n", + tid, squashedSeqNum[tid]); + + assert(squashIt[tid] != instList[tid].end()); + + if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) { + DPRINTF(ROB, "[tid:%i] Done squashing instructions.\n", + tid); + + squashIt[tid] = instList[tid].end(); + + doneSquashing[tid] = true; + return; + } + + bool robTailUpdate = false; + + unsigned int numInstsToSquash = squashWidth; + + // If the CPU is exiting, squash all of the instructions + // it is told to, even if that exceeds the squashWidth. + // Set the number to the number of entries (the max). + if (cpu->isThreadExiting(tid)) + { + numInstsToSquash = numEntries; + } + + for (int numSquashed = 0; + numSquashed < numInstsToSquash && + squashIt[tid] != instList[tid].end() && + (*squashIt[tid])->seqNum > squashedSeqNum[tid]; + ++numSquashed) + { + DPRINTF(ROB, "[tid:%i] Squashing instruction PC %s, seq num %i.\n", + (*squashIt[tid])->threadNumber, + (*squashIt[tid])->pcState(), + (*squashIt[tid])->seqNum); + + // Mark the instruction as squashed, and ready to commit so that + // it can drain out of the pipeline. + (*squashIt[tid])->setSquashed(); + + (*squashIt[tid])->setCanCommit(); + + + if (squashIt[tid] == instList[tid].begin()) { + DPRINTF(ROB, "Reached head of instruction list while " + "squashing.\n"); + + squashIt[tid] = instList[tid].end(); + + doneSquashing[tid] = true; + + return; + } + + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + if ((*squashIt[tid]) == (*tail_thread)) + robTailUpdate = true; + + squashIt[tid]--; + } + + + // Check if ROB is done squashing. + if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) { + DPRINTF(ROB, "[tid:%i] Done squashing instructions.\n", + tid); + + squashIt[tid] = instList[tid].end(); + + doneSquashing[tid] = true; + } + + if (robTailUpdate) { + updateTail(); + } +} + + +void +ROB::updateHead() +{ + InstSeqNum lowest_num = 0; + bool first_valid = true; + + // @todo: set ActiveThreads through ROB or CPU + std::list::iterator threads = activeThreads->begin(); + std::list::iterator end = activeThreads->end(); + + while (threads != end) { + ThreadID tid = *threads++; + + if (instList[tid].empty()) + continue; + + if (first_valid) { + head = instList[tid].begin(); + lowest_num = (*head)->seqNum; + first_valid = false; + continue; + } + + InstIt head_thread = instList[tid].begin(); + + O3DynInstPtr head_inst = (*head_thread); + + assert(head_inst != 0); + + if (head_inst->seqNum < lowest_num) { + head = head_thread; + lowest_num = head_inst->seqNum; + } + } + + if (first_valid) { + head = instList[0].end(); + } + +} + +void +ROB::updateTail() +{ + tail = instList[0].end(); + bool first_valid = true; + + std::list::iterator threads = activeThreads->begin(); + std::list::iterator end = activeThreads->end(); + + while (threads != end) { + ThreadID tid = *threads++; + + if (instList[tid].empty()) { + continue; + } + + // If this is the first valid then assign w/out + // comparison + if (first_valid) { + tail = instList[tid].end(); + tail--; + first_valid = false; + continue; + } + + // Assign new tail if this thread's tail is younger + // than our current "tail high" + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + if ((*tail_thread)->seqNum > (*tail)->seqNum) { + tail = tail_thread; + } + } +} + + +void +ROB::squash(InstSeqNum squash_num, ThreadID tid) +{ + if (isEmpty(tid)) { + DPRINTF(ROB, "Does not need to squash due to being empty " + "[sn:%llu]\n", + squash_num); + + return; + } + + DPRINTF(ROB, "Starting to squash within the ROB.\n"); + + robStatus[tid] = ROBSquashing; + + doneSquashing[tid] = false; + + squashedSeqNum[tid] = squash_num; + + if (!instList[tid].empty()) { + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + squashIt[tid] = tail_thread; + + doSquash(tid); + } +} + +const O3DynInstPtr& +ROB::readHeadInst(ThreadID tid) +{ + if (threadEntries[tid] != 0) { + InstIt head_thread = instList[tid].begin(); + + assert((*head_thread)->isInROB()); + + return *head_thread; + } else { + return dummyInst; + } +} + +O3DynInstPtr +ROB::readTailInst(ThreadID tid) +{ + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + return *tail_thread; +} + +ROB::ROBStats::ROBStats(Stats::Group *parent) + : Stats::Group(parent, "rob"), + ADD_STAT(reads, Stats::Units::Count::get(), "The number of ROB reads"), + ADD_STAT(writes, Stats::Units::Count::get(), "The number of ROB writes") +{ +} + +O3DynInstPtr +ROB::findInst(ThreadID tid, InstSeqNum squash_inst) +{ + for (InstIt it = instList[tid].begin(); it != instList[tid].end(); it++) { + if ((*it)->seqNum == squash_inst) { + return *it; + } + } + return NULL; +} diff --git a/src/cpu/o3/rob.hh b/src/cpu/o3/rob.hh index 155352a17d..b6270153ac 100644 --- a/src/cpu/o3/rob.hh +++ b/src/cpu/o3/rob.hh @@ -45,16 +45,24 @@ #include #include +#include "base/statistics.hh" #include "base/types.hh" +#include "config/the_isa.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/dyn_inst_ptr.hh" +#include "cpu/o3/impl.hh" #include "cpu/o3/limits.hh" +#include "cpu/reg_class.hh" #include "enums/SMTQueuePolicy.hh" +template +class FullO3CPU; + struct DerivO3CPUParams; /** * ROB class. The ROB is largely what drives squashing. */ -template class ROB { public: @@ -81,7 +89,7 @@ class ROB * @param _cpu The cpu object pointer. * @param params The cpu params including several ROB-specific parameters. */ - ROB(FullO3CPU *_cpu, const DerivO3CPUParams ¶ms); + ROB(FullO3CPU *_cpu, const DerivO3CPUParams ¶ms); std::string name() const; @@ -258,7 +266,7 @@ class ROB void resetState(); /** Pointer to the CPU. */ - FullO3CPU *cpu; + FullO3CPU *cpu; /** Active Threads in CPU */ std::list *activeThreads; diff --git a/src/cpu/o3/rob_impl.hh b/src/cpu/o3/rob_impl.hh deleted file mode 100644 index c48484c091..0000000000 --- a/src/cpu/o3/rob_impl.hh +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (c) 2012 ARM Limited - * All rights reserved - * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ROB_IMPL_HH__ -#define __CPU_O3_ROB_IMPL_HH__ - -#include - -#include "base/logging.hh" -#include "cpu/o3/limits.hh" -#include "cpu/o3/rob.hh" -#include "debug/Fetch.hh" -#include "debug/ROB.hh" -#include "params/DerivO3CPU.hh" - -template -ROB::ROB(FullO3CPU *_cpu, const DerivO3CPUParams ¶ms) - : robPolicy(params.smtROBPolicy), - cpu(_cpu), - numEntries(params.numROBEntries), - squashWidth(params.squashWidth), - numInstsInROB(0), - numThreads(params.numThreads), - stats(_cpu) -{ - //Figure out rob policy - if (robPolicy == SMTQueuePolicy::Dynamic) { - //Set Max Entries to Total ROB Capacity - for (ThreadID tid = 0; tid < numThreads; tid++) { - maxEntries[tid] = numEntries; - } - - } else if (robPolicy == SMTQueuePolicy::Partitioned) { - DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n"); - - //@todo:make work if part_amt doesnt divide evenly. - int part_amt = numEntries / numThreads; - - //Divide ROB up evenly - for (ThreadID tid = 0; tid < numThreads; tid++) { - maxEntries[tid] = part_amt; - } - - } else if (robPolicy == SMTQueuePolicy::Threshold) { - DPRINTF(Fetch, "ROB sharing policy set to Threshold\n"); - - int threshold = params.smtROBThreshold;; - - //Divide up by threshold amount - for (ThreadID tid = 0; tid < numThreads; tid++) { - maxEntries[tid] = threshold; - } - } - - for (ThreadID tid = numThreads; tid < O3MaxThreads; tid++) { - maxEntries[tid] = 0; - } - - resetState(); -} - -template -void -ROB::resetState() -{ - for (ThreadID tid = 0; tid < O3MaxThreads; tid++) { - threadEntries[tid] = 0; - squashIt[tid] = instList[tid].end(); - squashedSeqNum[tid] = 0; - doneSquashing[tid] = true; - } - numInstsInROB = 0; - - // Initialize the "universal" ROB head & tail point to invalid - // pointers - head = instList[0].end(); - tail = instList[0].end(); -} - -template -std::string -ROB::name() const -{ - return cpu->name() + ".rob"; -} - -template -void -ROB::setActiveThreads(std::list *at_ptr) -{ - DPRINTF(ROB, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template -void -ROB::drainSanityCheck() const -{ - for (ThreadID tid = 0; tid < numThreads; tid++) - assert(instList[tid].empty()); - assert(isEmpty()); -} - -template -void -ROB::takeOverFrom() -{ - resetState(); -} - -template -void -ROB::resetEntries() -{ - if (robPolicy != SMTQueuePolicy::Dynamic || numThreads > 1) { - auto active_threads = activeThreads->size(); - - std::list::iterator threads = activeThreads->begin(); - std::list::iterator end = activeThreads->end(); - - while (threads != end) { - ThreadID tid = *threads++; - - if (robPolicy == SMTQueuePolicy::Partitioned) { - maxEntries[tid] = numEntries / active_threads; - } else if (robPolicy == SMTQueuePolicy::Threshold && - active_threads == 1) { - maxEntries[tid] = numEntries; - } - } - } -} - -template -int -ROB::entryAmount(ThreadID num_threads) -{ - if (robPolicy == SMTQueuePolicy::Partitioned) { - return numEntries / num_threads; - } else { - return 0; - } -} - -template -int -ROB::countInsts() -{ - int total = 0; - - for (ThreadID tid = 0; tid < numThreads; tid++) - total += countInsts(tid); - - return total; -} - -template -size_t -ROB::countInsts(ThreadID tid) -{ - return instList[tid].size(); -} - -template -void -ROB::insertInst(const O3DynInstPtr &inst) -{ - assert(inst); - - stats.writes++; - - DPRINTF(ROB, "Adding inst PC %s to the ROB.\n", inst->pcState()); - - assert(numInstsInROB != numEntries); - - ThreadID tid = inst->threadNumber; - - instList[tid].push_back(inst); - - //Set Up head iterator if this is the 1st instruction in the ROB - if (numInstsInROB == 0) { - head = instList[tid].begin(); - assert((*head) == inst); - } - - //Must Decrement for iterator to actually be valid since __.end() - //actually points to 1 after the last inst - tail = instList[tid].end(); - tail--; - - inst->setInROB(); - - ++numInstsInROB; - ++threadEntries[tid]; - - assert((*tail) == inst); - - DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]); -} - -template -void -ROB::retireHead(ThreadID tid) -{ - stats.writes++; - - assert(numInstsInROB > 0); - - // Get the head ROB instruction by copying it and remove it from the list - InstIt head_it = instList[tid].begin(); - - O3DynInstPtr head_inst = std::move(*head_it); - instList[tid].erase(head_it); - - assert(head_inst->readyToCommit()); - - DPRINTF(ROB, "[tid:%i] Retiring head instruction, " - "instruction PC %s, [sn:%llu]\n", tid, head_inst->pcState(), - head_inst->seqNum); - - --numInstsInROB; - --threadEntries[tid]; - - head_inst->clearInROB(); - head_inst->setCommitted(); - - //Update "Global" Head of ROB - updateHead(); - - // @todo: A special case is needed if the instruction being - // retired is the only instruction in the ROB; otherwise the tail - // iterator will become invalidated. - cpu->removeFrontInst(head_inst); -} - -template -bool -ROB::isHeadReady(ThreadID tid) -{ - stats.reads++; - if (threadEntries[tid] != 0) { - return instList[tid].front()->readyToCommit(); - } - - return false; -} - -template -bool -ROB::canCommit() -{ - //@todo: set ActiveThreads through ROB or CPU - std::list::iterator threads = activeThreads->begin(); - std::list::iterator end = activeThreads->end(); - - while (threads != end) { - ThreadID tid = *threads++; - - if (isHeadReady(tid)) { - return true; - } - } - - return false; -} - -template -unsigned -ROB::numFreeEntries() -{ - return numEntries - numInstsInROB; -} - -template -unsigned -ROB::numFreeEntries(ThreadID tid) -{ - return maxEntries[tid] - threadEntries[tid]; -} - -template -void -ROB::doSquash(ThreadID tid) -{ - stats.writes++; - DPRINTF(ROB, "[tid:%i] Squashing instructions until [sn:%llu].\n", - tid, squashedSeqNum[tid]); - - assert(squashIt[tid] != instList[tid].end()); - - if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) { - DPRINTF(ROB, "[tid:%i] Done squashing instructions.\n", - tid); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - return; - } - - bool robTailUpdate = false; - - unsigned int numInstsToSquash = squashWidth; - - // If the CPU is exiting, squash all of the instructions - // it is told to, even if that exceeds the squashWidth. - // Set the number to the number of entries (the max). - if (cpu->isThreadExiting(tid)) - { - numInstsToSquash = numEntries; - } - - for (int numSquashed = 0; - numSquashed < numInstsToSquash && - squashIt[tid] != instList[tid].end() && - (*squashIt[tid])->seqNum > squashedSeqNum[tid]; - ++numSquashed) - { - DPRINTF(ROB, "[tid:%i] Squashing instruction PC %s, seq num %i.\n", - (*squashIt[tid])->threadNumber, - (*squashIt[tid])->pcState(), - (*squashIt[tid])->seqNum); - - // Mark the instruction as squashed, and ready to commit so that - // it can drain out of the pipeline. - (*squashIt[tid])->setSquashed(); - - (*squashIt[tid])->setCanCommit(); - - - if (squashIt[tid] == instList[tid].begin()) { - DPRINTF(ROB, "Reached head of instruction list while " - "squashing.\n"); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - - return; - } - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - if ((*squashIt[tid]) == (*tail_thread)) - robTailUpdate = true; - - squashIt[tid]--; - } - - - // Check if ROB is done squashing. - if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) { - DPRINTF(ROB, "[tid:%i] Done squashing instructions.\n", - tid); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - } - - if (robTailUpdate) { - updateTail(); - } -} - - -template -void -ROB::updateHead() -{ - InstSeqNum lowest_num = 0; - bool first_valid = true; - - // @todo: set ActiveThreads through ROB or CPU - std::list::iterator threads = activeThreads->begin(); - std::list::iterator end = activeThreads->end(); - - while (threads != end) { - ThreadID tid = *threads++; - - if (instList[tid].empty()) - continue; - - if (first_valid) { - head = instList[tid].begin(); - lowest_num = (*head)->seqNum; - first_valid = false; - continue; - } - - InstIt head_thread = instList[tid].begin(); - - O3DynInstPtr head_inst = (*head_thread); - - assert(head_inst != 0); - - if (head_inst->seqNum < lowest_num) { - head = head_thread; - lowest_num = head_inst->seqNum; - } - } - - if (first_valid) { - head = instList[0].end(); - } - -} - -template -void -ROB::updateTail() -{ - tail = instList[0].end(); - bool first_valid = true; - - std::list::iterator threads = activeThreads->begin(); - std::list::iterator end = activeThreads->end(); - - while (threads != end) { - ThreadID tid = *threads++; - - if (instList[tid].empty()) { - continue; - } - - // If this is the first valid then assign w/out - // comparison - if (first_valid) { - tail = instList[tid].end(); - tail--; - first_valid = false; - continue; - } - - // Assign new tail if this thread's tail is younger - // than our current "tail high" - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - if ((*tail_thread)->seqNum > (*tail)->seqNum) { - tail = tail_thread; - } - } -} - - -template -void -ROB::squash(InstSeqNum squash_num, ThreadID tid) -{ - if (isEmpty(tid)) { - DPRINTF(ROB, "Does not need to squash due to being empty " - "[sn:%llu]\n", - squash_num); - - return; - } - - DPRINTF(ROB, "Starting to squash within the ROB.\n"); - - robStatus[tid] = ROBSquashing; - - doneSquashing[tid] = false; - - squashedSeqNum[tid] = squash_num; - - if (!instList[tid].empty()) { - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - squashIt[tid] = tail_thread; - - doSquash(tid); - } -} - -template -const O3DynInstPtr& -ROB::readHeadInst(ThreadID tid) -{ - if (threadEntries[tid] != 0) { - InstIt head_thread = instList[tid].begin(); - - assert((*head_thread)->isInROB()); - - return *head_thread; - } else { - return dummyInst; - } -} - -template -O3DynInstPtr -ROB::readTailInst(ThreadID tid) -{ - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return *tail_thread; -} - -template -ROB::ROBStats::ROBStats(Stats::Group *parent) - : Stats::Group(parent, "rob"), - ADD_STAT(reads, Stats::Units::Count::get(), "The number of ROB reads"), - ADD_STAT(writes, Stats::Units::Count::get(), "The number of ROB writes") -{ -} - -template -O3DynInstPtr -ROB::findInst(ThreadID tid, InstSeqNum squash_inst) -{ - for (InstIt it = instList[tid].begin(); it != instList[tid].end(); it++) { - if ((*it)->seqNum == squash_inst) { - return *it; - } - } - return NULL; -} - -#endif//__CPU_O3_ROB_IMPL_HH__