base.cc revision 1388
12SN/A/* 21762SN/A * Copyright (c) 2002-2004 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 292665Ssaidi@eecs.umich.edu#include <iostream> 302SN/A#include <string> 312SN/A#include <sstream> 321388SN/A 332SN/A#include "base/cprintf.hh" 342SN/A#include "base/loader/symtab.hh" 352SN/A#include "base/misc.hh" 361191SN/A#include "base/output.hh" 371191SN/A#include "cpu/base_cpu.hh" 381191SN/A#include "cpu/exec_context.hh" 391388SN/A#include "sim/param.hh" 405529Snate@binkert.org#include "sim/sim_events.hh" 411717SN/A 422651Ssaidi@eecs.umich.eduusing namespace std; 432680Sktlim@umich.edu 441977SN/Avector<BaseCPU *> BaseCPU::cpuList; 455529Snate@binkert.org 463144Shsul@eecs.umich.edu// This variable reflects the max number of threads in any CPU. Be 472190SN/A// careful to only use it once all the CPUs that you care about have 4856SN/A// been initialized 492190SN/Aint maxThreadsPerCPU = 1; 502SN/A 512359SN/A#ifdef FULL_SYSTEM 522359SN/ABaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 532359SN/A Counter max_insts_any_thread, 542SN/A Counter max_insts_all_threads, 552SN/A Counter max_loads_any_thread, 562SN/A Counter max_loads_all_threads, 572SN/A System *_system, Tick freq, 582SN/A bool _function_trace, Tick _function_trace_start) 592SN/A : SimObject(_name), frequency(freq), checkInterrupts(true), 602SN/A deferRegistration(_def_reg), number_of_threads(_number_of_threads), 612SN/A system(_system) 622SN/A#else 635606Snate@binkert.orgBaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 645606Snate@binkert.org Counter max_insts_any_thread, 655606Snate@binkert.org Counter max_insts_all_threads, 663126Sktlim@umich.edu Counter max_loads_any_thread, 673126Sktlim@umich.edu Counter max_loads_all_threads, 685606Snate@binkert.org bool _function_trace, Tick _function_trace_start) 693126Sktlim@umich.edu : SimObject(_name), deferRegistration(_def_reg), 703126Sktlim@umich.edu number_of_threads(_number_of_threads) 712356SN/A#endif 722356SN/A{ 732356SN/A // add self to global list of CPUs 742367SN/A cpuList.push_back(this); 752356SN/A 765100Ssaidi@eecs.umich.edu if (number_of_threads > maxThreadsPerCPU) 772367SN/A maxThreadsPerCPU = number_of_threads; 782356SN/A 792356SN/A // allocate per-thread instruction-based event queues 802356SN/A comInstEventQueue = new EventQueue *[number_of_threads]; 812367SN/A for (int i = 0; i < number_of_threads; ++i) 822367SN/A comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 832367SN/A 842367SN/A // 852356SN/A // set up instruction-count-based termination events, if any 865606Snate@binkert.org // 872356SN/A if (max_insts_any_thread != 0) 882356SN/A for (int i = 0; i < number_of_threads; ++i) 892356SN/A new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 905336Shines@cs.fsu.edu "a thread reached the max instruction count"); 912356SN/A 924873Sstever@eecs.umich.edu if (max_insts_all_threads != 0) { 932356SN/A // allocate & initialize shared downcounter: each event will 942356SN/A // decrement this when triggered; simulation will terminate 951858SN/A // when counter reaches 0 961400SN/A int *counter = new int; 975712Shsul@eecs.umich.edu *counter = number_of_threads; 985712Shsul@eecs.umich.edu for (int i = 0; i < number_of_threads; ++i) 995529Snate@binkert.org new CountedExitEvent(comInstEventQueue[i], 1003661Srdreslin@umich.edu "all threads reached the max instruction count", 1012SN/A max_insts_all_threads, *counter); 1021400SN/A } 1035712Shsul@eecs.umich.edu 1045529Snate@binkert.org // allocate per-thread load-based event queues 1053661Srdreslin@umich.edu comLoadEventQueue = new EventQueue *[number_of_threads]; 1062SN/A for (int i = 0; i < number_of_threads; ++i) 1072SN/A comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1082359SN/A 1091062SN/A // 1105712Shsul@eecs.umich.edu // set up instruction-count-based termination events, if any 1115712Shsul@eecs.umich.edu // 1125712Shsul@eecs.umich.edu if (max_loads_any_thread != 0) 1135712Shsul@eecs.umich.edu for (int i = 0; i < number_of_threads; ++i) 1145712Shsul@eecs.umich.edu new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 1152SN/A "a thread reached the max load count"); 1162SN/A 1172SN/A if (max_loads_all_threads != 0) { 1185712Shsul@eecs.umich.edu // allocate & initialize shared downcounter: each event will 1195712Shsul@eecs.umich.edu // decrement this when triggered; simulation will terminate 1202SN/A // when counter reaches 0 1212SN/A int *counter = new int; 1222SN/A *counter = number_of_threads; 1232SN/A for (int i = 0; i < number_of_threads; ++i) 1241354SN/A new CountedExitEvent(comLoadEventQueue[i], 1252SN/A "all threads reached the max load count", 126503SN/A max_loads_all_threads, *counter); 1272SN/A } 1282SN/A 1292SN/A#ifdef FULL_SYSTEM 1302SN/A memset(interrupts, 0, sizeof(interrupts)); 1315606Snate@binkert.org intstatus = 0; 1325606Snate@binkert.org#endif 1335606Snate@binkert.org 1345606Snate@binkert.org functionTracingEnabled = false; 1355606Snate@binkert.org if (_function_trace) { 1365606Snate@binkert.org functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1375606Snate@binkert.org currentFunctionStart = currentFunctionEnd = 0; 1382SN/A functionEntryTick = _function_trace_start; 1391400SN/A 1405606Snate@binkert.org if (_function_trace_start == 0) { 1415606Snate@binkert.org functionTracingEnabled = true; 1422SN/A } else { 1432SN/A Event *e = 1442SN/A new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1452SN/A true); 1462SN/A e->schedule(_function_trace_start); 1475606Snate@binkert.org } 1485606Snate@binkert.org } 1495606Snate@binkert.org} 1505606Snate@binkert.org 1512SN/A 1522SN/Avoid 153124SN/ABaseCPU::enableFunctionTrace() 1541354SN/A{ 155124SN/A functionTracingEnabled = true; 156124SN/A} 157124SN/A 158124SN/ABaseCPU::~BaseCPU() 159124SN/A{ 160124SN/A} 1615606Snate@binkert.org 1625606Snate@binkert.orgvoid 1635606Snate@binkert.orgBaseCPU::init() 1645606Snate@binkert.org{ 1655606Snate@binkert.org if (!deferRegistration) 1665606Snate@binkert.org registerExecContexts(); 1675606Snate@binkert.org} 168124SN/A 1691400SN/Avoid 1705606Snate@binkert.orgBaseCPU::regStats() 171124SN/A{ 172124SN/A using namespace Stats; 173124SN/A 174124SN/A numCycles 175124SN/A .name(name() + ".numCycles") 1765606Snate@binkert.org .desc("number of cpu cycles simulated") 1775606Snate@binkert.org ; 1785606Snate@binkert.org 1795606Snate@binkert.org int size = execContexts.size(); 180124SN/A if (size > 1) { 181124SN/A for (int i = 0; i < size; ++i) { 1821191SN/A stringstream namestr; 1835529Snate@binkert.org ccprintf(namestr, "%s.ctx%d", name(), i); 1841388SN/A execContexts[i]->regStats(namestr.str()); 1851191SN/A } 1865529Snate@binkert.org } else if (size == 1) 1871191SN/A execContexts[0]->regStats(name()); 1885529Snate@binkert.org} 1891191SN/A 1901191SN/A 1915606Snate@binkert.orgvoid 1925606Snate@binkert.orgBaseCPU::registerExecContexts() 1935606Snate@binkert.org{ 1941191SN/A for (int i = 0; i < execContexts.size(); ++i) { 1951191SN/A ExecContext *xc = execContexts[i]; 1961917SN/A int cpu_id; 1975810Sgblack@eecs.umich.edu 1985810Sgblack@eecs.umich.edu#ifdef FULL_SYSTEM 1991917SN/A cpu_id = system->registerExecContext(xc); 2005529Snate@binkert.org#else 2015529Snate@binkert.org cpu_id = xc->process->registerExecContext(xc); 2021917SN/A#endif 2035529Snate@binkert.org 2041917SN/A xc->cpu_id = cpu_id; 2051191SN/A } 2061191SN/A} 2071191SN/A 2081191SN/A 2091191SN/Avoid 2101191SN/ABaseCPU::switchOut() 2111191SN/A{ 2121191SN/A // default: do nothing 2131191SN/A} 2141191SN/A 2151191SN/Avoid 2161129SN/ABaseCPU::takeOverFrom(BaseCPU *oldCPU) 2171129SN/A{ 2181129SN/A assert(execContexts.size() == oldCPU->execContexts.size()); 2195529Snate@binkert.org 2202680Sktlim@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 2211129SN/A ExecContext *newXC = execContexts[i]; 222180SN/A ExecContext *oldXC = oldCPU->execContexts[i]; 2232SN/A 2241917SN/A newXC->takeOverFrom(oldXC); 2251917SN/A assert(newXC->cpu_id == oldXC->cpu_id); 2261917SN/A#ifdef FULL_SYSTEM 2275529Snate@binkert.org system->replaceExecContext(newXC, newXC->cpu_id); 2285606Snate@binkert.org#else 2291917SN/A assert(newXC->process == oldXC->process); 2302356SN/A newXC->process->replaceExecContext(newXC, newXC->cpu_id); 2315529Snate@binkert.org#endif 2325606Snate@binkert.org } 2335606Snate@binkert.org 2345606Snate@binkert.org#ifdef FULL_SYSTEM 2352356SN/A for (int i = 0; i < NumInterruptLevels; ++i) 2361917SN/A interrupts[i] = oldCPU->interrupts[i]; 2371917SN/A intstatus = oldCPU->intstatus; 2381917SN/A#endif 2391917SN/A} 2402SN/A 2412SN/A 242729SN/A#ifdef FULL_SYSTEM 243707SN/Avoid 244707SN/ABaseCPU::post_interrupt(int int_num, int index) 245707SN/A{ 246707SN/A DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 247707SN/A 248707SN/A if (int_num < 0 || int_num >= NumInterruptLevels) 2492680Sktlim@umich.edu panic("int_num out of bounds\n"); 2502SN/A 2512SN/A if (index < 0 || index >= sizeof(uint64_t) * 8) 2522SN/A panic("int_num out of bounds\n"); 2532SN/A 2542680Sktlim@umich.edu checkInterrupts = true; 2552SN/A interrupts[int_num] |= 1 << index; 2562SN/A intstatus |= (ULL(1) << int_num); 2572680Sktlim@umich.edu} 2582190SN/A 2592190SN/Avoid 2602190SN/ABaseCPU::clear_interrupt(int int_num, int index) 2612SN/A{ 2622SN/A DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 2633495Sktlim@umich.edu 2643495Sktlim@umich.edu if (int_num < 0 || int_num >= NumInterruptLevels) 2653495Sktlim@umich.edu panic("int_num out of bounds\n"); 2663661Srdreslin@umich.edu 2673495Sktlim@umich.edu if (index < 0 || index >= sizeof(uint64_t) * 8) 2683661Srdreslin@umich.edu panic("int_num out of bounds\n"); 2693495Sktlim@umich.edu 2703495Sktlim@umich.edu interrupts[int_num] &= ~(1 << index); 2713495Sktlim@umich.edu if (interrupts[int_num] == 0) 2723495Sktlim@umich.edu intstatus &= ~(ULL(1) << int_num); 2733495Sktlim@umich.edu} 2743495Sktlim@umich.edu 2753495Sktlim@umich.eduvoid 2764599Sacolyte@umich.eduBaseCPU::clear_interrupts() 2774599Sacolyte@umich.edu{ 2783661Srdreslin@umich.edu DPRINTF(Interrupt, "Interrupts all cleared\n"); 2793495Sktlim@umich.edu 2803495Sktlim@umich.edu memset(interrupts, 0, sizeof(interrupts)); 2813495Sktlim@umich.edu intstatus = 0; 2823495Sktlim@umich.edu} 283180SN/A 284180SN/A 2852680Sktlim@umich.eduvoid 286180SN/ABaseCPU::serialize(std::ostream &os) 2872680Sktlim@umich.edu{ 2882680Sktlim@umich.edu SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 2892378SN/A SERIALIZE_SCALAR(intstatus); 2905718Shsul@eecs.umich.edu} 2915718Shsul@eecs.umich.edu 2925718Shsul@eecs.umich.eduvoid 2935718Shsul@eecs.umich.eduBaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 2945718Shsul@eecs.umich.edu{ 2955718Shsul@eecs.umich.edu UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 2965718Shsul@eecs.umich.edu UNSERIALIZE_SCALAR(intstatus); 2975718Shsul@eecs.umich.edu} 2985718Shsul@eecs.umich.edu 2995718Shsul@eecs.umich.edu#endif // FULL_SYSTEM 3005718Shsul@eecs.umich.edu 3015713Shsul@eecs.umich.eduvoid 3025714Shsul@eecs.umich.eduBaseCPU::traceFunctionsInternal(Addr pc) 303180SN/A{ 304180SN/A if (!debugSymbolTable) 305180SN/A return; 306180SN/A 307180SN/A // if pc enters different function, print new function symbol and 3084000Ssaidi@eecs.umich.edu // update saved range. Otherwise do nothing. 3094000Ssaidi@eecs.umich.edu if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 3104000Ssaidi@eecs.umich.edu string sym_str; 3114000Ssaidi@eecs.umich.edu bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 3124000Ssaidi@eecs.umich.edu currentFunctionStart, 3134000Ssaidi@eecs.umich.edu currentFunctionEnd); 3144000Ssaidi@eecs.umich.edu 3154000Ssaidi@eecs.umich.edu if (!found) { 3164000Ssaidi@eecs.umich.edu // no symbol found: use addr as label 3174000Ssaidi@eecs.umich.edu sym_str = csprintf("0x%x", pc); 318180SN/A currentFunctionStart = pc; 3192798Sktlim@umich.edu currentFunctionEnd = pc + 1; 320180SN/A } 3212359SN/A 3222359SN/A ccprintf(*functionTraceStream, " (%d)\n%d: %s", 3232359SN/A curTick - functionEntryTick, curTick, sym_str); 3245606Snate@binkert.org functionEntryTick = curTick; 3252359SN/A } 326180SN/A} 327180SN/A 328180SN/A 3294192Sktlim@umich.eduDEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 330180SN/A