base.cc revision 8737
112841Sgabeblack@google.com/*
212841Sgabeblack@google.com * Copyright (c) 2011 ARM Limited
312841Sgabeblack@google.com * All rights reserved
412841Sgabeblack@google.com *
512841Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612841Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712841Sgabeblack@google.com * property including but not limited to intellectual property relating
812841Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912841Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012841Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112841Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212841Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312841Sgabeblack@google.com *
1412841Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
1512841Sgabeblack@google.com * Copyright (c) 2011 Regents of the University of California
1612841Sgabeblack@google.com * All rights reserved.
1712841Sgabeblack@google.com *
1812841Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1912841Sgabeblack@google.com * modification, are permitted provided that the following conditions are
2012841Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
2112841Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
2212841Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
2312841Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2412841Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2512841Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2612841Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2712841Sgabeblack@google.com * this software without specific prior written permission.
2812841Sgabeblack@google.com *
2912841Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3012841Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3112841Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3212841Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3312841Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3412933Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3512933Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3612841Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3713044Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3812841Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3912841Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4013044Sgabeblack@google.com *
4112841Sgabeblack@google.com * Authors: Steve Reinhardt
4212841Sgabeblack@google.com *          Nathan Binkert
4312841Sgabeblack@google.com *          Rick Strong
4412841Sgabeblack@google.com */
4512841Sgabeblack@google.com
4612841Sgabeblack@google.com#include <iostream>
4712841Sgabeblack@google.com#include <sstream>
4812933Sgabeblack@google.com#include <string>
4912933Sgabeblack@google.com
5012933Sgabeblack@google.com#include "arch/tlb.hh"
5112933Sgabeblack@google.com#include "base/loader/symtab.hh"
5212933Sgabeblack@google.com#include "base/cprintf.hh"
5312933Sgabeblack@google.com#include "base/misc.hh"
5412933Sgabeblack@google.com#include "base/output.hh"
5512933Sgabeblack@google.com#include "base/trace.hh"
5612933Sgabeblack@google.com#include "config/use_checker.hh"
5712933Sgabeblack@google.com#include "cpu/base.hh"
5812933Sgabeblack@google.com#include "cpu/cpuevent.hh"
5912933Sgabeblack@google.com#include "cpu/profile.hh"
6012933Sgabeblack@google.com#include "cpu/thread_context.hh"
6112933Sgabeblack@google.com#include "debug/SyscallVerbose.hh"
6212933Sgabeblack@google.com#include "params/BaseCPU.hh"
6312933Sgabeblack@google.com#include "sim/process.hh"
6412841Sgabeblack@google.com#include "sim/sim_events.hh"
6512841Sgabeblack@google.com#include "sim/sim_exit.hh"
6612841Sgabeblack@google.com#include "sim/system.hh"
6712841Sgabeblack@google.com
6812841Sgabeblack@google.com#if USE_CHECKER
6912841Sgabeblack@google.com#include "cpu/checker/cpu.hh"
7012841Sgabeblack@google.com#endif
7113044Sgabeblack@google.com
7213141Sgabeblack@google.com// Hack
7312841Sgabeblack@google.com#include "sim/stat_control.hh"
7413044Sgabeblack@google.com
7513044Sgabeblack@google.comusing namespace std;
7613141Sgabeblack@google.com
7712841Sgabeblack@google.comvector<BaseCPU *> BaseCPU::cpuList;
7812912Sgabeblack@google.com
7913044Sgabeblack@google.com// This variable reflects the max number of threads in any CPU.  Be
8013141Sgabeblack@google.com// careful to only use it once all the CPUs that you care about have
8113044Sgabeblack@google.com// been initialized
8212841Sgabeblack@google.comint maxThreadsPerCPU = 1;
8312841Sgabeblack@google.com
8412841Sgabeblack@google.comCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
8512841Sgabeblack@google.com    : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
8612841Sgabeblack@google.com      cpu(_cpu), _repeatEvent(true)
8712841Sgabeblack@google.com{
8812841Sgabeblack@google.com    if (_interval)
8912841Sgabeblack@google.com        cpu->schedule(this, curTick() + _interval);
9013044Sgabeblack@google.com}
9113044Sgabeblack@google.com
9212841Sgabeblack@google.comvoid
9312841Sgabeblack@google.comCPUProgressEvent::process()
9412841Sgabeblack@google.com{
9512841Sgabeblack@google.com    Counter temp = cpu->totalInstructions();
9612841Sgabeblack@google.com#ifndef NDEBUG
9712841Sgabeblack@google.com    double ipc = double(temp - lastNumInst) / (_interval / cpu->ticks(1));
9812841Sgabeblack@google.com
9913044Sgabeblack@google.com    DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
10012841Sgabeblack@google.com             "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
10113044Sgabeblack@google.com             ipc);
10213044Sgabeblack@google.com    ipc = 0.0;
10313044Sgabeblack@google.com#else
10413044Sgabeblack@google.com    cprintf("%lli: %s progress event, total committed:%i, progress insts "
10513044Sgabeblack@google.com            "committed: %lli\n", curTick(), cpu->name(), temp,
10612841Sgabeblack@google.com            temp - lastNumInst);
10712841Sgabeblack@google.com#endif
10813044Sgabeblack@google.com    lastNumInst = temp;
10912841Sgabeblack@google.com
11013044Sgabeblack@google.com    if (_repeatEvent)
11112841Sgabeblack@google.com        cpu->schedule(this, curTick() + _interval);
11212841Sgabeblack@google.com}
11312841Sgabeblack@google.com
11413044Sgabeblack@google.comconst char *
11512841Sgabeblack@google.comCPUProgressEvent::description() const
11613044Sgabeblack@google.com{
11712841Sgabeblack@google.com    return "CPU Progress";
11812841Sgabeblack@google.com}
11912841Sgabeblack@google.com
12012841Sgabeblack@google.com#if FULL_SYSTEM
12112841Sgabeblack@google.comBaseCPU::BaseCPU(Params *p)
12212841Sgabeblack@google.com    : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id),
12313044Sgabeblack@google.com      interrupts(p->interrupts),
12412841Sgabeblack@google.com      numThreads(p->numThreads), system(p->system),
12512841Sgabeblack@google.com      phase(p->phase)
12612841Sgabeblack@google.com#else
12712841Sgabeblack@google.comBaseCPU::BaseCPU(Params *p)
12813044Sgabeblack@google.com    : MemObject(p), clock(p->clock), _cpuId(p->cpu_id),
12912841Sgabeblack@google.com      numThreads(p->numThreads), system(p->system),
13012841Sgabeblack@google.com      phase(p->phase)
13112841Sgabeblack@google.com#endif
13212841Sgabeblack@google.com{
13313141Sgabeblack@google.com//    currentTick = curTick();
13412841Sgabeblack@google.com
13512841Sgabeblack@google.com    // if Python did not provide a valid ID, do it here
13613044Sgabeblack@google.com    if (_cpuId == -1 ) {
13712841Sgabeblack@google.com        _cpuId = cpuList.size();
13813044Sgabeblack@google.com    }
13912841Sgabeblack@google.com
14013044Sgabeblack@google.com    // add self to global list of CPUs
14113044Sgabeblack@google.com    cpuList.push_back(this);
14213044Sgabeblack@google.com
14312841Sgabeblack@google.com    DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId);
14412841Sgabeblack@google.com
14512841Sgabeblack@google.com    if (numThreads > maxThreadsPerCPU)
14612841Sgabeblack@google.com        maxThreadsPerCPU = numThreads;
14712841Sgabeblack@google.com
14812841Sgabeblack@google.com    // allocate per-thread instruction-based event queues
14912841Sgabeblack@google.com    comInstEventQueue = new EventQueue *[numThreads];
15013044Sgabeblack@google.com    for (ThreadID tid = 0; tid < numThreads; ++tid)
15113044Sgabeblack@google.com        comInstEventQueue[tid] =
15213044Sgabeblack@google.com            new EventQueue("instruction-based event queue");
15313044Sgabeblack@google.com
15413141Sgabeblack@google.com    //
15513044Sgabeblack@google.com    // set up instruction-count-based termination events, if any
15612841Sgabeblack@google.com    //
15712841Sgabeblack@google.com    if (p->max_insts_any_thread != 0) {
15812945Sgabeblack@google.com        const char *cause = "a thread reached the max instruction count";
15912945Sgabeblack@google.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
16012945Sgabeblack@google.com            Event *event = new SimLoopExitEvent(cause, 0);
16112945Sgabeblack@google.com            comInstEventQueue[tid]->schedule(event, p->max_insts_any_thread);
16212945Sgabeblack@google.com        }
16312945Sgabeblack@google.com    }
16412841Sgabeblack@google.com
16513044Sgabeblack@google.com    if (p->max_insts_all_threads != 0) {
16613141Sgabeblack@google.com        const char *cause = "all threads reached the max instruction count";
16713044Sgabeblack@google.com
16812841Sgabeblack@google.com        // allocate & initialize shared downcounter: each event will
16912841Sgabeblack@google.com        // decrement this when triggered; simulation will terminate
17012841Sgabeblack@google.com        // when counter reaches 0
17112841Sgabeblack@google.com        int *counter = new int;
17212841Sgabeblack@google.com        *counter = numThreads;
17312841Sgabeblack@google.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
17412841Sgabeblack@google.com            Event *event = new CountedExitEvent(cause, *counter);
17512841Sgabeblack@google.com            comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads);
17612841Sgabeblack@google.com        }
17712841Sgabeblack@google.com    }
17812841Sgabeblack@google.com
17912841Sgabeblack@google.com    // allocate per-thread load-based event queues
18012841Sgabeblack@google.com    comLoadEventQueue = new EventQueue *[numThreads];
18112841Sgabeblack@google.com    for (ThreadID tid = 0; tid < numThreads; ++tid)
18212841Sgabeblack@google.com        comLoadEventQueue[tid] = new EventQueue("load-based event queue");
18312841Sgabeblack@google.com
18412841Sgabeblack@google.com    //
18512841Sgabeblack@google.com    // set up instruction-count-based termination events, if any
18612841Sgabeblack@google.com    //
18713044Sgabeblack@google.com    if (p->max_loads_any_thread != 0) {
18813044Sgabeblack@google.com        const char *cause = "a thread reached the max load count";
18913141Sgabeblack@google.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
19013141Sgabeblack@google.com            Event *event = new SimLoopExitEvent(cause, 0);
19113044Sgabeblack@google.com            comLoadEventQueue[tid]->schedule(event, p->max_loads_any_thread);
19213044Sgabeblack@google.com        }
19313044Sgabeblack@google.com    }
19413141Sgabeblack@google.com
19513141Sgabeblack@google.com    if (p->max_loads_all_threads != 0) {
19613044Sgabeblack@google.com        const char *cause = "all threads reached the max load count";
19712912Sgabeblack@google.com        // allocate & initialize shared downcounter: each event will
19813044Sgabeblack@google.com        // decrement this when triggered; simulation will terminate
19913141Sgabeblack@google.com        // when counter reaches 0
20013141Sgabeblack@google.com        int *counter = new int;
20113044Sgabeblack@google.com        *counter = numThreads;
20213044Sgabeblack@google.com        for (ThreadID tid = 0; tid < numThreads; ++tid) {
20312841Sgabeblack@google.com            Event *event = new CountedExitEvent(cause, *counter);
20412841Sgabeblack@google.com            comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads);
20512841Sgabeblack@google.com        }
20612841Sgabeblack@google.com    }
20712841Sgabeblack@google.com
20812841Sgabeblack@google.com    functionTracingEnabled = false;
20912841Sgabeblack@google.com    if (p->function_trace) {
21013044Sgabeblack@google.com        const string fname = csprintf("ftrace.%s", name());
21113044Sgabeblack@google.com        functionTraceStream = simout.find(fname);
21212841Sgabeblack@google.com        if (!functionTraceStream)
21312841Sgabeblack@google.com            functionTraceStream = simout.create(fname);
21412841Sgabeblack@google.com
21512841Sgabeblack@google.com        currentFunctionStart = currentFunctionEnd = 0;
21612841Sgabeblack@google.com        functionEntryTick = p->function_trace_start;
21712841Sgabeblack@google.com
21812841Sgabeblack@google.com        if (p->function_trace_start == 0) {
21913044Sgabeblack@google.com            functionTracingEnabled = true;
22012841Sgabeblack@google.com        } else {
22113044Sgabeblack@google.com            typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap;
22213044Sgabeblack@google.com            Event *event = new wrap(this, true);
22313044Sgabeblack@google.com            schedule(event, p->function_trace_start);
22413044Sgabeblack@google.com        }
22513044Sgabeblack@google.com    }
22612841Sgabeblack@google.com#if FULL_SYSTEM
22712841Sgabeblack@google.com    // Check if CPU model has interrupts connected. The CheckerCPU
22813044Sgabeblack@google.com    // cannot take interrupts directly for example.
22912841Sgabeblack@google.com    if (interrupts)
23013044Sgabeblack@google.com        interrupts->setCPU(this);
23112841Sgabeblack@google.com
23212841Sgabeblack@google.com    profileEvent = NULL;
23312841Sgabeblack@google.com    if (params()->profile)
23413044Sgabeblack@google.com        profileEvent = new ProfileEvent(this, params()->profile);
23512841Sgabeblack@google.com#endif
23613044Sgabeblack@google.com    tracer = params()->tracer;
23712841Sgabeblack@google.com}
23812841Sgabeblack@google.com
23912841Sgabeblack@google.comvoid
24012841Sgabeblack@google.comBaseCPU::enableFunctionTrace()
24112841Sgabeblack@google.com{
24212841Sgabeblack@google.com    functionTracingEnabled = true;
24313044Sgabeblack@google.com}
24412841Sgabeblack@google.com
24512841Sgabeblack@google.comBaseCPU::~BaseCPU()
24612841Sgabeblack@google.com{
24712841Sgabeblack@google.com}
24812841Sgabeblack@google.com
24913044Sgabeblack@google.comvoid
25012841Sgabeblack@google.comBaseCPU::init()
25112841Sgabeblack@google.com{
25212841Sgabeblack@google.com    if (!params()->defer_registration)
25312841Sgabeblack@google.com        registerThreadContexts();
25413044Sgabeblack@google.com}
25512841Sgabeblack@google.com
25612841Sgabeblack@google.comvoid
25712841Sgabeblack@google.comBaseCPU::startup()
25812841Sgabeblack@google.com{
25913044Sgabeblack@google.com#if FULL_SYSTEM
26012841Sgabeblack@google.com    if (!params()->defer_registration && profileEvent)
26112841Sgabeblack@google.com        schedule(profileEvent, curTick());
26212841Sgabeblack@google.com#endif
26312841Sgabeblack@google.com
26412841Sgabeblack@google.com    if (params()->progress_interval) {
26513141Sgabeblack@google.com        Tick num_ticks = ticks(params()->progress_interval);
26612841Sgabeblack@google.com
26712841Sgabeblack@google.com        new CPUProgressEvent(this, num_ticks);
26812841Sgabeblack@google.com    }
26912841Sgabeblack@google.com}
27013141Sgabeblack@google.com
27112841Sgabeblack@google.com
27212841Sgabeblack@google.comvoid
27312841Sgabeblack@google.comBaseCPU::regStats()
27412841Sgabeblack@google.com{
27513141Sgabeblack@google.com    using namespace Stats;
27612841Sgabeblack@google.com
27712841Sgabeblack@google.com    numCycles
27813044Sgabeblack@google.com        .name(name() + ".numCycles")
27912841Sgabeblack@google.com        .desc("number of cpu cycles simulated")
28013044Sgabeblack@google.com        ;
28112841Sgabeblack@google.com
28213044Sgabeblack@google.com    numWorkItemsStarted
28313044Sgabeblack@google.com        .name(name() + ".numWorkItemsStarted")
28413044Sgabeblack@google.com        .desc("number of work items this cpu started")
28512841Sgabeblack@google.com        ;
28612841Sgabeblack@google.com
28712841Sgabeblack@google.com    numWorkItemsCompleted
28812841Sgabeblack@google.com        .name(name() + ".numWorkItemsCompleted")
28912841Sgabeblack@google.com        .desc("number of work items this cpu completed")
29012841Sgabeblack@google.com        ;
29112841Sgabeblack@google.com
29213044Sgabeblack@google.com    int size = threadContexts.size();
29313044Sgabeblack@google.com    if (size > 1) {
29413044Sgabeblack@google.com        for (int i = 0; i < size; ++i) {
29513044Sgabeblack@google.com            stringstream namestr;
29613141Sgabeblack@google.com            ccprintf(namestr, "%s.ctx%d", name(), i);
29713141Sgabeblack@google.com            threadContexts[i]->regStats(namestr.str());
29813044Sgabeblack@google.com        }
29913141Sgabeblack@google.com    } else if (size == 1)
30013141Sgabeblack@google.com        threadContexts[0]->regStats(name());
30113044Sgabeblack@google.com
30213141Sgabeblack@google.com#if FULL_SYSTEM
30313141Sgabeblack@google.com#endif
30413044Sgabeblack@google.com}
30513141Sgabeblack@google.com
30612841Sgabeblack@google.comTick
30712841Sgabeblack@google.comBaseCPU::nextCycle()
30813044Sgabeblack@google.com{
30913044Sgabeblack@google.com    Tick next_tick = curTick() - phase + clock - 1;
31013044Sgabeblack@google.com    next_tick -= (next_tick % clock);
31112841Sgabeblack@google.com    next_tick += phase;
31213044Sgabeblack@google.com    return next_tick;
31313044Sgabeblack@google.com}
31413044Sgabeblack@google.com
31513044Sgabeblack@google.comTick
31613141Sgabeblack@google.comBaseCPU::nextCycle(Tick begin_tick)
31713141Sgabeblack@google.com{
31813141Sgabeblack@google.com    Tick next_tick = begin_tick;
31913141Sgabeblack@google.com    if (next_tick % clock != 0)
32012841Sgabeblack@google.com        next_tick = next_tick - (next_tick % clock) + clock;
32112841Sgabeblack@google.com    next_tick += phase;
32212841Sgabeblack@google.com
32312841Sgabeblack@google.com    assert(next_tick >= curTick());
32412841Sgabeblack@google.com    return next_tick;
32512841Sgabeblack@google.com}
32612841Sgabeblack@google.com
32712841Sgabeblack@google.comvoid
32812841Sgabeblack@google.comBaseCPU::registerThreadContexts()
32912841Sgabeblack@google.com{
33012841Sgabeblack@google.com    ThreadID size = threadContexts.size();
33113044Sgabeblack@google.com    for (ThreadID tid = 0; tid < size; ++tid) {
33213044Sgabeblack@google.com        ThreadContext *tc = threadContexts[tid];
33313141Sgabeblack@google.com
33413141Sgabeblack@google.com        /** This is so that contextId and cpuId match where there is a
33513044Sgabeblack@google.com         * 1cpu:1context relationship.  Otherwise, the order of registration
33613044Sgabeblack@google.com         * could affect the assignment and cpu 1 could have context id 3, for
33713044Sgabeblack@google.com         * example.  We may even want to do something like this for SMT so that
33813141Sgabeblack@google.com         * cpu 0 has the lowest thread contexts and cpu N has the highest, but
33913141Sgabeblack@google.com         * I'll just do this for now
34013044Sgabeblack@google.com         */
34112912Sgabeblack@google.com        if (numThreads == 1)
34212912Sgabeblack@google.com            tc->setContextId(system->registerThreadContext(tc, _cpuId));
34313044Sgabeblack@google.com        else
34413141Sgabeblack@google.com            tc->setContextId(system->registerThreadContext(tc));
34513141Sgabeblack@google.com#if !FULL_SYSTEM
34613044Sgabeblack@google.com        tc->getProcessPtr()->assignThreadContext(tc->contextId());
34713044Sgabeblack@google.com#endif
34812841Sgabeblack@google.com    }
34912841Sgabeblack@google.com}
35012841Sgabeblack@google.com
35112841Sgabeblack@google.com
35212841Sgabeblack@google.comint
35312841Sgabeblack@google.comBaseCPU::findContext(ThreadContext *tc)
35412841Sgabeblack@google.com{
35513044Sgabeblack@google.com    ThreadID size = threadContexts.size();
35613044Sgabeblack@google.com    for (ThreadID tid = 0; tid < size; ++tid) {
35712841Sgabeblack@google.com        if (tc == threadContexts[tid])
35812841Sgabeblack@google.com            return tid;
35912841Sgabeblack@google.com    }
36012841Sgabeblack@google.com    return 0;
36112841Sgabeblack@google.com}
36212841Sgabeblack@google.com
36312841Sgabeblack@google.comvoid
36413044Sgabeblack@google.comBaseCPU::switchOut()
36512841Sgabeblack@google.com{
36613044Sgabeblack@google.com//    panic("This CPU doesn't support sampling!");
36713044Sgabeblack@google.com#if FULL_SYSTEM
36813044Sgabeblack@google.com    if (profileEvent && profileEvent->scheduled())
36913044Sgabeblack@google.com        deschedule(profileEvent);
37013044Sgabeblack@google.com#endif
37112841Sgabeblack@google.com}
37212841Sgabeblack@google.com
37313044Sgabeblack@google.comvoid
37412841Sgabeblack@google.comBaseCPU::takeOverFrom(BaseCPU *oldCPU)
37513044Sgabeblack@google.com{
37612841Sgabeblack@google.com    Port *ic = getPort("icache_port");
37712841Sgabeblack@google.com    Port *dc = getPort("dcache_port");
37812841Sgabeblack@google.com    assert(threadContexts.size() == oldCPU->threadContexts.size());
37913044Sgabeblack@google.com
38012841Sgabeblack@google.com    _cpuId = oldCPU->cpuId();
38113044Sgabeblack@google.com
38212841Sgabeblack@google.com    ThreadID size = threadContexts.size();
38312841Sgabeblack@google.com    for (ThreadID i = 0; i < size; ++i) {
38412841Sgabeblack@google.com        ThreadContext *newTC = threadContexts[i];
38512841Sgabeblack@google.com        ThreadContext *oldTC = oldCPU->threadContexts[i];
38612841Sgabeblack@google.com
38712841Sgabeblack@google.com        newTC->takeOverFrom(oldTC);
38813044Sgabeblack@google.com
38912841Sgabeblack@google.com        CpuEvent::replaceThreadContext(oldTC, newTC);
39012841Sgabeblack@google.com
39112841Sgabeblack@google.com        assert(newTC->contextId() == oldTC->contextId());
39212841Sgabeblack@google.com        assert(newTC->threadId() == oldTC->threadId());
39312841Sgabeblack@google.com        system->replaceThreadContext(newTC, newTC->contextId());
39413044Sgabeblack@google.com
39512841Sgabeblack@google.com        /* This code no longer works since the zero register (e.g.,
39612841Sgabeblack@google.com         * r31 on Alpha) doesn't necessarily contain zero at this
39712841Sgabeblack@google.com         * point.
39812841Sgabeblack@google.com           if (DTRACE(Context))
39913044Sgabeblack@google.com            ThreadContext::compare(oldTC, newTC);
40012841Sgabeblack@google.com        */
40112841Sgabeblack@google.com
40212841Sgabeblack@google.com        Port  *old_itb_port, *old_dtb_port, *new_itb_port, *new_dtb_port;
40312841Sgabeblack@google.com        old_itb_port = oldTC->getITBPtr()->getPort();
40413044Sgabeblack@google.com        old_dtb_port = oldTC->getDTBPtr()->getPort();
40512841Sgabeblack@google.com        new_itb_port = newTC->getITBPtr()->getPort();
40612841Sgabeblack@google.com        new_dtb_port = newTC->getDTBPtr()->getPort();
40712841Sgabeblack@google.com
40812841Sgabeblack@google.com        // Move over any table walker ports if they exist
40912841Sgabeblack@google.com        if (new_itb_port && !new_itb_port->isConnected()) {
41013141Sgabeblack@google.com            assert(old_itb_port);
41112841Sgabeblack@google.com            Port *peer = old_itb_port->getPeer();;
41212841Sgabeblack@google.com            new_itb_port->setPeer(peer);
41312841Sgabeblack@google.com            peer->setPeer(new_itb_port);
41412841Sgabeblack@google.com        }
41513141Sgabeblack@google.com        if (new_dtb_port && !new_dtb_port->isConnected()) {
41612841Sgabeblack@google.com            assert(old_dtb_port);
41712841Sgabeblack@google.com            Port *peer = old_dtb_port->getPeer();;
41812841Sgabeblack@google.com            new_dtb_port->setPeer(peer);
41912841Sgabeblack@google.com            peer->setPeer(new_dtb_port);
42013141Sgabeblack@google.com        }
42112841Sgabeblack@google.com
42212841Sgabeblack@google.com#if USE_CHECKER
42313044Sgabeblack@google.com        Port *old_checker_itb_port, *old_checker_dtb_port;
42412841Sgabeblack@google.com        Port *new_checker_itb_port, *new_checker_dtb_port;
42513044Sgabeblack@google.com
42612841Sgabeblack@google.com        CheckerCPU *oldChecker =
42713044Sgabeblack@google.com            dynamic_cast<CheckerCPU*>(oldTC->getCheckerCpuPtr());
42813044Sgabeblack@google.com        CheckerCPU *newChecker =
42913044Sgabeblack@google.com            dynamic_cast<CheckerCPU*>(newTC->getCheckerCpuPtr());
43012841Sgabeblack@google.com        old_checker_itb_port = oldChecker->getITBPtr()->getPort();
43112841Sgabeblack@google.com        old_checker_dtb_port = oldChecker->getDTBPtr()->getPort();
43212841Sgabeblack@google.com        new_checker_itb_port = newChecker->getITBPtr()->getPort();
43312841Sgabeblack@google.com        new_checker_dtb_port = newChecker->getDTBPtr()->getPort();
43412841Sgabeblack@google.com
43512841Sgabeblack@google.com        // Move over any table walker ports if they exist for checker
43612841Sgabeblack@google.com        if (new_checker_itb_port && !new_checker_itb_port->isConnected()) {
43713044Sgabeblack@google.com            assert(old_checker_itb_port);
43813044Sgabeblack@google.com            Port *peer = old_checker_itb_port->getPeer();;
43913044Sgabeblack@google.com            new_checker_itb_port->setPeer(peer);
44013044Sgabeblack@google.com            peer->setPeer(new_checker_itb_port);
44113044Sgabeblack@google.com        }
44213044Sgabeblack@google.com        if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) {
44313044Sgabeblack@google.com            assert(old_checker_dtb_port);
44413044Sgabeblack@google.com            Port *peer = old_checker_dtb_port->getPeer();;
44513044Sgabeblack@google.com            new_checker_dtb_port->setPeer(peer);
44612841Sgabeblack@google.com            peer->setPeer(new_checker_dtb_port);
44712841Sgabeblack@google.com        }
44813044Sgabeblack@google.com#endif
44913044Sgabeblack@google.com
45013044Sgabeblack@google.com    }
45112841Sgabeblack@google.com
45213044Sgabeblack@google.com#if FULL_SYSTEM
45313044Sgabeblack@google.com    interrupts = oldCPU->interrupts;
45413044Sgabeblack@google.com    interrupts->setCPU(this);
45513044Sgabeblack@google.com
45613141Sgabeblack@google.com    for (ThreadID i = 0; i < size; ++i)
45713141Sgabeblack@google.com        threadContexts[i]->profileClear();
45813141Sgabeblack@google.com
45913141Sgabeblack@google.com    if (profileEvent)
46012841Sgabeblack@google.com        schedule(profileEvent, curTick());
46112841Sgabeblack@google.com#endif
46212841Sgabeblack@google.com
46312841Sgabeblack@google.com    // Connect new CPU to old CPU's memory only if new CPU isn't
46412841Sgabeblack@google.com    // connected to anything.  Also connect old CPU's memory to new
46512841Sgabeblack@google.com    // CPU.
46612841Sgabeblack@google.com    if (!ic->isConnected()) {
46712841Sgabeblack@google.com        Port *peer = oldCPU->getPort("icache_port")->getPeer();
46812841Sgabeblack@google.com        ic->setPeer(peer);
469        peer->setPeer(ic);
470    }
471
472    if (!dc->isConnected()) {
473        Port *peer = oldCPU->getPort("dcache_port")->getPeer();
474        dc->setPeer(peer);
475        peer->setPeer(dc);
476    }
477}
478
479
480#if FULL_SYSTEM
481BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval)
482    : cpu(_cpu), interval(_interval)
483{ }
484
485void
486BaseCPU::ProfileEvent::process()
487{
488    ThreadID size = cpu->threadContexts.size();
489    for (ThreadID i = 0; i < size; ++i) {
490        ThreadContext *tc = cpu->threadContexts[i];
491        tc->profileSample();
492    }
493
494    cpu->schedule(this, curTick() + interval);
495}
496
497void
498BaseCPU::serialize(std::ostream &os)
499{
500    SERIALIZE_SCALAR(instCnt);
501    interrupts->serialize(os);
502}
503
504void
505BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
506{
507    UNSERIALIZE_SCALAR(instCnt);
508    interrupts->unserialize(cp, section);
509}
510
511#endif // FULL_SYSTEM
512
513void
514BaseCPU::traceFunctionsInternal(Addr pc)
515{
516    if (!debugSymbolTable)
517        return;
518
519    // if pc enters different function, print new function symbol and
520    // update saved range.  Otherwise do nothing.
521    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
522        string sym_str;
523        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
524                                                         currentFunctionStart,
525                                                         currentFunctionEnd);
526
527        if (!found) {
528            // no symbol found: use addr as label
529            sym_str = csprintf("0x%x", pc);
530            currentFunctionStart = pc;
531            currentFunctionEnd = pc + 1;
532        }
533
534        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
535                 curTick() - functionEntryTick, curTick(), sym_str);
536        functionEntryTick = curTick();
537    }
538}
539
540bool
541BaseCPU::CpuPort::recvTiming(PacketPtr pkt)
542{
543    panic("BaseCPU doesn't expect recvTiming callback!");
544    return true;
545}
546
547void
548BaseCPU::CpuPort::recvRetry()
549{
550    panic("BaseCPU doesn't expect recvRetry callback!");
551}
552
553Tick
554BaseCPU::CpuPort::recvAtomic(PacketPtr pkt)
555{
556    panic("BaseCPU doesn't expect recvAtomic callback!");
557    return curTick();
558}
559
560void
561BaseCPU::CpuPort::recvFunctional(PacketPtr pkt)
562{
563    // No internal storage to update (in the general case). In the
564    // long term this should never be called, but that assumed a split
565    // into master/slave and request/response.
566}
567
568void
569BaseCPU::CpuPort::recvRangeChange()
570{
571}
572