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