base.cc revision 2356
1955SN/A/*
2955SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A */
282665Ssaidi@eecs.umich.edu
294762Snate@binkert.org#include <iostream>
30955SN/A#include <string>
315522Snate@binkert.org#include <sstream>
324762Snate@binkert.org
335522Snate@binkert.org#include "base/cprintf.hh"
34955SN/A#include "base/loader/symtab.hh"
355522Snate@binkert.org#include "base/misc.hh"
36955SN/A#include "base/output.hh"
375522Snate@binkert.org#include "cpu/base.hh"
384202Sbinkertn@umich.edu#include "cpu/exec_context.hh"
395742Snate@binkert.org#include "cpu/profile.hh"
40955SN/A#include "cpu/sampler/sampler.hh"
414381Sbinkertn@umich.edu#include "sim/param.hh"
424381Sbinkertn@umich.edu#include "sim/process.hh"
43955SN/A#include "sim/sim_events.hh"
44955SN/A#include "sim/system.hh"
45955SN/A
464202Sbinkertn@umich.edu#include "base/trace.hh"
47955SN/A
484382Sbinkertn@umich.eduusing namespace std;
494382Sbinkertn@umich.edu
504382Sbinkertn@umich.eduvector<BaseCPU *> BaseCPU::cpuList;
515863Snate@binkert.org
525517Snate@binkert.org// This variable reflects the max number of threads in any CPU.  Be
534762Snate@binkert.org// careful to only use it once all the CPUs that you care about have
544762Snate@binkert.org// been initialized
554762Snate@binkert.orgint maxThreadsPerCPU = 1;
564762Snate@binkert.org
574762Snate@binkert.orgvoid
584762Snate@binkert.orgCPUProgressEvent::process()
594762Snate@binkert.org{
604762Snate@binkert.org#ifndef NDEBUG
614762Snate@binkert.org    Counter temp = cpu->totalInstructions();
624762Snate@binkert.org    double ipc = double(temp - lastNumInst) / (interval / cpu->cycles(1));
635522Snate@binkert.org    DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n",
645604Snate@binkert.org             cpu->name(), temp - lastNumInst, ipc);
655604Snate@binkert.org    ipc = 0.0;
665604Snate@binkert.org    lastNumInst = temp;
674762Snate@binkert.org    schedule(curTick + interval);
684762Snate@binkert.org#endif
694762Snate@binkert.org}
705522Snate@binkert.org
715522Snate@binkert.orgconst char *
725522Snate@binkert.orgCPUProgressEvent::description()
735522Snate@binkert.org{
745604Snate@binkert.org    return "CPU Progress event";
755604Snate@binkert.org}
764762Snate@binkert.org
774762Snate@binkert.org#if FULL_SYSTEM
784762Snate@binkert.orgBaseCPU::BaseCPU(Params *p)
794762Snate@binkert.org    : SimObject(p->name), clock(p->clock), checkInterrupts(true),
805522Snate@binkert.org      params(p), number_of_threads(p->numberOfThreads), system(p->system)
814762Snate@binkert.org#else
824762Snate@binkert.orgBaseCPU::BaseCPU(Params *p)
835604Snate@binkert.org    : SimObject(p->name), clock(p->clock), params(p),
845604Snate@binkert.org      number_of_threads(p->numberOfThreads)
855604Snate@binkert.org#endif
865604Snate@binkert.org{
875604Snate@binkert.org    DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this);
885604Snate@binkert.org
894762Snate@binkert.org    // add self to global list of CPUs
904762Snate@binkert.org    cpuList.push_back(this);
914762Snate@binkert.org
924762Snate@binkert.org    DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n",
935604Snate@binkert.org            this);
944762Snate@binkert.org
955522Snate@binkert.org    if (number_of_threads > maxThreadsPerCPU)
965522Snate@binkert.org        maxThreadsPerCPU = number_of_threads;
975522Snate@binkert.org
984762Snate@binkert.org    // allocate per-thread instruction-based event queues
994382Sbinkertn@umich.edu    comInstEventQueue = new EventQueue *[number_of_threads];
1004762Snate@binkert.org    for (int i = 0; i < number_of_threads; ++i)
1014382Sbinkertn@umich.edu        comInstEventQueue[i] = new EventQueue("instruction-based event queue");
1025522Snate@binkert.org
1034381Sbinkertn@umich.edu    //
1045522Snate@binkert.org    // set up instruction-count-based termination events, if any
1054762Snate@binkert.org    //
1064762Snate@binkert.org    if (p->max_insts_any_thread != 0)
1074762Snate@binkert.org        for (int i = 0; i < number_of_threads; ++i)
1085522Snate@binkert.org            new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
1095522Snate@binkert.org                "a thread reached the max instruction count");
1105522Snate@binkert.org
1115522Snate@binkert.org    if (p->max_insts_all_threads != 0) {
1125522Snate@binkert.org        // allocate & initialize shared downcounter: each event will
1135522Snate@binkert.org        // decrement this when triggered; simulation will terminate
1145522Snate@binkert.org        // when counter reaches 0
1155522Snate@binkert.org        int *counter = new int;
1165522Snate@binkert.org        *counter = number_of_threads;
1174762Snate@binkert.org        for (int i = 0; i < number_of_threads; ++i)
1184762Snate@binkert.org            new CountedExitEvent(comInstEventQueue[i],
1194762Snate@binkert.org                "all threads reached the max instruction count",
1204762Snate@binkert.org                p->max_insts_all_threads, *counter);
1214762Snate@binkert.org    }
1224762Snate@binkert.org
1234762Snate@binkert.org    // allocate per-thread load-based event queues
1244762Snate@binkert.org    comLoadEventQueue = new EventQueue *[number_of_threads];
1254762Snate@binkert.org    for (int i = 0; i < number_of_threads; ++i)
1264762Snate@binkert.org        comLoadEventQueue[i] = new EventQueue("load-based event queue");
1274762Snate@binkert.org
1284762Snate@binkert.org    //
1294762Snate@binkert.org    // set up instruction-count-based termination events, if any
1304762Snate@binkert.org    //
1314762Snate@binkert.org    if (p->max_loads_any_thread != 0)
1324762Snate@binkert.org        for (int i = 0; i < number_of_threads; ++i)
1334762Snate@binkert.org            new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
1344762Snate@binkert.org                "a thread reached the max load count");
1354762Snate@binkert.org
1364762Snate@binkert.org    if (p->max_loads_all_threads != 0) {
1374762Snate@binkert.org        // allocate & initialize shared downcounter: each event will
1384762Snate@binkert.org        // decrement this when triggered; simulation will terminate
1394762Snate@binkert.org        // when counter reaches 0
1404762Snate@binkert.org        int *counter = new int;
1414762Snate@binkert.org        *counter = number_of_threads;
1424762Snate@binkert.org        for (int i = 0; i < number_of_threads; ++i)
1434762Snate@binkert.org            new CountedExitEvent(comLoadEventQueue[i],
1444762Snate@binkert.org                "all threads reached the max load count",
1454762Snate@binkert.org                p->max_loads_all_threads, *counter);
1464762Snate@binkert.org    }
1474762Snate@binkert.org
1484762Snate@binkert.org#if FULL_SYSTEM
1494762Snate@binkert.org    memset(interrupts, 0, sizeof(interrupts));
1504762Snate@binkert.org    intstatus = 0;
1514762Snate@binkert.org#endif
152955SN/A
1535584Snate@binkert.org    functionTracingEnabled = false;
1545584Snate@binkert.org    if (p->functionTrace) {
1555584Snate@binkert.org        functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
1565584Snate@binkert.org        currentFunctionStart = currentFunctionEnd = 0;
1575584Snate@binkert.org        functionEntryTick = p->functionTraceStart;
1585584Snate@binkert.org
1595584Snate@binkert.org        if (p->functionTraceStart == 0) {
1605584Snate@binkert.org            functionTracingEnabled = true;
1615584Snate@binkert.org        } else {
1625584Snate@binkert.org            Event *e =
1635584Snate@binkert.org                new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
1645584Snate@binkert.org                                                                         true);
1655584Snate@binkert.org            e->schedule(p->functionTraceStart);
1664382Sbinkertn@umich.edu        }
1674202Sbinkertn@umich.edu    }
1685522Snate@binkert.org#if FULL_SYSTEM
1694382Sbinkertn@umich.edu    profileEvent = NULL;
1704382Sbinkertn@umich.edu    if (params->profile)
1714382Sbinkertn@umich.edu        profileEvent = new ProfileEvent(this, params->profile);
1725584Snate@binkert.org#endif
1734382Sbinkertn@umich.edu}
1744382Sbinkertn@umich.edu
1754382Sbinkertn@umich.eduBaseCPU::Params::Params()
1765192Ssaidi@eecs.umich.edu{
1775192Ssaidi@eecs.umich.edu#if FULL_SYSTEM
1785799Snate@binkert.org    profile = false;
1795799Snate@binkert.org#endif
1805799Snate@binkert.org    checker = NULL;
1815192Ssaidi@eecs.umich.edu}
1825799Snate@binkert.org
1835192Ssaidi@eecs.umich.eduvoid
1845799Snate@binkert.orgBaseCPU::enableFunctionTrace()
1855799Snate@binkert.org{
1865192Ssaidi@eecs.umich.edu    functionTracingEnabled = true;
1875192Ssaidi@eecs.umich.edu}
1885192Ssaidi@eecs.umich.edu
1895192Ssaidi@eecs.umich.eduBaseCPU::~BaseCPU()
1905799Snate@binkert.org{
1915192Ssaidi@eecs.umich.edu}
1925799Snate@binkert.org
1935192Ssaidi@eecs.umich.eduvoid
1945192Ssaidi@eecs.umich.eduBaseCPU::init()
1955192Ssaidi@eecs.umich.edu{
1965799Snate@binkert.org    if (!params->deferRegistration)
1975192Ssaidi@eecs.umich.edu        registerExecContexts();
1985192Ssaidi@eecs.umich.edu}
1995192Ssaidi@eecs.umich.edu
2005192Ssaidi@eecs.umich.eduvoid
2015192Ssaidi@eecs.umich.eduBaseCPU::startup()
2025192Ssaidi@eecs.umich.edu{
2034382Sbinkertn@umich.edu#if FULL_SYSTEM
2044382Sbinkertn@umich.edu    if (!params->deferRegistration && profileEvent)
2054382Sbinkertn@umich.edu        profileEvent->schedule(curTick);
2062667Sstever@eecs.umich.edu#endif
2072667Sstever@eecs.umich.edu
2082667Sstever@eecs.umich.edu    if (params->progress_interval) {
2092667Sstever@eecs.umich.edu        new CPUProgressEvent(&mainEventQueue, params->progress_interval,
2102667Sstever@eecs.umich.edu                             this);
2112667Sstever@eecs.umich.edu    }
2125742Snate@binkert.org}
2135742Snate@binkert.org
2145742Snate@binkert.org
2152037SN/Avoid
2162037SN/ABaseCPU::regStats()
2172037SN/A{
2185793Snate@binkert.org    using namespace Stats;
2195793Snate@binkert.org
2205793Snate@binkert.org    numCycles
2215793Snate@binkert.org        .name(name() + ".numCycles")
2225793Snate@binkert.org        .desc("number of cpu cycles simulated")
2234382Sbinkertn@umich.edu        ;
2244762Snate@binkert.org
2255344Sstever@gmail.com    int size = execContexts.size();
2264382Sbinkertn@umich.edu    if (size > 1) {
2275341Sstever@gmail.com        for (int i = 0; i < size; ++i) {
2285742Snate@binkert.org            stringstream namestr;
2295742Snate@binkert.org            ccprintf(namestr, "%s.ctx%d", name(), i);
2305742Snate@binkert.org            execContexts[i]->regStats(namestr.str());
2315742Snate@binkert.org        }
2325742Snate@binkert.org    } else if (size == 1)
2334762Snate@binkert.org        execContexts[0]->regStats(name());
2345742Snate@binkert.org
2355742Snate@binkert.org#if FULL_SYSTEM
2365742Snate@binkert.org#endif
2375742Snate@binkert.org}
2385742Snate@binkert.org
2395742Snate@binkert.org
2405742Snate@binkert.orgvoid
2415341Sstever@gmail.comBaseCPU::registerExecContexts()
2425742Snate@binkert.org{
2435341Sstever@gmail.com    for (int i = 0; i < execContexts.size(); ++i) {
2444773Snate@binkert.org        ExecContext *xc = execContexts[i];
2455863Snate@binkert.org
2461858SN/A        if (xc->status() == ExecContext::Suspended) {
2471085SN/A#if FULL_SYSTEM
2484382Sbinkertn@umich.edu            int id = params->cpu_id;
2494382Sbinkertn@umich.edu            if (id != -1)
2504762Snate@binkert.org                id += i;
2514762Snate@binkert.org
2524762Snate@binkert.org        xc->setCpuId(system->registerExecContext(xc, id));
2535517Snate@binkert.org#else
2545517Snate@binkert.org        xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc));
2555517Snate@binkert.org#endif
2565517Snate@binkert.org        }
2575517Snate@binkert.org    }
2585517Snate@binkert.org}
2595517Snate@binkert.org
2605517Snate@binkert.org
2615517Snate@binkert.orgvoid
2625517Snate@binkert.orgBaseCPU::switchOut(Sampler *sampler)
2635517Snate@binkert.org{
2645517Snate@binkert.org    panic("This CPU doesn't support sampling!");
2655517Snate@binkert.org}
2665517Snate@binkert.org
2675517Snate@binkert.orgvoid
2685517Snate@binkert.orgBaseCPU::takeOverFrom(BaseCPU *oldCPU)
2695517Snate@binkert.org{
2705798Snate@binkert.org    assert(execContexts.size() == oldCPU->execContexts.size());
2715517Snate@binkert.org
2725517Snate@binkert.org    for (int i = 0; i < execContexts.size(); ++i) {
2735517Snate@binkert.org        ExecContext *newXC = execContexts[i];
2745517Snate@binkert.org        ExecContext *oldXC = oldCPU->execContexts[i];
2755517Snate@binkert.org
2765517Snate@binkert.org        newXC->takeOverFrom(oldXC);
2775517Snate@binkert.org        assert(newXC->readCpuId() == oldXC->readCpuId());
2785517Snate@binkert.org#if FULL_SYSTEM
2795517Snate@binkert.org        system->replaceExecContext(newXC, newXC->readCpuId());
2805517Snate@binkert.org#else
2815517Snate@binkert.org        assert(newXC->getProcessPtr() == oldXC->getProcessPtr());
2825517Snate@binkert.org        newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId());
2835517Snate@binkert.org#endif
2845517Snate@binkert.org    }
2855517Snate@binkert.org
2865517Snate@binkert.org#if FULL_SYSTEM
2875517Snate@binkert.org    for (int i = 0; i < TheISA::NumInterruptLevels; ++i)
2885517Snate@binkert.org        interrupts[i] = oldCPU->interrupts[i];
2895517Snate@binkert.org    intstatus = oldCPU->intstatus;
2905517Snate@binkert.org
2915517Snate@binkert.org    for (int i = 0; i < execContexts.size(); ++i)
2925517Snate@binkert.org        execContexts[i]->profileClear();
2935517Snate@binkert.org
2945798Snate@binkert.org    if (profileEvent)
2955798Snate@binkert.org        profileEvent->schedule(curTick);
2965517Snate@binkert.org#endif
2975517Snate@binkert.org}
2985517Snate@binkert.org
2995517Snate@binkert.org
3005517Snate@binkert.org#if FULL_SYSTEM
3015517Snate@binkert.orgBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
3025517Snate@binkert.org    : Event(&mainEventQueue), cpu(_cpu), interval(_interval)
3035517Snate@binkert.org{ }
3045517Snate@binkert.org
3055517Snate@binkert.orgvoid
3065517Snate@binkert.orgBaseCPU::ProfileEvent::process()
3075517Snate@binkert.org{
3085517Snate@binkert.org    for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) {
3095522Snate@binkert.org        ExecContext *xc = cpu->execContexts[i];
3105517Snate@binkert.org        xc->profileSample();
3115517Snate@binkert.org    }
3125517Snate@binkert.org
3135517Snate@binkert.org    schedule(curTick + interval);
3144762Snate@binkert.org}
3155517Snate@binkert.org
3165517Snate@binkert.orgvoid
3174762Snate@binkert.orgBaseCPU::post_interrupt(int int_num, int index)
3185517Snate@binkert.org{
3194762Snate@binkert.org    DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
3205517Snate@binkert.org
3215517Snate@binkert.org    if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
3225517Snate@binkert.org        panic("int_num out of bounds\n");
3235517Snate@binkert.org
3245517Snate@binkert.org    if (index < 0 || index >= sizeof(uint64_t) * 8)
3255517Snate@binkert.org        panic("int_num out of bounds\n");
3265517Snate@binkert.org
3275517Snate@binkert.org    checkInterrupts = true;
3285517Snate@binkert.org    interrupts[int_num] |= 1 << index;
3295517Snate@binkert.org    intstatus |= (ULL(1) << int_num);
3305517Snate@binkert.org}
3315517Snate@binkert.org
3325517Snate@binkert.orgvoid
3335517Snate@binkert.orgBaseCPU::clear_interrupt(int int_num, int index)
3345517Snate@binkert.org{
3355517Snate@binkert.org    DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
3365517Snate@binkert.org
3375517Snate@binkert.org    if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
3385517Snate@binkert.org        panic("int_num out of bounds\n");
3395517Snate@binkert.org
3405517Snate@binkert.org    if (index < 0 || index >= sizeof(uint64_t) * 8)
3415517Snate@binkert.org        panic("int_num out of bounds\n");
3425517Snate@binkert.org
3434762Snate@binkert.org    interrupts[int_num] &= ~(1 << index);
3444762Snate@binkert.org    if (interrupts[int_num] == 0)
3454762Snate@binkert.org        intstatus &= ~(ULL(1) << int_num);
3464762Snate@binkert.org}
3474762Snate@binkert.org
3484762Snate@binkert.orgvoid
3495517Snate@binkert.orgBaseCPU::clear_interrupts()
3504762Snate@binkert.org{
3514762Snate@binkert.org    DPRINTF(Interrupt, "Interrupts all cleared\n");
3524762Snate@binkert.org
3534762Snate@binkert.org    memset(interrupts, 0, sizeof(interrupts));
3544382Sbinkertn@umich.edu    intstatus = 0;
3554382Sbinkertn@umich.edu}
3565517Snate@binkert.org
3575517Snate@binkert.org
3585517Snate@binkert.orgvoid
3595517Snate@binkert.orgBaseCPU::serialize(std::ostream &os)
3605798Snate@binkert.org{
3615798Snate@binkert.org    SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
3625824Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(intstatus);
3635517Snate@binkert.org}
3645517Snate@binkert.org
3655863Snate@binkert.orgvoid
3665798Snate@binkert.orgBaseCPU::unserialize(Checkpoint *cp, const std::string &section)
3675798Snate@binkert.org{
3685798Snate@binkert.org    UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
3695798Snate@binkert.org    UNSERIALIZE_SCALAR(intstatus);
3705517Snate@binkert.org}
3715517Snate@binkert.org
3725517Snate@binkert.org#endif // FULL_SYSTEM
3735517Snate@binkert.org
3745517Snate@binkert.orgvoid
3755517Snate@binkert.orgBaseCPU::traceFunctionsInternal(Addr pc)
3765517Snate@binkert.org{
3775517Snate@binkert.org    if (!debugSymbolTable)
3785798Snate@binkert.org        return;
3795798Snate@binkert.org
3805798Snate@binkert.org    // if pc enters different function, print new function symbol and
3815798Snate@binkert.org    // update saved range.  Otherwise do nothing.
3825798Snate@binkert.org    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
3835798Snate@binkert.org        string sym_str;
3845517Snate@binkert.org        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
3855517Snate@binkert.org                                                         currentFunctionStart,
3865517Snate@binkert.org                                                         currentFunctionEnd);
3875517Snate@binkert.org
3885517Snate@binkert.org        if (!found) {
3895517Snate@binkert.org            // no symbol found: use addr as label
3905517Snate@binkert.org            sym_str = csprintf("0x%x", pc);
3915517Snate@binkert.org            currentFunctionStart = pc;
3925517Snate@binkert.org            currentFunctionEnd = pc + 1;
3934762Snate@binkert.org        }
3944382Sbinkertn@umich.edu
3954762Snate@binkert.org        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
3965517Snate@binkert.org                 curTick - functionEntryTick, curTick, sym_str);
3974382Sbinkertn@umich.edu        functionEntryTick = curTick;
3984382Sbinkertn@umich.edu    }
3994762Snate@binkert.org}
4004762Snate@binkert.org
4014762Snate@binkert.org
4024762Snate@binkert.orgDEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
4034762Snate@binkert.org