base.cc revision 1355
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 <string> 30#include <sstream> 31#include <iostream> 32 33#include "base/cprintf.hh" 34#include "base/loader/symtab.hh" 35#include "base/misc.hh" 36#include "cpu/base_cpu.hh" 37#include "cpu/exec_context.hh" 38#include "sim/param.hh" 39#include "sim/sim_events.hh" 40 41using namespace std; 42 43vector<BaseCPU *> BaseCPU::cpuList; 44 45// This variable reflects the max number of threads in any CPU. Be 46// careful to only use it once all the CPUs that you care about have 47// been initialized 48int maxThreadsPerCPU = 1; 49 50#ifdef FULL_SYSTEM 51BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 52 Counter max_insts_any_thread, 53 Counter max_insts_all_threads, 54 Counter max_loads_any_thread, 55 Counter max_loads_all_threads, 56 System *_system, Tick freq, 57 bool _function_trace, Tick _function_trace_start) 58 : SimObject(_name), frequency(freq), checkInterrupts(true), 59 deferRegistration(_def_reg), number_of_threads(_number_of_threads), 60 system(_system) 61#else 62BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, 63 Counter max_insts_any_thread, 64 Counter max_insts_all_threads, 65 Counter max_loads_any_thread, 66 Counter max_loads_all_threads, 67 bool _function_trace, Tick _function_trace_start) 68 : SimObject(_name), deferRegistration(_def_reg), 69 number_of_threads(_number_of_threads) 70#endif 71{ 72 // add self to global list of CPUs 73 cpuList.push_back(this); 74 75 if (number_of_threads > maxThreadsPerCPU) 76 maxThreadsPerCPU = number_of_threads; 77 78 // allocate per-thread instruction-based event queues 79 comInstEventQueue = new EventQueue *[number_of_threads]; 80 for (int i = 0; i < number_of_threads; ++i) 81 comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 82 83 // 84 // set up instruction-count-based termination events, if any 85 // 86 if (max_insts_any_thread != 0) 87 for (int i = 0; i < number_of_threads; ++i) 88 new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 89 "a thread reached the max instruction count"); 90 91 if (max_insts_all_threads != 0) { 92 // allocate & initialize shared downcounter: each event will 93 // decrement this when triggered; simulation will terminate 94 // when counter reaches 0 95 int *counter = new int; 96 *counter = number_of_threads; 97 for (int i = 0; i < number_of_threads; ++i) 98 new CountedExitEvent(comInstEventQueue[i], 99 "all threads reached the max instruction count", 100 max_insts_all_threads, *counter); 101 } 102 103 // allocate per-thread load-based event queues 104 comLoadEventQueue = new EventQueue *[number_of_threads]; 105 for (int i = 0; i < number_of_threads; ++i) 106 comLoadEventQueue[i] = new EventQueue("load-based event queue"); 107 108 // 109 // set up instruction-count-based termination events, if any 110 // 111 if (max_loads_any_thread != 0) 112 for (int i = 0; i < number_of_threads; ++i) 113 new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 114 "a thread reached the max load count"); 115 116 if (max_loads_all_threads != 0) { 117 // allocate & initialize shared downcounter: each event will 118 // decrement this when triggered; simulation will terminate 119 // when counter reaches 0 120 int *counter = new int; 121 *counter = number_of_threads; 122 for (int i = 0; i < number_of_threads; ++i) 123 new CountedExitEvent(comLoadEventQueue[i], 124 "all threads reached the max load count", 125 max_loads_all_threads, *counter); 126 } 127 128#ifdef FULL_SYSTEM 129 memset(interrupts, 0, sizeof(interrupts)); 130 intstatus = 0; 131#endif 132 133 functionTracingEnabled = false; 134 if (_function_trace) { 135 std::string filename = csprintf("ftrace.%s", name()); 136 functionTraceStream = makeOutputStream(filename); 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 if (functionTracingEnabled) 161 closeOutputStream(functionTraceStream); 162} 163 164 165void 166BaseCPU::init() 167{ 168 if (!deferRegistration) 169 registerExecContexts(); 170} 171 172void 173BaseCPU::regStats() 174{ 175 using namespace Stats; 176 177 numCycles 178 .name(name() + ".numCycles") 179 .desc("number of cpu cycles simulated") 180 ; 181 182 int size = execContexts.size(); 183 if (size > 1) { 184 for (int i = 0; i < size; ++i) { 185 stringstream namestr; 186 ccprintf(namestr, "%s.ctx%d", name(), i); 187 execContexts[i]->regStats(namestr.str()); 188 } 189 } else if (size == 1) 190 execContexts[0]->regStats(name()); 191} 192 193 194void 195BaseCPU::registerExecContexts() 196{ 197 for (int i = 0; i < execContexts.size(); ++i) { 198 ExecContext *xc = execContexts[i]; 199 int cpu_id; 200 201#ifdef FULL_SYSTEM 202 cpu_id = system->registerExecContext(xc); 203#else 204 cpu_id = xc->process->registerExecContext(xc); 205#endif 206 207 xc->cpu_id = cpu_id; 208 } 209} 210 211 212void 213BaseCPU::switchOut() 214{ 215 // default: do nothing 216} 217 218void 219BaseCPU::takeOverFrom(BaseCPU *oldCPU) 220{ 221 assert(execContexts.size() == oldCPU->execContexts.size()); 222 223 for (int i = 0; i < execContexts.size(); ++i) { 224 ExecContext *newXC = execContexts[i]; 225 ExecContext *oldXC = oldCPU->execContexts[i]; 226 227 newXC->takeOverFrom(oldXC); 228 assert(newXC->cpu_id == oldXC->cpu_id); 229#ifdef FULL_SYSTEM 230 system->replaceExecContext(newXC, newXC->cpu_id); 231#else 232 assert(newXC->process == oldXC->process); 233 newXC->process->replaceExecContext(newXC, newXC->cpu_id); 234#endif 235 } 236 237#ifdef FULL_SYSTEM 238 for (int i = 0; i < NumInterruptLevels; ++i) 239 interrupts[i] = oldCPU->interrupts[i]; 240 intstatus = oldCPU->intstatus; 241#endif 242} 243 244 245#ifdef FULL_SYSTEM 246void 247BaseCPU::post_interrupt(int int_num, int index) 248{ 249 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 250 251 if (int_num < 0 || int_num >= NumInterruptLevels) 252 panic("int_num out of bounds\n"); 253 254 if (index < 0 || index >= sizeof(uint64_t) * 8) 255 panic("int_num out of bounds\n"); 256 257 checkInterrupts = true; 258 interrupts[int_num] |= 1 << index; 259 intstatus |= (ULL(1) << int_num); 260} 261 262void 263BaseCPU::clear_interrupt(int int_num, int index) 264{ 265 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 266 267 if (int_num < 0 || int_num >= NumInterruptLevels) 268 panic("int_num out of bounds\n"); 269 270 if (index < 0 || index >= sizeof(uint64_t) * 8) 271 panic("int_num out of bounds\n"); 272 273 interrupts[int_num] &= ~(1 << index); 274 if (interrupts[int_num] == 0) 275 intstatus &= ~(ULL(1) << int_num); 276} 277 278void 279BaseCPU::clear_interrupts() 280{ 281 DPRINTF(Interrupt, "Interrupts all cleared\n"); 282 283 memset(interrupts, 0, sizeof(interrupts)); 284 intstatus = 0; 285} 286 287 288void 289BaseCPU::serialize(std::ostream &os) 290{ 291 SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 292 SERIALIZE_SCALAR(intstatus); 293} 294 295void 296BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 297{ 298 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 299 UNSERIALIZE_SCALAR(intstatus); 300} 301 302#endif // FULL_SYSTEM 303 304void 305BaseCPU::traceFunctionsInternal(Addr pc) 306{ 307 if (!debugSymbolTable) 308 return; 309 310 // if pc enters different function, print new function symbol and 311 // update saved range. Otherwise do nothing. 312 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 313 string sym_str; 314 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 315 currentFunctionStart, 316 currentFunctionEnd); 317 318 if (!found) { 319 // no symbol found: use addr as label 320 sym_str = csprintf("0x%x", pc); 321 currentFunctionStart = pc; 322 currentFunctionEnd = pc + 1; 323 } 324 325 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 326 curTick - functionEntryTick, curTick, sym_str); 327 functionEntryTick = curTick; 328 } 329} 330 331 332DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 333