base.cc revision 12276:22c220be30c5
14680Sgblack@eecs.umich.edu/*
25442Sgblack@eecs.umich.edu * Copyright (c) 2011-2012,2016-2017 ARM Limited
34680Sgblack@eecs.umich.edu * All rights reserved
44680Sgblack@eecs.umich.edu *
54680Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
64680Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
74680Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
84680Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
94680Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
104680Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
114680Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
124680Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
134680Sgblack@eecs.umich.edu *
144680Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
154680Sgblack@eecs.umich.edu * Copyright (c) 2011 Regents of the University of California
164680Sgblack@eecs.umich.edu * Copyright (c) 2013 Advanced Micro Devices, Inc.
174680Sgblack@eecs.umich.edu * Copyright (c) 2013 Mark D. Hill and David A. Wood
184680Sgblack@eecs.umich.edu * All rights reserved.
194680Sgblack@eecs.umich.edu *
204680Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
214680Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
224680Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
234680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
244680Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
254680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
264680Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
274680Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
284680Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
294680Sgblack@eecs.umich.edu * this software without specific prior written permission.
304680Sgblack@eecs.umich.edu *
314680Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
324680Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
334680Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3412491Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3512625Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3612450Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3712625Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3812450Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
394680Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
404680Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
415543Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
424680Sgblack@eecs.umich.edu *
434680Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
444680Sgblack@eecs.umich.edu *          Nathan Binkert
454680Sgblack@eecs.umich.edu *          Rick Strong
464680Sgblack@eecs.umich.edu */
474680Sgblack@eecs.umich.edu
484680Sgblack@eecs.umich.edu#include "cpu/base.hh"
4912450Sgabeblack@google.com
5012450Sgabeblack@google.com#include <iostream>
5112450Sgabeblack@google.com#include <sstream>
5212450Sgabeblack@google.com#include <string>
5312450Sgabeblack@google.com
5412450Sgabeblack@google.com#include "arch/tlb.hh"
5512450Sgabeblack@google.com#include "base/cprintf.hh"
5612450Sgabeblack@google.com#include "base/loader/symtab.hh"
5712450Sgabeblack@google.com#include "base/misc.hh"
5812450Sgabeblack@google.com#include "base/output.hh"
5912450Sgabeblack@google.com#include "base/trace.hh"
6012450Sgabeblack@google.com#include "cpu/checker/cpu.hh"
6112465Sgabeblack@google.com#include "cpu/cpuevent.hh"
6212465Sgabeblack@google.com#include "cpu/profile.hh"
6312465Sgabeblack@google.com#include "cpu/thread_context.hh"
6412465Sgabeblack@google.com#include "debug/Mwait.hh"
6512450Sgabeblack@google.com#include "debug/SyscallVerbose.hh"
6612465Sgabeblack@google.com#include "mem/page_table.hh"
6712465Sgabeblack@google.com#include "params/BaseCPU.hh"
6812465Sgabeblack@google.com#include "sim/clocked_object.hh"
6912465Sgabeblack@google.com#include "sim/full_system.hh"
7012465Sgabeblack@google.com#include "sim/process.hh"
7112465Sgabeblack@google.com#include "sim/sim_events.hh"
7212450Sgabeblack@google.com#include "sim/sim_exit.hh"
7312465Sgabeblack@google.com#include "sim/system.hh"
7412465Sgabeblack@google.com
7512465Sgabeblack@google.com// Hack
7612465Sgabeblack@google.com#include "sim/stat_control.hh"
7712465Sgabeblack@google.com
7812465Sgabeblack@google.comusing namespace std;
7912465Sgabeblack@google.com
8012450Sgabeblack@google.comvector<BaseCPU *> BaseCPU::cpuList;
8112450Sgabeblack@google.com
8212450Sgabeblack@google.com// This variable reflects the max number of threads in any CPU.  Be
8312465Sgabeblack@google.com// careful to only use it once all the CPUs that you care about have
8412465Sgabeblack@google.com// been initialized
8512450Sgabeblack@google.comint maxThreadsPerCPU = 1;
8612450Sgabeblack@google.com
8712450Sgabeblack@google.comCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
8812450Sgabeblack@google.com    : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
8912450Sgabeblack@google.com      cpu(_cpu), _repeatEvent(true)
9012450Sgabeblack@google.com{
9112450Sgabeblack@google.com    if (_interval)
9212450Sgabeblack@google.com        cpu->schedule(this, curTick() + _interval);
9312450Sgabeblack@google.com}
9412450Sgabeblack@google.com
9512450Sgabeblack@google.comvoid
9612450Sgabeblack@google.comCPUProgressEvent::process()
9712450Sgabeblack@google.com{
9812450Sgabeblack@google.com    Counter temp = cpu->totalOps();
9912450Sgabeblack@google.com
10012450Sgabeblack@google.com    if (_repeatEvent)
10112450Sgabeblack@google.com      cpu->schedule(this, curTick() + _interval);
10212450Sgabeblack@google.com
10312450Sgabeblack@google.com    if (cpu->switchedOut()) {
10412450Sgabeblack@google.com      return;
10512450Sgabeblack@google.com    }
10612450Sgabeblack@google.com
10712450Sgabeblack@google.com#ifndef NDEBUG
10812450Sgabeblack@google.com    double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod());
10912450Sgabeblack@google.com
11012450Sgabeblack@google.com    DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
11112450Sgabeblack@google.com             "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
11212450Sgabeblack@google.com             ipc);
11312450Sgabeblack@google.com    ipc = 0.0;
11412450Sgabeblack@google.com#else
11512450Sgabeblack@google.com    cprintf("%lli: %s progress event, total committed:%i, progress insts "
11612450Sgabeblack@google.com            "committed: %lli\n", curTick(), cpu->name(), temp,
11712450Sgabeblack@google.com            temp - lastNumInst);
11812450Sgabeblack@google.com#endif
11912450Sgabeblack@google.com    lastNumInst = temp;
12012450Sgabeblack@google.com}
12112450Sgabeblack@google.com
12212450Sgabeblack@google.comconst char *
12312450Sgabeblack@google.comCPUProgressEvent::description() const
12412450Sgabeblack@google.com{
12512450Sgabeblack@google.com    return "CPU Progress";
12612450Sgabeblack@google.com}
12712450Sgabeblack@google.com
12812450Sgabeblack@google.comBaseCPU::BaseCPU(Params *p, bool is_checker)
12912450Sgabeblack@google.com    : MemObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id),
13012450Sgabeblack@google.com      _instMasterId(p->system->getMasterId(name() + ".inst")),
13112450Sgabeblack@google.com      _dataMasterId(p->system->getMasterId(name() + ".data")),
13212450Sgabeblack@google.com      _taskId(ContextSwitchTaskId::Unknown), _pid(invldPid),
13312450Sgabeblack@google.com      _switchedOut(p->switched_out), _cacheLineSize(p->system->cacheLineSize()),
13412450Sgabeblack@google.com      interrupts(p->interrupts), profileEvent(NULL),
13512450Sgabeblack@google.com      numThreads(p->numThreads), system(p->system),
13612450Sgabeblack@google.com      functionTraceStream(nullptr), currentFunctionStart(0),
13712450Sgabeblack@google.com      currentFunctionEnd(0), functionEntryTick(0),
13812450Sgabeblack@google.com      addressMonitor(p->numThreads),
13912450Sgabeblack@google.com      syscallRetryLatency(p->syscallRetryLatency),
14012450Sgabeblack@google.com      pwrGatingLatency(p->pwr_gating_latency),
14112450Sgabeblack@google.com      enterPwrGatingEvent([this]{ enterPwrGating(); }, name())
14212450Sgabeblack@google.com{
14312450Sgabeblack@google.com    // if Python did not provide a valid ID, do it here
14412450Sgabeblack@google.com    if (_cpuId == -1 ) {
14512450Sgabeblack@google.com        _cpuId = cpuList.size();
14612450Sgabeblack@google.com    }
14712450Sgabeblack@google.com
14812450Sgabeblack@google.com    // add self to global list of CPUs
14912450Sgabeblack@google.com    cpuList.push_back(this);
15012450Sgabeblack@google.com
15112450Sgabeblack@google.com    DPRINTF(SyscallVerbose, "Constructing CPU with id %d, socket id %d\n",
15212450Sgabeblack@google.com                _cpuId, _socketId);
15312450Sgabeblack@google.com
15412450Sgabeblack@google.com    if (numThreads > maxThreadsPerCPU)
15512450Sgabeblack@google.com        maxThreadsPerCPU = numThreads;
15612450Sgabeblack@google.com
1574680Sgblack@eecs.umich.edu    // allocate per-thread instruction-based event queues
15812450Sgabeblack@google.com    comInstEventQueue = new EventQueue *[numThreads];
1594680Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
1604680Sgblack@eecs.umich.edu        comInstEventQueue[tid] =
16112450Sgabeblack@google.com            new EventQueue("instruction-based event queue");
16212450Sgabeblack@google.com
1634680Sgblack@eecs.umich.edu    //
16412450Sgabeblack@google.com    // set up instruction-count-based termination events, if any
16512450Sgabeblack@google.com    //
16612450Sgabeblack@google.com    if (p->max_insts_any_thread != 0) {
1674680Sgblack@eecs.umich.edu        const char *cause = "a thread reached the max instruction count";
16812450Sgabeblack@google.com        for (ThreadID tid = 0; tid < numThreads; ++tid)
16912450Sgabeblack@google.com            scheduleInstStop(tid, p->max_insts_any_thread, cause);
1704680Sgblack@eecs.umich.edu    }
17112450Sgabeblack@google.com
1724680Sgblack@eecs.umich.edu    // Set up instruction-count-based termination events for SimPoints
1734680Sgblack@eecs.umich.edu    // Typically, there are more than one action points.
17412450Sgabeblack@google.com    // Simulation.py is responsible to take the necessary actions upon
17512450Sgabeblack@google.com    // exitting the simulation loop.
1764680Sgblack@eecs.umich.edu    if (!p->simpoint_start_insts.empty()) {
17712450Sgabeblack@google.com        const char *cause = "simpoint starting point found";
1784680Sgblack@eecs.umich.edu        for (size_t i = 0; i < p->simpoint_start_insts.size(); ++i)
1794680Sgblack@eecs.umich.edu            scheduleInstStop(0, p->simpoint_start_insts[i], cause);
1804680Sgblack@eecs.umich.edu    }
18112450Sgabeblack@google.com
18212450Sgabeblack@google.com    if (p->max_insts_all_threads != 0) {
18312450Sgabeblack@google.com        const char *cause = "all threads reached the max instruction count";
18412450Sgabeblack@google.com
18512450Sgabeblack@google.com        // allocate & initialize shared downcounter: each event will
18612450Sgabeblack@google.com        // decrement this when triggered; simulation will terminate
18712450Sgabeblack@google.com        // when counter reaches 0
18812450Sgabeblack@google.com        int *counter = new int;
18912450Sgabeblack@google.com        *counter = numThreads;
19012450Sgabeblack@google.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
19112450Sgabeblack@google.com            Event *event = new CountedExitEvent(cause, *counter);
19212450Sgabeblack@google.com            comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads);
19312450Sgabeblack@google.com        }
19412450Sgabeblack@google.com    }
19512450Sgabeblack@google.com
19612450Sgabeblack@google.com    // allocate per-thread load-based event queues
19712450Sgabeblack@google.com    comLoadEventQueue = new EventQueue *[numThreads];
19812450Sgabeblack@google.com    for (ThreadID tid = 0; tid < numThreads; ++tid)
19912450Sgabeblack@google.com        comLoadEventQueue[tid] = new EventQueue("load-based event queue");
20012450Sgabeblack@google.com
20112450Sgabeblack@google.com    //
20212450Sgabeblack@google.com    // set up instruction-count-based termination events, if any
20312450Sgabeblack@google.com    //
20412450Sgabeblack@google.com    if (p->max_loads_any_thread != 0) {
20512450Sgabeblack@google.com        const char *cause = "a thread reached the max load count";
2064680Sgblack@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid)
2074680Sgblack@eecs.umich.edu            scheduleLoadStop(tid, p->max_loads_any_thread, cause);
20812450Sgabeblack@google.com    }
2094680Sgblack@eecs.umich.edu
21012450Sgabeblack@google.com    if (p->max_loads_all_threads != 0) {
21112450Sgabeblack@google.com        const char *cause = "all threads reached the max load count";
21212450Sgabeblack@google.com        // allocate & initialize shared downcounter: each event will
21312450Sgabeblack@google.com        // decrement this when triggered; simulation will terminate
21412450Sgabeblack@google.com        // when counter reaches 0
21512450Sgabeblack@google.com        int *counter = new int;
21612450Sgabeblack@google.com        *counter = numThreads;
21710289SAndreas.Sandberg@ARM.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
2184680Sgblack@eecs.umich.edu            Event *event = new CountedExitEvent(cause, *counter);
21912450Sgabeblack@google.com            comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads);
22012450Sgabeblack@google.com        }
2214680Sgblack@eecs.umich.edu    }
22212450Sgabeblack@google.com
22312450Sgabeblack@google.com    functionTracingEnabled = false;
22412450Sgabeblack@google.com    if (p->function_trace) {
22512450Sgabeblack@google.com        const string fname = csprintf("ftrace.%s", name());
22612450Sgabeblack@google.com        functionTraceStream = simout.findOrCreate(fname)->stream();
2274680Sgblack@eecs.umich.edu
2284680Sgblack@eecs.umich.edu        currentFunctionStart = currentFunctionEnd = 0;
2294680Sgblack@eecs.umich.edu        functionEntryTick = p->function_trace_start;
2304680Sgblack@eecs.umich.edu
2314680Sgblack@eecs.umich.edu        if (p->function_trace_start == 0) {
2324680Sgblack@eecs.umich.edu            functionTracingEnabled = true;
2334680Sgblack@eecs.umich.edu        } else {
2344680Sgblack@eecs.umich.edu            Event *event = new EventFunctionWrapper(
23512450Sgabeblack@google.com                [this]{ enableFunctionTrace(); }, name(), true);
2364680Sgblack@eecs.umich.edu            schedule(event, p->function_trace_start);
2374680Sgblack@eecs.umich.edu        }
23812450Sgabeblack@google.com    }
23912450Sgabeblack@google.com
24012450Sgabeblack@google.com    // The interrupts should always be present unless this CPU is
2414680Sgblack@eecs.umich.edu    // switched in later or in case it is a checker CPU
24212450Sgabeblack@google.com    if (!params()->switched_out && !is_checker) {
2434681Sgblack@eecs.umich.edu        fatal_if(interrupts.size() != numThreads,
24412450Sgabeblack@google.com                 "CPU %s has %i interrupt controllers, but is expecting one "
2454681Sgblack@eecs.umich.edu                 "per thread (%i)\n",
2464681Sgblack@eecs.umich.edu                 name(), interrupts.size(), numThreads);
2474681Sgblack@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; tid++)
2484681Sgblack@eecs.umich.edu            interrupts[tid]->setCPU(this);
24912450Sgabeblack@google.com    }
2504680Sgblack@eecs.umich.edu
25112450Sgabeblack@google.com    if (FullSystem) {
2524680Sgblack@eecs.umich.edu        if (params()->profile)
2534680Sgblack@eecs.umich.edu            profileEvent = new EventFunctionWrapper(
25412450Sgabeblack@google.com                [this]{ processProfileEvent(); },
25512450Sgabeblack@google.com                name());
2564680Sgblack@eecs.umich.edu    }
25712450Sgabeblack@google.com    tracer = params()->tracer;
25812450Sgabeblack@google.com
2594680Sgblack@eecs.umich.edu    if (params()->isa.size() != numThreads) {
2604680Sgblack@eecs.umich.edu        fatal("Number of ISAs (%i) assigned to the CPU does not equal number "
26112450Sgabeblack@google.com              "of threads (%i).\n", params()->isa.size(), numThreads);
26212450Sgabeblack@google.com    }
26310640Sgabeblack@google.com}
26412450Sgabeblack@google.com
26512450Sgabeblack@google.comvoid
26610640Sgabeblack@google.comBaseCPU::enableFunctionTrace()
26710640Sgabeblack@google.com{
2684680Sgblack@eecs.umich.edu    functionTracingEnabled = true;
26912450Sgabeblack@google.com}
2704680Sgblack@eecs.umich.edu
27112450Sgabeblack@google.comBaseCPU::~BaseCPU()
2724680Sgblack@eecs.umich.edu{
2734680Sgblack@eecs.umich.edu    delete profileEvent;
2744680Sgblack@eecs.umich.edu    delete[] comLoadEventQueue;
27512450Sgabeblack@google.com    delete[] comInstEventQueue;
2764680Sgblack@eecs.umich.edu}
27712450Sgabeblack@google.com
2784680Sgblack@eecs.umich.eduvoid
2794680Sgblack@eecs.umich.eduBaseCPU::armMonitor(ThreadID tid, Addr address)
2804680Sgblack@eecs.umich.edu{
2814680Sgblack@eecs.umich.edu    assert(tid < numThreads);
2824680Sgblack@eecs.umich.edu    AddressMonitor &monitor = addressMonitor[tid];
2834680Sgblack@eecs.umich.edu
2844680Sgblack@eecs.umich.edu    monitor.armed = true;
2854680Sgblack@eecs.umich.edu    monitor.vAddr = address;
2864680Sgblack@eecs.umich.edu    monitor.pAddr = 0x0;
2874680Sgblack@eecs.umich.edu    DPRINTF(Mwait,"[tid:%d] Armed monitor (vAddr=0x%lx)\n", tid, address);
2884680Sgblack@eecs.umich.edu}
28912450Sgabeblack@google.com
2904680Sgblack@eecs.umich.edubool
2914680Sgblack@eecs.umich.eduBaseCPU::mwait(ThreadID tid, PacketPtr pkt)
2924680Sgblack@eecs.umich.edu{
2934680Sgblack@eecs.umich.edu    assert(tid < numThreads);
29412450Sgabeblack@google.com    AddressMonitor &monitor = addressMonitor[tid];
2954680Sgblack@eecs.umich.edu
2964680Sgblack@eecs.umich.edu    if (!monitor.gotWakeup) {
2974680Sgblack@eecs.umich.edu        int block_size = cacheLineSize();
2985442Sgblack@eecs.umich.edu        uint64_t mask = ~((uint64_t)(block_size - 1));
2994680Sgblack@eecs.umich.edu
3004680Sgblack@eecs.umich.edu        assert(pkt->req->hasPaddr());
30112454Sgabeblack@google.com        monitor.pAddr = pkt->getAddr() & mask;
30212454Sgabeblack@google.com        monitor.waiting = true;
30312454Sgabeblack@google.com
30412454Sgabeblack@google.com        DPRINTF(Mwait,"[tid:%d] mwait called (vAddr=0x%lx, "
30512454Sgabeblack@google.com                "line's paddr=0x%lx)\n", tid, monitor.vAddr, monitor.pAddr);
30612454Sgabeblack@google.com        return true;
30712454Sgabeblack@google.com    } else {
3084680Sgblack@eecs.umich.edu        monitor.gotWakeup = false;
3094680Sgblack@eecs.umich.edu        return false;
31012450Sgabeblack@google.com    }
3114680Sgblack@eecs.umich.edu}
3124680Sgblack@eecs.umich.edu
3134680Sgblack@eecs.umich.eduvoid
3144680Sgblack@eecs.umich.eduBaseCPU::mwaitAtomic(ThreadID tid, ThreadContext *tc, TheISA::TLB *dtb)
3154680Sgblack@eecs.umich.edu{
3164680Sgblack@eecs.umich.edu    assert(tid < numThreads);
3174680Sgblack@eecs.umich.edu    AddressMonitor &monitor = addressMonitor[tid];
3184680Sgblack@eecs.umich.edu
3194680Sgblack@eecs.umich.edu    Request req;
3205442Sgblack@eecs.umich.edu    Addr addr = monitor.vAddr;
3214680Sgblack@eecs.umich.edu    int block_size = cacheLineSize();
3224680Sgblack@eecs.umich.edu    uint64_t mask = ~((uint64_t)(block_size - 1));
32312450Sgabeblack@google.com    int size = block_size;
3244680Sgblack@eecs.umich.edu
3254680Sgblack@eecs.umich.edu    //The address of the next line if it crosses a cache line boundary.
3264680Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(addr + size - 1, block_size);
32712450Sgabeblack@google.com
32812450Sgabeblack@google.com    if (secondAddr > addr)
3294680Sgblack@eecs.umich.edu        size = secondAddr - addr;
3304680Sgblack@eecs.umich.edu
3314680Sgblack@eecs.umich.edu    req.setVirt(0, addr, size, 0x0, dataMasterId(), tc->instAddr());
33212450Sgabeblack@google.com
3334680Sgblack@eecs.umich.edu    // translate to physical address
3344680Sgblack@eecs.umich.edu    Fault fault = dtb->translateAtomic(&req, tc, BaseTLB::Read);
3354680Sgblack@eecs.umich.edu    assert(fault == NoFault);
3364680Sgblack@eecs.umich.edu
3374680Sgblack@eecs.umich.edu    monitor.pAddr = req.getPaddr() & mask;
3384680Sgblack@eecs.umich.edu    monitor.waiting = true;
3394680Sgblack@eecs.umich.edu
3404680Sgblack@eecs.umich.edu    DPRINTF(Mwait,"[tid:%d] mwait called (vAddr=0x%lx, line's paddr=0x%lx)\n",
34112450Sgabeblack@google.com            tid, monitor.vAddr, monitor.pAddr);
34212450Sgabeblack@google.com}
3434680Sgblack@eecs.umich.edu
34412450Sgabeblack@google.comvoid
34512450Sgabeblack@google.comBaseCPU::init()
3464680Sgblack@eecs.umich.edu{
3474680Sgblack@eecs.umich.edu    if (!params()->switched_out) {
3484680Sgblack@eecs.umich.edu        registerThreadContexts();
3494680Sgblack@eecs.umich.edu
3504680Sgblack@eecs.umich.edu        verifyMemoryMode();
35112450Sgabeblack@google.com    }
3524680Sgblack@eecs.umich.edu}
3534680Sgblack@eecs.umich.edu
3544680Sgblack@eecs.umich.eduvoid
3554680Sgblack@eecs.umich.eduBaseCPU::startup()
35612450Sgabeblack@google.com{
3574680Sgblack@eecs.umich.edu    if (FullSystem) {
3584680Sgblack@eecs.umich.edu        if (!params()->switched_out && profileEvent)
3594680Sgblack@eecs.umich.edu            schedule(profileEvent, curTick());
3604680Sgblack@eecs.umich.edu    }
3614680Sgblack@eecs.umich.edu
3624680Sgblack@eecs.umich.edu    if (params()->progress_interval) {
3634680Sgblack@eecs.umich.edu        new CPUProgressEvent(this, params()->progress_interval);
3644680Sgblack@eecs.umich.edu    }
3654680Sgblack@eecs.umich.edu
3664680Sgblack@eecs.umich.edu    if (_switchedOut)
36712451Sgabeblack@google.com        ClockedObject::pwrState(Enums::PwrState::OFF);
36812451Sgabeblack@google.com
36912451Sgabeblack@google.com    // Assumption CPU start to operate instantaneously without any latency
37012451Sgabeblack@google.com    if (ClockedObject::pwrState() == Enums::PwrState::UNDEFINED)
37112451Sgabeblack@google.com        ClockedObject::pwrState(Enums::PwrState::ON);
37212451Sgabeblack@google.com
37312451Sgabeblack@google.com}
37412451Sgabeblack@google.com
37512451Sgabeblack@google.comProbePoints::PMUUPtr
37612451Sgabeblack@google.comBaseCPU::pmuProbePoint(const char *name)
37712451Sgabeblack@google.com{
37812451Sgabeblack@google.com    ProbePoints::PMUUPtr ptr;
37912451Sgabeblack@google.com    ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
38012451Sgabeblack@google.com
38112451Sgabeblack@google.com    return ptr;
38212451Sgabeblack@google.com}
38312451Sgabeblack@google.com
38412451Sgabeblack@google.comvoid
38512451Sgabeblack@google.comBaseCPU::regProbePoints()
38612451Sgabeblack@google.com{
38712451Sgabeblack@google.com    ppCycles = pmuProbePoint("Cycles");
38812451Sgabeblack@google.com
38912451Sgabeblack@google.com    ppRetiredInsts = pmuProbePoint("RetiredInsts");
39012451Sgabeblack@google.com    ppRetiredLoads = pmuProbePoint("RetiredLoads");
39112451Sgabeblack@google.com    ppRetiredStores = pmuProbePoint("RetiredStores");
39212451Sgabeblack@google.com    ppRetiredBranches = pmuProbePoint("RetiredBranches");
39312451Sgabeblack@google.com}
39412451Sgabeblack@google.com
39512451Sgabeblack@google.comvoid
39612451Sgabeblack@google.comBaseCPU::probeInstCommit(const StaticInstPtr &inst)
39712451Sgabeblack@google.com{
39812451Sgabeblack@google.com    if (!inst->isMicroop() || inst->isLastMicroop())
39912451Sgabeblack@google.com        ppRetiredInsts->notify(1);
40012451Sgabeblack@google.com
40112451Sgabeblack@google.com
40212451Sgabeblack@google.com    if (inst->isLoad())
40312451Sgabeblack@google.com        ppRetiredLoads->notify(1);
40412454Sgabeblack@google.com
40512454Sgabeblack@google.com    if (inst->isStore())
40612453Sgabeblack@google.com        ppRetiredStores->notify(1);
40712453Sgabeblack@google.com
40812453Sgabeblack@google.com    if (inst->isControl())
40912453Sgabeblack@google.com        ppRetiredBranches->notify(1);
41012453Sgabeblack@google.com}
41112453Sgabeblack@google.com
41212453Sgabeblack@google.comvoid
41312453Sgabeblack@google.comBaseCPU::regStats()
41412453Sgabeblack@google.com{
41512453Sgabeblack@google.com    MemObject::regStats();
41612453Sgabeblack@google.com
41712453Sgabeblack@google.com    using namespace Stats;
41812453Sgabeblack@google.com
41912625Sgabeblack@google.com    numCycles
42012625Sgabeblack@google.com        .name(name() + ".numCycles")
42112625Sgabeblack@google.com        .desc("number of cpu cycles simulated")
42212631Sgabeblack@google.com        ;
42312625Sgabeblack@google.com
42412631Sgabeblack@google.com    numWorkItemsStarted
42512625Sgabeblack@google.com        .name(name() + ".numWorkItemsStarted")
42612625Sgabeblack@google.com        .desc("number of work items this cpu started")
42712625Sgabeblack@google.com        ;
42812625Sgabeblack@google.com
42912625Sgabeblack@google.com    numWorkItemsCompleted
43012625Sgabeblack@google.com        .name(name() + ".numWorkItemsCompleted")
43112625Sgabeblack@google.com        .desc("number of work items this cpu completed")
43212625Sgabeblack@google.com        ;
43312625Sgabeblack@google.com
43412625Sgabeblack@google.com    int size = threadContexts.size();
43512631Sgabeblack@google.com    if (size > 1) {
43612625Sgabeblack@google.com        for (int i = 0; i < size; ++i) {
43712625Sgabeblack@google.com            stringstream namestr;
43812625Sgabeblack@google.com            ccprintf(namestr, "%s.ctx%d", name(), i);
43912625Sgabeblack@google.com            threadContexts[i]->regStats(namestr.str());
44012625Sgabeblack@google.com        }
44112625Sgabeblack@google.com    } else if (size == 1)
44212625Sgabeblack@google.com        threadContexts[0]->regStats(name());
44312631Sgabeblack@google.com}
44412625Sgabeblack@google.com
44512625Sgabeblack@google.comBaseMasterPort &
44612625Sgabeblack@google.comBaseCPU::getMasterPort(const string &if_name, PortID idx)
44712625Sgabeblack@google.com{
44812625Sgabeblack@google.com    // Get the right port based on name. This applies to all the
44912625Sgabeblack@google.com    // subclasses of the base CPU and relies on their implementation
45012625Sgabeblack@google.com    // of getDataPort and getInstPort. In all cases there methods
45112625Sgabeblack@google.com    // return a MasterPort pointer.
45212625Sgabeblack@google.com    if (if_name == "dcache_port")
45312625Sgabeblack@google.com        return getDataPort();
45412625Sgabeblack@google.com    else if (if_name == "icache_port")
45512625Sgabeblack@google.com        return getInstPort();
45612625Sgabeblack@google.com    else
45712625Sgabeblack@google.com        return MemObject::getMasterPort(if_name, idx);
45812625Sgabeblack@google.com}
45912625Sgabeblack@google.com
46012625Sgabeblack@google.comvoid
4614680Sgblack@eecs.umich.eduBaseCPU::registerThreadContexts()
462{
463    assert(system->multiThread || numThreads == 1);
464
465    ThreadID size = threadContexts.size();
466    for (ThreadID tid = 0; tid < size; ++tid) {
467        ThreadContext *tc = threadContexts[tid];
468
469        if (system->multiThread) {
470            tc->setContextId(system->registerThreadContext(tc));
471        } else {
472            tc->setContextId(system->registerThreadContext(tc, _cpuId));
473        }
474
475        if (!FullSystem)
476            tc->getProcessPtr()->assignThreadContext(tc->contextId());
477    }
478}
479
480void
481BaseCPU::deschedulePowerGatingEvent()
482{
483    if (enterPwrGatingEvent.scheduled()){
484        deschedule(enterPwrGatingEvent);
485    }
486}
487
488void
489BaseCPU::schedulePowerGatingEvent()
490{
491    for (auto tc : threadContexts) {
492        if (tc->status() == ThreadContext::Active)
493            return;
494    }
495
496    if (ClockedObject::pwrState() == Enums::PwrState::CLK_GATED) {
497        assert(!enterPwrGatingEvent.scheduled());
498        // Schedule a power gating event when clock gated for the specified
499        // amount of time
500        schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
501    }
502}
503
504int
505BaseCPU::findContext(ThreadContext *tc)
506{
507    ThreadID size = threadContexts.size();
508    for (ThreadID tid = 0; tid < size; ++tid) {
509        if (tc == threadContexts[tid])
510            return tid;
511    }
512    return 0;
513}
514
515void
516BaseCPU::activateContext(ThreadID thread_num)
517{
518    // Squash enter power gating event while cpu gets activated
519    if (enterPwrGatingEvent.scheduled())
520        deschedule(enterPwrGatingEvent);
521
522    // For any active thread running, update CPU power state to active (ON)
523    ClockedObject::pwrState(Enums::PwrState::ON);
524}
525
526void
527BaseCPU::suspendContext(ThreadID thread_num)
528{
529    // Check if all threads are suspended
530    for (auto t : threadContexts) {
531        if (t->status() != ThreadContext::Suspended) {
532            return;
533        }
534    }
535
536    // All CPU threads suspended, enter lower power state for the CPU
537    ClockedObject::pwrState(Enums::PwrState::CLK_GATED);
538
539    //Schedule power gating event when clock gated for a configurable cycles
540    schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
541}
542
543void
544BaseCPU::enterPwrGating(void)
545{
546    ClockedObject::pwrState(Enums::PwrState::OFF);
547}
548
549void
550BaseCPU::switchOut()
551{
552    assert(!_switchedOut);
553    _switchedOut = true;
554    if (profileEvent && profileEvent->scheduled())
555        deschedule(profileEvent);
556
557    // Flush all TLBs in the CPU to avoid having stale translations if
558    // it gets switched in later.
559    flushTLBs();
560
561    // Go to the power gating state
562    ClockedObject::pwrState(Enums::PwrState::OFF);
563}
564
565void
566BaseCPU::takeOverFrom(BaseCPU *oldCPU)
567{
568    assert(threadContexts.size() == oldCPU->threadContexts.size());
569    assert(_cpuId == oldCPU->cpuId());
570    assert(_switchedOut);
571    assert(oldCPU != this);
572    _pid = oldCPU->getPid();
573    _taskId = oldCPU->taskId();
574    // Take over the power state of the switchedOut CPU
575    ClockedObject::pwrState(oldCPU->pwrState());
576    _switchedOut = false;
577
578    ThreadID size = threadContexts.size();
579    for (ThreadID i = 0; i < size; ++i) {
580        ThreadContext *newTC = threadContexts[i];
581        ThreadContext *oldTC = oldCPU->threadContexts[i];
582
583        newTC->takeOverFrom(oldTC);
584
585        CpuEvent::replaceThreadContext(oldTC, newTC);
586
587        assert(newTC->contextId() == oldTC->contextId());
588        assert(newTC->threadId() == oldTC->threadId());
589        system->replaceThreadContext(newTC, newTC->contextId());
590
591        /* This code no longer works since the zero register (e.g.,
592         * r31 on Alpha) doesn't necessarily contain zero at this
593         * point.
594           if (DTRACE(Context))
595            ThreadContext::compare(oldTC, newTC);
596        */
597
598        BaseMasterPort *old_itb_port = oldTC->getITBPtr()->getMasterPort();
599        BaseMasterPort *old_dtb_port = oldTC->getDTBPtr()->getMasterPort();
600        BaseMasterPort *new_itb_port = newTC->getITBPtr()->getMasterPort();
601        BaseMasterPort *new_dtb_port = newTC->getDTBPtr()->getMasterPort();
602
603        // Move over any table walker ports if they exist
604        if (new_itb_port) {
605            assert(!new_itb_port->isConnected());
606            assert(old_itb_port);
607            assert(old_itb_port->isConnected());
608            BaseSlavePort &slavePort = old_itb_port->getSlavePort();
609            old_itb_port->unbind();
610            new_itb_port->bind(slavePort);
611        }
612        if (new_dtb_port) {
613            assert(!new_dtb_port->isConnected());
614            assert(old_dtb_port);
615            assert(old_dtb_port->isConnected());
616            BaseSlavePort &slavePort = old_dtb_port->getSlavePort();
617            old_dtb_port->unbind();
618            new_dtb_port->bind(slavePort);
619        }
620        newTC->getITBPtr()->takeOverFrom(oldTC->getITBPtr());
621        newTC->getDTBPtr()->takeOverFrom(oldTC->getDTBPtr());
622
623        // Checker whether or not we have to transfer CheckerCPU
624        // objects over in the switch
625        CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr();
626        CheckerCPU *newChecker = newTC->getCheckerCpuPtr();
627        if (oldChecker && newChecker) {
628            BaseMasterPort *old_checker_itb_port =
629                oldChecker->getITBPtr()->getMasterPort();
630            BaseMasterPort *old_checker_dtb_port =
631                oldChecker->getDTBPtr()->getMasterPort();
632            BaseMasterPort *new_checker_itb_port =
633                newChecker->getITBPtr()->getMasterPort();
634            BaseMasterPort *new_checker_dtb_port =
635                newChecker->getDTBPtr()->getMasterPort();
636
637            newChecker->getITBPtr()->takeOverFrom(oldChecker->getITBPtr());
638            newChecker->getDTBPtr()->takeOverFrom(oldChecker->getDTBPtr());
639
640            // Move over any table walker ports if they exist for checker
641            if (new_checker_itb_port) {
642                assert(!new_checker_itb_port->isConnected());
643                assert(old_checker_itb_port);
644                assert(old_checker_itb_port->isConnected());
645                BaseSlavePort &slavePort =
646                    old_checker_itb_port->getSlavePort();
647                old_checker_itb_port->unbind();
648                new_checker_itb_port->bind(slavePort);
649            }
650            if (new_checker_dtb_port) {
651                assert(!new_checker_dtb_port->isConnected());
652                assert(old_checker_dtb_port);
653                assert(old_checker_dtb_port->isConnected());
654                BaseSlavePort &slavePort =
655                    old_checker_dtb_port->getSlavePort();
656                old_checker_dtb_port->unbind();
657                new_checker_dtb_port->bind(slavePort);
658            }
659        }
660    }
661
662    interrupts = oldCPU->interrupts;
663    for (ThreadID tid = 0; tid < numThreads; tid++) {
664        interrupts[tid]->setCPU(this);
665    }
666    oldCPU->interrupts.clear();
667
668    if (FullSystem) {
669        for (ThreadID i = 0; i < size; ++i)
670            threadContexts[i]->profileClear();
671
672        if (profileEvent)
673            schedule(profileEvent, curTick());
674    }
675
676    // All CPUs have an instruction and a data port, and the new CPU's
677    // ports are dangling while the old CPU has its ports connected
678    // already. Unbind the old CPU and then bind the ports of the one
679    // we are switching to.
680    assert(!getInstPort().isConnected());
681    assert(oldCPU->getInstPort().isConnected());
682    BaseSlavePort &inst_peer_port = oldCPU->getInstPort().getSlavePort();
683    oldCPU->getInstPort().unbind();
684    getInstPort().bind(inst_peer_port);
685
686    assert(!getDataPort().isConnected());
687    assert(oldCPU->getDataPort().isConnected());
688    BaseSlavePort &data_peer_port = oldCPU->getDataPort().getSlavePort();
689    oldCPU->getDataPort().unbind();
690    getDataPort().bind(data_peer_port);
691}
692
693void
694BaseCPU::flushTLBs()
695{
696    for (ThreadID i = 0; i < threadContexts.size(); ++i) {
697        ThreadContext &tc(*threadContexts[i]);
698        CheckerCPU *checker(tc.getCheckerCpuPtr());
699
700        tc.getITBPtr()->flushAll();
701        tc.getDTBPtr()->flushAll();
702        if (checker) {
703            checker->getITBPtr()->flushAll();
704            checker->getDTBPtr()->flushAll();
705        }
706    }
707}
708
709void
710BaseCPU::processProfileEvent()
711{
712    ThreadID size = threadContexts.size();
713
714    for (ThreadID i = 0; i < size; ++i)
715        threadContexts[i]->profileSample();
716
717    schedule(profileEvent, curTick() + params()->profile);
718}
719
720void
721BaseCPU::serialize(CheckpointOut &cp) const
722{
723    SERIALIZE_SCALAR(instCnt);
724
725    if (!_switchedOut) {
726        /* Unlike _pid, _taskId is not serialized, as they are dynamically
727         * assigned unique ids that are only meaningful for the duration of
728         * a specific run. We will need to serialize the entire taskMap in
729         * system. */
730        SERIALIZE_SCALAR(_pid);
731
732        // Serialize the threads, this is done by the CPU implementation.
733        for (ThreadID i = 0; i < numThreads; ++i) {
734            ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
735            interrupts[i]->serialize(cp);
736            serializeThread(cp, i);
737        }
738    }
739}
740
741void
742BaseCPU::unserialize(CheckpointIn &cp)
743{
744    UNSERIALIZE_SCALAR(instCnt);
745
746    if (!_switchedOut) {
747        UNSERIALIZE_SCALAR(_pid);
748
749        // Unserialize the threads, this is done by the CPU implementation.
750        for (ThreadID i = 0; i < numThreads; ++i) {
751            ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
752            interrupts[i]->unserialize(cp);
753            unserializeThread(cp, i);
754        }
755    }
756}
757
758void
759BaseCPU::scheduleInstStop(ThreadID tid, Counter insts, const char *cause)
760{
761    const Tick now(comInstEventQueue[tid]->getCurTick());
762    Event *event(new LocalSimLoopExitEvent(cause, 0));
763
764    comInstEventQueue[tid]->schedule(event, now + insts);
765}
766
767uint64_t
768BaseCPU::getCurrentInstCount(ThreadID tid)
769{
770    return Tick(comInstEventQueue[tid]->getCurTick());
771}
772
773AddressMonitor::AddressMonitor() {
774    armed = false;
775    waiting = false;
776    gotWakeup = false;
777}
778
779bool AddressMonitor::doMonitor(PacketPtr pkt) {
780    assert(pkt->req->hasPaddr());
781    if (armed && waiting) {
782        if (pAddr == pkt->getAddr()) {
783            DPRINTF(Mwait,"pAddr=0x%lx invalidated: waking up core\n",
784                    pkt->getAddr());
785            waiting = false;
786            return true;
787        }
788    }
789    return false;
790}
791
792void
793BaseCPU::scheduleLoadStop(ThreadID tid, Counter loads, const char *cause)
794{
795    const Tick now(comLoadEventQueue[tid]->getCurTick());
796    Event *event(new LocalSimLoopExitEvent(cause, 0));
797
798    comLoadEventQueue[tid]->schedule(event, now + loads);
799}
800
801
802void
803BaseCPU::traceFunctionsInternal(Addr pc)
804{
805    if (!debugSymbolTable)
806        return;
807
808    // if pc enters different function, print new function symbol and
809    // update saved range.  Otherwise do nothing.
810    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
811        string sym_str;
812        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
813                                                         currentFunctionStart,
814                                                         currentFunctionEnd);
815
816        if (!found) {
817            // no symbol found: use addr as label
818            sym_str = csprintf("0x%x", pc);
819            currentFunctionStart = pc;
820            currentFunctionEnd = pc + 1;
821        }
822
823        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
824                 curTick() - functionEntryTick, curTick(), sym_str);
825        functionEntryTick = curTick();
826    }
827}
828
829bool
830BaseCPU::waitForRemoteGDB() const
831{
832    return params()->wait_for_remote_gdb;
833}
834