base.cc revision 124
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 196 numInst = 0; 197 last_idle = 0; 198 lastIcacheStall = 0; 199 lastDcacheStall = 0; 200 201 contexts.push_back(xc); 202} 203 204SimpleCPU::~SimpleCPU() 205{ 206} 207 208void 209SimpleCPU::regStats() 210{ 211 BaseCPU::regStats(); 212 213 numInsts 214 .name(name() + ".num_insts") 215 .desc("Number of instructions executed") 216 ; 217 218 numMemRefs 219 .name(name() + ".num_refs") 220 .desc("Number of memory references") 221 ; 222 223 idleCycles 224 .name(name() + ".idle_cycles") 225 .desc("Number of idle cycles") 226 ; 227 228 idleFraction 229 .name(name() + ".idle_fraction") 230 .desc("Percentage of idle cycles") 231 ; 232 233 icacheStallCycles 234 .name(name() + ".icache_stall_cycles") 235 .desc("ICache total stall cycles") 236 .prereq(icacheStallCycles) 237 ; 238 239 dcacheStallCycles 240 .name(name() + ".dcache_stall_cycles") 241 .desc("DCache total stall cycles") 242 .prereq(dcacheStallCycles) 243 ; 244 245 idleFraction = idleCycles / simTicks; 246 247 numInsts = Statistics::scalar(numInst); 248 simInsts += numInsts; 249} 250 251void 252SimpleCPU::serialize() 253{ 254 nameOut(); 255 256#ifdef FULL_SYSTEM 257#if 0 258 // do we need this anymore?? egh 259 childOut("itb", xc->itb); 260 childOut("dtb", xc->dtb); 261 childOut("physmem", physmem); 262#endif 263#endif 264 265 for (int i = 0; i < NumIntRegs; i++) { 266 stringstream buf; 267 ccprintf(buf, "R%02d", i); 268 paramOut(buf.str(), xc->regs.intRegFile[i]); 269 } 270 for (int i = 0; i < NumFloatRegs; i++) { 271 stringstream buf; 272 ccprintf(buf, "F%02d", i); 273 paramOut(buf.str(), xc->regs.floatRegFile.d[i]); 274 } 275 // CPUTraitsType::serializeSpecialRegs(getProxy(), xc->regs); 276} 277 278void 279SimpleCPU::unserialize(IniFile &db, const string &category, ConfigNode *node) 280{ 281 string data; 282 283 for (int i = 0; i < NumIntRegs; i++) { 284 stringstream buf; 285 ccprintf(buf, "R%02d", i); 286 db.findDefault(category, buf.str(), data); 287 to_number(data,xc->regs.intRegFile[i]); 288 } 289 for (int i = 0; i < NumFloatRegs; i++) { 290 stringstream buf; 291 ccprintf(buf, "F%02d", i); 292 db.findDefault(category, buf.str(), data); 293 xc->regs.floatRegFile.d[i] = strtod(data.c_str(),NULL); 294 } 295 296 // Read in Special registers 297 298 // CPUTraitsType::unserializeSpecialRegs(db,category,node,xc->regs); 299} 300 301void 302change_thread_state(int thread_number, int activate, int priority) 303{ 304} 305 306// precise architected memory state accessor macros 307template <class T> 308Fault 309SimpleCPU::read(Addr addr, T& data, unsigned flags) 310{ 311 memReq->reset(addr, sizeof(T), flags); 312 313 // translate to physical address 314 Fault fault = xc->translateDataReadReq(memReq); 315 316 // do functional access 317 if (fault == No_Fault) 318 fault = xc->read(memReq, data); 319 320 if (traceData) { 321 traceData->setAddr(addr); 322 if (fault == No_Fault) 323 traceData->setData(data); 324 } 325 326 // if we have a cache, do cache access too 327 if (fault == No_Fault && dcacheInterface) { 328 memReq->cmd = Read; 329 memReq->completionEvent = NULL; 330 memReq->time = curTick; 331 memReq->flags &= ~UNCACHEABLE; 332 MemAccessResult result = dcacheInterface->access(memReq); 333 334 // Ugly hack to get an event scheduled *only* if the access is 335 // a miss. We really should add first-class support for this 336 // at some point. 337 if (result != MA_HIT && dcacheInterface->doEvents) { 338 memReq->completionEvent = &cacheCompletionEvent; 339 setStatus(DcacheMissStall); 340 } 341 } 342 343 return fault; 344} 345 346#ifndef DOXYGEN_SHOULD_SKIP_THIS 347 348template 349Fault 350SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags); 351 352template 353Fault 354SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags); 355 356template 357Fault 358SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags); 359 360template 361Fault 362SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags); 363 364#endif //DOXYGEN_SHOULD_SKIP_THIS 365 366template<> 367Fault 368SimpleCPU::read(Addr addr, double& data, unsigned flags) 369{ 370 return read(addr, *(uint64_t*)&data, flags); 371} 372 373template<> 374Fault 375SimpleCPU::read(Addr addr, float& data, unsigned flags) 376{ 377 return read(addr, *(uint32_t*)&data, flags); 378} 379 380 381template<> 382Fault 383SimpleCPU::read(Addr addr, int32_t& data, unsigned flags) 384{ 385 return read(addr, (uint32_t&)data, flags); 386} 387 388 389template <class T> 390Fault 391SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 392{ 393 if (traceData) { 394 traceData->setAddr(addr); 395 traceData->setData(data); 396 } 397 398 memReq->reset(addr, sizeof(T), flags); 399 400 // translate to physical address 401 Fault fault = xc->translateDataWriteReq(memReq); 402 403 // do functional access 404 if (fault == No_Fault) 405 fault = xc->write(memReq, data); 406 407 if (fault == No_Fault && dcacheInterface) { 408 memReq->cmd = Write; 409 memReq->data = (uint8_t *)&data; 410 memReq->completionEvent = NULL; 411 memReq->time = curTick; 412 memReq->flags &= ~UNCACHEABLE; 413 MemAccessResult result = dcacheInterface->access(memReq); 414 415 // Ugly hack to get an event scheduled *only* if the access is 416 // a miss. We really should add first-class support for this 417 // at some point. 418 if (result != MA_HIT && dcacheInterface->doEvents) { 419 memReq->completionEvent = &cacheCompletionEvent; 420 setStatus(DcacheMissStall); 421 } 422 } 423 424 if (res && (fault == No_Fault)) 425 *res = memReq->result; 426 427 return fault; 428} 429 430 431#ifndef DOXYGEN_SHOULD_SKIP_THIS 432template 433Fault 434SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 435 436template 437Fault 438SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 439 440template 441Fault 442SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 443 444template 445Fault 446SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 447 448#endif //DOXYGEN_SHOULD_SKIP_THIS 449 450template<> 451Fault 452SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 453{ 454 return write(*(uint64_t*)&data, addr, flags, res); 455} 456 457template<> 458Fault 459SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 460{ 461 return write(*(uint32_t*)&data, addr, flags, res); 462} 463 464 465template<> 466Fault 467SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 468{ 469 return write((uint32_t)data, addr, flags, res); 470} 471 472 473#ifdef FULL_SYSTEM 474Addr 475SimpleCPU::dbg_vtophys(Addr addr) 476{ 477 return vtophys(xc, addr); 478} 479#endif // FULL_SYSTEM 480 481Tick save_cycle = 0; 482 483 484void 485SimpleCPU::processCacheCompletion() 486{ 487 switch (status()) { 488 case IcacheMissStall: 489 icacheStallCycles += curTick - lastIcacheStall; 490 setStatus(IcacheMissComplete); 491 break; 492 case DcacheMissStall: 493 dcacheStallCycles += curTick - lastDcacheStall; 494 setStatus(Running); 495 break; 496 default: 497 panic("SimpleCPU::processCacheCompletion: bad state"); 498 break; 499 } 500} 501 502#ifdef FULL_SYSTEM 503void 504SimpleCPU::post_interrupt(int int_num, int index) 505{ 506 BaseCPU::post_interrupt(int_num, index); 507 508 if (xc->status() == ExecContext::Suspended) { 509 DPRINTF(IPI,"Suspended Processor awoke\n"); 510 xc->setStatus(ExecContext::Active); 511 Annotate::Resume(xc); 512 } 513} 514#endif // FULL_SYSTEM 515 516/* start simulation, program loaded, processor precise state initialized */ 517void 518SimpleCPU::tick() 519{ 520 traceData = NULL; 521 522#ifdef FULL_SYSTEM 523 if (fault == No_Fault && AlphaISA::check_interrupts && 524 xc->cpu->check_interrupts() && 525 !PC_PAL(xc->regs.pc) && 526 status() != IcacheMissComplete) { 527 int ipl = 0; 528 int summary = 0; 529 AlphaISA::check_interrupts = 0; 530 IntReg *ipr = xc->regs.ipr; 531 532 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 533 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 534 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 535 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 536 // See table 4-19 of 21164 hardware reference 537 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 538 summary |= (ULL(1) << i); 539 } 540 } 541 } 542 543 uint64_t interrupts = xc->cpu->intr_status(); 544 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 545 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 546 if (interrupts & (ULL(1) << i)) { 547 // See table 4-19 of 21164 hardware reference 548 ipl = i; 549 summary |= (ULL(1) << i); 550 } 551 } 552 553 if (ipr[TheISA::IPR_ASTRR]) 554 panic("asynchronous traps not implemented\n"); 555 556 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 557 ipr[TheISA::IPR_ISR] = summary; 558 ipr[TheISA::IPR_INTID] = ipl; 559 xc->ev5_trap(Interrupt_Fault); 560 561 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 562 ipr[TheISA::IPR_IPLR], ipl, summary); 563 } 564 } 565#endif 566 567 // maintain $r0 semantics 568 xc->regs.intRegFile[ZeroReg] = 0; 569#ifdef TARGET_ALPHA 570 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 571#endif // TARGET_ALPHA 572 573 if (status() == IcacheMissComplete) { 574 // We've already fetched an instruction and were stalled on an 575 // I-cache miss. No need to fetch it again. 576 577 setStatus(Running); 578 } 579 else { 580 // Try to fetch an instruction 581 582 // set up memory request for instruction fetch 583#ifdef FULL_SYSTEM 584#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 585#else 586#define IFETCH_FLAGS(pc) 0 587#endif 588 589 memReq->cmd = Read; 590 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 591 IFETCH_FLAGS(xc->regs.pc)); 592 593 fault = xc->translateInstReq(memReq); 594 595 if (fault == No_Fault) 596 fault = xc->mem->read(memReq, inst); 597 598 if (icacheInterface && fault == No_Fault) { 599 memReq->completionEvent = NULL; 600 601 memReq->time = curTick; 602 memReq->flags &= ~UNCACHEABLE; 603 MemAccessResult result = icacheInterface->access(memReq); 604 605 // Ugly hack to get an event scheduled *only* if the access is 606 // a miss. We really should add first-class support for this 607 // at some point. 608 if (result != MA_HIT && icacheInterface->doEvents) { 609 memReq->completionEvent = &cacheCompletionEvent; 610 setStatus(IcacheMissStall); 611 return; 612 } 613 } 614 } 615 616 // If we've got a valid instruction (i.e., no fault on instruction 617 // fetch), then execute it. 618 if (fault == No_Fault) { 619 620 // keep an instruction count 621 numInst++; 622 623 // check for instruction-count-based events 624 comInsnEventQueue[0]->serviceEvents(numInst); 625 626 // decode the instruction 627 StaticInstPtr<TheISA> si(inst); 628 629 traceData = Trace::getInstRecord(curTick, xc, this, si, 630 xc->regs.pc); 631 632#ifdef FULL_SYSTEM 633 xc->regs.opcode = (inst >> 26) & 0x3f; 634 xc->regs.ra = (inst >> 21) & 0x1f; 635#endif // FULL_SYSTEM 636 637 xc->func_exe_insn++; 638 639 fault = si->execute(this, xc, traceData); 640 641 if (si->isMemRef()) { 642 numMemRefs++; 643 } 644 645 if (si->isLoad()) { 646 ++numLoad; 647 comLoadEventQueue[0]->serviceEvents(numLoad); 648 } 649 650 if (traceData) 651 traceData->finalize(); 652 653 } // if (fault == No_Fault) 654 655 if (fault != No_Fault) { 656#ifdef FULL_SYSTEM 657 xc->ev5_trap(fault); 658#else // !FULL_SYSTEM 659 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 660#endif // FULL_SYSTEM 661 } 662 else { 663 // go to the next instruction 664 xc->regs.pc = xc->regs.npc; 665 xc->regs.npc += sizeof(MachInst); 666 } 667 668#ifdef FULL_SYSTEM 669 Addr oldpc; 670 do { 671 oldpc = xc->regs.pc; 672 system->pcEventQueue.service(xc); 673 } while (oldpc != xc->regs.pc); 674#endif 675 676 assert(status() == Running || 677 status() == Idle || 678 status() == DcacheMissStall); 679 680 if (status() == Running && !tickEvent.scheduled()) 681 tickEvent.schedule(curTick + 1); 682} 683 684 685//////////////////////////////////////////////////////////////////////// 686// 687// SimpleCPU Simulation Object 688// 689BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 690 691 Param<Counter> max_insts_any_thread; 692 Param<Counter> max_insts_all_threads; 693 Param<Counter> max_loads_any_thread; 694 Param<Counter> max_loads_all_threads; 695 696#ifdef FULL_SYSTEM 697 SimObjectParam<AlphaItb *> itb; 698 SimObjectParam<AlphaDtb *> dtb; 699 SimObjectParam<FunctionalMemory *> mem; 700 SimObjectParam<System *> system; 701 Param<int> cpu_id; 702 Param<int> mult; 703#else 704 SimObjectParam<Process *> workload; 705#endif // FULL_SYSTEM 706 707 SimObjectParam<BaseMem *> icache; 708 SimObjectParam<BaseMem *> dcache; 709 710END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 711 712BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 713 714 INIT_PARAM_DFLT(max_insts_any_thread, 715 "terminate when any thread reaches this insn count", 716 0), 717 INIT_PARAM_DFLT(max_insts_all_threads, 718 "terminate when all threads have reached this insn count", 719 0), 720 INIT_PARAM_DFLT(max_loads_any_thread, 721 "terminate when any thread reaches this load count", 722 0), 723 INIT_PARAM_DFLT(max_loads_all_threads, 724 "terminate when all threads have reached this load count", 725 0), 726 727#ifdef FULL_SYSTEM 728 INIT_PARAM(itb, "Instruction TLB"), 729 INIT_PARAM(dtb, "Data TLB"), 730 INIT_PARAM(mem, "memory"), 731 INIT_PARAM(system, "system object"), 732 INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0), 733 INIT_PARAM_DFLT(mult, "system clock multiplier", 1), 734#else 735 INIT_PARAM(workload, "processes to run"), 736#endif // FULL_SYSTEM 737 738 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), 739 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL) 740 741END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 742 743 744CREATE_SIM_OBJECT(SimpleCPU) 745{ 746#ifdef FULL_SYSTEM 747 if (mult != 1) 748 panic("processor clock multiplier must be 1\n"); 749 750 return new SimpleCPU(getInstanceName(), system, 751 max_insts_any_thread, max_insts_all_threads, 752 max_loads_any_thread, max_loads_all_threads, 753 itb, dtb, mem, 754 (icache) ? icache->getInterface() : NULL, 755 (dcache) ? dcache->getInterface() : NULL, 756 cpu_id, ticksPerSecond * mult); 757#else 758 759 return new SimpleCPU(getInstanceName(), workload, 760 max_insts_any_thread, max_insts_all_threads, 761 max_loads_any_thread, max_loads_all_threads, 762 icache->getInterface(), dcache->getInterface()); 763 764#endif // FULL_SYSTEM 765} 766 767REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 768