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