base.cc revision 2439
12810Srdreslin@umich.edu/* 22810Srdreslin@umich.edu * Copyright (c) 2002-2005 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" 362810Srdreslin@umich.edu#include "base/output.hh" 372810Srdreslin@umich.edu#include "cpu/base.hh" 382810Srdreslin@umich.edu#include "cpu/exec_context.hh" 392810Srdreslin@umich.edu#include "cpu/profile.hh" 402810Srdreslin@umich.edu#include "cpu/sampler/sampler.hh" 412810Srdreslin@umich.edu#include "sim/param.hh" 422810Srdreslin@umich.edu#include "sim/process.hh" 432810Srdreslin@umich.edu#include "sim/sim_events.hh" 442810Srdreslin@umich.edu#include "sim/system.hh" 452810Srdreslin@umich.edu 462810Srdreslin@umich.edu#include "base/trace.hh" 472813Srdreslin@umich.edu 482813Srdreslin@umich.edu#if FULL_SYSTEM 492813Srdreslin@umich.edu#include "kern/kernel_stats.hh" 502810Srdreslin@umich.edu#endif 512810Srdreslin@umich.edu 522810Srdreslin@umich.eduusing namespace std; 532810Srdreslin@umich.edu 542810Srdreslin@umich.eduvector<BaseCPU *> BaseCPU::cpuList; 552810Srdreslin@umich.edu 562810Srdreslin@umich.edu// This variable reflects the max number of threads in any CPU. Be 572810Srdreslin@umich.edu// careful to only use it once all the CPUs that you care about have 582810Srdreslin@umich.edu// been initialized 592810Srdreslin@umich.eduint maxThreadsPerCPU = 1; 602810Srdreslin@umich.edu 612810Srdreslin@umich.edu#if FULL_SYSTEM 622810Srdreslin@umich.eduBaseCPU::BaseCPU(Params *p) 632810Srdreslin@umich.edu : SimObject(p->name), clock(p->clock), checkInterrupts(true), 642810Srdreslin@umich.edu params(p), number_of_threads(p->numberOfThreads), system(p->system) 652810Srdreslin@umich.edu#else 662810Srdreslin@umich.eduBaseCPU::BaseCPU(Params *p) 672810Srdreslin@umich.edu : SimObject(p->name), clock(p->clock), params(p), 682810Srdreslin@umich.edu number_of_threads(p->numberOfThreads), system(p->system) 692810Srdreslin@umich.edu#endif 702810Srdreslin@umich.edu{ 712810Srdreslin@umich.edu DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 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 DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 772810Srdreslin@umich.edu this); 782810Srdreslin@umich.edu 792810Srdreslin@umich.edu if (number_of_threads > maxThreadsPerCPU) 802810Srdreslin@umich.edu maxThreadsPerCPU = number_of_threads; 812810Srdreslin@umich.edu 822810Srdreslin@umich.edu // allocate per-thread instruction-based event queues 832810Srdreslin@umich.edu comInstEventQueue = new EventQueue *[number_of_threads]; 842810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 852810Srdreslin@umich.edu comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 862810Srdreslin@umich.edu 872810Srdreslin@umich.edu // 882810Srdreslin@umich.edu // set up instruction-count-based termination events, if any 892810Srdreslin@umich.edu // 902810Srdreslin@umich.edu if (p->max_insts_any_thread != 0) 912810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 922810Srdreslin@umich.edu new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 932810Srdreslin@umich.edu "a thread reached the max instruction count"); 942810Srdreslin@umich.edu 952810Srdreslin@umich.edu if (p->max_insts_all_threads != 0) { 962813Srdreslin@umich.edu // allocate & initialize shared downcounter: each event will 972813Srdreslin@umich.edu // decrement this when triggered; simulation will terminate 982813Srdreslin@umich.edu // when counter reaches 0 992813Srdreslin@umich.edu int *counter = new int; 1002813Srdreslin@umich.edu *counter = number_of_threads; 1012810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1022810Srdreslin@umich.edu new CountedExitEvent(comInstEventQueue[i], 1032810Srdreslin@umich.edu "all threads reached the max instruction count", 1042810Srdreslin@umich.edu p->max_insts_all_threads, *counter); 1052810Srdreslin@umich.edu } 1062810Srdreslin@umich.edu 1072810Srdreslin@umich.edu // allocate per-thread load-based event queues 1082810Srdreslin@umich.edu comLoadEventQueue = new EventQueue *[number_of_threads]; 1092810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1102810Srdreslin@umich.edu comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1112810Srdreslin@umich.edu 1122810Srdreslin@umich.edu // 1132810Srdreslin@umich.edu // set up instruction-count-based termination events, if any 1142810Srdreslin@umich.edu // 1152810Srdreslin@umich.edu if (p->max_loads_any_thread != 0) 1162810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1172810Srdreslin@umich.edu new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 1182810Srdreslin@umich.edu "a thread reached the max load count"); 1192810Srdreslin@umich.edu 1202810Srdreslin@umich.edu if (p->max_loads_all_threads != 0) { 1212810Srdreslin@umich.edu // allocate & initialize shared downcounter: each event will 1222810Srdreslin@umich.edu // decrement this when triggered; simulation will terminate 1232810Srdreslin@umich.edu // when counter reaches 0 1242810Srdreslin@umich.edu int *counter = new int; 1252810Srdreslin@umich.edu *counter = number_of_threads; 1262810Srdreslin@umich.edu for (int i = 0; i < number_of_threads; ++i) 1272810Srdreslin@umich.edu new CountedExitEvent(comLoadEventQueue[i], 1282810Srdreslin@umich.edu "all threads reached the max load count", 1292810Srdreslin@umich.edu p->max_loads_all_threads, *counter); 1302810Srdreslin@umich.edu } 1312810Srdreslin@umich.edu 1322813Srdreslin@umich.edu#if FULL_SYSTEM 1332810Srdreslin@umich.edu memset(interrupts, 0, sizeof(interrupts)); 1342810Srdreslin@umich.edu intstatus = 0; 1352813Srdreslin@umich.edu#endif 1362813Srdreslin@umich.edu 1372813Srdreslin@umich.edu functionTracingEnabled = false; 1382810Srdreslin@umich.edu if (p->functionTrace) { 1392813Srdreslin@umich.edu functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1402813Srdreslin@umich.edu currentFunctionStart = currentFunctionEnd = 0; 1412813Srdreslin@umich.edu functionEntryTick = p->functionTraceStart; 1422810Srdreslin@umich.edu 1432810Srdreslin@umich.edu if (p->functionTraceStart == 0) { 1442810Srdreslin@umich.edu functionTracingEnabled = true; 1452810Srdreslin@umich.edu } else { 1462810Srdreslin@umich.edu Event *e = 1472812Srdreslin@umich.edu new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1482810Srdreslin@umich.edu true); 1492825Srdreslin@umich.edu e->schedule(p->functionTraceStart); 1502813Srdreslin@umich.edu } 1512813Srdreslin@umich.edu } 1522826Srdreslin@umich.edu#if FULL_SYSTEM 1532813Srdreslin@umich.edu profileEvent = NULL; 1542826Srdreslin@umich.edu if (params->profile) 1552813Srdreslin@umich.edu profileEvent = new ProfileEvent(this, params->profile); 1562825Srdreslin@umich.edu 1572813Srdreslin@umich.edu kernelStats = new Kernel::Statistics(system); 1582810Srdreslin@umich.edu#endif 1592810Srdreslin@umich.edu 1602810Srdreslin@umich.edu} 1612810Srdreslin@umich.edu 1622810Srdreslin@umich.eduBaseCPU::Params::Params() 1632810Srdreslin@umich.edu{ 1642810Srdreslin@umich.edu#if FULL_SYSTEM 1652812Srdreslin@umich.edu profile = false; 1662810Srdreslin@umich.edu#endif 1672810Srdreslin@umich.edu} 1682810Srdreslin@umich.edu 1692810Srdreslin@umich.eduvoid 1702810Srdreslin@umich.eduBaseCPU::enableFunctionTrace() 1712844Srdreslin@umich.edu{ 1722810Srdreslin@umich.edu functionTracingEnabled = true; 1732810Srdreslin@umich.edu} 1742810Srdreslin@umich.edu 1752810Srdreslin@umich.eduBaseCPU::~BaseCPU() 1762810Srdreslin@umich.edu{ 1772810Srdreslin@umich.edu#if FULL_SYSTEM 1782810Srdreslin@umich.edu if (kernelStats) 1792810Srdreslin@umich.edu delete kernelStats; 1802810Srdreslin@umich.edu#endif 1812810Srdreslin@umich.edu} 1822810Srdreslin@umich.edu 1832810Srdreslin@umich.eduvoid 1842810Srdreslin@umich.eduBaseCPU::init() 1852810Srdreslin@umich.edu{ 1862810Srdreslin@umich.edu if (!params->deferRegistration) 1872810Srdreslin@umich.edu registerExecContexts(); 1882810Srdreslin@umich.edu} 1892810Srdreslin@umich.edu 1902810Srdreslin@umich.eduvoid 1912810Srdreslin@umich.eduBaseCPU::startup() 1922810Srdreslin@umich.edu{ 1932810Srdreslin@umich.edu#if FULL_SYSTEM 1942810Srdreslin@umich.edu if (!params->deferRegistration && profileEvent) 1952810Srdreslin@umich.edu profileEvent->schedule(curTick); 1962810Srdreslin@umich.edu#endif 1972810Srdreslin@umich.edu} 1982810Srdreslin@umich.edu 1992810Srdreslin@umich.edu 2002810Srdreslin@umich.eduvoid 2012810Srdreslin@umich.eduBaseCPU::regStats() 2022810Srdreslin@umich.edu{ 2032810Srdreslin@umich.edu using namespace Stats; 2042810Srdreslin@umich.edu 2052810Srdreslin@umich.edu numCycles 2062810Srdreslin@umich.edu .name(name() + ".numCycles") 2072810Srdreslin@umich.edu .desc("number of cpu cycles simulated") 2082810Srdreslin@umich.edu ; 2092810Srdreslin@umich.edu 2102810Srdreslin@umich.edu int size = execContexts.size(); 2112810Srdreslin@umich.edu if (size > 1) { 2122810Srdreslin@umich.edu for (int i = 0; i < size; ++i) { 2132810Srdreslin@umich.edu stringstream namestr; 2142810Srdreslin@umich.edu ccprintf(namestr, "%s.ctx%d", name(), i); 2152810Srdreslin@umich.edu execContexts[i]->regStats(namestr.str()); 2162810Srdreslin@umich.edu } 2172810Srdreslin@umich.edu } else if (size == 1) 2182810Srdreslin@umich.edu execContexts[0]->regStats(name()); 2192810Srdreslin@umich.edu 2202810Srdreslin@umich.edu#if FULL_SYSTEM 2212810Srdreslin@umich.edu if (kernelStats) 2222810Srdreslin@umich.edu kernelStats->regStats(name() + ".kern"); 2232810Srdreslin@umich.edu#endif 2242810Srdreslin@umich.edu} 2252810Srdreslin@umich.edu 2262811Srdreslin@umich.edu 2272810Srdreslin@umich.eduvoid 2282811Srdreslin@umich.eduBaseCPU::registerExecContexts() 2292810Srdreslin@umich.edu{ 2302811Srdreslin@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 2312810Srdreslin@umich.edu ExecContext *xc = execContexts[i]; 2322810Srdreslin@umich.edu 2332810Srdreslin@umich.edu#if FULL_SYSTEM 2342810Srdreslin@umich.edu int id = params->cpu_id; 2352810Srdreslin@umich.edu if (id != -1) 2362810Srdreslin@umich.edu id += i; 2372810Srdreslin@umich.edu 2382810Srdreslin@umich.edu xc->setCpuId(system->registerExecContext(xc, id)); 2392810Srdreslin@umich.edu#else 2402810Srdreslin@umich.edu xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); 2412810Srdreslin@umich.edu#endif 2422810Srdreslin@umich.edu } 2432810Srdreslin@umich.edu} 2442810Srdreslin@umich.edu 2452810Srdreslin@umich.edu 2462810Srdreslin@umich.eduvoid 2472810Srdreslin@umich.eduBaseCPU::switchOut(Sampler *sampler) 2482810Srdreslin@umich.edu{ 2492810Srdreslin@umich.edu panic("This CPU doesn't support sampling!"); 2502810Srdreslin@umich.edu} 2512810Srdreslin@umich.edu 2522810Srdreslin@umich.eduvoid 2532810Srdreslin@umich.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU) 2542810Srdreslin@umich.edu{ 2552810Srdreslin@umich.edu assert(execContexts.size() == oldCPU->execContexts.size()); 2562810Srdreslin@umich.edu 2572810Srdreslin@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 2582810Srdreslin@umich.edu ExecContext *newXC = execContexts[i]; 2592810Srdreslin@umich.edu ExecContext *oldXC = oldCPU->execContexts[i]; 2602810Srdreslin@umich.edu 2612810Srdreslin@umich.edu newXC->takeOverFrom(oldXC); 2622810Srdreslin@umich.edu assert(newXC->readCpuId() == oldXC->readCpuId()); 2632810Srdreslin@umich.edu#if FULL_SYSTEM 2642810Srdreslin@umich.edu system->replaceExecContext(newXC, newXC->readCpuId()); 2652810Srdreslin@umich.edu#else 2662810Srdreslin@umich.edu assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); 2672810Srdreslin@umich.edu newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); 2682810Srdreslin@umich.edu#endif 269 } 270 271#if FULL_SYSTEM 272 for (int i = 0; i < TheISA::NumInterruptLevels; ++i) 273 interrupts[i] = oldCPU->interrupts[i]; 274 intstatus = oldCPU->intstatus; 275 276 for (int i = 0; i < execContexts.size(); ++i) 277 execContexts[i]->profileClear(); 278 279 if (profileEvent) 280 profileEvent->schedule(curTick); 281#endif 282} 283 284 285#if FULL_SYSTEM 286BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 287 : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 288{ } 289 290void 291BaseCPU::ProfileEvent::process() 292{ 293 for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 294 ExecContext *xc = cpu->execContexts[i]; 295 xc->profileSample(); 296 } 297 298 schedule(curTick + interval); 299} 300 301void 302BaseCPU::post_interrupt(int int_num, int index) 303{ 304 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 305 306 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 307 panic("int_num out of bounds\n"); 308 309 if (index < 0 || index >= sizeof(uint64_t) * 8) 310 panic("int_num out of bounds\n"); 311 312 checkInterrupts = true; 313 interrupts[int_num] |= 1 << index; 314 intstatus |= (ULL(1) << int_num); 315} 316 317void 318BaseCPU::clear_interrupt(int int_num, int index) 319{ 320 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 321 322 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 323 panic("int_num out of bounds\n"); 324 325 if (index < 0 || index >= sizeof(uint64_t) * 8) 326 panic("int_num out of bounds\n"); 327 328 interrupts[int_num] &= ~(1 << index); 329 if (interrupts[int_num] == 0) 330 intstatus &= ~(ULL(1) << int_num); 331} 332 333void 334BaseCPU::clear_interrupts() 335{ 336 DPRINTF(Interrupt, "Interrupts all cleared\n"); 337 338 memset(interrupts, 0, sizeof(interrupts)); 339 intstatus = 0; 340} 341 342 343void 344BaseCPU::serialize(std::ostream &os) 345{ 346 SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 347 SERIALIZE_SCALAR(intstatus); 348 349#if FULL_SYSTEM 350 if (kernelStats) 351 kernelStats->serialize(os); 352#endif 353 354} 355 356void 357BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 358{ 359 UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 360 UNSERIALIZE_SCALAR(intstatus); 361 362#if FULL_SYSTEM 363 if (kernelStats) 364 kernelStats->unserialize(cp, section); 365#endif 366} 367 368#endif // FULL_SYSTEM 369 370void 371BaseCPU::traceFunctionsInternal(Addr pc) 372{ 373 if (!debugSymbolTable) 374 return; 375 376 // if pc enters different function, print new function symbol and 377 // update saved range. Otherwise do nothing. 378 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 379 string sym_str; 380 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 381 currentFunctionStart, 382 currentFunctionEnd); 383 384 if (!found) { 385 // no symbol found: use addr as label 386 sym_str = csprintf("0x%x", pc); 387 currentFunctionStart = pc; 388 currentFunctionEnd = pc + 1; 389 } 390 391 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 392 curTick - functionEntryTick, curTick, sym_str); 393 functionEntryTick = curTick; 394 } 395} 396 397 398DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 399