base.cc revision 2315
12SN/A/* 22188SN/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. 272665SN/A */ 282665SN/A 292665SN/A#include <iostream> 302665SN/A#include <string> 312665SN/A#include <sstream> 322SN/A 332SN/A#include "base/cprintf.hh" 342SN/A#include "base/loader/symtab.hh" 352SN/A#include "base/misc.hh" 362465SN/A#include "base/output.hh" 376658Snate@binkert.org#include "cpu/base.hh" 381717SN/A#include "cpu/exec_context.hh" 392683Sktlim@umich.edu#include "cpu/profile.hh" 402680SN/A#include "cpu/sampler/sampler.hh" 415529Snate@binkert.org#include "sim/param.hh" 422SN/A#include "sim/process.hh" 431858SN/A#include "sim/sim_events.hh" 443565Sgblack@eecs.umich.edu#include "sim/system.hh" 455529Snate@binkert.org 461917SN/A#include "base/trace.hh" 471070SN/A 481917SN/A#if FULL_SYSTEM 492188SN/A#include "kern/kernel_stats.hh" 501917SN/A#endif 512290SN/A 521070SN/Ausing namespace std; 531917SN/A 542SN/Avector<BaseCPU *> BaseCPU::cpuList; 555529Snate@binkert.org 56360SN/A// This variable reflects the max number of threads in any CPU. Be 572519SN/A// careful to only use it once all the CPUs that you care about have 582SN/A// been initialized 592SN/Aint maxThreadsPerCPU = 1; 602SN/A 612SN/A#if FULL_SYSTEM 622SN/ABaseCPU::BaseCPU(Params *p) 631858SN/A : SimObject(p->name), clock(p->clock), checkInterrupts(true), 642683Sktlim@umich.edu params(p), number_of_threads(p->numberOfThreads), system(p->system) 656022Sgblack@eecs.umich.edu#else 662683Sktlim@umich.eduBaseCPU::BaseCPU(Params *p) 676324Sgblack@eecs.umich.edu : SimObject(p->name), clock(p->clock), params(p), 686324Sgblack@eecs.umich.edu number_of_threads(p->numberOfThreads) 692521SN/A#endif 702SN/A{ 712683Sktlim@umich.edu DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 722190SN/A 732680SN/A // add self to global list of CPUs 742290SN/A cpuList.push_back(this); 756316Sgblack@eecs.umich.edu 761917SN/A DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 775529Snate@binkert.org this); 781982SN/A 791917SN/A if (number_of_threads > maxThreadsPerCPU) 802683Sktlim@umich.edu maxThreadsPerCPU = number_of_threads; 812683Sktlim@umich.edu 821917SN/A // allocate per-thread instruction-based event queues 831917SN/A comInstEventQueue = new EventQueue *[number_of_threads]; 841917SN/A for (int i = 0; i < number_of_threads; ++i) 851917SN/A comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 861917SN/A 871917SN/A // 881917SN/A // set up instruction-count-based termination events, if any 891917SN/A // 902521SN/A if (p->max_insts_any_thread != 0) 915482Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 923548Sgblack@eecs.umich.edu new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 932SN/A "a thread reached the max instruction count"); 942SN/A 954997Sgblack@eecs.umich.edu if (p->max_insts_all_threads != 0) { 966331Sgblack@eecs.umich.edu // allocate & initialize shared downcounter: each event will 976331Sgblack@eecs.umich.edu // decrement this when triggered; simulation will terminate 984997Sgblack@eecs.umich.edu // when counter reaches 0 992SN/A int *counter = new int; 1006316Sgblack@eecs.umich.edu *counter = number_of_threads; 1012683Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 1022SN/A new CountedExitEvent(comInstEventQueue[i], 1032190SN/A "all threads reached the max instruction count", 1042862Sktlim@umich.edu p->max_insts_all_threads, *counter); 1052862Sktlim@umich.edu } 1062864Sktlim@umich.edu 1072862Sktlim@umich.edu // allocate per-thread load-based event queues 1085712Shsul@eecs.umich.edu comLoadEventQueue = new EventQueue *[number_of_threads]; 1092862Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 1106331Sgblack@eecs.umich.edu comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1112862Sktlim@umich.edu 1122190SN/A // 1132683Sktlim@umich.edu // set up instruction-count-based termination events, if any 1142190SN/A // 1152190SN/A if (p->max_loads_any_thread != 0) 1162683Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 1171070SN/A new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 1183486Sktlim@umich.edu "a thread reached the max load count"); 1193486Sktlim@umich.edu 1203486Sktlim@umich.edu if (p->max_loads_all_threads != 0) { 1213486Sktlim@umich.edu // allocate & initialize shared downcounter: each event will 1222680SN/A // decrement this when triggered; simulation will terminate 1231070SN/A // when counter reaches 0 1241070SN/A int *counter = new int; 1251917SN/A *counter = number_of_threads; 1262683Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 127180SN/A new CountedExitEvent(comLoadEventQueue[i], 128180SN/A "all threads reached the max load count", 1291858SN/A p->max_loads_all_threads, *counter); 1302235SN/A } 131180SN/A 1322235SN/A#if FULL_SYSTEM 133180SN/A memset(interrupts, 0, sizeof(interrupts)); 134180SN/A intstatus = 0; 1352862Sktlim@umich.edu#endif 1362862Sktlim@umich.edu 1372313SN/A functionTracingEnabled = false; 1382313SN/A if (p->functionTrace) { 1392680SN/A functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1402313SN/A currentFunctionStart = currentFunctionEnd = 0; 1412680SN/A functionEntryTick = p->functionTraceStart; 1422313SN/A 1432313SN/A if (p->functionTraceStart == 0) { 1442680SN/A functionTracingEnabled = true; 1452313SN/A } else { 1462361SN/A Event *e = 1473548Sgblack@eecs.umich.edu new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1482361SN/A true); 1492361SN/A e->schedule(p->functionTraceStart); 1502361SN/A } 1512235SN/A } 152180SN/A#if FULL_SYSTEM 153180SN/A profileEvent = NULL; 154180SN/A if (params->profile) 1556029Ssteve.reinhardt@amd.com profileEvent = new ProfileEvent(this, params->profile); 156180SN/A 157180SN/A kernelStats = new Kernel::Statistics(system); 1582SN/A#endif 1592864Sktlim@umich.edu 1602864Sktlim@umich.edu} 1612864Sktlim@umich.edu 1622864Sktlim@umich.eduBaseCPU::Params::Params() 1632864Sktlim@umich.edu{ 1642864Sktlim@umich.edu#if FULL_SYSTEM 1652864Sktlim@umich.edu profile = false; 1662864Sktlim@umich.edu#endif 1672864Sktlim@umich.edu checker = NULL; 1683548Sgblack@eecs.umich.edu} 1692864Sktlim@umich.edu 1702864Sktlim@umich.eduvoid 1712864Sktlim@umich.eduBaseCPU::enableFunctionTrace() 1722864Sktlim@umich.edu{ 1732864Sktlim@umich.edu functionTracingEnabled = true; 1742864Sktlim@umich.edu} 1752864Sktlim@umich.edu 1762862Sktlim@umich.eduBaseCPU::~BaseCPU() 1772862Sktlim@umich.edu{ 1782862Sktlim@umich.edu#if FULL_SYSTEM 1792862Sktlim@umich.edu if (kernelStats) 1802862Sktlim@umich.edu delete kernelStats; 1812862Sktlim@umich.edu#endif 1822862Sktlim@umich.edu} 1832862Sktlim@umich.edu 1842915Sktlim@umich.eduvoid 1855714Shsul@eecs.umich.eduBaseCPU::init() 1865715Shsul@eecs.umich.edu{ 1875714Shsul@eecs.umich.edu if (!params->deferRegistration) 1882862Sktlim@umich.edu registerExecContexts(); 1892862Sktlim@umich.edu} 1902862Sktlim@umich.edu 1912683Sktlim@umich.eduvoid 192217SN/ABaseCPU::startup() 1932862Sktlim@umich.edu{ 1946315Sgblack@eecs.umich.edu#if FULL_SYSTEM 1956316Sgblack@eecs.umich.edu if (!params->deferRegistration && profileEvent) 1966324Sgblack@eecs.umich.edu profileEvent->schedule(curTick); 1976324Sgblack@eecs.umich.edu#endif 1986324Sgblack@eecs.umich.edu} 1996324Sgblack@eecs.umich.edu 2006324Sgblack@eecs.umich.edu 201223SN/Avoid 2026677SBrad.Beckmann@amd.comBaseCPU::regStats() 2036677SBrad.Beckmann@amd.com{ 2046677SBrad.Beckmann@amd.com using namespace Stats; 2056677SBrad.Beckmann@amd.com 2066677SBrad.Beckmann@amd.com numCycles 207217SN/A .name(name() + ".numCycles") 208217SN/A .desc("number of cpu cycles simulated") 209217SN/A ; 210217SN/A 2112683Sktlim@umich.edu int size = execContexts.size(); 212217SN/A if (size > 1) { 2132862Sktlim@umich.edu for (int i = 0; i < size; ++i) { 2146315Sgblack@eecs.umich.edu stringstream namestr; 2156316Sgblack@eecs.umich.edu ccprintf(namestr, "%s.ctx%d", name(), i); 2166324Sgblack@eecs.umich.edu execContexts[i]->regStats(namestr.str()); 2176324Sgblack@eecs.umich.edu } 2186324Sgblack@eecs.umich.edu } else if (size == 1) 2196324Sgblack@eecs.umich.edu execContexts[0]->regStats(name()); 2206324Sgblack@eecs.umich.edu 221223SN/A#if FULL_SYSTEM 2226677SBrad.Beckmann@amd.com if (kernelStats) 2236677SBrad.Beckmann@amd.com kernelStats->regStats(name() + ".kern"); 2246677SBrad.Beckmann@amd.com#endif 2256677SBrad.Beckmann@amd.com} 2266677SBrad.Beckmann@amd.com 227217SN/A 228217SN/Avoid 2292683Sktlim@umich.eduBaseCPU::registerExecContexts() 2302683Sktlim@umich.edu{ 2312683Sktlim@umich.edu for (int i = 0; i < execContexts.size(); ++i) { 2322683Sktlim@umich.edu ExecContext *xc = execContexts[i]; 2332683Sktlim@umich.edu 2342683Sktlim@umich.edu if (xc->status() == ExecContext::Suspended) { 2352683Sktlim@umich.edu#if FULL_SYSTEM 2362683Sktlim@umich.edu int id = params->cpu_id; 237217SN/A if (id != -1) 238217SN/A id += i; 2392683Sktlim@umich.edu 2402SN/A xc->setCpuId(system->registerExecContext(xc, id)); 2412680SN/A#else 2422SN/A xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); 2432SN/A#endif 2442188SN/A } 2452188SN/A } 2464400Srdreslin@umich.edu} 2475715Shsul@eecs.umich.edu 2485543Ssaidi@eecs.umich.edu 2494400Srdreslin@umich.eduvoid 2502290SN/ABaseCPU::switchOut(Sampler *sampler) 2512680SN/A{ 2522290SN/A panic("This CPU doesn't support sampling!"); 2532290SN/A} 2545715Shsul@eecs.umich.edu 255393SN/Avoid 256393SN/ABaseCPU::takeOverFrom(BaseCPU *oldCPU) 257393SN/A{ 2582683Sktlim@umich.edu assert(execContexts.size() == oldCPU->execContexts.size()); 259393SN/A 2602680SN/A for (int i = 0; i < execContexts.size(); ++i) { 261393SN/A ExecContext *newXC = execContexts[i]; 262393SN/A ExecContext *oldXC = oldCPU->execContexts[i]; 2632188SN/A 2642188SN/A newXC->takeOverFrom(oldXC); 2652188SN/A assert(newXC->readCpuId() == oldXC->readCpuId()); 2661858SN/A#if FULL_SYSTEM 2672SN/A system->replaceExecContext(newXC, newXC->readCpuId()); 2685704Snate@binkert.org#else 2692680SN/A assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); 2702SN/A newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); 2712SN/A#endif 2722SN/A } 2732188SN/A 2742680SN/A#if FULL_SYSTEM 2755715Shsul@eecs.umich.edu for (int i = 0; i < TheISA::NumInterruptLevels; ++i) 2762SN/A interrupts[i] = oldCPU->interrupts[i]; 2772SN/A intstatus = oldCPU->intstatus; 278393SN/A 279393SN/A for (int i = 0; i < execContexts.size(); ++i) 2802683Sktlim@umich.edu execContexts[i]->profileClear(); 281393SN/A 2822680SN/A if (profileEvent) 283393SN/A profileEvent->schedule(curTick); 284393SN/A#endif 2852680SN/A} 2865715Shsul@eecs.umich.edu 287393SN/A 288393SN/A#if FULL_SYSTEM 289393SN/ABaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 290393SN/A : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 2912683Sktlim@umich.edu{ } 2922SN/A 2932330SN/Avoid 2942341SN/ABaseCPU::ProfileEvent::process() 2952341SN/A{ 2962330SN/A for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 2972SN/A ExecContext *xc = cpu->execContexts[i]; 298716SN/A xc->profileSample(); 299716SN/A } 3002683Sktlim@umich.edu 3012190SN/A schedule(curTick + interval); 3022680SN/A} 3032190SN/A 3042190SN/Avoid 305BaseCPU::post_interrupt(int int_num, int index) 306{ 307 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 308 309 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 310 panic("int_num out of bounds\n"); 311 312 if (index < 0 || index >= sizeof(uint64_t) * 8) 313 panic("int_num out of bounds\n"); 314 315 checkInterrupts = true; 316 interrupts[int_num] |= 1 << index; 317 intstatus |= (ULL(1) << int_num); 318} 319 320void 321BaseCPU::clear_interrupt(int int_num, int index) 322{ 323 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 324 325 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 326 panic("int_num out of bounds\n"); 327 328 if (index < 0 || index >= sizeof(uint64_t) * 8) 329 panic("int_num out of bounds\n"); 330 331 interrupts[int_num] &= ~(1 << index); 332 if (interrupts[int_num] == 0) 333 intstatus &= ~(ULL(1) << int_num); 334} 335 336void 337BaseCPU::clear_interrupts() 338{ 339 DPRINTF(Interrupt, "Interrupts all cleared\n"); 340 341 memset(interrupts, 0, sizeof(interrupts)); 342 intstatus = 0; 343} 344 345 346void 347BaseCPU::serialize(std::ostream &os) 348{ 349 SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 350 SERIALIZE_SCALAR(intstatus); 351 352#if FULL_SYSTEM 353 if (kernelStats) 354 kernelStats->serialize(os); 355#endif 356 357} 358 359void 360BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 361{ 362 UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 363 UNSERIALIZE_SCALAR(intstatus); 364 365#if FULL_SYSTEM 366 if (kernelStats) 367 kernelStats->unserialize(cp, section); 368#endif 369} 370 371#endif // FULL_SYSTEM 372 373void 374BaseCPU::traceFunctionsInternal(Addr pc) 375{ 376 if (!debugSymbolTable) 377 return; 378 379 // if pc enters different function, print new function symbol and 380 // update saved range. Otherwise do nothing. 381 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 382 string sym_str; 383 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 384 currentFunctionStart, 385 currentFunctionEnd); 386 387 if (!found) { 388 // no symbol found: use addr as label 389 sym_str = csprintf("0x%x", pc); 390 currentFunctionStart = pc; 391 currentFunctionEnd = pc + 1; 392 } 393 394 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 395 curTick - functionEntryTick, curTick, sym_str); 396 functionEntryTick = curTick; 397 } 398} 399 400 401DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 402