rob_impl.hh revision 1681
1#ifndef __CPU_BETA_CPU_ROB_IMPL_HH__ 2#define __CPU_BETA_CPU_ROB_IMPL_HH__ 3 4#include "cpu/beta_cpu/rob.hh" 5 6template <class Impl> 7ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth) 8 : numEntries(_numEntries), 9 squashWidth(_squashWidth), 10 numInstsInROB(0), 11 squashedSeqNum(0) 12{ 13 doneSquashing = true; 14} 15 16template <class Impl> 17void 18ROB<Impl>::setCPU(FullCPU *cpu_ptr) 19{ 20 cpu = cpu_ptr; 21 22 // Set the tail to the beginning of the CPU instruction list so that 23 // upon the first instruction being inserted into the ROB, the tail 24 // iterator can simply be incremented. 25 tail = cpu->instList.begin(); 26 27 // Set the squash iterator to the end of the instruction list. 28 squashIt = cpu->instList.end(); 29} 30 31template <class Impl> 32int 33ROB<Impl>::countInsts() 34{ 35 // Start at 1; if the tail matches cpu->instList.begin(), then there is 36 // one inst in the ROB. 37 int return_val = 1; 38 39 // There are quite a few special cases. Do not use this function other 40 // than for debugging purposes. 41 if (cpu->instList.begin() == cpu->instList.end()) { 42 // In this case there are no instructions in the list. The ROB 43 // must be empty. 44 return 0; 45 } else if (tail == cpu->instList.end()) { 46 // In this case, the tail is not yet pointing to anything valid. 47 // The ROB must be empty. 48 return 0; 49 } 50 51 // Iterate through the ROB from the head to the tail, counting the 52 // entries. 53 for (InstIt_t i = cpu->instList.begin(); i != tail; ++i) 54 { 55 assert(i != cpu->instList.end()); 56 ++return_val; 57 } 58 59 return return_val; 60 61 // Because the head won't be tracked properly until the ROB gets the 62 // first instruction, and any time that the ROB is empty and has not 63 // yet gotten the instruction, this function doesn't work. 64// return numInstsInROB; 65} 66 67template <class Impl> 68void 69ROB<Impl>::insertInst(DynInstPtr &inst) 70{ 71 // Make sure we have the right number of instructions. 72 assert(numInstsInROB == countInsts()); 73 // Make sure the instruction is valid. 74 assert(inst); 75 76 DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC()); 77 78 // If the ROB is full then exit. 79 assert(numInstsInROB != numEntries); 80 81 ++numInstsInROB; 82 83 // Increment the tail iterator, moving it one instruction back. 84 // There is a special case if the ROB was empty prior to this insertion, 85 // in which case the tail will be pointing at instList.end(). If that 86 // happens, then reset the tail to the beginning of the list. 87 if (tail != cpu->instList.end()) { 88 ++tail; 89 } else { 90 tail = cpu->instList.begin(); 91 } 92 93 // Make sure the tail iterator is actually pointing at the instruction 94 // added. 95 assert((*tail) == inst); 96 97 DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB); 98 99} 100 101// Whatever calls this function needs to ensure that it properly frees up 102// registers prior to this function. 103template <class Impl> 104void 105ROB<Impl>::retireHead() 106{ 107 assert(numInstsInROB == countInsts()); 108 assert(numInstsInROB > 0); 109 110 // Get the head ROB instruction. 111 DynInstPtr head_inst = cpu->instList.front(); 112 113 // Make certain this can retire. 114 assert(head_inst->readyToCommit()); 115 116 DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, " 117 "instruction PC %#x, seq num %i\n", head_inst->readPC(), 118 head_inst->seqNum); 119 120 // Keep track of how many instructions are in the ROB. 121 --numInstsInROB; 122 123 // Tell CPU to remove the instruction from the list of instructions. 124 // A special case is needed if the instruction being retired is the 125 // only instruction in the ROB; otherwise the tail iterator will become 126 // invalidated. 127 cpu->removeFrontInst(head_inst); 128 129 if (numInstsInROB == 0) { 130 tail = cpu->instList.end(); 131 } 132} 133 134template <class Impl> 135bool 136ROB<Impl>::isHeadReady() 137{ 138 if (numInstsInROB != 0) { 139 return cpu->instList.front()->readyToCommit(); 140 } 141 142 return false; 143} 144 145template <class Impl> 146unsigned 147ROB<Impl>::numFreeEntries() 148{ 149 assert(numInstsInROB == countInsts()); 150 151 return numEntries - numInstsInROB; 152} 153 154template <class Impl> 155void 156ROB<Impl>::doSquash() 157{ 158 DPRINTF(ROB, "ROB: Squashing instructions.\n"); 159 160 assert(squashIt != cpu->instList.end()); 161 162 for (int numSquashed = 0; 163 numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum; 164 ++numSquashed) 165 { 166 // Ensure that the instruction is younger. 167 assert((*squashIt)->seqNum > squashedSeqNum); 168 169 DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n", 170 (*squashIt)->readPC(), (*squashIt)->seqNum); 171 172 // Mark the instruction as squashed, and ready to commit so that 173 // it can drain out of the pipeline. 174 (*squashIt)->setSquashed(); 175 176 (*squashIt)->setCanCommit(); 177 178 // Special case for when squashing due to a syscall. It's possible 179 // that the squash happened after the head instruction was already 180 // committed, meaning that (*squashIt)->seqNum != squashedSeqNum 181 // will never be false. Normally the squash would never be able 182 // to go past the head of the ROB; in this case it might, so it 183 // must be handled otherwise it will segfault. 184#ifndef FULL_SYSTEM 185 if (squashIt == cpu->instList.begin()) { 186 DPRINTF(ROB, "ROB: Reached head of instruction list while " 187 "squashing.\n"); 188 189 squashIt = cpu->instList.end(); 190 191 doneSquashing = true; 192 193 return; 194 } 195#endif 196 197 // Move the tail iterator to the next instruction. 198 squashIt--; 199 } 200 201 202 // Check if ROB is done squashing. 203 if ((*squashIt)->seqNum == squashedSeqNum) { 204 DPRINTF(ROB, "ROB: Done squashing instructions.\n"); 205 206 squashIt = cpu->instList.end(); 207 208 doneSquashing = true; 209 } 210} 211 212template <class Impl> 213void 214ROB<Impl>::squash(InstSeqNum squash_num) 215{ 216 DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n"); 217 doneSquashing = false; 218 219 squashedSeqNum = squash_num; 220 221 assert(tail != cpu->instList.end()); 222 223 squashIt = tail; 224 225 doSquash(); 226} 227 228template <class Impl> 229uint64_t 230ROB<Impl>::readHeadPC() 231{ 232 assert(numInstsInROB == countInsts()); 233 234 DynInstPtr head_inst = cpu->instList.front(); 235 236 return head_inst->readPC(); 237} 238 239template <class Impl> 240uint64_t 241ROB<Impl>::readHeadNextPC() 242{ 243 assert(numInstsInROB == countInsts()); 244 245 DynInstPtr head_inst = cpu->instList.front(); 246 247 return head_inst->readNextPC(); 248} 249 250template <class Impl> 251InstSeqNum 252ROB<Impl>::readHeadSeqNum() 253{ 254 // Return the last sequence number that has not been squashed. Other 255 // stages can use it to squash any instructions younger than the current 256 // tail. 257 DynInstPtr head_inst = cpu->instList.front(); 258 259 return head_inst->seqNum; 260} 261 262template <class Impl> 263uint64_t 264ROB<Impl>::readTailPC() 265{ 266 assert(numInstsInROB == countInsts()); 267 268 assert(tail != cpu->instList.end()); 269 270 return (*tail)->readPC(); 271} 272 273template <class Impl> 274InstSeqNum 275ROB<Impl>::readTailSeqNum() 276{ 277 // Return the last sequence number that has not been squashed. Other 278 // stages can use it to squash any instructions younger than the current 279 // tail. 280 return (*tail)->seqNum; 281} 282 283#endif // __CPU_BETA_CPU_ROB_IMPL_HH__ 284