decode_impl.hh revision 2665:a124942bacb8
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 * Authors: Kevin Lim 29 */ 30 31#include "cpu/o3/decode.hh" 32 33template<class Impl> 34SimpleDecode<Impl>::SimpleDecode(Params ¶ms) 35 : renameToDecodeDelay(params.renameToDecodeDelay), 36 iewToDecodeDelay(params.iewToDecodeDelay), 37 commitToDecodeDelay(params.commitToDecodeDelay), 38 fetchToDecodeDelay(params.fetchToDecodeDelay), 39 decodeWidth(params.decodeWidth), 40 numInst(0) 41{ 42 DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth); 43 _status = Idle; 44} 45 46template <class Impl> 47void 48SimpleDecode<Impl>::regStats() 49{ 50 decodeIdleCycles 51 .name(name() + ".decodeIdleCycles") 52 .desc("Number of cycles decode is idle") 53 .prereq(decodeIdleCycles); 54 decodeBlockedCycles 55 .name(name() + ".decodeBlockedCycles") 56 .desc("Number of cycles decode is blocked") 57 .prereq(decodeBlockedCycles); 58 decodeUnblockCycles 59 .name(name() + ".decodeUnblockCycles") 60 .desc("Number of cycles decode is unblocking") 61 .prereq(decodeUnblockCycles); 62 decodeSquashCycles 63 .name(name() + ".decodeSquashCycles") 64 .desc("Number of cycles decode is squashing") 65 .prereq(decodeSquashCycles); 66 decodeBranchMispred 67 .name(name() + ".decodeBranchMispred") 68 .desc("Number of times decode detected a branch misprediction") 69 .prereq(decodeBranchMispred); 70 decodeControlMispred 71 .name(name() + ".decodeControlMispred") 72 .desc("Number of times decode detected an instruction incorrectly" 73 " predicted as a control") 74 .prereq(decodeControlMispred); 75 decodeDecodedInsts 76 .name(name() + ".decodeDecodedInsts") 77 .desc("Number of instructions handled by decode") 78 .prereq(decodeDecodedInsts); 79 decodeSquashedInsts 80 .name(name() + ".decodeSquashedInsts") 81 .desc("Number of squashed instructions handled by decode") 82 .prereq(decodeSquashedInsts); 83} 84 85template<class Impl> 86void 87SimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr) 88{ 89 DPRINTF(Decode, "Decode: Setting CPU pointer.\n"); 90 cpu = cpu_ptr; 91} 92 93template<class Impl> 94void 95SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 96{ 97 DPRINTF(Decode, "Decode: Setting time buffer pointer.\n"); 98 timeBuffer = tb_ptr; 99 100 // Setup wire to write information back to fetch. 101 toFetch = timeBuffer->getWire(0); 102 103 // Create wires to get information from proper places in time buffer. 104 fromRename = timeBuffer->getWire(-renameToDecodeDelay); 105 fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 106 fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 107} 108 109template<class Impl> 110void 111SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 112{ 113 DPRINTF(Decode, "Decode: Setting decode queue pointer.\n"); 114 decodeQueue = dq_ptr; 115 116 // Setup wire to write information to proper place in decode queue. 117 toRename = decodeQueue->getWire(0); 118} 119 120template<class Impl> 121void 122SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 123{ 124 DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n"); 125 fetchQueue = fq_ptr; 126 127 // Setup wire to read information from fetch queue. 128 fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 129} 130 131template<class Impl> 132inline bool 133SimpleDecode<Impl>::fetchInstsValid() 134{ 135 return fromFetch->size > 0; 136} 137 138template<class Impl> 139void 140SimpleDecode<Impl>::block() 141{ 142 DPRINTF(Decode, "Decode: Blocking.\n"); 143 144 // Set the status to Blocked. 145 _status = Blocked; 146 147 // Add the current inputs to the skid buffer so they can be 148 // reprocessed when this stage unblocks. 149 skidBuffer.push(*fromFetch); 150 151 // Note that this stage only signals previous stages to stall when 152 // it is the cause of the stall originates at this stage. Otherwise 153 // the previous stages are expected to check all possible stall signals. 154} 155 156template<class Impl> 157inline void 158SimpleDecode<Impl>::unblock() 159{ 160 DPRINTF(Decode, "Decode: Unblocking, going to remove " 161 "instructions from skid buffer.\n"); 162 // Remove the now processed instructions from the skid buffer. 163 skidBuffer.pop(); 164 165 // If there's still information in the skid buffer, then 166 // continue to tell previous stages to stall. They will be 167 // able to restart once the skid buffer is empty. 168 if (!skidBuffer.empty()) { 169 toFetch->decodeInfo.stall = true; 170 } else { 171 DPRINTF(Decode, "Decode: Finished unblocking.\n"); 172 _status = Running; 173 } 174} 175 176// This squash is specifically for when Decode detects a PC-relative branch 177// was predicted incorrectly. 178template<class Impl> 179void 180SimpleDecode<Impl>::squash(DynInstPtr &inst) 181{ 182 DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction " 183 "detected at decode.\n"); 184 Addr new_PC = inst->readNextPC(); 185 186 toFetch->decodeInfo.branchMispredict = true; 187 toFetch->decodeInfo.doneSeqNum = inst->seqNum; 188 toFetch->decodeInfo.predIncorrect = true; 189 toFetch->decodeInfo.squash = true; 190 toFetch->decodeInfo.nextPC = new_PC; 191 toFetch->decodeInfo.branchTaken = true; 192 193 // Set status to squashing. 194 _status = Squashing; 195 196 // Clear the skid buffer in case it has any data in it. 197 while (!skidBuffer.empty()) { 198 skidBuffer.pop(); 199 } 200 201 // Squash instructions up until this one 202 // Slightly unrealistic! 203 cpu->removeInstsUntil(inst->seqNum); 204} 205 206template<class Impl> 207void 208SimpleDecode<Impl>::squash() 209{ 210 DPRINTF(Decode, "Decode: Squashing.\n"); 211 // Set status to squashing. 212 _status = Squashing; 213 214 // Maybe advance the time buffer? Not sure what to do in the normal 215 // case. 216 217 // Clear the skid buffer in case it has any data in it. 218 while (!skidBuffer.empty()) 219 { 220 skidBuffer.pop(); 221 } 222} 223 224template<class Impl> 225void 226SimpleDecode<Impl>::tick() 227{ 228 // Decode should try to execute as many instructions as its bandwidth 229 // will allow, as long as it is not currently blocked. 230 if (_status != Blocked && _status != Squashing) { 231 DPRINTF(Decode, "Decode: Not blocked, so attempting to run " 232 "stage.\n"); 233 // Make sure that the skid buffer has something in it if the 234 // status is unblocking. 235 assert(_status == Unblocking ? !skidBuffer.empty() : 1); 236 237 decode(); 238 239 // If the status was unblocking, then instructions from the skid 240 // buffer were used. Remove those instructions and handle 241 // the rest of unblocking. 242 if (_status == Unblocking) { 243 ++decodeUnblockCycles; 244 245 if (fetchInstsValid()) { 246 // Add the current inputs to the skid buffer so they can be 247 // reprocessed when this stage unblocks. 248 skidBuffer.push(*fromFetch); 249 } 250 251 unblock(); 252 } 253 } else if (_status == Blocked) { 254 ++decodeBlockedCycles; 255 256 if (fetchInstsValid()) { 257 block(); 258 } 259 260 if (!fromRename->renameInfo.stall && 261 !fromIEW->iewInfo.stall && 262 !fromCommit->commitInfo.stall) { 263 DPRINTF(Decode, "Decode: Stall signals cleared, going to " 264 "unblock.\n"); 265 _status = Unblocking; 266 267 // Continue to tell previous stage to block until this 268 // stage is done unblocking. 269 toFetch->decodeInfo.stall = true; 270 } else { 271 DPRINTF(Decode, "Decode: Still blocked.\n"); 272 toFetch->decodeInfo.stall = true; 273 } 274 275 if (fromCommit->commitInfo.squash || 276 fromCommit->commitInfo.robSquashing) { 277 squash(); 278 } 279 } else if (_status == Squashing) { 280 if (!fromCommit->commitInfo.squash && 281 !fromCommit->commitInfo.robSquashing) { 282 _status = Running; 283 } else if (fromCommit->commitInfo.squash) { 284 ++decodeSquashCycles; 285 286 squash(); 287 } 288 } 289} 290 291template<class Impl> 292void 293SimpleDecode<Impl>::decode() 294{ 295 // Check time buffer if being told to squash. 296 if (fromCommit->commitInfo.squash) { 297 squash(); 298 return; 299 } 300 301 // Check time buffer if being told to stall. 302 if (fromRename->renameInfo.stall || 303 fromIEW->iewInfo.stall || 304 fromCommit->commitInfo.stall) { 305 block(); 306 return; 307 } 308 309 // Check fetch queue to see if instructions are available. 310 // If no available instructions, do nothing, unless this stage is 311 // currently unblocking. 312 if (!fetchInstsValid() && _status != Unblocking) { 313 DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); 314 // Should I change the status to idle? 315 ++decodeIdleCycles; 316 return; 317 } 318 319 // Might be better to use a base DynInst * instead? 320 DynInstPtr inst; 321 322 unsigned to_rename_index = 0; 323 324 int insts_available = _status == Unblocking ? 325 skidBuffer.front().size - numInst : 326 fromFetch->size; 327 328 // Debug block... 329#if 0 330 if (insts_available) { 331 DPRINTF(Decode, "Decode: Instructions available.\n"); 332 } else { 333 if (_status == Unblocking && skidBuffer.empty()) { 334 DPRINTF(Decode, "Decode: No instructions available, skid buffer " 335 "empty.\n"); 336 } else if (_status != Unblocking && 337 !fromFetch->insts[0]) { 338 DPRINTF(Decode, "Decode: No instructions available, fetch queue " 339 "empty.\n"); 340 } else { 341 panic("Decode: No instructions available, unexpected condition!" 342 "\n"); 343 } 344 } 345#endif 346 347 while (insts_available > 0) 348 { 349 DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); 350 351 inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : 352 fromFetch->insts[numInst]; 353 354 DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n", 355 inst->seqNum, inst->readPC()); 356 357 if (inst->isSquashed()) { 358 DPRINTF(Decode, "Decode: Instruction %i with PC %#x is " 359 "squashed, skipping.\n", 360 inst->seqNum, inst->readPC()); 361 362 ++decodeSquashedInsts; 363 364 ++numInst; 365 --insts_available; 366 367 continue; 368 } 369 370 371 // Also check if instructions have no source registers. Mark 372 // them as ready to issue at any time. Not sure if this check 373 // should exist here or at a later stage; however it doesn't matter 374 // too much for function correctness. 375 // Isn't this handled by the inst queue? 376 if (inst->numSrcRegs() == 0) { 377 inst->setCanIssue(); 378 } 379 380 // This current instruction is valid, so add it into the decode 381 // queue. The next instruction may not be valid, so check to 382 // see if branches were predicted correctly. 383 toRename->insts[to_rename_index] = inst; 384 385 ++(toRename->size); 386 387 // Ensure that if it was predicted as a branch, it really is a 388 // branch. 389 if (inst->predTaken() && !inst->isControl()) { 390 panic("Instruction predicted as a branch!"); 391 392 ++decodeControlMispred; 393 // Might want to set some sort of boolean and just do 394 // a check at the end 395 squash(inst); 396 break; 397 } 398 399 // Go ahead and compute any PC-relative branches. 400 401 if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 402 403 inst->setNextPC(inst->branchTarget()); 404 405 if (inst->mispredicted()) { 406 ++decodeBranchMispred; 407 // Might want to set some sort of boolean and just do 408 // a check at the end 409 squash(inst); 410 break; 411 } 412 } 413 414 // Normally can check if a direct branch has the right target 415 // addr (either the immediate, or the branch PC + 4) and redirect 416 // fetch if it's incorrect. 417 418 // Increment which instruction we're looking at. 419 ++numInst; 420 ++to_rename_index; 421 ++decodeDecodedInsts; 422 423 --insts_available; 424 } 425 426 numInst = 0; 427} 428