base.cc revision 5714
11689SN/A/*
22325SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
31689SN/A * All rights reserved.
41689SN/A *
51689SN/A * Redistribution and use in source and binary forms, with or without
61689SN/A * modification, are permitted provided that the following conditions are
71689SN/A * met: redistributions of source code must retain the above copyright
81689SN/A * notice, this list of conditions and the following disclaimer;
91689SN/A * redistributions in binary form must reproduce the above copyright
101689SN/A * notice, this list of conditions and the following disclaimer in the
111689SN/A * documentation and/or other materials provided with the distribution;
121689SN/A * neither the name of the copyright holders nor the names of its
131689SN/A * contributors may be used to endorse or promote products derived from
141689SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
292756Sksewell@umich.edu *          Nathan Binkert
301689SN/A */
311689SN/A
321858SN/A#include <iostream>
332733Sktlim@umich.edu#include <string>
341858SN/A#include <sstream>
351858SN/A
362356SN/A#include "base/cprintf.hh"
371060SN/A#include "base/loader/symtab.hh"
381060SN/A#include "base/misc.hh"
391060SN/A#include "base/output.hh"
401060SN/A#include "base/trace.hh"
411060SN/A#include "cpu/base.hh"
422325SN/A#include "cpu/cpuevent.hh"
432683Sktlim@umich.edu#include "cpu/thread_context.hh"
442680Sktlim@umich.edu#include "cpu/profile.hh"
452817Sksewell@umich.edu#include "params/BaseCPU.hh"
461717SN/A#include "sim/sim_exit.hh"
471060SN/A#include "sim/process.hh"
484167Sbinkertn@umich.edu#include "sim/sim_events.hh"
492292SN/A#include "sim/system.hh"
502292SN/A
512794Sktlim@umich.edu// Hack
522794Sktlim@umich.edu#include "sim/stat_control.hh"
532794Sktlim@umich.edu
542794Sktlim@umich.eduusing namespace std;
551060SN/A
562669Sktlim@umich.eduvector<BaseCPU *> BaseCPU::cpuList;
571060SN/A
582733Sktlim@umich.edu// This variable reflects the max number of threads in any CPU.  Be
592292SN/A// careful to only use it once all the CPUs that you care about have
601060SN/A// been initialized
611060SN/Aint maxThreadsPerCPU = 1;
621060SN/A
632292SN/ACPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
642733Sktlim@umich.edu    : Event(Event::Progress_Event_Pri), interval(ival), lastNumInst(0),
652292SN/A      cpu(_cpu)
662292SN/A{
672292SN/A    if (interval)
682292SN/A        cpu->schedule(this, curTick + interval);
691060SN/A}
701755SN/A
711060SN/Avoid
721060SN/ACPUProgressEvent::process()
731060SN/A{
741060SN/A    Counter temp = cpu->totalInstructions();
751060SN/A#ifndef NDEBUG
761060SN/A    double ipc = double(temp - lastNumInst) / (interval / cpu->ticks(1));
771755SN/A
781060SN/A    DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n",
791060SN/A             cpu->name(), temp - lastNumInst, ipc);
801060SN/A    ipc = 0.0;
811060SN/A#else
821060SN/A    cprintf("%lli: %s progress event, instructions committed: %lli\n",
831060SN/A            curTick, cpu->name(), temp - lastNumInst);
841755SN/A#endif
851060SN/A    lastNumInst = temp;
861755SN/A    cpu->schedule(this, curTick + interval);
871060SN/A}
881060SN/A
891060SN/Aconst char *
902829Sksewell@umich.eduCPUProgressEvent::description() const
913221Sktlim@umich.edu{
922829Sksewell@umich.edu    return "CPU Progress";
932829Sksewell@umich.edu}
942829Sksewell@umich.edu
952829Sksewell@umich.edu#if FULL_SYSTEM
962829Sksewell@umich.eduBaseCPU::BaseCPU(Params *p)
972829Sksewell@umich.edu    : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id),
982829Sksewell@umich.edu      interrupts(p->interrupts),
992829Sksewell@umich.edu      number_of_threads(p->numThreads), system(p->system),
1002829Sksewell@umich.edu      phase(p->phase)
1012829Sksewell@umich.edu#else
1022829Sksewell@umich.eduBaseCPU::BaseCPU(Params *p)
1032829Sksewell@umich.edu    : MemObject(p), clock(p->clock), _cpuId(p->cpu_id),
1042829Sksewell@umich.edu      number_of_threads(p->numThreads), system(p->system),
1052829Sksewell@umich.edu      phase(p->phase)
1062829Sksewell@umich.edu#endif
1072829Sksewell@umich.edu{
1082829Sksewell@umich.edu//    currentTick = curTick;
1092829Sksewell@umich.edu
1102829Sksewell@umich.edu    // if Python did not provide a valid ID, do it here
1112829Sksewell@umich.edu    if (_cpuId == -1 ) {
1122829Sksewell@umich.edu        _cpuId = cpuList.size();
1132829Sksewell@umich.edu    }
1142829Sksewell@umich.edu
1152829Sksewell@umich.edu    // add self to global list of CPUs
1162829Sksewell@umich.edu    cpuList.push_back(this);
1172829Sksewell@umich.edu
1182829Sksewell@umich.edu    DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId);
1192875Sksewell@umich.edu
1203859Sbinkertn@umich.edu    if (number_of_threads > maxThreadsPerCPU)
1212875Sksewell@umich.edu        maxThreadsPerCPU = number_of_threads;
1222875Sksewell@umich.edu
1232875Sksewell@umich.edu    // allocate per-thread instruction-based event queues
1242875Sksewell@umich.edu    comInstEventQueue = new EventQueue *[number_of_threads];
1252875Sksewell@umich.edu    for (int i = 0; i < number_of_threads; ++i)
1262875Sksewell@umich.edu        comInstEventQueue[i] = new EventQueue("instruction-based event queue");
1273859Sbinkertn@umich.edu
1282875Sksewell@umich.edu    //
1292875Sksewell@umich.edu    // set up instruction-count-based termination events, if any
1302875Sksewell@umich.edu    //
1313859Sbinkertn@umich.edu    if (p->max_insts_any_thread != 0) {
1322875Sksewell@umich.edu        const char *cause = "a thread reached the max instruction count";
1332875Sksewell@umich.edu        for (int i = 0; i < number_of_threads; ++i) {
1342875Sksewell@umich.edu            Event *event = new SimLoopExitEvent(cause, 0);
1352875Sksewell@umich.edu            comInstEventQueue[i]->schedule(event, p->max_insts_any_thread);
1362875Sksewell@umich.edu        }
1372875Sksewell@umich.edu    }
1382875Sksewell@umich.edu
1393221Sktlim@umich.edu    if (p->max_insts_all_threads != 0) {
1403221Sktlim@umich.edu        const char *cause = "all threads reached the max instruction count";
1412875Sksewell@umich.edu
1422875Sksewell@umich.edu        // allocate & initialize shared downcounter: each event will
1432875Sksewell@umich.edu        // decrement this when triggered; simulation will terminate
1442875Sksewell@umich.edu        // when counter reaches 0
1452875Sksewell@umich.edu        int *counter = new int;
1462875Sksewell@umich.edu        *counter = number_of_threads;
1472875Sksewell@umich.edu        for (int i = 0; i < number_of_threads; ++i) {
1482875Sksewell@umich.edu            Event *event = new CountedExitEvent(cause, *counter);
1492875Sksewell@umich.edu            comInstEventQueue[i]->schedule(event, p->max_insts_any_thread);
1502875Sksewell@umich.edu        }
1514329Sktlim@umich.edu    }
1522733Sktlim@umich.edu
1533781Sgblack@eecs.umich.edu    // allocate per-thread load-based event queues
1543781Sgblack@eecs.umich.edu    comLoadEventQueue = new EventQueue *[number_of_threads];
1553781Sgblack@eecs.umich.edu    for (int i = 0; i < number_of_threads; ++i)
1563781Sgblack@eecs.umich.edu        comLoadEventQueue[i] = new EventQueue("load-based event queue");
1571060SN/A
1582292SN/A    //
1594329Sktlim@umich.edu    // set up instruction-count-based termination events, if any
1604329Sktlim@umich.edu    //
1614329Sktlim@umich.edu    if (p->max_loads_any_thread != 0) {
1624329Sktlim@umich.edu        const char *cause = "a thread reached the max load count";
1634329Sktlim@umich.edu        for (int i = 0; i < number_of_threads; ++i) {
1641060SN/A            Event *event = new SimLoopExitEvent(cause, 0);
1654329Sktlim@umich.edu            comLoadEventQueue[i]->schedule(event, p->max_loads_any_thread);
1664329Sktlim@umich.edu        }
1671060SN/A    }
1682831Sksewell@umich.edu
1692292SN/A    if (p->max_loads_all_threads != 0) {
1702292SN/A        const char *cause = "all threads reached the max load count";
1711060SN/A        // allocate & initialize shared downcounter: each event will
1724329Sktlim@umich.edu        // decrement this when triggered; simulation will terminate
1734329Sktlim@umich.edu        // when counter reaches 0
1742292SN/A        int *counter = new int;
1752292SN/A        *counter = number_of_threads;
1761060SN/A        for (int i = 0; i < number_of_threads; ++i) {
1772831Sksewell@umich.edu            Event *event = new CountedExitEvent(cause, *counter);
1782292SN/A            comLoadEventQueue[i]->schedule(event, p->max_loads_all_threads);
1792292SN/A        }
1802292SN/A    }
1812292SN/A
1821060SN/A    functionTracingEnabled = false;
1832873Sktlim@umich.edu    if (p->function_trace) {
1842873Sktlim@umich.edu        functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
1852873Sktlim@umich.edu        currentFunctionStart = currentFunctionEnd = 0;
1862873Sktlim@umich.edu        functionEntryTick = p->function_trace_start;
1872873Sktlim@umich.edu
1882873Sktlim@umich.edu        if (p->function_trace_start == 0) {
1892873Sktlim@umich.edu            functionTracingEnabled = true;
1902873Sktlim@umich.edu        } else {
1911060SN/A            typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap;
1921060SN/A            Event *event = new wrap(this, true);
1931858SN/A            schedule(event, p->function_trace_start);
1942292SN/A        }
1951060SN/A    }
1961060SN/A#if FULL_SYSTEM
1972843Sktlim@umich.edu    profileEvent = NULL;
1982316SN/A    if (params()->profile)
1992316SN/A        profileEvent = new ProfileEvent(this, params()->profile);
2001060SN/A#endif
2013221Sktlim@umich.edu    tracer = params()->tracer;
2023221Sktlim@umich.edu}
2033221Sktlim@umich.edu
2043221Sktlim@umich.eduvoid
2053221Sktlim@umich.eduBaseCPU::enableFunctionTrace()
2061681SN/A{
2072733Sktlim@umich.edu    functionTracingEnabled = true;
2082733Sktlim@umich.edu}
2092794Sktlim@umich.edu
2102733Sktlim@umich.eduBaseCPU::~BaseCPU()
2112316SN/A{
2122316SN/A}
2132316SN/A
2142316SN/Avoid
2152316SN/ABaseCPU::init()
2162794Sktlim@umich.edu{
2172794Sktlim@umich.edu    if (!params()->defer_registration)
2182794Sktlim@umich.edu        registerThreadContexts();
2192316SN/A}
2202316SN/A
2211858SN/Avoid
2222292SN/ABaseCPU::startup()
2232292SN/A{
2241681SN/A#if FULL_SYSTEM
2251681SN/A    if (!params()->defer_registration && profileEvent)
2262325SN/A        schedule(profileEvent, curTick);
2272325SN/A#endif
2282325SN/A
2291060SN/A    if (params()->progress_interval) {
2302292SN/A        Tick num_ticks = ticks(params()->progress_interval);
2312292SN/A        Event *event = new CPUProgressEvent(this, num_ticks);
2322292SN/A        schedule(event, curTick + num_ticks);
2332292SN/A    }
2342292SN/A}
2352292SN/A
2361060SN/A
2371060SN/Avoid
2381060SN/ABaseCPU::regStats()
2391060SN/A{
2401060SN/A    using namespace Stats;
2411060SN/A
2421060SN/A    numCycles
2431060SN/A        .name(name() + ".numCycles")
2441060SN/A        .desc("number of cpu cycles simulated")
2451060SN/A        ;
2461060SN/A
2472292SN/A    int size = threadContexts.size();
2481060SN/A    if (size > 1) {
2491060SN/A        for (int i = 0; i < size; ++i) {
2501060SN/A            stringstream namestr;
2511060SN/A            ccprintf(namestr, "%s.ctx%d", name(), i);
2521060SN/A            threadContexts[i]->regStats(namestr.str());
2531060SN/A        }
2541060SN/A    } else if (size == 1)
2551060SN/A        threadContexts[0]->regStats(name());
2562292SN/A
2572292SN/A#if FULL_SYSTEM
2582292SN/A#endif
2592292SN/A}
2602292SN/A
2612307SN/ATick
2622831Sksewell@umich.eduBaseCPU::nextCycle()
2632831Sksewell@umich.edu{
2642831Sksewell@umich.edu    Tick next_tick = curTick - phase + clock - 1;
2652831Sksewell@umich.edu    next_tick -= (next_tick % clock);
2662831Sksewell@umich.edu    next_tick += phase;
2672831Sksewell@umich.edu    return next_tick;
2682292SN/A}
2692307SN/A
2702292SN/ATick
2712292SN/ABaseCPU::nextCycle(Tick begin_tick)
2722316SN/A{
2732292SN/A    Tick next_tick = begin_tick;
2742292SN/A    if (next_tick % clock != 0)
2752292SN/A        next_tick = next_tick - (next_tick % clock) + clock;
2762292SN/A    next_tick += phase;
2772292SN/A
2782292SN/A    assert(next_tick >= curTick);
2791060SN/A    return next_tick;
2802292SN/A}
2812292SN/A
2821060SN/Avoid
2832292SN/ABaseCPU::registerThreadContexts()
2842307SN/A{
2852292SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
2862292SN/A        ThreadContext *tc = threadContexts[i];
2872292SN/A
2882325SN/A        tc->setContextId(system->registerThreadContext(tc));
2892292SN/A#if !FULL_SYSTEM
2902292SN/A        tc->getProcessPtr()->assignThreadContext(tc->contextId());
2912292SN/A#endif
2922325SN/A    }
2932292SN/A}
2942292SN/A
2952292SN/A
2962292SN/Aint
2972292SN/ABaseCPU::findContext(ThreadContext *tc)
2982292SN/A{
2992292SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
3002292SN/A        if (tc == threadContexts[i])
3012292SN/A            return i;
3022292SN/A    }
3032292SN/A    return 0;
3042325SN/A}
3052292SN/A
3062292SN/Avoid
3072292SN/ABaseCPU::switchOut()
3082325SN/A{
3092292SN/A//    panic("This CPU doesn't support sampling!");
3102292SN/A#if FULL_SYSTEM
3112292SN/A    if (profileEvent && profileEvent->scheduled())
3122292SN/A        deschedule(profileEvent);
3132292SN/A#endif
3142292SN/A}
3152292SN/A
3162292SN/Avoid
3173221Sktlim@umich.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
3183221Sktlim@umich.edu{
3193221Sktlim@umich.edu    assert(threadContexts.size() == oldCPU->threadContexts.size());
3202292SN/A
3212292SN/A    _cpuId = oldCPU->cpuId();
3222292SN/A
3232292SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
3242292SN/A        ThreadContext *newTC = threadContexts[i];
3252292SN/A        ThreadContext *oldTC = oldCPU->threadContexts[i];
3262292SN/A
3272292SN/A        newTC->takeOverFrom(oldTC);
3282292SN/A
3291060SN/A        CpuEvent::replaceThreadContext(oldTC, newTC);
3302292SN/A
3311060SN/A        assert(newTC->contextId() == oldTC->contextId());
3321060SN/A        system->replaceThreadContext(newTC, newTC->contextId());
3332292SN/A
3342292SN/A        if (DTRACE(Context))
3352292SN/A            ThreadContext::compare(oldTC, newTC);
3362829Sksewell@umich.edu    }
3372829Sksewell@umich.edu
3383093Sksewell@umich.edu#if FULL_SYSTEM
3393093Sksewell@umich.edu    interrupts = oldCPU->interrupts;
3403093Sksewell@umich.edu
3413093Sksewell@umich.edu    for (int i = 0; i < threadContexts.size(); ++i)
3423093Sksewell@umich.edu        threadContexts[i]->profileClear();
3432292SN/A
3441060SN/A    if (profileEvent)
3451060SN/A        schedule(profileEvent, curTick);
3461060SN/A#endif
3471755SN/A
3481060SN/A    // Connect new CPU to old CPU's memory only if new CPU isn't
3491060SN/A    // connected to anything.  Also connect old CPU's memory to new
3501060SN/A    // CPU.
3511060SN/A    if (!ic->isConnected()) {
3521060SN/A        Port *peer = oldCPU->getPort("icache_port")->getPeer();
3531755SN/A        ic->setPeer(peer);
3541062SN/A        peer->setPeer(ic);
3552733Sktlim@umich.edu    }
3562292SN/A
3572733Sktlim@umich.edu    if (!dc->isConnected()) {
3582292SN/A        Port *peer = oldCPU->getPort("dcache_port")->getPeer();
3592292SN/A        dc->setPeer(peer);
3602292SN/A        peer->setPeer(dc);
3612292SN/A    }
3622292SN/A}
3632292SN/A
3642292SN/A
3652292SN/A#if FULL_SYSTEM
3662292SN/ABaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval)
3672292SN/A    : cpu(_cpu), interval(_interval)
3682292SN/A{ }
3692292SN/A
3702292SN/Avoid
3712292SN/ABaseCPU::ProfileEvent::process()
3722292SN/A{
3732292SN/A    for (int i = 0, size = cpu->threadContexts.size(); i < size; ++i) {
3742292SN/A        ThreadContext *tc = cpu->threadContexts[i];
3752292SN/A        tc->profileSample();
3762292SN/A    }
3772292SN/A
3782292SN/A    cpu->schedule(this, curTick + interval);
3792292SN/A}
3802292SN/A
3812292SN/Avoid
3822292SN/ABaseCPU::postInterrupt(int int_num, int index)
3832292SN/A{
3842292SN/A    interrupts->post(int_num, index);
3852292SN/A}
3862292SN/A
3872292SN/Avoid
3882292SN/ABaseCPU::clearInterrupt(int int_num, int index)
3892292SN/A{
3902292SN/A    interrupts->clear(int_num, index);
3912292SN/A}
3922292SN/A
3932292SN/Avoid
3942292SN/ABaseCPU::clearInterrupts()
3952292SN/A{
3962292SN/A    interrupts->clearAll();
3972292SN/A}
3982292SN/A
3992292SN/Avoid
4002292SN/ABaseCPU::serialize(std::ostream &os)
4012292SN/A{
4022292SN/A    SERIALIZE_SCALAR(instCnt);
4032292SN/A    interrupts->serialize(os);
4042292SN/A}
4052292SN/A
4062292SN/Avoid
4071062SN/ABaseCPU::unserialize(Checkpoint *cp, const std::string &section)
4081062SN/A{
4091062SN/A    UNSERIALIZE_SCALAR(instCnt);
4102871Sktlim@umich.edu    interrupts->unserialize(cp, section);
4112871Sktlim@umich.edu}
4122871Sktlim@umich.edu
4132871Sktlim@umich.edu#endif // FULL_SYSTEM
4142871Sktlim@umich.edu
4152871Sktlim@umich.eduvoid
4162871Sktlim@umich.eduBaseCPU::traceFunctionsInternal(Addr pc)
4172871Sktlim@umich.edu{
4182871Sktlim@umich.edu    if (!debugSymbolTable)
4192871Sktlim@umich.edu        return;
4202871Sktlim@umich.edu
4212871Sktlim@umich.edu    // if pc enters different function, print new function symbol and
4221062SN/A    // update saved range.  Otherwise do nothing.
4231755SN/A    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
4241060SN/A        string sym_str;
4252733Sktlim@umich.edu        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
4261060SN/A                                                         currentFunctionStart,
4272292SN/A                                                         currentFunctionEnd);
4282292SN/A
4292325SN/A        if (!found) {
4302292SN/A            // no symbol found: use addr as label
4312292SN/A            sym_str = csprintf("0x%x", pc);
4321060SN/A            currentFunctionStart = pc;
4331060SN/A            currentFunctionEnd = pc + 1;
4341060SN/A        }
4351060SN/A
4361060SN/A        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
4371060SN/A                 curTick - functionEntryTick, curTick, sym_str);
4381060SN/A        functionEntryTick = curTick;
4391060SN/A    }
4401060SN/A}
4411060SN/A