base.cc revision 13818:f0126488ef9e
18839Sandreas.hansson@arm.com/*
28839Sandreas.hansson@arm.com * Copyright (c) 2011-2012,2016-2017 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 * Copyright (c) 2002-2005 The Regents of The University of Michigan
153101Sstever@eecs.umich.edu * Copyright (c) 2011 Regents of the University of California
163101Sstever@eecs.umich.edu * Copyright (c) 2013 Advanced Micro Devices, Inc.
173101Sstever@eecs.umich.edu * Copyright (c) 2013 Mark D. Hill and David A. Wood
183101Sstever@eecs.umich.edu * All rights reserved.
193101Sstever@eecs.umich.edu *
203101Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
213101Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
223101Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
233101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
243101Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
253101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
263101Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
273101Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
283101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
293101Sstever@eecs.umich.edu * this software without specific prior written permission.
303101Sstever@eecs.umich.edu *
313101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
323101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
333101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
343101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
353101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
363101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
373101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
383101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
393101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
403101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
413101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
427778Sgblack@eecs.umich.edu *
438839Sandreas.hansson@arm.com * Authors: Steve Reinhardt
443101Sstever@eecs.umich.edu *          Nathan Binkert
453101Sstever@eecs.umich.edu *          Rick Strong
463101Sstever@eecs.umich.edu */
473101Sstever@eecs.umich.edu
483101Sstever@eecs.umich.edu#include "cpu/base.hh"
493101Sstever@eecs.umich.edu
503101Sstever@eecs.umich.edu#include <iostream>
513101Sstever@eecs.umich.edu#include <sstream>
523101Sstever@eecs.umich.edu#include <string>
533101Sstever@eecs.umich.edu
543101Sstever@eecs.umich.edu#include "arch/generic/tlb.hh"
553101Sstever@eecs.umich.edu#include "base/cprintf.hh"
563101Sstever@eecs.umich.edu#include "base/loader/symtab.hh"
573101Sstever@eecs.umich.edu#include "base/logging.hh"
583101Sstever@eecs.umich.edu#include "base/output.hh"
593101Sstever@eecs.umich.edu#include "base/trace.hh"
603101Sstever@eecs.umich.edu#include "cpu/checker/cpu.hh"
613101Sstever@eecs.umich.edu#include "cpu/cpuevent.hh"
623885Sbinkertn@umich.edu#include "cpu/profile.hh"
633885Sbinkertn@umich.edu#include "cpu/thread_context.hh"
644762Snate@binkert.org#include "debug/Mwait.hh"
653885Sbinkertn@umich.edu#include "debug/SyscallVerbose.hh"
663885Sbinkertn@umich.edu#include "mem/page_table.hh"
677528Ssteve.reinhardt@amd.com#include "params/BaseCPU.hh"
683885Sbinkertn@umich.edu#include "sim/clocked_object.hh"
694380Sbinkertn@umich.edu#include "sim/full_system.hh"
704167Sbinkertn@umich.edu#include "sim/process.hh"
713102Sstever@eecs.umich.edu#include "sim/sim_events.hh"
723101Sstever@eecs.umich.edu#include "sim/sim_exit.hh"
734762Snate@binkert.org#include "sim/system.hh"
744762Snate@binkert.org
754762Snate@binkert.org// Hack
764762Snate@binkert.org#include "sim/stat_control.hh"
774762Snate@binkert.org
784762Snate@binkert.orgusing namespace std;
794762Snate@binkert.org
804762Snate@binkert.orgvector<BaseCPU *> BaseCPU::cpuList;
814762Snate@binkert.org
825033Smilesck@eecs.umich.edu// This variable reflects the max number of threads in any CPU.  Be
835033Smilesck@eecs.umich.edu// careful to only use it once all the CPUs that you care about have
845033Smilesck@eecs.umich.edu// been initialized
855033Smilesck@eecs.umich.eduint maxThreadsPerCPU = 1;
865033Smilesck@eecs.umich.edu
875033Smilesck@eecs.umich.eduCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
885033Smilesck@eecs.umich.edu    : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
895033Smilesck@eecs.umich.edu      cpu(_cpu), _repeatEvent(true)
905033Smilesck@eecs.umich.edu{
915033Smilesck@eecs.umich.edu    if (_interval)
923101Sstever@eecs.umich.edu        cpu->schedule(this, curTick() + _interval);
933101Sstever@eecs.umich.edu}
943101Sstever@eecs.umich.edu
955033Smilesck@eecs.umich.eduvoid
963101Sstever@eecs.umich.eduCPUProgressEvent::process()
978596Ssteve.reinhardt@amd.com{
988596Ssteve.reinhardt@amd.com    Counter temp = cpu->totalOps();
998596Ssteve.reinhardt@amd.com
1008596Ssteve.reinhardt@amd.com    if (_repeatEvent)
1017673Snate@binkert.org      cpu->schedule(this, curTick() + _interval);
1027673Snate@binkert.org
1037673Snate@binkert.org    if (cpu->switchedOut()) {
1047673Snate@binkert.org      return;
1058596Ssteve.reinhardt@amd.com    }
1068596Ssteve.reinhardt@amd.com
1078596Ssteve.reinhardt@amd.com#ifndef NDEBUG
1087673Snate@binkert.org    double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod());
1097673Snate@binkert.org
1107673Snate@binkert.org    DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
1113101Sstever@eecs.umich.edu             "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
1123101Sstever@eecs.umich.edu             ipc);
1133101Sstever@eecs.umich.edu    ipc = 0.0;
1143101Sstever@eecs.umich.edu#else
1153101Sstever@eecs.umich.edu    cprintf("%lli: %s progress event, total committed:%i, progress insts "
1163101Sstever@eecs.umich.edu            "committed: %lli\n", curTick(), cpu->name(), temp,
1173101Sstever@eecs.umich.edu            temp - lastNumInst);
1183101Sstever@eecs.umich.edu#endif
1193101Sstever@eecs.umich.edu    lastNumInst = temp;
1203101Sstever@eecs.umich.edu}
1213101Sstever@eecs.umich.edu
1223101Sstever@eecs.umich.educonst char *
1233101Sstever@eecs.umich.eduCPUProgressEvent::description() const
1243101Sstever@eecs.umich.edu{
1253101Sstever@eecs.umich.edu    return "CPU Progress";
1263101Sstever@eecs.umich.edu}
1273101Sstever@eecs.umich.edu
1283101Sstever@eecs.umich.eduBaseCPU::BaseCPU(Params *p, bool is_checker)
1293101Sstever@eecs.umich.edu    : MemObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id),
1303101Sstever@eecs.umich.edu      _instMasterId(p->system->getMasterId(this, "inst")),
1313101Sstever@eecs.umich.edu      _dataMasterId(p->system->getMasterId(this, "data")),
1323101Sstever@eecs.umich.edu      _taskId(ContextSwitchTaskId::Unknown), _pid(invldPid),
1333101Sstever@eecs.umich.edu      _switchedOut(p->switched_out), _cacheLineSize(p->system->cacheLineSize()),
1343101Sstever@eecs.umich.edu      interrupts(p->interrupts), profileEvent(NULL),
1353101Sstever@eecs.umich.edu      numThreads(p->numThreads), system(p->system),
1363101Sstever@eecs.umich.edu      previousCycle(0), previousState(CPU_STATE_SLEEP),
1373101Sstever@eecs.umich.edu      functionTraceStream(nullptr), currentFunctionStart(0),
1383101Sstever@eecs.umich.edu      currentFunctionEnd(0), functionEntryTick(0),
1393101Sstever@eecs.umich.edu      addressMonitor(p->numThreads),
1403101Sstever@eecs.umich.edu      syscallRetryLatency(p->syscallRetryLatency),
1413101Sstever@eecs.umich.edu      pwrGatingLatency(p->pwr_gating_latency),
1423101Sstever@eecs.umich.edu      powerGatingOnIdle(p->power_gating_on_idle),
1433101Sstever@eecs.umich.edu      enterPwrGatingEvent([this]{ enterPwrGating(); }, name())
1443101Sstever@eecs.umich.edu{
1453101Sstever@eecs.umich.edu    // if Python did not provide a valid ID, do it here
1463101Sstever@eecs.umich.edu    if (_cpuId == -1 ) {
1473101Sstever@eecs.umich.edu        _cpuId = cpuList.size();
1483101Sstever@eecs.umich.edu    }
1493101Sstever@eecs.umich.edu
1503101Sstever@eecs.umich.edu    // add self to global list of CPUs
1513101Sstever@eecs.umich.edu    cpuList.push_back(this);
1523101Sstever@eecs.umich.edu
1533101Sstever@eecs.umich.edu    DPRINTF(SyscallVerbose, "Constructing CPU with id %d, socket id %d\n",
1543101Sstever@eecs.umich.edu                _cpuId, _socketId);
1553101Sstever@eecs.umich.edu
1563101Sstever@eecs.umich.edu    if (numThreads > maxThreadsPerCPU)
1575033Smilesck@eecs.umich.edu        maxThreadsPerCPU = numThreads;
1586656Snate@binkert.org
1595033Smilesck@eecs.umich.edu    // allocate per-thread instruction-based event queues
1605033Smilesck@eecs.umich.edu    comInstEventQueue = new EventQueue *[numThreads];
1615033Smilesck@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
1623101Sstever@eecs.umich.edu        comInstEventQueue[tid] =
1633101Sstever@eecs.umich.edu            new EventQueue("instruction-based event queue");
1643101Sstever@eecs.umich.edu
1653101Sstever@eecs.umich.edu    //
1663101Sstever@eecs.umich.edu    // set up instruction-count-based termination events, if any
1673101Sstever@eecs.umich.edu    //
1683101Sstever@eecs.umich.edu    if (p->max_insts_any_thread != 0) {
1693101Sstever@eecs.umich.edu        const char *cause = "a thread reached the max instruction count";
1703101Sstever@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid)
1713101Sstever@eecs.umich.edu            scheduleInstStop(tid, p->max_insts_any_thread, cause);
1723101Sstever@eecs.umich.edu    }
1733101Sstever@eecs.umich.edu
1743101Sstever@eecs.umich.edu    // Set up instruction-count-based termination events for SimPoints
1753102Sstever@eecs.umich.edu    // Typically, there are more than one action points.
1763101Sstever@eecs.umich.edu    // Simulation.py is responsible to take the necessary actions upon
1773101Sstever@eecs.umich.edu    // exitting the simulation loop.
1783101Sstever@eecs.umich.edu    if (!p->simpoint_start_insts.empty()) {
1797673Snate@binkert.org        const char *cause = "simpoint starting point found";
1808607Sgblack@eecs.umich.edu        for (size_t i = 0; i < p->simpoint_start_insts.size(); ++i)
1817673Snate@binkert.org            scheduleInstStop(0, p->simpoint_start_insts[i], cause);
1823101Sstever@eecs.umich.edu    }
1837673Snate@binkert.org
1847673Snate@binkert.org    if (p->max_insts_all_threads != 0) {
1853101Sstever@eecs.umich.edu        const char *cause = "all threads reached the max instruction count";
1867673Snate@binkert.org
1877673Snate@binkert.org        // allocate & initialize shared downcounter: each event will
1883101Sstever@eecs.umich.edu        // decrement this when triggered; simulation will terminate
1893101Sstever@eecs.umich.edu        // when counter reaches 0
1903101Sstever@eecs.umich.edu        int *counter = new int;
1913101Sstever@eecs.umich.edu        *counter = numThreads;
1923101Sstever@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid) {
1933101Sstever@eecs.umich.edu            Event *event = new CountedExitEvent(cause, *counter);
1945033Smilesck@eecs.umich.edu            comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads);
1955475Snate@binkert.org        }
1965475Snate@binkert.org    }
1975475Snate@binkert.org
1985475Snate@binkert.org    // allocate per-thread load-based event queues
1993101Sstever@eecs.umich.edu    comLoadEventQueue = new EventQueue *[numThreads];
2003101Sstever@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
2013101Sstever@eecs.umich.edu        comLoadEventQueue[tid] = new EventQueue("load-based event queue");
2024762Snate@binkert.org
2034762Snate@binkert.org    //
2044762Snate@binkert.org    // set up instruction-count-based termination events, if any
2053101Sstever@eecs.umich.edu    //
2068460SAli.Saidi@ARM.com    if (p->max_loads_any_thread != 0) {
2078459SAli.Saidi@ARM.com        const char *cause = "a thread reached the max load count";
2088459SAli.Saidi@ARM.com        for (ThreadID tid = 0; tid < numThreads; ++tid)
2098459SAli.Saidi@ARM.com            scheduleLoadStop(tid, p->max_loads_any_thread, cause);
2103101Sstever@eecs.umich.edu    }
2117528Ssteve.reinhardt@amd.com
2127528Ssteve.reinhardt@amd.com    if (p->max_loads_all_threads != 0) {
2137528Ssteve.reinhardt@amd.com        const char *cause = "all threads reached the max load count";
2147528Ssteve.reinhardt@amd.com        // allocate & initialize shared downcounter: each event will
2157528Ssteve.reinhardt@amd.com        // decrement this when triggered; simulation will terminate
2167528Ssteve.reinhardt@amd.com        // when counter reaches 0
2173101Sstever@eecs.umich.edu        int *counter = new int;
2187528Ssteve.reinhardt@amd.com        *counter = numThreads;
2197528Ssteve.reinhardt@amd.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
2207528Ssteve.reinhardt@amd.com            Event *event = new CountedExitEvent(cause, *counter);
2217528Ssteve.reinhardt@amd.com            comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads);
2227528Ssteve.reinhardt@amd.com        }
2237528Ssteve.reinhardt@amd.com    }
2247528Ssteve.reinhardt@amd.com
2257528Ssteve.reinhardt@amd.com    functionTracingEnabled = false;
2267528Ssteve.reinhardt@amd.com    if (p->function_trace) {
2277528Ssteve.reinhardt@amd.com        const string fname = csprintf("ftrace.%s", name());
2288321Ssteve.reinhardt@amd.com        functionTraceStream = simout.findOrCreate(fname)->stream();
2298321Ssteve.reinhardt@amd.com
2307528Ssteve.reinhardt@amd.com        currentFunctionStart = currentFunctionEnd = 0;
2317528Ssteve.reinhardt@amd.com        functionEntryTick = p->function_trace_start;
2327528Ssteve.reinhardt@amd.com
2337528Ssteve.reinhardt@amd.com        if (p->function_trace_start == 0) {
2347528Ssteve.reinhardt@amd.com            functionTracingEnabled = true;
2357528Ssteve.reinhardt@amd.com        } else {
2367528Ssteve.reinhardt@amd.com            Event *event = new EventFunctionWrapper(
2377528Ssteve.reinhardt@amd.com                [this]{ enableFunctionTrace(); }, name(), true);
2387528Ssteve.reinhardt@amd.com            schedule(event, p->function_trace_start);
2397528Ssteve.reinhardt@amd.com        }
2407528Ssteve.reinhardt@amd.com    }
2417528Ssteve.reinhardt@amd.com
2427528Ssteve.reinhardt@amd.com    // The interrupts should always be present unless this CPU is
2433101Sstever@eecs.umich.edu    // switched in later or in case it is a checker CPU
2448664SAli.Saidi@ARM.com    if (!params()->switched_out && !is_checker) {
2458664SAli.Saidi@ARM.com        fatal_if(interrupts.size() != numThreads,
2468664SAli.Saidi@ARM.com                 "CPU %s has %i interrupt controllers, but is expecting one "
2478664SAli.Saidi@ARM.com                 "per thread (%i)\n",
2488664SAli.Saidi@ARM.com                 name(), interrupts.size(), numThreads);
2498664SAli.Saidi@ARM.com        for (ThreadID tid = 0; tid < numThreads; tid++)
2503101Sstever@eecs.umich.edu            interrupts[tid]->setCPU(this);
2513101Sstever@eecs.umich.edu    }
2523101Sstever@eecs.umich.edu
2533101Sstever@eecs.umich.edu    if (FullSystem) {
2543101Sstever@eecs.umich.edu        if (params()->profile)
2553101Sstever@eecs.umich.edu            profileEvent = new EventFunctionWrapper(
2563101Sstever@eecs.umich.edu                [this]{ processProfileEvent(); },
2573101Sstever@eecs.umich.edu                name());
2584762Snate@binkert.org    }
2594762Snate@binkert.org    tracer = params()->tracer;
2604762Snate@binkert.org
2614762Snate@binkert.org    if (params()->isa.size() != numThreads) {
2627528Ssteve.reinhardt@amd.com        fatal("Number of ISAs (%i) assigned to the CPU does not equal number "
2634762Snate@binkert.org              "of threads (%i).\n", params()->isa.size(), numThreads);
2644762Snate@binkert.org    }
2654762Snate@binkert.org}
2668596Ssteve.reinhardt@amd.com
2678596Ssteve.reinhardt@amd.comvoid
2688596Ssteve.reinhardt@amd.comBaseCPU::enableFunctionTrace()
2697673Snate@binkert.org{
2708596Ssteve.reinhardt@amd.com    functionTracingEnabled = true;
2714762Snate@binkert.org}
2727673Snate@binkert.org
2738596Ssteve.reinhardt@amd.comBaseCPU::~BaseCPU()
2747675Snate@binkert.org{
2757675Snate@binkert.org    delete profileEvent;
2767675Snate@binkert.org    delete[] comLoadEventQueue;
2777675Snate@binkert.org    delete[] comInstEventQueue;
2788656Sandreas.hansson@arm.com}
2798656Sandreas.hansson@arm.com
2808656Sandreas.hansson@arm.comvoid
2817675Snate@binkert.orgBaseCPU::armMonitor(ThreadID tid, Addr address)
2827675Snate@binkert.org{
2837673Snate@binkert.org    assert(tid < numThreads);
2847675Snate@binkert.org    AddressMonitor &monitor = addressMonitor[tid];
2857675Snate@binkert.org
2867675Snate@binkert.org    monitor.armed = true;
2877675Snate@binkert.org    monitor.vAddr = address;
2887675Snate@binkert.org    monitor.pAddr = 0x0;
2897673Snate@binkert.org    DPRINTF(Mwait,"[tid:%d] Armed monitor (vAddr=0x%lx)\n", tid, address);
2907675Snate@binkert.org}
2917675Snate@binkert.org
2927675Snate@binkert.orgbool
2937675Snate@binkert.orgBaseCPU::mwait(ThreadID tid, PacketPtr pkt)
2947675Snate@binkert.org{
2957675Snate@binkert.org    assert(tid < numThreads);
2967675Snate@binkert.org    AddressMonitor &monitor = addressMonitor[tid];
2977675Snate@binkert.org
2987675Snate@binkert.org    if (!monitor.gotWakeup) {
2997675Snate@binkert.org        int block_size = cacheLineSize();
3007675Snate@binkert.org        uint64_t mask = ~((uint64_t)(block_size - 1));
3017675Snate@binkert.org
3027675Snate@binkert.org        assert(pkt->req->hasPaddr());
3037675Snate@binkert.org        monitor.pAddr = pkt->getAddr() & mask;
3047675Snate@binkert.org        monitor.waiting = true;
3057675Snate@binkert.org
3067673Snate@binkert.org        DPRINTF(Mwait,"[tid:%d] mwait called (vAddr=0x%lx, "
3077673Snate@binkert.org                "line's paddr=0x%lx)\n", tid, monitor.vAddr, monitor.pAddr);
3083101Sstever@eecs.umich.edu        return true;
3097675Snate@binkert.org    } else {
3107675Snate@binkert.org        monitor.gotWakeup = false;
3117673Snate@binkert.org        return false;
3127673Snate@binkert.org    }
3137673Snate@binkert.org}
3143101Sstever@eecs.umich.edu
3157673Snate@binkert.orgvoid
3167673Snate@binkert.orgBaseCPU::mwaitAtomic(ThreadID tid, ThreadContext *tc, BaseTLB *dtb)
3173101Sstever@eecs.umich.edu{
3183101Sstever@eecs.umich.edu    assert(tid < numThreads);
3193101Sstever@eecs.umich.edu    AddressMonitor &monitor = addressMonitor[tid];
3203101Sstever@eecs.umich.edu
3213101Sstever@eecs.umich.edu    RequestPtr req = std::make_shared<Request>();
3223101Sstever@eecs.umich.edu
3233101Sstever@eecs.umich.edu    Addr addr = monitor.vAddr;
3243101Sstever@eecs.umich.edu    int block_size = cacheLineSize();
3253101Sstever@eecs.umich.edu    uint64_t mask = ~((uint64_t)(block_size - 1));
3263101Sstever@eecs.umich.edu    int size = block_size;
3273101Sstever@eecs.umich.edu
3283101Sstever@eecs.umich.edu    //The address of the next line if it crosses a cache line boundary.
3293101Sstever@eecs.umich.edu    Addr secondAddr = roundDown(addr + size - 1, block_size);
3303101Sstever@eecs.umich.edu
3313101Sstever@eecs.umich.edu    if (secondAddr > addr)
3325033Smilesck@eecs.umich.edu        size = secondAddr - addr;
3335033Smilesck@eecs.umich.edu
3343101Sstever@eecs.umich.edu    req->setVirt(0, addr, size, 0x0, dataMasterId(), tc->instAddr());
3353101Sstever@eecs.umich.edu
3363101Sstever@eecs.umich.edu    // translate to physical address
3373101Sstever@eecs.umich.edu    Fault fault = dtb->translateAtomic(req, tc, BaseTLB::Read);
3383101Sstever@eecs.umich.edu    assert(fault == NoFault);
3393101Sstever@eecs.umich.edu
3403101Sstever@eecs.umich.edu    monitor.pAddr = req->getPaddr() & mask;
3413101Sstever@eecs.umich.edu    monitor.waiting = true;
3423101Sstever@eecs.umich.edu
3433101Sstever@eecs.umich.edu    DPRINTF(Mwait,"[tid:%d] mwait called (vAddr=0x%lx, line's paddr=0x%lx)\n",
3443101Sstever@eecs.umich.edu            tid, monitor.vAddr, monitor.pAddr);
3453101Sstever@eecs.umich.edu}
3463101Sstever@eecs.umich.edu
3473101Sstever@eecs.umich.eduvoid
3483101Sstever@eecs.umich.eduBaseCPU::init()
3493101Sstever@eecs.umich.edu{
3503101Sstever@eecs.umich.edu    if (!params()->switched_out) {
3513101Sstever@eecs.umich.edu        registerThreadContexts();
3523101Sstever@eecs.umich.edu
3533101Sstever@eecs.umich.edu        verifyMemoryMode();
3543101Sstever@eecs.umich.edu    }
3553101Sstever@eecs.umich.edu}
3563101Sstever@eecs.umich.edu
3573101Sstever@eecs.umich.eduvoid
3583101Sstever@eecs.umich.eduBaseCPU::startup()
3597673Snate@binkert.org{
3607673Snate@binkert.org    if (FullSystem) {
3617673Snate@binkert.org        if (!params()->switched_out && profileEvent)
3627673Snate@binkert.org            schedule(profileEvent, curTick());
3637673Snate@binkert.org    }
3647673Snate@binkert.org
3657673Snate@binkert.org    if (params()->progress_interval) {
3667673Snate@binkert.org        new CPUProgressEvent(this, params()->progress_interval);
3674762Snate@binkert.org    }
3684762Snate@binkert.org
3694762Snate@binkert.org    if (_switchedOut)
3703101Sstever@eecs.umich.edu        ClockedObject::pwrState(Enums::PwrState::OFF);
3713101Sstever@eecs.umich.edu
3723101Sstever@eecs.umich.edu    // Assumption CPU start to operate instantaneously without any latency
3733101Sstever@eecs.umich.edu    if (ClockedObject::pwrState() == Enums::PwrState::UNDEFINED)
3743101Sstever@eecs.umich.edu        ClockedObject::pwrState(Enums::PwrState::ON);
3753101Sstever@eecs.umich.edu
3763101Sstever@eecs.umich.edu}
3773101Sstever@eecs.umich.edu
3783101Sstever@eecs.umich.eduProbePoints::PMUUPtr
3793101Sstever@eecs.umich.eduBaseCPU::pmuProbePoint(const char *name)
3803101Sstever@eecs.umich.edu{
3813714Sstever@eecs.umich.edu    ProbePoints::PMUUPtr ptr;
3823714Sstever@eecs.umich.edu    ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
3833714Sstever@eecs.umich.edu
3843714Sstever@eecs.umich.edu    return ptr;
3853714Sstever@eecs.umich.edu}
3863714Sstever@eecs.umich.edu
3873101Sstever@eecs.umich.eduvoid
3883101Sstever@eecs.umich.eduBaseCPU::regProbePoints()
3893101Sstever@eecs.umich.edu{
3903101Sstever@eecs.umich.edu    ppAllCycles = pmuProbePoint("Cycles");
3913101Sstever@eecs.umich.edu    ppActiveCycles = pmuProbePoint("ActiveCycles");
3923101Sstever@eecs.umich.edu
3933101Sstever@eecs.umich.edu    ppRetiredInsts = pmuProbePoint("RetiredInsts");
3943101Sstever@eecs.umich.edu    ppRetiredInstsPC = pmuProbePoint("RetiredInstsPC");
3953101Sstever@eecs.umich.edu    ppRetiredLoads = pmuProbePoint("RetiredLoads");
3963101Sstever@eecs.umich.edu    ppRetiredStores = pmuProbePoint("RetiredStores");
3973101Sstever@eecs.umich.edu    ppRetiredBranches = pmuProbePoint("RetiredBranches");
3983101Sstever@eecs.umich.edu
3993101Sstever@eecs.umich.edu    ppSleeping = new ProbePointArg<bool>(this->getProbeManager(),
4003101Sstever@eecs.umich.edu                                         "Sleeping");
4013101Sstever@eecs.umich.edu}
4023101Sstever@eecs.umich.edu
4033101Sstever@eecs.umich.eduvoid
4043101Sstever@eecs.umich.eduBaseCPU::probeInstCommit(const StaticInstPtr &inst, Addr pc)
4053101Sstever@eecs.umich.edu{
4063101Sstever@eecs.umich.edu    if (!inst->isMicroop() || inst->isLastMicroop()) {
4073101Sstever@eecs.umich.edu        ppRetiredInsts->notify(1);
4083101Sstever@eecs.umich.edu        ppRetiredInstsPC->notify(pc);
4093101Sstever@eecs.umich.edu    }
4103101Sstever@eecs.umich.edu
4113101Sstever@eecs.umich.edu    if (inst->isLoad())
4125033Smilesck@eecs.umich.edu        ppRetiredLoads->notify(1);
4133101Sstever@eecs.umich.edu
4143101Sstever@eecs.umich.edu    if (inst->isStore() || inst->isAtomic())
4153101Sstever@eecs.umich.edu        ppRetiredStores->notify(1);
4163101Sstever@eecs.umich.edu
4173101Sstever@eecs.umich.edu    if (inst->isControl())
4183101Sstever@eecs.umich.edu        ppRetiredBranches->notify(1);
4193101Sstever@eecs.umich.edu}
4203101Sstever@eecs.umich.edu
4213101Sstever@eecs.umich.eduvoid
4223101Sstever@eecs.umich.eduBaseCPU::regStats()
4233101Sstever@eecs.umich.edu{
4243101Sstever@eecs.umich.edu    MemObject::regStats();
4255822Ssaidi@eecs.umich.edu
4265822Ssaidi@eecs.umich.edu    using namespace Stats;
4273101Sstever@eecs.umich.edu
4283101Sstever@eecs.umich.edu    numCycles
4293101Sstever@eecs.umich.edu        .name(name() + ".numCycles")
4303101Sstever@eecs.umich.edu        .desc("number of cpu cycles simulated")
4313101Sstever@eecs.umich.edu        ;
4323101Sstever@eecs.umich.edu
4333101Sstever@eecs.umich.edu    numWorkItemsStarted
4343101Sstever@eecs.umich.edu        .name(name() + ".numWorkItemsStarted")
4353101Sstever@eecs.umich.edu        .desc("number of work items this cpu started")
4363101Sstever@eecs.umich.edu        ;
4373101Sstever@eecs.umich.edu
4383101Sstever@eecs.umich.edu    numWorkItemsCompleted
4393101Sstever@eecs.umich.edu        .name(name() + ".numWorkItemsCompleted")
4403101Sstever@eecs.umich.edu        .desc("number of work items this cpu completed")
4413101Sstever@eecs.umich.edu        ;
4423101Sstever@eecs.umich.edu
4433101Sstever@eecs.umich.edu    int size = threadContexts.size();
4443101Sstever@eecs.umich.edu    if (size > 1) {
4453101Sstever@eecs.umich.edu        for (int i = 0; i < size; ++i) {
4463101Sstever@eecs.umich.edu            stringstream namestr;
4473101Sstever@eecs.umich.edu            ccprintf(namestr, "%s.ctx%d", name(), i);
4483102Sstever@eecs.umich.edu            threadContexts[i]->regStats(namestr.str());
4493714Sstever@eecs.umich.edu        }
4503101Sstever@eecs.umich.edu    } else if (size == 1)
4513714Sstever@eecs.umich.edu        threadContexts[0]->regStats(name());
4523714Sstever@eecs.umich.edu}
4533714Sstever@eecs.umich.edu
4543101Sstever@eecs.umich.eduPort &
4553101Sstever@eecs.umich.eduBaseCPU::getPort(const string &if_name, PortID idx)
4567673Snate@binkert.org{
4577673Snate@binkert.org    // Get the right port based on name. This applies to all the
4587673Snate@binkert.org    // subclasses of the base CPU and relies on their implementation
4597673Snate@binkert.org    // of getDataPort and getInstPort.
4607673Snate@binkert.org    if (if_name == "dcache_port")
4617673Snate@binkert.org        return getDataPort();
4627673Snate@binkert.org    else if (if_name == "icache_port")
4637673Snate@binkert.org        return getInstPort();
4647673Snate@binkert.org    else
4657673Snate@binkert.org        return MemObject::getPort(if_name, idx);
4667673Snate@binkert.org}
4674762Snate@binkert.org
4684762Snate@binkert.orgvoid
4694762Snate@binkert.orgBaseCPU::registerThreadContexts()
4703101Sstever@eecs.umich.edu{
4713101Sstever@eecs.umich.edu    assert(system->multiThread || numThreads == 1);
4723101Sstever@eecs.umich.edu
4733101Sstever@eecs.umich.edu    ThreadID size = threadContexts.size();
4743101Sstever@eecs.umich.edu    for (ThreadID tid = 0; tid < size; ++tid) {
4753101Sstever@eecs.umich.edu        ThreadContext *tc = threadContexts[tid];
4763101Sstever@eecs.umich.edu
4773101Sstever@eecs.umich.edu        if (system->multiThread) {
4783101Sstever@eecs.umich.edu            tc->setContextId(system->registerThreadContext(tc));
4793101Sstever@eecs.umich.edu        } else {
4803101Sstever@eecs.umich.edu            tc->setContextId(system->registerThreadContext(tc, _cpuId));
4813101Sstever@eecs.umich.edu        }
4823101Sstever@eecs.umich.edu
4833101Sstever@eecs.umich.edu        if (!FullSystem)
4843101Sstever@eecs.umich.edu            tc->getProcessPtr()->assignThreadContext(tc->contextId());
4853101Sstever@eecs.umich.edu    }
4863101Sstever@eecs.umich.edu}
4873101Sstever@eecs.umich.edu
4883101Sstever@eecs.umich.eduvoid
4899184Sandreas.hansson@arm.comBaseCPU::deschedulePowerGatingEvent()
4909184Sandreas.hansson@arm.com{
4919184Sandreas.hansson@arm.com    if (enterPwrGatingEvent.scheduled()){
4929184Sandreas.hansson@arm.com        deschedule(enterPwrGatingEvent);
4939184Sandreas.hansson@arm.com    }
4949184Sandreas.hansson@arm.com}
4959184Sandreas.hansson@arm.com
4969184Sandreas.hansson@arm.comvoid
4979184Sandreas.hansson@arm.comBaseCPU::schedulePowerGatingEvent()
4983101Sstever@eecs.umich.edu{
4994446Sbinkertn@umich.edu    for (auto tc : threadContexts) {
5003101Sstever@eecs.umich.edu        if (tc->status() == ThreadContext::Active)
5015468Snate@binkert.org            return;
5025468Snate@binkert.org    }
5035468Snate@binkert.org
5045468Snate@binkert.org    if (ClockedObject::pwrState() == Enums::PwrState::CLK_GATED &&
5055468Snate@binkert.org        powerGatingOnIdle) {
5065468Snate@binkert.org        assert(!enterPwrGatingEvent.scheduled());
5075468Snate@binkert.org        // Schedule a power gating event when clock gated for the specified
5084762Snate@binkert.org        // amount of time
5094762Snate@binkert.org        schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
5104762Snate@binkert.org    }
5113101Sstever@eecs.umich.edu}
5123101Sstever@eecs.umich.edu
5133101Sstever@eecs.umich.eduint
5143101Sstever@eecs.umich.eduBaseCPU::findContext(ThreadContext *tc)
5153101Sstever@eecs.umich.edu{
5163101Sstever@eecs.umich.edu    ThreadID size = threadContexts.size();
5173101Sstever@eecs.umich.edu    for (ThreadID tid = 0; tid < size; ++tid) {
5183101Sstever@eecs.umich.edu        if (tc == threadContexts[tid])
5193102Sstever@eecs.umich.edu            return tid;
5203101Sstever@eecs.umich.edu    }
5213101Sstever@eecs.umich.edu    return 0;
5223101Sstever@eecs.umich.edu}
5234168Sbinkertn@umich.edu
5243101Sstever@eecs.umich.eduvoid
5253101Sstever@eecs.umich.eduBaseCPU::activateContext(ThreadID thread_num)
5263101Sstever@eecs.umich.edu{
5273101Sstever@eecs.umich.edu    // Squash enter power gating event while cpu gets activated
5283101Sstever@eecs.umich.edu    if (enterPwrGatingEvent.scheduled())
5293101Sstever@eecs.umich.edu        deschedule(enterPwrGatingEvent);
5303102Sstever@eecs.umich.edu    // For any active thread running, update CPU power state to active (ON)
5313101Sstever@eecs.umich.edu    ClockedObject::pwrState(Enums::PwrState::ON);
5323101Sstever@eecs.umich.edu
5333101Sstever@eecs.umich.edu    updateCycleCounters(CPU_STATE_WAKEUP);
5343101Sstever@eecs.umich.edu}
5353101Sstever@eecs.umich.edu
5363101Sstever@eecs.umich.eduvoid
5373101Sstever@eecs.umich.eduBaseCPU::suspendContext(ThreadID thread_num)
5383101Sstever@eecs.umich.edu{
5393101Sstever@eecs.umich.edu    // Check if all threads are suspended
5403101Sstever@eecs.umich.edu    for (auto t : threadContexts) {
5413101Sstever@eecs.umich.edu        if (t->status() != ThreadContext::Suspended) {
5423102Sstever@eecs.umich.edu            return;
5433101Sstever@eecs.umich.edu        }
5443101Sstever@eecs.umich.edu    }
5453101Sstever@eecs.umich.edu
5463584Ssaidi@eecs.umich.edu    // All CPU thread are suspended, update cycle count
5473584Ssaidi@eecs.umich.edu    updateCycleCounters(CPU_STATE_SLEEP);
5483584Ssaidi@eecs.umich.edu
5493584Ssaidi@eecs.umich.edu    // All CPU threads suspended, enter lower power state for the CPU
5503584Ssaidi@eecs.umich.edu    ClockedObject::pwrState(Enums::PwrState::CLK_GATED);
5513101Sstever@eecs.umich.edu
5523101Sstever@eecs.umich.edu    // If pwrGatingLatency is set to 0 then this mechanism is disabled
5535033Smilesck@eecs.umich.edu    if (powerGatingOnIdle) {
5543101Sstever@eecs.umich.edu        // Schedule power gating event when clock gated for pwrGatingLatency
5553101Sstever@eecs.umich.edu        // cycles
5563101Sstever@eecs.umich.edu        schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
5573101Sstever@eecs.umich.edu    }
5583101Sstever@eecs.umich.edu}
5593101Sstever@eecs.umich.edu
5603101Sstever@eecs.umich.eduvoid
5613101Sstever@eecs.umich.eduBaseCPU::haltContext(ThreadID thread_num)
5623101Sstever@eecs.umich.edu{
5633101Sstever@eecs.umich.edu    updateCycleCounters(BaseCPU::CPU_STATE_SLEEP);
5643101Sstever@eecs.umich.edu}
5653101Sstever@eecs.umich.edu
5663101Sstever@eecs.umich.eduvoid
5673101Sstever@eecs.umich.eduBaseCPU::enterPwrGating(void)
5683101Sstever@eecs.umich.edu{
5693101Sstever@eecs.umich.edu    ClockedObject::pwrState(Enums::PwrState::OFF);
5703101Sstever@eecs.umich.edu}
5713101Sstever@eecs.umich.edu
5723101Sstever@eecs.umich.eduvoid
5733101Sstever@eecs.umich.eduBaseCPU::switchOut()
5743101Sstever@eecs.umich.edu{
5753101Sstever@eecs.umich.edu    assert(!_switchedOut);
5763101Sstever@eecs.umich.edu    _switchedOut = true;
5773101Sstever@eecs.umich.edu    if (profileEvent && profileEvent->scheduled())
5783101Sstever@eecs.umich.edu        deschedule(profileEvent);
5793101Sstever@eecs.umich.edu
5803101Sstever@eecs.umich.edu    // Flush all TLBs in the CPU to avoid having stale translations if
5813101Sstever@eecs.umich.edu    // it gets switched in later.
5823101Sstever@eecs.umich.edu    flushTLBs();
5835219Ssaidi@eecs.umich.edu
5845219Ssaidi@eecs.umich.edu    // Go to the power gating state
5855219Ssaidi@eecs.umich.edu    ClockedObject::pwrState(Enums::PwrState::OFF);
5863101Sstever@eecs.umich.edu}
5873101Sstever@eecs.umich.edu
5883101Sstever@eecs.umich.eduvoid
5893101Sstever@eecs.umich.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU)
5903101Sstever@eecs.umich.edu{
5913101Sstever@eecs.umich.edu    assert(threadContexts.size() == oldCPU->threadContexts.size());
5923101Sstever@eecs.umich.edu    assert(_cpuId == oldCPU->cpuId());
5933101Sstever@eecs.umich.edu    assert(_switchedOut);
5943101Sstever@eecs.umich.edu    assert(oldCPU != this);
5953101Sstever@eecs.umich.edu    _pid = oldCPU->getPid();
5963101Sstever@eecs.umich.edu    _taskId = oldCPU->taskId();
5973101Sstever@eecs.umich.edu    // Take over the power state of the switchedOut CPU
5983101Sstever@eecs.umich.edu    ClockedObject::pwrState(oldCPU->pwrState());
5993101Sstever@eecs.umich.edu
6003101Sstever@eecs.umich.edu    previousState = oldCPU->previousState;
6013101Sstever@eecs.umich.edu    previousCycle = oldCPU->previousCycle;
6027673Snate@binkert.org
6037673Snate@binkert.org    _switchedOut = false;
6047675Snate@binkert.org
6057673Snate@binkert.org    ThreadID size = threadContexts.size();
6067675Snate@binkert.org    for (ThreadID i = 0; i < size; ++i) {
6077675Snate@binkert.org        ThreadContext *newTC = threadContexts[i];
6087675Snate@binkert.org        ThreadContext *oldTC = oldCPU->threadContexts[i];
6097675Snate@binkert.org
6107675Snate@binkert.org        newTC->takeOverFrom(oldTC);
6117673Snate@binkert.org
6123101Sstever@eecs.umich.edu        CpuEvent::replaceThreadContext(oldTC, newTC);
6133101Sstever@eecs.umich.edu
6147673Snate@binkert.org        assert(newTC->contextId() == oldTC->contextId());
6154762Snate@binkert.org        assert(newTC->threadId() == oldTC->threadId());
6167675Snate@binkert.org        system->replaceThreadContext(newTC, newTC->contextId());
6174762Snate@binkert.org
6184762Snate@binkert.org        /* This code no longer works since the zero register (e.g.,
6194762Snate@binkert.org         * r31 on Alpha) doesn't necessarily contain zero at this
6204762Snate@binkert.org         * point.
6214762Snate@binkert.org           if (DTRACE(Context))
6223101Sstever@eecs.umich.edu            ThreadContext::compare(oldTC, newTC);
6233101Sstever@eecs.umich.edu        */
6243101Sstever@eecs.umich.edu
6257673Snate@binkert.org        Port *old_itb_port = oldTC->getITBPtr()->getTableWalkerPort();
6264762Snate@binkert.org        Port *old_dtb_port = oldTC->getDTBPtr()->getTableWalkerPort();
6277675Snate@binkert.org        Port *new_itb_port = newTC->getITBPtr()->getTableWalkerPort();
6284762Snate@binkert.org        Port *new_dtb_port = newTC->getDTBPtr()->getTableWalkerPort();
6294762Snate@binkert.org
6304762Snate@binkert.org        // Move over any table walker ports if they exist
6314762Snate@binkert.org        if (new_itb_port) {
6324762Snate@binkert.org            assert(!new_itb_port->isConnected());
6333101Sstever@eecs.umich.edu            assert(old_itb_port);
6343101Sstever@eecs.umich.edu            assert(old_itb_port->isConnected());
6353101Sstever@eecs.umich.edu            auto &slavePort =
6363101Sstever@eecs.umich.edu                dynamic_cast<BaseMasterPort *>(old_itb_port)->getSlavePort();
6373101Sstever@eecs.umich.edu            old_itb_port->unbind();
6383101Sstever@eecs.umich.edu            new_itb_port->bind(slavePort);
6393101Sstever@eecs.umich.edu        }
6403101Sstever@eecs.umich.edu        if (new_dtb_port) {
6413102Sstever@eecs.umich.edu            assert(!new_dtb_port->isConnected());
6423101Sstever@eecs.umich.edu            assert(old_dtb_port);
6433101Sstever@eecs.umich.edu            assert(old_dtb_port->isConnected());
6443101Sstever@eecs.umich.edu            auto &slavePort =
6454762Snate@binkert.org                dynamic_cast<BaseMasterPort *>(old_dtb_port)->getSlavePort();
6464762Snate@binkert.org            old_dtb_port->unbind();
6474762Snate@binkert.org            new_dtb_port->bind(slavePort);
6483101Sstever@eecs.umich.edu        }
6493101Sstever@eecs.umich.edu        newTC->getITBPtr()->takeOverFrom(oldTC->getITBPtr());
6503101Sstever@eecs.umich.edu        newTC->getDTBPtr()->takeOverFrom(oldTC->getDTBPtr());
6518934SBrad.Beckmann@amd.com
6528934SBrad.Beckmann@amd.com        // Checker whether or not we have to transfer CheckerCPU
6538934SBrad.Beckmann@amd.com        // objects over in the switch
6548934SBrad.Beckmann@amd.com        CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr();
6558934SBrad.Beckmann@amd.com        CheckerCPU *newChecker = newTC->getCheckerCpuPtr();
6563101Sstever@eecs.umich.edu        if (oldChecker && newChecker) {
6573101Sstever@eecs.umich.edu            Port *old_checker_itb_port =
6583101Sstever@eecs.umich.edu                oldChecker->getITBPtr()->getTableWalkerPort();
6593101Sstever@eecs.umich.edu            Port *old_checker_dtb_port =
6603101Sstever@eecs.umich.edu                oldChecker->getDTBPtr()->getTableWalkerPort();
6613101Sstever@eecs.umich.edu            Port *new_checker_itb_port =
6623101Sstever@eecs.umich.edu                newChecker->getITBPtr()->getTableWalkerPort();
6633101Sstever@eecs.umich.edu            Port *new_checker_dtb_port =
6643101Sstever@eecs.umich.edu                newChecker->getDTBPtr()->getTableWalkerPort();
6653101Sstever@eecs.umich.edu
6663101Sstever@eecs.umich.edu            newChecker->getITBPtr()->takeOverFrom(oldChecker->getITBPtr());
6673101Sstever@eecs.umich.edu            newChecker->getDTBPtr()->takeOverFrom(oldChecker->getDTBPtr());
6683101Sstever@eecs.umich.edu
6693101Sstever@eecs.umich.edu            // Move over any table walker ports if they exist for checker
6703101Sstever@eecs.umich.edu            if (new_checker_itb_port) {
6713101Sstever@eecs.umich.edu                assert(!new_checker_itb_port->isConnected());
6723101Sstever@eecs.umich.edu                assert(old_checker_itb_port);
6734380Sbinkertn@umich.edu                assert(old_checker_itb_port->isConnected());
6744380Sbinkertn@umich.edu                auto &slavePort =
6754380Sbinkertn@umich.edu                    dynamic_cast<BaseMasterPort *>(old_checker_itb_port)->
6763101Sstever@eecs.umich.edu                    getSlavePort();
6774380Sbinkertn@umich.edu                old_checker_itb_port->unbind();
6784380Sbinkertn@umich.edu                new_checker_itb_port->bind(slavePort);
6794380Sbinkertn@umich.edu            }
6803101Sstever@eecs.umich.edu            if (new_checker_dtb_port) {
6813101Sstever@eecs.umich.edu                assert(!new_checker_dtb_port->isConnected());
6823101Sstever@eecs.umich.edu                assert(old_checker_dtb_port);
6837673Snate@binkert.org                assert(old_checker_dtb_port->isConnected());
6847673Snate@binkert.org                auto &slavePort =
6857673Snate@binkert.org                    dynamic_cast<BaseMasterPort *>(old_checker_dtb_port)->
6867673Snate@binkert.org                    getSlavePort();
6877673Snate@binkert.org                old_checker_dtb_port->unbind();
6887673Snate@binkert.org                new_checker_dtb_port->bind(slavePort);
6897673Snate@binkert.org            }
6907673Snate@binkert.org        }
6917673Snate@binkert.org    }
6923101Sstever@eecs.umich.edu
6933101Sstever@eecs.umich.edu    interrupts = oldCPU->interrupts;
6943101Sstever@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; tid++) {
6953101Sstever@eecs.umich.edu        interrupts[tid]->setCPU(this);
6963101Sstever@eecs.umich.edu    }
6973101Sstever@eecs.umich.edu    oldCPU->interrupts.clear();
6983101Sstever@eecs.umich.edu
6993101Sstever@eecs.umich.edu    if (FullSystem) {
7003101Sstever@eecs.umich.edu        for (ThreadID i = 0; i < size; ++i)
7013101Sstever@eecs.umich.edu            threadContexts[i]->profileClear();
7023101Sstever@eecs.umich.edu
7033101Sstever@eecs.umich.edu        if (profileEvent)
7043101Sstever@eecs.umich.edu            schedule(profileEvent, curTick());
7057743Sgblack@eecs.umich.edu    }
7063101Sstever@eecs.umich.edu
7073101Sstever@eecs.umich.edu    // All CPUs have an instruction and a data port, and the new CPU's
7083101Sstever@eecs.umich.edu    // ports are dangling while the old CPU has its ports connected
7093101Sstever@eecs.umich.edu    // already. Unbind the old CPU and then bind the ports of the one
7103101Sstever@eecs.umich.edu    // we are switching to.
7113101Sstever@eecs.umich.edu    assert(!getInstPort().isConnected());
7124380Sbinkertn@umich.edu    assert(oldCPU->getInstPort().isConnected());
7133101Sstever@eecs.umich.edu    auto &inst_peer_port =
7143101Sstever@eecs.umich.edu        dynamic_cast<BaseMasterPort &>(oldCPU->getInstPort()).getSlavePort();
7154762Snate@binkert.org    oldCPU->getInstPort().unbind();
7167677Snate@binkert.org    getInstPort().bind(inst_peer_port);
7174762Snate@binkert.org
7184762Snate@binkert.org    assert(!getDataPort().isConnected());
7194380Sbinkertn@umich.edu    assert(oldCPU->getDataPort().isConnected());
7204380Sbinkertn@umich.edu    auto &data_peer_port =
7213101Sstever@eecs.umich.edu        dynamic_cast<BaseMasterPort &>(oldCPU->getDataPort()).getSlavePort();
7227777Sgblack@eecs.umich.edu    oldCPU->getDataPort().unbind();
7237777Sgblack@eecs.umich.edu    getDataPort().bind(data_peer_port);
7247777Sgblack@eecs.umich.edu}
7257777Sgblack@eecs.umich.edu
7267777Sgblack@eecs.umich.eduvoid
7277777Sgblack@eecs.umich.eduBaseCPU::flushTLBs()
7287777Sgblack@eecs.umich.edu{
7297777Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < threadContexts.size(); ++i) {
7307777Sgblack@eecs.umich.edu        ThreadContext &tc(*threadContexts[i]);
7317777Sgblack@eecs.umich.edu        CheckerCPU *checker(tc.getCheckerCpuPtr());
7327777Sgblack@eecs.umich.edu
7337777Sgblack@eecs.umich.edu        tc.getITBPtr()->flushAll();
7347777Sgblack@eecs.umich.edu        tc.getDTBPtr()->flushAll();
7357777Sgblack@eecs.umich.edu        if (checker) {
7367777Sgblack@eecs.umich.edu            checker->getITBPtr()->flushAll();
7377777Sgblack@eecs.umich.edu            checker->getDTBPtr()->flushAll();
7387777Sgblack@eecs.umich.edu        }
7397777Sgblack@eecs.umich.edu    }
7407777Sgblack@eecs.umich.edu}
7417777Sgblack@eecs.umich.edu
7427777Sgblack@eecs.umich.eduvoid
7437777Sgblack@eecs.umich.eduBaseCPU::processProfileEvent()
7447777Sgblack@eecs.umich.edu{
7458579Ssteve.reinhardt@amd.com    ThreadID size = threadContexts.size();
7468579Ssteve.reinhardt@amd.com
7478579Ssteve.reinhardt@amd.com    for (ThreadID i = 0; i < size; ++i)
7488579Ssteve.reinhardt@amd.com        threadContexts[i]->profileSample();
7498579Ssteve.reinhardt@amd.com
7508579Ssteve.reinhardt@amd.com    schedule(profileEvent, curTick() + params()->profile);
7518579Ssteve.reinhardt@amd.com}
7528579Ssteve.reinhardt@amd.com
7538579Ssteve.reinhardt@amd.comvoid
7548579Ssteve.reinhardt@amd.comBaseCPU::serialize(CheckpointOut &cp) const
7558579Ssteve.reinhardt@amd.com{
7568579Ssteve.reinhardt@amd.com    SERIALIZE_SCALAR(instCnt);
7578579Ssteve.reinhardt@amd.com
7588579Ssteve.reinhardt@amd.com    if (!_switchedOut) {
7598579Ssteve.reinhardt@amd.com        /* Unlike _pid, _taskId is not serialized, as they are dynamically
7608579Ssteve.reinhardt@amd.com         * assigned unique ids that are only meaningful for the duration of
7618579Ssteve.reinhardt@amd.com         * a specific run. We will need to serialize the entire taskMap in
7628579Ssteve.reinhardt@amd.com         * system. */
7637777Sgblack@eecs.umich.edu        SERIALIZE_SCALAR(_pid);
7647777Sgblack@eecs.umich.edu
7657798Sgblack@eecs.umich.edu        // Serialize the threads, this is done by the CPU implementation.
7667777Sgblack@eecs.umich.edu        for (ThreadID i = 0; i < numThreads; ++i) {
7677777Sgblack@eecs.umich.edu            ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
7687777Sgblack@eecs.umich.edu            interrupts[i]->serialize(cp);
7697777Sgblack@eecs.umich.edu            serializeThread(cp, i);
7707777Sgblack@eecs.umich.edu        }
7717777Sgblack@eecs.umich.edu    }
7727777Sgblack@eecs.umich.edu}
7737777Sgblack@eecs.umich.edu
7747777Sgblack@eecs.umich.eduvoid
7757777Sgblack@eecs.umich.eduBaseCPU::unserialize(CheckpointIn &cp)
7767777Sgblack@eecs.umich.edu{
7777777Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(instCnt);
7787777Sgblack@eecs.umich.edu
7797777Sgblack@eecs.umich.edu    if (!_switchedOut) {
7807777Sgblack@eecs.umich.edu        UNSERIALIZE_SCALAR(_pid);
7817777Sgblack@eecs.umich.edu
7827777Sgblack@eecs.umich.edu        // Unserialize the threads, this is done by the CPU implementation.
7837777Sgblack@eecs.umich.edu        for (ThreadID i = 0; i < numThreads; ++i) {
7847777Sgblack@eecs.umich.edu            ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
7857777Sgblack@eecs.umich.edu            interrupts[i]->unserialize(cp);
7867777Sgblack@eecs.umich.edu            unserializeThread(cp, i);
7877777Sgblack@eecs.umich.edu        }
7887777Sgblack@eecs.umich.edu    }
7897777Sgblack@eecs.umich.edu}
7907777Sgblack@eecs.umich.edu
7917777Sgblack@eecs.umich.eduvoid
7927777Sgblack@eecs.umich.eduBaseCPU::scheduleInstStop(ThreadID tid, Counter insts, const char *cause)
7937777Sgblack@eecs.umich.edu{
7947777Sgblack@eecs.umich.edu    const Tick now(comInstEventQueue[tid]->getCurTick());
7957777Sgblack@eecs.umich.edu    Event *event(new LocalSimLoopExitEvent(cause, 0));
7967777Sgblack@eecs.umich.edu
7977777Sgblack@eecs.umich.edu    comInstEventQueue[tid]->schedule(event, now + insts);
7987777Sgblack@eecs.umich.edu}
7997777Sgblack@eecs.umich.edu
8007777Sgblack@eecs.umich.eduuint64_t
8017777Sgblack@eecs.umich.eduBaseCPU::getCurrentInstCount(ThreadID tid)
8027777Sgblack@eecs.umich.edu{
8037777Sgblack@eecs.umich.edu    return Tick(comInstEventQueue[tid]->getCurTick());
8047777Sgblack@eecs.umich.edu}
8057777Sgblack@eecs.umich.edu
8067777Sgblack@eecs.umich.eduAddressMonitor::AddressMonitor() {
8077777Sgblack@eecs.umich.edu    armed = false;
8087777Sgblack@eecs.umich.edu    waiting = false;
8097777Sgblack@eecs.umich.edu    gotWakeup = false;
8107777Sgblack@eecs.umich.edu}
8117777Sgblack@eecs.umich.edu
8127777Sgblack@eecs.umich.edubool AddressMonitor::doMonitor(PacketPtr pkt) {
8137777Sgblack@eecs.umich.edu    assert(pkt->req->hasPaddr());
8147777Sgblack@eecs.umich.edu    if (armed && waiting) {
8157777Sgblack@eecs.umich.edu        if (pAddr == pkt->getAddr()) {
8167777Sgblack@eecs.umich.edu            DPRINTF(Mwait,"pAddr=0x%lx invalidated: waking up core\n",
8177777Sgblack@eecs.umich.edu                    pkt->getAddr());
8187777Sgblack@eecs.umich.edu            waiting = false;
8197777Sgblack@eecs.umich.edu            return true;
8207777Sgblack@eecs.umich.edu        }
8218579Ssteve.reinhardt@amd.com    }
8228579Ssteve.reinhardt@amd.com    return false;
8238579Ssteve.reinhardt@amd.com}
8248579Ssteve.reinhardt@amd.com
8258579Ssteve.reinhardt@amd.comvoid
8268579Ssteve.reinhardt@amd.comBaseCPU::scheduleLoadStop(ThreadID tid, Counter loads, const char *cause)
8278579Ssteve.reinhardt@amd.com{
8288579Ssteve.reinhardt@amd.com    const Tick now(comLoadEventQueue[tid]->getCurTick());
8298579Ssteve.reinhardt@amd.com    Event *event(new LocalSimLoopExitEvent(cause, 0));
8308579Ssteve.reinhardt@amd.com
8318579Ssteve.reinhardt@amd.com    comLoadEventQueue[tid]->schedule(event, now + loads);
8328579Ssteve.reinhardt@amd.com}
8338579Ssteve.reinhardt@amd.com
8348579Ssteve.reinhardt@amd.com
8357777Sgblack@eecs.umich.eduvoid
8367777Sgblack@eecs.umich.eduBaseCPU::traceFunctionsInternal(Addr pc)
8377777Sgblack@eecs.umich.edu{
8387777Sgblack@eecs.umich.edu    if (!debugSymbolTable)
8397777Sgblack@eecs.umich.edu        return;
8407777Sgblack@eecs.umich.edu
8417777Sgblack@eecs.umich.edu    // if pc enters different function, print new function symbol and
8427777Sgblack@eecs.umich.edu    // update saved range.  Otherwise do nothing.
8437777Sgblack@eecs.umich.edu    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
8447777Sgblack@eecs.umich.edu        string sym_str;
8457777Sgblack@eecs.umich.edu        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
8467777Sgblack@eecs.umich.edu                                                         currentFunctionStart,
8477777Sgblack@eecs.umich.edu                                                         currentFunctionEnd);
8487777Sgblack@eecs.umich.edu
8497777Sgblack@eecs.umich.edu        if (!found) {
8507777Sgblack@eecs.umich.edu            // no symbol found: use addr as label
8517777Sgblack@eecs.umich.edu            sym_str = csprintf("0x%x", pc);
8527777Sgblack@eecs.umich.edu            currentFunctionStart = pc;
8537777Sgblack@eecs.umich.edu            currentFunctionEnd = pc + 1;
8547777Sgblack@eecs.umich.edu        }
8557777Sgblack@eecs.umich.edu
8567777Sgblack@eecs.umich.edu        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
8577777Sgblack@eecs.umich.edu                 curTick() - functionEntryTick, curTick(), sym_str);
8587777Sgblack@eecs.umich.edu        functionEntryTick = curTick();
8597777Sgblack@eecs.umich.edu    }
8607777Sgblack@eecs.umich.edu}
8617777Sgblack@eecs.umich.edu
8627777Sgblack@eecs.umich.edubool
8637777Sgblack@eecs.umich.eduBaseCPU::waitForRemoteGDB() const
8647777Sgblack@eecs.umich.edu{
8657777Sgblack@eecs.umich.edu    return params()->wait_for_remote_gdb;
8667777Sgblack@eecs.umich.edu}
8677777Sgblack@eecs.umich.edu