base.cc revision 1917
12SN/A/* 21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292SN/A#include <iostream> 302SN/A#include <string> 312439SN/A#include <sstream> 322984Sgblack@eecs.umich.edu 33146SN/A#include "base/cprintf.hh" 34146SN/A#include "base/loader/symtab.hh" 35146SN/A#include "base/misc.hh" 36146SN/A#include "base/output.hh" 37146SN/A#include "cpu/base.hh" 38146SN/A#include "cpu/exec_context.hh" 391717SN/A#include "cpu/sampler/sampler.hh" 40146SN/A#include "sim/param.hh" 411717SN/A#include "sim/sim_events.hh" 42146SN/A 431977SN/A#include "base/trace.hh" 442623SN/A 452683Sktlim@umich.eduusing namespace std; 461717SN/A 47146SN/Avector<BaseCPU *> BaseCPU::cpuList; 482683Sktlim@umich.edu 491917SN/A// This variable reflects the max number of threads in any CPU. Be 502592SN/A// careful to only use it once all the CPUs that you care about have 512683Sktlim@umich.edu// been initialized 522036SN/Aint maxThreadsPerCPU = 1; 53146SN/A 5456SN/A#if FULL_SYSTEM 5556SN/ABaseCPU::BaseCPU(Params *p) 5656SN/A : SimObject(p->name), clock(p->clock), checkInterrupts(true), 57695SN/A params(p), number_of_threads(p->numberOfThreads), system(p->system) 582901Ssaidi@eecs.umich.edu#else 592SN/ABaseCPU::BaseCPU(Params *p) 601858SN/A : SimObject(p->name), clock(p->clock), params(p), 6156SN/A number_of_threads(p->numberOfThreads) 622171SN/A#endif 632170SN/A{ 642170SN/A DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 65146SN/A 662462SN/A // add self to global list of CPUs 67146SN/A cpuList.push_back(this); 682SN/A 692SN/A DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 702449SN/A this); 711355SN/A 722623SN/A if (number_of_threads > maxThreadsPerCPU) 732683Sktlim@umich.edu maxThreadsPerCPU = number_of_threads; 74224SN/A 751858SN/A // allocate per-thread instruction-based event queues 762683Sktlim@umich.edu comInstEventQueue = new EventQueue *[number_of_threads]; 772420SN/A for (int i = 0; i < number_of_threads; ++i) 782683Sktlim@umich.edu comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 792520SN/A 802420SN/A // 812SN/A // set up instruction-count-based termination events, if any 822683Sktlim@umich.edu // 832672Sktlim@umich.edu if (p->max_insts_any_thread != 0) 842683Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 852SN/A new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 862SN/A "a thread reached the max instruction count"); 87334SN/A 88140SN/A if (p->max_insts_all_threads != 0) { 89334SN/A // allocate & initialize shared downcounter: each event will 902SN/A // decrement this when triggered; simulation will terminate 912SN/A // when counter reaches 0 922SN/A int *counter = new int; 932680Sktlim@umich.edu *counter = number_of_threads; 942SN/A for (int i = 0; i < number_of_threads; ++i) 952SN/A new CountedExitEvent(comInstEventQueue[i], 962623SN/A "all threads reached the max instruction count", 972SN/A p->max_insts_all_threads, *counter); 982SN/A } 992SN/A 100180SN/A // allocate per-thread load-based event queues 1012623SN/A comLoadEventQueue = new EventQueue *[number_of_threads]; 102393SN/A for (int i = 0; i < number_of_threads; ++i) 103393SN/A comLoadEventQueue[i] = new EventQueue("load-based event queue"); 104393SN/A 105393SN/A // 106384SN/A // set up instruction-count-based termination events, if any 107384SN/A // 108393SN/A if (p->max_loads_any_thread != 0) 1092623SN/A for (int i = 0; i < number_of_threads; ++i) 110393SN/A new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 111393SN/A "a thread reached the max load count"); 112393SN/A 113393SN/A if (p->max_loads_all_threads != 0) { 114384SN/A // allocate & initialize shared downcounter: each event will 115189SN/A // decrement this when triggered; simulation will terminate 116189SN/A // when counter reaches 0 1172623SN/A int *counter = new int; 1182SN/A *counter = number_of_threads; 119729SN/A for (int i = 0; i < number_of_threads; ++i) 120334SN/A new CountedExitEvent(comLoadEventQueue[i], 1212SN/A "all threads reached the max load count", 1222SN/A p->max_loads_all_threads, *counter); 1232SN/A } 1242SN/A 1252SN/A#if FULL_SYSTEM 1262SN/A memset(interrupts, 0, sizeof(interrupts)); 1272SN/A intstatus = 0; 1282SN/A#endif 1292SN/A 1302SN/A functionTracingEnabled = false; 1312SN/A if (p->functionTrace) { 1322SN/A functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1331001SN/A currentFunctionStart = currentFunctionEnd = 0; 1341001SN/A functionEntryTick = p->functionTraceStart; 1351001SN/A 1361001SN/A if (p->functionTraceStart == 0) { 1371001SN/A functionTracingEnabled = true; 1382SN/A } else { 1392SN/A Event *e = 1402SN/A new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1412SN/A true); 1422SN/A e->schedule(p->functionTraceStart); 1432SN/A } 1442SN/A } 1452SN/A#if FULL_SYSTEM 1462SN/A profileEvent = NULL; 1472SN/A if (params->profile) 1482SN/A profileEvent = new ProfileEvent(this, params->profile); 1492SN/A#endif 1502SN/A} 1512SN/A 1522SN/ABaseCPU::Params::Params() 1532SN/A{ 1542SN/A#if FULL_SYSTEM 1552390SN/A profile = false; 1562390SN/A#endif 1572390SN/A} 1582390SN/A 1592390SN/Avoid 1602390SN/ABaseCPU::enableFunctionTrace() 1612390SN/A{ 1622390SN/A functionTracingEnabled = true; 1632390SN/A} 1642390SN/A 1652390SN/ABaseCPU::~BaseCPU() 1662390SN/A{ 167385SN/A} 1682SN/A 1692SN/Avoid 1702SN/ABaseCPU::init() 1712623SN/A{ 172334SN/A if (!params->deferRegistration) 173334SN/A registerExecContexts(); 1742623SN/A} 175334SN/A 176334SN/Avoid 177334SN/ABaseCPU::startup() 1782623SN/A{ 1792SN/A#if FULL_SYSTEM 180921SN/A if (!params->deferRegistration && profileEvent) 1812915Sktlim@umich.edu profileEvent->schedule(curTick); 1822915Sktlim@umich.edu#endif 1832683Sktlim@umich.edu} 1842SN/A 1852SN/A 1862SN/Avoid 1872623SN/ABaseCPU::regStats() 1882SN/A{ 189921SN/A using namespace Stats; 1902915Sktlim@umich.edu 1912915Sktlim@umich.edu numCycles 1922SN/A .name(name() + ".numCycles") 1932SN/A .desc("number of cpu cycles simulated") 1942SN/A ; 1952SN/A 1962SN/A int size = execContexts.size(); 1972SN/A if (size > 1) { 1982SN/A for (int i = 0; i < size; ++i) { 199595SN/A stringstream namestr; 2002623SN/A ccprintf(namestr, "%s.ctx%d", name(), i); 201595SN/A execContexts[i]->regStats(namestr.str()); 2022390SN/A } 2031080SN/A } else if (size == 1) 2041080SN/A execContexts[0]->regStats(name()); 2051080SN/A} 2061080SN/A 2071080SN/A 2081080SN/Avoid 2091080SN/ABaseCPU::registerExecContexts() 2101121SN/A{ 2112107SN/A for (int i = 0; i < execContexts.size(); ++i) { 2121089SN/A ExecContext *xc = execContexts[i]; 2131089SN/A#if FULL_SYSTEM 2141080SN/A int id = params->cpu_id; 2151080SN/A if (id != -1) 2161080SN/A id += i; 2171080SN/A 218595SN/A xc->cpu_id = system->registerExecContext(xc, id); 2192623SN/A#else 2202683Sktlim@umich.edu xc->cpu_id = xc->process->registerExecContext(xc); 221595SN/A#endif 2222090SN/A } 2232683Sktlim@umich.edu} 2242683Sktlim@umich.edu 225595SN/A 2262205SN/Avoid 2272205SN/ABaseCPU::switchOut(Sampler *sampler) 2282683Sktlim@umich.edu{ 2292683Sktlim@umich.edu panic("This CPU doesn't support sampling!"); 230595SN/A} 231595SN/A 2322390SN/Avoid 2332423SN/ABaseCPU::takeOverFrom(BaseCPU *oldCPU) 2342390SN/A{ 235595SN/A assert(execContexts.size() == oldCPU->execContexts.size()); 236595SN/A 237595SN/A for (int i = 0; i < execContexts.size(); ++i) { 2382623SN/A ExecContext *newXC = execContexts[i]; 239595SN/A ExecContext *oldXC = oldCPU->execContexts[i]; 2402390SN/A 2411080SN/A newXC->takeOverFrom(oldXC); 242595SN/A assert(newXC->cpu_id == oldXC->cpu_id); 2431080SN/A#if FULL_SYSTEM 2441080SN/A system->replaceExecContext(newXC, newXC->cpu_id); 245595SN/A#else 2462683Sktlim@umich.edu assert(newXC->process == oldXC->process); 2471080SN/A newXC->process->replaceExecContext(newXC, newXC->cpu_id); 2481080SN/A#endif 2491080SN/A } 2501121SN/A 2512107SN/A#if FULL_SYSTEM 2521089SN/A for (int i = 0; i < NumInterruptLevels; ++i) 2531080SN/A interrupts[i] = oldCPU->interrupts[i]; 2541089SN/A intstatus = oldCPU->intstatus; 2551080SN/A 2561080SN/A for (int i = 0; i < execContexts.size(); ++i) 2571080SN/A execContexts[i]->profile->clear(); 258595SN/A 2592683Sktlim@umich.edu if (profileEvent) 2601080SN/A profileEvent->schedule(curTick); 2612090SN/A#endif 2621080SN/A} 263595SN/A 2642683Sktlim@umich.edu 2652683Sktlim@umich.edu#if FULL_SYSTEM 266595SN/ABaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 2672683Sktlim@umich.edu : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 2681098SN/A{ } 2691098SN/A 2701098SN/Avoid 2712683Sktlim@umich.eduBaseCPU::ProfileEvent::process() 2721098SN/A{ 2731098SN/A for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 2741098SN/A ExecContext *xc = cpu->execContexts[i]; 2752012SN/A xc->profile->sample(xc->profileNode, xc->profilePC); 2761098SN/A } 2771098SN/A 278595SN/A schedule(curTick + interval); 2792205SN/A} 2802205SN/A 2812205SN/Avoid 282595SN/ABaseCPU::post_interrupt(int int_num, int index) 2832390SN/A{ 2842420SN/A DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 2852423SN/A 2862390SN/A if (int_num < 0 || int_num >= NumInterruptLevels) 287595SN/A panic("int_num out of bounds\n"); 288595SN/A 2891858SN/A if (index < 0 || index >= sizeof(uint64_t) * 8) 2902SN/A panic("int_num out of bounds\n"); 2912623SN/A 2922SN/A checkInterrupts = true; 2932680Sktlim@umich.edu interrupts[int_num] |= 1 << index; 2942SN/A intstatus |= (ULL(1) << int_num); 2952SN/A} 2962SN/A 2971858SN/Avoid 2982SN/ABaseCPU::clear_interrupt(int int_num, int index) 2992623SN/A{ 3002SN/A DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 3012SN/A 3022SN/A if (int_num < 0 || int_num >= NumInterruptLevels) 3032683Sktlim@umich.edu panic("int_num out of bounds\n"); 3042SN/A 3052683Sktlim@umich.edu if (index < 0 || index >= sizeof(uint64_t) * 8) 3062SN/A panic("int_num out of bounds\n"); 3072SN/A 3082SN/A interrupts[int_num] &= ~(1 << index); 3092SN/A if (interrupts[int_num] == 0) 3102SN/A intstatus &= ~(ULL(1) << int_num); 3112623SN/A} 3122SN/A 3131858SN/Avoid 3142683Sktlim@umich.eduBaseCPU::clear_interrupts() 3152SN/A{ 3162SN/A DPRINTF(Interrupt, "Interrupts all cleared\n"); 3171133SN/A 3182SN/A memset(interrupts, 0, sizeof(interrupts)); 3192683Sktlim@umich.edu intstatus = 0; 3202107SN/A} 3212107SN/A 3222683Sktlim@umich.edu 3232SN/Avoid 3242107SN/ABaseCPU::serialize(std::ostream &os) 3252SN/A{ 3262SN/A SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 3272SN/A SERIALIZE_SCALAR(intstatus); 3282SN/A} 3292SN/A 3302683Sktlim@umich.eduvoid 3312107SN/ABaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 3322107SN/A{ 3332SN/A UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 3342SN/A UNSERIALIZE_SCALAR(intstatus); 3352SN/A} 3362SN/A 3372SN/A#endif // FULL_SYSTEM 3382SN/A 3392SN/Avoid 3402683Sktlim@umich.eduBaseCPU::traceFunctionsInternal(Addr pc) 3412SN/A{ 3422SN/A if (!debugSymbolTable) 3432683Sktlim@umich.edu return; 3442683Sktlim@umich.edu 3452683Sktlim@umich.edu // if pc enters different function, print new function symbol and 3462234SN/A // update saved range. Otherwise do nothing. 3472680Sktlim@umich.edu if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 3482SN/A string sym_str; 3492SN/A bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 3502683Sktlim@umich.edu currentFunctionStart, 3512SN/A currentFunctionEnd); 3522SN/A 3532SN/A if (!found) { 3542623SN/A // no symbol found: use addr as label 3552SN/A sym_str = csprintf("0x%x", pc); 3562623SN/A currentFunctionStart = pc; 3572623SN/A currentFunctionEnd = pc + 1; 3582662Sstever@eecs.umich.edu } 3592623SN/A 3602623SN/A ccprintf(*functionTraceStream, " (%d)\n%d: %s", 3612741Sksewell@umich.edu curTick - functionEntryTick, curTick, sym_str); 3622741Sksewell@umich.edu functionEntryTick = curTick; 3632741Sksewell@umich.edu } 3642741Sksewell@umich.edu} 3652683Sktlim@umich.edu 3662683Sktlim@umich.edu 3672741Sksewell@umich.eduDEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 3682623SN/A