base.cc revision 8779:2a590c51adb1
19022Sgblack@eecs.umich.edu/*
29022Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
39022Sgblack@eecs.umich.edu * Copyright (c) 2011 Regents of the University of California
49022Sgblack@eecs.umich.edu * All rights reserved.
59022Sgblack@eecs.umich.edu *
69022Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
79022Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
89022Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
99022Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
109022Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
119022Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
129022Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
139022Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
149022Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
159022Sgblack@eecs.umich.edu * this software without specific prior written permission.
169022Sgblack@eecs.umich.edu *
179022Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
189022Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
199022Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
209022Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
219022Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229022Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
239022Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249022Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259022Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269022Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
279022Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289022Sgblack@eecs.umich.edu *
299022Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
309022Sgblack@eecs.umich.edu *          Nathan Binkert
319022Sgblack@eecs.umich.edu *          Rick Strong
329023Sgblack@eecs.umich.edu */
339023Sgblack@eecs.umich.edu
349023Sgblack@eecs.umich.edu#include <iostream>
359023Sgblack@eecs.umich.edu#include <sstream>
369023Sgblack@eecs.umich.edu#include <string>
379022Sgblack@eecs.umich.edu
389022Sgblack@eecs.umich.edu#include "arch/tlb.hh"
399022Sgblack@eecs.umich.edu#include "base/loader/symtab.hh"
409376Sgblack@eecs.umich.edu#include "base/cprintf.hh"
419376Sgblack@eecs.umich.edu#include "base/misc.hh"
429376Sgblack@eecs.umich.edu#include "base/output.hh"
439023Sgblack@eecs.umich.edu#include "base/trace.hh"
449023Sgblack@eecs.umich.edu#include "cpu/base.hh"
459023Sgblack@eecs.umich.edu#include "cpu/cpuevent.hh"
469376Sgblack@eecs.umich.edu#include "cpu/profile.hh"
479376Sgblack@eecs.umich.edu#include "cpu/thread_context.hh"
489376Sgblack@eecs.umich.edu#include "debug/SyscallVerbose.hh"
499023Sgblack@eecs.umich.edu#include "params/BaseCPU.hh"
509023Sgblack@eecs.umich.edu#include "sim/full_system.hh"
5110924Snilay@cs.wisc.edu#include "sim/process.hh"
5210924Snilay@cs.wisc.edu#include "sim/sim_events.hh"
5310593Sgabeblack@google.com#include "sim/sim_exit.hh"
549023Sgblack@eecs.umich.edu#include "sim/system.hh"
559023Sgblack@eecs.umich.edu
569023Sgblack@eecs.umich.edu// Hack
579023Sgblack@eecs.umich.edu#include "sim/stat_control.hh"
589023Sgblack@eecs.umich.edu
599023Sgblack@eecs.umich.eduusing namespace std;
609023Sgblack@eecs.umich.edu
619023Sgblack@eecs.umich.eduvector<BaseCPU *> BaseCPU::cpuList;
629023Sgblack@eecs.umich.edu
639376Sgblack@eecs.umich.edu// This variable reflects the max number of threads in any CPU.  Be
649376Sgblack@eecs.umich.edu// careful to only use it once all the CPUs that you care about have
659376Sgblack@eecs.umich.edu// been initialized
669376Sgblack@eecs.umich.eduint maxThreadsPerCPU = 1;
679376Sgblack@eecs.umich.edu
689376Sgblack@eecs.umich.eduCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
699376Sgblack@eecs.umich.edu    : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
709023Sgblack@eecs.umich.edu      cpu(_cpu), _repeatEvent(true)
719023Sgblack@eecs.umich.edu{
729376Sgblack@eecs.umich.edu    if (_interval)
739376Sgblack@eecs.umich.edu        cpu->schedule(this, curTick() + _interval);
749023Sgblack@eecs.umich.edu}
759023Sgblack@eecs.umich.edu
769023Sgblack@eecs.umich.eduvoid
779023Sgblack@eecs.umich.eduCPUProgressEvent::process()
789023Sgblack@eecs.umich.edu{
799023Sgblack@eecs.umich.edu    Counter temp = cpu->totalInstructions();
809023Sgblack@eecs.umich.edu#ifndef NDEBUG
819023Sgblack@eecs.umich.edu    double ipc = double(temp - lastNumInst) / (_interval / cpu->ticks(1));
829023Sgblack@eecs.umich.edu
839376Sgblack@eecs.umich.edu    DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
849376Sgblack@eecs.umich.edu             "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
859376Sgblack@eecs.umich.edu             ipc);
869376Sgblack@eecs.umich.edu    ipc = 0.0;
879376Sgblack@eecs.umich.edu#else
889376Sgblack@eecs.umich.edu    cprintf("%lli: %s progress event, total committed:%i, progress insts "
899376Sgblack@eecs.umich.edu            "committed: %lli\n", curTick(), cpu->name(), temp,
909376Sgblack@eecs.umich.edu            temp - lastNumInst);
919023Sgblack@eecs.umich.edu#endif
929376Sgblack@eecs.umich.edu    lastNumInst = temp;
939023Sgblack@eecs.umich.edu
949376Sgblack@eecs.umich.edu    if (_repeatEvent)
959023Sgblack@eecs.umich.edu        cpu->schedule(this, curTick() + _interval);
969023Sgblack@eecs.umich.edu}
979023Sgblack@eecs.umich.edu
9810924Snilay@cs.wisc.educonst char *
9910924Snilay@cs.wisc.eduCPUProgressEvent::description() const
10010924Snilay@cs.wisc.edu{
10110924Snilay@cs.wisc.edu    return "CPU Progress";
10210924Snilay@cs.wisc.edu}
10310924Snilay@cs.wisc.edu
10410924Snilay@cs.wisc.eduBaseCPU::BaseCPU(Params *p)
10510924Snilay@cs.wisc.edu    : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id),
10610924Snilay@cs.wisc.edu      interrupts(p->interrupts),
10710924Snilay@cs.wisc.edu      numThreads(p->numThreads), system(p->system),
10810924Snilay@cs.wisc.edu      phase(p->phase)
10910924Snilay@cs.wisc.edu{
11010924Snilay@cs.wisc.edu//    currentTick = curTick();
11110593Sgabeblack@google.com
11210593Sgabeblack@google.com    // if Python did not provide a valid ID, do it here
11310593Sgabeblack@google.com    if (_cpuId == -1 ) {
11410593Sgabeblack@google.com        _cpuId = cpuList.size();
11510593Sgabeblack@google.com    }
11610593Sgabeblack@google.com
11710593Sgabeblack@google.com    // add self to global list of CPUs
11810593Sgabeblack@google.com    cpuList.push_back(this);
11910593Sgabeblack@google.com
12010593Sgabeblack@google.com    DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId);
12110593Sgabeblack@google.com
1229023Sgblack@eecs.umich.edu    if (numThreads > maxThreadsPerCPU)
1239023Sgblack@eecs.umich.edu        maxThreadsPerCPU = numThreads;
1249023Sgblack@eecs.umich.edu
1259023Sgblack@eecs.umich.edu    // allocate per-thread instruction-based event queues
1269023Sgblack@eecs.umich.edu    comInstEventQueue = new EventQueue *[numThreads];
1279023Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
1289023Sgblack@eecs.umich.edu        comInstEventQueue[tid] =
1299023Sgblack@eecs.umich.edu            new EventQueue("instruction-based event queue");
1309023Sgblack@eecs.umich.edu
1319023Sgblack@eecs.umich.edu    //
1329023Sgblack@eecs.umich.edu    // set up instruction-count-based termination events, if any
1339023Sgblack@eecs.umich.edu    //
1349023Sgblack@eecs.umich.edu    if (p->max_insts_any_thread != 0) {
1359023Sgblack@eecs.umich.edu        const char *cause = "a thread reached the max instruction count";
1369023Sgblack@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid) {
1379023Sgblack@eecs.umich.edu            Event *event = new SimLoopExitEvent(cause, 0);
1389023Sgblack@eecs.umich.edu            comInstEventQueue[tid]->schedule(event, p->max_insts_any_thread);
1399023Sgblack@eecs.umich.edu        }
1409023Sgblack@eecs.umich.edu    }
1419023Sgblack@eecs.umich.edu
1429023Sgblack@eecs.umich.edu    if (p->max_insts_all_threads != 0) {
1439376Sgblack@eecs.umich.edu        const char *cause = "all threads reached the max instruction count";
1449376Sgblack@eecs.umich.edu
1459376Sgblack@eecs.umich.edu        // allocate & initialize shared downcounter: each event will
1469376Sgblack@eecs.umich.edu        // decrement this when triggered; simulation will terminate
1479376Sgblack@eecs.umich.edu        // when counter reaches 0
1489376Sgblack@eecs.umich.edu        int *counter = new int;
1499376Sgblack@eecs.umich.edu        *counter = numThreads;
1509376Sgblack@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid) {
1519376Sgblack@eecs.umich.edu            Event *event = new CountedExitEvent(cause, *counter);
1529376Sgblack@eecs.umich.edu            comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads);
1539376Sgblack@eecs.umich.edu        }
1549376Sgblack@eecs.umich.edu    }
1559376Sgblack@eecs.umich.edu
1569376Sgblack@eecs.umich.edu    // allocate per-thread load-based event queues
1579376Sgblack@eecs.umich.edu    comLoadEventQueue = new EventQueue *[numThreads];
1589376Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
1599376Sgblack@eecs.umich.edu        comLoadEventQueue[tid] = new EventQueue("load-based event queue");
1609376Sgblack@eecs.umich.edu
1619376Sgblack@eecs.umich.edu    //
1629376Sgblack@eecs.umich.edu    // set up instruction-count-based termination events, if any
1639376Sgblack@eecs.umich.edu    //
1649376Sgblack@eecs.umich.edu    if (p->max_loads_any_thread != 0) {
1659376Sgblack@eecs.umich.edu        const char *cause = "a thread reached the max load count";
1669376Sgblack@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid) {
1679376Sgblack@eecs.umich.edu            Event *event = new SimLoopExitEvent(cause, 0);
1689376Sgblack@eecs.umich.edu            comLoadEventQueue[tid]->schedule(event, p->max_loads_any_thread);
1699376Sgblack@eecs.umich.edu        }
1709376Sgblack@eecs.umich.edu    }
1719376Sgblack@eecs.umich.edu
1729376Sgblack@eecs.umich.edu    if (p->max_loads_all_threads != 0) {
1739376Sgblack@eecs.umich.edu        const char *cause = "all threads reached the max load count";
1749376Sgblack@eecs.umich.edu        // allocate & initialize shared downcounter: each event will
1759023Sgblack@eecs.umich.edu        // decrement this when triggered; simulation will terminate
1769023Sgblack@eecs.umich.edu        // when counter reaches 0
1779376Sgblack@eecs.umich.edu        int *counter = new int;
1789376Sgblack@eecs.umich.edu        *counter = numThreads;
1799023Sgblack@eecs.umich.edu        for (ThreadID tid = 0; tid < numThreads; ++tid) {
1809023Sgblack@eecs.umich.edu            Event *event = new CountedExitEvent(cause, *counter);
1819023Sgblack@eecs.umich.edu            comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads);
1829023Sgblack@eecs.umich.edu        }
1839023Sgblack@eecs.umich.edu    }
1849023Sgblack@eecs.umich.edu
1859023Sgblack@eecs.umich.edu    functionTracingEnabled = false;
1869023Sgblack@eecs.umich.edu    if (p->function_trace) {
1879023Sgblack@eecs.umich.edu        functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
1889023Sgblack@eecs.umich.edu        currentFunctionStart = currentFunctionEnd = 0;
1899023Sgblack@eecs.umich.edu        functionEntryTick = p->function_trace_start;
1909023Sgblack@eecs.umich.edu
1919023Sgblack@eecs.umich.edu        if (p->function_trace_start == 0) {
1929023Sgblack@eecs.umich.edu            functionTracingEnabled = true;
1939023Sgblack@eecs.umich.edu        } else {
1949023Sgblack@eecs.umich.edu            typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap;
1959023Sgblack@eecs.umich.edu            Event *event = new wrap(this, true);
1969023Sgblack@eecs.umich.edu            schedule(event, p->function_trace_start);
1979023Sgblack@eecs.umich.edu        }
1989023Sgblack@eecs.umich.edu    }
1999023Sgblack@eecs.umich.edu    interrupts->setCPU(this);
2009023Sgblack@eecs.umich.edu
2019023Sgblack@eecs.umich.edu    if (FullSystem) {
2029023Sgblack@eecs.umich.edu#if FULL_SYSTEM
2039023Sgblack@eecs.umich.edu        profileEvent = NULL;
2049023Sgblack@eecs.umich.edu        if (params()->profile)
2059023Sgblack@eecs.umich.edu            profileEvent = new ProfileEvent(this, params()->profile);
2069023Sgblack@eecs.umich.edu#endif
2079023Sgblack@eecs.umich.edu    }
2089023Sgblack@eecs.umich.edu    tracer = params()->tracer;
2099023Sgblack@eecs.umich.edu}
2109023Sgblack@eecs.umich.edu
2119023Sgblack@eecs.umich.eduvoid
2129023Sgblack@eecs.umich.eduBaseCPU::enableFunctionTrace()
2139023Sgblack@eecs.umich.edu{
2149023Sgblack@eecs.umich.edu    functionTracingEnabled = true;
2159023Sgblack@eecs.umich.edu}
2169023Sgblack@eecs.umich.edu
2179023Sgblack@eecs.umich.eduBaseCPU::~BaseCPU()
2189023Sgblack@eecs.umich.edu{
2199023Sgblack@eecs.umich.edu}
2209023Sgblack@eecs.umich.edu
2219023Sgblack@eecs.umich.eduvoid
2229023Sgblack@eecs.umich.eduBaseCPU::init()
2239023Sgblack@eecs.umich.edu{
22410924Snilay@cs.wisc.edu    if (!params()->defer_registration)
22510924Snilay@cs.wisc.edu        registerThreadContexts();
22610924Snilay@cs.wisc.edu}
22710924Snilay@cs.wisc.edu
22810924Snilay@cs.wisc.eduvoid
22910924Snilay@cs.wisc.eduBaseCPU::startup()
23010924Snilay@cs.wisc.edu{
23110924Snilay@cs.wisc.edu    if (FullSystem) {
23210924Snilay@cs.wisc.edu        if (!params()->defer_registration && profileEvent)
23310924Snilay@cs.wisc.edu            schedule(profileEvent, curTick());
23410924Snilay@cs.wisc.edu    }
23510924Snilay@cs.wisc.edu
23610924Snilay@cs.wisc.edu    if (params()->progress_interval) {
2379023Sgblack@eecs.umich.edu        Tick num_ticks = ticks(params()->progress_interval);
23810593Sgabeblack@google.com
2399023Sgblack@eecs.umich.edu        Event *event;
24010924Snilay@cs.wisc.edu        event = new CPUProgressEvent(this, num_ticks);
2419023Sgblack@eecs.umich.edu    }
2429023Sgblack@eecs.umich.edu}
2439023Sgblack@eecs.umich.edu
2449023Sgblack@eecs.umich.edu
2459023Sgblack@eecs.umich.eduvoid
2469023Sgblack@eecs.umich.eduBaseCPU::regStats()
24710924Snilay@cs.wisc.edu{
24810924Snilay@cs.wisc.edu    using namespace Stats;
24910924Snilay@cs.wisc.edu
25010924Snilay@cs.wisc.edu    numCycles
25110924Snilay@cs.wisc.edu        .name(name() + ".numCycles")
25210924Snilay@cs.wisc.edu        .desc("number of cpu cycles simulated")
25310924Snilay@cs.wisc.edu        ;
25410924Snilay@cs.wisc.edu
25510924Snilay@cs.wisc.edu    numWorkItemsStarted
25610924Snilay@cs.wisc.edu        .name(name() + ".numWorkItemsStarted")
25710924Snilay@cs.wisc.edu        .desc("number of work items this cpu started")
25810924Snilay@cs.wisc.edu        ;
25910924Snilay@cs.wisc.edu
26010924Snilay@cs.wisc.edu    numWorkItemsCompleted
26110924Snilay@cs.wisc.edu        .name(name() + ".numWorkItemsCompleted")
26210924Snilay@cs.wisc.edu        .desc("number of work items this cpu completed")
26310924Snilay@cs.wisc.edu        ;
26410924Snilay@cs.wisc.edu
26510924Snilay@cs.wisc.edu    int size = threadContexts.size();
26610924Snilay@cs.wisc.edu    if (size > 1) {
26710924Snilay@cs.wisc.edu        for (int i = 0; i < size; ++i) {
26810924Snilay@cs.wisc.edu            stringstream namestr;
26910924Snilay@cs.wisc.edu            ccprintf(namestr, "%s.ctx%d", name(), i);
27010924Snilay@cs.wisc.edu            threadContexts[i]->regStats(namestr.str());
27110924Snilay@cs.wisc.edu        }
27210924Snilay@cs.wisc.edu    } else if (size == 1)
27310924Snilay@cs.wisc.edu        threadContexts[0]->regStats(name());
27410924Snilay@cs.wisc.edu}
27510924Snilay@cs.wisc.edu
27610924Snilay@cs.wisc.eduTick
27710924Snilay@cs.wisc.eduBaseCPU::nextCycle()
27810924Snilay@cs.wisc.edu{
27910924Snilay@cs.wisc.edu    Tick next_tick = curTick() - phase + clock - 1;
28010924Snilay@cs.wisc.edu    next_tick -= (next_tick % clock);
28110924Snilay@cs.wisc.edu    next_tick += phase;
28210924Snilay@cs.wisc.edu    return next_tick;
28310924Snilay@cs.wisc.edu}
28410924Snilay@cs.wisc.edu
28510924Snilay@cs.wisc.eduTick
28610593Sgabeblack@google.comBaseCPU::nextCycle(Tick begin_tick)
28710593Sgabeblack@google.com{
2889376Sgblack@eecs.umich.edu    Tick next_tick = begin_tick;
28910593Sgabeblack@google.com    if (next_tick % clock != 0)
2909023Sgblack@eecs.umich.edu        next_tick = next_tick - (next_tick % clock) + clock;
2919023Sgblack@eecs.umich.edu    next_tick += phase;
2929023Sgblack@eecs.umich.edu
29310924Snilay@cs.wisc.edu    assert(next_tick >= curTick());
29410924Snilay@cs.wisc.edu    return next_tick;
29510924Snilay@cs.wisc.edu}
29610924Snilay@cs.wisc.edu
29710924Snilay@cs.wisc.eduvoid
29810924Snilay@cs.wisc.eduBaseCPU::registerThreadContexts()
29910924Snilay@cs.wisc.edu{
30010593Sgabeblack@google.com    ThreadID size = threadContexts.size();
30110593Sgabeblack@google.com    for (ThreadID tid = 0; tid < size; ++tid) {
30210593Sgabeblack@google.com        ThreadContext *tc = threadContexts[tid];
30310593Sgabeblack@google.com
30410593Sgabeblack@google.com        /** This is so that contextId and cpuId match where there is a
3059023Sgblack@eecs.umich.edu         * 1cpu:1context relationship.  Otherwise, the order of registration
3069023Sgblack@eecs.umich.edu         * could affect the assignment and cpu 1 could have context id 3, for
30710593Sgabeblack@google.com         * example.  We may even want to do something like this for SMT so that
30810593Sgabeblack@google.com         * cpu 0 has the lowest thread contexts and cpu N has the highest, but
30910593Sgabeblack@google.com         * I'll just do this for now
31010593Sgabeblack@google.com         */
31110593Sgabeblack@google.com        if (numThreads == 1)
3129023Sgblack@eecs.umich.edu            tc->setContextId(system->registerThreadContext(tc, _cpuId));
31310593Sgabeblack@google.com        else
31410593Sgabeblack@google.com            tc->setContextId(system->registerThreadContext(tc));
31510593Sgabeblack@google.com
31610593Sgabeblack@google.com        if (!FullSystem)
31710593Sgabeblack@google.com            tc->getProcessPtr()->assignThreadContext(tc->contextId());
31810593Sgabeblack@google.com    }
31910593Sgabeblack@google.com}
32010593Sgabeblack@google.com
32110593Sgabeblack@google.com
32210593Sgabeblack@google.comint
32310593Sgabeblack@google.comBaseCPU::findContext(ThreadContext *tc)
32410593Sgabeblack@google.com{
32510593Sgabeblack@google.com    ThreadID size = threadContexts.size();
32610593Sgabeblack@google.com    for (ThreadID tid = 0; tid < size; ++tid) {
32710593Sgabeblack@google.com        if (tc == threadContexts[tid])
32810593Sgabeblack@google.com            return tid;
32910593Sgabeblack@google.com    }
3309023Sgblack@eecs.umich.edu    return 0;
33110593Sgabeblack@google.com}
33210593Sgabeblack@google.com
33310593Sgabeblack@google.comvoid
33410593Sgabeblack@google.comBaseCPU::switchOut()
3359023Sgblack@eecs.umich.edu{
33610593Sgabeblack@google.com    if (profileEvent && profileEvent->scheduled())
33710593Sgabeblack@google.com        deschedule(profileEvent);
33810593Sgabeblack@google.com}
33910593Sgabeblack@google.com
34010593Sgabeblack@google.comvoid
34110593Sgabeblack@google.comBaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
3429023Sgblack@eecs.umich.edu{
34310593Sgabeblack@google.com    assert(threadContexts.size() == oldCPU->threadContexts.size());
34410593Sgabeblack@google.com
34510593Sgabeblack@google.com    _cpuId = oldCPU->cpuId();
3469023Sgblack@eecs.umich.edu
34710593Sgabeblack@google.com    ThreadID size = threadContexts.size();
34810593Sgabeblack@google.com    for (ThreadID i = 0; i < size; ++i) {
3499023Sgblack@eecs.umich.edu        ThreadContext *newTC = threadContexts[i];
35010593Sgabeblack@google.com        ThreadContext *oldTC = oldCPU->threadContexts[i];
35110593Sgabeblack@google.com
35210593Sgabeblack@google.com        newTC->takeOverFrom(oldTC);
35310593Sgabeblack@google.com
35410593Sgabeblack@google.com        CpuEvent::replaceThreadContext(oldTC, newTC);
35510593Sgabeblack@google.com
35610593Sgabeblack@google.com        assert(newTC->contextId() == oldTC->contextId());
35710593Sgabeblack@google.com        assert(newTC->threadId() == oldTC->threadId());
35810593Sgabeblack@google.com        system->replaceThreadContext(newTC, newTC->contextId());
35910593Sgabeblack@google.com
36010593Sgabeblack@google.com        /* This code no longer works since the zero register (e.g.,
36110593Sgabeblack@google.com         * r31 on Alpha) doesn't necessarily contain zero at this
36210593Sgabeblack@google.com         * point.
36310593Sgabeblack@google.com           if (DTRACE(Context))
36410593Sgabeblack@google.com            ThreadContext::compare(oldTC, newTC);
36510593Sgabeblack@google.com        */
36610593Sgabeblack@google.com
36710593Sgabeblack@google.com        Port  *old_itb_port, *old_dtb_port, *new_itb_port, *new_dtb_port;
36810593Sgabeblack@google.com        old_itb_port = oldTC->getITBPtr()->getPort();
36910593Sgabeblack@google.com        old_dtb_port = oldTC->getDTBPtr()->getPort();
37010593Sgabeblack@google.com        new_itb_port = newTC->getITBPtr()->getPort();
37110593Sgabeblack@google.com        new_dtb_port = newTC->getDTBPtr()->getPort();
37210593Sgabeblack@google.com
37310593Sgabeblack@google.com        // Move over any table walker ports if they exist
37410593Sgabeblack@google.com        if (new_itb_port && !new_itb_port->isConnected()) {
37510593Sgabeblack@google.com            assert(old_itb_port);
37610593Sgabeblack@google.com            Port *peer = old_itb_port->getPeer();;
37710593Sgabeblack@google.com            new_itb_port->setPeer(peer);
37810593Sgabeblack@google.com            peer->setPeer(new_itb_port);
37910593Sgabeblack@google.com        }
38010593Sgabeblack@google.com        if (new_dtb_port && !new_dtb_port->isConnected()) {
38110593Sgabeblack@google.com            assert(old_dtb_port);
38210593Sgabeblack@google.com            Port *peer = old_dtb_port->getPeer();;
38310593Sgabeblack@google.com            new_dtb_port->setPeer(peer);
38410593Sgabeblack@google.com            peer->setPeer(new_dtb_port);
38510593Sgabeblack@google.com        }
38610593Sgabeblack@google.com    }
38710593Sgabeblack@google.com
38810593Sgabeblack@google.com    interrupts = oldCPU->interrupts;
38911321Ssteve.reinhardt@amd.com    interrupts->setCPU(this);
39010593Sgabeblack@google.com
39110593Sgabeblack@google.com    if (FullSystem) {
39210593Sgabeblack@google.com        for (ThreadID i = 0; i < size; ++i)
39310593Sgabeblack@google.com            threadContexts[i]->profileClear();
39410593Sgabeblack@google.com
39510593Sgabeblack@google.com        if (profileEvent)
39610593Sgabeblack@google.com            schedule(profileEvent, curTick());
39710593Sgabeblack@google.com    }
39810593Sgabeblack@google.com
39910593Sgabeblack@google.com    // Connect new CPU to old CPU's memory only if new CPU isn't
40010593Sgabeblack@google.com    // connected to anything.  Also connect old CPU's memory to new
40110593Sgabeblack@google.com    // CPU.
40210593Sgabeblack@google.com    if (!ic->isConnected()) {
40310593Sgabeblack@google.com        Port *peer = oldCPU->getPort("icache_port")->getPeer();
40410593Sgabeblack@google.com        ic->setPeer(peer);
40510593Sgabeblack@google.com        peer->setPeer(ic);
40610593Sgabeblack@google.com    }
40710593Sgabeblack@google.com
40810593Sgabeblack@google.com    if (!dc->isConnected()) {
40910593Sgabeblack@google.com        Port *peer = oldCPU->getPort("dcache_port")->getPeer();
41010593Sgabeblack@google.com        dc->setPeer(peer);
41110593Sgabeblack@google.com        peer->setPeer(dc);
41210593Sgabeblack@google.com    }
41311321Ssteve.reinhardt@amd.com}
41410593Sgabeblack@google.com
4159023Sgblack@eecs.umich.edu
41610593Sgabeblack@google.comBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval)
41710593Sgabeblack@google.com    : cpu(_cpu), interval(_interval)
4189023Sgblack@eecs.umich.edu{ }
4199023Sgblack@eecs.umich.edu
4209023Sgblack@eecs.umich.eduvoid
4219023Sgblack@eecs.umich.eduBaseCPU::ProfileEvent::process()
4229023Sgblack@eecs.umich.edu{
42310924Snilay@cs.wisc.edu    ThreadID size = cpu->threadContexts.size();
42410924Snilay@cs.wisc.edu    for (ThreadID i = 0; i < size; ++i) {
42510924Snilay@cs.wisc.edu        ThreadContext *tc = cpu->threadContexts[i];
42610924Snilay@cs.wisc.edu        tc->profileSample();
42710924Snilay@cs.wisc.edu    }
42810924Snilay@cs.wisc.edu
42910924Snilay@cs.wisc.edu    cpu->schedule(this, curTick() + interval);
43010924Snilay@cs.wisc.edu}
43110924Snilay@cs.wisc.edu
43210924Snilay@cs.wisc.eduvoid
43310924Snilay@cs.wisc.eduBaseCPU::serialize(std::ostream &os)
43410924Snilay@cs.wisc.edu{
43510924Snilay@cs.wisc.edu    SERIALIZE_SCALAR(instCnt);
43610924Snilay@cs.wisc.edu    interrupts->serialize(os);
43710924Snilay@cs.wisc.edu}
43810924Snilay@cs.wisc.edu
43910924Snilay@cs.wisc.eduvoid
44010924Snilay@cs.wisc.eduBaseCPU::unserialize(Checkpoint *cp, const std::string &section)
44110924Snilay@cs.wisc.edu{
44211321Ssteve.reinhardt@amd.com    UNSERIALIZE_SCALAR(instCnt);
44310924Snilay@cs.wisc.edu    interrupts->unserialize(cp, section);
44410924Snilay@cs.wisc.edu}
44510924Snilay@cs.wisc.edu
44610924Snilay@cs.wisc.eduvoid
44710924Snilay@cs.wisc.eduBaseCPU::traceFunctionsInternal(Addr pc)
44810924Snilay@cs.wisc.edu{
44910924Snilay@cs.wisc.edu    if (!debugSymbolTable)
45010924Snilay@cs.wisc.edu        return;
45110924Snilay@cs.wisc.edu
45210924Snilay@cs.wisc.edu    // if pc enters different function, print new function symbol and
45310924Snilay@cs.wisc.edu    // update saved range.  Otherwise do nothing.
45410924Snilay@cs.wisc.edu    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
45510924Snilay@cs.wisc.edu        string sym_str;
45610924Snilay@cs.wisc.edu        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
45710924Snilay@cs.wisc.edu                                                         currentFunctionStart,
45810924Snilay@cs.wisc.edu                                                         currentFunctionEnd);
45910924Snilay@cs.wisc.edu
46010924Snilay@cs.wisc.edu        if (!found) {
46110924Snilay@cs.wisc.edu            // no symbol found: use addr as label
46210924Snilay@cs.wisc.edu            sym_str = csprintf("0x%x", pc);
46310924Snilay@cs.wisc.edu            currentFunctionStart = pc;
46410924Snilay@cs.wisc.edu            currentFunctionEnd = pc + 1;
46510924Snilay@cs.wisc.edu        }
46610924Snilay@cs.wisc.edu
46710924Snilay@cs.wisc.edu        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
46810924Snilay@cs.wisc.edu                 curTick() - functionEntryTick, curTick(), sym_str);
46910924Snilay@cs.wisc.edu        functionEntryTick = curTick();
47010924Snilay@cs.wisc.edu    }
4719023Sgblack@eecs.umich.edu}
4729023Sgblack@eecs.umich.edu