base.cc revision 2856:89691405ec9c
12SN/A/* 213759Sgiacomo.gabrielli@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 37760SGiacomo.Gabrielli@arm.com * All rights reserved. 47760SGiacomo.Gabrielli@arm.com * 57760SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 67760SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are 77760SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright 87760SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer; 97760SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright 107760SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the 117760SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution; 127760SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its 137760SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from 141762SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272SN/A * 282SN/A * Authors: Steve Reinhardt 292SN/A * Nathan Binkert 302SN/A */ 312SN/A 322SN/A#include <iostream> 332SN/A#include <string> 342SN/A#include <sstream> 352SN/A 362SN/A#include "base/cprintf.hh" 372SN/A#include "base/loader/symtab.hh" 382SN/A#include "base/misc.hh" 392665Ssaidi@eecs.umich.edu#include "base/output.hh" 404762Snate@binkert.org#include "cpu/base.hh" 412SN/A#include "cpu/cpuevent.hh" 422SN/A#include "cpu/thread_context.hh" 432410SN/A#include "cpu/profile.hh" 442410SN/A#include "sim/param.hh" 452SN/A#include "sim/process.hh" 464762Snate@binkert.org#include "sim/sim_events.hh" 474762Snate@binkert.org#include "sim/system.hh" 484762Snate@binkert.org 494762Snate@binkert.org#include "base/trace.hh" 504762Snate@binkert.org 512SN/Ausing namespace std; 524762Snate@binkert.org 534762Snate@binkert.orgvector<BaseCPU *> BaseCPU::cpuList; 542SN/A 5510814Sandreas.hansson@arm.com// This variable reflects the max number of threads in any CPU. Be 5610814Sandreas.hansson@arm.com// careful to only use it once all the CPUs that you care about have 5710814Sandreas.hansson@arm.com// been initialized 5810814Sandreas.hansson@arm.comint maxThreadsPerCPU = 1; 5910814Sandreas.hansson@arm.com 6010814Sandreas.hansson@arm.com#if FULL_SYSTEM 6110814Sandreas.hansson@arm.comBaseCPU::BaseCPU(Params *p) 6211683Sfernando.endo2@gmail.com : SimObject(p->name), clock(p->clock), checkInterrupts(true), 6310814Sandreas.hansson@arm.com params(p), number_of_threads(p->numberOfThreads), system(p->system) 6411683Sfernando.endo2@gmail.com#else 6510814Sandreas.hansson@arm.comBaseCPU::BaseCPU(Params *p) 6610814Sandreas.hansson@arm.com : MemObject(p->name), clock(p->clock), params(p), 6710814Sandreas.hansson@arm.com number_of_threads(p->numberOfThreads), system(p->system) 6810814Sandreas.hansson@arm.com#endif 6910814Sandreas.hansson@arm.com{ 7010814Sandreas.hansson@arm.com DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 7110814Sandreas.hansson@arm.com 7210814Sandreas.hansson@arm.com // add self to global list of CPUs 7310814Sandreas.hansson@arm.com cpuList.push_back(this); 7410814Sandreas.hansson@arm.com 7510814Sandreas.hansson@arm.com DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 7613759Sgiacomo.gabrielli@arm.com this); 7710814Sandreas.hansson@arm.com 7813759Sgiacomo.gabrielli@arm.com if (number_of_threads > maxThreadsPerCPU) 7913759Sgiacomo.gabrielli@arm.com maxThreadsPerCPU = number_of_threads; 8013759Sgiacomo.gabrielli@arm.com 8110814Sandreas.hansson@arm.com // allocate per-thread instruction-based event queues 8210814Sandreas.hansson@arm.com comInstEventQueue = new EventQueue *[number_of_threads]; 8310814Sandreas.hansson@arm.com for (int i = 0; i < number_of_threads; ++i) 8410814Sandreas.hansson@arm.com comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 8510814Sandreas.hansson@arm.com 8610814Sandreas.hansson@arm.com // 8710814Sandreas.hansson@arm.com // set up instruction-count-based termination events, if any 8810814Sandreas.hansson@arm.com // 8910814Sandreas.hansson@arm.com if (p->max_insts_any_thread != 0) 9013759Sgiacomo.gabrielli@arm.com for (int i = 0; i < number_of_threads; ++i) 9113759Sgiacomo.gabrielli@arm.com new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread, 9213169Smatt.horsnell@arm.com "a thread reached the max instruction count"); 9313169Smatt.horsnell@arm.com 9413168Smatt.horsnell@arm.com if (p->max_insts_all_threads != 0) { 9513168Smatt.horsnell@arm.com // allocate & initialize shared downcounter: each event will 9613168Smatt.horsnell@arm.com // decrement this when triggered; simulation will terminate 9713168Smatt.horsnell@arm.com // when counter reaches 0 9813168Smatt.horsnell@arm.com int *counter = new int; 9913168Smatt.horsnell@arm.com *counter = number_of_threads; 10013759Sgiacomo.gabrielli@arm.com for (int i = 0; i < number_of_threads; ++i) 10110814Sandreas.hansson@arm.com new CountedExitEvent(comInstEventQueue[i], 10210814Sandreas.hansson@arm.com "all threads reached the max instruction count", 10311683Sfernando.endo2@gmail.com p->max_insts_all_threads, *counter); 10411683Sfernando.endo2@gmail.com } 10510814Sandreas.hansson@arm.com 10610814Sandreas.hansson@arm.com // allocate per-thread load-based event queues 10710814Sandreas.hansson@arm.com comLoadEventQueue = new EventQueue *[number_of_threads]; 1082SN/A for (int i = 0; i < number_of_threads; ++i) 1092410SN/A 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) 383