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