base.cc revision 2356
1955SN/A/* 2955SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 31762SN/A * All rights reserved. 4955SN/A * 5955SN/A * Redistribution and use in source and binary forms, with or without 6955SN/A * modification, are permitted provided that the following conditions are 7955SN/A * met: redistributions of source code must retain the above copyright 8955SN/A * notice, this list of conditions and the following disclaimer; 9955SN/A * redistributions in binary form must reproduce the above copyright 10955SN/A * notice, this list of conditions and the following disclaimer in the 11955SN/A * documentation and/or other materials provided with the distribution; 12955SN/A * neither the name of the copyright holders nor the names of its 13955SN/A * contributors may be used to endorse or promote products derived from 14955SN/A * this software without specific prior written permission. 15955SN/A * 16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27955SN/A */ 282665Ssaidi@eecs.umich.edu 294762Snate@binkert.org#include <iostream> 30955SN/A#include <string> 315522Snate@binkert.org#include <sstream> 324762Snate@binkert.org 335522Snate@binkert.org#include "base/cprintf.hh" 34955SN/A#include "base/loader/symtab.hh" 355522Snate@binkert.org#include "base/misc.hh" 36955SN/A#include "base/output.hh" 375522Snate@binkert.org#include "cpu/base.hh" 384202Sbinkertn@umich.edu#include "cpu/exec_context.hh" 395742Snate@binkert.org#include "cpu/profile.hh" 40955SN/A#include "cpu/sampler/sampler.hh" 414381Sbinkertn@umich.edu#include "sim/param.hh" 424381Sbinkertn@umich.edu#include "sim/process.hh" 43955SN/A#include "sim/sim_events.hh" 44955SN/A#include "sim/system.hh" 45955SN/A 464202Sbinkertn@umich.edu#include "base/trace.hh" 47955SN/A 484382Sbinkertn@umich.eduusing namespace std; 494382Sbinkertn@umich.edu 504382Sbinkertn@umich.eduvector<BaseCPU *> BaseCPU::cpuList; 515863Snate@binkert.org 525517Snate@binkert.org// This variable reflects the max number of threads in any CPU. Be 534762Snate@binkert.org// careful to only use it once all the CPUs that you care about have 544762Snate@binkert.org// been initialized 554762Snate@binkert.orgint maxThreadsPerCPU = 1; 564762Snate@binkert.org 574762Snate@binkert.orgvoid 584762Snate@binkert.orgCPUProgressEvent::process() 594762Snate@binkert.org{ 604762Snate@binkert.org#ifndef NDEBUG 614762Snate@binkert.org Counter temp = cpu->totalInstructions(); 624762Snate@binkert.org double ipc = double(temp - lastNumInst) / (interval / cpu->cycles(1)); 635522Snate@binkert.org DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n", 645604Snate@binkert.org cpu->name(), temp - lastNumInst, ipc); 655604Snate@binkert.org ipc = 0.0; 665604Snate@binkert.org lastNumInst = temp; 674762Snate@binkert.org schedule(curTick + interval); 684762Snate@binkert.org#endif 694762Snate@binkert.org} 705522Snate@binkert.org 715522Snate@binkert.orgconst char * 725522Snate@binkert.orgCPUProgressEvent::description() 735522Snate@binkert.org{ 745604Snate@binkert.org return "CPU Progress event"; 755604Snate@binkert.org} 764762Snate@binkert.org 774762Snate@binkert.org#if FULL_SYSTEM 784762Snate@binkert.orgBaseCPU::BaseCPU(Params *p) 794762Snate@binkert.org : SimObject(p->name), clock(p->clock), checkInterrupts(true), 805522Snate@binkert.org params(p), number_of_threads(p->numberOfThreads), system(p->system) 814762Snate@binkert.org#else 824762Snate@binkert.orgBaseCPU::BaseCPU(Params *p) 835604Snate@binkert.org : SimObject(p->name), clock(p->clock), params(p), 845604Snate@binkert.org number_of_threads(p->numberOfThreads) 855604Snate@binkert.org#endif 865604Snate@binkert.org{ 875604Snate@binkert.org DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 885604Snate@binkert.org 894762Snate@binkert.org // add self to global list of CPUs 904762Snate@binkert.org cpuList.push_back(this); 914762Snate@binkert.org 924762Snate@binkert.org DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 935604Snate@binkert.org this); 944762Snate@binkert.org 955522Snate@binkert.org if (number_of_threads > maxThreadsPerCPU) 965522Snate@binkert.org maxThreadsPerCPU = number_of_threads; 975522Snate@binkert.org 984762Snate@binkert.org // allocate per-thread instruction-based event queues 994382Sbinkertn@umich.edu comInstEventQueue = new EventQueue *[number_of_threads]; 1004762Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 1014382Sbinkertn@umich.edu comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 1025522Snate@binkert.org 1034381Sbinkertn@umich.edu // 1045522Snate@binkert.org // set up instruction-count-based termination events, if any 1054762Snate@binkert.org // 1064762Snate@binkert.org if (p->max_insts_any_thread != 0) 1074762Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 1085522Snate@binkert.org new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 1095522Snate@binkert.org "a thread reached the max instruction count"); 1105522Snate@binkert.org 1115522Snate@binkert.org if (p->max_insts_all_threads != 0) { 1125522Snate@binkert.org // allocate & initialize shared downcounter: each event will 1135522Snate@binkert.org // decrement this when triggered; simulation will terminate 1145522Snate@binkert.org // when counter reaches 0 1155522Snate@binkert.org int *counter = new int; 1165522Snate@binkert.org *counter = number_of_threads; 1174762Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 1184762Snate@binkert.org new CountedExitEvent(comInstEventQueue[i], 1194762Snate@binkert.org "all threads reached the max instruction count", 1204762Snate@binkert.org p->max_insts_all_threads, *counter); 1214762Snate@binkert.org } 1224762Snate@binkert.org 1234762Snate@binkert.org // allocate per-thread load-based event queues 1244762Snate@binkert.org comLoadEventQueue = new EventQueue *[number_of_threads]; 1254762Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 1264762Snate@binkert.org comLoadEventQueue[i] = new EventQueue("load-based event queue"); 1274762Snate@binkert.org 1284762Snate@binkert.org // 1294762Snate@binkert.org // set up instruction-count-based termination events, if any 1304762Snate@binkert.org // 1314762Snate@binkert.org if (p->max_loads_any_thread != 0) 1324762Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 1334762Snate@binkert.org new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 1344762Snate@binkert.org "a thread reached the max load count"); 1354762Snate@binkert.org 1364762Snate@binkert.org if (p->max_loads_all_threads != 0) { 1374762Snate@binkert.org // allocate & initialize shared downcounter: each event will 1384762Snate@binkert.org // decrement this when triggered; simulation will terminate 1394762Snate@binkert.org // when counter reaches 0 1404762Snate@binkert.org int *counter = new int; 1414762Snate@binkert.org *counter = number_of_threads; 1424762Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 1434762Snate@binkert.org new CountedExitEvent(comLoadEventQueue[i], 1444762Snate@binkert.org "all threads reached the max load count", 1454762Snate@binkert.org p->max_loads_all_threads, *counter); 1464762Snate@binkert.org } 1474762Snate@binkert.org 1484762Snate@binkert.org#if FULL_SYSTEM 1494762Snate@binkert.org memset(interrupts, 0, sizeof(interrupts)); 1504762Snate@binkert.org intstatus = 0; 1514762Snate@binkert.org#endif 152955SN/A 1535584Snate@binkert.org functionTracingEnabled = false; 1545584Snate@binkert.org if (p->functionTrace) { 1555584Snate@binkert.org functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 1565584Snate@binkert.org currentFunctionStart = currentFunctionEnd = 0; 1575584Snate@binkert.org functionEntryTick = p->functionTraceStart; 1585584Snate@binkert.org 1595584Snate@binkert.org if (p->functionTraceStart == 0) { 1605584Snate@binkert.org functionTracingEnabled = true; 1615584Snate@binkert.org } else { 1625584Snate@binkert.org Event *e = 1635584Snate@binkert.org new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 1645584Snate@binkert.org true); 1655584Snate@binkert.org e->schedule(p->functionTraceStart); 1664382Sbinkertn@umich.edu } 1674202Sbinkertn@umich.edu } 1685522Snate@binkert.org#if FULL_SYSTEM 1694382Sbinkertn@umich.edu profileEvent = NULL; 1704382Sbinkertn@umich.edu if (params->profile) 1714382Sbinkertn@umich.edu profileEvent = new ProfileEvent(this, params->profile); 1725584Snate@binkert.org#endif 1734382Sbinkertn@umich.edu} 1744382Sbinkertn@umich.edu 1754382Sbinkertn@umich.eduBaseCPU::Params::Params() 1765192Ssaidi@eecs.umich.edu{ 1775192Ssaidi@eecs.umich.edu#if FULL_SYSTEM 1785799Snate@binkert.org profile = false; 1795799Snate@binkert.org#endif 1805799Snate@binkert.org checker = NULL; 1815192Ssaidi@eecs.umich.edu} 1825799Snate@binkert.org 1835192Ssaidi@eecs.umich.eduvoid 1845799Snate@binkert.orgBaseCPU::enableFunctionTrace() 1855799Snate@binkert.org{ 1865192Ssaidi@eecs.umich.edu functionTracingEnabled = true; 1875192Ssaidi@eecs.umich.edu} 1885192Ssaidi@eecs.umich.edu 1895192Ssaidi@eecs.umich.eduBaseCPU::~BaseCPU() 1905799Snate@binkert.org{ 1915192Ssaidi@eecs.umich.edu} 1925799Snate@binkert.org 1935192Ssaidi@eecs.umich.eduvoid 1945192Ssaidi@eecs.umich.eduBaseCPU::init() 1955192Ssaidi@eecs.umich.edu{ 1965799Snate@binkert.org if (!params->deferRegistration) 1975192Ssaidi@eecs.umich.edu registerExecContexts(); 1985192Ssaidi@eecs.umich.edu} 1995192Ssaidi@eecs.umich.edu 2005192Ssaidi@eecs.umich.eduvoid 2015192Ssaidi@eecs.umich.eduBaseCPU::startup() 2025192Ssaidi@eecs.umich.edu{ 2034382Sbinkertn@umich.edu#if FULL_SYSTEM 2044382Sbinkertn@umich.edu if (!params->deferRegistration && profileEvent) 2054382Sbinkertn@umich.edu profileEvent->schedule(curTick); 2062667Sstever@eecs.umich.edu#endif 2072667Sstever@eecs.umich.edu 2082667Sstever@eecs.umich.edu if (params->progress_interval) { 2092667Sstever@eecs.umich.edu new CPUProgressEvent(&mainEventQueue, params->progress_interval, 2102667Sstever@eecs.umich.edu this); 2112667Sstever@eecs.umich.edu } 2125742Snate@binkert.org} 2135742Snate@binkert.org 2145742Snate@binkert.org 2152037SN/Avoid 2162037SN/ABaseCPU::regStats() 2172037SN/A{ 2185793Snate@binkert.org using namespace Stats; 2195793Snate@binkert.org 2205793Snate@binkert.org numCycles 2215793Snate@binkert.org .name(name() + ".numCycles") 2225793Snate@binkert.org .desc("number of cpu cycles simulated") 2234382Sbinkertn@umich.edu ; 2244762Snate@binkert.org 2255344Sstever@gmail.com int size = execContexts.size(); 2264382Sbinkertn@umich.edu if (size > 1) { 2275341Sstever@gmail.com for (int i = 0; i < size; ++i) { 2285742Snate@binkert.org stringstream namestr; 2295742Snate@binkert.org ccprintf(namestr, "%s.ctx%d", name(), i); 2305742Snate@binkert.org execContexts[i]->regStats(namestr.str()); 2315742Snate@binkert.org } 2325742Snate@binkert.org } else if (size == 1) 2334762Snate@binkert.org execContexts[0]->regStats(name()); 2345742Snate@binkert.org 2355742Snate@binkert.org#if FULL_SYSTEM 2365742Snate@binkert.org#endif 2375742Snate@binkert.org} 2385742Snate@binkert.org 2395742Snate@binkert.org 2405742Snate@binkert.orgvoid 2415341Sstever@gmail.comBaseCPU::registerExecContexts() 2425742Snate@binkert.org{ 2435341Sstever@gmail.com for (int i = 0; i < execContexts.size(); ++i) { 2444773Snate@binkert.org ExecContext *xc = execContexts[i]; 2455863Snate@binkert.org 2461858SN/A if (xc->status() == ExecContext::Suspended) { 2471085SN/A#if FULL_SYSTEM 2484382Sbinkertn@umich.edu int id = params->cpu_id; 2494382Sbinkertn@umich.edu if (id != -1) 2504762Snate@binkert.org id += i; 2514762Snate@binkert.org 2524762Snate@binkert.org xc->setCpuId(system->registerExecContext(xc, id)); 2535517Snate@binkert.org#else 2545517Snate@binkert.org xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); 2555517Snate@binkert.org#endif 2565517Snate@binkert.org } 2575517Snate@binkert.org } 2585517Snate@binkert.org} 2595517Snate@binkert.org 2605517Snate@binkert.org 2615517Snate@binkert.orgvoid 2625517Snate@binkert.orgBaseCPU::switchOut(Sampler *sampler) 2635517Snate@binkert.org{ 2645517Snate@binkert.org panic("This CPU doesn't support sampling!"); 2655517Snate@binkert.org} 2665517Snate@binkert.org 2675517Snate@binkert.orgvoid 2685517Snate@binkert.orgBaseCPU::takeOverFrom(BaseCPU *oldCPU) 2695517Snate@binkert.org{ 2705798Snate@binkert.org assert(execContexts.size() == oldCPU->execContexts.size()); 2715517Snate@binkert.org 2725517Snate@binkert.org for (int i = 0; i < execContexts.size(); ++i) { 2735517Snate@binkert.org ExecContext *newXC = execContexts[i]; 2745517Snate@binkert.org ExecContext *oldXC = oldCPU->execContexts[i]; 2755517Snate@binkert.org 2765517Snate@binkert.org newXC->takeOverFrom(oldXC); 2775517Snate@binkert.org assert(newXC->readCpuId() == oldXC->readCpuId()); 2785517Snate@binkert.org#if FULL_SYSTEM 2795517Snate@binkert.org system->replaceExecContext(newXC, newXC->readCpuId()); 2805517Snate@binkert.org#else 2815517Snate@binkert.org assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); 2825517Snate@binkert.org newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); 2835517Snate@binkert.org#endif 2845517Snate@binkert.org } 2855517Snate@binkert.org 2865517Snate@binkert.org#if FULL_SYSTEM 2875517Snate@binkert.org for (int i = 0; i < TheISA::NumInterruptLevels; ++i) 2885517Snate@binkert.org interrupts[i] = oldCPU->interrupts[i]; 2895517Snate@binkert.org intstatus = oldCPU->intstatus; 2905517Snate@binkert.org 2915517Snate@binkert.org for (int i = 0; i < execContexts.size(); ++i) 2925517Snate@binkert.org execContexts[i]->profileClear(); 2935517Snate@binkert.org 2945798Snate@binkert.org if (profileEvent) 2955798Snate@binkert.org profileEvent->schedule(curTick); 2965517Snate@binkert.org#endif 2975517Snate@binkert.org} 2985517Snate@binkert.org 2995517Snate@binkert.org 3005517Snate@binkert.org#if FULL_SYSTEM 3015517Snate@binkert.orgBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 3025517Snate@binkert.org : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 3035517Snate@binkert.org{ } 3045517Snate@binkert.org 3055517Snate@binkert.orgvoid 3065517Snate@binkert.orgBaseCPU::ProfileEvent::process() 3075517Snate@binkert.org{ 3085517Snate@binkert.org for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { 3095522Snate@binkert.org ExecContext *xc = cpu->execContexts[i]; 3105517Snate@binkert.org xc->profileSample(); 3115517Snate@binkert.org } 3125517Snate@binkert.org 3135517Snate@binkert.org schedule(curTick + interval); 3144762Snate@binkert.org} 3155517Snate@binkert.org 3165517Snate@binkert.orgvoid 3174762Snate@binkert.orgBaseCPU::post_interrupt(int int_num, int index) 3185517Snate@binkert.org{ 3194762Snate@binkert.org DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 3205517Snate@binkert.org 3215517Snate@binkert.org if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 3225517Snate@binkert.org panic("int_num out of bounds\n"); 3235517Snate@binkert.org 3245517Snate@binkert.org if (index < 0 || index >= sizeof(uint64_t) * 8) 3255517Snate@binkert.org panic("int_num out of bounds\n"); 3265517Snate@binkert.org 3275517Snate@binkert.org checkInterrupts = true; 3285517Snate@binkert.org interrupts[int_num] |= 1 << index; 3295517Snate@binkert.org intstatus |= (ULL(1) << int_num); 3305517Snate@binkert.org} 3315517Snate@binkert.org 3325517Snate@binkert.orgvoid 3335517Snate@binkert.orgBaseCPU::clear_interrupt(int int_num, int index) 3345517Snate@binkert.org{ 3355517Snate@binkert.org DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 3365517Snate@binkert.org 3375517Snate@binkert.org if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 3385517Snate@binkert.org panic("int_num out of bounds\n"); 3395517Snate@binkert.org 3405517Snate@binkert.org if (index < 0 || index >= sizeof(uint64_t) * 8) 3415517Snate@binkert.org panic("int_num out of bounds\n"); 3425517Snate@binkert.org 3434762Snate@binkert.org interrupts[int_num] &= ~(1 << index); 3444762Snate@binkert.org if (interrupts[int_num] == 0) 3454762Snate@binkert.org intstatus &= ~(ULL(1) << int_num); 3464762Snate@binkert.org} 3474762Snate@binkert.org 3484762Snate@binkert.orgvoid 3495517Snate@binkert.orgBaseCPU::clear_interrupts() 3504762Snate@binkert.org{ 3514762Snate@binkert.org DPRINTF(Interrupt, "Interrupts all cleared\n"); 3524762Snate@binkert.org 3534762Snate@binkert.org memset(interrupts, 0, sizeof(interrupts)); 3544382Sbinkertn@umich.edu intstatus = 0; 3554382Sbinkertn@umich.edu} 3565517Snate@binkert.org 3575517Snate@binkert.org 3585517Snate@binkert.orgvoid 3595517Snate@binkert.orgBaseCPU::serialize(std::ostream &os) 3605798Snate@binkert.org{ 3615798Snate@binkert.org SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 3625824Ssaidi@eecs.umich.edu SERIALIZE_SCALAR(intstatus); 3635517Snate@binkert.org} 3645517Snate@binkert.org 3655863Snate@binkert.orgvoid 3665798Snate@binkert.orgBaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 3675798Snate@binkert.org{ 3685798Snate@binkert.org UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 3695798Snate@binkert.org UNSERIALIZE_SCALAR(intstatus); 3705517Snate@binkert.org} 3715517Snate@binkert.org 3725517Snate@binkert.org#endif // FULL_SYSTEM 3735517Snate@binkert.org 3745517Snate@binkert.orgvoid 3755517Snate@binkert.orgBaseCPU::traceFunctionsInternal(Addr pc) 3765517Snate@binkert.org{ 3775517Snate@binkert.org if (!debugSymbolTable) 3785798Snate@binkert.org return; 3795798Snate@binkert.org 3805798Snate@binkert.org // if pc enters different function, print new function symbol and 3815798Snate@binkert.org // update saved range. Otherwise do nothing. 3825798Snate@binkert.org if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 3835798Snate@binkert.org string sym_str; 3845517Snate@binkert.org bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 3855517Snate@binkert.org currentFunctionStart, 3865517Snate@binkert.org currentFunctionEnd); 3875517Snate@binkert.org 3885517Snate@binkert.org if (!found) { 3895517Snate@binkert.org // no symbol found: use addr as label 3905517Snate@binkert.org sym_str = csprintf("0x%x", pc); 3915517Snate@binkert.org currentFunctionStart = pc; 3925517Snate@binkert.org currentFunctionEnd = pc + 1; 3934762Snate@binkert.org } 3944382Sbinkertn@umich.edu 3954762Snate@binkert.org ccprintf(*functionTraceStream, " (%d)\n%d: %s", 3965517Snate@binkert.org curTick - functionEntryTick, curTick, sym_str); 3974382Sbinkertn@umich.edu functionEntryTick = curTick; 3984382Sbinkertn@umich.edu } 3994762Snate@binkert.org} 4004762Snate@binkert.org 4014762Snate@binkert.org 4024762Snate@binkert.orgDEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 4034762Snate@binkert.org