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 &params,
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