iew_impl.hh revision 1060
1// @todo: Fix the instantaneous communication among all the stages within 2// iew. There's a clear delay between issue and execute, yet backwards 3// communication happens simultaneously. Might not be that bad really... 4// it might skew stats a bit though. Issue would otherwise try to issue 5// instructions that would never be executed if there were a delay; without 6// it issue will simply squash. Make this stage block properly. Make this 7// stage delay after a squash properly. Update the statuses for each stage. 8// Actually read instructions out of the skid buffer. 9 10#include <queue> 11 12#include "base/timebuf.hh" 13#include "cpu/beta_cpu/iew.hh" 14 15template<class Impl, class IQ> 16SimpleIEW<Impl, IQ>::SimpleIEW(Params ¶ms) 17 : // Just make this time buffer really big for now 18 issueToExecQueue(20, 20), 19 instQueue(params), 20 commitToIEWDelay(params.commitToIEWDelay), 21 renameToIEWDelay(params.renameToIEWDelay), 22 issueToExecuteDelay(params.issueToExecuteDelay), 23 issueReadWidth(params.issueWidth), 24 issueWidth(params.issueWidth), 25 executeWidth(params.executeWidth) 26{ 27 DPRINTF(IEW, "IEW: executeIntWidth: %i.\n", params.executeIntWidth); 28 _status = Idle; 29 _issueStatus = Idle; 30 _exeStatus = Idle; 31 _wbStatus = Idle; 32 33 // Setup wire to read instructions coming from issue. 34 fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay); 35 36 // Instruction queue needs the queue between issue and execute. 37 instQueue.setIssueToExecuteQueue(&issueToExecQueue); 38} 39 40template<class Impl, class IQ> 41void 42SimpleIEW<Impl, IQ>::setCPU(FullCPU *cpu_ptr) 43{ 44 DPRINTF(IEW, "IEW: Setting CPU pointer.\n"); 45 cpu = cpu_ptr; 46 47 instQueue.setCPU(cpu_ptr); 48} 49 50template<class Impl, class IQ> 51void 52SimpleIEW<Impl, IQ>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 53{ 54 DPRINTF(IEW, "IEW: Setting time buffer pointer.\n"); 55 timeBuffer = tb_ptr; 56 57 // Setup wire to read information from time buffer, from commit. 58 fromCommit = timeBuffer->getWire(-commitToIEWDelay); 59 60 // Setup wire to write information back to previous stages. 61 toRename = timeBuffer->getWire(0); 62 63 // Instruction queue also needs main time buffer. 64 instQueue.setTimeBuffer(tb_ptr); 65} 66 67template<class Impl, class IQ> 68void 69SimpleIEW<Impl, IQ>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) 70{ 71 DPRINTF(IEW, "IEW: Setting rename queue pointer.\n"); 72 renameQueue = rq_ptr; 73 74 // Setup wire to read information from rename queue. 75 fromRename = renameQueue->getWire(-renameToIEWDelay); 76} 77 78template<class Impl, class IQ> 79void 80SimpleIEW<Impl, IQ>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) 81{ 82 DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n"); 83 iewQueue = iq_ptr; 84 85 // Setup wire to write instructions to commit. 86 toCommit = iewQueue->getWire(0); 87} 88 89template<class Impl, class IQ> 90void 91SimpleIEW<Impl, IQ>::setRenameMap(RenameMap *rm_ptr) 92{ 93 DPRINTF(IEW, "IEW: Setting rename map pointer.\n"); 94 renameMap = rm_ptr; 95} 96 97template<class Impl, class IQ> 98void 99SimpleIEW<Impl, IQ>::wakeDependents(DynInst *inst) 100{ 101 instQueue.wakeDependents(inst); 102} 103 104template<class Impl, class IQ> 105void 106SimpleIEW<Impl, IQ>::block() 107{ 108 DPRINTF(IEW, "IEW: Blocking.\n"); 109 // Set the status to Blocked. 110 _status = Blocked; 111 112 // Add the current inputs to the skid buffer so they can be 113 // reprocessed when this stage unblocks. 114 skidBuffer.push(*fromRename); 115 116 // Note that this stage only signals previous stages to stall when 117 // it is the cause of the stall originates at this stage. Otherwise 118 // the previous stages are expected to check all possible stall signals. 119} 120 121template<class Impl, class IQ> 122inline void 123SimpleIEW<Impl, IQ>::unblock() 124{ 125 // Check if there's information in the skid buffer. If there is, then 126 // set status to unblocking, otherwise set it directly to running. 127 DPRINTF(IEW, "IEW: Reading instructions out of the skid " 128 "buffer.\n"); 129 // Remove the now processed instructions from the skid buffer. 130 skidBuffer.pop(); 131 132 // If there's still information in the skid buffer, then 133 // continue to tell previous stages to stall. They will be 134 // able to restart once the skid buffer is empty. 135 if (!skidBuffer.empty()) { 136 toRename->iewInfo.stall = true; 137 } else { 138 DPRINTF(IEW, "IEW: Stage is done unblocking.\n"); 139 _status = Running; 140 } 141} 142 143template<class Impl, class IQ> 144void 145SimpleIEW<Impl, IQ>::squash() 146{ 147 DPRINTF(IEW, "IEW: Squashing all instructions.\n"); 148 _status = Squashing; 149 150 // Tell the IQ to start squashing. 151 instQueue.squash(); 152 153 // Tell rename to squash through the time buffer. 154 // This communication may be redundant depending upon where squash() 155 // is called. 156// toRename->iewInfo.squash = true; 157} 158 159template<class Impl, class IQ> 160void 161SimpleIEW<Impl, IQ>::squash(DynInst *inst) 162{ 163 DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC:%#x.\n", 164 inst->PC); 165 // Perhaps leave the squashing up to the ROB stage to tell it when to 166 // squash? 167 _status = Squashing; 168 169 // Tell rename to squash through the time buffer. 170 toRename->iewInfo.squash = true; 171 // Also send PC update information back to prior stages. 172 toRename->iewInfo.squashedSeqNum = inst->seqNum; 173 toRename->iewInfo.nextPC = inst->readCalcTarg(); 174 toRename->iewInfo.predIncorrect = true; 175} 176 177template<class Impl, class IQ> 178void 179SimpleIEW<Impl, IQ>::tick() 180{ 181 // Considering putting all the state-determining stuff in this section. 182 183 // Try to fill up issue queue with as many instructions as bandwidth 184 // allows. 185 // Decode should try to execute as many instructions as its bandwidth 186 // will allow, as long as it is not currently blocked. 187 188 // Check if the stage is in a running status. 189 if (_status != Blocked && _status != Squashing) { 190 DPRINTF(IEW, "IEW: Status is not blocked, attempting to run " 191 "stage.\n"); 192 iew(); 193 194 // If it's currently unblocking, check to see if it should switch 195 // to running. 196 if (_status == Unblocking) { 197 unblock(); 198 } 199 } else if (_status == Squashing) { 200 201 DPRINTF(IEW, "IEW: Still squashing.\n"); 202 203 // Check if stage should remain squashing. Stop squashing if the 204 // squash signal clears. 205 if (!fromCommit->commitInfo.squash && 206 !fromCommit->commitInfo.robSquashing) { 207 DPRINTF(IEW, "IEW: Done squashing, changing status to " 208 "running.\n"); 209 210 _status = Running; 211 instQueue.stopSquash(); 212 } else { 213 instQueue.doSquash(); 214 } 215 216 // Also should advance its own time buffers if the stage ran. 217 // Not sure about this... 218// issueToExecQueue.advance(); 219 } else if (_status == Blocked) { 220 // Continue to tell previous stage to stall. 221 toRename->iewInfo.stall = true; 222 223 // Check if possible stall conditions have cleared. 224 if (!fromCommit->commitInfo.stall && 225 !instQueue.isFull()) { 226 DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n"); 227 _status = Unblocking; 228 } 229 230 // If there's still instructions coming from rename, continue to 231 // put them on the skid buffer. 232 if (fromRename->insts[0] != NULL) { 233 block(); 234 } 235 236 if (fromCommit->commitInfo.squash || 237 fromCommit->commitInfo.robSquashing) { 238 squash(); 239 } 240 } 241 242 // @todo: Maybe put these at the beginning, so if it's idle it can 243 // return early. 244 // Write back number of free IQ entries here. 245 toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries(); 246 247 DPRINTF(IEW, "IEW: IQ has %i free entries.\n", 248 instQueue.numFreeEntries()); 249} 250 251template<class Impl, class IQ> 252void 253SimpleIEW<Impl, IQ>::iew() 254{ 255 // Might want to put all state checks in the tick() function. 256 // Check if being told to stall from commit. 257 if (fromCommit->commitInfo.stall) { 258 block(); 259 return; 260 } else if (fromCommit->commitInfo.squash || 261 fromCommit->commitInfo.robSquashing) { 262 // Also check if commit is telling this stage to squash. 263 squash(); 264 return; 265 } 266 267 //////////////////////////////////////// 268 //ISSUE stage 269 //////////////////////////////////////// 270 271 //Put into its own function? 272 //Add instructions to IQ if there are any instructions there 273 274 // Check if there are any instructions coming from rename, and we're. 275 // not squashing. 276 if (fromRename->insts[0] != NULL && _status != Squashing) { 277 278 // Loop through the instructions, putting them in the instruction 279 // queue. 280 for (int inst_num = 0; inst_num < issueReadWidth; ++inst_num) 281 { 282 DynInst *inst = fromRename->insts[inst_num]; 283 284 // Make sure there's a valid instruction there. 285 if (inst == NULL) 286 break; 287 288 DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n", 289 inst->readPC()); 290 291 // If it's a memory reference, don't put it in the 292 // instruction queue. These will only be executed at commit. 293 // Do the same for nonspeculative instructions and nops. 294 // Be sure to mark these instructions as ready so that the 295 // commit stage can go ahead and execute them, and mark 296 // them as issued so the IQ doesn't reprocess them. 297 if (inst->isMemRef()) { 298 DPRINTF(IEW, "IEW: Issue: Memory instruction " 299 "encountered, skipping.\n"); 300 301 inst->setIssued(); 302 inst->setExecuted(); 303 inst->setCanCommit(); 304 305 instQueue.advanceTail(inst); 306 continue; 307 } else if (inst->isNonSpeculative()) { 308 DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction " 309 "encountered, skipping.\n"); 310 311 inst->setIssued(); 312 inst->setExecuted(); 313 inst->setCanCommit(); 314 315 instQueue.advanceTail(inst); 316 continue; 317 } else if (inst->isNop()) { 318 DPRINTF(IEW, "IEW: Issue: Nop instruction encountered " 319 ", skipping.\n"); 320 321 inst->setIssued(); 322 inst->setExecuted(); 323 inst->setCanCommit(); 324 325 instQueue.advanceTail(inst); 326 continue; 327 } else if (instQueue.isFull()) { 328 DPRINTF(IEW, "IEW: Issue: IQ has become full.\n"); 329 // Call function to start blocking. 330 block(); 331 // Tell previous stage to stall. 332 toRename->iewInfo.stall = true; 333 break; 334 } 335 336 // If the instruction queue is not full, then add the 337 // instruction. 338 instQueue.insert(fromRename->insts[inst_num]); 339 } 340 } 341 342 // Have the instruction queue try to schedule any ready instructions. 343 instQueue.scheduleReadyInsts(); 344 345 //////////////////////////////////////// 346 //EXECUTE/WRITEBACK stage 347 //////////////////////////////////////// 348 349 //Put into its own function? 350 //Similarly should probably have separate execution for int vs FP. 351 // Above comment is handled by the issue queue only issuing a valid 352 // mix of int/fp instructions. 353 //Actually okay to just have one execution, buuuuuut will need 354 //somewhere that defines the execution latency of all instructions. 355 // @todo: Move to the FU pool used in the current full cpu. 356 357 int fu_usage = 0; 358 359 // Execute/writeback any instructions that are available. 360 for (int inst_num = 0; 361 fu_usage < executeWidth && /* Haven't exceeded available FU's. */ 362 inst_num < issueWidth && /* Haven't exceeded issue width. */ 363 fromIssue->insts[inst_num]; /* There are available instructions. */ 364 ++inst_num) { 365 DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n"); 366 367 // Get instruction from issue's queue. 368 DynInst *inst = fromIssue->insts[inst_num]; 369 370 DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC()); 371 372 inst->setExecuted(); 373 374 // Check if the instruction is squashed; if so then skip it 375 // and don't count it towards the FU usage. 376 if (inst->isSquashed()) { 377 DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n"); 378 continue; 379 } 380 381 // If an instruction is executed, then count it towards FU usage. 382 ++fu_usage; 383 384 // Execute instruction. 385 // Note that if the instruction faults, it will be handled 386 // at the commit stage. 387 inst->execute(); 388 389 // First check the time slot that this instruction will write 390 // to. If there are free write ports at the time, then go ahead 391 // and write the instruction to that time. If there are not, 392 // keep looking back to see where's the first time there's a 393 // free slot. What happens if you run out of free spaces? 394 // For now naively assume that all instructions take one cycle. 395 // Otherwise would have to look into the time buffer based on the 396 // latency of the instruction. 397 398 // Add finished instruction to queue to commit. 399 toCommit->insts[inst_num] = inst; 400 401 // Check if branch was correct. This check happens after the 402 // instruction is added to the queue because even if the branch 403 // is mispredicted, the branch instruction itself is still valid. 404 if (inst->mispredicted()) { 405 DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n"); 406 DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n", 407 inst->nextPC); 408 409 // If incorrect, then signal the ROB that it must be squashed. 410 squash(inst); 411 412 // Not sure it really needs to break. 413// break; 414 } 415 } 416 417 // Loop through the head of the time buffer and wake any dependents. 418 // These instructions are about to write back. In the simple model 419 // this loop can really happen within the previous loop, but when 420 // instructions have actual latencies, this loop must be separate. 421 // Also mark scoreboard that this instruction is finally complete. 422 // Either have IEW have direct access to rename map, or have this as 423 // part of backwards communication. 424 for (int inst_num = 0; inst_num < executeWidth && 425 toCommit->insts[inst_num] != NULL; inst_num++) 426 { 427 DynInst *inst = toCommit->insts[inst_num]; 428 429 DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n", 430 inst->readPC()); 431 432 instQueue.wakeDependents(inst); 433 434 for (int i = 0; i < inst->numDestRegs(); i++) 435 { 436 renameMap->markAsReady(inst->renamedDestRegIdx(i)); 437 } 438 } 439 440 // Also should advance its own time buffers if the stage ran. 441 // Not the best place for it, but this works (hopefully). 442 issueToExecQueue.advance(); 443} 444