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