base.cc revision 2251
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 if (fault == NoFault) { 351 xc->copySrcAddr = src; 352 xc->copySrcPhysAddr = memReq->paddr + offset; 353 } else { 354 assert(!fault->isAlignmentFault()); 355 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 if (fault == NoFault) { 386 Addr dest_addr = memReq->paddr + offset; 387 // Need to read straight from memory since we have more than 8 bytes. 388 memReq->paddr = xc->copySrcPhysAddr; 389 xc->mem->read(memReq, data); 390 memReq->paddr = dest_addr; 391 xc->mem->write(memReq, data); 392 if (dcacheInterface) { 393 memReq->cmd = Copy; 394 memReq->completionEvent = NULL; 395 memReq->paddr = xc->copySrcPhysAddr; 396 memReq->dest = dest_addr; 397 memReq->size = 64; 398 memReq->time = curTick; 399 memReq->flags &= ~INST_READ; 400 dcacheInterface->access(memReq); 401 } 402 } 403 else 404 assert(!fault->isAlignmentFault()); 405 406 return fault; 407} 408 409// precise architected memory state accessor macros 410template <class T> 411Fault 412SimpleCPU::read(Addr addr, T &data, unsigned flags) 413{ 414 if (status() == DcacheMissStall || status() == DcacheMissSwitch) { 415 Fault fault = xc->read(memReq,data); 416 417 if (traceData) { 418 traceData->setAddr(addr); 419 } 420 return fault; 421 } 422 423 memReq->reset(addr, sizeof(T), flags); 424 425 // translate to physical address 426 Fault fault = xc->translateDataReadReq(memReq); 427 428 // if we have a cache, do cache access too 429 if (fault == NoFault && dcacheInterface) { 430 memReq->cmd = Read; 431 memReq->completionEvent = NULL; 432 memReq->time = curTick; 433 memReq->flags &= ~INST_READ; 434 MemAccessResult result = dcacheInterface->access(memReq); 435 436 // Ugly hack to get an event scheduled *only* if the access is 437 // a miss. We really should add first-class support for this 438 // at some point. 439 if (result != MA_HIT && dcacheInterface->doEvents()) { 440 memReq->completionEvent = &cacheCompletionEvent; 441 lastDcacheStall = curTick; 442 unscheduleTickEvent(); 443 _status = DcacheMissStall; 444 } else { 445 // do functional access 446 fault = xc->read(memReq, data); 447 448 } 449 } else if(fault == NoFault) { 450 // do functional access 451 fault = xc->read(memReq, data); 452 453 } 454 455 if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 456 recordEvent("Uncached Read"); 457 458 return fault; 459} 460 461#ifndef DOXYGEN_SHOULD_SKIP_THIS 462 463template 464Fault 465SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 466 467template 468Fault 469SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 470 471template 472Fault 473SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 474 475template 476Fault 477SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 478 479#endif //DOXYGEN_SHOULD_SKIP_THIS 480 481template<> 482Fault 483SimpleCPU::read(Addr addr, double &data, unsigned flags) 484{ 485 return read(addr, *(uint64_t*)&data, flags); 486} 487 488template<> 489Fault 490SimpleCPU::read(Addr addr, float &data, unsigned flags) 491{ 492 return read(addr, *(uint32_t*)&data, flags); 493} 494 495 496template<> 497Fault 498SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 499{ 500 return read(addr, (uint32_t&)data, flags); 501} 502 503 504template <class T> 505Fault 506SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 507{ 508 memReq->reset(addr, sizeof(T), flags); 509 510 // translate to physical address 511 Fault fault = xc->translateDataWriteReq(memReq); 512 513 // do functional access 514 if (fault == NoFault) 515 fault = xc->write(memReq, data); 516 517 if (fault == NoFault && dcacheInterface) { 518 memReq->cmd = Write; 519 memcpy(memReq->data,(uint8_t *)&data,memReq->size); 520 memReq->completionEvent = NULL; 521 memReq->time = curTick; 522 memReq->flags &= ~INST_READ; 523 MemAccessResult result = dcacheInterface->access(memReq); 524 525 // Ugly hack to get an event scheduled *only* if the access is 526 // a miss. We really should add first-class support for this 527 // at some point. 528 if (result != MA_HIT && dcacheInterface->doEvents()) { 529 memReq->completionEvent = &cacheCompletionEvent; 530 lastDcacheStall = curTick; 531 unscheduleTickEvent(); 532 _status = DcacheMissStall; 533 } 534 } 535 536 if (res && (fault == NoFault)) 537 *res = memReq->result; 538 539 if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 540 recordEvent("Uncached Write"); 541 542 return fault; 543} 544 545 546#ifndef DOXYGEN_SHOULD_SKIP_THIS 547template 548Fault 549SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 550 551template 552Fault 553SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 554 555template 556Fault 557SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 558 559template 560Fault 561SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 562 563#endif //DOXYGEN_SHOULD_SKIP_THIS 564 565template<> 566Fault 567SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 568{ 569 return write(*(uint64_t*)&data, addr, flags, res); 570} 571 572template<> 573Fault 574SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 575{ 576 return write(*(uint32_t*)&data, addr, flags, res); 577} 578 579 580template<> 581Fault 582SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 583{ 584 return write((uint32_t)data, addr, flags, res); 585} 586 587 588#if FULL_SYSTEM 589Addr 590SimpleCPU::dbg_vtophys(Addr addr) 591{ 592 return vtophys(xc, addr); 593} 594#endif // FULL_SYSTEM 595 596void 597SimpleCPU::processCacheCompletion() 598{ 599 switch (status()) { 600 case IcacheMissStall: 601 icacheStallCycles += curTick - lastIcacheStall; 602 _status = IcacheMissComplete; 603 scheduleTickEvent(1); 604 break; 605 case DcacheMissStall: 606 if (memReq->cmd.isRead()) { 607 curStaticInst->execute(this,traceData); 608 if (traceData) 609 traceData->finalize(); 610 } 611 dcacheStallCycles += curTick - lastDcacheStall; 612 _status = Running; 613 scheduleTickEvent(1); 614 break; 615 case DcacheMissSwitch: 616 if (memReq->cmd.isRead()) { 617 curStaticInst->execute(this,traceData); 618 if (traceData) 619 traceData->finalize(); 620 } 621 _status = SwitchedOut; 622 sampler->signalSwitched(); 623 case SwitchedOut: 624 // If this CPU has been switched out due to sampling/warm-up, 625 // ignore any further status changes (e.g., due to cache 626 // misses outstanding at the time of the switch). 627 return; 628 default: 629 panic("SimpleCPU::processCacheCompletion: bad state"); 630 break; 631 } 632} 633 634#if FULL_SYSTEM 635void 636SimpleCPU::post_interrupt(int int_num, int index) 637{ 638 BaseCPU::post_interrupt(int_num, index); 639 640 if (xc->status() == ExecContext::Suspended) { 641 DPRINTF(IPI,"Suspended Processor awoke\n"); 642 xc->activate(); 643 } 644} 645#endif // FULL_SYSTEM 646 647/* start simulation, program loaded, processor precise state initialized */ 648void 649SimpleCPU::tick() 650{ 651 numCycles++; 652 653 traceData = NULL; 654 655 Fault fault = NoFault; 656 657#if FULL_SYSTEM 658 if (checkInterrupts && check_interrupts() && !xc->inPalMode() && 659 status() != IcacheMissComplete) { 660 int ipl = 0; 661 int summary = 0; 662 checkInterrupts = false; 663 664 if (xc->readMiscReg(IPR_SIRR)) { 665 for (int i = INTLEVEL_SOFTWARE_MIN; 666 i < INTLEVEL_SOFTWARE_MAX; i++) { 667 if (xc->readMiscReg(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 (xc->readMiscReg(IPR_ASTRR)) 686 panic("asynchronous traps not implemented\n"); 687 688 if (ipl && ipl > xc->readMiscReg(IPR_IPLR)) { 689 xc->setMiscReg(IPR_ISR, summary); 690 xc->setMiscReg(IPR_INTID, ipl); 691 Fault(new InterruptFault)->invoke(xc); 692 693 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 694 xc->readMiscReg(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(makeExtMI(inst, xc->readPC())); 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->readMiscReg(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 fault->invoke(xc); 816#else // !FULL_SYSTEM 817 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 818#endif // FULL_SYSTEM 819 } 820 else { 821#if THE_ISA != MIPS_ISA 822 // go to the next instruction 823 xc->regs.pc = xc->regs.npc; 824 xc->regs.npc += sizeof(MachInst); 825#else 826 // go to the next instruction 827 xc->regs.pc = xc->regs.npc; 828 xc->regs.npc = xc->regs.nnpc; 829 xc->regs.nnpc += sizeof(MachInst); 830#endif 831 832 } 833 834#if FULL_SYSTEM 835 Addr oldpc; 836 do { 837 oldpc = xc->regs.pc; 838 system->pcEventQueue.service(xc); 839 } while (oldpc != xc->regs.pc); 840#endif 841 842 assert(status() == Running || 843 status() == Idle || 844 status() == DcacheMissStall); 845 846 if (status() == Running && !tickEvent.scheduled()) 847 tickEvent.schedule(curTick + cycles(1)); 848} 849 850//////////////////////////////////////////////////////////////////////// 851// 852// SimpleCPU Simulation Object 853// 854BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 855 856 Param<Counter> max_insts_any_thread; 857 Param<Counter> max_insts_all_threads; 858 Param<Counter> max_loads_any_thread; 859 Param<Counter> max_loads_all_threads; 860 861#if FULL_SYSTEM 862 SimObjectParam<AlphaITB *> itb; 863 SimObjectParam<AlphaDTB *> dtb; 864 SimObjectParam<FunctionalMemory *> mem; 865 SimObjectParam<System *> system; 866 Param<int> cpu_id; 867 Param<Tick> profile; 868#else 869 SimObjectParam<Process *> workload; 870#endif // FULL_SYSTEM 871 872 Param<int> clock; 873 SimObjectParam<BaseMem *> icache; 874 SimObjectParam<BaseMem *> dcache; 875 876 Param<bool> defer_registration; 877 Param<int> width; 878 Param<bool> function_trace; 879 Param<Tick> function_trace_start; 880 881END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 882 883BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 884 885 INIT_PARAM(max_insts_any_thread, 886 "terminate when any thread reaches this inst count"), 887 INIT_PARAM(max_insts_all_threads, 888 "terminate when all threads have reached this inst count"), 889 INIT_PARAM(max_loads_any_thread, 890 "terminate when any thread reaches this load count"), 891 INIT_PARAM(max_loads_all_threads, 892 "terminate when all threads have reached this load count"), 893 894#if FULL_SYSTEM 895 INIT_PARAM(itb, "Instruction TLB"), 896 INIT_PARAM(dtb, "Data TLB"), 897 INIT_PARAM(mem, "memory"), 898 INIT_PARAM(system, "system object"), 899 INIT_PARAM(cpu_id, "processor ID"), 900 INIT_PARAM(profile, ""), 901#else 902 INIT_PARAM(workload, "processes to run"), 903#endif // FULL_SYSTEM 904 905 INIT_PARAM(clock, "clock speed"), 906 INIT_PARAM(icache, "L1 instruction cache object"), 907 INIT_PARAM(dcache, "L1 data cache object"), 908 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 909 INIT_PARAM(width, "cpu width"), 910 INIT_PARAM(function_trace, "Enable function trace"), 911 INIT_PARAM(function_trace_start, "Cycle to start function trace") 912 913END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 914 915 916CREATE_SIM_OBJECT(SimpleCPU) 917{ 918 SimpleCPU::Params *params = new SimpleCPU::Params(); 919 params->name = getInstanceName(); 920 params->numberOfThreads = 1; 921 params->max_insts_any_thread = max_insts_any_thread; 922 params->max_insts_all_threads = max_insts_all_threads; 923 params->max_loads_any_thread = max_loads_any_thread; 924 params->max_loads_all_threads = max_loads_all_threads; 925 params->deferRegistration = defer_registration; 926 params->clock = clock; 927 params->functionTrace = function_trace; 928 params->functionTraceStart = function_trace_start; 929 params->icache_interface = (icache) ? icache->getInterface() : NULL; 930 params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; 931 params->width = width; 932 933#if FULL_SYSTEM 934 params->itb = itb; 935 params->dtb = dtb; 936 params->mem = mem; 937 params->system = system; 938 params->cpu_id = cpu_id; 939 params->profile = profile; 940#else 941 params->process = workload; 942#endif 943 944 SimpleCPU *cpu = new SimpleCPU(params); 945 return cpu; 946} 947 948REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 949 950