base.cc revision 6670
12SN/A/* 21762SN/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. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 292665Ssaidi@eecs.umich.edu * Nathan Binkert 302SN/A */ 312SN/A 321388SN/A#include <iostream> 332SN/A#include <string> 342SN/A#include <sstream> 352SN/A 361191SN/A#include "base/cprintf.hh" 371191SN/A#include "base/loader/symtab.hh" 381191SN/A#include "base/misc.hh" 391388SN/A#include "base/output.hh" 405529Snate@binkert.org#include "base/trace.hh" 411717SN/A#include "cpu/base.hh" 422651Ssaidi@eecs.umich.edu#include "cpu/cpuevent.hh" 432680Sktlim@umich.edu#include "cpu/thread_context.hh" 441977SN/A#include "cpu/profile.hh" 455529Snate@binkert.org#include "params/BaseCPU.hh" 463144Shsul@eecs.umich.edu#include "sim/sim_exit.hh" 472190SN/A#include "sim/process.hh" 4856SN/A#include "sim/sim_events.hh" 492190SN/A#include "sim/system.hh" 502SN/A 512359SN/A// Hack 522359SN/A#include "sim/stat_control.hh" 532359SN/A 542SN/Ausing namespace std; 552SN/A 562SN/Avector<BaseCPU *> BaseCPU::cpuList; 572SN/A 582SN/A// This variable reflects the max number of threads in any CPU. Be 592SN/A// careful to only use it once all the CPUs that you care about have 602SN/A// been initialized 612SN/Aint maxThreadsPerCPU = 1; 622SN/A 635606Snate@binkert.orgCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival) 646144Sksewell@umich.edu : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0), 656144Sksewell@umich.edu cpu(_cpu), _repeatEvent(true) 663126Sktlim@umich.edu{ 676144Sksewell@umich.edu if (_interval) 686144Sksewell@umich.edu cpu->schedule(this, curTick + _interval); 693126Sktlim@umich.edu} 703126Sktlim@umich.edu 712356SN/Avoid 722356SN/ACPUProgressEvent::process() 732356SN/A{ 742367SN/A Counter temp = cpu->totalInstructions(); 752356SN/A#ifndef NDEBUG 766144Sksewell@umich.edu double ipc = double(temp - lastNumInst) / (_interval / cpu->ticks(1)); 772367SN/A 786144Sksewell@umich.edu DPRINTFN("%s progress event, total committed:%i, progress insts committed: " 796144Sksewell@umich.edu "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst, 806144Sksewell@umich.edu ipc); 812356SN/A ipc = 0.0; 822367SN/A#else 836144Sksewell@umich.edu cprintf("%lli: %s progress event, total committed:%i, progress insts " 846144Sksewell@umich.edu "committed: %lli\n", curTick, cpu->name(), temp, 856144Sksewell@umich.edu temp - lastNumInst); 862367SN/A#endif 872356SN/A lastNumInst = temp; 886144Sksewell@umich.edu 896144Sksewell@umich.edu if (_repeatEvent) 906144Sksewell@umich.edu cpu->schedule(this, curTick + _interval); 912356SN/A} 922356SN/A 932356SN/Aconst char * 945336Shines@cs.fsu.eduCPUProgressEvent::description() const 952356SN/A{ 964873Sstever@eecs.umich.edu return "CPU Progress"; 972356SN/A} 982356SN/A 991858SN/A#if FULL_SYSTEM 1001400SN/ABaseCPU::BaseCPU(Params *p) 1015712Shsul@eecs.umich.edu : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id), 1025712Shsul@eecs.umich.edu interrupts(p->interrupts), 1036221Snate@binkert.org numThreads(p->numThreads), system(p->system), 1043661Srdreslin@umich.edu phase(p->phase) 1052SN/A#else 1061400SN/ABaseCPU::BaseCPU(Params *p) 1075712Shsul@eecs.umich.edu : MemObject(p), clock(p->clock), _cpuId(p->cpu_id), 1086221Snate@binkert.org numThreads(p->numThreads), system(p->system), 1093661Srdreslin@umich.edu phase(p->phase) 1102SN/A#endif 1112SN/A{ 1122359SN/A// currentTick = curTick; 1131062SN/A 1145712Shsul@eecs.umich.edu // if Python did not provide a valid ID, do it here 1155712Shsul@eecs.umich.edu if (_cpuId == -1 ) { 1165712Shsul@eecs.umich.edu _cpuId = cpuList.size(); 1175712Shsul@eecs.umich.edu } 1185712Shsul@eecs.umich.edu 1192SN/A // add self to global list of CPUs 1202SN/A cpuList.push_back(this); 1212SN/A 1225712Shsul@eecs.umich.edu DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId); 1235712Shsul@eecs.umich.edu 1246221Snate@binkert.org if (numThreads > maxThreadsPerCPU) 1256221Snate@binkert.org maxThreadsPerCPU = numThreads; 1262SN/A 1272SN/A // allocate per-thread instruction-based event queues 1286221Snate@binkert.org comInstEventQueue = new EventQueue *[numThreads]; 1296221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) 1306221Snate@binkert.org comInstEventQueue[tid] = 1316221Snate@binkert.org new EventQueue("instruction-based event queue"); 1322SN/A 1332SN/A // 1342SN/A // set up instruction-count-based termination events, if any 1352SN/A // 1365606Snate@binkert.org if (p->max_insts_any_thread != 0) { 1375606Snate@binkert.org const char *cause = "a thread reached the max instruction count"; 1386221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 1395606Snate@binkert.org Event *event = new SimLoopExitEvent(cause, 0); 1406221Snate@binkert.org comInstEventQueue[tid]->schedule(event, p->max_insts_any_thread); 1415606Snate@binkert.org } 1425606Snate@binkert.org } 1432SN/A 1441400SN/A if (p->max_insts_all_threads != 0) { 1455606Snate@binkert.org const char *cause = "all threads reached the max instruction count"; 1465606Snate@binkert.org 1472SN/A // allocate & initialize shared downcounter: each event will 1482SN/A // decrement this when triggered; simulation will terminate 1492SN/A // when counter reaches 0 1502SN/A int *counter = new int; 1516221Snate@binkert.org *counter = numThreads; 1526221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 1535606Snate@binkert.org Event *event = new CountedExitEvent(cause, *counter); 1546670Shsul@eecs.umich.edu comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads); 1555606Snate@binkert.org } 1562SN/A } 1572SN/A 158124SN/A // allocate per-thread load-based event queues 1596221Snate@binkert.org comLoadEventQueue = new EventQueue *[numThreads]; 1606221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) 1616221Snate@binkert.org comLoadEventQueue[tid] = new EventQueue("load-based event queue"); 162124SN/A 163124SN/A // 164124SN/A // set up instruction-count-based termination events, if any 165124SN/A // 1665606Snate@binkert.org if (p->max_loads_any_thread != 0) { 1675606Snate@binkert.org const char *cause = "a thread reached the max load count"; 1686221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 1695606Snate@binkert.org Event *event = new SimLoopExitEvent(cause, 0); 1706221Snate@binkert.org comLoadEventQueue[tid]->schedule(event, p->max_loads_any_thread); 1715606Snate@binkert.org } 1725606Snate@binkert.org } 173124SN/A 1741400SN/A if (p->max_loads_all_threads != 0) { 1755606Snate@binkert.org const char *cause = "all threads reached the max load count"; 176124SN/A // allocate & initialize shared downcounter: each event will 177124SN/A // decrement this when triggered; simulation will terminate 178124SN/A // when counter reaches 0 179124SN/A int *counter = new int; 1806221Snate@binkert.org *counter = numThreads; 1816221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 1825606Snate@binkert.org Event *event = new CountedExitEvent(cause, *counter); 1836221Snate@binkert.org comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads); 1845606Snate@binkert.org } 185124SN/A } 186124SN/A 1871191SN/A functionTracingEnabled = false; 1885529Snate@binkert.org if (p->function_trace) { 1891388SN/A functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1901191SN/A currentFunctionStart = currentFunctionEnd = 0; 1915529Snate@binkert.org functionEntryTick = p->function_trace_start; 1921191SN/A 1935529Snate@binkert.org if (p->function_trace_start == 0) { 1941191SN/A functionTracingEnabled = true; 1951191SN/A } else { 1965606Snate@binkert.org typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap; 1975606Snate@binkert.org Event *event = new wrap(this, true); 1985606Snate@binkert.org schedule(event, p->function_trace_start); 1991191SN/A } 2001191SN/A } 2011917SN/A#if FULL_SYSTEM 2025810Sgblack@eecs.umich.edu interrupts->setCPU(this); 2035810Sgblack@eecs.umich.edu 2041917SN/A profileEvent = NULL; 2055529Snate@binkert.org if (params()->profile) 2065529Snate@binkert.org profileEvent = new ProfileEvent(this, params()->profile); 2071917SN/A#endif 2085529Snate@binkert.org tracer = params()->tracer; 2091917SN/A} 2101191SN/A 2111191SN/Avoid 2121191SN/ABaseCPU::enableFunctionTrace() 2131191SN/A{ 2141191SN/A functionTracingEnabled = true; 2151191SN/A} 2161191SN/A 2171191SN/ABaseCPU::~BaseCPU() 2181191SN/A{ 2191191SN/A} 2201191SN/A 2211129SN/Avoid 2221129SN/ABaseCPU::init() 2231129SN/A{ 2245529Snate@binkert.org if (!params()->defer_registration) 2252680Sktlim@umich.edu registerThreadContexts(); 2261129SN/A} 227180SN/A 2282SN/Avoid 2291917SN/ABaseCPU::startup() 2301917SN/A{ 2311917SN/A#if FULL_SYSTEM 2325529Snate@binkert.org if (!params()->defer_registration && profileEvent) 2335606Snate@binkert.org schedule(profileEvent, curTick); 2341917SN/A#endif 2352356SN/A 2365529Snate@binkert.org if (params()->progress_interval) { 2375606Snate@binkert.org Tick num_ticks = ticks(params()->progress_interval); 2386144Sksewell@umich.edu 2396144Sksewell@umich.edu Event *event; 2406144Sksewell@umich.edu event = new CPUProgressEvent(this, num_ticks); 2412356SN/A } 2421917SN/A} 2431917SN/A 2441917SN/A 2451917SN/Avoid 2462SN/ABaseCPU::regStats() 2472SN/A{ 248729SN/A using namespace Stats; 249707SN/A 250707SN/A numCycles 251707SN/A .name(name() + ".numCycles") 252707SN/A .desc("number of cpu cycles simulated") 253707SN/A ; 254707SN/A 2552680Sktlim@umich.edu int size = threadContexts.size(); 2562SN/A if (size > 1) { 2572SN/A for (int i = 0; i < size; ++i) { 2582SN/A stringstream namestr; 2592SN/A ccprintf(namestr, "%s.ctx%d", name(), i); 2602680Sktlim@umich.edu threadContexts[i]->regStats(namestr.str()); 2612SN/A } 2622SN/A } else if (size == 1) 2632680Sktlim@umich.edu threadContexts[0]->regStats(name()); 2642190SN/A 2652190SN/A#if FULL_SYSTEM 2662190SN/A#endif 2672SN/A} 2682SN/A 2693495Sktlim@umich.eduTick 2703495Sktlim@umich.eduBaseCPU::nextCycle() 2713495Sktlim@umich.edu{ 2723661Srdreslin@umich.edu Tick next_tick = curTick - phase + clock - 1; 2733495Sktlim@umich.edu next_tick -= (next_tick % clock); 2743661Srdreslin@umich.edu next_tick += phase; 2753495Sktlim@umich.edu return next_tick; 2763495Sktlim@umich.edu} 2773495Sktlim@umich.edu 2783495Sktlim@umich.eduTick 2793495Sktlim@umich.eduBaseCPU::nextCycle(Tick begin_tick) 2803495Sktlim@umich.edu{ 2813495Sktlim@umich.edu Tick next_tick = begin_tick; 2824599Sacolyte@umich.edu if (next_tick % clock != 0) 2834599Sacolyte@umich.edu next_tick = next_tick - (next_tick % clock) + clock; 2843661Srdreslin@umich.edu next_tick += phase; 2853495Sktlim@umich.edu 2863495Sktlim@umich.edu assert(next_tick >= curTick); 2873495Sktlim@umich.edu return next_tick; 2883495Sktlim@umich.edu} 289180SN/A 290180SN/Avoid 2912680Sktlim@umich.eduBaseCPU::registerThreadContexts() 292180SN/A{ 2936221Snate@binkert.org ThreadID size = threadContexts.size(); 2946221Snate@binkert.org for (ThreadID tid = 0; tid < size; ++tid) { 2956221Snate@binkert.org ThreadContext *tc = threadContexts[tid]; 2962378SN/A 2975718Shsul@eecs.umich.edu /** This is so that contextId and cpuId match where there is a 2985718Shsul@eecs.umich.edu * 1cpu:1context relationship. Otherwise, the order of registration 2995718Shsul@eecs.umich.edu * could affect the assignment and cpu 1 could have context id 3, for 3005718Shsul@eecs.umich.edu * example. We may even want to do something like this for SMT so that 3015718Shsul@eecs.umich.edu * cpu 0 has the lowest thread contexts and cpu N has the highest, but 3025718Shsul@eecs.umich.edu * I'll just do this for now 3035718Shsul@eecs.umich.edu */ 3046221Snate@binkert.org if (numThreads == 1) 3055718Shsul@eecs.umich.edu tc->setContextId(system->registerThreadContext(tc, _cpuId)); 3065718Shsul@eecs.umich.edu else 3075718Shsul@eecs.umich.edu tc->setContextId(system->registerThreadContext(tc)); 3085713Shsul@eecs.umich.edu#if !FULL_SYSTEM 3095714Shsul@eecs.umich.edu tc->getProcessPtr()->assignThreadContext(tc->contextId()); 310180SN/A#endif 311180SN/A } 312180SN/A} 313180SN/A 314180SN/A 3154000Ssaidi@eecs.umich.eduint 3164000Ssaidi@eecs.umich.eduBaseCPU::findContext(ThreadContext *tc) 3174000Ssaidi@eecs.umich.edu{ 3186221Snate@binkert.org ThreadID size = threadContexts.size(); 3196221Snate@binkert.org for (ThreadID tid = 0; tid < size; ++tid) { 3206221Snate@binkert.org if (tc == threadContexts[tid]) 3216221Snate@binkert.org return tid; 3224000Ssaidi@eecs.umich.edu } 3234000Ssaidi@eecs.umich.edu return 0; 3244000Ssaidi@eecs.umich.edu} 3254000Ssaidi@eecs.umich.edu 326180SN/Avoid 3272798Sktlim@umich.eduBaseCPU::switchOut() 328180SN/A{ 3292359SN/A// panic("This CPU doesn't support sampling!"); 3302359SN/A#if FULL_SYSTEM 3312359SN/A if (profileEvent && profileEvent->scheduled()) 3325606Snate@binkert.org deschedule(profileEvent); 3332359SN/A#endif 334180SN/A} 335180SN/A 336180SN/Avoid 3374192Sktlim@umich.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) 338180SN/A{ 3392680Sktlim@umich.edu assert(threadContexts.size() == oldCPU->threadContexts.size()); 340180SN/A 3415712Shsul@eecs.umich.edu _cpuId = oldCPU->cpuId(); 3425712Shsul@eecs.umich.edu 3436221Snate@binkert.org ThreadID size = threadContexts.size(); 3446221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) { 3452680Sktlim@umich.edu ThreadContext *newTC = threadContexts[i]; 3462680Sktlim@umich.edu ThreadContext *oldTC = oldCPU->threadContexts[i]; 347180SN/A 3482680Sktlim@umich.edu newTC->takeOverFrom(oldTC); 3492651Ssaidi@eecs.umich.edu 3502680Sktlim@umich.edu CpuEvent::replaceThreadContext(oldTC, newTC); 3512651Ssaidi@eecs.umich.edu 3525714Shsul@eecs.umich.edu assert(newTC->contextId() == oldTC->contextId()); 3535715Shsul@eecs.umich.edu assert(newTC->threadId() == oldTC->threadId()); 3545714Shsul@eecs.umich.edu system->replaceThreadContext(newTC, newTC->contextId()); 3552359SN/A 3565875Ssteve.reinhardt@amd.com /* This code no longer works since the zero register (e.g., 3575875Ssteve.reinhardt@amd.com * r31 on Alpha) doesn't necessarily contain zero at this 3585875Ssteve.reinhardt@amd.com * point. 3595875Ssteve.reinhardt@amd.com if (DTRACE(Context)) 3605217Ssaidi@eecs.umich.edu ThreadContext::compare(oldTC, newTC); 3615875Ssteve.reinhardt@amd.com */ 362180SN/A } 363605SN/A 3641858SN/A#if FULL_SYSTEM 3653520Sgblack@eecs.umich.edu interrupts = oldCPU->interrupts; 3665810Sgblack@eecs.umich.edu interrupts->setCPU(this); 3672254SN/A 3686221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) 3692680Sktlim@umich.edu threadContexts[i]->profileClear(); 3702254SN/A 3714947Snate@binkert.org if (profileEvent) 3725606Snate@binkert.org schedule(profileEvent, curTick); 373612SN/A#endif 3744192Sktlim@umich.edu 3754192Sktlim@umich.edu // Connect new CPU to old CPU's memory only if new CPU isn't 3764192Sktlim@umich.edu // connected to anything. Also connect old CPU's memory to new 3774192Sktlim@umich.edu // CPU. 3785476Snate@binkert.org if (!ic->isConnected()) { 3795476Snate@binkert.org Port *peer = oldCPU->getPort("icache_port")->getPeer(); 3804192Sktlim@umich.edu ic->setPeer(peer); 3815476Snate@binkert.org peer->setPeer(ic); 3824192Sktlim@umich.edu } 3834192Sktlim@umich.edu 3845476Snate@binkert.org if (!dc->isConnected()) { 3855476Snate@binkert.org Port *peer = oldCPU->getPort("dcache_port")->getPeer(); 3864192Sktlim@umich.edu dc->setPeer(peer); 3875476Snate@binkert.org peer->setPeer(dc); 3884192Sktlim@umich.edu } 389180SN/A} 390180SN/A 391180SN/A 3921858SN/A#if FULL_SYSTEM 3935536Srstrong@hp.comBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) 3945606Snate@binkert.org : cpu(_cpu), interval(_interval) 3951917SN/A{ } 3961917SN/A 3971917SN/Avoid 3981917SN/ABaseCPU::ProfileEvent::process() 3991917SN/A{ 4006221Snate@binkert.org ThreadID size = cpu->threadContexts.size(); 4016221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) { 4022680Sktlim@umich.edu ThreadContext *tc = cpu->threadContexts[i]; 4032680Sktlim@umich.edu tc->profileSample(); 4041917SN/A } 4052254SN/A 4065606Snate@binkert.org cpu->schedule(this, curTick + interval); 4071917SN/A} 4081917SN/A 4092SN/Avoid 410921SN/ABaseCPU::serialize(std::ostream &os) 411921SN/A{ 4124000Ssaidi@eecs.umich.edu SERIALIZE_SCALAR(instCnt); 4135647Sgblack@eecs.umich.edu interrupts->serialize(os); 414921SN/A} 415921SN/A 416921SN/Avoid 417921SN/ABaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 418921SN/A{ 4194000Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(instCnt); 4205647Sgblack@eecs.umich.edu interrupts->unserialize(cp, section); 421921SN/A} 422921SN/A 4232SN/A#endif // FULL_SYSTEM 4242SN/A 4251191SN/Avoid 4261191SN/ABaseCPU::traceFunctionsInternal(Addr pc) 4271191SN/A{ 4281191SN/A if (!debugSymbolTable) 4291191SN/A return; 4301191SN/A 4311191SN/A // if pc enters different function, print new function symbol and 4321191SN/A // update saved range. Otherwise do nothing. 4331191SN/A if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 4341191SN/A string sym_str; 4351191SN/A bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 4361191SN/A currentFunctionStart, 4371191SN/A currentFunctionEnd); 4381191SN/A 4391191SN/A if (!found) { 4401191SN/A // no symbol found: use addr as label 4411191SN/A sym_str = csprintf("0x%x", pc); 4421191SN/A currentFunctionStart = pc; 4431191SN/A currentFunctionEnd = pc + 1; 4441191SN/A } 4451191SN/A 4461191SN/A ccprintf(*functionTraceStream, " (%d)\n%d: %s", 4471191SN/A curTick - functionEntryTick, curTick, sym_str); 4481191SN/A functionEntryTick = curTick; 4491191SN/A } 4501191SN/A} 451