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

Generated on Fri Jul 3 2020 15:53:00 for gem5 by doxygen 1.8.13