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