base.cc revision 2359
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" 373565Sgblack@eecs.umich.edu#include "cpu/base.hh" 385529Snate@binkert.org#include "cpu/exec_context.hh" 398777Sgblack@eecs.umich.edu#include "cpu/profile.hh" 401917SN/A#include "cpu/sampler/sampler.hh" 411070SN/A#include "sim/param.hh" 421917SN/A#include "sim/process.hh" 432188SN/A#include "sim/sim_events.hh" 448777Sgblack@eecs.umich.edu#include "sim/system.hh" 458777Sgblack@eecs.umich.edu 461917SN/A#include "base/trace.hh" 472290SN/A 488777Sgblack@eecs.umich.edu// Hack 498777Sgblack@eecs.umich.edu#include "sim/stat_control.hh" 508706Sandreas.hansson@arm.com 518799Sgblack@eecs.umich.eduusing namespace std; 528809Sgblack@eecs.umich.edu 538793Sgblack@eecs.umich.eduvector<BaseCPU *> BaseCPU::cpuList; 548777Sgblack@eecs.umich.edu 551070SN/A// This variable reflects the max number of threads in any CPU. Be 561917SN/A// careful to only use it once all the CPUs that you care about have 572519SN/A// been initialized 582SN/Aint maxThreadsPerCPU = 1; 592SN/A 602SN/Avoid 612SN/ACPUProgressEvent::process() 628820Sgblack@eecs.umich.edu{ 638820Sgblack@eecs.umich.edu#ifndef NDEBUG 649384SAndreas.Sandberg@arm.com Counter temp = cpu->totalInstructions(); 659384SAndreas.Sandberg@arm.com double ipc = double(temp - lastNumInst) / (interval / cpu->cycles(1)); 669384SAndreas.Sandberg@arm.com DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n", 678766Sgblack@eecs.umich.edu cpu->name(), temp - lastNumInst, ipc); 688766Sgblack@eecs.umich.edu ipc = 0.0; 698766Sgblack@eecs.umich.edu lastNumInst = temp; 708766Sgblack@eecs.umich.edu schedule(curTick + interval); 719377Sgblack@eecs.umich.edu#endif 722683Sktlim@umich.edu} 736022Sgblack@eecs.umich.edu 749384SAndreas.Sandberg@arm.comconst char * 759384SAndreas.Sandberg@arm.comCPUProgressEvent::description() 769384SAndreas.Sandberg@arm.com{ 772SN/A return "CPU Progress event"; 782683Sktlim@umich.edu} 792190SN/A 802680SN/A#if FULL_SYSTEM 812290SN/ABaseCPU::BaseCPU(Params *p) 826316Sgblack@eecs.umich.edu : SimObject(p->name), clock(p->clock), checkInterrupts(true), 831917SN/A params(p), number_of_threads(p->numberOfThreads), system(p->system) 848735Sandreas.hanson@arm.com#else 851982SN/ABaseCPU::BaseCPU(Params *p) 861917SN/A : SimObject(p->name), clock(p->clock), params(p), 872683Sktlim@umich.edu number_of_threads(p->numberOfThreads) 882683Sktlim@umich.edu#endif 891917SN/A{ 901917SN/A// currentTick = curTick; 911917SN/A DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 921917SN/A 931917SN/A // add self to global list of CPUs 941917SN/A cpuList.push_back(this); 951917SN/A 961917SN/A DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 972521SN/A this); 985482Snate@binkert.org 993548Sgblack@eecs.umich.edu if (number_of_threads > maxThreadsPerCPU) 1002SN/A maxThreadsPerCPU = number_of_threads; 1012862Sktlim@umich.edu 1022864Sktlim@umich.edu // allocate per-thread instruction-based event queues 1039384SAndreas.Sandberg@arm.com comInstEventQueue = new EventQueue *[number_of_threads]; 1042190SN/A for (int i = 0; i < number_of_threads; ++i) 1052683Sktlim@umich.edu comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 1062190SN/A 1072190SN/A // 1082683Sktlim@umich.edu // set up instruction-count-based termination events, if any 1091070SN/A // 1102680SN/A if (p->max_insts_any_thread != 0) 1111070SN/A for (int i = 0; i < number_of_threads; ++i) 1121070SN/A new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 1131917SN/A "a thread reached the max instruction count"); 1142683Sktlim@umich.edu 115180SN/A if (p->max_insts_all_threads != 0) { 116180SN/A // allocate & initialize shared downcounter: each event will 1178793Sgblack@eecs.umich.edu // decrement this when triggered; simulation will terminate 1188793Sgblack@eecs.umich.edu // when counter reaches 0 1192235SN/A int *counter = new int; 120180SN/A *counter = number_of_threads; 1212862Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 1228793Sgblack@eecs.umich.edu new CountedExitEvent(comInstEventQueue[i], 1238793Sgblack@eecs.umich.edu "all threads reached the max instruction count", 1248793Sgblack@eecs.umich.edu p->max_insts_all_threads, *counter); 1258793Sgblack@eecs.umich.edu } 1268793Sgblack@eecs.umich.edu 1278793Sgblack@eecs.umich.edu // allocate per-thread load-based event queues 1288793Sgblack@eecs.umich.edu comLoadEventQueue = new EventQueue *[number_of_threads]; 1298793Sgblack@eecs.umich.edu for (int i = 0; i < number_of_threads; ++i) 1308793Sgblack@eecs.umich.edu comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1318793Sgblack@eecs.umich.edu 1328793Sgblack@eecs.umich.edu // 1338793Sgblack@eecs.umich.edu // set up instruction-count-based termination events, if any 1348793Sgblack@eecs.umich.edu // 1358793Sgblack@eecs.umich.edu if (p->max_loads_any_thread != 0) 1368793Sgblack@eecs.umich.edu for (int i = 0; i < number_of_threads; ++i) 1372313SN/A new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 138180SN/A "a thread reached the max load count"); 139180SN/A 140180SN/A if (p->max_loads_all_threads != 0) { 1416029Ssteve.reinhardt@amd.com // allocate & initialize shared downcounter: each event will 142180SN/A // decrement this when triggered; simulation will terminate 143180SN/A // when counter reaches 0 1442SN/A int *counter = new int; 1452864Sktlim@umich.edu *counter = number_of_threads; 1462864Sktlim@umich.edu for (int i = 0; i < number_of_threads; ++i) 1472864Sktlim@umich.edu new CountedExitEvent(comLoadEventQueue[i], 1482864Sktlim@umich.edu "all threads reached the max load count", 1498793Sgblack@eecs.umich.edu p->max_loads_all_threads, *counter); 1508793Sgblack@eecs.umich.edu } 1518793Sgblack@eecs.umich.edu 1528793Sgblack@eecs.umich.edu if (p->stats_reset_inst != 0) { 1538793Sgblack@eecs.umich.edu Stats::SetupEvent(Stats::Reset, p->stats_reset_inst, 0, comInstEventQueue[0]); 1548793Sgblack@eecs.umich.edu cprintf("Stats reset event scheduled for %lli insts\n", 1558793Sgblack@eecs.umich.edu p->stats_reset_inst); 1568793Sgblack@eecs.umich.edu } 1578793Sgblack@eecs.umich.edu 1582864Sktlim@umich.edu#if FULL_SYSTEM 1592864Sktlim@umich.edu memset(interrupts, 0, sizeof(interrupts)); 1602864Sktlim@umich.edu intstatus = 0; 1612864Sktlim@umich.edu#endif 1622862Sktlim@umich.edu 1632862Sktlim@umich.edu functionTracingEnabled = false; 1642862Sktlim@umich.edu if (p->functionTrace) { 1652862Sktlim@umich.edu functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1662862Sktlim@umich.edu currentFunctionStart = currentFunctionEnd = 0; 1678793Sgblack@eecs.umich.edu functionEntryTick = p->functionTraceStart; 1688793Sgblack@eecs.umich.edu 1695714Shsul@eecs.umich.edu if (p->functionTraceStart == 0) { 1705715Shsul@eecs.umich.edu functionTracingEnabled = true; 1715714Shsul@eecs.umich.edu } else { 1722862Sktlim@umich.edu Event *e = 1732862Sktlim@umich.edu new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1742862Sktlim@umich.edu true); 1752683Sktlim@umich.edu e->schedule(p->functionTraceStart); 176217SN/A } 1772862Sktlim@umich.edu } 1786315Sgblack@eecs.umich.edu#if FULL_SYSTEM 1796316Sgblack@eecs.umich.edu profileEvent = NULL; 1807720Sgblack@eecs.umich.edu if (params->profile) 181223SN/A profileEvent = new ProfileEvent(this, params->profile); 1826677SBrad.Beckmann@amd.com#endif 1836677SBrad.Beckmann@amd.com} 1846677SBrad.Beckmann@amd.com 1856677SBrad.Beckmann@amd.comBaseCPU::Params::Params() 1869384SAndreas.Sandberg@arm.com{ 187217SN/A#if FULL_SYSTEM 188217SN/A profile = false; 189217SN/A#endif 190217SN/A checker = NULL; 1912683Sktlim@umich.edu} 192217SN/A 1932862Sktlim@umich.eduvoid 1946315Sgblack@eecs.umich.eduBaseCPU::enableFunctionTrace() 1956316Sgblack@eecs.umich.edu{ 1967720Sgblack@eecs.umich.edu functionTracingEnabled = true; 197223SN/A} 1986677SBrad.Beckmann@amd.com 1996677SBrad.Beckmann@amd.comBaseCPU::~BaseCPU() 2006677SBrad.Beckmann@amd.com{ 2016677SBrad.Beckmann@amd.com} 2029384SAndreas.Sandberg@arm.com 203217SN/Avoid 204217SN/ABaseCPU::init() 2052683Sktlim@umich.edu{ 2062683Sktlim@umich.edu if (!params->deferRegistration) 2072683Sktlim@umich.edu registerExecContexts(); 2088735Sandreas.hanson@arm.com} 2098735Sandreas.hanson@arm.com 2102683Sktlim@umich.eduvoid 2112683Sktlim@umich.eduBaseCPU::startup() 212217SN/A{ 213217SN/A#if FULL_SYSTEM 2149180Sandreas.hansson@arm.com if (!params->deferRegistration && profileEvent) 2152SN/A profileEvent->schedule(curTick); 2162680SN/A#endif 2172SN/A 2182SN/A if (params->progress_interval) { 2197823Ssteve.reinhardt@amd.com new CPUProgressEvent(&mainEventQueue, params->progress_interval, 2202188SN/A this); 2214400Srdreslin@umich.edu } 2225715Shsul@eecs.umich.edu} 2235543Ssaidi@eecs.umich.edu 2244400Srdreslin@umich.edu 2252290SN/Avoid 2262680SN/ABaseCPU::regStats() 2272290SN/A{ 2282290SN/A using namespace Stats; 2298735Sandreas.hanson@arm.com 230393SN/A numCycles 231393SN/A .name(name() + ".numCycles") 232393SN/A .desc("number of cpu cycles simulated") 2332683Sktlim@umich.edu ; 234393SN/A 2352680SN/A int size = execContexts.size(); 236393SN/A if (size > 1) { 237393SN/A for (int i = 0; i < size; ++i) { 2387823Ssteve.reinhardt@amd.com stringstream namestr; 2397823Ssteve.reinhardt@amd.com ccprintf(namestr, "%s.ctx%d", name(), i); 2402680SN/A execContexts[i]->regStats(namestr.str()); 2418735Sandreas.hanson@arm.com } 2422SN/A } else if (size == 1) 2432SN/A execContexts[0]->regStats(name()); 244393SN/A 245393SN/A#if FULL_SYSTEM 2462683Sktlim@umich.edu#endif 247393SN/A} 2482680SN/A 249393SN/A 250393SN/Avoid 2512680SN/ABaseCPU::registerExecContexts() 2528735Sandreas.hanson@arm.com{ 253393SN/A for (int i = 0; i < execContexts.size(); ++i) { 254393SN/A ExecContext *xc = execContexts[i]; 255393SN/A 256393SN/A if (xc->status() == ExecContext::Suspended) { 2572683Sktlim@umich.edu#if FULL_SYSTEM 2582SN/A int id = params->cpu_id; 2598793Sgblack@eecs.umich.edu if (id != -1) 2602341SN/A id += i; 2612SN/A 262716SN/A xc->setCpuId(system->registerExecContext(xc, id)); 263716SN/A#else 2642683Sktlim@umich.edu xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); 2652190SN/A#endif 2662680SN/A } 2672190SN/A } 2682190SN/A} 269 270 271void 272BaseCPU::switchOut(Sampler *sampler) 273{ 274// panic("This CPU doesn't support sampling!"); 275#if FULL_SYSTEM 276 if (profileEvent && profileEvent->scheduled()) 277 profileEvent->deschedule(); 278#endif 279} 280 281void 282BaseCPU::takeOverFrom(BaseCPU *oldCPU) 283{ 284// currentTick = oldCPU->currentTick; 285 assert(execContexts.size() == oldCPU->execContexts.size()); 286 287 for (int i = 0; i < execContexts.size(); ++i) { 288 ExecContext *newXC = execContexts[i]; 289 ExecContext *oldXC = oldCPU->execContexts[i]; 290 291 newXC->takeOverFrom(oldXC); 292 assert(newXC->readCpuId() == oldXC->readCpuId()); 293#if FULL_SYSTEM 294 system->replaceExecContext(newXC, newXC->readCpuId()); 295#else 296 assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); 297 newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); 298#endif 299 300// TheISA::compareXCs(oldXC, newXC); 301 } 302 303#if FULL_SYSTEM 304 for (int i = 0; i < TheISA::NumInterruptLevels; ++i) 305 interrupts[i] = oldCPU->interrupts[i]; 306 intstatus = oldCPU->intstatus; 307 checkInterrupts = oldCPU->checkInterrupts; 308 309// for (int i = 0; i < execContexts.size(); ++i) 310// execContexts[i]->profileClear(); 311 312 // The Sampler must take care of this! 313// if (profileEvent) 314// profileEvent->schedule(curTick); 315#endif 316} 317 318 319#if FULL_SYSTEM 320BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 321 : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 322{ } 323 324void 325BaseCPU::ProfileEvent::process() 326{ 327 for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 328 ExecContext *xc = cpu->execContexts[i]; 329 xc->profileSample(); 330 } 331 332 schedule(curTick + interval); 333} 334 335void 336BaseCPU::post_interrupt(int int_num, int index) 337{ 338 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 339 340 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 341 panic("int_num out of bounds\n"); 342 343 if (index < 0 || index >= sizeof(uint64_t) * 8) 344 panic("int_num out of bounds\n"); 345 346 checkInterrupts = true; 347 interrupts[int_num] |= 1 << index; 348 intstatus |= (ULL(1) << int_num); 349} 350 351void 352BaseCPU::clear_interrupt(int int_num, int index) 353{ 354 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 355 356 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 357 panic("int_num out of bounds\n"); 358 359 if (index < 0 || index >= sizeof(uint64_t) * 8) 360 panic("int_num out of bounds\n"); 361 362 interrupts[int_num] &= ~(1 << index); 363 if (interrupts[int_num] == 0) 364 intstatus &= ~(ULL(1) << int_num); 365} 366 367void 368BaseCPU::clear_interrupts() 369{ 370 DPRINTF(Interrupt, "Interrupts all cleared\n"); 371 372 memset(interrupts, 0, sizeof(interrupts)); 373 intstatus = 0; 374} 375 376 377void 378BaseCPU::serialize(std::ostream &os) 379{ 380 SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 381 SERIALIZE_SCALAR(intstatus); 382} 383 384void 385BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 386{ 387 UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 388 UNSERIALIZE_SCALAR(intstatus); 389} 390 391#endif // FULL_SYSTEM 392 393void 394BaseCPU::traceFunctionsInternal(Addr pc) 395{ 396 if (!debugSymbolTable) 397 return; 398 399 // if pc enters different function, print new function symbol and 400 // update saved range. Otherwise do nothing. 401 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 402 string sym_str; 403 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 404 currentFunctionStart, 405 currentFunctionEnd); 406 407 if (!found) { 408 // no symbol found: use addr as label 409 sym_str = csprintf("0x%x", pc); 410 currentFunctionStart = pc; 411 currentFunctionEnd = pc + 1; 412 } 413 414 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 415 curTick - functionEntryTick, curTick, sym_str); 416 functionEntryTick = curTick; 417 } 418} 419 420 421DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 422