2 * Copyright (c) 2004-2006 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "config/full_system.hh"
33 #include "cpu/o3/rob.hh"
38 ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
39 std::string _smtROBPolicy, unsigned _smtROBThreshold,
41 : numEntries(_numEntries),
42 squashWidth(_squashWidth),
44 numThreads(_numThreads)
46 for (int tid=0; tid < numThreads; tid++) {
47 squashedSeqNum[tid] = 0;
48 doneSquashing[tid] = true;
49 threadEntries[tid] = 0;
52 std::string policy = _smtROBPolicy;
54 //Convert string to lowercase
55 std::transform(policy.begin(), policy.end(), policy.begin(),
56 (int(*)(int)) tolower);
58 //Figure out rob policy
59 if (policy == "dynamic") {
62 //Set Max Entries to Total ROB Capacity
63 for (int i = 0; i < numThreads; i++) {
64 maxEntries[i]=numEntries;
67 } else if (policy == "partitioned") {
68 robPolicy = Partitioned;
69 // DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n");
71 //@todo:make work if part_amt doesnt divide evenly.
72 int part_amt = numEntries / numThreads;
74 //Divide ROB up evenly
75 for (int i = 0; i < numThreads; i++) {
76 maxEntries[i]=part_amt;
79 } else if (policy == "threshold") {
80 robPolicy = Threshold;
81 // DPRINTF(Fetch, "ROB sharing policy set to Threshold\n");
83 int threshold = _smtROBThreshold;;
85 //Divide up by threshold amount
86 for (int i = 0; i < numThreads; i++) {
87 maxEntries[i]=threshold;
90 assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic,"
91 "Partitioned, Threshold}");
97 ROB<Impl>::name() const
99 return cpu->name() + ".rob";
102 template <class Impl>
104 ROB<Impl>::setCPU(O3CPU *cpu_ptr)
108 // Set the per-thread iterators to the end of the instruction list.
109 for (int i=0; i < numThreads;i++) {
110 squashIt[i] = instList[i].end();
113 // Initialize the "universal" ROB head & tail point to invalid
115 head = instList[0].end();
116 tail = instList[0].end();
119 template <class Impl>
121 ROB<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
123 DPRINTF(ROB, "Setting active threads list pointer.\n");
124 activeThreads = at_ptr;
127 template <class Impl>
129 ROB<Impl>::switchOut()
131 for (int tid = 0; tid < numThreads; tid++) {
132 instList[tid].clear();
136 template <class Impl>
138 ROB<Impl>::takeOverFrom()
140 for (int tid=0; tid < numThreads; tid++) {
141 doneSquashing[tid] = true;
142 threadEntries[tid] = 0;
143 squashIt[tid] = instList[tid].end();
147 // Initialize the "universal" ROB head & tail point to invalid
149 head = instList[0].end();
150 tail = instList[0].end();
153 template <class Impl>
155 ROB<Impl>::resetEntries()
157 if (robPolicy != Dynamic || numThreads > 1) {
158 int active_threads = activeThreads->size();
160 std::list<unsigned>::iterator threads = activeThreads->begin();
161 std::list<unsigned>::iterator end = activeThreads->end();
163 while (threads != end) {
164 unsigned tid = *threads++;
166 if (robPolicy == Partitioned) {
167 maxEntries[tid] = numEntries / active_threads;
168 } else if (robPolicy == Threshold && active_threads == 1) {
169 maxEntries[tid] = numEntries;
175 template <class Impl>
177 ROB<Impl>::entryAmount(int num_threads)
179 if (robPolicy == Partitioned) {
180 return numEntries / num_threads;
186 template <class Impl>
188 ROB<Impl>::countInsts()
192 for (int i=0;i < numThreads;i++)
193 total += countInsts(i);
198 template <class Impl>
200 ROB<Impl>::countInsts(unsigned tid)
202 return instList[tid].size();
205 template <class Impl>
207 ROB<Impl>::insertInst(DynInstPtr &inst)
209 //assert(numInstsInROB == countInsts());
212 DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC());
214 assert(numInstsInROB != numEntries);
216 int tid = inst->threadNumber;
218 instList[tid].push_back(inst);
220 //Set Up head iterator if this is the 1st instruction in the ROB
221 if (numInstsInROB == 0) {
222 head = instList[tid].begin();
223 assert((*head) == inst);
226 //Must Decrement for iterator to actually be valid since __.end()
227 //actually points to 1 after the last inst
228 tail = instList[tid].end();
234 ++threadEntries[tid];
236 assert((*tail) == inst);
238 DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]);
241 // Whatever calls this function needs to ensure that it properly frees up
242 // registers prior to this function.
244 template <class Impl>
246 ROB<Impl>::retireHead()
248 //assert(numInstsInROB == countInsts());
249 assert(numInstsInROB > 0);
251 int tid = (*head)->threadNumber;
255 if (numInstsInROB == 0) {
256 tail = instList[tid].end();
261 template <class Impl>
263 ROB<Impl>::retireHead(unsigned tid)
265 //assert(numInstsInROB == countInsts());
266 assert(numInstsInROB > 0);
268 // Get the head ROB instruction.
269 InstIt head_it = instList[tid].begin();
271 DynInstPtr head_inst = (*head_it);
273 assert(head_inst->readyToCommit());
275 DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
276 "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(),
280 --threadEntries[tid];
282 head_inst->clearInROB();
283 head_inst->setCommitted();
285 instList[tid].erase(head_it);
287 //Update "Global" Head of ROB
290 // @todo: A special case is needed if the instruction being
291 // retired is the only instruction in the ROB; otherwise the tail
292 // iterator will become invalidated.
293 cpu->removeFrontInst(head_inst);
296 template <class Impl>
298 ROB<Impl>::isHeadReady()
300 if (numInstsInROB != 0) {
301 return (*head)->readyToCommit();
307 template <class Impl>
309 ROB<Impl>::isHeadReady(unsigned tid)
311 if (threadEntries[tid] != 0) {
312 return instList[tid].front()->readyToCommit();
318 template <class Impl>
320 ROB<Impl>::canCommit()
322 //@todo: set ActiveThreads through ROB or CPU
323 std::list<unsigned>::iterator threads = activeThreads->begin();
324 std::list<unsigned>::iterator end = activeThreads->end();
326 while (threads != end) {
327 unsigned tid = *threads++;
329 if (isHeadReady(tid)) {
337 template <class Impl>
339 ROB<Impl>::numFreeEntries()
341 //assert(numInstsInROB == countInsts());
343 return numEntries - numInstsInROB;
346 template <class Impl>
348 ROB<Impl>::numFreeEntries(unsigned tid)
350 return maxEntries[tid] - threadEntries[tid];
353 template <class Impl>
355 ROB<Impl>::doSquash(unsigned tid)
357 DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
358 tid, squashedSeqNum[tid]);
360 assert(squashIt[tid] != instList[tid].end());
362 if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) {
363 DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
366 squashIt[tid] = instList[tid].end();
368 doneSquashing[tid] = true;
372 bool robTailUpdate = false;
374 for (int numSquashed = 0;
375 numSquashed < squashWidth &&
376 squashIt[tid] != instList[tid].end() &&
377 (*squashIt[tid])->seqNum > squashedSeqNum[tid];
380 DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
381 (*squashIt[tid])->threadNumber,
382 (*squashIt[tid])->readPC(),
383 (*squashIt[tid])->seqNum);
385 // Mark the instruction as squashed, and ready to commit so that
386 // it can drain out of the pipeline.
387 (*squashIt[tid])->setSquashed();
389 (*squashIt[tid])->setCanCommit();
392 if (squashIt[tid] == instList[tid].begin()) {
393 DPRINTF(ROB, "Reached head of instruction list while "
396 squashIt[tid] = instList[tid].end();
398 doneSquashing[tid] = true;
403 InstIt tail_thread = instList[tid].end();
406 if ((*squashIt[tid]) == (*tail_thread))
407 robTailUpdate = true;
413 // Check if ROB is done squashing.
414 if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) {
415 DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
418 squashIt[tid] = instList[tid].end();
420 doneSquashing[tid] = true;
429 template <class Impl>
431 ROB<Impl>::updateHead()
433 DynInstPtr head_inst;
434 InstSeqNum lowest_num = 0;
435 bool first_valid = true;
437 // @todo: set ActiveThreads through ROB or CPU
438 std::list<unsigned>::iterator threads = activeThreads->begin();
439 std::list<unsigned>::iterator end = activeThreads->end();
441 while (threads != end) {
442 unsigned tid = *threads++;
444 if (instList[tid].empty())
448 head = instList[tid].begin();
449 lowest_num = (*head)->seqNum;
454 InstIt head_thread = instList[tid].begin();
456 DynInstPtr head_inst = (*head_thread);
458 assert(head_inst != 0);
460 if (head_inst->seqNum < lowest_num) {
462 lowest_num = head_inst->seqNum;
467 head = instList[0].end();
472 template <class Impl>
474 ROB<Impl>::updateTail()
476 tail = instList[0].end();
477 bool first_valid = true;
479 std::list<unsigned>::iterator threads = activeThreads->begin();
480 std::list<unsigned>::iterator end = activeThreads->end();
482 while (threads != end) {
483 unsigned tid = *threads++;
485 if (instList[tid].empty()) {
489 // If this is the first valid then assign w/out
492 tail = instList[tid].end();
498 // Assign new tail if this thread's tail is younger
499 // than our current "tail high"
500 InstIt tail_thread = instList[tid].end();
503 if ((*tail_thread)->seqNum > (*tail)->seqNum) {
510 template <class Impl>
512 ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid)
515 DPRINTF(ROB, "Does not need to squash due to being empty "
522 DPRINTF(ROB, "Starting to squash within the ROB.\n");
524 robStatus[tid] = ROBSquashing;
526 doneSquashing[tid] = false;
528 squashedSeqNum[tid] = squash_num;
530 if (!instList[tid].empty()) {
531 InstIt tail_thread = instList[tid].end();
534 squashIt[tid] = tail_thread;
540 template <class Impl>
541 typename Impl::DynInstPtr
542 ROB<Impl>::readHeadInst()
544 if (numInstsInROB != 0) {
545 assert((*head)->isInROB()==true);
553 template <class Impl>
554 typename Impl::DynInstPtr
555 ROB<Impl>::readHeadInst(unsigned tid)
557 if (threadEntries[tid] != 0) {
558 InstIt head_thread = instList[tid].begin();
560 assert((*head_thread)->isInROB()==true);
569 template <class Impl>
571 ROB<Impl>::readHeadPC()
573 //assert(numInstsInROB == countInsts());
575 DynInstPtr head_inst = *head;
577 return head_inst->readPC();
580 template <class Impl>
582 ROB<Impl>::readHeadPC(unsigned tid)
584 //assert(numInstsInROB == countInsts());
585 InstIt head_thread = instList[tid].begin();
587 return (*head_thread)->readPC();
591 template <class Impl>
593 ROB<Impl>::readHeadNextPC()
595 //assert(numInstsInROB == countInsts());
597 DynInstPtr head_inst = *head;
599 return head_inst->readNextPC();
602 template <class Impl>
604 ROB<Impl>::readHeadNextPC(unsigned tid)
606 //assert(numInstsInROB == countInsts());
607 InstIt head_thread = instList[tid].begin();
609 return (*head_thread)->readNextPC();
612 template <class Impl>
614 ROB<Impl>::readHeadSeqNum()
616 //assert(numInstsInROB == countInsts());
617 DynInstPtr head_inst = *head;
619 return head_inst->seqNum;
622 template <class Impl>
624 ROB<Impl>::readHeadSeqNum(unsigned tid)
626 InstIt head_thread = instList[tid].begin();
628 return ((*head_thread)->seqNum);
631 template <class Impl>
632 typename Impl::DynInstPtr
633 ROB<Impl>::readTailInst()
635 //assert(numInstsInROB == countInsts());
636 //assert(tail != instList[0].end());
641 template <class Impl>
642 typename Impl::DynInstPtr
643 ROB<Impl>::readTailInst(unsigned tid)
645 //assert(tail_thread[tid] != instList[tid].end());
647 InstIt tail_thread = instList[tid].end();
654 template <class Impl>
656 ROB<Impl>::readTailPC()
658 //assert(numInstsInROB == countInsts());
660 //assert(tail != instList[0].end());
662 return (*tail)->readPC();
665 template <class Impl>
667 ROB<Impl>::readTailPC(unsigned tid)
669 //assert(tail_thread[tid] != instList[tid].end());
671 InstIt tail_thread = instList[tid].end();
674 return (*tail_thread)->readPC();
677 template <class Impl>
679 ROB<Impl>::readTailSeqNum()
681 // Return the last sequence number that has not been squashed. Other
682 // stages can use it to squash any instructions younger than the current
684 return (*tail)->seqNum;
687 template <class Impl>
689 ROB<Impl>::readTailSeqNum(unsigned tid)
691 // Return the last sequence number that has not been squashed. Other
692 // stages can use it to squash any instructions younger than the current
694 // assert(tail_thread[tid] != instList[tid].end());
696 InstIt tail_thread = instList[tid].end();
699 return (*tail_thread)->seqNum;