rob_impl.hh revision 1717
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#ifndef __CPU_BETA_CPU_ROB_IMPL_HH__ 30#define __CPU_BETA_CPU_ROB_IMPL_HH__ 31 32#include "cpu/o3/rob.hh" 33 34template <class Impl> 35ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth) 36 : numEntries(_numEntries), 37 squashWidth(_squashWidth), 38 numInstsInROB(0), 39 squashedSeqNum(0) 40{ 41 doneSquashing = true; 42} 43 44template <class Impl> 45void 46ROB<Impl>::setCPU(FullCPU *cpu_ptr) 47{ 48 cpu = cpu_ptr; 49 50 // Set the tail to the beginning of the CPU instruction list so that 51 // upon the first instruction being inserted into the ROB, the tail 52 // iterator can simply be incremented. 53 tail = cpu->instList.begin(); 54 55 // Set the squash iterator to the end of the instruction list. 56 squashIt = cpu->instList.end(); 57} 58 59template <class Impl> 60int 61ROB<Impl>::countInsts() 62{ 63 // Start at 1; if the tail matches cpu->instList.begin(), then there is 64 // one inst in the ROB. 65 int return_val = 1; 66 67 // There are quite a few special cases. Do not use this function other 68 // than for debugging purposes. 69 if (cpu->instList.begin() == cpu->instList.end()) { 70 // In this case there are no instructions in the list. The ROB 71 // must be empty. 72 return 0; 73 } else if (tail == cpu->instList.end()) { 74 // In this case, the tail is not yet pointing to anything valid. 75 // The ROB must be empty. 76 return 0; 77 } 78 79 // Iterate through the ROB from the head to the tail, counting the 80 // entries. 81 for (InstIt_t i = cpu->instList.begin(); i != tail; ++i) 82 { 83 assert(i != cpu->instList.end()); 84 ++return_val; 85 } 86 87 return return_val; 88 89 // Because the head won't be tracked properly until the ROB gets the 90 // first instruction, and any time that the ROB is empty and has not 91 // yet gotten the instruction, this function doesn't work. 92// return numInstsInROB; 93} 94 95template <class Impl> 96void 97ROB<Impl>::insertInst(DynInstPtr &inst) 98{ 99 // Make sure we have the right number of instructions. 100 assert(numInstsInROB == countInsts()); 101 // Make sure the instruction is valid. 102 assert(inst); 103 104 DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC()); 105 106 // If the ROB is full then exit. 107 assert(numInstsInROB != numEntries); 108 109 ++numInstsInROB; 110 111 // Increment the tail iterator, moving it one instruction back. 112 // There is a special case if the ROB was empty prior to this insertion, 113 // in which case the tail will be pointing at instList.end(). If that 114 // happens, then reset the tail to the beginning of the list. 115 if (tail != cpu->instList.end()) { 116 ++tail; 117 } else { 118 tail = cpu->instList.begin(); 119 } 120 121 // Make sure the tail iterator is actually pointing at the instruction 122 // added. 123 assert((*tail) == inst); 124 125 DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB); 126 127} 128 129// Whatever calls this function needs to ensure that it properly frees up 130// registers prior to this function. 131template <class Impl> 132void 133ROB<Impl>::retireHead() 134{ 135 assert(numInstsInROB == countInsts()); 136 assert(numInstsInROB > 0); 137 138 // Get the head ROB instruction. 139 DynInstPtr head_inst = cpu->instList.front(); 140 141 // Make certain this can retire. 142 assert(head_inst->readyToCommit()); 143 144 DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, " 145 "instruction PC %#x, seq num %i\n", head_inst->readPC(), 146 head_inst->seqNum); 147 148 // Keep track of how many instructions are in the ROB. 149 --numInstsInROB; 150 151 // Tell CPU to remove the instruction from the list of instructions. 152 // A special case is needed if the instruction being retired is the 153 // only instruction in the ROB; otherwise the tail iterator will become 154 // invalidated. 155 cpu->removeFrontInst(head_inst); 156 157 if (numInstsInROB == 0) { 158 tail = cpu->instList.end(); 159 } 160} 161 162template <class Impl> 163bool 164ROB<Impl>::isHeadReady() 165{ 166 if (numInstsInROB != 0) { 167 return cpu->instList.front()->readyToCommit(); 168 } 169 170 return false; 171} 172 173template <class Impl> 174unsigned 175ROB<Impl>::numFreeEntries() 176{ 177 assert(numInstsInROB == countInsts()); 178 179 return numEntries - numInstsInROB; 180} 181 182template <class Impl> 183void 184ROB<Impl>::doSquash() 185{ 186 DPRINTF(ROB, "ROB: Squashing instructions.\n"); 187 188 assert(squashIt != cpu->instList.end()); 189 190 for (int numSquashed = 0; 191 numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum; 192 ++numSquashed) 193 { 194 // Ensure that the instruction is younger. 195 assert((*squashIt)->seqNum > squashedSeqNum); 196 197 DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n", 198 (*squashIt)->readPC(), (*squashIt)->seqNum); 199 200 // Mark the instruction as squashed, and ready to commit so that 201 // it can drain out of the pipeline. 202 (*squashIt)->setSquashed(); 203 204 (*squashIt)->setCanCommit(); 205 206 // Special case for when squashing due to a syscall. It's possible 207 // that the squash happened after the head instruction was already 208 // committed, meaning that (*squashIt)->seqNum != squashedSeqNum 209 // will never be false. Normally the squash would never be able 210 // to go past the head of the ROB; in this case it might, so it 211 // must be handled otherwise it will segfault. 212#ifndef FULL_SYSTEM 213 if (squashIt == cpu->instList.begin()) { 214 DPRINTF(ROB, "ROB: Reached head of instruction list while " 215 "squashing.\n"); 216 217 squashIt = cpu->instList.end(); 218 219 doneSquashing = true; 220 221 return; 222 } 223#endif 224 225 // Move the tail iterator to the next instruction. 226 squashIt--; 227 } 228 229 230 // Check if ROB is done squashing. 231 if ((*squashIt)->seqNum == squashedSeqNum) { 232 DPRINTF(ROB, "ROB: Done squashing instructions.\n"); 233 234 squashIt = cpu->instList.end(); 235 236 doneSquashing = true; 237 } 238} 239 240template <class Impl> 241void 242ROB<Impl>::squash(InstSeqNum squash_num) 243{ 244 DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n"); 245 doneSquashing = false; 246 247 squashedSeqNum = squash_num; 248 249 assert(tail != cpu->instList.end()); 250 251 squashIt = tail; 252 253 doSquash(); 254} 255 256template <class Impl> 257uint64_t 258ROB<Impl>::readHeadPC() 259{ 260 assert(numInstsInROB == countInsts()); 261 262 DynInstPtr head_inst = cpu->instList.front(); 263 264 return head_inst->readPC(); 265} 266 267template <class Impl> 268uint64_t 269ROB<Impl>::readHeadNextPC() 270{ 271 assert(numInstsInROB == countInsts()); 272 273 DynInstPtr head_inst = cpu->instList.front(); 274 275 return head_inst->readNextPC(); 276} 277 278template <class Impl> 279InstSeqNum 280ROB<Impl>::readHeadSeqNum() 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 DynInstPtr head_inst = cpu->instList.front(); 286 287 return head_inst->seqNum; 288} 289 290template <class Impl> 291uint64_t 292ROB<Impl>::readTailPC() 293{ 294 assert(numInstsInROB == countInsts()); 295 296 assert(tail != cpu->instList.end()); 297 298 return (*tail)->readPC(); 299} 300 301template <class Impl> 302InstSeqNum 303ROB<Impl>::readTailSeqNum() 304{ 305 // Return the last sequence number that has not been squashed. Other 306 // stages can use it to squash any instructions younger than the current 307 // tail. 308 return (*tail)->seqNum; 309} 310 311#endif // __CPU_BETA_CPU_ROB_IMPL_HH__ 312