Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/42106 )
Change subject: cpu: De-templatize the O3 ROB.
......................................................................
cpu: De-templatize the O3 ROB.
Change-Id: I257d2a71be5d4254437d84a5bfa59e2e8dc6420a
---
M src/cpu/o3/commit.hh
M src/cpu/o3/commit_impl.hh
M src/cpu/o3/cpu.hh
M src/cpu/o3/rob.cc
M src/cpu/o3/rob.hh
D src/cpu/o3/rob_impl.hh
6 files changed, 513 insertions(+), 572 deletions(-)
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index 35223d6..227feb8 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -166,7 +166,7 @@
void setRenameMap(UnifiedRenameMap rm_ptr[O3MaxThreads]);
/** Sets pointer to the ROB. */
- void setROB(ROB<Impl> *rob_ptr);
+ void setROB(ROB *rob_ptr);
/** Initializes stage by sending back the number of free entries. */
void startupStage();
@@ -345,7 +345,7 @@
public:
/** ROB interface. */
- ROB<Impl> *rob;
+ ROB *rob;
private:
/** Pointer to O3CPU. */
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index 8e73e39..1781416 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -318,7 +318,7 @@
template <class Impl>
void
-DefaultCommit<Impl>::setROB(ROB<Impl> *rob_ptr)
+DefaultCommit<Impl>::setROB(ROB *rob_ptr)
{
rob = rob_ptr;
}
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index f1f2a17..879dc81 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -572,7 +572,7 @@
UnifiedRenameMap commitRenameMap[O3MaxThreads];
/** The re-order buffer. */
- ROB<Impl> rob;
+ ROB rob;
/** Active Threads List */
std::list<ThreadID> activeThreads;
diff --git a/src/cpu/o3/rob.cc b/src/cpu/o3/rob.cc
index 6f1af96..5418dcf 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<O3CPUImpl>;
+#include <list>
+
+#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<O3CPUImpl> *_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<ThreadID> *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<ThreadID>::iterator threads = activeThreads->begin();
+ std::list<ThreadID>::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<ThreadID>::iterator threads = activeThreads->begin();
+ std::list<ThreadID>::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<ThreadID>::iterator threads = activeThreads->begin();
+ std::list<ThreadID>::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<ThreadID>::iterator threads = activeThreads->begin();
+ std::list<ThreadID>::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, UNIT_COUNT, "The number of ROB reads"),
+ ADD_STAT(writes, UNIT_COUNT, "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 27a2f28..461f840 100644
--- a/src/cpu/o3/rob.hh
+++ b/src/cpu/o3/rob.hh
@@ -48,6 +48,7 @@
#include "arch/registers.hh"
#include "base/types.hh"
#include "config/the_isa.hh"
+#include "cpu/o3/impl.hh"
#include "cpu/o3/limits.hh"
#include "enums/SMTQueuePolicy.hh"
@@ -56,7 +57,6 @@
/**
* ROB class. The ROB is largely what drives squashing.
*/
-template <class Impl>
class ROB
{
public:
@@ -82,7 +82,7 @@
* @param _cpu The cpu object pointer.
* @param params The cpu params including several ROB-specific
parameters.
*/
- ROB(FullO3CPU<Impl> *_cpu, const DerivO3CPUParams ¶ms);
+ ROB(FullO3CPU<O3CPUImpl> *_cpu, const DerivO3CPUParams ¶ms);
std::string name() const;
@@ -259,7 +259,7 @@
void resetState();
/** Pointer to the CPU. */
- FullO3CPU<Impl> *cpu;
+ FullO3CPU<O3CPUImpl> *cpu;
/** Active Threads in CPU */
std::list<ThreadID> *activeThreads;
diff --git a/src/cpu/o3/rob_impl.hh b/src/cpu/o3/rob_impl.hh
deleted file mode 100644
index 24f283a..0000000
--- 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 <list>
-
-#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 <class Impl>
-ROB<Impl>::ROB(FullO3CPU<Impl> *_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 <class Impl>
-void
-ROB<Impl>::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 <class Impl>
-std::string
-ROB<Impl>::name() const
-{
- return cpu->name() + ".rob";
-}
-
-template <class Impl>
-void
-ROB<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr)
-{
- DPRINTF(ROB, "Setting active threads list pointer.\n");
- activeThreads = at_ptr;
-}
-
-template <class Impl>
-void
-ROB<Impl>::drainSanityCheck() const
-{
- for (ThreadID tid = 0; tid < numThreads; tid++)
- assert(instList[tid].empty());
- assert(isEmpty());
-}
-
-template <class Impl>
-void
-ROB<Impl>::takeOverFrom()
-{
- resetState();
-}
-
-template <class Impl>
-void
-ROB<Impl>::resetEntries()
-{
- if (robPolicy != SMTQueuePolicy::Dynamic || numThreads > 1) {
- auto active_threads = activeThreads->size();
-
- std::list<ThreadID>::iterator threads = activeThreads->begin();
- std::list<ThreadID>::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 <class Impl>
-int
-ROB<Impl>::entryAmount(ThreadID num_threads)
-{
- if (robPolicy == SMTQueuePolicy::Partitioned) {
- return numEntries / num_threads;
- } else {
- return 0;
- }
-}
-
-template <class Impl>
-int
-ROB<Impl>::countInsts()
-{
- int total = 0;
-
- for (ThreadID tid = 0; tid < numThreads; tid++)
- total += countInsts(tid);
-
- return total;
-}
-
-template <class Impl>
-size_t
-ROB<Impl>::countInsts(ThreadID tid)
-{
- return instList[tid].size();
-}
-
-template <class Impl>
-void
-ROB<Impl>::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 <class Impl>
-void
-ROB<Impl>::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 <class Impl>
-bool
-ROB<Impl>::isHeadReady(ThreadID tid)
-{
- stats.reads++;
- if (threadEntries[tid] != 0) {
- return instList[tid].front()->readyToCommit();
- }
-
- return false;
-}
-
-template <class Impl>
-bool
-ROB<Impl>::canCommit()
-{
- //@todo: set ActiveThreads through ROB or CPU
- std::list<ThreadID>::iterator threads = activeThreads->begin();
- std::list<ThreadID>::iterator end = activeThreads->end();
-
- while (threads != end) {
- ThreadID tid = *threads++;
-
- if (isHeadReady(tid)) {
- return true;
- }
- }
-
- return false;
-}
-
-template <class Impl>
-unsigned
-ROB<Impl>::numFreeEntries()
-{
- return numEntries - numInstsInROB;
-}
-
-template <class Impl>
-unsigned
-ROB<Impl>::numFreeEntries(ThreadID tid)
-{
- return maxEntries[tid] - threadEntries[tid];
-}
-
-template <class Impl>
-void
-ROB<Impl>::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 <class Impl>
-void
-ROB<Impl>::updateHead()
-{
- InstSeqNum lowest_num = 0;
- bool first_valid = true;
-
- // @todo: set ActiveThreads through ROB or CPU
- std::list<ThreadID>::iterator threads = activeThreads->begin();
- std::list<ThreadID>::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 <class Impl>
-void
-ROB<Impl>::updateTail()
-{
- tail = instList[0].end();
- bool first_valid = true;
-
- std::list<ThreadID>::iterator threads = activeThreads->begin();
- std::list<ThreadID>::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 <class Impl>
-void
-ROB<Impl>::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 <class Impl>
-const O3DynInstPtr&
-ROB<Impl>::readHeadInst(ThreadID tid)
-{
- if (threadEntries[tid] != 0) {
- InstIt head_thread = instList[tid].begin();
-
- assert((*head_thread)->isInROB());
-
- return *head_thread;
- } else {
- return dummyInst;
- }
-}
-
-template <class Impl>
-O3DynInstPtr
-ROB<Impl>::readTailInst(ThreadID tid)
-{
- InstIt tail_thread = instList[tid].end();
- tail_thread--;
-
- return *tail_thread;
-}
-
-template <class Impl>
-ROB<Impl>::ROBStats::ROBStats(Stats::Group *parent)
- : Stats::Group(parent, "rob"),
- ADD_STAT(reads, UNIT_COUNT, "The number of ROB reads"),
- ADD_STAT(writes, UNIT_COUNT, "The number of ROB writes")
-{
-}
-
-template <class Impl>
-O3DynInstPtr
-ROB<Impl>::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__
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/42106
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I257d2a71be5d4254437d84a5bfa59e2e8dc6420a
Gerrit-Change-Number: 42106
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s