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