base.cc revision 224
1/* 2 * Copyright (c) 2003 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 <cmath> 30#include <cstdio> 31#include <cstdlib> 32#include <iostream> 33#include <iomanip> 34#include <list> 35#include <sstream> 36#include <string> 37 38#include "base/cprintf.hh" 39#include "base/inifile.hh" 40#include "base/loader/symtab.hh" 41#include "base/misc.hh" 42#include "base/pollevent.hh" 43#include "base/range.hh" 44#include "base/trace.hh" 45#include "cpu/base_cpu.hh" 46#include "cpu/exec_context.hh" 47#include "cpu/exetrace.hh" 48#include "cpu/full_cpu/smt.hh" 49#include "cpu/simple_cpu/simple_cpu.hh" 50#include "cpu/static_inst.hh" 51#include "mem/base_mem.hh" 52#include "mem/mem_interface.hh" 53#include "sim/annotation.hh" 54#include "sim/builder.hh" 55#include "sim/debug.hh" 56#include "sim/host.hh" 57#include "sim/sim_events.hh" 58#include "sim/sim_object.hh" 59#include "sim/sim_stats.hh" 60 61#ifdef FULL_SYSTEM 62#include "base/remote_gdb.hh" 63#include "dev/alpha_access.h" 64#include "dev/pciareg.h" 65#include "mem/functional_mem/memory_control.hh" 66#include "mem/functional_mem/physical_memory.hh" 67#include "sim/system.hh" 68#include "targetarch/alpha_memory.hh" 69#include "targetarch/vtophys.hh" 70#else // !FULL_SYSTEM 71#include "eio/eio.hh" 72#include "mem/functional_mem/functional_memory.hh" 73#include "sim/prog.hh" 74#endif // FULL_SYSTEM 75 76using namespace std; 77 78SimpleCPU::TickEvent::TickEvent(SimpleCPU *c) 79 : Event(&mainEventQueue, "SimpleCPU::TickEvent", 100), cpu(c) 80{ 81} 82 83void 84SimpleCPU::TickEvent::process() 85{ 86 cpu->tick(); 87} 88 89const char * 90SimpleCPU::TickEvent::description() 91{ 92 return "SimpleCPU tick event"; 93} 94 95 96SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 97 : Event(&mainEventQueue, "SimpleCPU::CacheCompletionEvent"), 98 cpu(_cpu) 99{ 100} 101 102void SimpleCPU::CacheCompletionEvent::process() 103{ 104 cpu->processCacheCompletion(); 105} 106 107const char * 108SimpleCPU::CacheCompletionEvent::description() 109{ 110 return "SimpleCPU cache completion event"; 111} 112 113#ifdef FULL_SYSTEM 114SimpleCPU::SimpleCPU(const string &_name, 115 System *_system, 116 Counter max_insts_any_thread, 117 Counter max_insts_all_threads, 118 Counter max_loads_any_thread, 119 Counter max_loads_all_threads, 120 AlphaItb *itb, AlphaDtb *dtb, 121 FunctionalMemory *mem, 122 MemInterface *icache_interface, 123 MemInterface *dcache_interface, 124 Tick freq) 125 : BaseCPU(_name, /* number_of_threads */ 1, 126 max_insts_any_thread, max_insts_all_threads, 127 max_loads_any_thread, max_loads_all_threads, 128 _system, freq), 129#else 130SimpleCPU::SimpleCPU(const string &_name, Process *_process, 131 Counter max_insts_any_thread, 132 Counter max_insts_all_threads, 133 Counter max_loads_any_thread, 134 Counter max_loads_all_threads, 135 MemInterface *icache_interface, 136 MemInterface *dcache_interface) 137 : BaseCPU(_name, /* number_of_threads */ 1, 138 max_insts_any_thread, max_insts_all_threads, 139 max_loads_any_thread, max_loads_all_threads), 140#endif 141 tickEvent(this), xc(NULL), cacheCompletionEvent(this) 142{ 143 _status = Idle; 144#ifdef FULL_SYSTEM 145 xc = new ExecContext(this, 0, system, itb, dtb, mem); 146 147 // initialize CPU, including PC 148 TheISA::initCPU(&xc->regs); 149#else 150 xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); 151#endif // !FULL_SYSTEM 152 153 icacheInterface = icache_interface; 154 dcacheInterface = dcache_interface; 155 156 memReq = new MemReq(); 157 memReq->xc = xc; 158 memReq->asid = 0; 159 memReq->data = new uint8_t[64]; 160 161 numInst = 0; 162 numLoad = 0; 163 last_idle = 0; 164 lastIcacheStall = 0; 165 lastDcacheStall = 0; 166 167 execContexts.push_back(xc); 168} 169 170SimpleCPU::~SimpleCPU() 171{ 172} 173 174 175void 176SimpleCPU::switchOut() 177{ 178 _status = SwitchedOut; 179 if (tickEvent.scheduled()) 180 tickEvent.squash(); 181} 182 183 184void 185SimpleCPU::takeOverFrom(BaseCPU *oldCPU) 186{ 187 BaseCPU::takeOverFrom(oldCPU); 188 189 assert(!tickEvent.scheduled()); 190 191 // if any of this CPU's ExecContexts are active, mark the CPU as 192 // running and schedule its tick event. 193 for (int i = 0; i < execContexts.size(); ++i) { 194 ExecContext *xc = execContexts[i]; 195 if (xc->status() == ExecContext::Active && _status != Running) { 196 _status = Running; 197 tickEvent.schedule(curTick); 198 } 199 } 200 201 oldCPU->switchOut(); 202} 203 204 205void 206SimpleCPU::execCtxStatusChg(int thread_num) { 207 assert(thread_num == 0); 208 assert(xc); 209 210 if (xc->status() == ExecContext::Active) 211 setStatus(Running); 212 else 213 setStatus(Idle); 214} 215 216 217void 218SimpleCPU::regStats() 219{ 220 BaseCPU::regStats(); 221 222 numInsts 223 .name(name() + ".num_insts") 224 .desc("Number of instructions executed") 225 ; 226 227 numMemRefs 228 .name(name() + ".num_refs") 229 .desc("Number of memory references") 230 ; 231 232 idleCycles 233 .name(name() + ".idle_cycles") 234 .desc("Number of idle cycles") 235 ; 236 237 idleFraction 238 .name(name() + ".idle_fraction") 239 .desc("Percentage of idle cycles") 240 ; 241 242 icacheStallCycles 243 .name(name() + ".icache_stall_cycles") 244 .desc("ICache total stall cycles") 245 .prereq(icacheStallCycles) 246 ; 247 248 dcacheStallCycles 249 .name(name() + ".dcache_stall_cycles") 250 .desc("DCache total stall cycles") 251 .prereq(dcacheStallCycles) 252 ; 253 254 idleFraction = idleCycles / simTicks; 255 256 numInsts = Statistics::scalar(numInst); 257 simInsts += numInsts; 258} 259 260void 261SimpleCPU::serialize(ostream &os) 262{ 263 SERIALIZE_ENUM(_status); 264 SERIALIZE_SCALAR(inst); 265 xc->serialize(os); 266 nameOut(os, csprintf("%s.tickEvent", name())); 267 tickEvent.serialize(os); 268 nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 269 cacheCompletionEvent.serialize(os); 270} 271 272void 273SimpleCPU::unserialize(const IniFile *db, const string §ion) 274{ 275 UNSERIALIZE_ENUM(_status); 276 UNSERIALIZE_SCALAR(inst); 277 xc->unserialize(db, section); 278 tickEvent.unserialize(db, csprintf("%s.tickEvent", name())); 279 cacheCompletionEvent 280 .unserialize(db, csprintf("%s.cacheCompletionEvent", name())); 281} 282 283void 284change_thread_state(int thread_number, int activate, int priority) 285{ 286} 287 288// precise architected memory state accessor macros 289template <class T> 290Fault 291SimpleCPU::read(Addr addr, T& data, unsigned flags) 292{ 293 memReq->reset(addr, sizeof(T), flags); 294 295 // translate to physical address 296 Fault fault = xc->translateDataReadReq(memReq); 297 298 // do functional access 299 if (fault == No_Fault) 300 fault = xc->read(memReq, data); 301 302 if (traceData) { 303 traceData->setAddr(addr); 304 if (fault == No_Fault) 305 traceData->setData(data); 306 } 307 308 // if we have a cache, do cache access too 309 if (fault == No_Fault && dcacheInterface) { 310 memReq->cmd = Read; 311 memReq->completionEvent = NULL; 312 memReq->time = curTick; 313 memReq->flags &= ~UNCACHEABLE; 314 MemAccessResult result = dcacheInterface->access(memReq); 315 316 // Ugly hack to get an event scheduled *only* if the access is 317 // a miss. We really should add first-class support for this 318 // at some point. 319 if (result != MA_HIT && dcacheInterface->doEvents) { 320 memReq->completionEvent = &cacheCompletionEvent; 321 setStatus(DcacheMissStall); 322 } 323 } 324 325 return fault; 326} 327 328#ifndef DOXYGEN_SHOULD_SKIP_THIS 329 330template 331Fault 332SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags); 333 334template 335Fault 336SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags); 337 338template 339Fault 340SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags); 341 342template 343Fault 344SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags); 345 346#endif //DOXYGEN_SHOULD_SKIP_THIS 347 348template<> 349Fault 350SimpleCPU::read(Addr addr, double& data, unsigned flags) 351{ 352 return read(addr, *(uint64_t*)&data, flags); 353} 354 355template<> 356Fault 357SimpleCPU::read(Addr addr, float& data, unsigned flags) 358{ 359 return read(addr, *(uint32_t*)&data, flags); 360} 361 362 363template<> 364Fault 365SimpleCPU::read(Addr addr, int32_t& data, unsigned flags) 366{ 367 return read(addr, (uint32_t&)data, flags); 368} 369 370 371template <class T> 372Fault 373SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 374{ 375 if (traceData) { 376 traceData->setAddr(addr); 377 traceData->setData(data); 378 } 379 380 memReq->reset(addr, sizeof(T), flags); 381 382 // translate to physical address 383 Fault fault = xc->translateDataWriteReq(memReq); 384 385 // do functional access 386 if (fault == No_Fault) 387 fault = xc->write(memReq, data); 388 389 if (fault == No_Fault && dcacheInterface) { 390 memReq->cmd = Write; 391 memcpy(memReq->data,(uint8_t *)&data,memReq->size); 392 memReq->completionEvent = NULL; 393 memReq->time = curTick; 394 memReq->flags &= ~UNCACHEABLE; 395 MemAccessResult result = dcacheInterface->access(memReq); 396 397 // Ugly hack to get an event scheduled *only* if the access is 398 // a miss. We really should add first-class support for this 399 // at some point. 400 if (result != MA_HIT && dcacheInterface->doEvents) { 401 memReq->completionEvent = &cacheCompletionEvent; 402 setStatus(DcacheMissStall); 403 } 404 } 405 406 if (res && (fault == No_Fault)) 407 *res = memReq->result; 408 409 return fault; 410} 411 412 413#ifndef DOXYGEN_SHOULD_SKIP_THIS 414template 415Fault 416SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 417 418template 419Fault 420SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 421 422template 423Fault 424SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 425 426template 427Fault 428SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 429 430#endif //DOXYGEN_SHOULD_SKIP_THIS 431 432template<> 433Fault 434SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 435{ 436 return write(*(uint64_t*)&data, addr, flags, res); 437} 438 439template<> 440Fault 441SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 442{ 443 return write(*(uint32_t*)&data, addr, flags, res); 444} 445 446 447template<> 448Fault 449SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 450{ 451 return write((uint32_t)data, addr, flags, res); 452} 453 454 455#ifdef FULL_SYSTEM 456Addr 457SimpleCPU::dbg_vtophys(Addr addr) 458{ 459 return vtophys(xc, addr); 460} 461#endif // FULL_SYSTEM 462 463Tick save_cycle = 0; 464 465 466void 467SimpleCPU::processCacheCompletion() 468{ 469 switch (status()) { 470 case IcacheMissStall: 471 icacheStallCycles += curTick - lastIcacheStall; 472 setStatus(IcacheMissComplete); 473 break; 474 case DcacheMissStall: 475 dcacheStallCycles += curTick - lastDcacheStall; 476 setStatus(Running); 477 break; 478 case SwitchedOut: 479 // If this CPU has been switched out due to sampling/warm-up, 480 // ignore any further status changes (e.g., due to cache 481 // misses outstanding at the time of the switch). 482 return; 483 default: 484 panic("SimpleCPU::processCacheCompletion: bad state"); 485 break; 486 } 487} 488 489#ifdef FULL_SYSTEM 490void 491SimpleCPU::post_interrupt(int int_num, int index) 492{ 493 BaseCPU::post_interrupt(int_num, index); 494 495 if (xc->status() == ExecContext::Suspended) { 496 DPRINTF(IPI,"Suspended Processor awoke\n"); 497 xc->setStatus(ExecContext::Active); 498 Annotate::Resume(xc); 499 } 500} 501#endif // FULL_SYSTEM 502 503/* start simulation, program loaded, processor precise state initialized */ 504void 505SimpleCPU::tick() 506{ 507 traceData = NULL; 508 509 Fault fault = No_Fault; 510 511#ifdef FULL_SYSTEM 512 if (AlphaISA::check_interrupts && 513 xc->cpu->check_interrupts() && 514 !PC_PAL(xc->regs.pc) && 515 status() != IcacheMissComplete) { 516 int ipl = 0; 517 int summary = 0; 518 AlphaISA::check_interrupts = 0; 519 IntReg *ipr = xc->regs.ipr; 520 521 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 522 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 523 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 524 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 525 // See table 4-19 of 21164 hardware reference 526 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 527 summary |= (ULL(1) << i); 528 } 529 } 530 } 531 532 uint64_t interrupts = xc->cpu->intr_status(); 533 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 534 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 535 if (interrupts & (ULL(1) << i)) { 536 // See table 4-19 of 21164 hardware reference 537 ipl = i; 538 summary |= (ULL(1) << i); 539 } 540 } 541 542 if (ipr[TheISA::IPR_ASTRR]) 543 panic("asynchronous traps not implemented\n"); 544 545 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 546 ipr[TheISA::IPR_ISR] = summary; 547 ipr[TheISA::IPR_INTID] = ipl; 548 xc->ev5_trap(Interrupt_Fault); 549 550 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 551 ipr[TheISA::IPR_IPLR], ipl, summary); 552 } 553 } 554#endif 555 556 // maintain $r0 semantics 557 xc->regs.intRegFile[ZeroReg] = 0; 558#ifdef TARGET_ALPHA 559 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 560#endif // TARGET_ALPHA 561 562 if (status() == IcacheMissComplete) { 563 // We've already fetched an instruction and were stalled on an 564 // I-cache miss. No need to fetch it again. 565 566 setStatus(Running); 567 } 568 else { 569 // Try to fetch an instruction 570 571 // set up memory request for instruction fetch 572#ifdef FULL_SYSTEM 573#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 574#else 575#define IFETCH_FLAGS(pc) 0 576#endif 577 578 memReq->cmd = Read; 579 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 580 IFETCH_FLAGS(xc->regs.pc)); 581 582 fault = xc->translateInstReq(memReq); 583 584 if (fault == No_Fault) 585 fault = xc->mem->read(memReq, inst); 586 587 if (icacheInterface && fault == No_Fault) { 588 memReq->completionEvent = NULL; 589 590 memReq->time = curTick; 591 memReq->flags &= ~UNCACHEABLE; 592 MemAccessResult result = icacheInterface->access(memReq); 593 594 // Ugly hack to get an event scheduled *only* if the access is 595 // a miss. We really should add first-class support for this 596 // at some point. 597 if (result != MA_HIT && icacheInterface->doEvents) { 598 memReq->completionEvent = &cacheCompletionEvent; 599 setStatus(IcacheMissStall); 600 return; 601 } 602 } 603 } 604 605 // If we've got a valid instruction (i.e., no fault on instruction 606 // fetch), then execute it. 607 if (fault == No_Fault) { 608 609 // keep an instruction count 610 numInst++; 611 612 // check for instruction-count-based events 613 comInsnEventQueue[0]->serviceEvents(numInst); 614 615 // decode the instruction 616 StaticInstPtr<TheISA> si(inst); 617 618 traceData = Trace::getInstRecord(curTick, xc, this, si, 619 xc->regs.pc); 620 621#ifdef FULL_SYSTEM 622 xc->regs.opcode = (inst >> 26) & 0x3f; 623 xc->regs.ra = (inst >> 21) & 0x1f; 624#endif // FULL_SYSTEM 625 626 xc->func_exe_insn++; 627 628 fault = si->execute(this, xc, traceData); 629 630 if (si->isMemRef()) { 631 numMemRefs++; 632 } 633 634 if (si->isLoad()) { 635 ++numLoad; 636 comLoadEventQueue[0]->serviceEvents(numLoad); 637 } 638 639 if (traceData) 640 traceData->finalize(); 641 642 } // if (fault == No_Fault) 643 644 if (fault != No_Fault) { 645#ifdef FULL_SYSTEM 646 xc->ev5_trap(fault); 647#else // !FULL_SYSTEM 648 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 649#endif // FULL_SYSTEM 650 } 651 else { 652 // go to the next instruction 653 xc->regs.pc = xc->regs.npc; 654 xc->regs.npc += sizeof(MachInst); 655 } 656 657#ifdef FULL_SYSTEM 658 Addr oldpc; 659 do { 660 oldpc = xc->regs.pc; 661 system->pcEventQueue.service(xc); 662 } while (oldpc != xc->regs.pc); 663#endif 664 665 assert(status() == Running || 666 status() == Idle || 667 status() == DcacheMissStall); 668 669 if (status() == Running && !tickEvent.scheduled()) 670 tickEvent.schedule(curTick + 1); 671} 672 673 674//////////////////////////////////////////////////////////////////////// 675// 676// SimpleCPU Simulation Object 677// 678BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 679 680 Param<Counter> max_insts_any_thread; 681 Param<Counter> max_insts_all_threads; 682 Param<Counter> max_loads_any_thread; 683 Param<Counter> max_loads_all_threads; 684 685#ifdef FULL_SYSTEM 686 SimObjectParam<AlphaItb *> itb; 687 SimObjectParam<AlphaDtb *> dtb; 688 SimObjectParam<FunctionalMemory *> mem; 689 SimObjectParam<System *> system; 690 Param<int> mult; 691#else 692 SimObjectParam<Process *> workload; 693#endif // FULL_SYSTEM 694 695 SimObjectParam<BaseMem *> icache; 696 SimObjectParam<BaseMem *> dcache; 697 698 Param<bool> defer_registration; 699 700END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 701 702BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 703 704 INIT_PARAM_DFLT(max_insts_any_thread, 705 "terminate when any thread reaches this insn count", 706 0), 707 INIT_PARAM_DFLT(max_insts_all_threads, 708 "terminate when all threads have reached this insn count", 709 0), 710 INIT_PARAM_DFLT(max_loads_any_thread, 711 "terminate when any thread reaches this load count", 712 0), 713 INIT_PARAM_DFLT(max_loads_all_threads, 714 "terminate when all threads have reached this load count", 715 0), 716 717#ifdef FULL_SYSTEM 718 INIT_PARAM(itb, "Instruction TLB"), 719 INIT_PARAM(dtb, "Data TLB"), 720 INIT_PARAM(mem, "memory"), 721 INIT_PARAM(system, "system object"), 722 INIT_PARAM_DFLT(mult, "system clock multiplier", 1), 723#else 724 INIT_PARAM(workload, "processes to run"), 725#endif // FULL_SYSTEM 726 727 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), 728 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), 729 INIT_PARAM_DFLT(defer_registration, "defer registration with system " 730 "(for sampling)", false) 731 732END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 733 734 735CREATE_SIM_OBJECT(SimpleCPU) 736{ 737 SimpleCPU *cpu; 738#ifdef FULL_SYSTEM 739 if (mult != 1) 740 panic("processor clock multiplier must be 1\n"); 741 742 cpu = new SimpleCPU(getInstanceName(), system, 743 max_insts_any_thread, max_insts_all_threads, 744 max_loads_any_thread, max_loads_all_threads, 745 itb, dtb, mem, 746 (icache) ? icache->getInterface() : NULL, 747 (dcache) ? dcache->getInterface() : NULL, 748 ticksPerSecond * mult); 749#else 750 751 cpu = new SimpleCPU(getInstanceName(), workload, 752 max_insts_any_thread, max_insts_all_threads, 753 max_loads_any_thread, max_loads_all_threads, 754 (icache) ? icache->getInterface() : NULL, 755 (dcache) ? dcache->getInterface() : NULL); 756 757#endif // FULL_SYSTEM 758 759 if (!defer_registration) { 760 cpu->registerExecContexts(); 761 } 762 763 return cpu; 764} 765 766REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 767