rob_impl.hh revision 1062
1#ifndef __ROB_IMPL_HH__ 2#define __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 DynInstPtr head_inst; 111 112 // Get the head ROB instruction. 113 head_inst = cpu->instList.front(); 114 115 // Make certain this can retire. 116 assert(head_inst->readyToCommit()); 117 118 DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, " 119 "instruction PC %#x, seq num %i\n", head_inst->readPC(), 120 head_inst->seqNum); 121 122 // Keep track of how many instructions are in the ROB. 123 --numInstsInROB; 124 125 // Tell CPU to remove the instruction from the list of instructions. 126 // A special case is needed if the instruction being retired is the 127 // only instruction in the ROB; otherwise the tail iterator will become 128 // invalidated. 129 if (tail == cpu->instList.begin()) { 130 cpu->removeFrontInst(head_inst); 131 tail = cpu->instList.end(); 132 } else { 133 cpu->removeFrontInst(head_inst); 134 } 135} 136 137template <class Impl> 138bool 139ROB<Impl>::isHeadReady() 140{ 141 if (numInstsInROB != 0) { 142 return cpu->instList.front()->readyToCommit(); 143 } 144 145 return false; 146} 147 148template <class Impl> 149unsigned 150ROB<Impl>::numFreeEntries() 151{ 152 assert(numInstsInROB == countInsts()); 153 154 return numEntries - numInstsInROB; 155} 156 157template <class Impl> 158void 159ROB<Impl>::doSquash() 160{ 161 DPRINTF(ROB, "ROB: Squashing instructions.\n"); 162 163 assert(squashIt != cpu->instList.end()); 164 165 for (int numSquashed = 0; 166 numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum; 167 ++numSquashed) 168 { 169 // Ensure that the instruction is younger. 170 assert((*squashIt)->seqNum > squashedSeqNum); 171 172 DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n", 173 (*squashIt)->readPC(), (*squashIt)->seqNum); 174 175 // Mark the instruction as squashed, and ready to commit so that 176 // it can drain out of the pipeline. 177 (*squashIt)->setSquashed(); 178 179 (*squashIt)->setCanCommit(); 180 181 // Special case for when squashing due to a syscall. It's possible 182 // that the squash happened after the head instruction was already 183 // committed, meaning that (*squashIt)->seqNum != squashedSeqNum 184 // will never be false. Normally the squash would never be able 185 // to go past the head of the ROB; in this case it might, so it 186 // must be handled otherwise it will segfault. 187#ifndef FULL_SYSTEM 188 if (squashIt == cpu->instList.begin()) { 189 DPRINTF(ROB, "ROB: Reached head of instruction list while " 190 "squashing.\n"); 191 192 squashIt = cpu->instList.end(); 193 194 doneSquashing = true; 195 196 return; 197 } 198#endif 199 200 // Move the tail iterator to the next instruction. 201 squashIt--; 202 } 203 204 205 // Check if ROB is done squashing. 206 if ((*squashIt)->seqNum == squashedSeqNum) { 207 DPRINTF(ROB, "ROB: Done squashing instructions.\n"); 208 209 squashIt = cpu->instList.end(); 210 211 doneSquashing = true; 212 } 213} 214 215template <class Impl> 216void 217ROB<Impl>::squash(InstSeqNum squash_num) 218{ 219 DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n"); 220 doneSquashing = false; 221 222 squashedSeqNum = squash_num; 223 224 assert(tail != cpu->instList.end()); 225 226 squashIt = tail; 227 228 doSquash(); 229} 230 231template <class Impl> 232uint64_t 233ROB<Impl>::readHeadPC() 234{ 235 assert(numInstsInROB == countInsts()); 236 237 DynInstPtr head_inst = cpu->instList.front(); 238 239 return head_inst->readPC(); 240} 241 242template <class Impl> 243uint64_t 244ROB<Impl>::readHeadNextPC() 245{ 246 assert(numInstsInROB == countInsts()); 247 248 DynInstPtr head_inst = cpu->instList.front(); 249 250 return head_inst->readNextPC(); 251} 252 253template <class Impl> 254InstSeqNum 255ROB<Impl>::readHeadSeqNum() 256{ 257 // Return the last sequence number that has not been squashed. Other 258 // stages can use it to squash any instructions younger than the current 259 // tail. 260 DynInstPtr head_inst = cpu->instList.front(); 261 262 return head_inst->seqNum; 263} 264 265template <class Impl> 266uint64_t 267ROB<Impl>::readTailPC() 268{ 269 assert(numInstsInROB == countInsts()); 270 271 assert(tail != cpu->instList.end()); 272 273 return (*tail)->readPC(); 274} 275 276template <class Impl> 277InstSeqNum 278ROB<Impl>::readTailSeqNum() 279{ 280 // Return the last sequence number that has not been squashed. Other 281 // stages can use it to squash any instructions younger than the current 282 // tail. 283 return (*tail)->seqNum; 284} 285 286#endif // __ROB_IMPL_HH__ 287