gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rob_impl.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 2004-2006 The Regents of The University of Michigan
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * Authors: Kevin Lim
41  * Korey Sewell
42  */
43 
44 #ifndef __CPU_O3_ROB_IMPL_HH__
45 #define __CPU_O3_ROB_IMPL_HH__
46 
47 #include <list>
48 
49 #include "cpu/o3/rob.hh"
50 #include "debug/Fetch.hh"
51 #include "debug/ROB.hh"
52 #include "params/DerivO3CPU.hh"
53 
54 using namespace std;
55 
56 template <class Impl>
57 ROB<Impl>::ROB(O3CPU *_cpu, DerivO3CPUParams *params)
58  : cpu(_cpu),
59  numEntries(params->numROBEntries),
60  squashWidth(params->squashWidth),
61  numInstsInROB(0),
62  numThreads(params->numThreads)
63 {
64  std::string policy = params->smtROBPolicy;
65 
66  //Convert string to lowercase
67  std::transform(policy.begin(), policy.end(), policy.begin(),
68  (int(*)(int)) tolower);
69 
70  //Figure out rob policy
71  if (policy == "dynamic") {
73 
74  //Set Max Entries to Total ROB Capacity
75  for (ThreadID tid = 0; tid < numThreads; tid++) {
76  maxEntries[tid] = numEntries;
77  }
78 
79  } else if (policy == "partitioned") {
81  DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n");
82 
83  //@todo:make work if part_amt doesnt divide evenly.
84  int part_amt = numEntries / numThreads;
85 
86  //Divide ROB up evenly
87  for (ThreadID tid = 0; tid < numThreads; tid++) {
88  maxEntries[tid] = part_amt;
89  }
90 
91  } else if (policy == "threshold") {
93  DPRINTF(Fetch, "ROB sharing policy set to Threshold\n");
94 
95  int threshold = params->smtROBThreshold;;
96 
97  //Divide up by threshold amount
98  for (ThreadID tid = 0; tid < numThreads; tid++) {
99  maxEntries[tid] = threshold;
100  }
101  } else {
102  assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic,"
103  "Partitioned, Threshold}");
104  }
105 
106  resetState();
107 }
108 
109 template <class Impl>
110 void
112 {
113  for (ThreadID tid = 0; tid < numThreads; tid++) {
114  doneSquashing[tid] = true;
115  threadEntries[tid] = 0;
116  squashIt[tid] = instList[tid].end();
117  squashedSeqNum[tid] = 0;
118  }
119  numInstsInROB = 0;
120 
121  // Initialize the "universal" ROB head & tail point to invalid
122  // pointers
123  head = instList[0].end();
124  tail = instList[0].end();
125 }
126 
127 template <class Impl>
128 std::string
130 {
131  return cpu->name() + ".rob";
132 }
133 
134 template <class Impl>
135 void
137 {
138  DPRINTF(ROB, "Setting active threads list pointer.\n");
139  activeThreads = at_ptr;
140 }
141 
142 template <class Impl>
143 void
145 {
146  for (ThreadID tid = 0; tid < numThreads; tid++)
147  assert(instList[tid].empty());
148  assert(isEmpty());
149 }
150 
151 template <class Impl>
152 void
154 {
155  resetState();
156 }
157 
158 template <class Impl>
159 void
161 {
162  if (robPolicy != Dynamic || numThreads > 1) {
163  int active_threads = activeThreads->size();
164 
165  list<ThreadID>::iterator threads = activeThreads->begin();
166  list<ThreadID>::iterator end = activeThreads->end();
167 
168  while (threads != end) {
169  ThreadID tid = *threads++;
170 
171  if (robPolicy == Partitioned) {
172  maxEntries[tid] = numEntries / active_threads;
173  } else if (robPolicy == Threshold && active_threads == 1) {
174  maxEntries[tid] = numEntries;
175  }
176  }
177  }
178 }
179 
180 template <class Impl>
181 int
183 {
184  if (robPolicy == Partitioned) {
185  return numEntries / num_threads;
186  } else {
187  return 0;
188  }
189 }
190 
191 template <class Impl>
192 int
194 {
195  int total = 0;
196 
197  for (ThreadID tid = 0; tid < numThreads; tid++)
198  total += countInsts(tid);
199 
200  return total;
201 }
202 
203 template <class Impl>
204 int
206 {
207  return instList[tid].size();
208 }
209 
210 template <class Impl>
211 void
213 {
214  assert(inst);
215 
216  robWrites++;
217 
218  DPRINTF(ROB, "Adding inst PC %s to the ROB.\n", inst->pcState());
219 
220  assert(numInstsInROB != numEntries);
221 
222  ThreadID tid = inst->threadNumber;
223 
224  instList[tid].push_back(inst);
225 
226  //Set Up head iterator if this is the 1st instruction in the ROB
227  if (numInstsInROB == 0) {
228  head = instList[tid].begin();
229  assert((*head) == inst);
230  }
231 
232  //Must Decrement for iterator to actually be valid since __.end()
233  //actually points to 1 after the last inst
234  tail = instList[tid].end();
235  tail--;
236 
237  inst->setInROB();
238 
239  ++numInstsInROB;
240  ++threadEntries[tid];
241 
242  assert((*tail) == inst);
243 
244  DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]);
245 }
246 
247 template <class Impl>
248 void
250 {
251  robWrites++;
252 
253  assert(numInstsInROB > 0);
254 
255  // Get the head ROB instruction.
256  InstIt head_it = instList[tid].begin();
257 
258  DynInstPtr head_inst = (*head_it);
259 
260  assert(head_inst->readyToCommit());
261 
262  DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
263  "instruction PC %s, [sn:%lli]\n", tid, head_inst->pcState(),
264  head_inst->seqNum);
265 
266  --numInstsInROB;
267  --threadEntries[tid];
268 
269  head_inst->clearInROB();
270  head_inst->setCommitted();
271 
272  instList[tid].erase(head_it);
273 
274  //Update "Global" Head of ROB
275  updateHead();
276 
277  // @todo: A special case is needed if the instruction being
278  // retired is the only instruction in the ROB; otherwise the tail
279  // iterator will become invalidated.
280  cpu->removeFrontInst(head_inst);
281 }
282 
283 template <class Impl>
284 bool
286 {
287  robReads++;
288  if (threadEntries[tid] != 0) {
289  return instList[tid].front()->readyToCommit();
290  }
291 
292  return false;
293 }
294 
295 template <class Impl>
296 bool
298 {
299  //@todo: set ActiveThreads through ROB or CPU
300  list<ThreadID>::iterator threads = activeThreads->begin();
301  list<ThreadID>::iterator end = activeThreads->end();
302 
303  while (threads != end) {
304  ThreadID tid = *threads++;
305 
306  if (isHeadReady(tid)) {
307  return true;
308  }
309  }
310 
311  return false;
312 }
313 
314 template <class Impl>
315 unsigned
317 {
318  return numEntries - numInstsInROB;
319 }
320 
321 template <class Impl>
322 unsigned
324 {
325  return maxEntries[tid] - threadEntries[tid];
326 }
327 
328 template <class Impl>
329 void
331 {
332  robWrites++;
333  DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
334  tid, squashedSeqNum[tid]);
335 
336  assert(squashIt[tid] != instList[tid].end());
337 
338  if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) {
339  DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
340  tid);
341 
342  squashIt[tid] = instList[tid].end();
343 
344  doneSquashing[tid] = true;
345  return;
346  }
347 
348  bool robTailUpdate = false;
349 
350  for (int numSquashed = 0;
351  numSquashed < squashWidth &&
352  squashIt[tid] != instList[tid].end() &&
353  (*squashIt[tid])->seqNum > squashedSeqNum[tid];
354  ++numSquashed)
355  {
356  DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %s, seq num %i.\n",
357  (*squashIt[tid])->threadNumber,
358  (*squashIt[tid])->pcState(),
359  (*squashIt[tid])->seqNum);
360 
361  // Mark the instruction as squashed, and ready to commit so that
362  // it can drain out of the pipeline.
363  (*squashIt[tid])->setSquashed();
364 
365  (*squashIt[tid])->setCanCommit();
366 
367 
368  if (squashIt[tid] == instList[tid].begin()) {
369  DPRINTF(ROB, "Reached head of instruction list while "
370  "squashing.\n");
371 
372  squashIt[tid] = instList[tid].end();
373 
374  doneSquashing[tid] = true;
375 
376  return;
377  }
378 
379  InstIt tail_thread = instList[tid].end();
380  tail_thread--;
381 
382  if ((*squashIt[tid]) == (*tail_thread))
383  robTailUpdate = true;
384 
385  squashIt[tid]--;
386  }
387 
388 
389  // Check if ROB is done squashing.
390  if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) {
391  DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
392  tid);
393 
394  squashIt[tid] = instList[tid].end();
395 
396  doneSquashing[tid] = true;
397  }
398 
399  if (robTailUpdate) {
400  updateTail();
401  }
402 }
403 
404 
405 template <class Impl>
406 void
408 {
409  InstSeqNum lowest_num = 0;
410  bool first_valid = true;
411 
412  // @todo: set ActiveThreads through ROB or CPU
413  list<ThreadID>::iterator threads = activeThreads->begin();
414  list<ThreadID>::iterator end = activeThreads->end();
415 
416  while (threads != end) {
417  ThreadID tid = *threads++;
418 
419  if (instList[tid].empty())
420  continue;
421 
422  if (first_valid) {
423  head = instList[tid].begin();
424  lowest_num = (*head)->seqNum;
425  first_valid = false;
426  continue;
427  }
428 
429  InstIt head_thread = instList[tid].begin();
430 
431  DynInstPtr head_inst = (*head_thread);
432 
433  assert(head_inst != 0);
434 
435  if (head_inst->seqNum < lowest_num) {
436  head = head_thread;
437  lowest_num = head_inst->seqNum;
438  }
439  }
440 
441  if (first_valid) {
442  head = instList[0].end();
443  }
444 
445 }
446 
447 template <class Impl>
448 void
450 {
451  tail = instList[0].end();
452  bool first_valid = true;
453 
454  list<ThreadID>::iterator threads = activeThreads->begin();
455  list<ThreadID>::iterator end = activeThreads->end();
456 
457  while (threads != end) {
458  ThreadID tid = *threads++;
459 
460  if (instList[tid].empty()) {
461  continue;
462  }
463 
464  // If this is the first valid then assign w/out
465  // comparison
466  if (first_valid) {
467  tail = instList[tid].end();
468  tail--;
469  first_valid = false;
470  continue;
471  }
472 
473  // Assign new tail if this thread's tail is younger
474  // than our current "tail high"
475  InstIt tail_thread = instList[tid].end();
476  tail_thread--;
477 
478  if ((*tail_thread)->seqNum > (*tail)->seqNum) {
479  tail = tail_thread;
480  }
481  }
482 }
483 
484 
485 template <class Impl>
486 void
488 {
489  if (isEmpty(tid)) {
490  DPRINTF(ROB, "Does not need to squash due to being empty "
491  "[sn:%i]\n",
492  squash_num);
493 
494  return;
495  }
496 
497  DPRINTF(ROB, "Starting to squash within the ROB.\n");
498 
499  robStatus[tid] = ROBSquashing;
500 
501  doneSquashing[tid] = false;
502 
503  squashedSeqNum[tid] = squash_num;
504 
505  if (!instList[tid].empty()) {
506  InstIt tail_thread = instList[tid].end();
507  tail_thread--;
508 
509  squashIt[tid] = tail_thread;
510 
511  doSquash(tid);
512  }
513 }
514 
515 template <class Impl>
516 typename Impl::DynInstPtr
518 {
519  if (threadEntries[tid] != 0) {
520  InstIt head_thread = instList[tid].begin();
521 
522  assert((*head_thread)->isInROB());
523 
524  return *head_thread;
525  } else {
526  return dummyInst;
527  }
528 }
529 
530 template <class Impl>
531 typename Impl::DynInstPtr
533 {
534  InstIt tail_thread = instList[tid].end();
535  tail_thread--;
536 
537  return *tail_thread;
538 }
539 
540 template <class Impl>
541 void
543 {
544  using namespace Stats;
545  robReads
546  .name(name() + ".rob_reads")
547  .desc("The number of ROB reads");
548 
549  robWrites
550  .name(name() + ".rob_writes")
551  .desc("The number of ROB writes");
552 }
553 
554 template <class Impl>
555 typename Impl::DynInstPtr
557 {
558  for (InstIt it = instList[tid].begin(); it != instList[tid].end(); it++) {
559  if ((*it)->seqNum == squash_inst) {
560  return *it;
561  }
562  }
563  return NULL;
564 }
565 
566 #endif//__CPU_O3_ROB_IMPL_HH__
void takeOverFrom()
Takes over another CPU's thread.
Definition: rob_impl.hh:153
#define DPRINTF(x,...)
Definition: trace.hh:212
bool canCommit()
Is there any commitable head instruction across all threads ready.
Definition: rob_impl.hh:297
void doSquash(ThreadID tid)
Executes the squash, marking squashed instructions.
Definition: rob_impl.hh:330
void retireHead(ThreadID tid)
Retires the head instruction, removing it from the ROB.
Definition: rob_impl.hh:249
const std::string & name()
Definition: trace.cc:49
void resetState()
Reset the ROB state.
Definition: rob_impl.hh:111
void insertInst(DynInstPtr &inst)
Function to insert an instruction into the ROB.
Definition: rob_impl.hh:212
ROB(O3CPU *_cpu, DerivO3CPUParams *params)
ROB constructor.
Definition: rob_impl.hh:57
ThreadID numThreads
Number of active threads.
Definition: rob.hh:335
DynInstPtr findInst(ThreadID tid, InstSeqNum squash_inst)
Returns a pointer to the instruction with the given sequence if it is in the ROB. ...
Definition: rob_impl.hh:556
void updateHead()
Updates the head instruction with the new oldest instruction.
Definition: rob_impl.hh:407
DynInstPtr readTailInst(ThreadID tid)
Returns pointer to the tail instruction within the ROB.
Definition: rob_impl.hh:532
Impl::DynInstPtr DynInstPtr
Definition: rob.hh:68
std::list< DynInstPtr >::iterator InstIt
Definition: rob.hh:71
unsigned numFreeEntries()
Returns the number of total free entries in the ROB.
Definition: rob_impl.hh:316
ROBPolicy robPolicy
ROB resource sharing policy for SMT mode.
Definition: rob.hh:92
void setActiveThreads(std::list< ThreadID > *at_ptr)
Sets pointer to the list of active threads.
Definition: rob_impl.hh:136
void drainSanityCheck() const
Perform sanity checks after a drain.
Definition: rob_impl.hh:144
uint64_t InstSeqNum
Definition: inst_seq.hh:40
void updateTail()
Updates the tail instruction with the new youngest instruction.
Definition: rob_impl.hh:449
std::string name() const
Definition: rob_impl.hh:129
const FlagsType total
Print the total.
Definition: info.hh:49
void squash(InstSeqNum squash_num, ThreadID tid)
Squashes all instructions younger than the given sequence number for the specific thread...
Definition: rob_impl.hh:487
int16_t ThreadID
Thread index/ID type.
Definition: types.hh:171
void regStats()
Registers statistics.
Definition: rob_impl.hh:542
void resetEntries()
Re-adjust ROB partitioning.
Definition: rob_impl.hh:160
Impl::O3CPU O3CPU
Definition: rob.hh:67
bool isHeadReady(ThreadID tid)
Is the oldest instruction across all threads ready.
Definition: rob_impl.hh:285
int countInsts()
This is more of a debugging function than anything.
Definition: rob_impl.hh:193
DynInstPtr readHeadInst(ThreadID tid)
Returns pointer to the head instruction within the ROB.
Definition: rob_impl.hh:517
unsigned numEntries
Number of instructions in the ROB.
Definition: rob.hh:285
ROB class.
Definition: rob.hh:61
int entryAmount(ThreadID num_threads)
Number of entries needed For 'num_threads' amount of threads.
Definition: rob_impl.hh:182
unsigned maxEntries[Impl::MaxThreads]
Max Insts a Thread Can Have in the ROB.
Definition: rob.hh:291

Generated on Fri Jun 9 2017 13:03:44 for gem5 by doxygen 1.8.6