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 §ion) 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