decode_impl.hh revision 1061
111731Sjason@lowepower.com#ifndef __SIMPLE_DECODE_CC__ 211731Sjason@lowepower.com#define __SIMPLE_DECODE_CC__ 311731Sjason@lowepower.com 411731Sjason@lowepower.com#include "cpu/beta_cpu/decode.hh" 511731Sjason@lowepower.com 612137Sar4jc@virginia.edutemplate<class Impl> 712137Sar4jc@virginia.eduSimpleDecode<Impl>::SimpleDecode(Params ¶ms) 812137Sar4jc@virginia.edu : renameToDecodeDelay(params.renameToDecodeDelay), 912137Sar4jc@virginia.edu iewToDecodeDelay(params.iewToDecodeDelay), 1011731Sjason@lowepower.com commitToDecodeDelay(params.commitToDecodeDelay), 1111731Sjason@lowepower.com fetchToDecodeDelay(params.fetchToDecodeDelay), 1211731Sjason@lowepower.com decodeWidth(params.decodeWidth), 1311731Sjason@lowepower.com numInst(0) 1411731Sjason@lowepower.com{ 1511731Sjason@lowepower.com DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth); 1611731Sjason@lowepower.com _status = Idle; 1711731Sjason@lowepower.com} 1811731Sjason@lowepower.com 1911731Sjason@lowepower.comtemplate<class Impl> 2011731Sjason@lowepower.comvoid 2111731Sjason@lowepower.comSimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr) 2211731Sjason@lowepower.com{ 2311731Sjason@lowepower.com DPRINTF(Decode, "Decode: Setting CPU pointer.\n"); 2411731Sjason@lowepower.com cpu = cpu_ptr; 2511731Sjason@lowepower.com} 2611731Sjason@lowepower.com 2711731Sjason@lowepower.comtemplate<class Impl> 2811731Sjason@lowepower.comvoid 2911731Sjason@lowepower.comSimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 3011731Sjason@lowepower.com{ 3111731Sjason@lowepower.com DPRINTF(Decode, "Decode: Setting time buffer pointer.\n"); 3211731Sjason@lowepower.com timeBuffer = tb_ptr; 3311731Sjason@lowepower.com 3411731Sjason@lowepower.com // Setup wire to write information back to fetch. 3511731Sjason@lowepower.com toFetch = timeBuffer->getWire(0); 3611731Sjason@lowepower.com 3711731Sjason@lowepower.com // Create wires to get information from proper places in time buffer. 3811731Sjason@lowepower.com fromRename = timeBuffer->getWire(-renameToDecodeDelay); 3911731Sjason@lowepower.com fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 4011731Sjason@lowepower.com fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 4111731Sjason@lowepower.com} 4211731Sjason@lowepower.com 4311731Sjason@lowepower.comtemplate<class Impl> 4411731Sjason@lowepower.comvoid 4511731Sjason@lowepower.comSimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 4611731Sjason@lowepower.com{ 4712137Sar4jc@virginia.edu DPRINTF(Decode, "Decode: Setting decode queue pointer.\n"); 48 decodeQueue = dq_ptr; 49 50 // Setup wire to write information to proper place in decode queue. 51 toRename = decodeQueue->getWire(0); 52} 53 54template<class Impl> 55void 56SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 57{ 58 DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n"); 59 fetchQueue = fq_ptr; 60 61 // Setup wire to read information from fetch queue. 62 fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 63} 64 65template<class Impl> 66void 67SimpleDecode<Impl>::block() 68{ 69 DPRINTF(Decode, "Decode: Blocking.\n"); 70 71 // Set the status to Blocked. 72 _status = Blocked; 73 74 // Add the current inputs to the skid buffer so they can be 75 // reprocessed when this stage unblocks. 76 skidBuffer.push(*fromFetch); 77 78 // Note that this stage only signals previous stages to stall when 79 // it is the cause of the stall originates at this stage. Otherwise 80 // the previous stages are expected to check all possible stall signals. 81} 82 83template<class Impl> 84inline void 85SimpleDecode<Impl>::unblock() 86{ 87 DPRINTF(Decode, "Decode: Unblocking, going to remove " 88 "instructions from skid buffer.\n"); 89 // Remove the now processed instructions from the skid buffer. 90 skidBuffer.pop(); 91 92 // If there's still information in the skid buffer, then 93 // continue to tell previous stages to stall. They will be 94 // able to restart once the skid buffer is empty. 95 if (!skidBuffer.empty()) { 96 toFetch->decodeInfo.stall = true; 97 } else { 98 DPRINTF(Decode, "Decode: Finished unblocking.\n"); 99 _status = Running; 100 } 101} 102 103// This squash is specifically for when Decode detects a PC-relative branch 104// was predicted incorrectly. 105template<class Impl> 106void 107SimpleDecode<Impl>::squash(DynInstPtr &inst) 108{ 109 DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction " 110 "detected at decode.\n"); 111 Addr new_PC = inst->nextPC; 112 113 toFetch->decodeInfo.predIncorrect = true; 114 toFetch->decodeInfo.squash = true; 115 toFetch->decodeInfo.nextPC = new_PC; 116 117 // Set status to squashing. 118 _status = Squashing; 119 120 // Maybe advance the time buffer? Not sure what to do in the normal 121 // case. 122 123 // Clear the skid buffer in case it has any data in it. 124 while (!skidBuffer.empty()) 125 { 126 skidBuffer.pop(); 127 } 128} 129 130template<class Impl> 131void 132SimpleDecode<Impl>::squash() 133{ 134 DPRINTF(Decode, "Decode: Squashing.\n"); 135 // Set status to squashing. 136 _status = Squashing; 137 138 // Maybe advance the time buffer? Not sure what to do in the normal 139 // case. 140 141 // Clear the skid buffer in case it has any data in it. 142 while (!skidBuffer.empty()) 143 { 144 skidBuffer.pop(); 145 } 146} 147 148template<class Impl> 149void 150SimpleDecode<Impl>::tick() 151{ 152 // Decode should try to execute as many instructions as its bandwidth 153 // will allow, as long as it is not currently blocked. 154 if (_status != Blocked && _status != Squashing) { 155 DPRINTF(Decode, "Decode: Not blocked, so attempting to run " 156 "stage.\n"); 157 // Make sure that the skid buffer has something in it if the 158 // status is unblocking. 159 assert(_status == Unblocking ? !skidBuffer.empty() : 1); 160 161 decode(); 162 163 // If the status was unblocking, then instructions from the skid 164 // buffer were used. Remove those instructions and handle 165 // the rest of unblocking. 166 if (_status == Unblocking) { 167 if (fromFetch->size > 0) { 168 // Add the current inputs to the skid buffer so they can be 169 // reprocessed when this stage unblocks. 170 skidBuffer.push(*fromFetch); 171 } 172 173 unblock(); 174 } 175 } else if (_status == Blocked) { 176 if (fromFetch->size > 0) { 177 block(); 178 } 179 180 if (!fromRename->renameInfo.stall && 181 !fromIEW->iewInfo.stall && 182 !fromCommit->commitInfo.stall) { 183 DPRINTF(Decode, "Decode: Stall signals cleared, going to " 184 "unblock.\n"); 185 _status = Unblocking; 186 187 // Continue to tell previous stage to block until this 188 // stage is done unblocking. 189 toFetch->decodeInfo.stall = true; 190 } else { 191 DPRINTF(Decode, "Decode: Still blocked.\n"); 192 toFetch->decodeInfo.stall = true; 193 } 194 195 if (fromCommit->commitInfo.squash || 196 fromCommit->commitInfo.robSquashing) { 197 squash(); 198 } 199 } else if (_status == Squashing) { 200 if (!fromCommit->commitInfo.squash && 201 !fromCommit->commitInfo.robSquashing) { 202 _status = Running; 203 } else if (fromCommit->commitInfo.squash) { 204 squash(); 205 } 206 } 207} 208 209template<class Impl> 210void 211SimpleDecode<Impl>::decode() 212{ 213 // Check time buffer if being told to squash. 214 if (fromCommit->commitInfo.squash) { 215 squash(); 216 return; 217 } 218 219 // Check time buffer if being told to stall. 220 if (fromRename->renameInfo.stall || 221 fromIEW->iewInfo.stall || 222 fromCommit->commitInfo.stall) 223 { 224 block(); 225 return; 226 } 227 228 // Check fetch queue to see if instructions are available. 229 // If no available instructions, do nothing, unless this stage is 230 // currently unblocking. 231 if (!fromFetch->insts[0] && _status != Unblocking) { 232 DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); 233 // Should I change the status to idle? 234 return; 235 } 236 237 DynInstPtr inst; 238 239 // Instead have a class member variable that records which instruction 240 // was the last one that was ended on. At the tick() stage, it can 241 // check if that's equal to 0. If not, then don't pop stuff off. 242 unsigned to_rename_index = 0; 243 244 int insts_available = _status == Unblocking ? 245 skidBuffer.front().size : 246 fromFetch->size; 247 248 // Debug block... 249#if 0 250 if (insts_available) { 251 DPRINTF(Decode, "Decode: Instructions available.\n"); 252 } else { 253 if (_status == Unblocking && skidBuffer.empty()) { 254 DPRINTF(Decode, "Decode: No instructions available, skid buffer " 255 "empty.\n"); 256 } else if (_status != Unblocking && 257 !fromFetch->insts[0]) { 258 DPRINTF(Decode, "Decode: No instructions available, fetch queue " 259 "empty.\n"); 260 } else { 261 panic("Decode: No instructions available, unexpected condition!" 262 "\n"); 263 } 264 } 265#endif 266 267 // Check to make sure that instructions coming from fetch are valid. 268 // Normally at this stage the branch target of PC-relative branches 269 // should be computed here. However in this simple model all 270 // computation will take place at execute. Hence doneTargCalc() 271 // will always be false. 272 while (insts_available > 0) 273 { 274 DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); 275 // Might create some sort of accessor to get an instruction 276 // on a per thread basis. Or might be faster to just get 277 // a pointer to an array or list of instructions and use that 278 // within this code. 279 inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : 280 fromFetch->insts[numInst]; 281 282 DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n", 283 inst->seqNum, inst->readPC()); 284 285 if (inst->isSquashed()) { 286 DPRINTF(Decode, "Decode: Instruction %i with PC %#x is " 287 "squashed, skipping.\n", 288 inst->seqNum, inst->readPC()); 289 290 ++numInst; 291 --insts_available; 292 293 continue; 294 } 295 296 // This current instruction is valid, so add it into the decode 297 // queue. The next instruction may not be valid, so check to 298 // see if branches were predicted correctly. 299 toRename->insts[to_rename_index] = inst; 300 301 ++(toRename->size); 302 303 // Ensure that if it was predicted as a branch, it really is a 304 // branch. 305 if (inst->predTaken() && !inst->isControl()) { 306 panic("Instruction predicted as a branch!"); 307 308 // Might want to set some sort of boolean and just do 309 // a check at the end 310 squash(inst); 311 break; 312 } 313 314 // Ensure that the predicted branch target is the actual branch 315 // target if possible (branches that are PC relative). 316 if (inst->isControl() && inst->doneTargCalc()) { 317 if (inst->mispredicted()) { 318 // Might want to set some sort of boolean and just do 319 // a check at the end 320 squash(inst); 321 break; 322 } 323 } 324 325 // Also check if instructions have no source registers. Mark 326 // them as ready to issue at any time. Not sure if this check 327 // should exist here or at a later stage; however it doesn't matter 328 // too much for function correctness. 329 // Isn't this handled by the inst queue? 330 if (inst->numSrcRegs() == 0) { 331 inst->setCanIssue(); 332 } 333 334 // Increment which instruction we're looking at. 335 ++numInst; 336 ++to_rename_index; 337 338 --insts_available; 339 } 340 341 numInst = 0; 342} 343 344#endif // __SIMPLE_DECODE_CC__ 345