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