base.cc revision 1388
1/* 2 * Copyright (c) 2002-2004 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <iostream> 30#include <string> 31#include <sstream> 32 33#include "base/cprintf.hh" 34#include "base/loader/symtab.hh" 35#include "base/misc.hh" 36#include "base/output.hh" 37#include "cpu/base_cpu.hh" 38#include "cpu/exec_context.hh" 39#include "sim/param.hh" 40#include "sim/sim_events.hh" 41 42using namespace std; 43 44vector<BaseCPU *> BaseCPU::cpuList; 45 46// This variable reflects the max number of threads in any CPU. Be 47// careful to only use it once all the CPUs that you care about have 48// been initialized 49int maxThreadsPerCPU = 1; 50 51#ifdef FULL_SYSTEM 52BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 53 Counter max_insts_any_thread, 54 Counter max_insts_all_threads, 55 Counter max_loads_any_thread, 56 Counter max_loads_all_threads, 57 System *_system, Tick freq, 58 bool _function_trace, Tick _function_trace_start) 59 : SimObject(_name), frequency(freq), checkInterrupts(true), 60 deferRegistration(_def_reg), number_of_threads(_number_of_threads), 61 system(_system) 62#else 63BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 64 Counter max_insts_any_thread, 65 Counter max_insts_all_threads, 66 Counter max_loads_any_thread, 67 Counter max_loads_all_threads, 68 bool _function_trace, Tick _function_trace_start) 69 : SimObject(_name), deferRegistration(_def_reg), 70 number_of_threads(_number_of_threads) 71#endif 72{ 73 // add self to global list of CPUs 74 cpuList.push_back(this); 75 76 if (number_of_threads > maxThreadsPerCPU) 77 maxThreadsPerCPU = number_of_threads; 78 79 // allocate per-thread instruction-based event queues 80 comInstEventQueue = new EventQueue *[number_of_threads]; 81 for (int i = 0; i < number_of_threads; ++i) 82 comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 83 84 // 85 // set up instruction-count-based termination events, if any 86 // 87 if (max_insts_any_thread != 0) 88 for (int i = 0; i < number_of_threads; ++i) 89 new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 90 "a thread reached the max instruction count"); 91 92 if (max_insts_all_threads != 0) { 93 // allocate & initialize shared downcounter: each event will 94 // decrement this when triggered; simulation will terminate 95 // when counter reaches 0 96 int *counter = new int; 97 *counter = number_of_threads; 98 for (int i = 0; i < number_of_threads; ++i) 99 new CountedExitEvent(comInstEventQueue[i], 100 "all threads reached the max instruction count", 101 max_insts_all_threads, *counter); 102 } 103 104 // allocate per-thread load-based event queues 105 comLoadEventQueue = new EventQueue *[number_of_threads]; 106 for (int i = 0; i < number_of_threads; ++i) 107 comLoadEventQueue[i] = new EventQueue("load-based event queue"); 108 109 // 110 // set up instruction-count-based termination events, if any 111 // 112 if (max_loads_any_thread != 0) 113 for (int i = 0; i < number_of_threads; ++i) 114 new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 115 "a thread reached the max load count"); 116 117 if (max_loads_all_threads != 0) { 118 // allocate & initialize shared downcounter: each event will 119 // decrement this when triggered; simulation will terminate 120 // when counter reaches 0 121 int *counter = new int; 122 *counter = number_of_threads; 123 for (int i = 0; i < number_of_threads; ++i) 124 new CountedExitEvent(comLoadEventQueue[i], 125 "all threads reached the max load count", 126 max_loads_all_threads, *counter); 127 } 128 129#ifdef FULL_SYSTEM 130 memset(interrupts, 0, sizeof(interrupts)); 131 intstatus = 0; 132#endif 133 134 functionTracingEnabled = false; 135 if (_function_trace) { 136 functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 137 currentFunctionStart = currentFunctionEnd = 0; 138 functionEntryTick = _function_trace_start; 139 140 if (_function_trace_start == 0) { 141 functionTracingEnabled = true; 142 } else { 143 Event *e = 144 new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 145 true); 146 e->schedule(_function_trace_start); 147 } 148 } 149} 150 151 152void 153BaseCPU::enableFunctionTrace() 154{ 155 functionTracingEnabled = true; 156} 157 158BaseCPU::~BaseCPU() 159{ 160} 161 162void 163BaseCPU::init() 164{ 165 if (!deferRegistration) 166 registerExecContexts(); 167} 168 169void 170BaseCPU::regStats() 171{ 172 using namespace Stats; 173 174 numCycles 175 .name(name() + ".numCycles") 176 .desc("number of cpu cycles simulated") 177 ; 178 179 int size = execContexts.size(); 180 if (size > 1) { 181 for (int i = 0; i < size; ++i) { 182 stringstream namestr; 183 ccprintf(namestr, "%s.ctx%d", name(), i); 184 execContexts[i]->regStats(namestr.str()); 185 } 186 } else if (size == 1) 187 execContexts[0]->regStats(name()); 188} 189 190 191void 192BaseCPU::registerExecContexts() 193{ 194 for (int i = 0; i < execContexts.size(); ++i) { 195 ExecContext *xc = execContexts[i]; 196 int cpu_id; 197 198#ifdef FULL_SYSTEM 199 cpu_id = system->registerExecContext(xc); 200#else 201 cpu_id = xc->process->registerExecContext(xc); 202#endif 203 204 xc->cpu_id = cpu_id; 205 } 206} 207 208 209void 210BaseCPU::switchOut() 211{ 212 // default: do nothing 213} 214 215void 216BaseCPU::takeOverFrom(BaseCPU *oldCPU) 217{ 218 assert(execContexts.size() == oldCPU->execContexts.size()); 219 220 for (int i = 0; i < execContexts.size(); ++i) { 221 ExecContext *newXC = execContexts[i]; 222 ExecContext *oldXC = oldCPU->execContexts[i]; 223 224 newXC->takeOverFrom(oldXC); 225 assert(newXC->cpu_id == oldXC->cpu_id); 226#ifdef FULL_SYSTEM 227 system->replaceExecContext(newXC, newXC->cpu_id); 228#else 229 assert(newXC->process == oldXC->process); 230 newXC->process->replaceExecContext(newXC, newXC->cpu_id); 231#endif 232 } 233 234#ifdef FULL_SYSTEM 235 for (int i = 0; i < NumInterruptLevels; ++i) 236 interrupts[i] = oldCPU->interrupts[i]; 237 intstatus = oldCPU->intstatus; 238#endif 239} 240 241 242#ifdef FULL_SYSTEM 243void 244BaseCPU::post_interrupt(int int_num, int index) 245{ 246 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 247 248 if (int_num < 0 || int_num >= NumInterruptLevels) 249 panic("int_num out of bounds\n"); 250 251 if (index < 0 || index >= sizeof(uint64_t) * 8) 252 panic("int_num out of bounds\n"); 253 254 checkInterrupts = true; 255 interrupts[int_num] |= 1 << index; 256 intstatus |= (ULL(1) << int_num); 257} 258 259void 260BaseCPU::clear_interrupt(int int_num, int index) 261{ 262 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 263 264 if (int_num < 0 || int_num >= NumInterruptLevels) 265 panic("int_num out of bounds\n"); 266 267 if (index < 0 || index >= sizeof(uint64_t) * 8) 268 panic("int_num out of bounds\n"); 269 270 interrupts[int_num] &= ~(1 << index); 271 if (interrupts[int_num] == 0) 272 intstatus &= ~(ULL(1) << int_num); 273} 274 275void 276BaseCPU::clear_interrupts() 277{ 278 DPRINTF(Interrupt, "Interrupts all cleared\n"); 279 280 memset(interrupts, 0, sizeof(interrupts)); 281 intstatus = 0; 282} 283 284 285void 286BaseCPU::serialize(std::ostream &os) 287{ 288 SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 289 SERIALIZE_SCALAR(intstatus); 290} 291 292void 293BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 294{ 295 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 296 UNSERIALIZE_SCALAR(intstatus); 297} 298 299#endif // FULL_SYSTEM 300 301void 302BaseCPU::traceFunctionsInternal(Addr pc) 303{ 304 if (!debugSymbolTable) 305 return; 306 307 // if pc enters different function, print new function symbol and 308 // update saved range. Otherwise do nothing. 309 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 310 string sym_str; 311 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 312 currentFunctionStart, 313 currentFunctionEnd); 314 315 if (!found) { 316 // no symbol found: use addr as label 317 sym_str = csprintf("0x%x", pc); 318 currentFunctionStart = pc; 319 currentFunctionEnd = pc + 1; 320 } 321 322 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 323 curTick - functionEntryTick, curTick, sym_str); 324 functionEntryTick = curTick; 325 } 326} 327 328 329DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 330