1/* 2 * Copyright (c) 2002-2005 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 * Authors: Steve Reinhardt 29 * Nathan Binkert 30 */ 31 32#include <iostream> 33#include <string> 34#include <sstream> 35 36#include "base/cprintf.hh" 37#include "base/loader/symtab.hh" 38#include "base/misc.hh" 39#include "base/output.hh" 40#include "cpu/base.hh" 41#include "cpu/cpuevent.hh" 42#include "cpu/thread_context.hh" 43#include "cpu/profile.hh" 44#include "sim/param.hh" 45#include "sim/process.hh" 46#include "sim/sim_events.hh" 47#include "sim/system.hh" 48 49#include "base/trace.hh" 50 51using namespace std; 52 53vector<BaseCPU *> BaseCPU::cpuList; 54 55// This variable reflects the max number of threads in any CPU. Be 56// careful to only use it once all the CPUs that you care about have 57// been initialized 58int maxThreadsPerCPU = 1; 59 60#if FULL_SYSTEM 61BaseCPU::BaseCPU(Params *p) 62 : SimObject(p->name), clock(p->clock), checkInterrupts(true), 63 params(p), number_of_threads(p->numberOfThreads), system(p->system) 64#else 65BaseCPU::BaseCPU(Params *p)
|
67 number_of_threads(p->numberOfThreads), system(p->system) 68#endif 69{ 70 DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 71 72 // add self to global list of CPUs 73 cpuList.push_back(this); 74 75 DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 76 this); 77 78 if (number_of_threads > maxThreadsPerCPU) 79 maxThreadsPerCPU = number_of_threads; 80 81 // allocate per-thread instruction-based event queues 82 comInstEventQueue = new EventQueue *[number_of_threads]; 83 for (int i = 0; i < number_of_threads; ++i) 84 comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 85 86 // 87 // set up instruction-count-based termination events, if any 88 // 89 if (p->max_insts_any_thread != 0) 90 for (int i = 0; i < number_of_threads; ++i) 91 new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 92 "a thread reached the max instruction count"); 93 94 if (p->max_insts_all_threads != 0) { 95 // allocate & initialize shared downcounter: each event will 96 // decrement this when triggered; simulation will terminate 97 // when counter reaches 0 98 int *counter = new int; 99 *counter = number_of_threads; 100 for (int i = 0; i < number_of_threads; ++i) 101 new CountedExitEvent(comInstEventQueue[i], 102 "all threads reached the max instruction count", 103 p->max_insts_all_threads, *counter); 104 } 105 106 // allocate per-thread load-based event queues 107 comLoadEventQueue = new EventQueue *[number_of_threads]; 108 for (int i = 0; i < number_of_threads; ++i) 109 comLoadEventQueue[i] = new EventQueue("load-based event queue"); 110 111 // 112 // set up instruction-count-based termination events, if any 113 // 114 if (p->max_loads_any_thread != 0) 115 for (int i = 0; i < number_of_threads; ++i) 116 new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, 117 "a thread reached the max load count"); 118 119 if (p->max_loads_all_threads != 0) { 120 // allocate & initialize shared downcounter: each event will 121 // decrement this when triggered; simulation will terminate 122 // when counter reaches 0 123 int *counter = new int; 124 *counter = number_of_threads; 125 for (int i = 0; i < number_of_threads; ++i) 126 new CountedExitEvent(comLoadEventQueue[i], 127 "all threads reached the max load count", 128 p->max_loads_all_threads, *counter); 129 } 130 131#if FULL_SYSTEM 132 memset(interrupts, 0, sizeof(interrupts)); 133 intstatus = 0; 134#endif 135 136 functionTracingEnabled = false; 137 if (p->functionTrace) { 138 functionTraceStream = simout.find(csprintf("ftrace.%s", name())); 139 currentFunctionStart = currentFunctionEnd = 0; 140 functionEntryTick = p->functionTraceStart; 141 142 if (p->functionTraceStart == 0) { 143 functionTracingEnabled = true; 144 } else { 145 Event *e = 146 new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, 147 true); 148 e->schedule(p->functionTraceStart); 149 } 150 } 151#if FULL_SYSTEM 152 profileEvent = NULL; 153 if (params->profile) 154 profileEvent = new ProfileEvent(this, params->profile); 155#endif 156 157} 158 159BaseCPU::Params::Params() 160{ 161#if FULL_SYSTEM 162 profile = false; 163#endif 164 checker = NULL; 165} 166 167void 168BaseCPU::enableFunctionTrace() 169{ 170 functionTracingEnabled = true; 171} 172 173BaseCPU::~BaseCPU() 174{ 175} 176 177void 178BaseCPU::init() 179{ 180 if (!params->deferRegistration) 181 registerThreadContexts(); 182} 183 184void 185BaseCPU::startup() 186{ 187#if FULL_SYSTEM 188 if (!params->deferRegistration && profileEvent) 189 profileEvent->schedule(curTick); 190#endif 191} 192 193 194void 195BaseCPU::regStats() 196{ 197 using namespace Stats; 198 199 numCycles 200 .name(name() + ".numCycles") 201 .desc("number of cpu cycles simulated") 202 ; 203 204 int size = threadContexts.size(); 205 if (size > 1) { 206 for (int i = 0; i < size; ++i) { 207 stringstream namestr; 208 ccprintf(namestr, "%s.ctx%d", name(), i); 209 threadContexts[i]->regStats(namestr.str()); 210 } 211 } else if (size == 1) 212 threadContexts[0]->regStats(name()); 213 214#if FULL_SYSTEM 215#endif 216} 217 218 219void 220BaseCPU::registerThreadContexts() 221{ 222 for (int i = 0; i < threadContexts.size(); ++i) { 223 ThreadContext *tc = threadContexts[i]; 224 225#if FULL_SYSTEM 226 int id = params->cpu_id; 227 if (id != -1) 228 id += i; 229 230 tc->setCpuId(system->registerThreadContext(tc, id)); 231#else 232 tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc)); 233#endif 234 } 235} 236 237 238void 239BaseCPU::switchOut() 240{ 241 panic("This CPU doesn't support sampling!"); 242} 243 244void 245BaseCPU::takeOverFrom(BaseCPU *oldCPU) 246{ 247 assert(threadContexts.size() == oldCPU->threadContexts.size()); 248 249 for (int i = 0; i < threadContexts.size(); ++i) { 250 ThreadContext *newTC = threadContexts[i]; 251 ThreadContext *oldTC = oldCPU->threadContexts[i]; 252 253 newTC->takeOverFrom(oldTC); 254 255 CpuEvent::replaceThreadContext(oldTC, newTC); 256 257 assert(newTC->readCpuId() == oldTC->readCpuId()); 258#if FULL_SYSTEM 259 system->replaceThreadContext(newTC, newTC->readCpuId()); 260#else 261 assert(newTC->getProcessPtr() == oldTC->getProcessPtr()); 262 newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId()); 263#endif 264 } 265 266#if FULL_SYSTEM 267 for (int i = 0; i < TheISA::NumInterruptLevels; ++i) 268 interrupts[i] = oldCPU->interrupts[i]; 269 intstatus = oldCPU->intstatus; 270 271 for (int i = 0; i < threadContexts.size(); ++i) 272 threadContexts[i]->profileClear(); 273 274 if (profileEvent) 275 profileEvent->schedule(curTick); 276#endif 277} 278 279 280#if FULL_SYSTEM 281BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) 282 : Event(&mainEventQueue), cpu(_cpu), interval(_interval) 283{ } 284 285void 286BaseCPU::ProfileEvent::process() 287{ 288 for (int i = 0, size = cpu->threadContexts.size(); i < size; ++i) { 289 ThreadContext *tc = cpu->threadContexts[i]; 290 tc->profileSample(); 291 } 292 293 schedule(curTick + interval); 294} 295 296void 297BaseCPU::post_interrupt(int int_num, int index) 298{ 299 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 300 301 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 302 panic("int_num out of bounds\n"); 303 304 if (index < 0 || index >= sizeof(uint64_t) * 8) 305 panic("int_num out of bounds\n"); 306 307 checkInterrupts = true; 308 interrupts[int_num] |= 1 << index; 309 intstatus |= (ULL(1) << int_num); 310} 311 312void 313BaseCPU::clear_interrupt(int int_num, int index) 314{ 315 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 316 317 if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) 318 panic("int_num out of bounds\n"); 319 320 if (index < 0 || index >= sizeof(uint64_t) * 8) 321 panic("int_num out of bounds\n"); 322 323 interrupts[int_num] &= ~(1 << index); 324 if (interrupts[int_num] == 0) 325 intstatus &= ~(ULL(1) << int_num); 326} 327 328void 329BaseCPU::clear_interrupts() 330{ 331 DPRINTF(Interrupt, "Interrupts all cleared\n"); 332 333 memset(interrupts, 0, sizeof(interrupts)); 334 intstatus = 0; 335} 336 337 338void 339BaseCPU::serialize(std::ostream &os) 340{ 341 SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 342 SERIALIZE_SCALAR(intstatus); 343} 344 345void 346BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 347{ 348 UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); 349 UNSERIALIZE_SCALAR(intstatus); 350} 351 352#endif // FULL_SYSTEM 353 354void 355BaseCPU::traceFunctionsInternal(Addr pc) 356{ 357 if (!debugSymbolTable) 358 return; 359 360 // if pc enters different function, print new function symbol and 361 // update saved range. Otherwise do nothing. 362 if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 363 string sym_str; 364 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 365 currentFunctionStart, 366 currentFunctionEnd); 367 368 if (!found) { 369 // no symbol found: use addr as label 370 sym_str = csprintf("0x%x", pc); 371 currentFunctionStart = pc; 372 currentFunctionEnd = pc + 1; 373 } 374 375 ccprintf(*functionTraceStream, " (%d)\n%d: %s", 376 curTick - functionEntryTick, curTick, sym_str); 377 functionEntryTick = curTick; 378 } 379} 380 381 382DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
|