2c2
< * Copyright (c) 2004-2005 The Regents of The University of Michigan
---
> * Copyright (c) 2004-2006 The Regents of The University of Michigan
31,33d30
< #ifndef __CPU_O3_CPU_ROB_IMPL_HH__
< #define __CPU_O3_CPU_ROB_IMPL_HH__
<
36a34,35
> using namespace std;
>
38c37,39
< ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth)
---
> ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
> string _smtROBPolicy, unsigned _smtROBThreshold,
> unsigned _numThreads)
42c43,44
< squashedSeqNum(0)
---
> squashedSeqNum(0),
> numThreads(_numThreads)
44c46,91
< doneSquashing = true;
---
> for (int tid=0; tid < numThreads; tid++) {
> doneSquashing[tid] = true;
> threadEntries[tid] = 0;
> }
>
> string policy = _smtROBPolicy;
>
> //Convert string to lowercase
> std::transform(policy.begin(), policy.end(), policy.begin(),
> (int(*)(int)) tolower);
>
> //Figure out rob policy
> if (policy == "dynamic") {
> robPolicy = Dynamic;
>
> //Set Max Entries to Total ROB Capacity
> for (int i = 0; i < numThreads; i++) {
> maxEntries[i]=numEntries;
> }
>
> } else if (policy == "partitioned") {
> robPolicy = 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 (int i = 0; i < numThreads; i++) {
> maxEntries[i]=part_amt;
> }
>
> } else if (policy == "threshold") {
> robPolicy = Threshold;
> DPRINTF(Fetch, "ROB sharing policy set to Threshold\n");
>
> int threshold = _smtROBThreshold;;
>
> //Divide up by threshold amount
> for (int i = 0; i < numThreads; i++) {
> maxEntries[i]=threshold;
> }
> } else {
> assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic,"
> "Partitioned, Threshold}");
> }
47a95,101
> std::string
> ROB<Impl>::name() const
> {
> return cpu->name() + ".rob";
> }
>
> template <class Impl>
53,56c107,110
< // Set the tail to the beginning of the CPU instruction list so that
< // upon the first instruction being inserted into the ROB, the tail
< // iterator can simply be incremented.
< tail = cpu->instList.begin();
---
> // Set the per-thread iterators to the end of the instruction list.
> for (int i=0; i < numThreads;i++) {
> squashIt[i] = instList[i].end();
> }
58,59c112,115
< // Set the squash iterator to the end of the instruction list.
< squashIt = cpu->instList.end();
---
> // Initialize the "universal" ROB head & tail point to invalid
> // pointers
> head = instList[0].end();
> tail = instList[0].end();
63,64c119,120
< int
< ROB<Impl>::countInsts()
---
> void
> ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr)
66,68c122,124
< // Start at 1; if the tail matches cpu->instList.begin(), then there is
< // one inst in the ROB.
< int return_val = 1;
---
> DPRINTF(ROB, "Setting active threads list pointer.\n");
> activeThreads = at_ptr;
> }
70,79c126,131
< // There are quite a few special cases. Do not use this function other
< // than for debugging purposes.
< if (cpu->instList.begin() == cpu->instList.end()) {
< // In this case there are no instructions in the list. The ROB
< // must be empty.
< return 0;
< } else if (tail == cpu->instList.end()) {
< // In this case, the tail is not yet pointing to anything valid.
< // The ROB must be empty.
< return 0;
---
> template <class Impl>
> void
> ROB<Impl>::switchOut()
> {
> for (int tid = 0; tid < numThreads; tid++) {
> instList[tid].clear();
80a133
> }
82,87c135,142
< // Iterate through the ROB from the head to the tail, counting the
< // entries.
< for (InstIt_t i = cpu->instList.begin(); i != tail; ++i)
< {
< assert(i != cpu->instList.end());
< ++return_val;
---
> template <class Impl>
> void
> ROB<Impl>::takeOverFrom()
> {
> for (int tid=0; tid < numThreads; tid++) {
> doneSquashing[tid] = true;
> threadEntries[tid] = 0;
> squashIt[tid] = instList[tid].end();
88a144
> numInstsInROB = 0;
90c146,150
< return return_val;
---
> // Initialize the "universal" ROB head & tail point to invalid
> // pointers
> head = instList[0].end();
> tail = instList[0].end();
> }
92,95c152,169
< // 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 <class Impl>
> void
> ROB<Impl>::resetEntries()
> {
> if (robPolicy != Dynamic || numThreads > 1) {
> int active_threads = (*activeThreads).size();
>
> list<unsigned>::iterator threads = (*activeThreads).begin();
> list<unsigned>::iterator list_end = (*activeThreads).end();
>
> while (threads != list_end) {
> if (robPolicy == Partitioned) {
> maxEntries[*threads++] = numEntries / active_threads;
> } else if (robPolicy == Threshold && active_threads == 1) {
> maxEntries[*threads++] = numEntries;
> }
> }
> }
98a173,202
> int
> ROB<Impl>::entryAmount(int num_threads)
> {
> if (robPolicy == Partitioned) {
> return numEntries / num_threads;
> } else {
> return 0;
> }
> }
>
> template <class Impl>
> int
> ROB<Impl>::countInsts()
> {
> int total=0;
>
> for (int i=0;i < numThreads;i++)
> total += countInsts(i);
>
> return total;
> }
>
> template <class Impl>
> int
> ROB<Impl>::countInsts(unsigned tid)
> {
> return instList[tid].size();
> }
>
> template <class Impl>
102,104c206
< // Make sure we have the right number of instructions.
< assert(numInstsInROB == countInsts());
< // Make sure the instruction is valid.
---
> //assert(numInstsInROB == countInsts());
107c209
< DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC());
---
> DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC());
109d210
< // If the ROB is full then exit.
112c213
< ++numInstsInROB;
---
> int tid = inst->threadNumber;
114,121c215,220
< // 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();
---
> 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);
124,126c223,226
< // Make sure the tail iterator is actually pointing at the instruction
< // added.
< assert((*tail) == inst);
---
> //Must Decrement for iterator to actually be valid since __.end()
> //actually points to 1 after the last inst
> tail = instList[tid].end();
> tail--;
128c228
< DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB);
---
> inst->setInROB();
129a230,235
> ++numInstsInROB;
> ++threadEntries[tid];
>
> assert((*tail) == inst);
>
> DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]);
133a240
> /*
138c245
< assert(numInstsInROB == countInsts());
---
> //assert(numInstsInROB == countInsts());
140a248,264
> int tid = (*head)->threadNumber;
>
> retireHead(tid);
>
> if (numInstsInROB == 0) {
> tail = instList[tid].end();
> }
> }
> */
>
> template <class Impl>
> void
> ROB<Impl>::retireHead(unsigned tid)
> {
> //assert(numInstsInROB == countInsts());
> assert(numInstsInROB > 0);
>
142c266
< DynInstPtr head_inst = cpu->instList.front();
---
> InstIt head_it = instList[tid].begin();
144c268,269
< // Make certain this can retire.
---
> DynInstPtr head_inst = (*head_it);
>
147,148c272,273
< DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, "
< "instruction PC %#x, seq num %i\n", head_inst->readPC(),
---
> DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
> "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(),
151d275
< // Keep track of how many instructions are in the ROB.
152a277
> --threadEntries[tid];
154,157c279,289
< // 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.
---
> head_inst->removeInROB();
> head_inst->setCommitted();
>
> instList[tid].erase(head_it);
>
> //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.
158a291,299
> }
> /*
> template <class Impl>
> bool
> ROB<Impl>::isHeadReady()
> {
> if (numInstsInROB != 0) {
> return (*head)->readyToCommit();
> }
160,161c301,309
< if (numInstsInROB == 0) {
< tail = cpu->instList.end();
---
> return false;
> }
> */
> template <class Impl>
> bool
> ROB<Impl>::isHeadReady(unsigned tid)
> {
> if (threadEntries[tid] != 0) {
> return instList[tid].front()->readyToCommit();
162a311,312
>
> return false;
167c317
< ROB<Impl>::isHeadReady()
---
> ROB<Impl>::canCommit()
169,170c319,327
< if (numInstsInROB != 0) {
< return cpu->instList.front()->readyToCommit();
---
> //@todo: set ActiveThreads through ROB or CPU
> list<unsigned>::iterator threads = (*activeThreads).begin();
>
> while (threads != (*activeThreads).end()) {
> unsigned tid = *threads++;
>
> if (isHeadReady(tid)) {
> return true;
> }
180c337
< assert(numInstsInROB == countInsts());
---
> //assert(numInstsInROB == countInsts());
185a343,349
> unsigned
> ROB<Impl>::numFreeEntries(unsigned tid)
> {
> return maxEntries[tid] - threadEntries[tid];
> }
>
> template <class Impl>
187c351
< ROB<Impl>::doSquash()
---
> ROB<Impl>::doSquash(unsigned tid)
189c353,354
< DPRINTF(ROB, "ROB: Squashing instructions.\n");
---
> DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
> tid, squashedSeqNum);
191c356
< assert(squashIt != cpu->instList.end());
---
> assert(squashIt[tid] != instList[tid].end());
192a358,369
> if ((*squashIt[tid])->seqNum < squashedSeqNum) {
> DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
> tid);
>
> squashIt[tid] = instList[tid].end();
>
> doneSquashing[tid] = true;
> return;
> }
>
> bool robTailUpdate = false;
>
194c371,373
< numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum;
---
> numSquashed < squashWidth &&
> squashIt[tid] != instList[tid].end() &&
> (*squashIt[tid])->seqNum > squashedSeqNum;
197,198c376,379
< // Ensure that the instruction is younger.
< assert((*squashIt)->seqNum > squashedSeqNum);
---
> DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
> (*squashIt[tid])->threadNumber,
> (*squashIt[tid])->readPC(),
> (*squashIt[tid])->seqNum);
200,202d380
< DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n",
< (*squashIt)->readPC(), (*squashIt)->seqNum);
<
205c383
< (*squashIt)->setSquashed();
---
> (*squashIt[tid])->setSquashed();
207c385
< (*squashIt)->setCanCommit();
---
> (*squashIt[tid])->setCanCommit();
209,217c387,389
< // Special case for when squashing due to a syscall. It's possible
< // that the squash happened after the head instruction was already
< // committed, meaning that (*squashIt)->seqNum != squashedSeqNum
< // will never be false. Normally the squash would never be able
< // to go past the head of the ROB; in this case it might, so it
< // must be handled otherwise it will segfault.
< #if !FULL_SYSTEM
< if (squashIt == cpu->instList.begin()) {
< DPRINTF(ROB, "ROB: Reached head of instruction list while "
---
>
> if (squashIt[tid] == instList[tid].begin()) {
> DPRINTF(ROB, "Reached head of instruction list while "
220c392
< squashIt = cpu->instList.end();
---
> squashIt[tid] = instList[tid].end();
222c394
< doneSquashing = true;
---
> doneSquashing[tid] = true;
226d397
< #endif
228,229c399,405
< // Move the tail iterator to the next instruction.
< squashIt--;
---
> InstIt tail_thread = instList[tid].end();
> tail_thread--;
>
> if ((*squashIt[tid]) == (*tail_thread))
> robTailUpdate = true;
>
> squashIt[tid]--;
234,235c410,412
< if ((*squashIt)->seqNum == squashedSeqNum) {
< DPRINTF(ROB, "ROB: Done squashing instructions.\n");
---
> if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
> DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
> tid);
237c414
< squashIt = cpu->instList.end();
---
> squashIt[tid] = instList[tid].end();
239c416
< doneSquashing = true;
---
> doneSquashing[tid] = true;
240a418,421
>
> if (robTailUpdate) {
> updateTail();
> }
242a424
>
245c427
< ROB<Impl>::squash(InstSeqNum squash_num)
---
> ROB<Impl>::updateHead()
247,248c429,431
< DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n");
< doneSquashing = false;
---
> DynInstPtr head_inst;
> InstSeqNum lowest_num = 0;
> bool first_valid = true;
249a433,521
> // @todo: set ActiveThreads through ROB or CPU
> list<unsigned>::iterator threads = (*activeThreads).begin();
>
> while (threads != (*activeThreads).end()) {
> unsigned thread_num = *threads++;
>
> if (instList[thread_num].empty())
> continue;
>
> if (first_valid) {
> head = instList[thread_num].begin();
> lowest_num = (*head)->seqNum;
> first_valid = false;
> continue;
> }
>
> InstIt head_thread = instList[thread_num].begin();
>
> DynInstPtr 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;
>
> list<unsigned>::iterator threads = (*activeThreads).begin();
>
> while (threads != (*activeThreads).end()) {
> unsigned 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,unsigned tid)
> {
> if (isEmpty()) {
> DPRINTF(ROB, "Does not need to squash due to being empty "
> "[sn:%i]\n",
> squash_num);
>
> return;
> }
>
> DPRINTF(ROB, "Starting to squash within the ROB.\n");
>
> robStatus[tid] = ROBSquashing;
>
> doneSquashing[tid] = false;
>
252c524,526
< assert(tail != cpu->instList.end());
---
> if (!instList[tid].empty()) {
> InstIt tail_thread = instList[tid].end();
> tail_thread--;
254c528
< squashIt = tail;
---
> squashIt[tid] = tail_thread;
256c530,531
< doSquash();
---
> doSquash(tid);
> }
257a533,551
> /*
> template <class Impl>
> typename Impl::DynInstPtr
> ROB<Impl>::readHeadInst()
> {
> if (numInstsInROB != 0) {
> assert((*head)->isInROB()==true);
> return *head;
> } else {
> return dummyInst;
> }
> }
> */
> template <class Impl>
> typename Impl::DynInstPtr
> ROB<Impl>::readHeadInst(unsigned tid)
> {
> if (threadEntries[tid] != 0) {
> InstIt head_thread = instList[tid].begin();
258a553,560
> assert((*head_thread)->isInROB()==true);
>
> return *head_thread;
> } else {
> return dummyInst;
> }
> }
> /*
263c565
< assert(numInstsInROB == countInsts());
---
> //assert(numInstsInROB == countInsts());
265c567
< DynInstPtr head_inst = cpu->instList.front();
---
> DynInstPtr head_inst = *head;
271a574,584
> ROB<Impl>::readHeadPC(unsigned tid)
> {
> //assert(numInstsInROB == countInsts());
> InstIt head_thread = instList[tid].begin();
>
> return (*head_thread)->readPC();
> }
>
>
> template <class Impl>
> uint64_t
274c587
< assert(numInstsInROB == countInsts());
---
> //assert(numInstsInROB == countInsts());
276c589
< DynInstPtr head_inst = cpu->instList.front();
---
> DynInstPtr head_inst = *head;
281a595,604
> uint64_t
> ROB<Impl>::readHeadNextPC(unsigned tid)
> {
> //assert(numInstsInROB == countInsts());
> InstIt head_thread = instList[tid].begin();
>
> return (*head_thread)->readNextPC();
> }
>
> template <class Impl>
285,288c608,609
< // Return the last sequence number that has not been squashed. Other
< // stages can use it to squash any instructions younger than the current
< // tail.
< DynInstPtr head_inst = cpu->instList.front();
---
> //assert(numInstsInROB == countInsts());
> DynInstPtr head_inst = *head;
293a615,646
> InstSeqNum
> ROB<Impl>::readHeadSeqNum(unsigned tid)
> {
> InstIt head_thread = instList[tid].begin();
>
> return ((*head_thread)->seqNum);
> }
>
> template <class Impl>
> typename Impl::DynInstPtr
> ROB<Impl>::readTailInst()
> {
> //assert(numInstsInROB == countInsts());
> //assert(tail != instList[0].end());
>
> return (*tail);
> }
> */
> template <class Impl>
> typename Impl::DynInstPtr
> ROB<Impl>::readTailInst(unsigned tid)
> {
> //assert(tail_thread[tid] != instList[tid].end());
>
> InstIt tail_thread = instList[tid].end();
> tail_thread--;
>
> return *tail_thread;
> }
>
> /*
> template <class Impl>
297c650
< assert(numInstsInROB == countInsts());
---
> //assert(numInstsInROB == countInsts());
299c652
< assert(tail != cpu->instList.end());
---
> //assert(tail != instList[0].end());
304a658,669
> uint64_t
> ROB<Impl>::readTailPC(unsigned tid)
> {
> //assert(tail_thread[tid] != instList[tid].end());
>
> InstIt tail_thread = instList[tid].end();
> tail_thread--;
>
> return (*tail_thread)->readPC();
> }
>
> template <class Impl>
314c679,693
< #endif // __CPU_O3_CPU_ROB_IMPL_HH__
---
> template <class Impl>
> InstSeqNum
> ROB<Impl>::readTailSeqNum(unsigned tid)
> {
> // Return the last sequence number that has not been squashed. Other
> // stages can use it to squash any instructions younger than the current
> // tail.
> // assert(tail_thread[tid] != instList[tid].end());
>
> InstIt tail_thread = instList[tid].end();
> tail_thread--;
>
> return (*tail_thread)->seqNum;
> }
> */