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