fetch2.cc revision 13652:45d94ac03a27
18839Sandreas.hansson@arm.com/* 28839Sandreas.hansson@arm.com * Copyright (c) 2013-2014,2016 ARM Limited 38839Sandreas.hansson@arm.com * All rights reserved 48839Sandreas.hansson@arm.com * 58839Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 68839Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 78839Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 88839Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 98839Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 108839Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 118839Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 128839Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 133101Sstever@eecs.umich.edu * 148579Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without 153101Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are 163101Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright 173101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 183101Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 193101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 203101Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution; 213101Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its 223101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 233101Sstever@eecs.umich.edu * this software without specific prior written permission. 243101Sstever@eecs.umich.edu * 253101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 263101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 273101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 283101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 293101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 303101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 313101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 323101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 333101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 343101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 353101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 363101Sstever@eecs.umich.edu * 373101Sstever@eecs.umich.edu * Authors: Andrew Bardsley 383101Sstever@eecs.umich.edu */ 393101Sstever@eecs.umich.edu 403101Sstever@eecs.umich.edu#include "cpu/minor/fetch2.hh" 413101Sstever@eecs.umich.edu 427778Sgblack@eecs.umich.edu#include <string> 438839Sandreas.hansson@arm.com 443101Sstever@eecs.umich.edu#include "arch/decoder.hh" 453101Sstever@eecs.umich.edu#include "arch/utility.hh" 463101Sstever@eecs.umich.edu#include "cpu/minor/pipeline.hh" 473101Sstever@eecs.umich.edu#include "cpu/pred/bpred_unit.hh" 483101Sstever@eecs.umich.edu#include "debug/Branch.hh" 493101Sstever@eecs.umich.edu#include "debug/Fetch.hh" 503101Sstever@eecs.umich.edu#include "debug/MinorTrace.hh" 513101Sstever@eecs.umich.edu 523101Sstever@eecs.umich.edunamespace Minor 533101Sstever@eecs.umich.edu{ 543101Sstever@eecs.umich.edu 553101Sstever@eecs.umich.eduFetch2::Fetch2(const std::string &name, 563101Sstever@eecs.umich.edu MinorCPU &cpu_, 573101Sstever@eecs.umich.edu MinorCPUParams ¶ms, 583101Sstever@eecs.umich.edu Latch<ForwardLineData>::Output inp_, 593101Sstever@eecs.umich.edu Latch<BranchData>::Output branchInp_, 603101Sstever@eecs.umich.edu Latch<BranchData>::Input predictionOut_, 613101Sstever@eecs.umich.edu Latch<ForwardInstData>::Input out_, 623885Sbinkertn@umich.edu std::vector<InputBuffer<ForwardInstData>> &next_stage_input_buffer) : 633885Sbinkertn@umich.edu Named(name), 644762Snate@binkert.org cpu(cpu_), 653885Sbinkertn@umich.edu inp(inp_), 663885Sbinkertn@umich.edu branchInp(branchInp_), 677528Ssteve.reinhardt@amd.com predictionOut(predictionOut_), 683885Sbinkertn@umich.edu out(out_), 694380Sbinkertn@umich.edu nextStageReserve(next_stage_input_buffer), 704167Sbinkertn@umich.edu outputWidth(params.decodeInputWidth), 713102Sstever@eecs.umich.edu processMoreThanOneInput(params.fetch2CycleInput), 723101Sstever@eecs.umich.edu branchPredictor(*params.branchPred), 734762Snate@binkert.org fetchInfo(params.numThreads), 744762Snate@binkert.org threadPriority(0) 754762Snate@binkert.org{ 764762Snate@binkert.org if (outputWidth < 1) 774762Snate@binkert.org fatal("%s: decodeInputWidth must be >= 1 (%d)\n", name, outputWidth); 784762Snate@binkert.org 794762Snate@binkert.org if (params.fetch2InputBufferSize < 1) { 804762Snate@binkert.org fatal("%s: fetch2InputBufferSize must be >= 1 (%d)\n", name, 814762Snate@binkert.org params.fetch2InputBufferSize); 825033Smilesck@eecs.umich.edu } 835033Smilesck@eecs.umich.edu 845033Smilesck@eecs.umich.edu /* Per-thread input buffers */ 855033Smilesck@eecs.umich.edu for (ThreadID tid = 0; tid < params.numThreads; tid++) { 865033Smilesck@eecs.umich.edu inputBuffer.push_back( 875033Smilesck@eecs.umich.edu InputBuffer<ForwardLineData>( 885033Smilesck@eecs.umich.edu name + ".inputBuffer" + std::to_string(tid), "lines", 895033Smilesck@eecs.umich.edu params.fetch2InputBufferSize)); 905033Smilesck@eecs.umich.edu } 915033Smilesck@eecs.umich.edu} 923101Sstever@eecs.umich.edu 933101Sstever@eecs.umich.educonst ForwardLineData * 943101Sstever@eecs.umich.eduFetch2::getInput(ThreadID tid) 955033Smilesck@eecs.umich.edu{ 963101Sstever@eecs.umich.edu /* Get a line from the inputBuffer to work with */ 978596Ssteve.reinhardt@amd.com if (!inputBuffer[tid].empty()) { 988596Ssteve.reinhardt@amd.com return &(inputBuffer[tid].front()); 998596Ssteve.reinhardt@amd.com } else { 1008596Ssteve.reinhardt@amd.com return NULL; 1017673Snate@binkert.org } 1027673Snate@binkert.org} 1037673Snate@binkert.org 1047673Snate@binkert.orgvoid 1058596Ssteve.reinhardt@amd.comFetch2::popInput(ThreadID tid) 1068596Ssteve.reinhardt@amd.com{ 1078596Ssteve.reinhardt@amd.com if (!inputBuffer[tid].empty()) { 1087673Snate@binkert.org inputBuffer[tid].front().freeLine(); 1097673Snate@binkert.org inputBuffer[tid].pop(); 1107673Snate@binkert.org } 1113101Sstever@eecs.umich.edu 1123101Sstever@eecs.umich.edu fetchInfo[tid].inputIndex = 0; 1133101Sstever@eecs.umich.edu} 1143101Sstever@eecs.umich.edu 1153101Sstever@eecs.umich.eduvoid 1163101Sstever@eecs.umich.eduFetch2::dumpAllInput(ThreadID tid) 1173101Sstever@eecs.umich.edu{ 1183101Sstever@eecs.umich.edu DPRINTF(Fetch, "Dumping whole input buffer\n"); 1193101Sstever@eecs.umich.edu while (!inputBuffer[tid].empty()) 1203101Sstever@eecs.umich.edu popInput(tid); 1213101Sstever@eecs.umich.edu 1223101Sstever@eecs.umich.edu fetchInfo[tid].inputIndex = 0; 1233101Sstever@eecs.umich.edu fetchInfo[tid].havePC = false; 1243101Sstever@eecs.umich.edu} 1253101Sstever@eecs.umich.edu 1263101Sstever@eecs.umich.eduvoid 1273101Sstever@eecs.umich.eduFetch2::updateBranchPrediction(const BranchData &branch) 1283101Sstever@eecs.umich.edu{ 1293101Sstever@eecs.umich.edu MinorDynInstPtr inst = branch.inst; 1303101Sstever@eecs.umich.edu 1313101Sstever@eecs.umich.edu /* Don't even consider instructions we didn't try to predict or faults */ 1323101Sstever@eecs.umich.edu if (inst->isFault() || !inst->triedToPredict) 1333101Sstever@eecs.umich.edu return; 1343101Sstever@eecs.umich.edu 1353101Sstever@eecs.umich.edu switch (branch.reason) { 1363101Sstever@eecs.umich.edu case BranchData::NoBranch: 1373101Sstever@eecs.umich.edu /* No data to update */ 1383101Sstever@eecs.umich.edu break; 1393101Sstever@eecs.umich.edu case BranchData::Interrupt: 1403101Sstever@eecs.umich.edu /* Never try to predict interrupts */ 1413101Sstever@eecs.umich.edu break; 1423101Sstever@eecs.umich.edu case BranchData::SuspendThread: 1433101Sstever@eecs.umich.edu /* Don't need to act on suspends */ 1443101Sstever@eecs.umich.edu break; 1453101Sstever@eecs.umich.edu case BranchData::HaltFetch: 1463101Sstever@eecs.umich.edu /* Don't need to act on fetch wakeup */ 1473101Sstever@eecs.umich.edu break; 1483101Sstever@eecs.umich.edu case BranchData::BranchPrediction: 1493101Sstever@eecs.umich.edu /* Shouldn't happen. Fetch2 is the only source of 1503101Sstever@eecs.umich.edu * BranchPredictions */ 1513101Sstever@eecs.umich.edu break; 1523101Sstever@eecs.umich.edu case BranchData::UnpredictedBranch: 1533101Sstever@eecs.umich.edu /* Unpredicted branch or barrier */ 1543101Sstever@eecs.umich.edu DPRINTF(Branch, "Unpredicted branch seen inst: %s\n", *inst); 1553101Sstever@eecs.umich.edu branchPredictor.squash(inst->id.fetchSeqNum, 1563101Sstever@eecs.umich.edu branch.target, true, inst->id.threadId); 1575033Smilesck@eecs.umich.edu // Update after squashing to accomodate O3CPU 1586656Snate@binkert.org // using the branch prediction code. 1595033Smilesck@eecs.umich.edu branchPredictor.update(inst->id.fetchSeqNum, 1605033Smilesck@eecs.umich.edu inst->id.threadId); 1615033Smilesck@eecs.umich.edu break; 1623101Sstever@eecs.umich.edu case BranchData::CorrectlyPredictedBranch: 1633101Sstever@eecs.umich.edu /* Predicted taken, was taken */ 1643101Sstever@eecs.umich.edu DPRINTF(Branch, "Branch predicted correctly inst: %s\n", *inst); 1653101Sstever@eecs.umich.edu branchPredictor.update(inst->id.fetchSeqNum, 1663101Sstever@eecs.umich.edu inst->id.threadId); 1673101Sstever@eecs.umich.edu break; 1683101Sstever@eecs.umich.edu case BranchData::BadlyPredictedBranch: 1693101Sstever@eecs.umich.edu /* Predicted taken, not taken */ 1703101Sstever@eecs.umich.edu DPRINTF(Branch, "Branch mis-predicted inst: %s\n", *inst); 1713101Sstever@eecs.umich.edu branchPredictor.squash(inst->id.fetchSeqNum, 1723101Sstever@eecs.umich.edu branch.target /* Not used */, false, inst->id.threadId); 1733101Sstever@eecs.umich.edu // Update after squashing to accomodate O3CPU 1743101Sstever@eecs.umich.edu // using the branch prediction code. 1753102Sstever@eecs.umich.edu branchPredictor.update(inst->id.fetchSeqNum, 1763101Sstever@eecs.umich.edu inst->id.threadId); 1773101Sstever@eecs.umich.edu break; 1783101Sstever@eecs.umich.edu case BranchData::BadlyPredictedBranchTarget: 1797673Snate@binkert.org /* Predicted taken, was taken but to a different target */ 1808607Sgblack@eecs.umich.edu DPRINTF(Branch, "Branch mis-predicted target inst: %s target: %s\n", 1817673Snate@binkert.org *inst, branch.target); 1823101Sstever@eecs.umich.edu branchPredictor.squash(inst->id.fetchSeqNum, 1837673Snate@binkert.org branch.target, true, inst->id.threadId); 1847673Snate@binkert.org break; 1853101Sstever@eecs.umich.edu } 1867673Snate@binkert.org} 1877673Snate@binkert.org 1883101Sstever@eecs.umich.eduvoid 1893101Sstever@eecs.umich.eduFetch2::predictBranch(MinorDynInstPtr inst, BranchData &branch) 1903101Sstever@eecs.umich.edu{ 1913101Sstever@eecs.umich.edu Fetch2ThreadInfo &thread = fetchInfo[inst->id.threadId]; 1923101Sstever@eecs.umich.edu TheISA::PCState inst_pc = inst->pc; 1933101Sstever@eecs.umich.edu 1945033Smilesck@eecs.umich.edu assert(!inst->predictedTaken); 1955475Snate@binkert.org 1965475Snate@binkert.org /* Skip non-control/sys call instructions */ 1975475Snate@binkert.org if (inst->staticInst->isControl() || 1985475Snate@binkert.org inst->staticInst->isSyscall()) 1993101Sstever@eecs.umich.edu { 2003101Sstever@eecs.umich.edu /* Tried to predict */ 2013101Sstever@eecs.umich.edu inst->triedToPredict = true; 2024762Snate@binkert.org 2034762Snate@binkert.org DPRINTF(Branch, "Trying to predict for inst: %s\n", *inst); 2044762Snate@binkert.org 2053101Sstever@eecs.umich.edu if (branchPredictor.predict(inst->staticInst, 2068460SAli.Saidi@ARM.com inst->id.fetchSeqNum, inst_pc, 2078459SAli.Saidi@ARM.com inst->id.threadId)) 2088459SAli.Saidi@ARM.com { 2098459SAli.Saidi@ARM.com inst->predictedTaken = true; 2103101Sstever@eecs.umich.edu inst->predictedTarget = inst_pc; 2117528Ssteve.reinhardt@amd.com branch.target = inst_pc; 2127528Ssteve.reinhardt@amd.com } 2137528Ssteve.reinhardt@amd.com } else { 2147528Ssteve.reinhardt@amd.com DPRINTF(Branch, "Not attempting prediction for inst: %s\n", *inst); 2157528Ssteve.reinhardt@amd.com } 2167528Ssteve.reinhardt@amd.com 2173101Sstever@eecs.umich.edu /* If we predict taken, set branch and update sequence numbers */ 2187528Ssteve.reinhardt@amd.com if (inst->predictedTaken) { 2197528Ssteve.reinhardt@amd.com /* Update the predictionSeqNum and remember the streamSeqNum that it 2207528Ssteve.reinhardt@amd.com * was associated with */ 2217528Ssteve.reinhardt@amd.com thread.expectedStreamSeqNum = inst->id.streamSeqNum; 2227528Ssteve.reinhardt@amd.com 2237528Ssteve.reinhardt@amd.com BranchData new_branch = BranchData(BranchData::BranchPrediction, 2247528Ssteve.reinhardt@amd.com inst->id.threadId, 2257528Ssteve.reinhardt@amd.com inst->id.streamSeqNum, thread.predictionSeqNum + 1, 2267528Ssteve.reinhardt@amd.com inst->predictedTarget, inst); 2277528Ssteve.reinhardt@amd.com 2288321Ssteve.reinhardt@amd.com /* Mark with a new prediction number by the stream number of the 2298321Ssteve.reinhardt@amd.com * instruction causing the prediction */ 2307528Ssteve.reinhardt@amd.com thread.predictionSeqNum++; 2317528Ssteve.reinhardt@amd.com branch = new_branch; 2327528Ssteve.reinhardt@amd.com 2337528Ssteve.reinhardt@amd.com DPRINTF(Branch, "Branch predicted taken inst: %s target: %s" 2347528Ssteve.reinhardt@amd.com " new predictionSeqNum: %d\n", 2357528Ssteve.reinhardt@amd.com *inst, inst->predictedTarget, thread.predictionSeqNum); 2367528Ssteve.reinhardt@amd.com } 2377528Ssteve.reinhardt@amd.com} 2387528Ssteve.reinhardt@amd.com 2397528Ssteve.reinhardt@amd.comvoid 2407528Ssteve.reinhardt@amd.comFetch2::evaluate() 2417528Ssteve.reinhardt@amd.com{ 2427528Ssteve.reinhardt@amd.com /* Push input onto appropriate input buffer */ 2433101Sstever@eecs.umich.edu if (!inp.outputWire->isBubble()) 2448664SAli.Saidi@ARM.com inputBuffer[inp.outputWire->id.threadId].setTail(*inp.outputWire); 2458664SAli.Saidi@ARM.com 2468664SAli.Saidi@ARM.com ForwardInstData &insts_out = *out.inputWire; 2478664SAli.Saidi@ARM.com BranchData prediction; 2488664SAli.Saidi@ARM.com BranchData &branch_inp = *branchInp.outputWire; 2498664SAli.Saidi@ARM.com 2503101Sstever@eecs.umich.edu assert(insts_out.isBubble()); 2513101Sstever@eecs.umich.edu 2523101Sstever@eecs.umich.edu /* React to branches from Execute to update local branch prediction 2533101Sstever@eecs.umich.edu * structures */ 2543101Sstever@eecs.umich.edu updateBranchPrediction(branch_inp); 2553101Sstever@eecs.umich.edu 2563101Sstever@eecs.umich.edu /* If a branch arrives, don't try and do anything about it. Only 2573101Sstever@eecs.umich.edu * react to your own predictions */ 2584762Snate@binkert.org if (branch_inp.isStreamChange()) { 2594762Snate@binkert.org DPRINTF(Fetch, "Dumping all input as a stream changing branch" 2604762Snate@binkert.org " has arrived\n"); 2614762Snate@binkert.org dumpAllInput(branch_inp.threadId); 2627528Ssteve.reinhardt@amd.com fetchInfo[branch_inp.threadId].havePC = false; 2634762Snate@binkert.org } 2644762Snate@binkert.org 2654762Snate@binkert.org assert(insts_out.isBubble()); 2668596Ssteve.reinhardt@amd.com /* Even when blocked, clear out input lines with the wrong 2678596Ssteve.reinhardt@amd.com * prediction sequence number */ 2688596Ssteve.reinhardt@amd.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 2697673Snate@binkert.org Fetch2ThreadInfo &thread = fetchInfo[tid]; 2708596Ssteve.reinhardt@amd.com 2714762Snate@binkert.org thread.blocked = !nextStageReserve[tid].canReserve(); 2727673Snate@binkert.org 2738596Ssteve.reinhardt@amd.com const ForwardLineData *line_in = getInput(tid); 2747675Snate@binkert.org 2757675Snate@binkert.org while (line_in && 2767675Snate@binkert.org thread.expectedStreamSeqNum == line_in->id.streamSeqNum && 2777675Snate@binkert.org thread.predictionSeqNum != line_in->id.predictionSeqNum) 2788656Sandreas.hansson@arm.com { 2798656Sandreas.hansson@arm.com DPRINTF(Fetch, "Discarding line %s" 2808656Sandreas.hansson@arm.com " due to predictionSeqNum mismatch (expected: %d)\n", 2817675Snate@binkert.org line_in->id, thread.predictionSeqNum); 2827675Snate@binkert.org 2837673Snate@binkert.org popInput(tid); 2847675Snate@binkert.org fetchInfo[tid].havePC = false; 2857675Snate@binkert.org 2867675Snate@binkert.org if (processMoreThanOneInput) { 2877675Snate@binkert.org DPRINTF(Fetch, "Wrapping\n"); 2887675Snate@binkert.org line_in = getInput(tid); 2897673Snate@binkert.org } else { 2907675Snate@binkert.org line_in = NULL; 2917675Snate@binkert.org } 2927675Snate@binkert.org } 2937675Snate@binkert.org } 2947675Snate@binkert.org 2957675Snate@binkert.org ThreadID tid = getScheduledThread(); 2967675Snate@binkert.org DPRINTF(Fetch, "Scheduled Thread: %d\n", tid); 2977675Snate@binkert.org 2987675Snate@binkert.org assert(insts_out.isBubble()); 2997675Snate@binkert.org if (tid != InvalidThreadID) { 3007675Snate@binkert.org Fetch2ThreadInfo &fetch_info = fetchInfo[tid]; 3017675Snate@binkert.org 3027675Snate@binkert.org const ForwardLineData *line_in = getInput(tid); 3037675Snate@binkert.org 3047675Snate@binkert.org unsigned int output_index = 0; 3057675Snate@binkert.org 3067673Snate@binkert.org /* Pack instructions into the output while we can. This may involve 3077673Snate@binkert.org * using more than one input line. Note that lineWidth will be 0 3083101Sstever@eecs.umich.edu * for faulting lines */ 3097675Snate@binkert.org while (line_in && 3107675Snate@binkert.org (line_in->isFault() || 3117673Snate@binkert.org fetch_info.inputIndex < line_in->lineWidth) && /* More input */ 3127673Snate@binkert.org output_index < outputWidth && /* More output to fill */ 3137673Snate@binkert.org prediction.isBubble() /* No predicted branch */) 3143101Sstever@eecs.umich.edu { 3157673Snate@binkert.org ThreadContext *thread = cpu.getContext(line_in->id.threadId); 3167673Snate@binkert.org TheISA::Decoder *decoder = thread->getDecoderPtr(); 3173101Sstever@eecs.umich.edu 3183101Sstever@eecs.umich.edu /* Discard line due to prediction sequence number being wrong but 3193101Sstever@eecs.umich.edu * without the streamSeqNum number having changed */ 3203101Sstever@eecs.umich.edu bool discard_line = 3213101Sstever@eecs.umich.edu fetch_info.expectedStreamSeqNum == line_in->id.streamSeqNum && 3223101Sstever@eecs.umich.edu fetch_info.predictionSeqNum != line_in->id.predictionSeqNum; 3233101Sstever@eecs.umich.edu 3243101Sstever@eecs.umich.edu /* Set the PC if the stream changes. Setting havePC to false in 3253101Sstever@eecs.umich.edu * a previous cycle handles all other change of flow of control 3263101Sstever@eecs.umich.edu * issues */ 3273101Sstever@eecs.umich.edu bool set_pc = fetch_info.lastStreamSeqNum != line_in->id.streamSeqNum; 3283101Sstever@eecs.umich.edu 3293101Sstever@eecs.umich.edu if (!discard_line && (!fetch_info.havePC || set_pc)) { 3303101Sstever@eecs.umich.edu /* Set the inputIndex to be the MachInst-aligned offset 3313101Sstever@eecs.umich.edu * from lineBaseAddr of the new PC value */ 3325033Smilesck@eecs.umich.edu fetch_info.inputIndex = 3335033Smilesck@eecs.umich.edu (line_in->pc.instAddr() & BaseCPU::PCMask) - 3343101Sstever@eecs.umich.edu line_in->lineBaseAddr; 3353101Sstever@eecs.umich.edu DPRINTF(Fetch, "Setting new PC value: %s inputIndex: 0x%x" 3363101Sstever@eecs.umich.edu " lineBaseAddr: 0x%x lineWidth: 0x%x\n", 3373101Sstever@eecs.umich.edu line_in->pc, fetch_info.inputIndex, line_in->lineBaseAddr, 3383101Sstever@eecs.umich.edu line_in->lineWidth); 3393101Sstever@eecs.umich.edu fetch_info.pc = line_in->pc; 3403101Sstever@eecs.umich.edu fetch_info.havePC = true; 3413101Sstever@eecs.umich.edu decoder->reset(); 3423101Sstever@eecs.umich.edu } 3433101Sstever@eecs.umich.edu 3443101Sstever@eecs.umich.edu /* The generated instruction. Leave as NULL if no instruction 3453101Sstever@eecs.umich.edu * is to be packed into the output */ 3463101Sstever@eecs.umich.edu MinorDynInstPtr dyn_inst = NULL; 3473101Sstever@eecs.umich.edu 3483101Sstever@eecs.umich.edu if (discard_line) { 3493101Sstever@eecs.umich.edu /* Rest of line was from an older prediction in the same 3503101Sstever@eecs.umich.edu * stream */ 3513101Sstever@eecs.umich.edu DPRINTF(Fetch, "Discarding line %s (from inputIndex: %d)" 3523101Sstever@eecs.umich.edu " due to predictionSeqNum mismatch (expected: %d)\n", 3533101Sstever@eecs.umich.edu line_in->id, fetch_info.inputIndex, 3543101Sstever@eecs.umich.edu fetch_info.predictionSeqNum); 3553101Sstever@eecs.umich.edu } else if (line_in->isFault()) { 3563101Sstever@eecs.umich.edu /* Pack a fault as a MinorDynInst with ->fault set */ 3573101Sstever@eecs.umich.edu 3583101Sstever@eecs.umich.edu /* Make a new instruction and pick up the line, stream, 3597673Snate@binkert.org * prediction, thread ids from the incoming line */ 3607673Snate@binkert.org dyn_inst = new MinorDynInst(line_in->id); 3617673Snate@binkert.org 3627673Snate@binkert.org /* Fetch and prediction sequence numbers originate here */ 3637673Snate@binkert.org dyn_inst->id.fetchSeqNum = fetch_info.fetchSeqNum; 3647673Snate@binkert.org dyn_inst->id.predictionSeqNum = fetch_info.predictionSeqNum; 3657673Snate@binkert.org /* To complete the set, test that exec sequence number has 3667673Snate@binkert.org * not been set */ 3674762Snate@binkert.org assert(dyn_inst->id.execSeqNum == 0); 3684762Snate@binkert.org 3694762Snate@binkert.org dyn_inst->pc = fetch_info.pc; 3703101Sstever@eecs.umich.edu 3713101Sstever@eecs.umich.edu /* Pack a faulting instruction but allow other 3723101Sstever@eecs.umich.edu * instructions to be generated. (Fetch2 makes no 3733101Sstever@eecs.umich.edu * immediate judgement about streamSeqNum) */ 3743101Sstever@eecs.umich.edu dyn_inst->fault = line_in->fault; 3753101Sstever@eecs.umich.edu DPRINTF(Fetch, "Fault being passed output_index: " 3763101Sstever@eecs.umich.edu "%d: %s\n", output_index, dyn_inst->fault->name()); 3773101Sstever@eecs.umich.edu } else { 3783101Sstever@eecs.umich.edu uint8_t *line = line_in->line; 3793101Sstever@eecs.umich.edu 3803101Sstever@eecs.umich.edu TheISA::MachInst inst_word; 3813714Sstever@eecs.umich.edu /* The instruction is wholly in the line, can just 3823714Sstever@eecs.umich.edu * assign */ 3833714Sstever@eecs.umich.edu inst_word = TheISA::gtoh( 3843714Sstever@eecs.umich.edu *(reinterpret_cast<TheISA::MachInst *> 3853714Sstever@eecs.umich.edu (line + fetch_info.inputIndex))); 3863714Sstever@eecs.umich.edu 3873101Sstever@eecs.umich.edu if (!decoder->instReady()) { 3883101Sstever@eecs.umich.edu decoder->moreBytes(fetch_info.pc, 3893101Sstever@eecs.umich.edu line_in->lineBaseAddr + fetch_info.inputIndex, 3903101Sstever@eecs.umich.edu inst_word); 3913101Sstever@eecs.umich.edu DPRINTF(Fetch, "Offering MachInst to decoder addr: 0x%x\n", 3923101Sstever@eecs.umich.edu line_in->lineBaseAddr + fetch_info.inputIndex); 3933101Sstever@eecs.umich.edu } 3943101Sstever@eecs.umich.edu 3953101Sstever@eecs.umich.edu /* Maybe make the above a loop to accomodate ISAs with 3963101Sstever@eecs.umich.edu * instructions longer than sizeof(MachInst) */ 3973101Sstever@eecs.umich.edu 3983101Sstever@eecs.umich.edu if (decoder->instReady()) { 3993101Sstever@eecs.umich.edu /* Make a new instruction and pick up the line, stream, 4003101Sstever@eecs.umich.edu * prediction, thread ids from the incoming line */ 4013101Sstever@eecs.umich.edu dyn_inst = new MinorDynInst(line_in->id); 4023101Sstever@eecs.umich.edu 4033101Sstever@eecs.umich.edu /* Fetch and prediction sequence numbers originate here */ 4043101Sstever@eecs.umich.edu dyn_inst->id.fetchSeqNum = fetch_info.fetchSeqNum; 4053101Sstever@eecs.umich.edu dyn_inst->id.predictionSeqNum = fetch_info.predictionSeqNum; 4063101Sstever@eecs.umich.edu /* To complete the set, test that exec sequence number 4073101Sstever@eecs.umich.edu * has not been set */ 4083101Sstever@eecs.umich.edu assert(dyn_inst->id.execSeqNum == 0); 4093101Sstever@eecs.umich.edu 4103101Sstever@eecs.umich.edu /* Note that the decoder can update the given PC. 4113101Sstever@eecs.umich.edu * Remember not to assign it until *after* calling 4125033Smilesck@eecs.umich.edu * decode */ 4133101Sstever@eecs.umich.edu StaticInstPtr decoded_inst = decoder->decode(fetch_info.pc); 4143101Sstever@eecs.umich.edu dyn_inst->staticInst = decoded_inst; 4153101Sstever@eecs.umich.edu 4163101Sstever@eecs.umich.edu dyn_inst->pc = fetch_info.pc; 4173101Sstever@eecs.umich.edu DPRINTF(Fetch, "decoder inst %s\n", *dyn_inst); 4183101Sstever@eecs.umich.edu 4193101Sstever@eecs.umich.edu // Collect some basic inst class stats 4203101Sstever@eecs.umich.edu if (decoded_inst->isLoad()) 4213101Sstever@eecs.umich.edu loadInstructions++; 4223101Sstever@eecs.umich.edu else if (decoded_inst->isStore()) 4233101Sstever@eecs.umich.edu storeInstructions++; 4243101Sstever@eecs.umich.edu else if (decoded_inst->isAtomic()) 4255822Ssaidi@eecs.umich.edu amoInstructions++; 4265822Ssaidi@eecs.umich.edu else if (decoded_inst->isVector()) 4273101Sstever@eecs.umich.edu vecInstructions++; 4283101Sstever@eecs.umich.edu else if (decoded_inst->isFloating()) 4293101Sstever@eecs.umich.edu fpInstructions++; 4303101Sstever@eecs.umich.edu else if (decoded_inst->isInteger()) 4313101Sstever@eecs.umich.edu intInstructions++; 4323101Sstever@eecs.umich.edu 4333101Sstever@eecs.umich.edu DPRINTF(Fetch, "Instruction extracted from line %s" 4343101Sstever@eecs.umich.edu " lineWidth: %d output_index: %d inputIndex: %d" 4353101Sstever@eecs.umich.edu " pc: %s inst: %s\n", 4363101Sstever@eecs.umich.edu line_in->id, 4373101Sstever@eecs.umich.edu line_in->lineWidth, output_index, fetch_info.inputIndex, 4383101Sstever@eecs.umich.edu fetch_info.pc, *dyn_inst); 4393101Sstever@eecs.umich.edu 4403101Sstever@eecs.umich.edu#if THE_ISA == X86_ISA || THE_ISA == ARM_ISA 4413101Sstever@eecs.umich.edu /* In SE mode, it's possible to branch to a microop when 4423101Sstever@eecs.umich.edu * replaying faults such as page faults (or simply 4433101Sstever@eecs.umich.edu * intra-microcode branches in X86). Unfortunately, 4443101Sstever@eecs.umich.edu * as Minor has micro-op decomposition in a separate 4453101Sstever@eecs.umich.edu * pipeline stage from instruction decomposition, the 4463101Sstever@eecs.umich.edu * following advancePC (which may follow a branch with 4473101Sstever@eecs.umich.edu * microPC() != 0) *must* see a fresh macroop. This 4483102Sstever@eecs.umich.edu * kludge should be improved with an addition to PCState 4493714Sstever@eecs.umich.edu * but I offer it in this form for the moment 4503101Sstever@eecs.umich.edu * 4513714Sstever@eecs.umich.edu * X86 can branch within microops so we need to deal with 4523714Sstever@eecs.umich.edu * the case that, after a branch, the first un-advanced PC 4533714Sstever@eecs.umich.edu * may be pointing to a microop other than 0. Once 4543101Sstever@eecs.umich.edu * advanced, however, the microop number *must* be 0 */ 4553101Sstever@eecs.umich.edu fetch_info.pc.upc(0); 4567673Snate@binkert.org fetch_info.pc.nupc(1); 4577673Snate@binkert.org#endif 4587673Snate@binkert.org 4597673Snate@binkert.org /* Advance PC for the next instruction */ 4607673Snate@binkert.org TheISA::advancePC(fetch_info.pc, decoded_inst); 4617673Snate@binkert.org 4627673Snate@binkert.org /* Predict any branches and issue a branch if 4637673Snate@binkert.org * necessary */ 4647673Snate@binkert.org predictBranch(dyn_inst, prediction); 4657673Snate@binkert.org } else { 4667673Snate@binkert.org DPRINTF(Fetch, "Inst not ready yet\n"); 4674762Snate@binkert.org } 4684762Snate@binkert.org 4694762Snate@binkert.org /* Step on the pointer into the line if there's no 4703101Sstever@eecs.umich.edu * complete instruction waiting */ 4713101Sstever@eecs.umich.edu if (decoder->needMoreBytes()) { 4723101Sstever@eecs.umich.edu fetch_info.inputIndex += sizeof(TheISA::MachInst); 4733101Sstever@eecs.umich.edu 4743101Sstever@eecs.umich.edu DPRINTF(Fetch, "Updated inputIndex value PC: %s" 4753101Sstever@eecs.umich.edu " inputIndex: 0x%x lineBaseAddr: 0x%x lineWidth: 0x%x\n", 4763101Sstever@eecs.umich.edu line_in->pc, fetch_info.inputIndex, line_in->lineBaseAddr, 4773101Sstever@eecs.umich.edu line_in->lineWidth); 4783101Sstever@eecs.umich.edu } 4793101Sstever@eecs.umich.edu } 4803101Sstever@eecs.umich.edu 4813101Sstever@eecs.umich.edu if (dyn_inst) { 4823101Sstever@eecs.umich.edu /* Step to next sequence number */ 4833101Sstever@eecs.umich.edu fetch_info.fetchSeqNum++; 4843101Sstever@eecs.umich.edu 4853101Sstever@eecs.umich.edu /* Correctly size the output before writing */ 4863101Sstever@eecs.umich.edu if (output_index == 0) { 4873101Sstever@eecs.umich.edu insts_out.resize(outputWidth); 4883101Sstever@eecs.umich.edu } 4893101Sstever@eecs.umich.edu /* Pack the generated dynamic instruction into the output */ 4904446Sbinkertn@umich.edu insts_out.insts[output_index] = dyn_inst; 4913101Sstever@eecs.umich.edu output_index++; 4925468Snate@binkert.org 4935468Snate@binkert.org /* Output MinorTrace instruction info for 4945468Snate@binkert.org * pre-microop decomposition macroops */ 4955468Snate@binkert.org if (DTRACE(MinorTrace) && !dyn_inst->isFault() && 4965468Snate@binkert.org dyn_inst->staticInst->isMacroop()) 4975468Snate@binkert.org { 4985468Snate@binkert.org dyn_inst->minorTraceInst(*this); 4994762Snate@binkert.org } 5004762Snate@binkert.org } 5014762Snate@binkert.org 5023101Sstever@eecs.umich.edu /* Remember the streamSeqNum of this line so we can tell when 5033101Sstever@eecs.umich.edu * we change stream */ 5043101Sstever@eecs.umich.edu fetch_info.lastStreamSeqNum = line_in->id.streamSeqNum; 5053101Sstever@eecs.umich.edu 5063101Sstever@eecs.umich.edu /* Asked to discard line or there was a branch or fault */ 5073101Sstever@eecs.umich.edu if (!prediction.isBubble() || /* The remains of a 5083101Sstever@eecs.umich.edu line with a prediction in it */ 5093101Sstever@eecs.umich.edu line_in->isFault() /* A line which is just a fault */) 5103102Sstever@eecs.umich.edu { 5113101Sstever@eecs.umich.edu DPRINTF(Fetch, "Discarding all input on branch/fault\n"); 5123101Sstever@eecs.umich.edu dumpAllInput(tid); 5133101Sstever@eecs.umich.edu fetch_info.havePC = false; 5144168Sbinkertn@umich.edu line_in = NULL; 5153101Sstever@eecs.umich.edu } else if (discard_line) { 5163101Sstever@eecs.umich.edu /* Just discard one line, one's behind it may have new 5173101Sstever@eecs.umich.edu * stream sequence numbers. There's a DPRINTF above 5183101Sstever@eecs.umich.edu * for this event */ 5193101Sstever@eecs.umich.edu popInput(tid); 5203101Sstever@eecs.umich.edu fetch_info.havePC = false; 5213102Sstever@eecs.umich.edu line_in = NULL; 5223101Sstever@eecs.umich.edu } else if (fetch_info.inputIndex == line_in->lineWidth) { 5233101Sstever@eecs.umich.edu /* Got to end of a line, pop the line but keep PC 5243101Sstever@eecs.umich.edu * in case this is a line-wrapping inst. */ 5253101Sstever@eecs.umich.edu popInput(tid); 5263101Sstever@eecs.umich.edu line_in = NULL; 5273101Sstever@eecs.umich.edu } 5283101Sstever@eecs.umich.edu 5293101Sstever@eecs.umich.edu if (!line_in && processMoreThanOneInput) { 5303101Sstever@eecs.umich.edu DPRINTF(Fetch, "Wrapping\n"); 5313101Sstever@eecs.umich.edu line_in = getInput(tid); 5323101Sstever@eecs.umich.edu } 5333102Sstever@eecs.umich.edu } 5343101Sstever@eecs.umich.edu 5353101Sstever@eecs.umich.edu /* The rest of the output (if any) should already have been packed 5363101Sstever@eecs.umich.edu * with bubble instructions by insts_out's initialisation */ 5373584Ssaidi@eecs.umich.edu } 5383584Ssaidi@eecs.umich.edu if (tid == InvalidThreadID) { 5393584Ssaidi@eecs.umich.edu assert(insts_out.isBubble()); 5403584Ssaidi@eecs.umich.edu } 5413584Ssaidi@eecs.umich.edu /** Reserve a slot in the next stage and output data */ 5423101Sstever@eecs.umich.edu *predictionOut.inputWire = prediction; 5433101Sstever@eecs.umich.edu 5445033Smilesck@eecs.umich.edu /* If we generated output, reserve space for the result in the next stage 5453101Sstever@eecs.umich.edu * and mark the stage as being active this cycle */ 5463101Sstever@eecs.umich.edu if (!insts_out.isBubble()) { 5473101Sstever@eecs.umich.edu /* Note activity of following buffer */ 5483101Sstever@eecs.umich.edu cpu.activityRecorder->activity(); 5493101Sstever@eecs.umich.edu insts_out.threadId = tid; 5503101Sstever@eecs.umich.edu nextStageReserve[tid].reserve(); 5513101Sstever@eecs.umich.edu } 5523101Sstever@eecs.umich.edu 5533101Sstever@eecs.umich.edu /* If we still have input to process and somewhere to put it, 5543101Sstever@eecs.umich.edu * mark stage as active */ 5553101Sstever@eecs.umich.edu for (ThreadID i = 0; i < cpu.numThreads; i++) 5563101Sstever@eecs.umich.edu { 5573101Sstever@eecs.umich.edu if (getInput(i) && nextStageReserve[i].canReserve()) { 5583101Sstever@eecs.umich.edu cpu.activityRecorder->activateStage(Pipeline::Fetch2StageId); 5593101Sstever@eecs.umich.edu break; 5603101Sstever@eecs.umich.edu } 5613101Sstever@eecs.umich.edu } 5623101Sstever@eecs.umich.edu 5633101Sstever@eecs.umich.edu /* Make sure the input (if any left) is pushed */ 5643101Sstever@eecs.umich.edu if (!inp.outputWire->isBubble()) 5653101Sstever@eecs.umich.edu inputBuffer[inp.outputWire->id.threadId].pushTail(); 5663101Sstever@eecs.umich.edu} 5673101Sstever@eecs.umich.edu 5683101Sstever@eecs.umich.eduinline ThreadID 5693101Sstever@eecs.umich.eduFetch2::getScheduledThread() 5703101Sstever@eecs.umich.edu{ 5713101Sstever@eecs.umich.edu /* Select thread via policy. */ 5723101Sstever@eecs.umich.edu std::vector<ThreadID> priority_list; 5733101Sstever@eecs.umich.edu 5745219Ssaidi@eecs.umich.edu switch (cpu.threadPolicy) { 5755219Ssaidi@eecs.umich.edu case Enums::SingleThreaded: 5765219Ssaidi@eecs.umich.edu priority_list.push_back(0); 5773101Sstever@eecs.umich.edu break; 5783101Sstever@eecs.umich.edu case Enums::RoundRobin: 5793101Sstever@eecs.umich.edu priority_list = cpu.roundRobinPriority(threadPriority); 5803101Sstever@eecs.umich.edu break; 5813101Sstever@eecs.umich.edu case Enums::Random: 5823101Sstever@eecs.umich.edu priority_list = cpu.randomPriority(); 5833101Sstever@eecs.umich.edu break; 5843101Sstever@eecs.umich.edu default: 5853101Sstever@eecs.umich.edu panic("Unknown fetch policy"); 5863101Sstever@eecs.umich.edu } 5873101Sstever@eecs.umich.edu 5883101Sstever@eecs.umich.edu for (auto tid : priority_list) { 5893101Sstever@eecs.umich.edu if (cpu.getContext(tid)->status() == ThreadContext::Active && 5903101Sstever@eecs.umich.edu getInput(tid) && 5913101Sstever@eecs.umich.edu !fetchInfo[tid].blocked) { 5923101Sstever@eecs.umich.edu threadPriority = tid; 5937673Snate@binkert.org return tid; 5947673Snate@binkert.org } 5957675Snate@binkert.org } 5967673Snate@binkert.org 5977675Snate@binkert.org return InvalidThreadID; 5987675Snate@binkert.org} 5997675Snate@binkert.org 6007675Snate@binkert.orgbool 6017675Snate@binkert.orgFetch2::isDrained() 6027673Snate@binkert.org{ 6033101Sstever@eecs.umich.edu for (const auto &buffer : inputBuffer) { 6043101Sstever@eecs.umich.edu if (!buffer.empty()) 6057673Snate@binkert.org return false; 6064762Snate@binkert.org } 6077675Snate@binkert.org 6084762Snate@binkert.org return (*inp.outputWire).isBubble() && 6094762Snate@binkert.org (*predictionOut.inputWire).isBubble(); 6104762Snate@binkert.org} 6114762Snate@binkert.org 6124762Snate@binkert.orgvoid 6133101Sstever@eecs.umich.eduFetch2::regStats() 6143101Sstever@eecs.umich.edu{ 6153101Sstever@eecs.umich.edu using namespace Stats; 6167673Snate@binkert.org 6174762Snate@binkert.org intInstructions 6187675Snate@binkert.org .name(name() + ".int_instructions") 6194762Snate@binkert.org .desc("Number of integer instructions successfully decoded") 6204762Snate@binkert.org .flags(total); 6214762Snate@binkert.org 6224762Snate@binkert.org fpInstructions 6234762Snate@binkert.org .name(name() + ".fp_instructions") 6243101Sstever@eecs.umich.edu .desc("Number of floating point instructions successfully decoded") 6253101Sstever@eecs.umich.edu .flags(total); 6263101Sstever@eecs.umich.edu 6273101Sstever@eecs.umich.edu vecInstructions 6283101Sstever@eecs.umich.edu .name(name() + ".vec_instructions") 6293101Sstever@eecs.umich.edu .desc("Number of SIMD instructions successfully decoded") 6303101Sstever@eecs.umich.edu .flags(total); 6313101Sstever@eecs.umich.edu 6323102Sstever@eecs.umich.edu loadInstructions 6333101Sstever@eecs.umich.edu .name(name() + ".load_instructions") 6343101Sstever@eecs.umich.edu .desc("Number of memory load instructions successfully decoded") 6353101Sstever@eecs.umich.edu .flags(total); 6364762Snate@binkert.org 6374762Snate@binkert.org storeInstructions 6384762Snate@binkert.org .name(name() + ".store_instructions") 6393101Sstever@eecs.umich.edu .desc("Number of memory store instructions successfully decoded") 6403101Sstever@eecs.umich.edu .flags(total); 6413101Sstever@eecs.umich.edu 6428934SBrad.Beckmann@amd.com amoInstructions 6438934SBrad.Beckmann@amd.com .name(name() + ".amo_instructions") 6448934SBrad.Beckmann@amd.com .desc("Number of memory atomic instructions successfully decoded") 6458934SBrad.Beckmann@amd.com .flags(total); 6468934SBrad.Beckmann@amd.com} 6473101Sstever@eecs.umich.edu 6483101Sstever@eecs.umich.eduvoid 6493101Sstever@eecs.umich.eduFetch2::minorTrace() const 6503101Sstever@eecs.umich.edu{ 6513101Sstever@eecs.umich.edu std::ostringstream data; 6523101Sstever@eecs.umich.edu 6533101Sstever@eecs.umich.edu if (fetchInfo[0].blocked) 6543101Sstever@eecs.umich.edu data << 'B'; 6553101Sstever@eecs.umich.edu else 6563101Sstever@eecs.umich.edu (*out.inputWire).reportData(data); 6573101Sstever@eecs.umich.edu 6583101Sstever@eecs.umich.edu MINORTRACE("inputIndex=%d havePC=%d predictionSeqNum=%d insts=%s\n", 6593101Sstever@eecs.umich.edu fetchInfo[0].inputIndex, fetchInfo[0].havePC, fetchInfo[0].predictionSeqNum, data.str()); 6603101Sstever@eecs.umich.edu inputBuffer[0].minorTrace(); 6613101Sstever@eecs.umich.edu} 6623101Sstever@eecs.umich.edu 6633101Sstever@eecs.umich.edu} 6644380Sbinkertn@umich.edu