base.cc revision 1388
12810Srdreslin@umich.edu/* 22810Srdreslin@umich.edu * Copyright (c) 2002-2004 The Regents of The University of Michigan 32810Srdreslin@umich.edu * All rights reserved. 42810Srdreslin@umich.edu * 52810Srdreslin@umich.edu * Redistribution and use in source and binary forms, with or without 62810Srdreslin@umich.edu * modification, are permitted provided that the following conditions are 72810Srdreslin@umich.edu * met: redistributions of source code must retain the above copyright 82810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer; 92810Srdreslin@umich.edu * redistributions in binary form must reproduce the above copyright 102810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer in the 112810Srdreslin@umich.edu * documentation and/or other materials provided with the distribution; 122810Srdreslin@umich.edu * neither the name of the copyright holders nor the names of its 132810Srdreslin@umich.edu * contributors may be used to endorse or promote products derived from 142810Srdreslin@umich.edu * this software without specific prior written permission. 152810Srdreslin@umich.edu * 162810Srdreslin@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810Srdreslin@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810Srdreslin@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810Srdreslin@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810Srdreslin@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810Srdreslin@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810Srdreslin@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810Srdreslin@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810Srdreslin@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810Srdreslin@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810Srdreslin@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810Srdreslin@umich.edu */ 282810Srdreslin@umich.edu 292810Srdreslin@umich.edu#include <iostream> 302810Srdreslin@umich.edu#include <string> 312810Srdreslin@umich.edu#include <sstream> 322810Srdreslin@umich.edu 332810Srdreslin@umich.edu#include "base/cprintf.hh" 342810Srdreslin@umich.edu#include "base/loader/symtab.hh" 352810Srdreslin@umich.edu#include "base/misc.hh" 366216Snate@binkert.org#include "base/output.hh" 372810Srdreslin@umich.edu#include "cpu/base_cpu.hh" 382810Srdreslin@umich.edu#include "cpu/exec_context.hh" 392810Srdreslin@umich.edu#include "sim/param.hh" 402814Srdreslin@umich.edu#include "sim/sim_events.hh" 416216Snate@binkert.org 422810Srdreslin@umich.eduusing namespace std; 432810Srdreslin@umich.edu 442810Srdreslin@umich.eduvector<BaseCPU *> BaseCPU::cpuList; 456227Snate@binkert.org 462810Srdreslin@umich.edu// This variable reflects the max number of threads in any CPU. Be 472810Srdreslin@umich.edu// careful to only use it once all the CPUs that you care about have 482810Srdreslin@umich.edu// been initialized 492810Srdreslin@umich.eduint maxThreadsPerCPU = 1; 502810Srdreslin@umich.edu 512810Srdreslin@umich.edu#ifdef FULL_SYSTEM 522810Srdreslin@umich.eduBaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 532810Srdreslin@umich.edu Counter max_insts_any_thread, 542810Srdreslin@umich.edu Counter max_insts_all_threads, 552810Srdreslin@umich.edu Counter max_loads_any_thread, 562810Srdreslin@umich.edu Counter max_loads_all_threads, 572810Srdreslin@umich.edu System *_system, Tick freq, 582810Srdreslin@umich.edu bool _function_trace, Tick _function_trace_start) 592810Srdreslin@umich.edu : SimObject(_name), frequency(freq), checkInterrupts(true), 602810Srdreslin@umich.edu deferRegistration(_def_reg), number_of_threads(_number_of_threads), 612810Srdreslin@umich.edu system(_system) 622810Srdreslin@umich.edu#else 632810Srdreslin@umich.eduBaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 642810Srdreslin@umich.edu Counter max_insts_any_thread, 652810Srdreslin@umich.edu Counter max_insts_all_threads, 662810Srdreslin@umich.edu Counter max_loads_any_thread, 672810Srdreslin@umich.edu Counter max_loads_all_threads, 682810Srdreslin@umich.edu bool _function_trace, Tick _function_trace_start) 692810Srdreslin@umich.edu : SimObject(_name), deferRegistration(_def_reg), 702810Srdreslin@umich.edu number_of_threads(_number_of_threads) 712810Srdreslin@umich.edu#endif 722810Srdreslin@umich.edu{ 732810Srdreslin@umich.edu // add self to global list of CPUs 742810Srdreslin@umich.edu cpuList.push_back(this); 752810Srdreslin@umich.edu 762810Srdreslin@umich.edu if (number_of_threads > maxThreadsPerCPU) 772810Srdreslin@umich.edu maxThreadsPerCPU = number_of_threads; 782810Srdreslin@umich.edu 792810Srdreslin@umich.edu // allocate per-thread instruction-based event queues 802810Srdreslin@umich.edu comInstEventQueue = new EventQueue *[number_of_threads]; 816227Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 826227Snate@binkert.org comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 832810Srdreslin@umich.edu 846227Snate@binkert.org // 852810Srdreslin@umich.edu // set up instruction-count-based termination events, if any 862810Srdreslin@umich.edu // 872810Srdreslin@umich.edu if (max_insts_any_thread != 0) 882810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 892810Srdreslin@umich.edu new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 902810Srdreslin@umich.edu "a thread reached the max instruction count"); 912810Srdreslin@umich.edu 922810Srdreslin@umich.edu if (max_insts_all_threads != 0) { 932810Srdreslin@umich.edu // allocate & initialize shared downcounter: each event will 942810Srdreslin@umich.edu // decrement this when triggered; simulation will terminate 952810Srdreslin@umich.edu // when counter reaches 0 962810Srdreslin@umich.edu int *counter = new int; 972810Srdreslin@umich.edu *counter = number_of_threads; 982810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 992810Srdreslin@umich.edu new CountedExitEvent(comInstEventQueue[i], 1002810Srdreslin@umich.edu "all threads reached the max instruction count", 1012810Srdreslin@umich.edu max_insts_all_threads, *counter); 1022810Srdreslin@umich.edu } 1032810Srdreslin@umich.edu 1042810Srdreslin@umich.edu // allocate per-thread load-based event queues 1052810Srdreslin@umich.edu comLoadEventQueue = new EventQueue *[number_of_threads]; 1062810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1072810Srdreslin@umich.edu comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1082810Srdreslin@umich.edu 1092810Srdreslin@umich.edu // 1102810Srdreslin@umich.edu // set up instruction-count-based termination events, if any 1112810Srdreslin@umich.edu // 1122810Srdreslin@umich.edu if (max_loads_any_thread != 0) 1132810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1142810Srdreslin@umich.edu new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 1152810Srdreslin@umich.edu "a thread reached the max load count"); 1162810Srdreslin@umich.edu 1172810Srdreslin@umich.edu if (max_loads_all_threads != 0) { 1182810Srdreslin@umich.edu // allocate & initialize shared downcounter: each event will 1192810Srdreslin@umich.edu // decrement this when triggered; simulation will terminate 1202810Srdreslin@umich.edu // when counter reaches 0 1216227Snate@binkert.org int *counter = new int; 1222810Srdreslin@umich.edu *counter = number_of_threads; 1232810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1242810Srdreslin@umich.edu new CountedExitEvent(comLoadEventQueue[i], 1252810Srdreslin@umich.edu "all threads reached the max load count", 1262810Srdreslin@umich.edu max_loads_all_threads, *counter); 1272810Srdreslin@umich.edu } 1282810Srdreslin@umich.edu 1292810Srdreslin@umich.edu#ifdef FULL_SYSTEM 1302810Srdreslin@umich.edu memset(interrupts, 0, sizeof(interrupts)); 1312810Srdreslin@umich.edu intstatus = 0; 1322810Srdreslin@umich.edu#endif 1332810Srdreslin@umich.edu 1342810Srdreslin@umich.edu functionTracingEnabled = false; 1352810Srdreslin@umich.edu if (_function_trace) { 1362810Srdreslin@umich.edu functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1372810Srdreslin@umich.edu currentFunctionStart = currentFunctionEnd = 0; 1382810Srdreslin@umich.edu functionEntryTick = _function_trace_start; 1392810Srdreslin@umich.edu 1402810Srdreslin@umich.edu if (_function_trace_start == 0) { 1412810Srdreslin@umich.edu functionTracingEnabled = true; 1422810Srdreslin@umich.edu } else { 1432810Srdreslin@umich.edu Event *e = 1442810Srdreslin@umich.edu new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1452810Srdreslin@umich.edu true); 1462810Srdreslin@umich.edu e->schedule(_function_trace_start); 1473862Sstever@eecs.umich.edu } 1482810Srdreslin@umich.edu } 1492810Srdreslin@umich.edu} 1502810Srdreslin@umich.edu 1512810Srdreslin@umich.edu 1522810Srdreslin@umich.eduvoid 1532810Srdreslin@umich.eduBaseCPU::enableFunctionTrace() 1542810Srdreslin@umich.edu{ 1552810Srdreslin@umich.edu functionTracingEnabled = true; 1562810Srdreslin@umich.edu} 1575716Shsul@eecs.umich.edu 1582810Srdreslin@umich.eduBaseCPU::~BaseCPU() 1592810Srdreslin@umich.edu{ 1602810Srdreslin@umich.edu} 1612810Srdreslin@umich.edu 1622810Srdreslin@umich.eduvoid 1632810Srdreslin@umich.eduBaseCPU::init() 1642810Srdreslin@umich.edu{ 1652810Srdreslin@umich.edu if (!deferRegistration) 1662810Srdreslin@umich.edu registerExecContexts(); 1676227Snate@binkert.org} 1682810Srdreslin@umich.edu 1692810Srdreslin@umich.eduvoid 1702810Srdreslin@umich.eduBaseCPU::regStats() 1712810Srdreslin@umich.edu{ 1722810Srdreslin@umich.edu using namespace Stats; 1732810Srdreslin@umich.edu 1742810Srdreslin@umich.edu numCycles 1752810Srdreslin@umich.edu .name(name() + ".numCycles") 1762810Srdreslin@umich.edu .desc("number of cpu cycles simulated") 1772810Srdreslin@umich.edu ; 1782810Srdreslin@umich.edu 1792810Srdreslin@umich.edu int size = execContexts.size(); 1806227Snate@binkert.org if (size > 1) { 1812810Srdreslin@umich.edu for (int i = 0; i < size; ++i) { 1822810Srdreslin@umich.edu stringstream namestr; 1832810Srdreslin@umich.edu ccprintf(namestr, "%s.ctx%d", name(), i); 1842810Srdreslin@umich.edu execContexts[i]->regStats(namestr.str()); 1852810Srdreslin@umich.edu } 1862810Srdreslin@umich.edu } else if (size == 1) 1872810Srdreslin@umich.edu execContexts[0]->regStats(name()); 1882810Srdreslin@umich.edu} 1892810Srdreslin@umich.edu 1902810Srdreslin@umich.edu 1912810Srdreslin@umich.eduvoid 1922810Srdreslin@umich.eduBaseCPU::registerExecContexts() 1932810Srdreslin@umich.edu{ 1942810Srdreslin@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 1952991Srdreslin@umich.edu ExecContext *xc = execContexts[i]; 1962810Srdreslin@umich.edu int cpu_id; 1972810Srdreslin@umich.edu 1982810Srdreslin@umich.edu#ifdef FULL_SYSTEM 1992810Srdreslin@umich.edu cpu_id = system->registerExecContext(xc); 2002810Srdreslin@umich.edu#else 2012810Srdreslin@umich.edu cpu_id = xc->process->registerExecContext(xc); 2022810Srdreslin@umich.edu#endif 2032810Srdreslin@umich.edu 2042810Srdreslin@umich.edu xc->cpu_id = cpu_id; 2052810Srdreslin@umich.edu } 2062810Srdreslin@umich.edu} 2072810Srdreslin@umich.edu 2082810Srdreslin@umich.edu 2095717Shsul@eecs.umich.eduvoid 2102810Srdreslin@umich.eduBaseCPU::switchOut() 2112810Srdreslin@umich.edu{ 2122810Srdreslin@umich.edu // default: do nothing 2132810Srdreslin@umich.edu} 2142810Srdreslin@umich.edu 2154626Sstever@eecs.umich.eduvoid 2162810Srdreslin@umich.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU) 2172814Srdreslin@umich.edu{ 2182810Srdreslin@umich.edu assert(execContexts.size() == oldCPU->execContexts.size()); 2192810Srdreslin@umich.edu 2202810Srdreslin@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 2212810Srdreslin@umich.edu ExecContext *newXC = execContexts[i]; 2222810Srdreslin@umich.edu ExecContext *oldXC = oldCPU->execContexts[i]; 2232810Srdreslin@umich.edu 2242810Srdreslin@umich.edu newXC->takeOverFrom(oldXC); 2252810Srdreslin@umich.edu assert(newXC->cpu_id == oldXC->cpu_id); 2262810Srdreslin@umich.edu#ifdef FULL_SYSTEM 2272810Srdreslin@umich.edu system->replaceExecContext(newXC, newXC->cpu_id); 2282810Srdreslin@umich.edu#else 2292810Srdreslin@umich.edu assert(newXC->process == oldXC->process); 2302810Srdreslin@umich.edu newXC->process->replaceExecContext(newXC, newXC->cpu_id); 2315717Shsul@eecs.umich.edu#endif 2325717Shsul@eecs.umich.edu } 2335717Shsul@eecs.umich.edu 2345717Shsul@eecs.umich.edu#ifdef FULL_SYSTEM 2355717Shsul@eecs.umich.edu for (int i = 0; i < NumInterruptLevels; ++i) 2362810Srdreslin@umich.edu interrupts[i] = oldCPU->interrupts[i]; 2372810Srdreslin@umich.edu intstatus = oldCPU->intstatus; 2382810Srdreslin@umich.edu#endif 2396227Snate@binkert.org} 2402810Srdreslin@umich.edu 2412810Srdreslin@umich.edu 2422810Srdreslin@umich.edu#ifdef FULL_SYSTEM 2432810Srdreslin@umich.eduvoid 2442810Srdreslin@umich.eduBaseCPU::post_interrupt(int int_num, int index) 2452810Srdreslin@umich.edu{ 2462810Srdreslin@umich.edu DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 2472810Srdreslin@umich.edu 2482810Srdreslin@umich.edu if (int_num < 0 || int_num >= NumInterruptLevels) 2492810Srdreslin@umich.edu panic("int_num out of bounds\n"); 2502810Srdreslin@umich.edu 2512810Srdreslin@umich.edu if (index < 0 || index >= sizeof(uint64_t) * 8) 2522810Srdreslin@umich.edu panic("int_num out of bounds\n"); 2532810Srdreslin@umich.edu 2542810Srdreslin@umich.edu checkInterrupts = true; 2552810Srdreslin@umich.edu interrupts[int_num] |= 1 << index; 2562810Srdreslin@umich.edu intstatus |= (ULL(1) << int_num); 2572810Srdreslin@umich.edu} 2582810Srdreslin@umich.edu 2592810Srdreslin@umich.eduvoid 2602810Srdreslin@umich.eduBaseCPU::clear_interrupt(int int_num, int index) 2612810Srdreslin@umich.edu{ 2622810Srdreslin@umich.edu DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 2632810Srdreslin@umich.edu 2642810Srdreslin@umich.edu if (int_num < 0 || int_num >= NumInterruptLevels) 2652810Srdreslin@umich.edu panic("int_num out of bounds\n"); 2662810Srdreslin@umich.edu 2672810Srdreslin@umich.edu if (index < 0 || index >= sizeof(uint64_t) * 8) 2682810Srdreslin@umich.edu panic("int_num out of bounds\n"); 2692810Srdreslin@umich.edu 2702810Srdreslin@umich.edu interrupts[int_num] &= ~(1 << index); 2712810Srdreslin@umich.edu if (interrupts[int_num] == 0) 2722810Srdreslin@umich.edu intstatus &= ~(ULL(1) << int_num); 2732810Srdreslin@umich.edu} 2742810Srdreslin@umich.edu 2752810Srdreslin@umich.eduvoid 2762810Srdreslin@umich.eduBaseCPU::clear_interrupts() 2772810Srdreslin@umich.edu{ 2782810Srdreslin@umich.edu DPRINTF(Interrupt, "Interrupts all cleared\n"); 2792810Srdreslin@umich.edu 2802810Srdreslin@umich.edu memset(interrupts, 0, sizeof(interrupts)); 2812810Srdreslin@umich.edu intstatus = 0; 2822810Srdreslin@umich.edu} 2832810Srdreslin@umich.edu 2842810Srdreslin@umich.edu 2852810Srdreslin@umich.eduvoid 2862810Srdreslin@umich.eduBaseCPU::serialize(std::ostream &os) 2872810Srdreslin@umich.edu{ 2882810Srdreslin@umich.edu SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 289 SERIALIZE_SCALAR(intstatus); 290} 291 292void 293BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 294{ 295 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 296 UNSERIALIZE_SCALAR(intstatus); 297} 298 299#endif // FULL_SYSTEM 300 301void 302BaseCPU::traceFunctionsInternal(Addr pc) 303{ 304 if (!debugSymbolTable) 305 return; 306 307 // if pc enters different function, print new function symbol and 308 // update saved range. Otherwise do nothing. 309 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 310 string sym_str; 311 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 312 currentFunctionStart, 313 currentFunctionEnd); 314 315 if (!found) { 316 // no symbol found: use addr as label 317 sym_str = csprintf("0x%x", pc); 318 currentFunctionStart = pc; 319 currentFunctionEnd = pc + 1; 320 } 321 322 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 323 curTick - functionEntryTick, curTick, sym_str); 324 functionEntryTick = curTick; 325 } 326} 327 328 329DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 330