gem5  v22.1.0.0
rob.cc
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 
41 #include "cpu/o3/rob.hh"
42 
43 #include <list>
44 
45 #include "base/logging.hh"
46 #include "cpu/o3/dyn_inst.hh"
47 #include "cpu/o3/limits.hh"
48 #include "debug/Fetch.hh"
49 #include "debug/ROB.hh"
50 #include "params/BaseO3CPU.hh"
51 
52 namespace gem5
53 {
54 
55 namespace o3
56 {
57 
58 ROB::ROB(CPU *_cpu, const BaseO3CPUParams &params)
59  : robPolicy(params.smtROBPolicy),
60  cpu(_cpu),
61  numEntries(params.numROBEntries),
62  squashWidth(params.squashWidth),
63  numInstsInROB(0),
64  numThreads(params.numThreads),
65  stats(_cpu)
66 {
67  //Figure out rob policy
68  if (robPolicy == SMTQueuePolicy::Dynamic) {
69  //Set Max Entries to Total ROB Capacity
70  for (ThreadID tid = 0; tid < numThreads; tid++) {
71  maxEntries[tid] = numEntries;
72  }
73 
74  } else if (robPolicy == SMTQueuePolicy::Partitioned) {
75  DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n");
76 
77  //@todo:make work if part_amt doesnt divide evenly.
78  int part_amt = numEntries / numThreads;
79 
80  //Divide ROB up evenly
81  for (ThreadID tid = 0; tid < numThreads; tid++) {
82  maxEntries[tid] = part_amt;
83  }
84 
85  } else if (robPolicy == SMTQueuePolicy::Threshold) {
86  DPRINTF(Fetch, "ROB sharing policy set to Threshold\n");
87 
88  int threshold = params.smtROBThreshold;;
89 
90  //Divide up by threshold amount
91  for (ThreadID tid = 0; tid < numThreads; tid++) {
92  maxEntries[tid] = threshold;
93  }
94  }
95 
96  for (ThreadID tid = numThreads; tid < MaxThreads; tid++) {
97  maxEntries[tid] = 0;
98  }
99 
100  resetState();
101 }
102 
103 void
105 {
106  for (ThreadID tid = 0; tid < MaxThreads; tid++) {
107  threadEntries[tid] = 0;
108  squashIt[tid] = instList[tid].end();
109  squashedSeqNum[tid] = 0;
110  doneSquashing[tid] = true;
111  }
112  numInstsInROB = 0;
113 
114  // Initialize the "universal" ROB head & tail point to invalid
115  // pointers
116  head = instList[0].end();
117  tail = instList[0].end();
118 }
119 
120 std::string
121 ROB::name() const
122 {
123  return cpu->name() + ".rob";
124 }
125 
126 void
128 {
129  DPRINTF(ROB, "Setting active threads list pointer.\n");
130  activeThreads = at_ptr;
131 }
132 
133 void
135 {
136  for (ThreadID tid = 0; tid < numThreads; tid++)
137  assert(instList[tid].empty());
138  assert(isEmpty());
139 }
140 
141 void
143 {
144  resetState();
145 }
146 
147 void
149 {
150  if (robPolicy != SMTQueuePolicy::Dynamic || numThreads > 1) {
151  auto active_threads = activeThreads->size();
152 
153  std::list<ThreadID>::iterator threads = activeThreads->begin();
155 
156  while (threads != end) {
157  ThreadID tid = *threads++;
158 
159  if (robPolicy == SMTQueuePolicy::Partitioned) {
160  maxEntries[tid] = numEntries / active_threads;
161  } else if (robPolicy == SMTQueuePolicy::Threshold &&
162  active_threads == 1) {
163  maxEntries[tid] = numEntries;
164  }
165  }
166  }
167 }
168 
169 int
171 {
172  if (robPolicy == SMTQueuePolicy::Partitioned) {
173  return numEntries / num_threads;
174  } else {
175  return 0;
176  }
177 }
178 
179 int
181 {
182  int total = 0;
183 
184  for (ThreadID tid = 0; tid < numThreads; tid++)
185  total += countInsts(tid);
186 
187  return total;
188 }
189 
190 size_t
192 {
193  return instList[tid].size();
194 }
195 
196 void
198 {
199  assert(inst);
200 
201  stats.writes++;
202 
203  DPRINTF(ROB, "Adding inst PC %s to the ROB.\n", inst->pcState());
204 
205  assert(numInstsInROB != numEntries);
206 
207  ThreadID tid = inst->threadNumber;
208 
209  instList[tid].push_back(inst);
210 
211  //Set Up head iterator if this is the 1st instruction in the ROB
212  if (numInstsInROB == 0) {
213  head = instList[tid].begin();
214  assert((*head) == inst);
215  }
216 
217  //Must Decrement for iterator to actually be valid since __.end()
218  //actually points to 1 after the last inst
219  tail = instList[tid].end();
220  tail--;
221 
222  inst->setInROB();
223 
224  ++numInstsInROB;
225  ++threadEntries[tid];
226 
227  assert((*tail) == inst);
228 
229  DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid,
230  threadEntries[tid]);
231 }
232 
233 void
235 {
236  stats.writes++;
237 
238  assert(numInstsInROB > 0);
239 
240  // Get the head ROB instruction by copying it and remove it from the list
241  InstIt head_it = instList[tid].begin();
242 
243  DynInstPtr head_inst = std::move(*head_it);
244  instList[tid].erase(head_it);
245 
246  assert(head_inst->readyToCommit());
247 
248  DPRINTF(ROB, "[tid:%i] Retiring head instruction, "
249  "instruction PC %s, [sn:%llu]\n", tid, head_inst->pcState(),
250  head_inst->seqNum);
251 
252  --numInstsInROB;
253  --threadEntries[tid];
254 
255  head_inst->clearInROB();
256  head_inst->setCommitted();
257 
258  //Update "Global" Head of ROB
259  updateHead();
260 
261  // @todo: A special case is needed if the instruction being
262  // retired is the only instruction in the ROB; otherwise the tail
263  // iterator will become invalidated.
264  cpu->removeFrontInst(head_inst);
265 }
266 
267 bool
269 {
270  stats.reads++;
271  if (threadEntries[tid] != 0) {
272  return instList[tid].front()->readyToCommit();
273  }
274 
275  return false;
276 }
277 
278 bool
280 {
281  //@todo: set ActiveThreads through ROB or CPU
282  std::list<ThreadID>::iterator threads = activeThreads->begin();
284 
285  while (threads != end) {
286  ThreadID tid = *threads++;
287 
288  if (isHeadReady(tid)) {
289  return true;
290  }
291  }
292 
293  return false;
294 }
295 
296 unsigned
298 {
299  return numEntries - numInstsInROB;
300 }
301 
302 unsigned
304 {
305  return maxEntries[tid] - threadEntries[tid];
306 }
307 
308 void
310 {
311  stats.writes++;
312  DPRINTF(ROB, "[tid:%i] Squashing instructions until [sn:%llu].\n",
313  tid, squashedSeqNum[tid]);
314 
315  assert(squashIt[tid] != instList[tid].end());
316 
317  if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) {
318  DPRINTF(ROB, "[tid:%i] Done squashing instructions.\n",
319  tid);
320 
321  squashIt[tid] = instList[tid].end();
322 
323  doneSquashing[tid] = true;
324  return;
325  }
326 
327  bool robTailUpdate = false;
328 
329  unsigned int numInstsToSquash = squashWidth;
330 
331  // If the CPU is exiting, squash all of the instructions
332  // it is told to, even if that exceeds the squashWidth.
333  // Set the number to the number of entries (the max).
334  if (cpu->isThreadExiting(tid))
335  {
336  numInstsToSquash = numEntries;
337  }
338 
339  for (int numSquashed = 0;
340  numSquashed < numInstsToSquash &&
341  squashIt[tid] != instList[tid].end() &&
342  (*squashIt[tid])->seqNum > squashedSeqNum[tid];
343  ++numSquashed)
344  {
345  DPRINTF(ROB, "[tid:%i] Squashing instruction PC %s, seq num %i.\n",
346  (*squashIt[tid])->threadNumber,
347  (*squashIt[tid])->pcState(),
348  (*squashIt[tid])->seqNum);
349 
350  // Mark the instruction as squashed, and ready to commit so that
351  // it can drain out of the pipeline.
352  (*squashIt[tid])->setSquashed();
353 
354  (*squashIt[tid])->setCanCommit();
355 
356 
357  if (squashIt[tid] == instList[tid].begin()) {
358  DPRINTF(ROB, "Reached head of instruction list while "
359  "squashing.\n");
360 
361  squashIt[tid] = instList[tid].end();
362 
363  doneSquashing[tid] = true;
364 
365  return;
366  }
367 
368  InstIt tail_thread = instList[tid].end();
369  tail_thread--;
370 
371  if ((*squashIt[tid]) == (*tail_thread))
372  robTailUpdate = true;
373 
374  squashIt[tid]--;
375  }
376 
377 
378  // Check if ROB is done squashing.
379  if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) {
380  DPRINTF(ROB, "[tid:%i] Done squashing instructions.\n",
381  tid);
382 
383  squashIt[tid] = instList[tid].end();
384 
385  doneSquashing[tid] = true;
386  }
387 
388  if (robTailUpdate) {
389  updateTail();
390  }
391 }
392 
393 
394 void
396 {
397  InstSeqNum lowest_num = 0;
398  bool first_valid = true;
399 
400  // @todo: set ActiveThreads through ROB or CPU
401  std::list<ThreadID>::iterator threads = activeThreads->begin();
403 
404  while (threads != end) {
405  ThreadID tid = *threads++;
406 
407  if (instList[tid].empty())
408  continue;
409 
410  if (first_valid) {
411  head = instList[tid].begin();
412  lowest_num = (*head)->seqNum;
413  first_valid = false;
414  continue;
415  }
416 
417  InstIt head_thread = instList[tid].begin();
418 
419  DynInstPtr head_inst = (*head_thread);
420 
421  assert(head_inst != 0);
422 
423  if (head_inst->seqNum < lowest_num) {
424  head = head_thread;
425  lowest_num = head_inst->seqNum;
426  }
427  }
428 
429  if (first_valid) {
430  head = instList[0].end();
431  }
432 
433 }
434 
435 void
437 {
438  tail = instList[0].end();
439  bool first_valid = true;
440 
441  std::list<ThreadID>::iterator threads = activeThreads->begin();
443 
444  while (threads != end) {
445  ThreadID tid = *threads++;
446 
447  if (instList[tid].empty()) {
448  continue;
449  }
450 
451  // If this is the first valid then assign w/out
452  // comparison
453  if (first_valid) {
454  tail = instList[tid].end();
455  tail--;
456  first_valid = false;
457  continue;
458  }
459 
460  // Assign new tail if this thread's tail is younger
461  // than our current "tail high"
462  InstIt tail_thread = instList[tid].end();
463  tail_thread--;
464 
465  if ((*tail_thread)->seqNum > (*tail)->seqNum) {
466  tail = tail_thread;
467  }
468  }
469 }
470 
471 
472 void
474 {
475  if (isEmpty(tid)) {
476  DPRINTF(ROB, "Does not need to squash due to being empty "
477  "[sn:%llu]\n",
478  squash_num);
479 
480  return;
481  }
482 
483  DPRINTF(ROB, "Starting to squash within the ROB.\n");
484 
485  robStatus[tid] = ROBSquashing;
486 
487  doneSquashing[tid] = false;
488 
489  squashedSeqNum[tid] = squash_num;
490 
491  if (!instList[tid].empty()) {
492  InstIt tail_thread = instList[tid].end();
493  tail_thread--;
494 
495  squashIt[tid] = tail_thread;
496 
497  doSquash(tid);
498  }
499 }
500 
501 const DynInstPtr&
503 {
504  if (threadEntries[tid] != 0) {
505  InstIt head_thread = instList[tid].begin();
506 
507  assert((*head_thread)->isInROB());
508 
509  return *head_thread;
510  } else {
511  return dummyInst;
512  }
513 }
514 
517 {
518  InstIt tail_thread = instList[tid].end();
519  tail_thread--;
520 
521  return *tail_thread;
522 }
523 
525  : statistics::Group(parent, "rob"),
526  ADD_STAT(reads, statistics::units::Count::get(),
527  "The number of ROB reads"),
528  ADD_STAT(writes, statistics::units::Count::get(),
529  "The number of ROB writes")
530 {
531 }
532 
535 {
536  for (InstIt it = instList[tid].begin(); it != instList[tid].end(); it++) {
537  if ((*it)->seqNum == squash_inst) {
538  return *it;
539  }
540  }
541  return NULL;
542 }
543 
544 } // namespace o3
545 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
virtual std::string name() const
Definition: named.hh:47
O3CPU class, has each of the stages (fetch through commit) within it, as well as all of the time buff...
Definition: cpu.hh:94
bool isThreadExiting(ThreadID tid) const
Is the thread trying to exit?
Definition: cpu.cc:1480
void removeFrontInst(const DynInstPtr &inst)
Remove an instruction from the front end of the list.
Definition: cpu.cc:1243
Fetch class handles both single threaded and SMT fetch.
Definition: fetch.hh:79
ROB class.
Definition: rob.hh:72
bool canCommit()
Is there any commitable head instruction across all threads ready.
Definition: rob.cc:279
int countInsts()
This is more of a debugging function than anything.
Definition: rob.cc:180
void insertInst(const DynInstPtr &inst)
Function to insert an instruction into the ROB.
Definition: rob.cc:197
gem5::o3::ROB::ROBStats stats
unsigned numFreeEntries()
Returns the number of total free entries in the ROB.
Definition: rob.cc:297
void updateTail()
Updates the tail instruction with the new youngest instruction.
Definition: rob.cc:436
InstIt tail
Iterator pointing to the instruction which is the last instruction in the ROB.
Definition: rob.hh:299
void resetEntries()
Re-adjust ROB partitioning.
Definition: rob.cc:148
void squash(InstSeqNum squash_num, ThreadID tid)
Squashes all instructions younger than the given sequence number for the specific thread.
Definition: rob.cc:473
bool isHeadReady(ThreadID tid)
Is the oldest instruction across all threads ready.
Definition: rob.cc:268
ROB(CPU *_cpu, const BaseO3CPUParams &params)
ROB constructor.
Definition: rob.cc:58
void retireHead(ThreadID tid)
Retires the head instruction, removing it from the ROB.
Definition: rob.cc:234
std::list< DynInstPtr > instList[MaxThreads]
ROB List of Instructions.
Definition: rob.hh:289
std::string name() const
Definition: rob.cc:121
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.cc:534
@ ROBSquashing
Definition: rob.hh:82
InstSeqNum squashedSeqNum[MaxThreads]
The sequence number of the squashed instruction.
Definition: rob.hh:324
std::list< ThreadID > * activeThreads
Active Threads in CPU.
Definition: rob.hh:277
void updateHead()
Updates the head instruction with the new oldest instruction.
Definition: rob.cc:395
void drainSanityCheck() const
Perform sanity checks after a drain.
Definition: rob.cc:134
Status robStatus[MaxThreads]
Per-thread ROB status.
Definition: rob.hh:87
void doSquash(ThreadID tid)
Executes the squash, marking squashed instructions.
Definition: rob.cc:309
const DynInstPtr & readHeadInst(ThreadID tid)
Returns pointer to the head instruction within the ROB.
Definition: rob.cc:502
unsigned maxEntries[MaxThreads]
Max Insts a Thread Can Have in the ROB.
Definition: rob.hh:286
InstIt head
Iterator pointing to the instruction which is the first instruction in in the ROB.
Definition: rob.hh:303
int entryAmount(ThreadID num_threads)
Number of entries needed For 'num_threads' amount of threads.
Definition: rob.cc:170
SMTQueuePolicy robPolicy
ROB resource sharing policy for SMT mode.
Definition: rob.hh:90
DynInstPtr readTailInst(ThreadID tid)
Returns pointer to the tail instruction within the ROB.
Definition: rob.cc:516
InstIt squashIt[MaxThreads]
Iterator used for walking through the list of instructions when squashing.
Definition: rob.hh:313
void setActiveThreads(std::list< ThreadID > *at_ptr)
Sets pointer to the list of active threads.
Definition: rob.cc:127
unsigned numEntries
Number of instructions in the ROB.
Definition: rob.hh:280
void resetState()
Reset the ROB state.
Definition: rob.cc:104
ThreadID numThreads
Number of active threads.
Definition: rob.hh:330
bool doneSquashing[MaxThreads]
Is the ROB done squashing.
Definition: rob.hh:327
CPU * cpu
Pointer to the CPU.
Definition: rob.hh:274
unsigned squashWidth
Number of instructions that can be squashed in a single cycle.
Definition: rob.hh:292
std::list< DynInstPtr >::iterator InstIt
Definition: rob.hh:75
bool isEmpty() const
Returns if the ROB is empty.
Definition: rob.hh:194
void takeOverFrom()
Takes over another CPU's thread.
Definition: rob.cc:142
DynInstPtr dummyInst
Dummy instruction returned if there are no insts left.
Definition: rob.hh:320
int numInstsInROB
Number of instructions in the ROB.
Definition: rob.hh:317
unsigned threadEntries[MaxThreads]
Entries Per Thread.
Definition: rob.hh:283
Statistics container.
Definition: group.hh:94
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
static constexpr int MaxThreads
Definition: limits.hh:38
const FlagsType total
Print the total.
Definition: info.hh:60
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
int16_t ThreadID
Thread index/ID type.
Definition: types.hh:235
uint64_t InstSeqNum
Definition: inst_seq.hh:40
ROBStats(statistics::Group *parent)
Definition: rob.cc:524
statistics::Scalar reads
Definition: rob.hh:338
statistics::Scalar writes
Definition: rob.hh:340

Generated on Wed Dec 21 2022 10:22:31 for gem5 by doxygen 1.9.1