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