fetch2.cc revision 13632:483aaa00c69c
15217Ssaidi@eecs.umich.edu/* 29428SAndreas.Sandberg@ARM.com * Copyright (c) 2013-2014,2016 ARM Limited 39428SAndreas.Sandberg@ARM.com * All rights reserved 49428SAndreas.Sandberg@ARM.com * 59428SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 69428SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 79428SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 89428SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 99428SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 109428SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 119428SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 129428SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 139428SAndreas.Sandberg@ARM.com * 145217Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 155217Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are 165217Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright 175217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 185217Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 195217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 205217Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution; 215217Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its 225217Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 235217Ssaidi@eecs.umich.edu * this software without specific prior written permission. 245217Ssaidi@eecs.umich.edu * 255217Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 265217Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 275217Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 285217Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 295217Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 305217Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 315217Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 325217Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 335217Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 345217Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 355217Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 365217Ssaidi@eecs.umich.edu * 375217Ssaidi@eecs.umich.edu * Authors: Andrew Bardsley 385217Ssaidi@eecs.umich.edu */ 395217Ssaidi@eecs.umich.edu 405217Ssaidi@eecs.umich.edu#include "cpu/minor/fetch2.hh" 415217Ssaidi@eecs.umich.edu 425217Ssaidi@eecs.umich.edu#include <string> 435217Ssaidi@eecs.umich.edu 445217Ssaidi@eecs.umich.edu#include "arch/decoder.hh" 456658Snate@binkert.org#include "arch/utility.hh" 469441SAndreas.Sandberg@ARM.com#include "cpu/minor/pipeline.hh" 479441SAndreas.Sandberg@ARM.com#include "cpu/pred/bpred_unit.hh" 485217Ssaidi@eecs.umich.edu#include "debug/Branch.hh" 498232Snate@binkert.org#include "debug/Fetch.hh" 509441SAndreas.Sandberg@ARM.com#include "debug/MinorTrace.hh" 515217Ssaidi@eecs.umich.edu 525217Ssaidi@eecs.umich.edunamespace Minor 535217Ssaidi@eecs.umich.edu{ 545217Ssaidi@eecs.umich.edu 555217Ssaidi@eecs.umich.eduFetch2::Fetch2(const std::string &name, 565217Ssaidi@eecs.umich.edu MinorCPU &cpu_, 575217Ssaidi@eecs.umich.edu MinorCPUParams ¶ms, 585217Ssaidi@eecs.umich.edu Latch<ForwardLineData>::Output inp_, 595217Ssaidi@eecs.umich.edu Latch<BranchData>::Output branchInp_, 605217Ssaidi@eecs.umich.edu Latch<BranchData>::Input predictionOut_, 615217Ssaidi@eecs.umich.edu Latch<ForwardInstData>::Input out_, 625217Ssaidi@eecs.umich.edu std::vector<InputBuffer<ForwardInstData>> &next_stage_input_buffer) : 635217Ssaidi@eecs.umich.edu Named(name), 645217Ssaidi@eecs.umich.edu cpu(cpu_), 655217Ssaidi@eecs.umich.edu inp(inp_), 665217Ssaidi@eecs.umich.edu branchInp(branchInp_), 675217Ssaidi@eecs.umich.edu predictionOut(predictionOut_), 685217Ssaidi@eecs.umich.edu out(out_), 695217Ssaidi@eecs.umich.edu nextStageReserve(next_stage_input_buffer), 705217Ssaidi@eecs.umich.edu outputWidth(params.decodeInputWidth), 715217Ssaidi@eecs.umich.edu processMoreThanOneInput(params.fetch2CycleInput), 725217Ssaidi@eecs.umich.edu branchPredictor(*params.branchPred), 735217Ssaidi@eecs.umich.edu fetchInfo(params.numThreads), 745217Ssaidi@eecs.umich.edu threadPriority(0) 755217Ssaidi@eecs.umich.edu{ 765217Ssaidi@eecs.umich.edu if (outputWidth < 1) 775217Ssaidi@eecs.umich.edu fatal("%s: decodeInputWidth must be >= 1 (%d)\n", name, outputWidth); 785217Ssaidi@eecs.umich.edu 795217Ssaidi@eecs.umich.edu if (params.fetch2InputBufferSize < 1) { 805217Ssaidi@eecs.umich.edu fatal("%s: fetch2InputBufferSize must be >= 1 (%d)\n", name, 815217Ssaidi@eecs.umich.edu params.fetch2InputBufferSize); 827720Sgblack@eecs.umich.edu } 837720Sgblack@eecs.umich.edu 845712Shsul@eecs.umich.edu /* Per-thread input buffers */ 855712Shsul@eecs.umich.edu for (ThreadID tid = 0; tid < params.numThreads; tid++) { 865217Ssaidi@eecs.umich.edu inputBuffer.push_back( 875217Ssaidi@eecs.umich.edu InputBuffer<ForwardLineData>( 885714Shsul@eecs.umich.edu name + ".inputBuffer" + std::to_string(tid), "lines", 895714Shsul@eecs.umich.edu params.fetch2InputBufferSize)); 905714Shsul@eecs.umich.edu } 915714Shsul@eecs.umich.edu} 925714Shsul@eecs.umich.edu 935714Shsul@eecs.umich.educonst ForwardLineData * 945714Shsul@eecs.umich.eduFetch2::getInput(ThreadID tid) 955217Ssaidi@eecs.umich.edu{ 969428SAndreas.Sandberg@ARM.com /* Get a line from the inputBuffer to work with */ 979428SAndreas.Sandberg@ARM.com if (!inputBuffer[tid].empty()) { 989428SAndreas.Sandberg@ARM.com return &(inputBuffer[tid].front()); 999428SAndreas.Sandberg@ARM.com } else { 1009428SAndreas.Sandberg@ARM.com return NULL; 1019428SAndreas.Sandberg@ARM.com } 1029428SAndreas.Sandberg@ARM.com} 1039428SAndreas.Sandberg@ARM.com 1049428SAndreas.Sandberg@ARM.comvoid 1059428SAndreas.Sandberg@ARM.comFetch2::popInput(ThreadID tid) 1069428SAndreas.Sandberg@ARM.com{ 1079428SAndreas.Sandberg@ARM.com if (!inputBuffer[tid].empty()) { 1089428SAndreas.Sandberg@ARM.com inputBuffer[tid].front().freeLine(); 1099428SAndreas.Sandberg@ARM.com inputBuffer[tid].pop(); 1109428SAndreas.Sandberg@ARM.com } 1119428SAndreas.Sandberg@ARM.com 1129428SAndreas.Sandberg@ARM.com fetchInfo[tid].inputIndex = 0; 1139428SAndreas.Sandberg@ARM.com} 1149428SAndreas.Sandberg@ARM.com 1159428SAndreas.Sandberg@ARM.comvoid 1169428SAndreas.Sandberg@ARM.comFetch2::dumpAllInput(ThreadID tid) 1179428SAndreas.Sandberg@ARM.com{ 1189428SAndreas.Sandberg@ARM.com DPRINTF(Fetch, "Dumping whole input buffer\n"); 1199428SAndreas.Sandberg@ARM.com while (!inputBuffer[tid].empty()) 1209428SAndreas.Sandberg@ARM.com popInput(tid); 1219428SAndreas.Sandberg@ARM.com 1229428SAndreas.Sandberg@ARM.com fetchInfo[tid].inputIndex = 0; 1239428SAndreas.Sandberg@ARM.com fetchInfo[tid].havePC = false; 1249428SAndreas.Sandberg@ARM.com} 1259428SAndreas.Sandberg@ARM.com 1269428SAndreas.Sandberg@ARM.comvoid 1279428SAndreas.Sandberg@ARM.comFetch2::updateBranchPrediction(const BranchData &branch) 1289428SAndreas.Sandberg@ARM.com{ 1299428SAndreas.Sandberg@ARM.com MinorDynInstPtr inst = branch.inst; 1309428SAndreas.Sandberg@ARM.com 1319428SAndreas.Sandberg@ARM.com /* Don't even consider instructions we didn't try to predict or faults */ 1329428SAndreas.Sandberg@ARM.com if (inst->isFault() || !inst->triedToPredict) 1339428SAndreas.Sandberg@ARM.com return; 1349428SAndreas.Sandberg@ARM.com 1359428SAndreas.Sandberg@ARM.com switch (branch.reason) { 1369428SAndreas.Sandberg@ARM.com case BranchData::NoBranch: 1379428SAndreas.Sandberg@ARM.com /* No data to update */ 1389428SAndreas.Sandberg@ARM.com break; 1399428SAndreas.Sandberg@ARM.com case BranchData::Interrupt: 1409428SAndreas.Sandberg@ARM.com /* Never try to predict interrupts */ 1419428SAndreas.Sandberg@ARM.com break; 1429441SAndreas.Sandberg@ARM.com case BranchData::SuspendThread: 1439441SAndreas.Sandberg@ARM.com /* Don't need to act on suspends */ 1449441SAndreas.Sandberg@ARM.com break; 1459441SAndreas.Sandberg@ARM.com case BranchData::HaltFetch: 1469441SAndreas.Sandberg@ARM.com /* Don't need to act on fetch wakeup */ 1479441SAndreas.Sandberg@ARM.com break; 1489441SAndreas.Sandberg@ARM.com case BranchData::BranchPrediction: 1499441SAndreas.Sandberg@ARM.com /* Shouldn't happen. Fetch2 is the only source of 1509441SAndreas.Sandberg@ARM.com * BranchPredictions */ 1519441SAndreas.Sandberg@ARM.com break; 1529441SAndreas.Sandberg@ARM.com case BranchData::UnpredictedBranch: 1539441SAndreas.Sandberg@ARM.com /* Unpredicted branch or barrier */ 1549441SAndreas.Sandberg@ARM.com DPRINTF(Branch, "Unpredicted branch seen inst: %s\n", *inst); 1559441SAndreas.Sandberg@ARM.com branchPredictor.squash(inst->id.fetchSeqNum, 1569441SAndreas.Sandberg@ARM.com branch.target, true, inst->id.threadId); 1579441SAndreas.Sandberg@ARM.com // Update after squashing to accomodate O3CPU 1589441SAndreas.Sandberg@ARM.com // using the branch prediction code. 1599441SAndreas.Sandberg@ARM.com branchPredictor.update(inst->id.fetchSeqNum, 1609441SAndreas.Sandberg@ARM.com inst->id.threadId); 1619441SAndreas.Sandberg@ARM.com break; 1629441SAndreas.Sandberg@ARM.com case BranchData::CorrectlyPredictedBranch: 1639441SAndreas.Sandberg@ARM.com /* Predicted taken, was taken */ 1649441SAndreas.Sandberg@ARM.com DPRINTF(Branch, "Branch predicted correctly inst: %s\n", *inst); 1659441SAndreas.Sandberg@ARM.com branchPredictor.update(inst->id.fetchSeqNum, 1669441SAndreas.Sandberg@ARM.com inst->id.threadId); 1679441SAndreas.Sandberg@ARM.com break; 1689441SAndreas.Sandberg@ARM.com case BranchData::BadlyPredictedBranch: 1699441SAndreas.Sandberg@ARM.com /* Predicted taken, not taken */ 1709441SAndreas.Sandberg@ARM.com DPRINTF(Branch, "Branch mis-predicted inst: %s\n", *inst); 1719441SAndreas.Sandberg@ARM.com branchPredictor.squash(inst->id.fetchSeqNum, 1729441SAndreas.Sandberg@ARM.com branch.target /* Not used */, false, inst->id.threadId); 1739441SAndreas.Sandberg@ARM.com // Update after squashing to accomodate O3CPU 1749441SAndreas.Sandberg@ARM.com // using the branch prediction code. 1759441SAndreas.Sandberg@ARM.com branchPredictor.update(inst->id.fetchSeqNum, 176 inst->id.threadId); 177 break; 178 case BranchData::BadlyPredictedBranchTarget: 179 /* Predicted taken, was taken but to a different target */ 180 DPRINTF(Branch, "Branch mis-predicted target inst: %s target: %s\n", 181 *inst, branch.target); 182 branchPredictor.squash(inst->id.fetchSeqNum, 183 branch.target, true, inst->id.threadId); 184 break; 185 } 186} 187 188void 189Fetch2::predictBranch(MinorDynInstPtr inst, BranchData &branch) 190{ 191 Fetch2ThreadInfo &thread = fetchInfo[inst->id.threadId]; 192 TheISA::PCState inst_pc = inst->pc; 193 194 assert(!inst->predictedTaken); 195 196 /* Skip non-control/sys call instructions */ 197 if (inst->staticInst->isControl() || 198 inst->staticInst->isSyscall()) 199 { 200 /* Tried to predict */ 201 inst->triedToPredict = true; 202 203 DPRINTF(Branch, "Trying to predict for inst: %s\n", *inst); 204 205 if (branchPredictor.predict(inst->staticInst, 206 inst->id.fetchSeqNum, inst_pc, 207 inst->id.threadId)) 208 { 209 inst->predictedTaken = true; 210 inst->predictedTarget = inst_pc; 211 branch.target = inst_pc; 212 } 213 } else { 214 DPRINTF(Branch, "Not attempting prediction for inst: %s\n", *inst); 215 } 216 217 /* If we predict taken, set branch and update sequence numbers */ 218 if (inst->predictedTaken) { 219 /* Update the predictionSeqNum and remember the streamSeqNum that it 220 * was associated with */ 221 thread.expectedStreamSeqNum = inst->id.streamSeqNum; 222 223 BranchData new_branch = BranchData(BranchData::BranchPrediction, 224 inst->id.threadId, 225 inst->id.streamSeqNum, thread.predictionSeqNum + 1, 226 inst->predictedTarget, inst); 227 228 /* Mark with a new prediction number by the stream number of the 229 * instruction causing the prediction */ 230 thread.predictionSeqNum++; 231 branch = new_branch; 232 233 DPRINTF(Branch, "Branch predicted taken inst: %s target: %s" 234 " new predictionSeqNum: %d\n", 235 *inst, inst->predictedTarget, thread.predictionSeqNum); 236 } 237} 238 239void 240Fetch2::evaluate() 241{ 242 /* Push input onto appropriate input buffer */ 243 if (!inp.outputWire->isBubble()) 244 inputBuffer[inp.outputWire->id.threadId].setTail(*inp.outputWire); 245 246 ForwardInstData &insts_out = *out.inputWire; 247 BranchData prediction; 248 BranchData &branch_inp = *branchInp.outputWire; 249 250 assert(insts_out.isBubble()); 251 252 /* React to branches from Execute to update local branch prediction 253 * structures */ 254 updateBranchPrediction(branch_inp); 255 256 /* If a branch arrives, don't try and do anything about it. Only 257 * react to your own predictions */ 258 if (branch_inp.isStreamChange()) { 259 DPRINTF(Fetch, "Dumping all input as a stream changing branch" 260 " has arrived\n"); 261 dumpAllInput(branch_inp.threadId); 262 fetchInfo[branch_inp.threadId].havePC = false; 263 } 264 265 assert(insts_out.isBubble()); 266 /* Even when blocked, clear out input lines with the wrong 267 * prediction sequence number */ 268 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 269 Fetch2ThreadInfo &thread = fetchInfo[tid]; 270 271 thread.blocked = !nextStageReserve[tid].canReserve(); 272 273 const ForwardLineData *line_in = getInput(tid); 274 275 while (line_in && 276 thread.expectedStreamSeqNum == line_in->id.streamSeqNum && 277 thread.predictionSeqNum != line_in->id.predictionSeqNum) 278 { 279 DPRINTF(Fetch, "Discarding line %s" 280 " due to predictionSeqNum mismatch (expected: %d)\n", 281 line_in->id, thread.predictionSeqNum); 282 283 popInput(tid); 284 fetchInfo[tid].havePC = false; 285 286 if (processMoreThanOneInput) { 287 DPRINTF(Fetch, "Wrapping\n"); 288 line_in = getInput(tid); 289 } else { 290 line_in = NULL; 291 } 292 } 293 } 294 295 ThreadID tid = getScheduledThread(); 296 DPRINTF(Fetch, "Scheduled Thread: %d\n", tid); 297 298 assert(insts_out.isBubble()); 299 if (tid != InvalidThreadID) { 300 Fetch2ThreadInfo &fetch_info = fetchInfo[tid]; 301 302 const ForwardLineData *line_in = getInput(tid); 303 304 unsigned int output_index = 0; 305 306 /* Pack instructions into the output while we can. This may involve 307 * using more than one input line. Note that lineWidth will be 0 308 * for faulting lines */ 309 while (line_in && 310 (line_in->isFault() || 311 fetch_info.inputIndex < line_in->lineWidth) && /* More input */ 312 output_index < outputWidth && /* More output to fill */ 313 prediction.isBubble() /* No predicted branch */) 314 { 315 ThreadContext *thread = cpu.getContext(line_in->id.threadId); 316 TheISA::Decoder *decoder = thread->getDecoderPtr(); 317 318 /* Discard line due to prediction sequence number being wrong but 319 * without the streamSeqNum number having changed */ 320 bool discard_line = 321 fetch_info.expectedStreamSeqNum == line_in->id.streamSeqNum && 322 fetch_info.predictionSeqNum != line_in->id.predictionSeqNum; 323 324 /* Set the PC if the stream changes. Setting havePC to false in 325 * a previous cycle handles all other change of flow of control 326 * issues */ 327 bool set_pc = fetch_info.lastStreamSeqNum != line_in->id.streamSeqNum; 328 329 if (!discard_line && (!fetch_info.havePC || set_pc)) { 330 /* Set the inputIndex to be the MachInst-aligned offset 331 * from lineBaseAddr of the new PC value */ 332 fetch_info.inputIndex = 333 (line_in->pc.instAddr() & BaseCPU::PCMask) - 334 line_in->lineBaseAddr; 335 DPRINTF(Fetch, "Setting new PC value: %s inputIndex: 0x%x" 336 " lineBaseAddr: 0x%x lineWidth: 0x%x\n", 337 line_in->pc, fetch_info.inputIndex, line_in->lineBaseAddr, 338 line_in->lineWidth); 339 fetch_info.pc = line_in->pc; 340 fetch_info.havePC = true; 341 decoder->reset(); 342 } 343 344 /* The generated instruction. Leave as NULL if no instruction 345 * is to be packed into the output */ 346 MinorDynInstPtr dyn_inst = NULL; 347 348 if (discard_line) { 349 /* Rest of line was from an older prediction in the same 350 * stream */ 351 DPRINTF(Fetch, "Discarding line %s (from inputIndex: %d)" 352 " due to predictionSeqNum mismatch (expected: %d)\n", 353 line_in->id, fetch_info.inputIndex, 354 fetch_info.predictionSeqNum); 355 } else if (line_in->isFault()) { 356 /* Pack a fault as a MinorDynInst with ->fault set */ 357 358 /* Make a new instruction and pick up the line, stream, 359 * prediction, thread ids from the incoming line */ 360 dyn_inst = new MinorDynInst(line_in->id); 361 362 /* Fetch and prediction sequence numbers originate here */ 363 dyn_inst->id.fetchSeqNum = fetch_info.fetchSeqNum; 364 dyn_inst->id.predictionSeqNum = fetch_info.predictionSeqNum; 365 /* To complete the set, test that exec sequence number has 366 * not been set */ 367 assert(dyn_inst->id.execSeqNum == 0); 368 369 dyn_inst->pc = fetch_info.pc; 370 371 /* Pack a faulting instruction but allow other 372 * instructions to be generated. (Fetch2 makes no 373 * immediate judgement about streamSeqNum) */ 374 dyn_inst->fault = line_in->fault; 375 DPRINTF(Fetch, "Fault being passed output_index: " 376 "%d: %s\n", output_index, dyn_inst->fault->name()); 377 } else { 378 uint8_t *line = line_in->line; 379 380 TheISA::MachInst inst_word; 381 /* The instruction is wholly in the line, can just 382 * assign */ 383 inst_word = TheISA::gtoh( 384 *(reinterpret_cast<TheISA::MachInst *> 385 (line + fetch_info.inputIndex))); 386 387 if (!decoder->instReady()) { 388 decoder->moreBytes(fetch_info.pc, 389 line_in->lineBaseAddr + fetch_info.inputIndex, 390 inst_word); 391 DPRINTF(Fetch, "Offering MachInst to decoder addr: 0x%x\n", 392 line_in->lineBaseAddr + fetch_info.inputIndex); 393 } 394 395 /* Maybe make the above a loop to accomodate ISAs with 396 * instructions longer than sizeof(MachInst) */ 397 398 if (decoder->instReady()) { 399 /* Make a new instruction and pick up the line, stream, 400 * prediction, thread ids from the incoming line */ 401 dyn_inst = new MinorDynInst(line_in->id); 402 403 /* Fetch and prediction sequence numbers originate here */ 404 dyn_inst->id.fetchSeqNum = fetch_info.fetchSeqNum; 405 dyn_inst->id.predictionSeqNum = fetch_info.predictionSeqNum; 406 /* To complete the set, test that exec sequence number 407 * has not been set */ 408 assert(dyn_inst->id.execSeqNum == 0); 409 410 /* Note that the decoder can update the given PC. 411 * Remember not to assign it until *after* calling 412 * decode */ 413 StaticInstPtr decoded_inst = decoder->decode(fetch_info.pc); 414 dyn_inst->staticInst = decoded_inst; 415 416 dyn_inst->pc = fetch_info.pc; 417 DPRINTF(Fetch, "decoder inst %s\n", *dyn_inst); 418 419 // Collect some basic inst class stats 420 if (decoded_inst->isLoad()) 421 loadInstructions++; 422 else if (decoded_inst->isStore()) 423 storeInstructions++; 424 else if (decoded_inst->isVector()) 425 vecInstructions++; 426 else if (decoded_inst->isFloating()) 427 fpInstructions++; 428 else if (decoded_inst->isInteger()) 429 intInstructions++; 430 431 DPRINTF(Fetch, "Instruction extracted from line %s" 432 " lineWidth: %d output_index: %d inputIndex: %d" 433 " pc: %s inst: %s\n", 434 line_in->id, 435 line_in->lineWidth, output_index, fetch_info.inputIndex, 436 fetch_info.pc, *dyn_inst); 437 438#if THE_ISA == X86_ISA || THE_ISA == ARM_ISA 439 /* In SE mode, it's possible to branch to a microop when 440 * replaying faults such as page faults (or simply 441 * intra-microcode branches in X86). Unfortunately, 442 * as Minor has micro-op decomposition in a separate 443 * pipeline stage from instruction decomposition, the 444 * following advancePC (which may follow a branch with 445 * microPC() != 0) *must* see a fresh macroop. This 446 * kludge should be improved with an addition to PCState 447 * but I offer it in this form for the moment 448 * 449 * X86 can branch within microops so we need to deal with 450 * the case that, after a branch, the first un-advanced PC 451 * may be pointing to a microop other than 0. Once 452 * advanced, however, the microop number *must* be 0 */ 453 fetch_info.pc.upc(0); 454 fetch_info.pc.nupc(1); 455#endif 456 457 /* Advance PC for the next instruction */ 458 TheISA::advancePC(fetch_info.pc, decoded_inst); 459 460 /* Predict any branches and issue a branch if 461 * necessary */ 462 predictBranch(dyn_inst, prediction); 463 } else { 464 DPRINTF(Fetch, "Inst not ready yet\n"); 465 } 466 467 /* Step on the pointer into the line if there's no 468 * complete instruction waiting */ 469 if (decoder->needMoreBytes()) { 470 fetch_info.inputIndex += sizeof(TheISA::MachInst); 471 472 DPRINTF(Fetch, "Updated inputIndex value PC: %s" 473 " inputIndex: 0x%x lineBaseAddr: 0x%x lineWidth: 0x%x\n", 474 line_in->pc, fetch_info.inputIndex, line_in->lineBaseAddr, 475 line_in->lineWidth); 476 } 477 } 478 479 if (dyn_inst) { 480 /* Step to next sequence number */ 481 fetch_info.fetchSeqNum++; 482 483 /* Correctly size the output before writing */ 484 if (output_index == 0) { 485 insts_out.resize(outputWidth); 486 } 487 /* Pack the generated dynamic instruction into the output */ 488 insts_out.insts[output_index] = dyn_inst; 489 output_index++; 490 491 /* Output MinorTrace instruction info for 492 * pre-microop decomposition macroops */ 493 if (DTRACE(MinorTrace) && !dyn_inst->isFault() && 494 dyn_inst->staticInst->isMacroop()) 495 { 496 dyn_inst->minorTraceInst(*this); 497 } 498 } 499 500 /* Remember the streamSeqNum of this line so we can tell when 501 * we change stream */ 502 fetch_info.lastStreamSeqNum = line_in->id.streamSeqNum; 503 504 /* Asked to discard line or there was a branch or fault */ 505 if (!prediction.isBubble() || /* The remains of a 506 line with a prediction in it */ 507 line_in->isFault() /* A line which is just a fault */) 508 { 509 DPRINTF(Fetch, "Discarding all input on branch/fault\n"); 510 dumpAllInput(tid); 511 fetch_info.havePC = false; 512 line_in = NULL; 513 } else if (discard_line) { 514 /* Just discard one line, one's behind it may have new 515 * stream sequence numbers. There's a DPRINTF above 516 * for this event */ 517 popInput(tid); 518 fetch_info.havePC = false; 519 line_in = NULL; 520 } else if (fetch_info.inputIndex == line_in->lineWidth) { 521 /* Got to end of a line, pop the line but keep PC 522 * in case this is a line-wrapping inst. */ 523 popInput(tid); 524 line_in = NULL; 525 } 526 527 if (!line_in && processMoreThanOneInput) { 528 DPRINTF(Fetch, "Wrapping\n"); 529 line_in = getInput(tid); 530 } 531 } 532 533 /* The rest of the output (if any) should already have been packed 534 * with bubble instructions by insts_out's initialisation */ 535 } 536 if (tid == InvalidThreadID) { 537 assert(insts_out.isBubble()); 538 } 539 /** Reserve a slot in the next stage and output data */ 540 *predictionOut.inputWire = prediction; 541 542 /* If we generated output, reserve space for the result in the next stage 543 * and mark the stage as being active this cycle */ 544 if (!insts_out.isBubble()) { 545 /* Note activity of following buffer */ 546 cpu.activityRecorder->activity(); 547 insts_out.threadId = tid; 548 nextStageReserve[tid].reserve(); 549 } 550 551 /* If we still have input to process and somewhere to put it, 552 * mark stage as active */ 553 for (ThreadID i = 0; i < cpu.numThreads; i++) 554 { 555 if (getInput(i) && nextStageReserve[i].canReserve()) { 556 cpu.activityRecorder->activateStage(Pipeline::Fetch2StageId); 557 break; 558 } 559 } 560 561 /* Make sure the input (if any left) is pushed */ 562 if (!inp.outputWire->isBubble()) 563 inputBuffer[inp.outputWire->id.threadId].pushTail(); 564} 565 566inline ThreadID 567Fetch2::getScheduledThread() 568{ 569 /* Select thread via policy. */ 570 std::vector<ThreadID> priority_list; 571 572 switch (cpu.threadPolicy) { 573 case Enums::SingleThreaded: 574 priority_list.push_back(0); 575 break; 576 case Enums::RoundRobin: 577 priority_list = cpu.roundRobinPriority(threadPriority); 578 break; 579 case Enums::Random: 580 priority_list = cpu.randomPriority(); 581 break; 582 default: 583 panic("Unknown fetch policy"); 584 } 585 586 for (auto tid : priority_list) { 587 if (getInput(tid) && !fetchInfo[tid].blocked) { 588 threadPriority = tid; 589 return tid; 590 } 591 } 592 593 return InvalidThreadID; 594} 595 596bool 597Fetch2::isDrained() 598{ 599 for (const auto &buffer : inputBuffer) { 600 if (!buffer.empty()) 601 return false; 602 } 603 604 return (*inp.outputWire).isBubble() && 605 (*predictionOut.inputWire).isBubble(); 606} 607 608void 609Fetch2::regStats() 610{ 611 using namespace Stats; 612 613 intInstructions 614 .name(name() + ".int_instructions") 615 .desc("Number of integer instructions successfully decoded") 616 .flags(total); 617 618 fpInstructions 619 .name(name() + ".fp_instructions") 620 .desc("Number of floating point instructions successfully decoded") 621 .flags(total); 622 623 vecInstructions 624 .name(name() + ".vec_instructions") 625 .desc("Number of SIMD instructions successfully decoded") 626 .flags(total); 627 628 loadInstructions 629 .name(name() + ".load_instructions") 630 .desc("Number of memory load instructions successfully decoded") 631 .flags(total); 632 633 storeInstructions 634 .name(name() + ".store_instructions") 635 .desc("Number of memory store instructions successfully decoded") 636 .flags(total); 637} 638 639void 640Fetch2::minorTrace() const 641{ 642 std::ostringstream data; 643 644 if (fetchInfo[0].blocked) 645 data << 'B'; 646 else 647 (*out.inputWire).reportData(data); 648 649 MINORTRACE("inputIndex=%d havePC=%d predictionSeqNum=%d insts=%s\n", 650 fetchInfo[0].inputIndex, fetchInfo[0].havePC, fetchInfo[0].predictionSeqNum, data.str()); 651 inputBuffer[0].minorTrace(); 652} 653 654} 655