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.
29 #include "config/full_system.hh"
30 #include "cpu/o3/rob.hh"
35 ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
36 string _smtROBPolicy, unsigned _smtROBThreshold,
38 : numEntries(_numEntries),
39 squashWidth(_squashWidth),
42 numThreads(_numThreads)
44 for (int tid=0; tid < numThreads; tid++) {
45 doneSquashing[tid] = true;
46 threadEntries[tid] = 0;
49 string policy = _smtROBPolicy;
51 //Convert string to lowercase
52 std::transform(policy.begin(), policy.end(), policy.begin(),
53 (int(*)(int)) tolower);
55 //Figure out rob policy
56 if (policy == "dynamic") {
59 //Set Max Entries to Total ROB Capacity
60 for (int i = 0; i < numThreads; i++) {
61 maxEntries[i]=numEntries;
64 } else if (policy == "partitioned") {
65 robPolicy = Partitioned;
66 DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n");
68 //@todo:make work if part_amt doesnt divide evenly.
69 int part_amt = numEntries / numThreads;
71 //Divide ROB up evenly
72 for (int i = 0; i < numThreads; i++) {
73 maxEntries[i]=part_amt;
76 } else if (policy == "threshold") {
77 robPolicy = Threshold;
78 DPRINTF(Fetch, "ROB sharing policy set to Threshold\n");
80 int threshold = _smtROBThreshold;;
82 //Divide up by threshold amount
83 for (int i = 0; i < numThreads; i++) {
84 maxEntries[i]=threshold;
87 assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic,"
88 "Partitioned, Threshold}");
94 ROB<Impl>::name() const
96 return cpu->name() + ".rob";
101 ROB<Impl>::setCPU(FullCPU *cpu_ptr)
105 // Set the per-thread iterators to the end of the instruction list.
106 for (int i=0; i < numThreads;i++) {
107 squashIt[i] = instList[i].end();
110 // Initialize the "universal" ROB head & tail point to invalid
112 head = instList[0].end();
113 tail = instList[0].end();
116 template <class Impl>
118 ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr)
120 DPRINTF(ROB, "Setting active threads list pointer.\n");
121 activeThreads = at_ptr;
124 template <class Impl>
126 ROB<Impl>::switchOut()
128 for (int tid = 0; tid < numThreads; tid++) {
129 instList[tid].clear();
133 template <class Impl>
135 ROB<Impl>::takeOverFrom()
137 for (int tid=0; tid < numThreads; tid++) {
138 doneSquashing[tid] = true;
139 threadEntries[tid] = 0;
140 squashIt[tid] = instList[tid].end();
144 // Initialize the "universal" ROB head & tail point to invalid
146 head = instList[0].end();
147 tail = instList[0].end();
150 template <class Impl>
152 ROB<Impl>::resetEntries()
154 if (robPolicy != Dynamic || numThreads > 1) {
155 int active_threads = (*activeThreads).size();
157 list<unsigned>::iterator threads = (*activeThreads).begin();
158 list<unsigned>::iterator list_end = (*activeThreads).end();
160 while (threads != list_end) {
161 if (robPolicy == Partitioned) {
162 maxEntries[*threads++] = numEntries / active_threads;
163 } else if (robPolicy == Threshold && active_threads == 1) {
164 maxEntries[*threads++] = numEntries;
170 template <class Impl>
172 ROB<Impl>::entryAmount(int num_threads)
174 if (robPolicy == Partitioned) {
175 return numEntries / num_threads;
181 template <class Impl>
183 ROB<Impl>::countInsts()
187 for (int i=0;i < numThreads;i++)
188 total += countInsts(i);
193 template <class Impl>
195 ROB<Impl>::countInsts(unsigned tid)
197 return instList[tid].size();
200 template <class Impl>
202 ROB<Impl>::insertInst(DynInstPtr &inst)
204 //assert(numInstsInROB == countInsts());
207 DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC());
209 assert(numInstsInROB != numEntries);
211 int tid = inst->threadNumber;
213 instList[tid].push_back(inst);
215 //Set Up head iterator if this is the 1st instruction in the ROB
216 if (numInstsInROB == 0) {
217 head = instList[tid].begin();
218 assert((*head) == inst);
221 //Must Decrement for iterator to actually be valid since __.end()
222 //actually points to 1 after the last inst
223 tail = instList[tid].end();
229 ++threadEntries[tid];
231 assert((*tail) == inst);
233 DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]);
236 // Whatever calls this function needs to ensure that it properly frees up
237 // registers prior to this function.
239 template <class Impl>
241 ROB<Impl>::retireHead()
243 //assert(numInstsInROB == countInsts());
244 assert(numInstsInROB > 0);
246 int tid = (*head)->threadNumber;
250 if (numInstsInROB == 0) {
251 tail = instList[tid].end();
256 template <class Impl>
258 ROB<Impl>::retireHead(unsigned tid)
260 //assert(numInstsInROB == countInsts());
261 assert(numInstsInROB > 0);
263 // Get the head ROB instruction.
264 InstIt head_it = instList[tid].begin();
266 DynInstPtr head_inst = (*head_it);
268 assert(head_inst->readyToCommit());
270 DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
271 "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(),
275 --threadEntries[tid];
277 head_inst->removeInROB();
278 head_inst->setCommitted();
280 instList[tid].erase(head_it);
282 //Update "Global" Head of ROB
285 // @todo: A special case is needed if the instruction being
286 // retired is the only instruction in the ROB; otherwise the tail
287 // iterator will become invalidated.
288 cpu->removeFrontInst(head_inst);
291 template <class Impl>
293 ROB<Impl>::isHeadReady()
295 if (numInstsInROB != 0) {
296 return (*head)->readyToCommit();
302 template <class Impl>
304 ROB<Impl>::isHeadReady(unsigned tid)
306 if (threadEntries[tid] != 0) {
307 return instList[tid].front()->readyToCommit();
313 template <class Impl>
315 ROB<Impl>::canCommit()
317 //@todo: set ActiveThreads through ROB or CPU
318 list<unsigned>::iterator threads = (*activeThreads).begin();
320 while (threads != (*activeThreads).end()) {
321 unsigned tid = *threads++;
323 if (isHeadReady(tid)) {
331 template <class Impl>
333 ROB<Impl>::numFreeEntries()
335 //assert(numInstsInROB == countInsts());
337 return numEntries - numInstsInROB;
340 template <class Impl>
342 ROB<Impl>::numFreeEntries(unsigned tid)
344 return maxEntries[tid] - threadEntries[tid];
347 template <class Impl>
349 ROB<Impl>::doSquash(unsigned tid)
351 DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
352 tid, squashedSeqNum);
354 assert(squashIt[tid] != instList[tid].end());
356 if ((*squashIt[tid])->seqNum < squashedSeqNum) {
357 DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
360 squashIt[tid] = instList[tid].end();
362 doneSquashing[tid] = true;
366 bool robTailUpdate = false;
368 for (int numSquashed = 0;
369 numSquashed < squashWidth &&
370 squashIt[tid] != instList[tid].end() &&
371 (*squashIt[tid])->seqNum > squashedSeqNum;
374 DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
375 (*squashIt[tid])->threadNumber,
376 (*squashIt[tid])->readPC(),
377 (*squashIt[tid])->seqNum);
379 // Mark the instruction as squashed, and ready to commit so that
380 // it can drain out of the pipeline.
381 (*squashIt[tid])->setSquashed();
383 (*squashIt[tid])->setCanCommit();
386 if (squashIt[tid] == instList[tid].begin()) {
387 DPRINTF(ROB, "Reached head of instruction list while "
390 squashIt[tid] = instList[tid].end();
392 doneSquashing[tid] = true;
397 InstIt tail_thread = instList[tid].end();
400 if ((*squashIt[tid]) == (*tail_thread))
401 robTailUpdate = true;
407 // Check if ROB is done squashing.
408 if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
409 DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
412 squashIt[tid] = instList[tid].end();
414 doneSquashing[tid] = true;
423 template <class Impl>
425 ROB<Impl>::updateHead()
427 DynInstPtr head_inst;
428 InstSeqNum lowest_num = 0;
429 bool first_valid = true;
431 // @todo: set ActiveThreads through ROB or CPU
432 list<unsigned>::iterator threads = (*activeThreads).begin();
434 while (threads != (*activeThreads).end()) {
435 unsigned thread_num = *threads++;
437 if (instList[thread_num].empty())
441 head = instList[thread_num].begin();
442 lowest_num = (*head)->seqNum;
447 InstIt head_thread = instList[thread_num].begin();
449 DynInstPtr head_inst = (*head_thread);
451 assert(head_inst != 0);
453 if (head_inst->seqNum < lowest_num) {
455 lowest_num = head_inst->seqNum;
460 head = instList[0].end();
465 template <class Impl>
467 ROB<Impl>::updateTail()
469 tail = instList[0].end();
470 bool first_valid = true;
472 list<unsigned>::iterator threads = (*activeThreads).begin();
474 while (threads != (*activeThreads).end()) {
475 unsigned tid = *threads++;
477 if (instList[tid].empty()) {
481 // If this is the first valid then assign w/out
484 tail = instList[tid].end();
490 // Assign new tail if this thread's tail is younger
491 // than our current "tail high"
492 InstIt tail_thread = instList[tid].end();
495 if ((*tail_thread)->seqNum > (*tail)->seqNum) {
502 template <class Impl>
504 ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid)
507 DPRINTF(ROB, "Does not need to squash due to being empty "
514 DPRINTF(ROB, "Starting to squash within the ROB.\n");
516 robStatus[tid] = ROBSquashing;
518 doneSquashing[tid] = false;
520 squashedSeqNum = squash_num;
522 if (!instList[tid].empty()) {
523 InstIt tail_thread = instList[tid].end();
526 squashIt[tid] = tail_thread;
532 template <class Impl>
533 typename Impl::DynInstPtr
534 ROB<Impl>::readHeadInst()
536 if (numInstsInROB != 0) {
537 assert((*head)->isInROB()==true);
544 template <class Impl>
545 typename Impl::DynInstPtr
546 ROB<Impl>::readHeadInst(unsigned tid)
548 if (threadEntries[tid] != 0) {
549 InstIt head_thread = instList[tid].begin();
551 assert((*head_thread)->isInROB()==true);
559 template <class Impl>
561 ROB<Impl>::readHeadPC()
563 //assert(numInstsInROB == countInsts());
565 DynInstPtr head_inst = *head;
567 return head_inst->readPC();
570 template <class Impl>
572 ROB<Impl>::readHeadPC(unsigned tid)
574 //assert(numInstsInROB == countInsts());
575 InstIt head_thread = instList[tid].begin();
577 return (*head_thread)->readPC();
581 template <class Impl>
583 ROB<Impl>::readHeadNextPC()
585 //assert(numInstsInROB == countInsts());
587 DynInstPtr head_inst = *head;
589 return head_inst->readNextPC();
592 template <class Impl>
594 ROB<Impl>::readHeadNextPC(unsigned tid)
596 //assert(numInstsInROB == countInsts());
597 InstIt head_thread = instList[tid].begin();
599 return (*head_thread)->readNextPC();
602 template <class Impl>
604 ROB<Impl>::readHeadSeqNum()
606 //assert(numInstsInROB == countInsts());
607 DynInstPtr head_inst = *head;
609 return head_inst->seqNum;
612 template <class Impl>
614 ROB<Impl>::readHeadSeqNum(unsigned tid)
616 InstIt head_thread = instList[tid].begin();
618 return ((*head_thread)->seqNum);
621 template <class Impl>
622 typename Impl::DynInstPtr
623 ROB<Impl>::readTailInst()
625 //assert(numInstsInROB == countInsts());
626 //assert(tail != instList[0].end());
631 template <class Impl>
632 typename Impl::DynInstPtr
633 ROB<Impl>::readTailInst(unsigned tid)
635 //assert(tail_thread[tid] != instList[tid].end());
637 InstIt tail_thread = instList[tid].end();
644 template <class Impl>
646 ROB<Impl>::readTailPC()
648 //assert(numInstsInROB == countInsts());
650 //assert(tail != instList[0].end());
652 return (*tail)->readPC();
655 template <class Impl>
657 ROB<Impl>::readTailPC(unsigned tid)
659 //assert(tail_thread[tid] != instList[tid].end());
661 InstIt tail_thread = instList[tid].end();
664 return (*tail_thread)->readPC();
667 template <class Impl>
669 ROB<Impl>::readTailSeqNum()
671 // Return the last sequence number that has not been squashed. Other
672 // stages can use it to squash any instructions younger than the current
674 return (*tail)->seqNum;
677 template <class Impl>
679 ROB<Impl>::readTailSeqNum(unsigned tid)
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 // assert(tail_thread[tid] != instList[tid].end());
686 InstIt tail_thread = instList[tid].end();
689 return (*tail_thread)->seqNum;