cpu.cc revision 14085
12SN/A/*
21762SN/A * Copyright (c) 2011-2012, 2014, 2016, 2017, 2019 ARM Limited
32SN/A * Copyright (c) 2013 Advanced Micro Devices, Inc.
42SN/A * All rights reserved
52SN/A *
62SN/A * The license below extends only to copyright in the software and shall
72SN/A * not be construed as granting a license to any other intellectual
82SN/A * property including but not limited to intellectual property relating
92SN/A * to a hardware implementation of the functionality of the software
102SN/A * licensed hereunder.  You may use the software subject to the license
112SN/A * terms below provided that you ensure that this notice is replicated
122SN/A * unmodified and in its entirety in all distributions of the software,
132SN/A * modified or unmodified, in source code or in binary form.
142SN/A *
152SN/A * Copyright (c) 2004-2006 The Regents of The University of Michigan
162SN/A * Copyright (c) 2011 Regents of the University of California
172SN/A * All rights reserved.
182SN/A *
192SN/A * Redistribution and use in source and binary forms, with or without
202SN/A * modification, are permitted provided that the following conditions are
212SN/A * met: redistributions of source code must retain the above copyright
222SN/A * notice, this list of conditions and the following disclaimer;
232SN/A * redistributions in binary form must reproduce the above copyright
242SN/A * notice, this list of conditions and the following disclaimer in the
252SN/A * documentation and/or other materials provided with the distribution;
262SN/A * neither the name of the copyright holders nor the names of its
272665Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from
282665Ssaidi@eecs.umich.edu * this software without specific prior written permission.
292665Ssaidi@eecs.umich.edu *
302665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
312665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
322SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
332SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
342SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
352SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
363506Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
373506Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
382SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
392973Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
403584Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4156SN/A *
423614Sgblack@eecs.umich.edu * Authors: Kevin Lim
431717SN/A *          Korey Sewell
442518SN/A *          Rick Strong
4556SN/A */
462518SN/A
472518SN/A#include "cpu/o3/cpu.hh"
482SN/A
493614Sgblack@eecs.umich.edu#include "arch/generic/traits.hh"
503614Sgblack@eecs.umich.edu#include "arch/kernel_stats.hh"
513614Sgblack@eecs.umich.edu#include "config/the_isa.hh"
523614Sgblack@eecs.umich.edu#include "cpu/activity.hh"
533065Sgblack@eecs.umich.edu#include "cpu/checker/cpu.hh"
543065Sgblack@eecs.umich.edu#include "cpu/checker/thread_context.hh"
553506Ssaidi@eecs.umich.edu#include "cpu/o3/isa_specific.hh"
563065Sgblack@eecs.umich.edu#include "cpu/o3/thread_context.hh"
572SN/A#include "cpu/quiesce_event.hh"
582973Sgblack@eecs.umich.edu#include "cpu/simple_thread.hh"
592SN/A#include "cpu/thread_context.hh"
603840Shsul@eecs.umich.edu#include "debug/Activity.hh"
613825Ssaidi@eecs.umich.edu#include "debug/Drain.hh"
623903Ssaidi@eecs.umich.edu#include "debug/O3CPU.hh"
633840Shsul@eecs.umich.edu#include "debug/Quiesce.hh"
643825Ssaidi@eecs.umich.edu#include "enums/MemoryMode.hh"
653506Ssaidi@eecs.umich.edu#include "sim/core.hh"
663506Ssaidi@eecs.umich.edu#include "sim/full_system.hh"
673506Ssaidi@eecs.umich.edu#include "sim/process.hh"
683506Ssaidi@eecs.umich.edu#include "sim/stat_control.hh"
692SN/A#include "sim/system.hh"
702SN/A
712SN/A#if THE_ISA == ALPHA_ISA
722SN/A#include "arch/alpha/osfpal.hh"
732SN/A#include "debug/Activity.hh"
743748Sgblack@eecs.umich.edu
753748Sgblack@eecs.umich.edu#endif
763748Sgblack@eecs.umich.edu
773748Sgblack@eecs.umich.edustruct BaseCPUParams;
783748Sgblack@eecs.umich.edu
793748Sgblack@eecs.umich.eduusing namespace TheISA;
803748Sgblack@eecs.umich.eduusing namespace std;
813748Sgblack@eecs.umich.edu
823748Sgblack@eecs.umich.eduBaseO3CPU::BaseO3CPU(BaseCPUParams *params)
833748Sgblack@eecs.umich.edu    : BaseCPU(params)
843748Sgblack@eecs.umich.edu{
853748Sgblack@eecs.umich.edu}
863748Sgblack@eecs.umich.edu
873748Sgblack@eecs.umich.eduvoid
883748Sgblack@eecs.umich.eduBaseO3CPU::regStats()
893748Sgblack@eecs.umich.edu{
903748Sgblack@eecs.umich.edu    BaseCPU::regStats();
913748Sgblack@eecs.umich.edu}
923748Sgblack@eecs.umich.edu
933748Sgblack@eecs.umich.edutemplate<class Impl>
943748Sgblack@eecs.umich.edubool
953748Sgblack@eecs.umich.eduFullO3CPU<Impl>::IcachePort::recvTimingResp(PacketPtr pkt)
963748Sgblack@eecs.umich.edu{
973748Sgblack@eecs.umich.edu    DPRINTF(O3CPU, "Fetch unit received timing\n");
983748Sgblack@eecs.umich.edu    // We shouldn't ever get a cacheable block in Modified state
993748Sgblack@eecs.umich.edu    assert(pkt->req->isUncacheable() ||
1003748Sgblack@eecs.umich.edu           !(pkt->cacheResponding() && !pkt->hasSharers()));
1013748Sgblack@eecs.umich.edu    fetch->processCacheCompletion(pkt);
1023748Sgblack@eecs.umich.edu
1033748Sgblack@eecs.umich.edu    return true;
1043748Sgblack@eecs.umich.edu}
1053748Sgblack@eecs.umich.edu
1063748Sgblack@eecs.umich.edutemplate<class Impl>
1073748Sgblack@eecs.umich.eduvoid
1083748Sgblack@eecs.umich.eduFullO3CPU<Impl>::IcachePort::recvReqRetry()
1093748Sgblack@eecs.umich.edu{
1103748Sgblack@eecs.umich.edu    fetch->recvReqRetry();
1113748Sgblack@eecs.umich.edu}
1123748Sgblack@eecs.umich.edu
1133748Sgblack@eecs.umich.edutemplate <class Impl>
1143748Sgblack@eecs.umich.edubool
1153748Sgblack@eecs.umich.eduFullO3CPU<Impl>::DcachePort::recvTimingResp(PacketPtr pkt)
1163748Sgblack@eecs.umich.edu{
1173748Sgblack@eecs.umich.edu    return lsq->recvTimingResp(pkt);
1183748Sgblack@eecs.umich.edu}
1193748Sgblack@eecs.umich.edu
1203748Sgblack@eecs.umich.edutemplate <class Impl>
1213748Sgblack@eecs.umich.eduvoid
1223748Sgblack@eecs.umich.eduFullO3CPU<Impl>::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
1233748Sgblack@eecs.umich.edu{
1242SN/A    for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
1252SN/A        if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
1262SN/A            cpu->wakeup(tid);
1272SN/A        }
1283903Ssaidi@eecs.umich.edu    }
1292973Sgblack@eecs.umich.edu    lsq->recvTimingSnoopReq(pkt);
1302973Sgblack@eecs.umich.edu}
1313065Sgblack@eecs.umich.edu
1323380Sgblack@eecs.umich.edutemplate <class Impl>
1333380Sgblack@eecs.umich.eduvoid
1343380Sgblack@eecs.umich.eduFullO3CPU<Impl>::DcachePort::recvReqRetry()
1353380Sgblack@eecs.umich.edu{
1363380Sgblack@eecs.umich.edu    lsq->recvReqRetry();
1373380Sgblack@eecs.umich.edu}
1383380Sgblack@eecs.umich.edu
1393380Sgblack@eecs.umich.edutemplate <class Impl>
1403380Sgblack@eecs.umich.eduFullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
1413380Sgblack@eecs.umich.edu    : BaseO3CPU(params),
1423380Sgblack@eecs.umich.edu      itb(params->itb),
1433380Sgblack@eecs.umich.edu      dtb(params->dtb),
1443380Sgblack@eecs.umich.edu      tickEvent([this]{ tick(); }, "FullO3CPU tick",
1453380Sgblack@eecs.umich.edu                false, Event::CPU_Tick_Pri),
1463065Sgblack@eecs.umich.edu      threadExitEvent([this]{ exitThreads(); }, "FullO3CPU exit threads",
1473588Sgblack@eecs.umich.edu                false, Event::CPU_Exit_Pri),
1483588Sgblack@eecs.umich.edu#ifndef NDEBUG
1493588Sgblack@eecs.umich.edu      instcount(0),
1503380Sgblack@eecs.umich.edu#endif
1513380Sgblack@eecs.umich.edu      removeInstsThisCycle(false),
1523059Sgblack@eecs.umich.edu      fetch(this, params),
1533588Sgblack@eecs.umich.edu      decode(this, params),
1543380Sgblack@eecs.umich.edu      rename(this, params),
1553380Sgblack@eecs.umich.edu      iew(this, params),
1563380Sgblack@eecs.umich.edu      commit(this, params),
1573380Sgblack@eecs.umich.edu
1583380Sgblack@eecs.umich.edu      /* It is mandatory that all SMT threads use the same renaming mode as
1593588Sgblack@eecs.umich.edu       * they are sharing registers and rename */
1603380Sgblack@eecs.umich.edu      vecMode(RenameMode<TheISA::ISA>::init(params->isa[0])),
1613380Sgblack@eecs.umich.edu      regFile(params->numPhysIntRegs,
1623380Sgblack@eecs.umich.edu              params->numPhysFloatRegs,
1633380Sgblack@eecs.umich.edu              params->numPhysVecRegs,
1643380Sgblack@eecs.umich.edu              params->numPhysVecPredRegs,
1653059Sgblack@eecs.umich.edu              params->numPhysCCRegs,
1663380Sgblack@eecs.umich.edu              vecMode),
1673380Sgblack@eecs.umich.edu
1683380Sgblack@eecs.umich.edu      freeList(name() + ".freelist", &regFile),
1693380Sgblack@eecs.umich.edu
1703588Sgblack@eecs.umich.edu      rob(this, params),
1713380Sgblack@eecs.umich.edu
1723380Sgblack@eecs.umich.edu      scoreboard(name() + ".scoreboard",
1733059Sgblack@eecs.umich.edu                 regFile.totalNumPhysRegs()),
1743059Sgblack@eecs.umich.edu
1753380Sgblack@eecs.umich.edu      isa(numThreads, NULL),
1763380Sgblack@eecs.umich.edu
1773380Sgblack@eecs.umich.edu      icachePort(&fetch, this),
1783380Sgblack@eecs.umich.edu      dcachePort(&iew.ldstQueue, this),
1793380Sgblack@eecs.umich.edu
1803588Sgblack@eecs.umich.edu      timeBuffer(params->backComSize, params->forwardComSize),
1813380Sgblack@eecs.umich.edu      fetchQueue(params->backComSize, params->forwardComSize),
1823380Sgblack@eecs.umich.edu      decodeQueue(params->backComSize, params->forwardComSize),
1833380Sgblack@eecs.umich.edu      renameQueue(params->backComSize, params->forwardComSize),
1843588Sgblack@eecs.umich.edu      iewQueue(params->backComSize, params->forwardComSize),
1853059Sgblack@eecs.umich.edu      activityRec(name(), NumStages,
1863065Sgblack@eecs.umich.edu                  params->backComSize + params->forwardComSize,
1872973Sgblack@eecs.umich.edu                  params->activity),
1882973Sgblack@eecs.umich.edu
1891968SN/A      globalSeqNum(1),
1903064Sgblack@eecs.umich.edu      system(params->system),
1911968SN/A      lastRunningCycle(curCycle())
1921968SN/A{
1931968SN/A    if (!params->switched_out) {
1941968SN/A        _status = Running;
1951967SN/A    } else {
1961967SN/A        _status = SwitchedOut;
1971967SN/A    }
1981967SN/A
1991967SN/A    if (params->checker) {
2001967SN/A        BaseCPU *temp_checker = params->checker;
2011967SN/A        checker = dynamic_cast<Checker<Impl> *>(temp_checker);
2021967SN/A        checker->setIcachePort(&icachePort);
2031967SN/A        checker->setSystem(params->system);
2041967SN/A    } else {
2051904SN/A        checker = NULL;
2061904SN/A    }
2071904SN/A
2081904SN/A    if (!FullSystem) {
209452SN/A        thread.resize(numThreads);
2103064Sgblack@eecs.umich.edu        tids.resize(numThreads);
2112SN/A    }
2121904SN/A
2131904SN/A    // The stages also need their CPU pointer setup.  However this
2142SN/A    // must be done at the upper level CPU because they have pointers
2151904SN/A    // to the upper level CPU, and not this FullO3CPU.
2163064Sgblack@eecs.umich.edu
2172SN/A    // Set up Pointers to the activeThreads list for each stage
2182SN/A    fetch.setActiveThreads(&activeThreads);
2191904SN/A    decode.setActiveThreads(&activeThreads);
2201904SN/A    rename.setActiveThreads(&activeThreads);
2211904SN/A    iew.setActiveThreads(&activeThreads);
2222299SN/A    commit.setActiveThreads(&activeThreads);
2232299SN/A
2241904SN/A    // Give each of the stages the time buffer they will use.
2251904SN/A    fetch.setTimeBuffer(&timeBuffer);
2261904SN/A    decode.setTimeBuffer(&timeBuffer);
2271904SN/A    rename.setTimeBuffer(&timeBuffer);
2281904SN/A    iew.setTimeBuffer(&timeBuffer);
2291904SN/A    commit.setTimeBuffer(&timeBuffer);
2301904SN/A
231452SN/A    // Also setup each of the stages' queues.
2321904SN/A    fetch.setFetchQueue(&fetchQueue);
2331904SN/A    decode.setFetchQueue(&fetchQueue);
2341904SN/A    commit.setFetchQueue(&fetchQueue);
2352SN/A    decode.setDecodeQueue(&decodeQueue);
2362SN/A    rename.setDecodeQueue(&decodeQueue);
2371904SN/A    rename.setRenameQueue(&renameQueue);
2381904SN/A    iew.setRenameQueue(&renameQueue);
2391904SN/A    iew.setIEWQueue(&iewQueue);
2401904SN/A    commit.setIEWQueue(&iewQueue);
2411904SN/A    commit.setRenameQueue(&renameQueue);
2421904SN/A
2432SN/A    commit.setIEWStage(&iew);
2441904SN/A    rename.setIEWStage(&iew);
2452SN/A    rename.setCommitStage(&commit);
2462SN/A
2471904SN/A    ThreadID active_threads;
2482SN/A    if (FullSystem) {
2491904SN/A        active_threads = 1;
2501904SN/A    } else {
2511904SN/A        active_threads = params->workload.size();
2521904SN/A
2531904SN/A        if (active_threads > Impl::MaxThreads) {
2541904SN/A            panic("Workload Size too large. Increase the 'MaxThreads' "
2551904SN/A                  "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
2561904SN/A                  "or edit your workload size.");
2571904SN/A        }
2581904SN/A    }
2591904SN/A
2601904SN/A    //Make Sure That this a Valid Architeture
2611904SN/A    assert(params->numPhysIntRegs   >= numThreads * TheISA::NumIntRegs);
2621904SN/A    assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs);
2631904SN/A    assert(params->numPhysVecRegs >= numThreads * TheISA::NumVecRegs);
2641904SN/A    assert(params->numPhysVecPredRegs >= numThreads * TheISA::NumVecPredRegs);
2651904SN/A    assert(params->numPhysCCRegs >= numThreads * TheISA::NumCCRegs);
2661904SN/A
2671904SN/A    rename.setScoreboard(&scoreboard);
2681904SN/A    iew.setScoreboard(&scoreboard);
2692525SN/A
2701904SN/A    // Setup the rename map for whichever stages need it.
2712525SN/A    for (ThreadID tid = 0; tid < numThreads; tid++) {
2722525SN/A        isa[tid] = params->isa[tid];
2732525SN/A        assert(RenameMode<TheISA::ISA>::equalsInit(isa[tid], isa[0]));
2741904SN/A
2751904SN/A        // Only Alpha has an FP zero register, so for other ISAs we
2761904SN/A        // use an invalid FP register index to avoid special treatment
2771904SN/A        // of any valid FP reg.
2781904SN/A        RegIndex invalidFPReg = TheISA::NumFloatRegs + 1;
2791904SN/A        RegIndex fpZeroReg =
2801904SN/A            (THE_ISA == ALPHA_ISA) ? TheISA::ZeroReg : invalidFPReg;
2811904SN/A
2821967SN/A        commitRenameMap[tid].init(&regFile, TheISA::ZeroReg, fpZeroReg,
2831967SN/A                                  &freeList,
2841967SN/A                                  vecMode);
2851967SN/A
2861967SN/A        renameMap[tid].init(&regFile, TheISA::ZeroReg, fpZeroReg,
2872SN/A                            &freeList, vecMode);
2883817Ssaidi@eecs.umich.edu    }
2893506Ssaidi@eecs.umich.edu
2903506Ssaidi@eecs.umich.edu    // Initialize rename map to assign physical registers to the
2913506Ssaidi@eecs.umich.edu    // architectural registers for active threads only.
2923506Ssaidi@eecs.umich.edu    for (ThreadID tid = 0; tid < active_threads; tid++) {
2933506Ssaidi@eecs.umich.edu        for (RegIndex ridx = 0; ridx < TheISA::NumIntRegs; ++ridx) {
2943814Ssaidi@eecs.umich.edu            // Note that we can't use the rename() method because we don't
2953506Ssaidi@eecs.umich.edu            // want special treatment for the zero register at this point
2963931Ssaidi@eecs.umich.edu            PhysRegIdPtr phys_reg = freeList.getIntReg();
2973931Ssaidi@eecs.umich.edu            renameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg);
2983748Sgblack@eecs.umich.edu            commitRenameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg);
2993748Sgblack@eecs.umich.edu        }
3003748Sgblack@eecs.umich.edu
3013748Sgblack@eecs.umich.edu        for (RegIndex ridx = 0; ridx < TheISA::NumFloatRegs; ++ridx) {
3023748Sgblack@eecs.umich.edu            PhysRegIdPtr phys_reg = freeList.getFloatReg();
3033748Sgblack@eecs.umich.edu            renameMap[tid].setEntry(RegId(FloatRegClass, ridx), phys_reg);
3043748Sgblack@eecs.umich.edu            commitRenameMap[tid].setEntry(
3053748Sgblack@eecs.umich.edu                    RegId(FloatRegClass, ridx), phys_reg);
3063748Sgblack@eecs.umich.edu        }
3073748Sgblack@eecs.umich.edu
3083748Sgblack@eecs.umich.edu        /* Here we need two 'interfaces' the 'whole register' and the
3093748Sgblack@eecs.umich.edu         * 'register element'. At any point only one of them will be
3103748Sgblack@eecs.umich.edu         * active. */
3113748Sgblack@eecs.umich.edu        if (vecMode == Enums::Full) {
3123748Sgblack@eecs.umich.edu            /* Initialize the full-vector interface */
3133748Sgblack@eecs.umich.edu            for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) {
3143748Sgblack@eecs.umich.edu                RegId rid = RegId(VecRegClass, ridx);
3153748Sgblack@eecs.umich.edu                PhysRegIdPtr phys_reg = freeList.getVecReg();
3163748Sgblack@eecs.umich.edu                renameMap[tid].setEntry(rid, phys_reg);
3173748Sgblack@eecs.umich.edu                commitRenameMap[tid].setEntry(rid, phys_reg);
3183880Ssaidi@eecs.umich.edu            }
3193603Ssaidi@eecs.umich.edu        } else {
3203603Ssaidi@eecs.umich.edu            /* Initialize the vector-element interface */
3213903Ssaidi@eecs.umich.edu            for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) {
3223903Ssaidi@eecs.umich.edu                for (ElemIndex ldx = 0; ldx < TheISA::NumVecElemPerVecReg;
3233903Ssaidi@eecs.umich.edu                        ++ldx) {
3243903Ssaidi@eecs.umich.edu                    RegId lrid = RegId(VecElemClass, ridx, ldx);
3253903Ssaidi@eecs.umich.edu                    PhysRegIdPtr phys_elem = freeList.getVecElem();
3263903Ssaidi@eecs.umich.edu                    renameMap[tid].setEntry(lrid, phys_elem);
3273903Ssaidi@eecs.umich.edu                    commitRenameMap[tid].setEntry(lrid, phys_elem);
3283903Ssaidi@eecs.umich.edu                }
3293903Ssaidi@eecs.umich.edu            }
3303903Ssaidi@eecs.umich.edu        }
3313903Ssaidi@eecs.umich.edu
3323903Ssaidi@eecs.umich.edu        for (RegIndex ridx = 0; ridx < TheISA::NumVecPredRegs; ++ridx) {
3333903Ssaidi@eecs.umich.edu            PhysRegIdPtr phys_reg = freeList.getVecPredReg();
3343903Ssaidi@eecs.umich.edu            renameMap[tid].setEntry(RegId(VecPredRegClass, ridx), phys_reg);
3353903Ssaidi@eecs.umich.edu            commitRenameMap[tid].setEntry(
3363903Ssaidi@eecs.umich.edu                    RegId(VecPredRegClass, ridx), phys_reg);
3373903Ssaidi@eecs.umich.edu        }
3383903Ssaidi@eecs.umich.edu
3393506Ssaidi@eecs.umich.edu        for (RegIndex ridx = 0; ridx < TheISA::NumCCRegs; ++ridx) {
3403584Ssaidi@eecs.umich.edu            PhysRegIdPtr phys_reg = freeList.getCCReg();
3413584Ssaidi@eecs.umich.edu            renameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg);
3423584Ssaidi@eecs.umich.edu            commitRenameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg);
3433748Sgblack@eecs.umich.edu        }
3443928Ssaidi@eecs.umich.edu    }
3453928Ssaidi@eecs.umich.edu
3463928Ssaidi@eecs.umich.edu    rename.setRenameMap(renameMap);
3473748Sgblack@eecs.umich.edu    commit.setRenameMap(commitRenameMap);
3483603Ssaidi@eecs.umich.edu    rename.setFreeList(&freeList);
3493584Ssaidi@eecs.umich.edu
3503814Ssaidi@eecs.umich.edu    // Setup the ROB for whichever stages need it.
3513814Ssaidi@eecs.umich.edu    commit.setROB(&rob);
3523814Ssaidi@eecs.umich.edu
3533814Ssaidi@eecs.umich.edu    lastActivatedCycle = 0;
3543814Ssaidi@eecs.umich.edu
3553743Sgblack@eecs.umich.edu    DPRINTF(O3CPU, "Creating O3CPU object.\n");
3563743Sgblack@eecs.umich.edu
3573584Ssaidi@eecs.umich.edu    // Setup any thread state.
3583743Sgblack@eecs.umich.edu    this->thread.resize(this->numThreads);
3593754Sgblack@eecs.umich.edu
3603603Ssaidi@eecs.umich.edu    for (ThreadID tid = 0; tid < this->numThreads; ++tid) {
3613931Ssaidi@eecs.umich.edu        if (FullSystem) {
3623603Ssaidi@eecs.umich.edu            // SMT is not supported in FS mode yet.
3633584Ssaidi@eecs.umich.edu            assert(this->numThreads == 1);
3643931Ssaidi@eecs.umich.edu            this->thread[tid] = new Thread(this, 0, NULL);
3653931Ssaidi@eecs.umich.edu        } else {
3663931Ssaidi@eecs.umich.edu            if (tid < params->workload.size()) {
3673931Ssaidi@eecs.umich.edu                DPRINTF(O3CPU, "Workload[%i] process is %#x",
3683931Ssaidi@eecs.umich.edu                        tid, this->thread[tid]);
3693931Ssaidi@eecs.umich.edu                this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
3703748Sgblack@eecs.umich.edu                        (typename Impl::O3CPU *)(this),
3713748Sgblack@eecs.umich.edu                        tid, params->workload[tid]);
3723748Sgblack@eecs.umich.edu
3733748Sgblack@eecs.umich.edu                //usedTids[tid] = true;
3743748Sgblack@eecs.umich.edu                //threadMap[tid] = tid;
3753815Ssaidi@eecs.umich.edu            } else {
3763748Sgblack@eecs.umich.edu                //Allocate Empty thread so M5 can use later
3773748Sgblack@eecs.umich.edu                //when scheduling threads to CPU
3783815Ssaidi@eecs.umich.edu                Process* dummy_proc = NULL;
3793748Sgblack@eecs.umich.edu
3803748Sgblack@eecs.umich.edu                this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
3813815Ssaidi@eecs.umich.edu                        (typename Impl::O3CPU *)(this),
3823748Sgblack@eecs.umich.edu                        tid, dummy_proc);
3833748Sgblack@eecs.umich.edu                //usedTids[tid] = false;
3843815Ssaidi@eecs.umich.edu            }
3853748Sgblack@eecs.umich.edu        }
3863748Sgblack@eecs.umich.edu
3873815Ssaidi@eecs.umich.edu        ThreadContext *tc;
3883748Sgblack@eecs.umich.edu
3893748Sgblack@eecs.umich.edu        // Setup the TC that will serve as the interface to the threads/CPU.
3903748Sgblack@eecs.umich.edu        O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
3913584Ssaidi@eecs.umich.edu
3923748Sgblack@eecs.umich.edu        tc = o3_tc;
3933748Sgblack@eecs.umich.edu
3943748Sgblack@eecs.umich.edu        // If we're using a checker, then the TC should be the
3953748Sgblack@eecs.umich.edu        // CheckerThreadContext.
3963748Sgblack@eecs.umich.edu        if (params->checker) {
3973748Sgblack@eecs.umich.edu            tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
3983748Sgblack@eecs.umich.edu                o3_tc, this->checker);
3993748Sgblack@eecs.umich.edu        }
4003748Sgblack@eecs.umich.edu
4013748Sgblack@eecs.umich.edu        o3_tc->cpu = (typename Impl::O3CPU *)(this);
4023748Sgblack@eecs.umich.edu        assert(o3_tc->cpu);
4033748Sgblack@eecs.umich.edu        o3_tc->thread = this->thread[tid];
4043748Sgblack@eecs.umich.edu
4053748Sgblack@eecs.umich.edu        // Setup quiesce event.
4063748Sgblack@eecs.umich.edu        this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc);
4073748Sgblack@eecs.umich.edu
4083748Sgblack@eecs.umich.edu        // Give the thread the TC.
4093748Sgblack@eecs.umich.edu        this->thread[tid]->tc = tc;
4103748Sgblack@eecs.umich.edu
4113748Sgblack@eecs.umich.edu        // Add the TC to the CPU's list of TC's.
4123748Sgblack@eecs.umich.edu        this->threadContexts.push_back(tc);
4133748Sgblack@eecs.umich.edu    }
4143748Sgblack@eecs.umich.edu
4153748Sgblack@eecs.umich.edu    // FullO3CPU always requires an interrupt controller.
4163748Sgblack@eecs.umich.edu    if (!params->switched_out && interrupts.empty()) {
4173748Sgblack@eecs.umich.edu        fatal("FullO3CPU %s has no interrupt controller.\n"
4183748Sgblack@eecs.umich.edu              "Ensure createInterruptController() is called.\n", name());
4193748Sgblack@eecs.umich.edu    }
4203748Sgblack@eecs.umich.edu
4213748Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < this->numThreads; tid++)
4223748Sgblack@eecs.umich.edu        this->thread[tid]->setFuncExeInst(0);
4233748Sgblack@eecs.umich.edu}
4243748Sgblack@eecs.umich.edu
4253748Sgblack@eecs.umich.edutemplate <class Impl>
4263748Sgblack@eecs.umich.eduFullO3CPU<Impl>::~FullO3CPU()
4273748Sgblack@eecs.umich.edu{
4283880Ssaidi@eecs.umich.edu}
4293880Ssaidi@eecs.umich.edu
4303880Ssaidi@eecs.umich.edutemplate <class Impl>
4313880Ssaidi@eecs.umich.eduvoid
4323880Ssaidi@eecs.umich.eduFullO3CPU<Impl>::regProbePoints()
4333880Ssaidi@eecs.umich.edu{
4343880Ssaidi@eecs.umich.edu    BaseCPU::regProbePoints();
4353931Ssaidi@eecs.umich.edu
4363931Ssaidi@eecs.umich.edu    ppInstAccessComplete = new ProbePointArg<PacketPtr>(getProbeManager(), "InstAccessComplete");
4373931Ssaidi@eecs.umich.edu    ppDataAccessComplete = new ProbePointArg<std::pair<DynInstPtr, PacketPtr> >(getProbeManager(), "DataAccessComplete");
4383931Ssaidi@eecs.umich.edu
4393931Ssaidi@eecs.umich.edu    fetch.regProbePoints();
4403931Ssaidi@eecs.umich.edu    rename.regProbePoints();
4413863Ssaidi@eecs.umich.edu    iew.regProbePoints();
4423880Ssaidi@eecs.umich.edu    commit.regProbePoints();
4433880Ssaidi@eecs.umich.edu}
4443880Ssaidi@eecs.umich.edu
4453863Ssaidi@eecs.umich.edutemplate <class Impl>
4463584Ssaidi@eecs.umich.eduvoid
4473584Ssaidi@eecs.umich.eduFullO3CPU<Impl>::regStats()
4483584Ssaidi@eecs.umich.edu{
4493814Ssaidi@eecs.umich.edu    BaseO3CPU::regStats();
4503814Ssaidi@eecs.umich.edu
4513584Ssaidi@eecs.umich.edu    // Register any of the O3CPU's stats here.
4523584Ssaidi@eecs.umich.edu    timesIdled
4533931Ssaidi@eecs.umich.edu        .name(name() + ".timesIdled")
4543584Ssaidi@eecs.umich.edu        .desc("Number of times that the entire CPU went into an idle state and"
4553931Ssaidi@eecs.umich.edu              " unscheduled itself")
4563931Ssaidi@eecs.umich.edu        .prereq(timesIdled);
4573748Sgblack@eecs.umich.edu
4583748Sgblack@eecs.umich.edu    idleCycles
4593748Sgblack@eecs.umich.edu        .name(name() + ".idleCycles")
4603748Sgblack@eecs.umich.edu        .desc("Total number of cycles that the CPU has spent unscheduled due "
4613748Sgblack@eecs.umich.edu              "to idling")
4623748Sgblack@eecs.umich.edu        .prereq(idleCycles);
4633748Sgblack@eecs.umich.edu
4643748Sgblack@eecs.umich.edu    quiesceCycles
4653748Sgblack@eecs.umich.edu        .name(name() + ".quiesceCycles")
4663748Sgblack@eecs.umich.edu        .desc("Total number of cycles that CPU has spent quiesced or waiting "
4673748Sgblack@eecs.umich.edu              "for an interrupt")
4683748Sgblack@eecs.umich.edu        .prereq(quiesceCycles);
4693748Sgblack@eecs.umich.edu
4703748Sgblack@eecs.umich.edu    // Number of Instructions simulated
4713748Sgblack@eecs.umich.edu    // --------------------------------
4723748Sgblack@eecs.umich.edu    // Should probably be in Base CPU but need templated
4733748Sgblack@eecs.umich.edu    // MaxThreads so put in here instead
4743748Sgblack@eecs.umich.edu    committedInsts
4753748Sgblack@eecs.umich.edu        .init(numThreads)
4763748Sgblack@eecs.umich.edu        .name(name() + ".committedInsts")
4773748Sgblack@eecs.umich.edu        .desc("Number of Instructions Simulated")
4783748Sgblack@eecs.umich.edu        .flags(Stats::total);
4793748Sgblack@eecs.umich.edu
4803748Sgblack@eecs.umich.edu    committedOps
4813748Sgblack@eecs.umich.edu        .init(numThreads)
4823748Sgblack@eecs.umich.edu        .name(name() + ".committedOps")
4833748Sgblack@eecs.umich.edu        .desc("Number of Ops (including micro ops) Simulated")
4843748Sgblack@eecs.umich.edu        .flags(Stats::total);
4853748Sgblack@eecs.umich.edu
4863748Sgblack@eecs.umich.edu    cpi
4873748Sgblack@eecs.umich.edu        .name(name() + ".cpi")
4883748Sgblack@eecs.umich.edu        .desc("CPI: Cycles Per Instruction")
4893748Sgblack@eecs.umich.edu        .precision(6);
4903748Sgblack@eecs.umich.edu    cpi = numCycles / committedInsts;
4913748Sgblack@eecs.umich.edu
4923748Sgblack@eecs.umich.edu    totalCpi
4933748Sgblack@eecs.umich.edu        .name(name() + ".cpi_total")
4943748Sgblack@eecs.umich.edu        .desc("CPI: Total CPI of All Threads")
4953880Ssaidi@eecs.umich.edu        .precision(6);
4963880Ssaidi@eecs.umich.edu    totalCpi = numCycles / sum(committedInsts);
4973603Ssaidi@eecs.umich.edu
4983584Ssaidi@eecs.umich.edu    ipc
4993603Ssaidi@eecs.umich.edu        .name(name() + ".ipc")
5003584Ssaidi@eecs.umich.edu        .desc("IPC: Instructions Per Cycle")
5013603Ssaidi@eecs.umich.edu        .precision(6);
5023584Ssaidi@eecs.umich.edu    ipc =  committedInsts / numCycles;
5033584Ssaidi@eecs.umich.edu
5043603Ssaidi@eecs.umich.edu    totalIpc
5053584Ssaidi@eecs.umich.edu        .name(name() + ".ipc_total")
5063814Ssaidi@eecs.umich.edu        .desc("IPC: Total IPC of All Threads")
5073814Ssaidi@eecs.umich.edu        .precision(6);
5083814Ssaidi@eecs.umich.edu    totalIpc =  sum(committedInsts) / numCycles;
5093814Ssaidi@eecs.umich.edu
5103814Ssaidi@eecs.umich.edu    this->fetch.regStats();
5113814Ssaidi@eecs.umich.edu    this->decode.regStats();
5123814Ssaidi@eecs.umich.edu    this->rename.regStats();
5133584Ssaidi@eecs.umich.edu    this->iew.regStats();
5143584Ssaidi@eecs.umich.edu    this->commit.regStats();
5153584Ssaidi@eecs.umich.edu    this->rob.regStats();
5163603Ssaidi@eecs.umich.edu
5173584Ssaidi@eecs.umich.edu    intRegfileReads
5183584Ssaidi@eecs.umich.edu        .name(name() + ".int_regfile_reads")
5193748Sgblack@eecs.umich.edu        .desc("number of integer regfile reads")
5203748Sgblack@eecs.umich.edu        .prereq(intRegfileReads);
5213748Sgblack@eecs.umich.edu
5223584Ssaidi@eecs.umich.edu    intRegfileWrites
5233584Ssaidi@eecs.umich.edu        .name(name() + ".int_regfile_writes")
5243584Ssaidi@eecs.umich.edu        .desc("number of integer regfile writes")
5253584Ssaidi@eecs.umich.edu        .prereq(intRegfileWrites);
5263603Ssaidi@eecs.umich.edu
5273748Sgblack@eecs.umich.edu    fpRegfileReads
5283584Ssaidi@eecs.umich.edu        .name(name() + ".fp_regfile_reads")
5293748Sgblack@eecs.umich.edu        .desc("number of floating regfile reads")
5303748Sgblack@eecs.umich.edu        .prereq(fpRegfileReads);
5313748Sgblack@eecs.umich.edu
5323748Sgblack@eecs.umich.edu    fpRegfileWrites
5333748Sgblack@eecs.umich.edu        .name(name() + ".fp_regfile_writes")
5343748Sgblack@eecs.umich.edu        .desc("number of floating regfile writes")
5353748Sgblack@eecs.umich.edu        .prereq(fpRegfileWrites);
5363748Sgblack@eecs.umich.edu
5373748Sgblack@eecs.umich.edu    vecRegfileReads
5383748Sgblack@eecs.umich.edu        .name(name() + ".vec_regfile_reads")
5393748Sgblack@eecs.umich.edu        .desc("number of vector regfile reads")
5403748Sgblack@eecs.umich.edu        .prereq(vecRegfileReads);
5413748Sgblack@eecs.umich.edu
5423748Sgblack@eecs.umich.edu    vecRegfileWrites
5433748Sgblack@eecs.umich.edu        .name(name() + ".vec_regfile_writes")
5443748Sgblack@eecs.umich.edu        .desc("number of vector regfile writes")
5453748Sgblack@eecs.umich.edu        .prereq(vecRegfileWrites);
5463748Sgblack@eecs.umich.edu
5473748Sgblack@eecs.umich.edu    vecPredRegfileReads
5483748Sgblack@eecs.umich.edu        .name(name() + ".pred_regfile_reads")
5493748Sgblack@eecs.umich.edu        .desc("number of predicate regfile reads")
5503748Sgblack@eecs.umich.edu        .prereq(vecPredRegfileReads);
5513748Sgblack@eecs.umich.edu
5523748Sgblack@eecs.umich.edu    vecPredRegfileWrites
5533748Sgblack@eecs.umich.edu        .name(name() + ".pred_regfile_writes")
5543748Sgblack@eecs.umich.edu        .desc("number of predicate regfile writes")
5553748Sgblack@eecs.umich.edu        .prereq(vecPredRegfileWrites);
5563748Sgblack@eecs.umich.edu
5573748Sgblack@eecs.umich.edu    ccRegfileReads
5583748Sgblack@eecs.umich.edu        .name(name() + ".cc_regfile_reads")
5593748Sgblack@eecs.umich.edu        .desc("number of cc regfile reads")
5603748Sgblack@eecs.umich.edu        .prereq(ccRegfileReads);
5613748Sgblack@eecs.umich.edu
5623748Sgblack@eecs.umich.edu    ccRegfileWrites
5633748Sgblack@eecs.umich.edu        .name(name() + ".cc_regfile_writes")
5643748Sgblack@eecs.umich.edu        .desc("number of cc regfile writes")
5653748Sgblack@eecs.umich.edu        .prereq(ccRegfileWrites);
5663748Sgblack@eecs.umich.edu
5673748Sgblack@eecs.umich.edu    miscRegfileReads
5683748Sgblack@eecs.umich.edu        .name(name() + ".misc_regfile_reads")
5693748Sgblack@eecs.umich.edu        .desc("number of misc regfile reads")
5703748Sgblack@eecs.umich.edu        .prereq(miscRegfileReads);
5713748Sgblack@eecs.umich.edu
5723748Sgblack@eecs.umich.edu    miscRegfileWrites
5733748Sgblack@eecs.umich.edu        .name(name() + ".misc_regfile_writes")
5743748Sgblack@eecs.umich.edu        .desc("number of misc regfile writes")
5753748Sgblack@eecs.umich.edu        .prereq(miscRegfileWrites);
5763748Sgblack@eecs.umich.edu}
5773748Sgblack@eecs.umich.edu
5783748Sgblack@eecs.umich.edutemplate <class Impl>
5793748Sgblack@eecs.umich.eduvoid
5803815Ssaidi@eecs.umich.eduFullO3CPU<Impl>::tick()
5813748Sgblack@eecs.umich.edu{
5823748Sgblack@eecs.umich.edu    DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
5833815Ssaidi@eecs.umich.edu    assert(!switchedOut());
5843748Sgblack@eecs.umich.edu    assert(drainState() != DrainState::Drained);
5853748Sgblack@eecs.umich.edu
5863815Ssaidi@eecs.umich.edu    ++numCycles;
5873748Sgblack@eecs.umich.edu    updateCycleCounters(BaseCPU::CPU_STATE_ON);
5883748Sgblack@eecs.umich.edu
5893815Ssaidi@eecs.umich.edu//    activity = false;
5903748Sgblack@eecs.umich.edu
5913748Sgblack@eecs.umich.edu    //Tick each of the stages
5923815Ssaidi@eecs.umich.edu    fetch.tick();
5933748Sgblack@eecs.umich.edu
5943748Sgblack@eecs.umich.edu    decode.tick();
5953584Ssaidi@eecs.umich.edu
5963584Ssaidi@eecs.umich.edu    rename.tick();
5973748Sgblack@eecs.umich.edu
5983584Ssaidi@eecs.umich.edu    iew.tick();
5993931Ssaidi@eecs.umich.edu
6003931Ssaidi@eecs.umich.edu    commit.tick();
6013748Sgblack@eecs.umich.edu
6023748Sgblack@eecs.umich.edu    // Now advance the time buffers
6033748Sgblack@eecs.umich.edu    timeBuffer.advance();
6043748Sgblack@eecs.umich.edu
6053748Sgblack@eecs.umich.edu    fetchQueue.advance();
6063931Ssaidi@eecs.umich.edu    decodeQueue.advance();
6073931Ssaidi@eecs.umich.edu    renameQueue.advance();
6083931Ssaidi@eecs.umich.edu    iewQueue.advance();
6093931Ssaidi@eecs.umich.edu
6103931Ssaidi@eecs.umich.edu    activityRec.advance();
6113931Ssaidi@eecs.umich.edu
6123931Ssaidi@eecs.umich.edu    if (removeInstsThisCycle) {
6133931Ssaidi@eecs.umich.edu        cleanUpRemovedInsts();
6143931Ssaidi@eecs.umich.edu    }
6153584Ssaidi@eecs.umich.edu
6163584Ssaidi@eecs.umich.edu    if (!tickEvent.scheduled()) {
6173903Ssaidi@eecs.umich.edu        if (_status == SwitchedOut) {
6183903Ssaidi@eecs.umich.edu            DPRINTF(O3CPU, "Switched out!\n");
6193903Ssaidi@eecs.umich.edu            // increment stat
6203903Ssaidi@eecs.umich.edu            lastRunningCycle = curCycle();
6213903Ssaidi@eecs.umich.edu        } else if (!activityRec.active() || _status == Idle) {
6223903Ssaidi@eecs.umich.edu            DPRINTF(O3CPU, "Idle!\n");
6233903Ssaidi@eecs.umich.edu            lastRunningCycle = curCycle();
6243903Ssaidi@eecs.umich.edu            timesIdled++;
6253903Ssaidi@eecs.umich.edu        } else {
6263903Ssaidi@eecs.umich.edu            schedule(tickEvent, clockEdge(Cycles(1)));
6273880Ssaidi@eecs.umich.edu            DPRINTF(O3CPU, "Scheduling next tick!\n");
6283903Ssaidi@eecs.umich.edu        }
6293903Ssaidi@eecs.umich.edu    }
6303903Ssaidi@eecs.umich.edu
6313903Ssaidi@eecs.umich.edu    if (!FullSystem)
6323903Ssaidi@eecs.umich.edu        updateThreadPriority();
6333903Ssaidi@eecs.umich.edu
6343903Ssaidi@eecs.umich.edu    tryDrain();
6353903Ssaidi@eecs.umich.edu}
6363903Ssaidi@eecs.umich.edu
6373903Ssaidi@eecs.umich.edutemplate <class Impl>
6383880Ssaidi@eecs.umich.eduvoid
6393826Ssaidi@eecs.umich.eduFullO3CPU<Impl>::init()
6403825Ssaidi@eecs.umich.edu{
6413832Ssaidi@eecs.umich.edu    BaseCPU::init();
6423825Ssaidi@eecs.umich.edu
6433892Ssaidi@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid) {
6443892Ssaidi@eecs.umich.edu        // Set noSquashFromTC so that the CPU doesn't squash when initially
6453584Ssaidi@eecs.umich.edu        // setting up registers.
6463584Ssaidi@eecs.umich.edu        thread[tid]->noSquashFromTC = true;
6473584Ssaidi@eecs.umich.edu        // Initialise the ThreadContext's memory proxies
6483506Ssaidi@eecs.umich.edu        thread[tid]->initMemProxies(thread[tid]->getTC());
6493584Ssaidi@eecs.umich.edu    }
6503584Ssaidi@eecs.umich.edu
6513506Ssaidi@eecs.umich.edu    if (FullSystem && !params()->switched_out) {
6523584Ssaidi@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; tid++) {
6532SN/A            ThreadContext *src_tc = threadContexts[tid];
6542SN/A            TheISA::initCPU(src_tc, src_tc->contextId());
6552SN/A        }
6562SN/A    }
6571967SN/A
6582SN/A    // Clear noSquashFromTC.
6592SN/A    for (int tid = 0; tid < numThreads; ++tid)
6602SN/A        thread[tid]->noSquashFromTC = false;
6612SN/A
6622SN/A    commit.setThreads(thread);
6632SN/A}
6642SN/A
6652SN/Atemplate <class Impl>
6662SN/Avoid
6672SN/AFullO3CPU<Impl>::startup()
6682SN/A{
6692SN/A    BaseCPU::startup();
6702SN/A    for (int tid = 0; tid < numThreads; ++tid)
6712SN/A        isa[tid]->startup(threadContexts[tid]);
6722SN/A
6732SN/A    fetch.startupStage();
6742SN/A    decode.startupStage();
6752SN/A    iew.startupStage();
6762SN/A    rename.startupStage();
6772SN/A    commit.startupStage();
6781413SN/A}
6792SN/A
6802SN/Atemplate <class Impl>
6812SN/Avoid
6822SN/AFullO3CPU<Impl>::activateThread(ThreadID tid)
6832SN/A{
6842SN/A    list<ThreadID>::iterator isActive =
6852SN/A        std::find(activeThreads.begin(), activeThreads.end(), tid);
6862SN/A
6872SN/A    DPRINTF(O3CPU, "[tid:%i] Calling activate thread.\n", tid);
6882SN/A    assert(!switchedOut());
6892SN/A
6902SN/A    if (isActive == activeThreads.end()) {
6912SN/A        DPRINTF(O3CPU, "[tid:%i] Adding to active threads list\n",
6922SN/A                tid);
6932SN/A
6942SN/A        activeThreads.push_back(tid);
6952SN/A    }
6962973Sgblack@eecs.umich.edu}
6972973Sgblack@eecs.umich.edu
6982299SN/Atemplate <class Impl>
6992299SN/Avoid
7001904SN/AFullO3CPU<Impl>::deactivateThread(ThreadID tid)
7011904SN/A{
7023506Ssaidi@eecs.umich.edu    //Remove From Active List, if Active
7033506Ssaidi@eecs.umich.edu    list<ThreadID>::iterator thread_it =
7043506Ssaidi@eecs.umich.edu        std::find(activeThreads.begin(), activeThreads.end(), tid);
7051967SN/A
7061967SN/A    DPRINTF(O3CPU, "[tid:%i] Calling deactivate thread.\n", tid);
7071967SN/A    assert(!switchedOut());
7081904SN/A
7092SN/A    if (thread_it != activeThreads.end()) {
7102SN/A        DPRINTF(O3CPU,"[tid:%i] Removing from active threads list\n",
7112SN/A                tid);
7122SN/A        activeThreads.erase(thread_it);
7132SN/A    }
7142SN/A
7152SN/A    fetch.deactivateThread(tid);
7162SN/A    commit.deactivateThread(tid);
7172SN/A}
7182SN/A
7192SN/Atemplate <class Impl>
7202SN/ACounter
7212SN/AFullO3CPU<Impl>::totalInsts() const
7222SN/A{
7232SN/A    Counter total(0);
7242SN/A
7252SN/A    ThreadID size = thread.size();
7262SN/A    for (ThreadID i = 0; i < size; i++)
7272973Sgblack@eecs.umich.edu        total += thread[i]->numInst;
7282299SN/A
7291904SN/A    return total;
7303506Ssaidi@eecs.umich.edu}
7311967SN/A
7323506Ssaidi@eecs.umich.edutemplate <class Impl>
7333506Ssaidi@eecs.umich.eduCounter
7343506Ssaidi@eecs.umich.eduFullO3CPU<Impl>::totalOps() const
7353506Ssaidi@eecs.umich.edu{
7363603Ssaidi@eecs.umich.edu    Counter total(0);
7373506Ssaidi@eecs.umich.edu
7383506Ssaidi@eecs.umich.edu    ThreadID size = thread.size();
7393506Ssaidi@eecs.umich.edu    for (ThreadID i = 0; i < size; i++)
7403506Ssaidi@eecs.umich.edu        total += thread[i]->numOp;
7413506Ssaidi@eecs.umich.edu
7423506Ssaidi@eecs.umich.edu    return total;
7433506Ssaidi@eecs.umich.edu}
7443506Ssaidi@eecs.umich.edu
7453506Ssaidi@eecs.umich.edutemplate <class Impl>
7463506Ssaidi@eecs.umich.eduvoid
7473506Ssaidi@eecs.umich.eduFullO3CPU<Impl>::activateContext(ThreadID tid)
7483506Ssaidi@eecs.umich.edu{
7493506Ssaidi@eecs.umich.edu    assert(!switchedOut());
7503506Ssaidi@eecs.umich.edu
7513603Ssaidi@eecs.umich.edu    // Needs to set each stage to running as well.
7523603Ssaidi@eecs.umich.edu    activateThread(tid);
7533506Ssaidi@eecs.umich.edu
7542SN/A    // We don't want to wake the CPU if it is drained. In that case,
7552SN/A    // we just want to flag the thread as active and schedule the tick
7562SN/A    // event from drainResume() instead.
7572SN/A    if (drainState() == DrainState::Drained)
7582SN/A        return;
7592SN/A
7602SN/A    // If we are time 0 or if the last activation time is in the past,
7612SN/A    // schedule the next tick and wake up the fetch unit
762    if (lastActivatedCycle == 0 || lastActivatedCycle < curTick()) {
763        scheduleTickEvent(Cycles(0));
764
765        // Be sure to signal that there's some activity so the CPU doesn't
766        // deschedule itself.
767        activityRec.activity();
768        fetch.wakeFromQuiesce();
769
770        Cycles cycles(curCycle() - lastRunningCycle);
771        // @todo: This is an oddity that is only here to match the stats
772        if (cycles != 0)
773            --cycles;
774        quiesceCycles += cycles;
775
776        lastActivatedCycle = curTick();
777
778        _status = Running;
779
780        BaseCPU::activateContext(tid);
781    }
782}
783
784template <class Impl>
785void
786FullO3CPU<Impl>::suspendContext(ThreadID tid)
787{
788    DPRINTF(O3CPU,"[tid:%i] Suspending Thread Context.\n", tid);
789    assert(!switchedOut());
790
791    deactivateThread(tid);
792
793    // If this was the last thread then unschedule the tick event.
794    if (activeThreads.size() == 0) {
795        unscheduleTickEvent();
796        lastRunningCycle = curCycle();
797        _status = Idle;
798    }
799
800    DPRINTF(Quiesce, "Suspending Context\n");
801
802    BaseCPU::suspendContext(tid);
803}
804
805template <class Impl>
806void
807FullO3CPU<Impl>::haltContext(ThreadID tid)
808{
809    //For now, this is the same as deallocate
810    DPRINTF(O3CPU,"[tid:%i] Halt Context called. Deallocating\n", tid);
811    assert(!switchedOut());
812
813    deactivateThread(tid);
814    removeThread(tid);
815
816    updateCycleCounters(BaseCPU::CPU_STATE_SLEEP);
817}
818
819template <class Impl>
820void
821FullO3CPU<Impl>::insertThread(ThreadID tid)
822{
823    DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
824    // Will change now that the PC and thread state is internal to the CPU
825    // and not in the ThreadContext.
826    ThreadContext *src_tc;
827    if (FullSystem)
828        src_tc = system->threadContexts[tid];
829    else
830        src_tc = tcBase(tid);
831
832    //Bind Int Regs to Rename Map
833
834    for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs;
835         reg_id.index()++) {
836        PhysRegIdPtr phys_reg = freeList.getIntReg();
837        renameMap[tid].setEntry(reg_id, phys_reg);
838        scoreboard.setReg(phys_reg);
839    }
840
841    //Bind Float Regs to Rename Map
842    for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs;
843         reg_id.index()++) {
844        PhysRegIdPtr phys_reg = freeList.getFloatReg();
845        renameMap[tid].setEntry(reg_id, phys_reg);
846        scoreboard.setReg(phys_reg);
847    }
848
849    //Bind condition-code Regs to Rename Map
850    for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs;
851         reg_id.index()++) {
852        PhysRegIdPtr phys_reg = freeList.getCCReg();
853        renameMap[tid].setEntry(reg_id, phys_reg);
854        scoreboard.setReg(phys_reg);
855    }
856
857    //Copy Thread Data Into RegFile
858    //this->copyFromTC(tid);
859
860    //Set PC/NPC/NNPC
861    pcState(src_tc->pcState(), tid);
862
863    src_tc->setStatus(ThreadContext::Active);
864
865    activateContext(tid);
866
867    //Reset ROB/IQ/LSQ Entries
868    commit.rob->resetEntries();
869}
870
871template <class Impl>
872void
873FullO3CPU<Impl>::removeThread(ThreadID tid)
874{
875    DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);
876
877    // Copy Thread Data From RegFile
878    // If thread is suspended, it might be re-allocated
879    // this->copyToTC(tid);
880
881
882    // @todo: 2-27-2008: Fix how we free up rename mappings
883    // here to alleviate the case for double-freeing registers
884    // in SMT workloads.
885
886    // clear all thread-specific states in each stage of the pipeline
887    // since this thread is going to be completely removed from the CPU
888    commit.clearStates(tid);
889    fetch.clearStates(tid);
890    decode.clearStates(tid);
891    rename.clearStates(tid);
892    iew.clearStates(tid);
893
894    // at this step, all instructions in the pipeline should be already
895    // either committed successfully or squashed. All thread-specific
896    // queues in the pipeline must be empty.
897    assert(iew.instQueue.getCount(tid) == 0);
898    assert(iew.ldstQueue.getCount(tid) == 0);
899    assert(commit.rob->isEmpty(tid));
900
901    // Reset ROB/IQ/LSQ Entries
902
903    // Commented out for now.  This should be possible to do by
904    // telling all the pipeline stages to drain first, and then
905    // checking until the drain completes.  Once the pipeline is
906    // drained, call resetEntries(). - 10-09-06 ktlim
907/*
908    if (activeThreads.size() >= 1) {
909        commit.rob->resetEntries();
910        iew.resetEntries();
911    }
912*/
913}
914
915template <class Impl>
916void
917FullO3CPU<Impl>::switchRenameMode(ThreadID tid, UnifiedFreeList* freelist)
918{
919    auto pc = this->pcState(tid);
920
921    // new_mode is the new vector renaming mode
922    auto new_mode = RenameMode<TheISA::ISA>::mode(pc);
923
924    // We update vecMode only if there has been a change
925    if (new_mode != vecMode) {
926        vecMode = new_mode;
927
928        renameMap[tid].switchMode(vecMode);
929        commitRenameMap[tid].switchMode(vecMode);
930        renameMap[tid].switchFreeList(freelist);
931    }
932}
933
934template <class Impl>
935Fault
936FullO3CPU<Impl>::getInterrupts()
937{
938    // Check if there are any outstanding interrupts
939    return this->interrupts[0]->getInterrupt(this->threadContexts[0]);
940}
941
942template <class Impl>
943void
944FullO3CPU<Impl>::processInterrupts(const Fault &interrupt)
945{
946    // Check for interrupts here.  For now can copy the code that
947    // exists within isa_fullsys_traits.hh.  Also assume that thread 0
948    // is the one that handles the interrupts.
949    // @todo: Possibly consolidate the interrupt checking code.
950    // @todo: Allow other threads to handle interrupts.
951
952    assert(interrupt != NoFault);
953    this->interrupts[0]->updateIntrInfo(this->threadContexts[0]);
954
955    DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
956    this->trap(interrupt, 0, nullptr);
957}
958
959template <class Impl>
960void
961FullO3CPU<Impl>::trap(const Fault &fault, ThreadID tid,
962                      const StaticInstPtr &inst)
963{
964    // Pass the thread's TC into the invoke method.
965    fault->invoke(this->threadContexts[tid], inst);
966}
967
968template <class Impl>
969void
970FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid, Fault *fault)
971{
972    DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);
973
974    DPRINTF(Activity,"Activity: syscall() called.\n");
975
976    // Temporarily increase this by one to account for the syscall
977    // instruction.
978    ++(this->thread[tid]->funcExeInst);
979
980    // Execute the actual syscall.
981    this->thread[tid]->syscall(callnum, fault);
982
983    // Decrease funcExeInst by one as the normal commit will handle
984    // incrementing it.
985    --(this->thread[tid]->funcExeInst);
986}
987
988template <class Impl>
989void
990FullO3CPU<Impl>::serializeThread(CheckpointOut &cp, ThreadID tid) const
991{
992    thread[tid]->serialize(cp);
993}
994
995template <class Impl>
996void
997FullO3CPU<Impl>::unserializeThread(CheckpointIn &cp, ThreadID tid)
998{
999    thread[tid]->unserialize(cp);
1000}
1001
1002template <class Impl>
1003DrainState
1004FullO3CPU<Impl>::drain()
1005{
1006    // Deschedule any power gating event (if any)
1007    deschedulePowerGatingEvent();
1008
1009    // If the CPU isn't doing anything, then return immediately.
1010    if (switchedOut())
1011        return DrainState::Drained;
1012
1013    DPRINTF(Drain, "Draining...\n");
1014
1015    // We only need to signal a drain to the commit stage as this
1016    // initiates squashing controls the draining. Once the commit
1017    // stage commits an instruction where it is safe to stop, it'll
1018    // squash the rest of the instructions in the pipeline and force
1019    // the fetch stage to stall. The pipeline will be drained once all
1020    // in-flight instructions have retired.
1021    commit.drain();
1022
1023    // Wake the CPU and record activity so everything can drain out if
1024    // the CPU was not able to immediately drain.
1025    if (!isCpuDrained())  {
1026        // If a thread is suspended, wake it up so it can be drained
1027        for (auto t : threadContexts) {
1028            if (t->status() == ThreadContext::Suspended){
1029                DPRINTF(Drain, "Currently suspended so activate %i \n",
1030                        t->threadId());
1031                t->activate();
1032                // As the thread is now active, change the power state as well
1033                activateContext(t->threadId());
1034            }
1035        }
1036
1037        wakeCPU();
1038        activityRec.activity();
1039
1040        DPRINTF(Drain, "CPU not drained\n");
1041
1042        return DrainState::Draining;
1043    } else {
1044        DPRINTF(Drain, "CPU is already drained\n");
1045        if (tickEvent.scheduled())
1046            deschedule(tickEvent);
1047
1048        // Flush out any old data from the time buffers.  In
1049        // particular, there might be some data in flight from the
1050        // fetch stage that isn't visible in any of the CPU buffers we
1051        // test in isCpuDrained().
1052        for (int i = 0; i < timeBuffer.getSize(); ++i) {
1053            timeBuffer.advance();
1054            fetchQueue.advance();
1055            decodeQueue.advance();
1056            renameQueue.advance();
1057            iewQueue.advance();
1058        }
1059
1060        drainSanityCheck();
1061        return DrainState::Drained;
1062    }
1063}
1064
1065template <class Impl>
1066bool
1067FullO3CPU<Impl>::tryDrain()
1068{
1069    if (drainState() != DrainState::Draining || !isCpuDrained())
1070        return false;
1071
1072    if (tickEvent.scheduled())
1073        deschedule(tickEvent);
1074
1075    DPRINTF(Drain, "CPU done draining, processing drain event\n");
1076    signalDrainDone();
1077
1078    return true;
1079}
1080
1081template <class Impl>
1082void
1083FullO3CPU<Impl>::drainSanityCheck() const
1084{
1085    assert(isCpuDrained());
1086    fetch.drainSanityCheck();
1087    decode.drainSanityCheck();
1088    rename.drainSanityCheck();
1089    iew.drainSanityCheck();
1090    commit.drainSanityCheck();
1091}
1092
1093template <class Impl>
1094bool
1095FullO3CPU<Impl>::isCpuDrained() const
1096{
1097    bool drained(true);
1098
1099    if (!instList.empty() || !removeList.empty()) {
1100        DPRINTF(Drain, "Main CPU structures not drained.\n");
1101        drained = false;
1102    }
1103
1104    if (!fetch.isDrained()) {
1105        DPRINTF(Drain, "Fetch not drained.\n");
1106        drained = false;
1107    }
1108
1109    if (!decode.isDrained()) {
1110        DPRINTF(Drain, "Decode not drained.\n");
1111        drained = false;
1112    }
1113
1114    if (!rename.isDrained()) {
1115        DPRINTF(Drain, "Rename not drained.\n");
1116        drained = false;
1117    }
1118
1119    if (!iew.isDrained()) {
1120        DPRINTF(Drain, "IEW not drained.\n");
1121        drained = false;
1122    }
1123
1124    if (!commit.isDrained()) {
1125        DPRINTF(Drain, "Commit not drained.\n");
1126        drained = false;
1127    }
1128
1129    return drained;
1130}
1131
1132template <class Impl>
1133void
1134FullO3CPU<Impl>::commitDrained(ThreadID tid)
1135{
1136    fetch.drainStall(tid);
1137}
1138
1139template <class Impl>
1140void
1141FullO3CPU<Impl>::drainResume()
1142{
1143    if (switchedOut())
1144        return;
1145
1146    DPRINTF(Drain, "Resuming...\n");
1147    verifyMemoryMode();
1148
1149    fetch.drainResume();
1150    commit.drainResume();
1151
1152    _status = Idle;
1153    for (ThreadID i = 0; i < thread.size(); i++) {
1154        if (thread[i]->status() == ThreadContext::Active) {
1155            DPRINTF(Drain, "Activating thread: %i\n", i);
1156            activateThread(i);
1157            _status = Running;
1158        }
1159    }
1160
1161    assert(!tickEvent.scheduled());
1162    if (_status == Running)
1163        schedule(tickEvent, nextCycle());
1164
1165    // Reschedule any power gating event (if any)
1166    schedulePowerGatingEvent();
1167}
1168
1169template <class Impl>
1170void
1171FullO3CPU<Impl>::switchOut()
1172{
1173    DPRINTF(O3CPU, "Switching out\n");
1174    BaseCPU::switchOut();
1175
1176    activityRec.reset();
1177
1178    _status = SwitchedOut;
1179
1180    if (checker)
1181        checker->switchOut();
1182}
1183
1184template <class Impl>
1185void
1186FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
1187{
1188    BaseCPU::takeOverFrom(oldCPU);
1189
1190    fetch.takeOverFrom();
1191    decode.takeOverFrom();
1192    rename.takeOverFrom();
1193    iew.takeOverFrom();
1194    commit.takeOverFrom();
1195
1196    assert(!tickEvent.scheduled());
1197
1198    FullO3CPU<Impl> *oldO3CPU = dynamic_cast<FullO3CPU<Impl>*>(oldCPU);
1199    if (oldO3CPU)
1200        globalSeqNum = oldO3CPU->globalSeqNum;
1201
1202    lastRunningCycle = curCycle();
1203    _status = Idle;
1204}
1205
1206template <class Impl>
1207void
1208FullO3CPU<Impl>::verifyMemoryMode() const
1209{
1210    if (!system->isTimingMode()) {
1211        fatal("The O3 CPU requires the memory system to be in "
1212              "'timing' mode.\n");
1213    }
1214}
1215
1216template <class Impl>
1217RegVal
1218FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid) const
1219{
1220    return this->isa[tid]->readMiscRegNoEffect(misc_reg);
1221}
1222
1223template <class Impl>
1224RegVal
1225FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid)
1226{
1227    miscRegfileReads++;
1228    return this->isa[tid]->readMiscReg(misc_reg, tcBase(tid));
1229}
1230
1231template <class Impl>
1232void
1233FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, RegVal val, ThreadID tid)
1234{
1235    this->isa[tid]->setMiscRegNoEffect(misc_reg, val);
1236}
1237
1238template <class Impl>
1239void
1240FullO3CPU<Impl>::setMiscReg(int misc_reg, RegVal val, ThreadID tid)
1241{
1242    miscRegfileWrites++;
1243    this->isa[tid]->setMiscReg(misc_reg, val, tcBase(tid));
1244}
1245
1246template <class Impl>
1247RegVal
1248FullO3CPU<Impl>::readIntReg(PhysRegIdPtr phys_reg)
1249{
1250    intRegfileReads++;
1251    return regFile.readIntReg(phys_reg);
1252}
1253
1254template <class Impl>
1255RegVal
1256FullO3CPU<Impl>::readFloatReg(PhysRegIdPtr phys_reg)
1257{
1258    fpRegfileReads++;
1259    return regFile.readFloatReg(phys_reg);
1260}
1261
1262template <class Impl>
1263auto
1264FullO3CPU<Impl>::readVecReg(PhysRegIdPtr phys_reg) const
1265        -> const VecRegContainer&
1266{
1267    vecRegfileReads++;
1268    return regFile.readVecReg(phys_reg);
1269}
1270
1271template <class Impl>
1272auto
1273FullO3CPU<Impl>::getWritableVecReg(PhysRegIdPtr phys_reg)
1274        -> VecRegContainer&
1275{
1276    vecRegfileWrites++;
1277    return regFile.getWritableVecReg(phys_reg);
1278}
1279
1280template <class Impl>
1281auto
1282FullO3CPU<Impl>::readVecElem(PhysRegIdPtr phys_reg) const -> const VecElem&
1283{
1284    vecRegfileReads++;
1285    return regFile.readVecElem(phys_reg);
1286}
1287
1288template <class Impl>
1289auto
1290FullO3CPU<Impl>::readVecPredReg(PhysRegIdPtr phys_reg) const
1291        -> const VecPredRegContainer&
1292{
1293    vecPredRegfileReads++;
1294    return regFile.readVecPredReg(phys_reg);
1295}
1296
1297template <class Impl>
1298auto
1299FullO3CPU<Impl>::getWritableVecPredReg(PhysRegIdPtr phys_reg)
1300        -> VecPredRegContainer&
1301{
1302    vecPredRegfileWrites++;
1303    return regFile.getWritableVecPredReg(phys_reg);
1304}
1305
1306template <class Impl>
1307RegVal
1308FullO3CPU<Impl>::readCCReg(PhysRegIdPtr phys_reg)
1309{
1310    ccRegfileReads++;
1311    return regFile.readCCReg(phys_reg);
1312}
1313
1314template <class Impl>
1315void
1316FullO3CPU<Impl>::setIntReg(PhysRegIdPtr phys_reg, RegVal val)
1317{
1318    intRegfileWrites++;
1319    regFile.setIntReg(phys_reg, val);
1320}
1321
1322template <class Impl>
1323void
1324FullO3CPU<Impl>::setFloatReg(PhysRegIdPtr phys_reg, RegVal val)
1325{
1326    fpRegfileWrites++;
1327    regFile.setFloatReg(phys_reg, val);
1328}
1329
1330template <class Impl>
1331void
1332FullO3CPU<Impl>::setVecReg(PhysRegIdPtr phys_reg, const VecRegContainer& val)
1333{
1334    vecRegfileWrites++;
1335    regFile.setVecReg(phys_reg, val);
1336}
1337
1338template <class Impl>
1339void
1340FullO3CPU<Impl>::setVecElem(PhysRegIdPtr phys_reg, const VecElem& val)
1341{
1342    vecRegfileWrites++;
1343    regFile.setVecElem(phys_reg, val);
1344}
1345
1346template <class Impl>
1347void
1348FullO3CPU<Impl>::setVecPredReg(PhysRegIdPtr phys_reg,
1349                               const VecPredRegContainer& val)
1350{
1351    vecPredRegfileWrites++;
1352    regFile.setVecPredReg(phys_reg, val);
1353}
1354
1355template <class Impl>
1356void
1357FullO3CPU<Impl>::setCCReg(PhysRegIdPtr phys_reg, RegVal val)
1358{
1359    ccRegfileWrites++;
1360    regFile.setCCReg(phys_reg, val);
1361}
1362
1363template <class Impl>
1364RegVal
1365FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid)
1366{
1367    intRegfileReads++;
1368    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1369            RegId(IntRegClass, reg_idx));
1370
1371    return regFile.readIntReg(phys_reg);
1372}
1373
1374template <class Impl>
1375RegVal
1376FullO3CPU<Impl>::readArchFloatReg(int reg_idx, ThreadID tid)
1377{
1378    fpRegfileReads++;
1379    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1380        RegId(FloatRegClass, reg_idx));
1381
1382    return regFile.readFloatReg(phys_reg);
1383}
1384
1385template <class Impl>
1386auto
1387FullO3CPU<Impl>::readArchVecReg(int reg_idx, ThreadID tid) const
1388        -> const VecRegContainer&
1389{
1390    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1391                RegId(VecRegClass, reg_idx));
1392    return readVecReg(phys_reg);
1393}
1394
1395template <class Impl>
1396auto
1397FullO3CPU<Impl>::getWritableArchVecReg(int reg_idx, ThreadID tid)
1398        -> VecRegContainer&
1399{
1400    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1401                RegId(VecRegClass, reg_idx));
1402    return getWritableVecReg(phys_reg);
1403}
1404
1405template <class Impl>
1406auto
1407FullO3CPU<Impl>::readArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
1408                                 ThreadID tid) const -> const VecElem&
1409{
1410    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1411                                RegId(VecElemClass, reg_idx, ldx));
1412    return readVecElem(phys_reg);
1413}
1414
1415template <class Impl>
1416auto
1417FullO3CPU<Impl>::readArchVecPredReg(int reg_idx, ThreadID tid) const
1418        -> const VecPredRegContainer&
1419{
1420    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1421                RegId(VecPredRegClass, reg_idx));
1422    return readVecPredReg(phys_reg);
1423}
1424
1425template <class Impl>
1426auto
1427FullO3CPU<Impl>::getWritableArchVecPredReg(int reg_idx, ThreadID tid)
1428        -> VecPredRegContainer&
1429{
1430    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1431                RegId(VecPredRegClass, reg_idx));
1432    return getWritableVecPredReg(phys_reg);
1433}
1434
1435template <class Impl>
1436RegVal
1437FullO3CPU<Impl>::readArchCCReg(int reg_idx, ThreadID tid)
1438{
1439    ccRegfileReads++;
1440    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1441        RegId(CCRegClass, reg_idx));
1442
1443    return regFile.readCCReg(phys_reg);
1444}
1445
1446template <class Impl>
1447void
1448FullO3CPU<Impl>::setArchIntReg(int reg_idx, RegVal val, ThreadID tid)
1449{
1450    intRegfileWrites++;
1451    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1452            RegId(IntRegClass, reg_idx));
1453
1454    regFile.setIntReg(phys_reg, val);
1455}
1456
1457template <class Impl>
1458void
1459FullO3CPU<Impl>::setArchFloatReg(int reg_idx, RegVal val, ThreadID tid)
1460{
1461    fpRegfileWrites++;
1462    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1463            RegId(FloatRegClass, reg_idx));
1464
1465    regFile.setFloatReg(phys_reg, val);
1466}
1467
1468template <class Impl>
1469void
1470FullO3CPU<Impl>::setArchVecReg(int reg_idx, const VecRegContainer& val,
1471                               ThreadID tid)
1472{
1473    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1474                RegId(VecRegClass, reg_idx));
1475    setVecReg(phys_reg, val);
1476}
1477
1478template <class Impl>
1479void
1480FullO3CPU<Impl>::setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx,
1481                                const VecElem& val, ThreadID tid)
1482{
1483    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1484                RegId(VecElemClass, reg_idx, ldx));
1485    setVecElem(phys_reg, val);
1486}
1487
1488template <class Impl>
1489void
1490FullO3CPU<Impl>::setArchVecPredReg(int reg_idx, const VecPredRegContainer& val,
1491                                   ThreadID tid)
1492{
1493    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1494                RegId(VecPredRegClass, reg_idx));
1495    setVecPredReg(phys_reg, val);
1496}
1497
1498template <class Impl>
1499void
1500FullO3CPU<Impl>::setArchCCReg(int reg_idx, RegVal val, ThreadID tid)
1501{
1502    ccRegfileWrites++;
1503    PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup(
1504            RegId(CCRegClass, reg_idx));
1505
1506    regFile.setCCReg(phys_reg, val);
1507}
1508
1509template <class Impl>
1510TheISA::PCState
1511FullO3CPU<Impl>::pcState(ThreadID tid)
1512{
1513    return commit.pcState(tid);
1514}
1515
1516template <class Impl>
1517void
1518FullO3CPU<Impl>::pcState(const TheISA::PCState &val, ThreadID tid)
1519{
1520    commit.pcState(val, tid);
1521}
1522
1523template <class Impl>
1524Addr
1525FullO3CPU<Impl>::instAddr(ThreadID tid)
1526{
1527    return commit.instAddr(tid);
1528}
1529
1530template <class Impl>
1531Addr
1532FullO3CPU<Impl>::nextInstAddr(ThreadID tid)
1533{
1534    return commit.nextInstAddr(tid);
1535}
1536
1537template <class Impl>
1538MicroPC
1539FullO3CPU<Impl>::microPC(ThreadID tid)
1540{
1541    return commit.microPC(tid);
1542}
1543
1544template <class Impl>
1545void
1546FullO3CPU<Impl>::squashFromTC(ThreadID tid)
1547{
1548    this->thread[tid]->noSquashFromTC = true;
1549    this->commit.generateTCEvent(tid);
1550}
1551
1552template <class Impl>
1553typename FullO3CPU<Impl>::ListIt
1554FullO3CPU<Impl>::addInst(const DynInstPtr &inst)
1555{
1556    instList.push_back(inst);
1557
1558    return --(instList.end());
1559}
1560
1561template <class Impl>
1562void
1563FullO3CPU<Impl>::instDone(ThreadID tid, const DynInstPtr &inst)
1564{
1565    // Keep an instruction count.
1566    if (!inst->isMicroop() || inst->isLastMicroop()) {
1567        thread[tid]->numInst++;
1568        thread[tid]->numInsts++;
1569        committedInsts[tid]++;
1570        system->totalNumInsts++;
1571
1572        // Check for instruction-count-based events.
1573        comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1574        system->instEventQueue.serviceEvents(system->totalNumInsts);
1575    }
1576    thread[tid]->numOp++;
1577    thread[tid]->numOps++;
1578    committedOps[tid]++;
1579
1580    probeInstCommit(inst->staticInst, inst->instAddr());
1581}
1582
1583template <class Impl>
1584void
1585FullO3CPU<Impl>::removeFrontInst(const DynInstPtr &inst)
1586{
1587    DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %s "
1588            "[sn:%lli]\n",
1589            inst->threadNumber, inst->pcState(), inst->seqNum);
1590
1591    removeInstsThisCycle = true;
1592
1593    // Remove the front instruction.
1594    removeList.push(inst->getInstListIt());
1595}
1596
1597template <class Impl>
1598void
1599FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid)
1600{
1601    DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
1602            " list.\n", tid);
1603
1604    ListIt end_it;
1605
1606    bool rob_empty = false;
1607
1608    if (instList.empty()) {
1609        return;
1610    } else if (rob.isEmpty(tid)) {
1611        DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
1612        end_it = instList.begin();
1613        rob_empty = true;
1614    } else {
1615        end_it = (rob.readTailInst(tid))->getInstListIt();
1616        DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
1617    }
1618
1619    removeInstsThisCycle = true;
1620
1621    ListIt inst_it = instList.end();
1622
1623    inst_it--;
1624
1625    // Walk through the instruction list, removing any instructions
1626    // that were inserted after the given instruction iterator, end_it.
1627    while (inst_it != end_it) {
1628        assert(!instList.empty());
1629
1630        squashInstIt(inst_it, tid);
1631
1632        inst_it--;
1633    }
1634
1635    // If the ROB was empty, then we actually need to remove the first
1636    // instruction as well.
1637    if (rob_empty) {
1638        squashInstIt(inst_it, tid);
1639    }
1640}
1641
1642template <class Impl>
1643void
1644FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1645{
1646    assert(!instList.empty());
1647
1648    removeInstsThisCycle = true;
1649
1650    ListIt inst_iter = instList.end();
1651
1652    inst_iter--;
1653
1654    DPRINTF(O3CPU, "Deleting instructions from instruction "
1655            "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1656            tid, seq_num, (*inst_iter)->seqNum);
1657
1658    while ((*inst_iter)->seqNum > seq_num) {
1659
1660        bool break_loop = (inst_iter == instList.begin());
1661
1662        squashInstIt(inst_iter, tid);
1663
1664        inst_iter--;
1665
1666        if (break_loop)
1667            break;
1668    }
1669}
1670
1671template <class Impl>
1672inline void
1673FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid)
1674{
1675    if ((*instIt)->threadNumber == tid) {
1676        DPRINTF(O3CPU, "Squashing instruction, "
1677                "[tid:%i] [sn:%lli] PC %s\n",
1678                (*instIt)->threadNumber,
1679                (*instIt)->seqNum,
1680                (*instIt)->pcState());
1681
1682        // Mark it as squashed.
1683        (*instIt)->setSquashed();
1684
1685        // @todo: Formulate a consistent method for deleting
1686        // instructions from the instruction list
1687        // Remove the instruction from the list.
1688        removeList.push(instIt);
1689    }
1690}
1691
1692template <class Impl>
1693void
1694FullO3CPU<Impl>::cleanUpRemovedInsts()
1695{
1696    while (!removeList.empty()) {
1697        DPRINTF(O3CPU, "Removing instruction, "
1698                "[tid:%i] [sn:%lli] PC %s\n",
1699                (*removeList.front())->threadNumber,
1700                (*removeList.front())->seqNum,
1701                (*removeList.front())->pcState());
1702
1703        instList.erase(removeList.front());
1704
1705        removeList.pop();
1706    }
1707
1708    removeInstsThisCycle = false;
1709}
1710/*
1711template <class Impl>
1712void
1713FullO3CPU<Impl>::removeAllInsts()
1714{
1715    instList.clear();
1716}
1717*/
1718template <class Impl>
1719void
1720FullO3CPU<Impl>::dumpInsts()
1721{
1722    int num = 0;
1723
1724    ListIt inst_list_it = instList.begin();
1725
1726    cprintf("Dumping Instruction List\n");
1727
1728    while (inst_list_it != instList.end()) {
1729        cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1730                "Squashed:%i\n\n",
1731                num, (*inst_list_it)->instAddr(), (*inst_list_it)->threadNumber,
1732                (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1733                (*inst_list_it)->isSquashed());
1734        inst_list_it++;
1735        ++num;
1736    }
1737}
1738/*
1739template <class Impl>
1740void
1741FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst)
1742{
1743    iew.wakeDependents(inst);
1744}
1745*/
1746template <class Impl>
1747void
1748FullO3CPU<Impl>::wakeCPU()
1749{
1750    if (activityRec.active() || tickEvent.scheduled()) {
1751        DPRINTF(Activity, "CPU already running.\n");
1752        return;
1753    }
1754
1755    DPRINTF(Activity, "Waking up CPU\n");
1756
1757    Cycles cycles(curCycle() - lastRunningCycle);
1758    // @todo: This is an oddity that is only here to match the stats
1759    if (cycles > 1) {
1760        --cycles;
1761        idleCycles += cycles;
1762        numCycles += cycles;
1763    }
1764
1765    schedule(tickEvent, clockEdge());
1766}
1767
1768template <class Impl>
1769void
1770FullO3CPU<Impl>::wakeup(ThreadID tid)
1771{
1772    if (this->thread[tid]->status() != ThreadContext::Suspended)
1773        return;
1774
1775    this->wakeCPU();
1776
1777    DPRINTF(Quiesce, "Suspended Processor woken\n");
1778    this->threadContexts[tid]->activate();
1779}
1780
1781template <class Impl>
1782ThreadID
1783FullO3CPU<Impl>::getFreeTid()
1784{
1785    for (ThreadID tid = 0; tid < numThreads; tid++) {
1786        if (!tids[tid]) {
1787            tids[tid] = true;
1788            return tid;
1789        }
1790    }
1791
1792    return InvalidThreadID;
1793}
1794
1795template <class Impl>
1796void
1797FullO3CPU<Impl>::updateThreadPriority()
1798{
1799    if (activeThreads.size() > 1) {
1800        //DEFAULT TO ROUND ROBIN SCHEME
1801        //e.g. Move highest priority to end of thread list
1802        list<ThreadID>::iterator list_begin = activeThreads.begin();
1803
1804        unsigned high_thread = *list_begin;
1805
1806        activeThreads.erase(list_begin);
1807
1808        activeThreads.push_back(high_thread);
1809    }
1810}
1811
1812template <class Impl>
1813void
1814FullO3CPU<Impl>::addThreadToExitingList(ThreadID tid)
1815{
1816    DPRINTF(O3CPU, "Thread %d is inserted to exitingThreads list\n", tid);
1817
1818    // the thread trying to exit can't be already halted
1819    assert(tcBase(tid)->status() != ThreadContext::Halted);
1820
1821    // make sure the thread has not been added to the list yet
1822    assert(exitingThreads.count(tid) == 0);
1823
1824    // add the thread to exitingThreads list to mark that this thread is
1825    // trying to exit. The boolean value in the pair denotes if a thread is
1826    // ready to exit. The thread is not ready to exit until the corresponding
1827    // exit trap event is processed in the future. Until then, it'll be still
1828    // an active thread that is trying to exit.
1829    exitingThreads.emplace(std::make_pair(tid, false));
1830}
1831
1832template <class Impl>
1833bool
1834FullO3CPU<Impl>::isThreadExiting(ThreadID tid) const
1835{
1836    return exitingThreads.count(tid) == 1;
1837}
1838
1839template <class Impl>
1840void
1841FullO3CPU<Impl>::scheduleThreadExitEvent(ThreadID tid)
1842{
1843    assert(exitingThreads.count(tid) == 1);
1844
1845    // exit trap event has been processed. Now, the thread is ready to exit
1846    // and be removed from the CPU.
1847    exitingThreads[tid] = true;
1848
1849    // we schedule a threadExitEvent in the next cycle to properly clean
1850    // up the thread's states in the pipeline. threadExitEvent has lower
1851    // priority than tickEvent, so the cleanup will happen at the very end
1852    // of the next cycle after all pipeline stages complete their operations.
1853    // We want all stages to complete squashing instructions before doing
1854    // the cleanup.
1855    if (!threadExitEvent.scheduled()) {
1856        schedule(threadExitEvent, nextCycle());
1857    }
1858}
1859
1860template <class Impl>
1861void
1862FullO3CPU<Impl>::exitThreads()
1863{
1864    // there must be at least one thread trying to exit
1865    assert(exitingThreads.size() > 0);
1866
1867    // terminate all threads that are ready to exit
1868    auto it = exitingThreads.begin();
1869    while (it != exitingThreads.end()) {
1870        ThreadID thread_id = it->first;
1871        bool readyToExit = it->second;
1872
1873        if (readyToExit) {
1874            DPRINTF(O3CPU, "Exiting thread %d\n", thread_id);
1875            haltContext(thread_id);
1876            tcBase(thread_id)->setStatus(ThreadContext::Halted);
1877            it = exitingThreads.erase(it);
1878        } else {
1879            it++;
1880        }
1881    }
1882}
1883
1884// Forward declaration of FullO3CPU.
1885template class FullO3CPU<O3CPUImpl>;
1886