base.cc revision 1354
111103Snilay@cs.wisc.edu/* 211103Snilay@cs.wisc.edu * Copyright (c) 2002-2004 The Regents of The University of Michigan 38441SN/A * All rights reserved. 48441SN/A * 57893SN/A * Redistribution and use in source and binary forms, with or without 611680SCurtis.Dunham@arm.com * modification, are permitted provided that the following conditions are 711680SCurtis.Dunham@arm.com * met: redistributions of source code must retain the above copyright 811680SCurtis.Dunham@arm.com * notice, this list of conditions and the following disclaimer; 911570SCurtis.Dunham@arm.com * redistributions in binary form must reproduce the above copyright 1010798Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer in the 1111570SCurtis.Dunham@arm.com * documentation and/or other materials provided with the distribution; 1211570SCurtis.Dunham@arm.com * neither the name of the copyright holders nor the names of its 137893SN/A * contributors may be used to endorse or promote products derived from 147893SN/A * this software without specific prior written permission. 157893SN/A * 167893SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177893SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187893SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197893SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207893SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217893SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2211570SCurtis.Dunham@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2311680SCurtis.Dunham@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411680SCurtis.Dunham@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511680SCurtis.Dunham@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611680SCurtis.Dunham@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2711680SCurtis.Dunham@arm.com */ 2811680SCurtis.Dunham@arm.com 2911680SCurtis.Dunham@arm.com#include <string> 3011680SCurtis.Dunham@arm.com#include <sstream> 3111680SCurtis.Dunham@arm.com#include <iostream> 3211680SCurtis.Dunham@arm.com 3311680SCurtis.Dunham@arm.com#include "base/cprintf.hh" 3411680SCurtis.Dunham@arm.com#include "base/loader/symtab.hh" 3511680SCurtis.Dunham@arm.com#include "base/misc.hh" 3611680SCurtis.Dunham@arm.com#include "cpu/base_cpu.hh" 3711680SCurtis.Dunham@arm.com#include "cpu/exec_context.hh" 3811680SCurtis.Dunham@arm.com#include "sim/param.hh" 3911680SCurtis.Dunham@arm.com#include "sim/sim_events.hh" 4011680SCurtis.Dunham@arm.com 4111680SCurtis.Dunham@arm.comusing namespace std; 4211680SCurtis.Dunham@arm.com 4311680SCurtis.Dunham@arm.comvector<BaseCPU *> BaseCPU::cpuList; 4411680SCurtis.Dunham@arm.com 4511680SCurtis.Dunham@arm.com// This variable reflects the max number of threads in any CPU. Be 4611680SCurtis.Dunham@arm.com// careful to only use it once all the CPUs that you care about have 4711680SCurtis.Dunham@arm.com// been initialized 4811680SCurtis.Dunham@arm.comint maxThreadsPerCPU = 1; 4911680SCurtis.Dunham@arm.com 5011680SCurtis.Dunham@arm.com#ifdef FULL_SYSTEM 5111680SCurtis.Dunham@arm.comBaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 5211680SCurtis.Dunham@arm.com Counter max_insts_any_thread, 5311680SCurtis.Dunham@arm.com Counter max_insts_all_threads, 5411680SCurtis.Dunham@arm.com Counter max_loads_any_thread, 5511680SCurtis.Dunham@arm.com Counter max_loads_all_threads, 5611680SCurtis.Dunham@arm.com System *_system, Tick freq, 5711680SCurtis.Dunham@arm.com bool _function_trace, Tick _function_trace_start) 5811680SCurtis.Dunham@arm.com : SimObject(_name), frequency(freq), checkInterrupts(true), 5911680SCurtis.Dunham@arm.com deferRegistration(_def_reg), number_of_threads(_number_of_threads), 6011680SCurtis.Dunham@arm.com system(_system) 6111680SCurtis.Dunham@arm.com#else 6211680SCurtis.Dunham@arm.comBaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 6311680SCurtis.Dunham@arm.com Counter max_insts_any_thread, 6411680SCurtis.Dunham@arm.com Counter max_insts_all_threads, 6511680SCurtis.Dunham@arm.com Counter max_loads_any_thread, 6611680SCurtis.Dunham@arm.com Counter max_loads_all_threads, 6711680SCurtis.Dunham@arm.com bool _function_trace, Tick _function_trace_start) 6811680SCurtis.Dunham@arm.com : SimObject(_name), deferRegistration(_def_reg), 6911680SCurtis.Dunham@arm.com number_of_threads(_number_of_threads) 7011680SCurtis.Dunham@arm.com#endif 7111680SCurtis.Dunham@arm.com{ 7211680SCurtis.Dunham@arm.com // add self to global list of CPUs 7311680SCurtis.Dunham@arm.com cpuList.push_back(this); 7411680SCurtis.Dunham@arm.com 7511680SCurtis.Dunham@arm.com if (number_of_threads > maxThreadsPerCPU) 7611680SCurtis.Dunham@arm.com maxThreadsPerCPU = number_of_threads; 7711680SCurtis.Dunham@arm.com 7811680SCurtis.Dunham@arm.com // allocate per-thread instruction-based event queues 7911680SCurtis.Dunham@arm.com comInstEventQueue = new EventQueue *[number_of_threads]; 8011680SCurtis.Dunham@arm.com for (int i = 0; i < number_of_threads; ++i) 8111680SCurtis.Dunham@arm.com comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 8211680SCurtis.Dunham@arm.com 8311680SCurtis.Dunham@arm.com // 8411680SCurtis.Dunham@arm.com // set up instruction-count-based termination events, if any 8511680SCurtis.Dunham@arm.com // 8611680SCurtis.Dunham@arm.com if (max_insts_any_thread != 0) 8711680SCurtis.Dunham@arm.com for (int i = 0; i < number_of_threads; ++i) 8811680SCurtis.Dunham@arm.com new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 8911680SCurtis.Dunham@arm.com "a thread reached the max instruction count"); 9011680SCurtis.Dunham@arm.com 9111680SCurtis.Dunham@arm.com if (max_insts_all_threads != 0) { 9211680SCurtis.Dunham@arm.com // allocate & initialize shared downcounter: each event will 9311680SCurtis.Dunham@arm.com // decrement this when triggered; simulation will terminate 9411680SCurtis.Dunham@arm.com // when counter reaches 0 9511680SCurtis.Dunham@arm.com int *counter = new int; 9611680SCurtis.Dunham@arm.com *counter = number_of_threads; 9711680SCurtis.Dunham@arm.com for (int i = 0; i < number_of_threads; ++i) 9811680SCurtis.Dunham@arm.com new CountedExitEvent(comInstEventQueue[i], 9911680SCurtis.Dunham@arm.com "all threads reached the max instruction count", 10011680SCurtis.Dunham@arm.com max_insts_all_threads, *counter); 10111680SCurtis.Dunham@arm.com } 10211680SCurtis.Dunham@arm.com 10311680SCurtis.Dunham@arm.com // allocate per-thread load-based event queues 10411680SCurtis.Dunham@arm.com comLoadEventQueue = new EventQueue *[number_of_threads]; 10511680SCurtis.Dunham@arm.com for (int i = 0; i < number_of_threads; ++i) 10611680SCurtis.Dunham@arm.com comLoadEventQueue[i] = new EventQueue("load-based event queue"); 10711680SCurtis.Dunham@arm.com 10811680SCurtis.Dunham@arm.com // 10911680SCurtis.Dunham@arm.com // set up instruction-count-based termination events, if any 11011680SCurtis.Dunham@arm.com // 11111680SCurtis.Dunham@arm.com if (max_loads_any_thread != 0) 11211680SCurtis.Dunham@arm.com for (int i = 0; i < number_of_threads; ++i) 11311680SCurtis.Dunham@arm.com new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 11411680SCurtis.Dunham@arm.com "a thread reached the max load count"); 11511680SCurtis.Dunham@arm.com 11611680SCurtis.Dunham@arm.com if (max_loads_all_threads != 0) { 11711680SCurtis.Dunham@arm.com // allocate & initialize shared downcounter: each event will 11811680SCurtis.Dunham@arm.com // decrement this when triggered; simulation will terminate 11911680SCurtis.Dunham@arm.com // when counter reaches 0 12011680SCurtis.Dunham@arm.com int *counter = new int; 12111680SCurtis.Dunham@arm.com *counter = number_of_threads; 12211680SCurtis.Dunham@arm.com for (int i = 0; i < number_of_threads; ++i) 12311680SCurtis.Dunham@arm.com new CountedExitEvent(comLoadEventQueue[i], 12411680SCurtis.Dunham@arm.com "all threads reached the max load count", 12511680SCurtis.Dunham@arm.com max_loads_all_threads, *counter); 12611680SCurtis.Dunham@arm.com } 12711680SCurtis.Dunham@arm.com 12811680SCurtis.Dunham@arm.com#ifdef FULL_SYSTEM 12911680SCurtis.Dunham@arm.com memset(interrupts, 0, sizeof(interrupts)); 13011680SCurtis.Dunham@arm.com intstatus = 0; 13111680SCurtis.Dunham@arm.com#endif 13211680SCurtis.Dunham@arm.com 13311680SCurtis.Dunham@arm.com functionTracingEnabled = false; 13411680SCurtis.Dunham@arm.com if (_function_trace) { 13511680SCurtis.Dunham@arm.com std::string filename = csprintf("ftrace.%s", name()); 13611680SCurtis.Dunham@arm.com functionTraceStream = makeOutputStream(filename); 13711680SCurtis.Dunham@arm.com currentFunctionStart = currentFunctionEnd = 0; 13811680SCurtis.Dunham@arm.com functionEntryTick = _function_trace_start; 13911680SCurtis.Dunham@arm.com 14011680SCurtis.Dunham@arm.com if (_function_trace_start == 0) { 14111680SCurtis.Dunham@arm.com functionTracingEnabled = true; 14211680SCurtis.Dunham@arm.com } else { 14311680SCurtis.Dunham@arm.com Event *e = 14411680SCurtis.Dunham@arm.com new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 14511680SCurtis.Dunham@arm.com true); 14611680SCurtis.Dunham@arm.com e->schedule(_function_trace_start); 14711680SCurtis.Dunham@arm.com } 14811680SCurtis.Dunham@arm.com } 14911680SCurtis.Dunham@arm.com} 15011680SCurtis.Dunham@arm.com 15111680SCurtis.Dunham@arm.com 15211680SCurtis.Dunham@arm.comvoid 15311680SCurtis.Dunham@arm.comBaseCPU::enableFunctionTrace() 15411680SCurtis.Dunham@arm.com{ 15511680SCurtis.Dunham@arm.com functionTracingEnabled = true; 15611680SCurtis.Dunham@arm.com} 15711680SCurtis.Dunham@arm.com 15811680SCurtis.Dunham@arm.comBaseCPU::~BaseCPU() 15911680SCurtis.Dunham@arm.com{ 16011680SCurtis.Dunham@arm.com if (functionTracingEnabled) 16111680SCurtis.Dunham@arm.com closeOutputStream(functionTraceStream); 16211680SCurtis.Dunham@arm.com} 16311680SCurtis.Dunham@arm.com 16411680SCurtis.Dunham@arm.com 16511680SCurtis.Dunham@arm.comvoid 16611680SCurtis.Dunham@arm.comBaseCPU::init() 16711680SCurtis.Dunham@arm.com{ 16811680SCurtis.Dunham@arm.com if (!deferRegistration) 16911680SCurtis.Dunham@arm.com registerExecContexts(); 17011680SCurtis.Dunham@arm.com} 17111680SCurtis.Dunham@arm.com 17211680SCurtis.Dunham@arm.comvoid 17311680SCurtis.Dunham@arm.comBaseCPU::regStats() 17411680SCurtis.Dunham@arm.com{ 17511680SCurtis.Dunham@arm.com using namespace Stats; 17611680SCurtis.Dunham@arm.com 17711680SCurtis.Dunham@arm.com numCycles 17811680SCurtis.Dunham@arm.com .name(name() + ".numCycles") 17911680SCurtis.Dunham@arm.com .desc("number of cpu cycles simulated") 18011680SCurtis.Dunham@arm.com ; 18111680SCurtis.Dunham@arm.com 18211680SCurtis.Dunham@arm.com int size = execContexts.size(); 18311680SCurtis.Dunham@arm.com if (size > 1) { 18411680SCurtis.Dunham@arm.com for (int i = 0; i < size; ++i) { 18511680SCurtis.Dunham@arm.com stringstream namestr; 18611680SCurtis.Dunham@arm.com ccprintf(namestr, "%s.ctx%d", name(), i); 18711680SCurtis.Dunham@arm.com execContexts[i]->regStats(namestr.str()); 18811680SCurtis.Dunham@arm.com } 18911680SCurtis.Dunham@arm.com } else if (size == 1) 19011680SCurtis.Dunham@arm.com execContexts[0]->regStats(name()); 19111680SCurtis.Dunham@arm.com} 19211680SCurtis.Dunham@arm.com 19311680SCurtis.Dunham@arm.com 19411680SCurtis.Dunham@arm.comvoid 19511680SCurtis.Dunham@arm.comBaseCPU::registerExecContexts() 19611680SCurtis.Dunham@arm.com{ 19711680SCurtis.Dunham@arm.com for (int i = 0; i < execContexts.size(); ++i) { 19811680SCurtis.Dunham@arm.com ExecContext *xc = execContexts[i]; 19911680SCurtis.Dunham@arm.com int cpu_id; 20011680SCurtis.Dunham@arm.com 20111680SCurtis.Dunham@arm.com#ifdef FULL_SYSTEM 20211680SCurtis.Dunham@arm.com cpu_id = system->registerExecContext(xc); 20311680SCurtis.Dunham@arm.com#else 20411680SCurtis.Dunham@arm.com cpu_id = xc->process->registerExecContext(xc); 20511680SCurtis.Dunham@arm.com#endif 20611680SCurtis.Dunham@arm.com 20711680SCurtis.Dunham@arm.com xc->cpu_id = cpu_id; 20811680SCurtis.Dunham@arm.com } 20911680SCurtis.Dunham@arm.com} 21011680SCurtis.Dunham@arm.com 21111680SCurtis.Dunham@arm.com 21211680SCurtis.Dunham@arm.comvoid 21311680SCurtis.Dunham@arm.comBaseCPU::switchOut() 21411680SCurtis.Dunham@arm.com{ 21511680SCurtis.Dunham@arm.com // default: do nothing 21611680SCurtis.Dunham@arm.com} 21711680SCurtis.Dunham@arm.com 21811680SCurtis.Dunham@arm.comvoid 21911680SCurtis.Dunham@arm.comBaseCPU::takeOverFrom(BaseCPU *oldCPU) 22011680SCurtis.Dunham@arm.com{ 22111680SCurtis.Dunham@arm.com assert(execContexts.size() == oldCPU->execContexts.size()); 22211680SCurtis.Dunham@arm.com 22311680SCurtis.Dunham@arm.com for (int i = 0; i < execContexts.size(); ++i) { 22411680SCurtis.Dunham@arm.com ExecContext *newXC = execContexts[i]; 22511680SCurtis.Dunham@arm.com ExecContext *oldXC = oldCPU->execContexts[i]; 22611680SCurtis.Dunham@arm.com 22711680SCurtis.Dunham@arm.com newXC->takeOverFrom(oldXC); 22811680SCurtis.Dunham@arm.com assert(newXC->cpu_id == oldXC->cpu_id); 22911680SCurtis.Dunham@arm.com#ifdef FULL_SYSTEM 23011680SCurtis.Dunham@arm.com system->replaceExecContext(newXC, newXC->cpu_id); 23111680SCurtis.Dunham@arm.com#else 23211680SCurtis.Dunham@arm.com assert(newXC->process == oldXC->process); 23311680SCurtis.Dunham@arm.com newXC->process->replaceExecContext(newXC, newXC->cpu_id); 23411680SCurtis.Dunham@arm.com#endif 23511680SCurtis.Dunham@arm.com } 23611680SCurtis.Dunham@arm.com 23711680SCurtis.Dunham@arm.com#ifdef FULL_SYSTEM 23811680SCurtis.Dunham@arm.com for (int i = 0; i < NumInterruptLevels; ++i) 23911680SCurtis.Dunham@arm.com interrupts[i] = oldCPU->interrupts[i]; 24011680SCurtis.Dunham@arm.com intstatus = oldCPU->intstatus; 24111680SCurtis.Dunham@arm.com#endif 24211680SCurtis.Dunham@arm.com} 24311680SCurtis.Dunham@arm.com 24411680SCurtis.Dunham@arm.com 24511680SCurtis.Dunham@arm.com#ifdef FULL_SYSTEM 24611680SCurtis.Dunham@arm.comvoid 24711680SCurtis.Dunham@arm.comBaseCPU::post_interrupt(int int_num, int index) 24811680SCurtis.Dunham@arm.com{ 24911680SCurtis.Dunham@arm.com DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 25011680SCurtis.Dunham@arm.com 25111680SCurtis.Dunham@arm.com if (int_num < 0 || int_num >= NumInterruptLevels) 25211680SCurtis.Dunham@arm.com panic("int_num out of bounds\n"); 25311680SCurtis.Dunham@arm.com 25411680SCurtis.Dunham@arm.com if (index < 0 || index >= sizeof(uint64_t) * 8) 25511680SCurtis.Dunham@arm.com panic("int_num out of bounds\n"); 25611680SCurtis.Dunham@arm.com 25711680SCurtis.Dunham@arm.com checkInterrupts = true; 25811680SCurtis.Dunham@arm.com interrupts[int_num] |= 1 << index; 25911680SCurtis.Dunham@arm.com intstatus |= (ULL(1) << int_num); 26011680SCurtis.Dunham@arm.com} 26111680SCurtis.Dunham@arm.com 26211680SCurtis.Dunham@arm.comvoid 26311680SCurtis.Dunham@arm.comBaseCPU::clear_interrupt(int int_num, int index) 26411680SCurtis.Dunham@arm.com{ 26511680SCurtis.Dunham@arm.com DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 26611680SCurtis.Dunham@arm.com 26711680SCurtis.Dunham@arm.com if (int_num < 0 || int_num >= NumInterruptLevels) 26811680SCurtis.Dunham@arm.com panic("int_num out of bounds\n"); 26911680SCurtis.Dunham@arm.com 27011680SCurtis.Dunham@arm.com if (index < 0 || index >= sizeof(uint64_t) * 8) 27111680SCurtis.Dunham@arm.com panic("int_num out of bounds\n"); 27211680SCurtis.Dunham@arm.com 27311680SCurtis.Dunham@arm.com interrupts[int_num] &= ~(1 << index); 27411680SCurtis.Dunham@arm.com if (interrupts[int_num] == 0) 27511680SCurtis.Dunham@arm.com intstatus &= ~(ULL(1) << int_num); 27611680SCurtis.Dunham@arm.com} 27711680SCurtis.Dunham@arm.com 27811680SCurtis.Dunham@arm.comvoid 27911680SCurtis.Dunham@arm.comBaseCPU::clear_interrupts() 28011680SCurtis.Dunham@arm.com{ 28111680SCurtis.Dunham@arm.com DPRINTF(Interrupt, "Interrupts all cleared\n"); 28211680SCurtis.Dunham@arm.com 28311680SCurtis.Dunham@arm.com memset(interrupts, 0, sizeof(interrupts)); 28411680SCurtis.Dunham@arm.com intstatus = 0; 28511680SCurtis.Dunham@arm.com} 28611680SCurtis.Dunham@arm.com 28711680SCurtis.Dunham@arm.com 28811680SCurtis.Dunham@arm.comvoid 28911680SCurtis.Dunham@arm.comBaseCPU::serialize(std::ostream &os) 29011680SCurtis.Dunham@arm.com{ 29111680SCurtis.Dunham@arm.com SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 29211680SCurtis.Dunham@arm.com SERIALIZE_SCALAR(intstatus); 29311680SCurtis.Dunham@arm.com} 29411680SCurtis.Dunham@arm.com 29511680SCurtis.Dunham@arm.comvoid 29611680SCurtis.Dunham@arm.comBaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 29711680SCurtis.Dunham@arm.com{ 29811680SCurtis.Dunham@arm.com UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 29911680SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(intstatus); 30011680SCurtis.Dunham@arm.com} 30111680SCurtis.Dunham@arm.com 30211680SCurtis.Dunham@arm.com#endif // FULL_SYSTEM 30311680SCurtis.Dunham@arm.com 30411680SCurtis.Dunham@arm.comvoid 30511680SCurtis.Dunham@arm.comBaseCPU::traceFunctionsInternal(Addr pc) 30611680SCurtis.Dunham@arm.com{ 30711680SCurtis.Dunham@arm.com if (!debugSymbolTable) 30811680SCurtis.Dunham@arm.com return; 30911680SCurtis.Dunham@arm.com 31011680SCurtis.Dunham@arm.com // if pc enters different function, print new function symbol and 31111680SCurtis.Dunham@arm.com // update saved range. Otherwise do nothing. 31211680SCurtis.Dunham@arm.com if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 31311680SCurtis.Dunham@arm.com string sym_str; 31411680SCurtis.Dunham@arm.com bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 31511680SCurtis.Dunham@arm.com currentFunctionStart, 31611680SCurtis.Dunham@arm.com currentFunctionEnd); 31711680SCurtis.Dunham@arm.com 31811680SCurtis.Dunham@arm.com if (!found) { 31911680SCurtis.Dunham@arm.com // no symbol found: use addr as label 32011680SCurtis.Dunham@arm.com sym_str = csprintf("0x%x", pc); 32111680SCurtis.Dunham@arm.com currentFunctionStart = pc; 32211680SCurtis.Dunham@arm.com currentFunctionEnd = pc + 1; 32311680SCurtis.Dunham@arm.com } 32411680SCurtis.Dunham@arm.com 32511680SCurtis.Dunham@arm.com ccprintf(*functionTraceStream, " (%d)\n%d: %s", 32611680SCurtis.Dunham@arm.com curTick - functionEntryTick, curTick, sym_str); 32711680SCurtis.Dunham@arm.com functionEntryTick = curTick; 32811680SCurtis.Dunham@arm.com } 32911680SCurtis.Dunham@arm.com} 33011680SCurtis.Dunham@arm.com 33111680SCurtis.Dunham@arm.com 33211680SCurtis.Dunham@arm.comDEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 33311680SCurtis.Dunham@arm.com