base.cc revision 2367
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 292756Sksewell@umich.edu#include <iostream> 301689SN/A#include <string> 311689SN/A#include <sstream> 321858SN/A 332733Sktlim@umich.edu#include "base/cprintf.hh" 341858SN/A#include "base/loader/symtab.hh" 351858SN/A#include "base/misc.hh" 362356SN/A#include "base/output.hh" 371060SN/A#include "cpu/base.hh" 381060SN/A#include "cpu/exec_context.hh" 391060SN/A#include "cpu/profile.hh" 401060SN/A#include "cpu/sampler/sampler.hh" 411060SN/A#include "sim/param.hh" 422325SN/A#include "sim/process.hh" 432683Sktlim@umich.edu#include "sim/sim_events.hh" 442680Sktlim@umich.edu#include "sim/system.hh" 452817Sksewell@umich.edu 461717SN/A#include "base/trace.hh" 471060SN/A 482325SN/A// Hack 492292SN/A#include "sim/stat_control.hh" 502292SN/A 512794Sktlim@umich.eduusing namespace std; 522794Sktlim@umich.edu 532794Sktlim@umich.eduvector<BaseCPU *> BaseCPU::cpuList; 542794Sktlim@umich.edu 551060SN/A// This variable reflects the max number of threads in any CPU. Be 562669Sktlim@umich.edu// careful to only use it once all the CPUs that you care about have 571060SN/A// been initialized 582733Sktlim@umich.eduint maxThreadsPerCPU = 1; 592292SN/A 601060SN/Avoid 611060SN/ACPUProgressEvent::process() 621060SN/A{ 632292SN/A Counter temp = cpu->totalInstructions(); 642733Sktlim@umich.edu#ifndef NDEBUG 652292SN/A double ipc = double(temp - lastNumInst) / (interval / cpu->cycles(1)); 662292SN/A 672292SN/A DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n", 682292SN/A cpu->name(), temp - lastNumInst, ipc); 691060SN/A ipc = 0.0; 701755SN/A#else 711060SN/A cprintf("%lli: %s progress event, instructions committed: %lli\n", 721060SN/A curTick, cpu->name(), temp - lastNumInst); 731060SN/A#endif 741060SN/A lastNumInst = temp; 751060SN/A schedule(curTick + interval); 761060SN/A} 771755SN/A 781060SN/Aconst char * 791060SN/ACPUProgressEvent::description() 801060SN/A{ 811060SN/A return "CPU Progress event"; 821060SN/A} 831060SN/A 841755SN/A#if FULL_SYSTEM 851060SN/ABaseCPU::BaseCPU(Params *p) 861755SN/A : SimObject(p->name), clock(p->clock), checkInterrupts(true), 871060SN/A params(p), number_of_threads(p->numberOfThreads), system(p->system) 881060SN/A#else 891060SN/ABaseCPU::BaseCPU(Params *p) 902829Sksewell@umich.edu : SimObject(p->name), clock(p->clock), params(p), 913221Sktlim@umich.edu number_of_threads(p->numberOfThreads) 922829Sksewell@umich.edu#endif 932829Sksewell@umich.edu{ 942829Sksewell@umich.edu// currentTick = curTick; 952829Sksewell@umich.edu DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 962829Sksewell@umich.edu 972829Sksewell@umich.edu // add self to global list of CPUs 982829Sksewell@umich.edu cpuList.push_back(this); 992829Sksewell@umich.edu 1002829Sksewell@umich.edu DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 1012829Sksewell@umich.edu this); 1022829Sksewell@umich.edu 1032829Sksewell@umich.edu if (number_of_threads > maxThreadsPerCPU) 1042829Sksewell@umich.edu maxThreadsPerCPU = number_of_threads; 1052829Sksewell@umich.edu 1062829Sksewell@umich.edu // allocate per-thread instruction-based event queues 1072829Sksewell@umich.edu comInstEventQueue = new EventQueue *[number_of_threads]; 1082829Sksewell@umich.edu for (int i = 0; i < number_of_threads; ++i) 1092829Sksewell@umich.edu comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 1102829Sksewell@umich.edu 1112829Sksewell@umich.edu // 1122829Sksewell@umich.edu // set up instruction-count-based termination events, if any 1132829Sksewell@umich.edu // 1142829Sksewell@umich.edu if (p->max_insts_any_thread != 0) 1152829Sksewell@umich.edu for (int i = 0; i < number_of_threads; ++i) 1162829Sksewell@umich.edu new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 1172829Sksewell@umich.edu "a thread reached the max instruction count"); 1182829Sksewell@umich.edu 1192875Sksewell@umich.edu if (p->max_insts_all_threads != 0) { 1203859Sbinkertn@umich.edu // allocate & initialize shared downcounter: each event will 1212875Sksewell@umich.edu // decrement this when triggered; simulation will terminate 1222875Sksewell@umich.edu // when counter reaches 0 1232875Sksewell@umich.edu int *counter = new int; 1242875Sksewell@umich.edu *counter = number_of_threads; 1252875Sksewell@umich.edu for (int i = 0; i < number_of_threads; ++i) 1262875Sksewell@umich.edu new CountedExitEvent(comInstEventQueue[i], 1273859Sbinkertn@umich.edu "all threads reached the max instruction count", 1282875Sksewell@umich.edu p->max_insts_all_threads, *counter); 1292875Sksewell@umich.edu } 1302875Sksewell@umich.edu 1313859Sbinkertn@umich.edu // allocate per-thread load-based event queues 1322875Sksewell@umich.edu comLoadEventQueue = new EventQueue *[number_of_threads]; 1332875Sksewell@umich.edu for (int i = 0; i < number_of_threads; ++i) 1342875Sksewell@umich.edu comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1352875Sksewell@umich.edu 1362875Sksewell@umich.edu // 1372875Sksewell@umich.edu // set up instruction-count-based termination events, if any 1382875Sksewell@umich.edu // 1393221Sktlim@umich.edu if (p->max_loads_any_thread != 0) 1403221Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 1412875Sksewell@umich.edu new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 1422875Sksewell@umich.edu "a thread reached the max load count"); 1432875Sksewell@umich.edu 1442875Sksewell@umich.edu if (p->max_loads_all_threads != 0) { 1452875Sksewell@umich.edu // allocate & initialize shared downcounter: each event will 1462875Sksewell@umich.edu // decrement this when triggered; simulation will terminate 1472875Sksewell@umich.edu // when counter reaches 0 1482875Sksewell@umich.edu int *counter = new int; 1492875Sksewell@umich.edu *counter = number_of_threads; 1502875Sksewell@umich.edu for (int i = 0; i < number_of_threads; ++i) 1512292SN/A new CountedExitEvent(comLoadEventQueue[i], 1522733Sktlim@umich.edu "all threads reached the max load count", 1533781Sgblack@eecs.umich.edu p->max_loads_all_threads, *counter); 1543781Sgblack@eecs.umich.edu } 1553781Sgblack@eecs.umich.edu 1563781Sgblack@eecs.umich.edu if (p->stats_reset_inst != 0) { 1571060SN/A Stats::SetupEvent(Stats::Reset, p->stats_reset_inst, 0, comInstEventQueue[0]); 1582292SN/A cprintf("Stats reset event scheduled for %lli insts\n", 1591060SN/A p->stats_reset_inst); 1601060SN/A } 1611060SN/A 1621060SN/A#if FULL_SYSTEM 1631060SN/A memset(interrupts, 0, sizeof(interrupts)); 1641060SN/A intstatus = 0; 1652292SN/A#endif 1661060SN/A 1672831Sksewell@umich.edu functionTracingEnabled = false; 1682292SN/A if (p->functionTrace) { 1692292SN/A functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1701060SN/A currentFunctionStart = currentFunctionEnd = 0; 1712292SN/A functionEntryTick = p->functionTraceStart; 1722292SN/A 1732292SN/A if (p->functionTraceStart == 0) { 1741060SN/A functionTracingEnabled = true; 1752831Sksewell@umich.edu } else { 1762292SN/A Event *e = 1772292SN/A new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1782292SN/A true); 1792292SN/A e->schedule(p->functionTraceStart); 1801060SN/A } 1812873Sktlim@umich.edu } 1822873Sktlim@umich.edu#if FULL_SYSTEM 1832873Sktlim@umich.edu profileEvent = NULL; 1842873Sktlim@umich.edu if (params->profile) 1852873Sktlim@umich.edu profileEvent = new ProfileEvent(this, params->profile); 1862873Sktlim@umich.edu#endif 1872873Sktlim@umich.edu} 1882873Sktlim@umich.edu 1891060SN/ABaseCPU::Params::Params() 1901060SN/A{ 1911858SN/A#if FULL_SYSTEM 1922292SN/A profile = false; 1931060SN/A#endif 1941060SN/A checker = NULL; 1952843Sktlim@umich.edu} 1962316SN/A 1972316SN/Avoid 1981060SN/ABaseCPU::enableFunctionTrace() 1993221Sktlim@umich.edu{ 2003221Sktlim@umich.edu functionTracingEnabled = true; 2013221Sktlim@umich.edu} 2023221Sktlim@umich.edu 2033221Sktlim@umich.eduBaseCPU::~BaseCPU() 2041681SN/A{ 2052733Sktlim@umich.edu} 2062733Sktlim@umich.edu 2072794Sktlim@umich.eduvoid 2082733Sktlim@umich.eduBaseCPU::init() 2092316SN/A{ 2102316SN/A if (!params->deferRegistration) 2112316SN/A registerExecContexts(); 2122316SN/A} 2132316SN/A 2142794Sktlim@umich.eduvoid 2152794Sktlim@umich.eduBaseCPU::startup() 2162794Sktlim@umich.edu{ 2172316SN/A#if FULL_SYSTEM 2182316SN/A if (!params->deferRegistration && profileEvent) 2191858SN/A profileEvent->schedule(curTick); 2202292SN/A#endif 2212292SN/A 2221681SN/A if (params->progress_interval) { 2231681SN/A new CPUProgressEvent(&mainEventQueue, params->progress_interval, 2242325SN/A this); 2252325SN/A } 2262325SN/A} 2271060SN/A 2282292SN/A 2292292SN/Avoid 2302292SN/ABaseCPU::regStats() 2312292SN/A{ 2322292SN/A using namespace Stats; 2332292SN/A 2341060SN/A numCycles 2351060SN/A .name(name() + ".numCycles") 2361060SN/A .desc("number of cpu cycles simulated") 2371060SN/A ; 2381060SN/A 2391060SN/A int size = execContexts.size(); 2401060SN/A if (size > 1) { 2411060SN/A for (int i = 0; i < size; ++i) { 2421060SN/A stringstream namestr; 2431060SN/A ccprintf(namestr, "%s.ctx%d", name(), i); 2441060SN/A execContexts[i]->regStats(namestr.str()); 2452292SN/A } 2461060SN/A } else if (size == 1) 2471060SN/A execContexts[0]->regStats(name()); 2481060SN/A 2491060SN/A#if FULL_SYSTEM 2501060SN/A#endif 2511060SN/A} 2521060SN/A 2531060SN/A 2542292SN/Avoid 2552292SN/ABaseCPU::registerExecContexts() 2562292SN/A{ 2572292SN/A for (int i = 0; i < execContexts.size(); ++i) { 2582292SN/A ExecContext *xc = execContexts[i]; 2592307SN/A 2602831Sksewell@umich.edu if (xc->status() == ExecContext::Suspended) { 2612831Sksewell@umich.edu#if FULL_SYSTEM 2622831Sksewell@umich.edu int id = params->cpu_id; 2632831Sksewell@umich.edu if (id != -1) 2642831Sksewell@umich.edu id += i; 2652831Sksewell@umich.edu 2662292SN/A xc->setCpuId(system->registerExecContext(xc, id)); 2672307SN/A#else 2682292SN/A xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); 2692292SN/A#endif 2702316SN/A } 2712292SN/A } 2722292SN/A} 2732292SN/A 2742292SN/A 2752292SN/Avoid 2762292SN/ABaseCPU::switchOut(Sampler *sampler) 2771060SN/A{ 2782292SN/A// panic("This CPU doesn't support sampling!"); 2792292SN/A#if FULL_SYSTEM 2801060SN/A if (profileEvent && profileEvent->scheduled()) 2812292SN/A profileEvent->deschedule(); 2822307SN/A#endif 2832292SN/A} 2842292SN/A 2852292SN/Avoid 2862325SN/ABaseCPU::takeOverFrom(BaseCPU *oldCPU) 2872292SN/A{ 2882292SN/A// currentTick = oldCPU->currentTick; 2892292SN/A assert(execContexts.size() == oldCPU->execContexts.size()); 2902325SN/A 2912292SN/A for (int i = 0; i < execContexts.size(); ++i) { 2922292SN/A ExecContext *newXC = execContexts[i]; 2932292SN/A ExecContext *oldXC = oldCPU->execContexts[i]; 2942292SN/A 2952292SN/A newXC->takeOverFrom(oldXC); 2962292SN/A assert(newXC->readCpuId() == oldXC->readCpuId()); 2972292SN/A#if FULL_SYSTEM 2982292SN/A system->replaceExecContext(newXC, newXC->readCpuId()); 2992292SN/A#else 3002292SN/A assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); 3012292SN/A newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); 3022325SN/A#endif 3032292SN/A 3042292SN/A// TheISA::compareXCs(oldXC, newXC); 3052292SN/A } 3062325SN/A 3072292SN/A#if FULL_SYSTEM 3082292SN/A for (int i = 0; i < TheISA::NumInterruptLevels; ++i) 3092292SN/A interrupts[i] = oldCPU->interrupts[i]; 3102292SN/A intstatus = oldCPU->intstatus; 3112292SN/A checkInterrupts = oldCPU->checkInterrupts; 3122292SN/A 3132292SN/A// for (int i = 0; i < execContexts.size(); ++i) 3142292SN/A// execContexts[i]->profileClear(); 3153221Sktlim@umich.edu 3163221Sktlim@umich.edu // The Sampler must take care of this! 3173221Sktlim@umich.edu// if (profileEvent) 3182292SN/A// profileEvent->schedule(curTick); 3192292SN/A#endif 3202292SN/A} 3212292SN/A 3222292SN/A 3232292SN/A#if FULL_SYSTEM 3242292SN/ABaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 3252292SN/A : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 3262292SN/A{ } 3271060SN/A 3282292SN/Avoid 3291060SN/ABaseCPU::ProfileEvent::process() 3301060SN/A{ 3312292SN/A for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 3322292SN/A ExecContext *xc = cpu->execContexts[i]; 3332292SN/A xc->profileSample(); 3342829Sksewell@umich.edu } 3352829Sksewell@umich.edu 3363093Sksewell@umich.edu schedule(curTick + interval); 3373093Sksewell@umich.edu} 3383093Sksewell@umich.edu 3393093Sksewell@umich.eduvoid 3403093Sksewell@umich.eduBaseCPU::post_interrupt(int int_num, int index) 3412292SN/A{ 3421060SN/A DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 3431060SN/A 3441060SN/A if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 3451755SN/A panic("int_num out of bounds\n"); 3461060SN/A 3471060SN/A if (index < 0 || index >= sizeof(uint64_t) * 8) 3481060SN/A panic("int_num out of bounds\n"); 3491060SN/A 3501060SN/A checkInterrupts = true; 3511755SN/A interrupts[int_num] |= 1 << index; 3521062SN/A intstatus |= (ULL(1) << int_num); 3532733Sktlim@umich.edu} 3542292SN/A 3552733Sktlim@umich.eduvoid 3562292SN/ABaseCPU::clear_interrupt(int int_num, int index) 3572292SN/A{ 3582292SN/A DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 3592292SN/A 3602292SN/A if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 3612292SN/A panic("int_num out of bounds\n"); 3622292SN/A 3632292SN/A if (index < 0 || index >= sizeof(uint64_t) * 8) 3642292SN/A panic("int_num out of bounds\n"); 3652292SN/A 3662292SN/A interrupts[int_num] &= ~(1 << index); 3672292SN/A if (interrupts[int_num] == 0) 3682292SN/A intstatus &= ~(ULL(1) << int_num); 3692292SN/A} 3702292SN/A 3712292SN/Avoid 3722292SN/ABaseCPU::clear_interrupts() 3732292SN/A{ 3742292SN/A DPRINTF(Interrupt, "Interrupts all cleared\n"); 3752292SN/A 3762292SN/A memset(interrupts, 0, sizeof(interrupts)); 3772292SN/A intstatus = 0; 3782292SN/A} 3792292SN/A 3802292SN/A 3812292SN/Avoid 3822292SN/ABaseCPU::serialize(std::ostream &os) 3832292SN/A{ 3842292SN/A SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 3852292SN/A SERIALIZE_SCALAR(intstatus); 3862292SN/A} 3872292SN/A 3882292SN/Avoid 3892292SN/ABaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 3902292SN/A{ 3912292SN/A UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 3922292SN/A UNSERIALIZE_SCALAR(intstatus); 3932292SN/A} 3942292SN/A 3952292SN/A#endif // FULL_SYSTEM 3962292SN/A 3972292SN/Avoid 3982292SN/ABaseCPU::traceFunctionsInternal(Addr pc) 3992292SN/A{ 4002292SN/A if (!debugSymbolTable) 4012292SN/A return; 4022292SN/A 4032292SN/A // if pc enters different function, print new function symbol and 4042292SN/A // update saved range. Otherwise do nothing. 4051062SN/A if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 4061062SN/A string sym_str; 4071062SN/A bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 4082871Sktlim@umich.edu currentFunctionStart, 4092871Sktlim@umich.edu currentFunctionEnd); 4102871Sktlim@umich.edu 4112871Sktlim@umich.edu if (!found) { 4122871Sktlim@umich.edu // no symbol found: use addr as label 4132871Sktlim@umich.edu sym_str = csprintf("0x%x", pc); 4142871Sktlim@umich.edu currentFunctionStart = pc; 4152871Sktlim@umich.edu currentFunctionEnd = pc + 1; 4162871Sktlim@umich.edu } 4172871Sktlim@umich.edu 4182871Sktlim@umich.edu ccprintf(*functionTraceStream, " (%d)\n%d: %s", 4192871Sktlim@umich.edu curTick - functionEntryTick, curTick, sym_str); 4201062SN/A functionEntryTick = curTick; 4211755SN/A } 4221060SN/A} 4232733Sktlim@umich.edu 4241060SN/A 4252292SN/ADEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 4262292SN/A