base.cc revision 2036
12810SN/A/* 22810SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32810SN/A * All rights reserved. 42810SN/A * 52810SN/A * Redistribution and use in source and binary forms, with or without 62810SN/A * modification, are permitted provided that the following conditions are 72810SN/A * met: redistributions of source code must retain the above copyright 82810SN/A * notice, this list of conditions and the following disclaimer; 92810SN/A * redistributions in binary form must reproduce the above copyright 102810SN/A * notice, this list of conditions and the following disclaimer in the 112810SN/A * documentation and/or other materials provided with the distribution; 122810SN/A * neither the name of the copyright holders nor the names of its 132810SN/A * contributors may be used to endorse or promote products derived from 142810SN/A * this software without specific prior written permission. 152810SN/A * 162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810SN/A */ 282810SN/A 292810SN/A#include <iostream> 302810SN/A#include <string> 312810SN/A#include <sstream> 322810SN/A 332810SN/A#include "base/cprintf.hh" 342810SN/A#include "base/loader/symtab.hh" 352810SN/A#include "base/misc.hh" 365875Ssteve.reinhardt@amd.com#include "base/output.hh" 372810SN/A#include "cpu/base.hh" 385338Sstever@gmail.com#include "cpu/exec_context.hh" 395338Sstever@gmail.com#include "cpu/profile.hh" 402814SN/A#include "cpu/sampler/sampler.hh" 412810SN/A#include "sim/param.hh" 422810SN/A#include "sim/sim_events.hh" 435034SN/A 445034SN/A#include "base/trace.hh" 455034SN/A 465034SN/Ausing namespace std; 475875Ssteve.reinhardt@amd.com 482810SN/Avector<BaseCPU *> BaseCPU::cpuList; 492810SN/A 502810SN/A// This variable reflects the max number of threads in any CPU. Be 512810SN/A// careful to only use it once all the CPUs that you care about have 522810SN/A// been initialized 532810SN/Aint maxThreadsPerCPU = 1; 542810SN/A 552810SN/A#if FULL_SYSTEM 565875Ssteve.reinhardt@amd.comBaseCPU::BaseCPU(Params *p) 572810SN/A : SimObject(p->name), clock(p->clock), checkInterrupts(true), 582810SN/A params(p), number_of_threads(p->numberOfThreads), system(p->system) 592810SN/A#else 602810SN/ABaseCPU::BaseCPU(Params *p) 612810SN/A : SimObject(p->name), clock(p->clock), params(p), 622810SN/A number_of_threads(p->numberOfThreads) 632810SN/A#endif 642810SN/A{ 652810SN/A DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 662810SN/A 672810SN/A // add self to global list of CPUs 682810SN/A cpuList.push_back(this); 692810SN/A 702810SN/A DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 712810SN/A this); 722810SN/A 732810SN/A if (number_of_threads > maxThreadsPerCPU) 742810SN/A maxThreadsPerCPU = number_of_threads; 752810SN/A 762810SN/A // allocate per-thread instruction-based event queues 772810SN/A comInstEventQueue = new EventQueue *[number_of_threads]; 782810SN/A for (int i = 0; i < number_of_threads; ++i) 792810SN/A comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 802810SN/A 812810SN/A // 822810SN/A // set up instruction-count-based termination events, if any 832810SN/A // 842810SN/A if (p->max_insts_any_thread != 0) 852810SN/A for (int i = 0; i < number_of_threads; ++i) 862810SN/A new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 872810SN/A "a thread reached the max instruction count"); 882810SN/A 892810SN/A if (p->max_insts_all_threads != 0) { 902810SN/A // allocate & initialize shared downcounter: each event will 912810SN/A // decrement this when triggered; simulation will terminate 922810SN/A // when counter reaches 0 932810SN/A int *counter = new int; 942810SN/A *counter = number_of_threads; 952810SN/A for (int i = 0; i < number_of_threads; ++i) 962810SN/A new CountedExitEvent(comInstEventQueue[i], 972810SN/A "all threads reached the max instruction count", 982810SN/A p->max_insts_all_threads, *counter); 992810SN/A } 1002810SN/A 1012810SN/A // allocate per-thread load-based event queues 1022810SN/A comLoadEventQueue = new EventQueue *[number_of_threads]; 1032810SN/A for (int i = 0; i < number_of_threads; ++i) 1045875Ssteve.reinhardt@amd.com comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1055875Ssteve.reinhardt@amd.com 1062810SN/A // 1072810SN/A // set up instruction-count-based termination events, if any 1082810SN/A // 1093861SN/A if (p->max_loads_any_thread != 0) 1103861SN/A for (int i = 0; i < number_of_threads; ++i) 1113861SN/A new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 1123861SN/A "a thread reached the max load count"); 1133861SN/A 1143861SN/A if (p->max_loads_all_threads != 0) { 1153861SN/A // allocate & initialize shared downcounter: each event will 1163861SN/A // decrement this when triggered; simulation will terminate 1173861SN/A // when counter reaches 0 1183861SN/A int *counter = new int; 1193861SN/A *counter = number_of_threads; 1203861SN/A for (int i = 0; i < number_of_threads; ++i) 1213861SN/A new CountedExitEvent(comLoadEventQueue[i], 1223861SN/A "all threads reached the max load count", 1233861SN/A p->max_loads_all_threads, *counter); 1243861SN/A } 1253861SN/A 1263861SN/A#if FULL_SYSTEM 1273861SN/A memset(interrupts, 0, sizeof(interrupts)); 1283861SN/A intstatus = 0; 1293349SN/A#endif 1302810SN/A 1312810SN/A functionTracingEnabled = false; 1325875Ssteve.reinhardt@amd.com if (p->functionTrace) { 1332810SN/A functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1342810SN/A currentFunctionStart = currentFunctionEnd = 0; 1355875Ssteve.reinhardt@amd.com functionEntryTick = p->functionTraceStart; 1362810SN/A 1372810SN/A if (p->functionTraceStart == 0) { 1382810SN/A functionTracingEnabled = true; 1393349SN/A } else { 1405875Ssteve.reinhardt@amd.com Event *e = 1412810SN/A new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1422810SN/A true); 1432810SN/A e->schedule(p->functionTraceStart); 1442810SN/A } 1455875Ssteve.reinhardt@amd.com } 1462810SN/A#if FULL_SYSTEM 1475875Ssteve.reinhardt@amd.com profileEvent = NULL; 1485875Ssteve.reinhardt@amd.com if (params->profile) 1495875Ssteve.reinhardt@amd.com profileEvent = new ProfileEvent(this, params->profile); 1505875Ssteve.reinhardt@amd.com#endif 1515875Ssteve.reinhardt@amd.com} 1525875Ssteve.reinhardt@amd.com 1535875Ssteve.reinhardt@amd.comBaseCPU::Params::Params() 1545875Ssteve.reinhardt@amd.com{ 1552810SN/A#if FULL_SYSTEM 1564628SN/A profile = false; 1575875Ssteve.reinhardt@amd.com#endif 1585875Ssteve.reinhardt@amd.com} 1595875Ssteve.reinhardt@amd.com 1602810SN/Avoid 1615875Ssteve.reinhardt@amd.comBaseCPU::enableFunctionTrace() 1622810SN/A{ 1632810SN/A functionTracingEnabled = true; 1645875Ssteve.reinhardt@amd.com} 1655875Ssteve.reinhardt@amd.com 1662810SN/ABaseCPU::~BaseCPU() 1672810SN/A{ 1682810SN/A} 1695875Ssteve.reinhardt@amd.com 1705875Ssteve.reinhardt@amd.comvoid 1715875Ssteve.reinhardt@amd.comBaseCPU::init() 1722810SN/A{ 1736105Ssteve.reinhardt@amd.com if (!params->deferRegistration) 1745875Ssteve.reinhardt@amd.com registerExecContexts(); 1755875Ssteve.reinhardt@amd.com} 1762810SN/A 1775875Ssteve.reinhardt@amd.comvoid 1785875Ssteve.reinhardt@amd.comBaseCPU::startup() 1792810SN/A{ 1805875Ssteve.reinhardt@amd.com#if FULL_SYSTEM 1815875Ssteve.reinhardt@amd.com if (!params->deferRegistration && profileEvent) 1822810SN/A profileEvent->schedule(curTick); 1835875Ssteve.reinhardt@amd.com#endif 1845875Ssteve.reinhardt@amd.com} 1852810SN/A 1862810SN/A 1874628SN/Avoid 1882810SN/ABaseCPU::regStats() 1892810SN/A{ 1905875Ssteve.reinhardt@amd.com using namespace Stats; 1915875Ssteve.reinhardt@amd.com 1925875Ssteve.reinhardt@amd.com numCycles 1935875Ssteve.reinhardt@amd.com .name(name() + ".numCycles") 1945875Ssteve.reinhardt@amd.com .desc("number of cpu cycles simulated") 1952810SN/A ; 1962810SN/A 1972810SN/A int size = execContexts.size(); 1982810SN/A if (size > 1) { 1992810SN/A for (int i = 0; i < size; ++i) { 2005875Ssteve.reinhardt@amd.com stringstream namestr; 2015875Ssteve.reinhardt@amd.com ccprintf(namestr, "%s.ctx%d", name(), i); 2025875Ssteve.reinhardt@amd.com execContexts[i]->regStats(namestr.str()); 2035875Ssteve.reinhardt@amd.com } 2045875Ssteve.reinhardt@amd.com } else if (size == 1) 2052810SN/A execContexts[0]->regStats(name()); 2062810SN/A} 2072810SN/A 2084628SN/A 2092810SN/Avoid 2102810SN/ABaseCPU::registerExecContexts() 2112810SN/A{ 2122810SN/A for (int i = 0; i < execContexts.size(); ++i) { 2132810SN/A ExecContext *xc = execContexts[i]; 2142810SN/A#if FULL_SYSTEM 2152810SN/A int id = params->cpu_id; 2165875Ssteve.reinhardt@amd.com if (id != -1) 2175875Ssteve.reinhardt@amd.com id += i; 2185875Ssteve.reinhardt@amd.com 2195875Ssteve.reinhardt@amd.com xc->cpu_id = system->registerExecContext(xc, id); 2205875Ssteve.reinhardt@amd.com#else 2212810SN/A xc->cpu_id = xc->process->registerExecContext(xc); 2225875Ssteve.reinhardt@amd.com#endif 2235875Ssteve.reinhardt@amd.com } 2245875Ssteve.reinhardt@amd.com} 2255875Ssteve.reinhardt@amd.com 2265875Ssteve.reinhardt@amd.com 2275875Ssteve.reinhardt@amd.comvoid 2285875Ssteve.reinhardt@amd.comBaseCPU::switchOut(Sampler *sampler) 2295875Ssteve.reinhardt@amd.com{ 2305875Ssteve.reinhardt@amd.com panic("This CPU doesn't support sampling!"); 2315875Ssteve.reinhardt@amd.com} 2325875Ssteve.reinhardt@amd.com 2335875Ssteve.reinhardt@amd.comvoid 2345875Ssteve.reinhardt@amd.comBaseCPU::takeOverFrom(BaseCPU *oldCPU) 2355875Ssteve.reinhardt@amd.com{ 2365875Ssteve.reinhardt@amd.com assert(execContexts.size() == oldCPU->execContexts.size()); 2375875Ssteve.reinhardt@amd.com 2385875Ssteve.reinhardt@amd.com for (int i = 0; i < execContexts.size(); ++i) { 2395875Ssteve.reinhardt@amd.com ExecContext *newXC = execContexts[i]; 2405875Ssteve.reinhardt@amd.com ExecContext *oldXC = oldCPU->execContexts[i]; 2415875Ssteve.reinhardt@amd.com 2425875Ssteve.reinhardt@amd.com newXC->takeOverFrom(oldXC); 2435875Ssteve.reinhardt@amd.com assert(newXC->cpu_id == oldXC->cpu_id); 2445875Ssteve.reinhardt@amd.com#if FULL_SYSTEM 2455875Ssteve.reinhardt@amd.com system->replaceExecContext(newXC, newXC->cpu_id); 2465875Ssteve.reinhardt@amd.com#else 2475875Ssteve.reinhardt@amd.com assert(newXC->process == oldXC->process); 2485875Ssteve.reinhardt@amd.com newXC->process->replaceExecContext(newXC, newXC->cpu_id); 2495875Ssteve.reinhardt@amd.com#endif 2502825SN/A } 2515714Shsul@eecs.umich.edu 2525714Shsul@eecs.umich.edu#if FULL_SYSTEM 2532814SN/A for (int i = 0; i < NumInterruptLevels; ++i) 2545875Ssteve.reinhardt@amd.com interrupts[i] = oldCPU->interrupts[i]; 2552810SN/A intstatus = oldCPU->intstatus; 2565875Ssteve.reinhardt@amd.com 2575875Ssteve.reinhardt@amd.com for (int i = 0; i < execContexts.size(); ++i) 2582810SN/A if (execContexts[i]->profile) 2595875Ssteve.reinhardt@amd.com execContexts[i]->profile->clear(); 2605875Ssteve.reinhardt@amd.com 2615875Ssteve.reinhardt@amd.com if (profileEvent) 2625875Ssteve.reinhardt@amd.com profileEvent->schedule(curTick); 2635875Ssteve.reinhardt@amd.com#endif 2642810SN/A} 2652810SN/A 2662810SN/A 2672810SN/A#if FULL_SYSTEM 2682810SN/ABaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 2692810SN/A : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 2705875Ssteve.reinhardt@amd.com{ } 2715875Ssteve.reinhardt@amd.com 2722810SN/Avoid 2732810SN/ABaseCPU::ProfileEvent::process() 2743349SN/A{ 2752810SN/A for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 2762810SN/A ExecContext *xc = cpu->execContexts[i]; 2775875Ssteve.reinhardt@amd.com xc->profile->sample(xc->profileNode, xc->profilePC); 2783349SN/A } 2795875Ssteve.reinhardt@amd.com 2802814SN/A schedule(curTick + interval); 2812810SN/A} 2822810SN/A 2832810SN/Avoid 2842810SN/ABaseCPU::post_interrupt(int int_num, int index) 2852810SN/A{ 2862810SN/A DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 2875875Ssteve.reinhardt@amd.com 2885875Ssteve.reinhardt@amd.com if (int_num < 0 || int_num >= NumInterruptLevels) 2895875Ssteve.reinhardt@amd.com panic("int_num out of bounds\n"); 2905875Ssteve.reinhardt@amd.com 2915875Ssteve.reinhardt@amd.com if (index < 0 || index >= sizeof(uint64_t) * 8) 292 panic("int_num out of bounds\n"); 293 294 checkInterrupts = true; 295 interrupts[int_num] |= 1 << index; 296 intstatus |= (ULL(1) << int_num); 297} 298 299void 300BaseCPU::clear_interrupt(int int_num, int index) 301{ 302 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 303 304 if (int_num < 0 || int_num >= NumInterruptLevels) 305 panic("int_num out of bounds\n"); 306 307 if (index < 0 || index >= sizeof(uint64_t) * 8) 308 panic("int_num out of bounds\n"); 309 310 interrupts[int_num] &= ~(1 << index); 311 if (interrupts[int_num] == 0) 312 intstatus &= ~(ULL(1) << int_num); 313} 314 315void 316BaseCPU::clear_interrupts() 317{ 318 DPRINTF(Interrupt, "Interrupts all cleared\n"); 319 320 memset(interrupts, 0, sizeof(interrupts)); 321 intstatus = 0; 322} 323 324 325void 326BaseCPU::serialize(std::ostream &os) 327{ 328 SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 329 SERIALIZE_SCALAR(intstatus); 330} 331 332void 333BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 334{ 335 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 336 UNSERIALIZE_SCALAR(intstatus); 337} 338 339#endif // FULL_SYSTEM 340 341void 342BaseCPU::traceFunctionsInternal(Addr pc) 343{ 344 if (!debugSymbolTable) 345 return; 346 347 // if pc enters different function, print new function symbol and 348 // update saved range. Otherwise do nothing. 349 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 350 string sym_str; 351 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 352 currentFunctionStart, 353 currentFunctionEnd); 354 355 if (!found) { 356 // no symbol found: use addr as label 357 sym_str = csprintf("0x%x", pc); 358 currentFunctionStart = pc; 359 currentFunctionEnd = pc + 1; 360 } 361 362 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 363 curTick - functionEntryTick, curTick, sym_str); 364 functionEntryTick = curTick; 365 } 366} 367 368 369DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 370