decode_impl.hh revision 1689
16145SN/A/* 28683SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 310973Sdavid.hashe@amd.com * All rights reserved. 46145SN/A * 56145SN/A * Redistribution and use in source and binary forms, with or without 66145SN/A * modification, are permitted provided that the following conditions are 76145SN/A * met: redistributions of source code must retain the above copyright 86145SN/A * notice, this list of conditions and the following disclaimer; 96145SN/A * redistributions in binary form must reproduce the above copyright 106145SN/A * notice, this list of conditions and the following disclaimer in the 116145SN/A * documentation and/or other materials provided with the distribution; 126145SN/A * neither the name of the copyright holders nor the names of its 136145SN/A * contributors may be used to endorse or promote products derived from 146145SN/A * this software without specific prior written permission. 156145SN/A * 166145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276145SN/A */ 286145SN/A 296145SN/A#include "cpu/beta_cpu/decode.hh" 3010441Snilay@cs.wisc.edu 3110441Snilay@cs.wisc.edutemplate<class Impl> 326145SN/ASimpleDecode<Impl>::SimpleDecode(Params ¶ms) 337055SN/A : renameToDecodeDelay(params.renameToDecodeDelay), 346145SN/A iewToDecodeDelay(params.iewToDecodeDelay), 356145SN/A commitToDecodeDelay(params.commitToDecodeDelay), 367039SN/A fetchToDecodeDelay(params.fetchToDecodeDelay), 379104SN/A decodeWidth(params.decodeWidth), 3810301Snilay@cs.wisc.edu numInst(0) 399105SN/A{ 408174SN/A DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth); 417039SN/A _status = Idle; 427039SN/A} 437039SN/A 4410970Sdavid.hashe@amd.comtemplate <class Impl> 4510301Snilay@cs.wisc.eduvoid 4610301Snilay@cs.wisc.eduSimpleDecode<Impl>::regStats() 477039SN/A{ 487039SN/A decodeIdleCycles 496145SN/A .name(name() + ".decodeIdleCycles") 507039SN/A .desc("Number of cycles decode is idle") 517039SN/A .prereq(decodeIdleCycles); 527039SN/A decodeBlockedCycles 536876SN/A .name(name() + ".decodeBlockedCycles") 547039SN/A .desc("Number of cycles decode is blocked") 557039SN/A .prereq(decodeBlockedCycles); 566145SN/A decodeUnblockCycles 577039SN/A .name(name() + ".decodeUnblockCycles") 586145SN/A .desc("Number of cycles decode is unblocking") 5911049Snilay@cs.wisc.edu .prereq(decodeUnblockCycles); 6011049Snilay@cs.wisc.edu decodeSquashCycles 6111049Snilay@cs.wisc.edu .name(name() + ".decodeSquashCycles") 6211049Snilay@cs.wisc.edu .desc("Number of cycles decode is squashing") 6311049Snilay@cs.wisc.edu .prereq(decodeSquashCycles); 6411049Snilay@cs.wisc.edu decodeBranchMispred 6511049Snilay@cs.wisc.edu .name(name() + ".decodeBranchMispred") 6611049Snilay@cs.wisc.edu .desc("Number of times decode detected a branch misprediction") 6711049Snilay@cs.wisc.edu .prereq(decodeBranchMispred); 687039SN/A decodeControlMispred 6911025Snilay@cs.wisc.edu .name(name() + ".decodeControlMispred") 706145SN/A .desc("Number of times decode detected an instruction incorrectly" 717039SN/A " predicted as a control") 727039SN/A .prereq(decodeControlMispred); 737039SN/A decodeDecodedInsts 7411025Snilay@cs.wisc.edu .name(name() + ".decodeDecodedInsts") 756145SN/A .desc("Number of instructions handled by decode") 767039SN/A .prereq(decodeDecodedInsts); 7711025Snilay@cs.wisc.edu decodeSquashedInsts 7810974Sdavid.hashe@amd.com .name(name() + ".decodeSquashedInsts") 7911025Snilay@cs.wisc.edu .desc("Number of squashed instructions handled by decode") 8010974Sdavid.hashe@amd.com .prereq(decodeSquashedInsts); 8110974Sdavid.hashe@amd.com} 8210974Sdavid.hashe@amd.com 8311025Snilay@cs.wisc.edutemplate<class Impl> 848193SN/Avoid 8510974Sdavid.hashe@amd.comSimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr) 868193SN/A{ 876145SN/A DPRINTF(Decode, "Decode: Setting CPU pointer.\n"); 887039SN/A cpu = cpu_ptr; 8911025Snilay@cs.wisc.edu} 906145SN/A 917039SN/Atemplate<class Impl> 9211025Snilay@cs.wisc.eduvoid 936145SN/ASimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 947039SN/A{ 9511025Snilay@cs.wisc.edu DPRINTF(Decode, "Decode: Setting time buffer pointer.\n"); 9611025Snilay@cs.wisc.edu timeBuffer = tb_ptr; 976145SN/A 9810969Sdavid.hashe@amd.com // Setup wire to write information back to fetch. 9910969Sdavid.hashe@amd.com toFetch = timeBuffer->getWire(0); 10010969Sdavid.hashe@amd.com 10111049Snilay@cs.wisc.edu // Create wires to get information from proper places in time buffer. 10211049Snilay@cs.wisc.edu fromRename = timeBuffer->getWire(-renameToDecodeDelay); 1036285SN/A fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 1047039SN/A fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 1058683SN/A} 1066145SN/A 1077039SN/Atemplate<class Impl> 10811025Snilay@cs.wisc.eduvoid 1096145SN/ASimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 11011025Snilay@cs.wisc.edu{ 11111025Snilay@cs.wisc.edu DPRINTF(Decode, "Decode: Setting decode queue pointer.\n"); 11211025Snilay@cs.wisc.edu decodeQueue = dq_ptr; 1139692SN/A 1147039SN/A // Setup wire to write information to proper place in decode queue. 1157055SN/A toRename = decodeQueue->getWire(0); 1167055SN/A} 1176145SN/A 1189692SN/Atemplate<class Impl> 11911025Snilay@cs.wisc.eduvoid 12011025Snilay@cs.wisc.eduSimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 1216374SN/A{ 1229692SN/A DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n"); 1239692SN/A fetchQueue = fq_ptr; 1249692SN/A 1259692SN/A // Setup wire to read information from fetch queue. 1269692SN/A fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 1279692SN/A} 1289692SN/A 1299692SN/Atemplate<class Impl> 1309692SN/Ainline bool 1319692SN/ASimpleDecode<Impl>::fetchInstsValid() 1329104SN/A{ 1339104SN/A return fromFetch->size > 0; 1349104SN/A} 1359104SN/A 1369104SN/Atemplate<class Impl> 1379104SN/Avoid 1389105SN/ASimpleDecode<Impl>::block() 1399105SN/A{ 1409692SN/A DPRINTF(Decode, "Decode: Blocking.\n"); 14110973Sdavid.hashe@amd.com 14210973Sdavid.hashe@amd.com // Set the status to Blocked. 14311025Snilay@cs.wisc.edu _status = Blocked; 14410973Sdavid.hashe@amd.com 1457039SN/A // Add the current inputs to the skid buffer so they can be 1467039SN/A // reprocessed when this stage unblocks. 14711049Snilay@cs.wisc.edu skidBuffer.push(*fromFetch); 1486145SN/A 1497039SN/A // Note that this stage only signals previous stages to stall when 1507039SN/A // it is the cause of the stall originates at this stage. Otherwise 15111049Snilay@cs.wisc.edu // the previous stages are expected to check all possible stall signals. 15211049Snilay@cs.wisc.edu} 1536145SN/A 1547039SN/Atemplate<class Impl> 1557039SN/Ainline void 1567039SN/ASimpleDecode<Impl>::unblock() 1576145SN/A{ 1587039SN/A DPRINTF(Decode, "Decode: Unblocking, going to remove " 1597039SN/A "instructions from skid buffer.\n"); 1607039SN/A // Remove the now processed instructions from the skid buffer. 1616285SN/A skidBuffer.pop(); 1627039SN/A 1637039SN/A // If there's still information in the skid buffer, then 16411025Snilay@cs.wisc.edu // continue to tell previous stages to stall. They will be 1657454SN/A // able to restart once the skid buffer is empty. 1666145SN/A if (!skidBuffer.empty()) { 1677039SN/A toFetch->decodeInfo.stall = true; 1686145SN/A } else { 1699105SN/A DPRINTF(Decode, "Decode: Finished unblocking.\n"); 1709105SN/A _status = Running; 1719105SN/A } 1727039SN/A} 1737039SN/A 1747039SN/A// This squash is specifically for when Decode detects a PC-relative branch 1757039SN/A// was predicted incorrectly. 1767564SN/Atemplate<class Impl> 1779105SN/Avoid 1786145SN/ASimpleDecode<Impl>::squash(DynInstPtr &inst) 1796145SN/A{ 1809554SN/A DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction " 1819554SN/A "detected at decode.\n"); 18210441Snilay@cs.wisc.edu Addr new_PC = inst->readNextPC(); 183 184 toFetch->decodeInfo.branchMispredict = true; 185 toFetch->decodeInfo.doneSeqNum = inst->seqNum; 186 toFetch->decodeInfo.predIncorrect = true; 187 toFetch->decodeInfo.squash = true; 188 toFetch->decodeInfo.nextPC = new_PC; 189 toFetch->decodeInfo.branchTaken = true; 190 191 // Set status to squashing. 192 _status = Squashing; 193 194 // Clear the skid buffer in case it has any data in it. 195 while (!skidBuffer.empty()) { 196 skidBuffer.pop(); 197 } 198 199 // Squash instructions up until this one 200 // Slightly unrealistic! 201 cpu->removeInstsUntil(inst->seqNum); 202} 203 204template<class Impl> 205void 206SimpleDecode<Impl>::squash() 207{ 208 DPRINTF(Decode, "Decode: Squashing.\n"); 209 // Set status to squashing. 210 _status = Squashing; 211 212 // Maybe advance the time buffer? Not sure what to do in the normal 213 // case. 214 215 // Clear the skid buffer in case it has any data in it. 216 while (!skidBuffer.empty()) 217 { 218 skidBuffer.pop(); 219 } 220} 221 222template<class Impl> 223void 224SimpleDecode<Impl>::tick() 225{ 226 // Decode should try to execute as many instructions as its bandwidth 227 // will allow, as long as it is not currently blocked. 228 if (_status != Blocked && _status != Squashing) { 229 DPRINTF(Decode, "Decode: Not blocked, so attempting to run " 230 "stage.\n"); 231 // Make sure that the skid buffer has something in it if the 232 // status is unblocking. 233 assert(_status == Unblocking ? !skidBuffer.empty() : 1); 234 235 decode(); 236 237 // If the status was unblocking, then instructions from the skid 238 // buffer were used. Remove those instructions and handle 239 // the rest of unblocking. 240 if (_status == Unblocking) { 241 ++decodeUnblockCycles; 242 243 if (fetchInstsValid()) { 244 // Add the current inputs to the skid buffer so they can be 245 // reprocessed when this stage unblocks. 246 skidBuffer.push(*fromFetch); 247 } 248 249 unblock(); 250 } 251 } else if (_status == Blocked) { 252 ++decodeBlockedCycles; 253 254 if (fetchInstsValid()) { 255 block(); 256 } 257 258 if (!fromRename->renameInfo.stall && 259 !fromIEW->iewInfo.stall && 260 !fromCommit->commitInfo.stall) { 261 DPRINTF(Decode, "Decode: Stall signals cleared, going to " 262 "unblock.\n"); 263 _status = Unblocking; 264 265 // Continue to tell previous stage to block until this 266 // stage is done unblocking. 267 toFetch->decodeInfo.stall = true; 268 } else { 269 DPRINTF(Decode, "Decode: Still blocked.\n"); 270 toFetch->decodeInfo.stall = true; 271 } 272 273 if (fromCommit->commitInfo.squash || 274 fromCommit->commitInfo.robSquashing) { 275 squash(); 276 } 277 } else if (_status == Squashing) { 278 if (!fromCommit->commitInfo.squash && 279 !fromCommit->commitInfo.robSquashing) { 280 _status = Running; 281 } else if (fromCommit->commitInfo.squash) { 282 ++decodeSquashCycles; 283 284 squash(); 285 } 286 } 287} 288 289template<class Impl> 290void 291SimpleDecode<Impl>::decode() 292{ 293 // Check time buffer if being told to squash. 294 if (fromCommit->commitInfo.squash) { 295 squash(); 296 return; 297 } 298 299 // Check time buffer if being told to stall. 300 if (fromRename->renameInfo.stall || 301 fromIEW->iewInfo.stall || 302 fromCommit->commitInfo.stall) { 303 block(); 304 return; 305 } 306 307 // Check fetch queue to see if instructions are available. 308 // If no available instructions, do nothing, unless this stage is 309 // currently unblocking. 310 if (!fetchInstsValid() && _status != Unblocking) { 311 DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); 312 // Should I change the status to idle? 313 ++decodeIdleCycles; 314 return; 315 } 316 317 // Might be better to use a base DynInst * instead? 318 DynInstPtr inst; 319 320 unsigned to_rename_index = 0; 321 322 int insts_available = _status == Unblocking ? 323 skidBuffer.front().size - numInst : 324 fromFetch->size; 325 326 // Debug block... 327#if 0 328 if (insts_available) { 329 DPRINTF(Decode, "Decode: Instructions available.\n"); 330 } else { 331 if (_status == Unblocking && skidBuffer.empty()) { 332 DPRINTF(Decode, "Decode: No instructions available, skid buffer " 333 "empty.\n"); 334 } else if (_status != Unblocking && 335 !fromFetch->insts[0]) { 336 DPRINTF(Decode, "Decode: No instructions available, fetch queue " 337 "empty.\n"); 338 } else { 339 panic("Decode: No instructions available, unexpected condition!" 340 "\n"); 341 } 342 } 343#endif 344 345 while (insts_available > 0) 346 { 347 DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); 348 349 inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : 350 fromFetch->insts[numInst]; 351 352 DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n", 353 inst->seqNum, inst->readPC()); 354 355 if (inst->isSquashed()) { 356 DPRINTF(Decode, "Decode: Instruction %i with PC %#x is " 357 "squashed, skipping.\n", 358 inst->seqNum, inst->readPC()); 359 360 ++decodeSquashedInsts; 361 362 ++numInst; 363 --insts_available; 364 365 continue; 366 } 367 368 369 // Also check if instructions have no source registers. Mark 370 // them as ready to issue at any time. Not sure if this check 371 // should exist here or at a later stage; however it doesn't matter 372 // too much for function correctness. 373 // Isn't this handled by the inst queue? 374 if (inst->numSrcRegs() == 0) { 375 inst->setCanIssue(); 376 } 377 378 // This current instruction is valid, so add it into the decode 379 // queue. The next instruction may not be valid, so check to 380 // see if branches were predicted correctly. 381 toRename->insts[to_rename_index] = inst; 382 383 ++(toRename->size); 384 385 // Ensure that if it was predicted as a branch, it really is a 386 // branch. 387 if (inst->predTaken() && !inst->isControl()) { 388 panic("Instruction predicted as a branch!"); 389 390 ++decodeControlMispred; 391 // Might want to set some sort of boolean and just do 392 // a check at the end 393 squash(inst); 394 break; 395 } 396 397 // Go ahead and compute any PC-relative branches. 398 399 if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 400 401 inst->setNextPC(inst->branchTarget()); 402 403 if (inst->mispredicted()) { 404 ++decodeBranchMispred; 405 // Might want to set some sort of boolean and just do 406 // a check at the end 407 squash(inst); 408 break; 409 } 410 } 411 412 // Normally can check if a direct branch has the right target 413 // addr (either the immediate, or the branch PC + 4) and redirect 414 // fetch if it's incorrect. 415 416 // Increment which instruction we're looking at. 417 ++numInst; 418 ++to_rename_index; 419 ++decodeDecodedInsts; 420 421 --insts_available; 422 } 423 424 numInst = 0; 425} 426