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