2c2
< * Copyright (c) 2004-2006 The Regents of The University of Michigan
---
> * Copyright (c) 2004-2005 The Regents of The University of Michigan
26a27,28
> *
> * Authors: Kevin Lim
28a31,33
> #ifndef __CPU_O3_CPU_ROB_IMPL_HH__
> #define __CPU_O3_CPU_ROB_IMPL_HH__
>
32,33d36
< using namespace std;
<
35,37c38
< ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
< string _smtROBPolicy, unsigned _smtROBThreshold,
< unsigned _numThreads)
---
> ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth)
41,42c42
< squashedSeqNum(0),
< numThreads(_numThreads)
---
> squashedSeqNum(0)
44,89c44
< 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}");
< }
---
> doneSquashing = true;
93,99d47
< std::string
< ROB<Impl>::name() const
< {
< return cpu->name() + ".rob";
< }
<
< template <class Impl>
105,108c53,56
< // Set the per-thread iterators to the end of the instruction list.
< for (int i=0; i < numThreads;i++) {
< squashIt[i] = instList[i].end();
< }
---
> // 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();
110,113c58,59
< // Initialize the "universal" ROB head & tail point to invalid
< // pointers
< head = instList[0].end();
< tail = instList[0].end();
---
> // Set the squash iterator to the end of the instruction list.
> squashIt = cpu->instList.end();
117,118c63,64
< void
< ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr)
---
> int
> ROB<Impl>::countInsts()
120,122c66,68
< DPRINTF(ROB, "Setting active threads list pointer.\n");
< activeThreads = at_ptr;
< }
---
> // Start at 1; if the tail matches cpu->instList.begin(), then there is
> // one inst in the ROB.
> int return_val = 1;
124,129c70,79
< template <class Impl>
< void
< ROB<Impl>::switchOut()
< {
< for (int tid = 0; tid < numThreads; tid++) {
< instList[tid].clear();
---
> // 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;
131d80
< }
133,140c82,87
< 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();
---
> // 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;
142d88
< numInstsInROB = 0;
144,148c90
< // Initialize the "universal" ROB head & tail point to invalid
< // pointers
< head = instList[0].end();
< tail = instList[0].end();
< }
---
> return return_val;
150,167c92,95
< 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;
< }
< }
< }
---
> // 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;
171,200d98
< 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>
204c102,104
< //assert(numInstsInROB == countInsts());
---
> // Make sure we have the right number of instructions.
> assert(numInstsInROB == countInsts());
> // Make sure the instruction is valid.
207c107
< DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC());
---
> DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC());
208a109
> // If the ROB is full then exit.
211c112
< int tid = inst->threadNumber;
---
> ++numInstsInROB;
213,218c114,121
< 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);
---
> // 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();
221,230c124,125
< //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];
<
---
> // Make sure the tail iterator is actually pointing at the instruction
> // added.
233c128,129
< DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]);
---
> DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB);
>
238d133
< /*
243c138
< //assert(numInstsInROB == countInsts());
---
> assert(numInstsInROB == countInsts());
246,262d140
< 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);
<
264c142
< InstIt head_it = instList[tid].begin();
---
> DynInstPtr head_inst = cpu->instList.front();
266,267c144
< DynInstPtr head_inst = (*head_it);
<
---
> // Make certain this can retire.
270,271c147,148
< DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
< "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(),
---
> DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, "
> "instruction PC %#x, seq num %i\n", head_inst->readPC(),
273a151
> // Keep track of how many instructions are in the ROB.
275d152
< --threadEntries[tid];
277,287c154,157
< 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.
---
> // 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.
289,297d158
< }
< /*
< template <class Impl>
< bool
< ROB<Impl>::isHeadReady()
< {
< if (numInstsInROB != 0) {
< return (*head)->readyToCommit();
< }
299,307c160,161
< return false;
< }
< */
< template <class Impl>
< bool
< ROB<Impl>::isHeadReady(unsigned tid)
< {
< if (threadEntries[tid] != 0) {
< return instList[tid].front()->readyToCommit();
---
> if (numInstsInROB == 0) {
> tail = cpu->instList.end();
309,310d162
<
< return false;
315c167
< ROB<Impl>::canCommit()
---
> ROB<Impl>::isHeadReady()
317,325c169,170
< //@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;
< }
---
> if (numInstsInROB != 0) {
> return cpu->instList.front()->readyToCommit();
335c180
< //assert(numInstsInROB == countInsts());
---
> assert(numInstsInROB == countInsts());
341,347d185
< unsigned
< ROB<Impl>::numFreeEntries(unsigned tid)
< {
< return maxEntries[tid] - threadEntries[tid];
< }
<
< template <class Impl>
349c187
< ROB<Impl>::doSquash(unsigned tid)
---
> ROB<Impl>::doSquash()
351,352c189
< DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
< tid, squashedSeqNum);
---
> DPRINTF(ROB, "ROB: Squashing instructions.\n");
354c191
< assert(squashIt[tid] != instList[tid].end());
---
> assert(squashIt != cpu->instList.end());
356,367d192
< 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;
<
369,371c194
< numSquashed < squashWidth &&
< squashIt[tid] != instList[tid].end() &&
< (*squashIt[tid])->seqNum > squashedSeqNum;
---
> numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum;
374,377c197,198
< DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
< (*squashIt[tid])->threadNumber,
< (*squashIt[tid])->readPC(),
< (*squashIt[tid])->seqNum);
---
> // Ensure that the instruction is younger.
> assert((*squashIt)->seqNum > squashedSeqNum);
378a200,202
> DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n",
> (*squashIt)->readPC(), (*squashIt)->seqNum);
>
381c205
< (*squashIt[tid])->setSquashed();
---
> (*squashIt)->setSquashed();
383c207
< (*squashIt[tid])->setCanCommit();
---
> (*squashIt)->setCanCommit();
385,387c209,217
<
< if (squashIt[tid] == instList[tid].begin()) {
< DPRINTF(ROB, "Reached head of instruction list while "
---
> // 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 "
390c220
< squashIt[tid] = instList[tid].end();
---
> squashIt = cpu->instList.end();
392c222
< doneSquashing[tid] = true;
---
> doneSquashing = true;
395a226
> #endif
397,403c228,229
< InstIt tail_thread = instList[tid].end();
< tail_thread--;
<
< if ((*squashIt[tid]) == (*tail_thread))
< robTailUpdate = true;
<
< squashIt[tid]--;
---
> // Move the tail iterator to the next instruction.
> squashIt--;
408,410c234,235
< if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
< DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
< tid);
---
> if ((*squashIt)->seqNum == squashedSeqNum) {
> DPRINTF(ROB, "ROB: Done squashing instructions.\n");
412c237
< squashIt[tid] = instList[tid].end();
---
> squashIt = cpu->instList.end();
414c239
< doneSquashing[tid] = true;
---
> doneSquashing = true;
416,419d240
<
< if (robTailUpdate) {
< updateTail();
< }
422d242
<
425c245
< ROB<Impl>::updateHead()
---
> ROB<Impl>::squash(InstSeqNum squash_num)
427,429c247,248
< DynInstPtr head_inst;
< InstSeqNum lowest_num = 0;
< bool first_valid = true;
---
> DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n");
> doneSquashing = false;
431,519d249
< // @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;
<
522,524c252
< if (!instList[tid].empty()) {
< InstIt tail_thread = instList[tid].end();
< tail_thread--;
---
> assert(tail != cpu->instList.end());
526c254
< squashIt[tid] = tail_thread;
---
> squashIt = tail;
528,529c256
< doSquash(tid);
< }
---
> doSquash();
531,549d257
< /*
< 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();
551,558d258
< assert((*head_thread)->isInROB()==true);
<
< return *head_thread;
< } else {
< return dummyInst;
< }
< }
< /*
563c263
< //assert(numInstsInROB == countInsts());
---
> assert(numInstsInROB == countInsts());
565c265
< DynInstPtr head_inst = *head;
---
> DynInstPtr head_inst = cpu->instList.front();
572,582d271
< ROB<Impl>::readHeadPC(unsigned tid)
< {
< //assert(numInstsInROB == countInsts());
< InstIt head_thread = instList[tid].begin();
<
< return (*head_thread)->readPC();
< }
<
<
< template <class Impl>
< uint64_t
585c274
< //assert(numInstsInROB == countInsts());
---
> assert(numInstsInROB == countInsts());
587c276
< DynInstPtr head_inst = *head;
---
> DynInstPtr head_inst = cpu->instList.front();
593,602d281
< uint64_t
< ROB<Impl>::readHeadNextPC(unsigned tid)
< {
< //assert(numInstsInROB == countInsts());
< InstIt head_thread = instList[tid].begin();
<
< return (*head_thread)->readNextPC();
< }
<
< template <class Impl>
606,607c285,288
< //assert(numInstsInROB == countInsts());
< DynInstPtr head_inst = *head;
---
> // 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();
613,644d293
< 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>
648c297
< //assert(numInstsInROB == countInsts());
---
> assert(numInstsInROB == countInsts());
650c299
< //assert(tail != instList[0].end());
---
> assert(tail != cpu->instList.end());
656,667d304
< 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>
677,691c314
< 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;
< }
< */
---
> #endif // __CPU_O3_CPU_ROB_IMPL_HH__