base.cc revision 2741
12131SN/A/* 22131SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32131SN/A * All rights reserved. 42131SN/A * 52131SN/A * Redistribution and use in source and binary forms, with or without 62131SN/A * modification, are permitted provided that the following conditions are 72131SN/A * met: redistributions of source code must retain the above copyright 82131SN/A * notice, this list of conditions and the following disclaimer; 92131SN/A * redistributions in binary form must reproduce the above copyright 102131SN/A * notice, this list of conditions and the following disclaimer in the 112131SN/A * documentation and/or other materials provided with the distribution; 122131SN/A * neither the name of the copyright holders nor the names of its 132131SN/A * contributors may be used to endorse or promote products derived from 142131SN/A * this software without specific prior written permission. 152131SN/A * 162131SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172131SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182131SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192131SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202131SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212131SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222131SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232131SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242131SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252131SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262131SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282935Sksewell@umich.edu * Authors: Steve Reinhardt 292935Sksewell@umich.edu * Korey Sewell 302131SN/A */ 312131SN/A 322239SN/A#include "arch/utility.hh" 332239SN/A#include "base/cprintf.hh" 342131SN/A#include "base/inifile.hh" 352131SN/A#include "base/loader/symtab.hh" 362447SN/A#include "base/misc.hh" 372447SN/A#include "base/pollevent.hh" 382447SN/A#include "base/range.hh" 392447SN/A#include "base/stats/events.hh" 402447SN/A#include "base/trace.hh" 412447SN/A#include "cpu/base.hh" 422447SN/A#include "cpu/exetrace.hh" 432131SN/A#include "cpu/profile.hh" 442239SN/A#include "cpu/sampler/sampler.hh" 452131SN/A#include "cpu/simple/base.hh" 462447SN/A#include "cpu/simple_thread.hh" 472447SN/A#include "cpu/smt.hh" 482447SN/A#include "cpu/static_inst.hh" 492131SN/A#include "cpu/thread_context.hh" 502447SN/A#include "kern/kernel_stats.hh" 512680Sktlim@umich.edu#include "mem/packet_impl.hh" 522447SN/A#include "sim/builder.hh" 532447SN/A#include "sim/byteswap.hh" 542447SN/A#include "sim/debug.hh" 552131SN/A#include "sim/host.hh" 562131SN/A#include "sim/sim_events.hh" 572447SN/A#include "sim/sim_object.hh" 582131SN/A#include "sim/stats.hh" 592447SN/A 602447SN/A#if FULL_SYSTEM 612447SN/A#include "base/remote_gdb.hh" 622447SN/A#include "sim/system.hh" 632131SN/A#include "arch/tlb.hh" 642447SN/A#include "arch/stacktrace.hh" 652447SN/A#include "arch/vtophys.hh" 662447SN/A#else // !FULL_SYSTEM 672447SN/A#include "mem/mem_object.hh" 682447SN/A#endif // FULL_SYSTEM 692131SN/A 702447SN/Ausing namespace std; 712131SN/Ausing namespace TheISA; 722447SN/A 732447SN/ABaseSimpleCPU::BaseSimpleCPU(Params *p) 742447SN/A : BaseCPU(p), mem(p->mem), thread(NULL) 752447SN/A{ 762131SN/A#if FULL_SYSTEM 772447SN/A thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); 782447SN/A#else 792447SN/A thread = new SimpleThread(this, /* thread_num */ 0, p->process, 802447SN/A /* asid */ 0, mem); 812447SN/A#endif // !FULL_SYSTEM 822131SN/A 834661Sksewell@umich.edu thread->setStatus(ThreadContext::Suspended); 844661Sksewell@umich.edu 854661Sksewell@umich.edu tc = thread->getTC(); 864661Sksewell@umich.edu 874661Sksewell@umich.edu numInst = 0; 884661Sksewell@umich.edu startNumInst = 0; 894661Sksewell@umich.edu numLoad = 0; 904661Sksewell@umich.edu startNumLoad = 0; 914661Sksewell@umich.edu lastIcacheStall = 0; 924661Sksewell@umich.edu lastDcacheStall = 0; 934661Sksewell@umich.edu 944661Sksewell@umich.edu threadContexts.push_back(tc); 954661Sksewell@umich.edu} 964661Sksewell@umich.edu 974661Sksewell@umich.eduBaseSimpleCPU::~BaseSimpleCPU() 984661Sksewell@umich.edu{ 994661Sksewell@umich.edu} 1004661Sksewell@umich.edu 1014661Sksewell@umich.eduvoid 1024661Sksewell@umich.eduBaseSimpleCPU::deallocateContext(int thread_num) 1034661Sksewell@umich.edu{ 1044661Sksewell@umich.edu // for now, these are equivalent 1054661Sksewell@umich.edu suspendContext(thread_num); 1064661Sksewell@umich.edu} 1074661Sksewell@umich.edu 1084661Sksewell@umich.edu 1094661Sksewell@umich.eduvoid 1104661Sksewell@umich.eduBaseSimpleCPU::haltContext(int thread_num) 1114661Sksewell@umich.edu{ 1124661Sksewell@umich.edu // for now, these are equivalent 1134661Sksewell@umich.edu suspendContext(thread_num); 1144661Sksewell@umich.edu} 1154661Sksewell@umich.edu 1164661Sksewell@umich.edu 1174661Sksewell@umich.eduvoid 1184661Sksewell@umich.eduBaseSimpleCPU::regStats() 1192447SN/A{ 1202131SN/A using namespace Stats; 1212447SN/A 1222447SN/A BaseCPU::regStats(); 1232447SN/A 1242447SN/A numInsts 1252447SN/A .name(name() + ".num_insts") 1262447SN/A .desc("Number of instructions executed") 1272447SN/A ; 1282447SN/A 1292447SN/A numMemRefs 1302447SN/A .name(name() + ".num_refs") 1312447SN/A .desc("Number of memory references") 1322447SN/A ; 1332447SN/A 1342447SN/A notIdleFraction 1352131SN/A .name(name() + ".not_idle_fraction") 1362447SN/A .desc("Percentage of non-idle cycles") 1372447SN/A ; 1382447SN/A 1394661Sksewell@umich.edu idleFraction 1402447SN/A .name(name() + ".idle_fraction") 1412131SN/A .desc("Percentage of idle cycles") 1424661Sksewell@umich.edu ; 1434661Sksewell@umich.edu 1444661Sksewell@umich.edu icacheStallCycles 1454661Sksewell@umich.edu .name(name() + ".icache_stall_cycles") 1464661Sksewell@umich.edu .desc("ICache total stall cycles") 1474661Sksewell@umich.edu .prereq(icacheStallCycles) 1484661Sksewell@umich.edu ; 1494661Sksewell@umich.edu 1504661Sksewell@umich.edu dcacheStallCycles 1514661Sksewell@umich.edu .name(name() + ".dcache_stall_cycles") 1524661Sksewell@umich.edu .desc("DCache total stall cycles") 1534661Sksewell@umich.edu .prereq(dcacheStallCycles) 1544661Sksewell@umich.edu ; 1554661Sksewell@umich.edu 1564661Sksewell@umich.edu icacheRetryCycles 1574661Sksewell@umich.edu .name(name() + ".icache_retry_cycles") 1584661Sksewell@umich.edu .desc("ICache total retry cycles") 1594661Sksewell@umich.edu .prereq(icacheRetryCycles) 1604661Sksewell@umich.edu ; 1614661Sksewell@umich.edu 1624661Sksewell@umich.edu dcacheRetryCycles 1634661Sksewell@umich.edu .name(name() + ".dcache_retry_cycles") 1644661Sksewell@umich.edu .desc("DCache total retry cycles") 1654661Sksewell@umich.edu .prereq(dcacheRetryCycles) 1664661Sksewell@umich.edu ; 1674661Sksewell@umich.edu 1684661Sksewell@umich.edu idleFraction = constant(1.0) - notIdleFraction; 1694661Sksewell@umich.edu} 1704661Sksewell@umich.edu 1714661Sksewell@umich.eduvoid 1724661Sksewell@umich.eduBaseSimpleCPU::resetStats() 1734661Sksewell@umich.edu{ 1744661Sksewell@umich.edu startNumInst = numInst; 1754661Sksewell@umich.edu // notIdleFraction = (_status != Idle); 1764661Sksewell@umich.edu} 1774661Sksewell@umich.edu 1784661Sksewell@umich.eduvoid 1794661Sksewell@umich.eduBaseSimpleCPU::serialize(ostream &os) 1804661Sksewell@umich.edu{ 1814661Sksewell@umich.edu BaseCPU::serialize(os); 1822447SN/A SERIALIZE_SCALAR(inst); 1832131SN/A nameOut(os, csprintf("%s.xc", name())); 1842447SN/A thread->serialize(os); 1852447SN/A} 1862447SN/A 1872447SN/Avoid 1882447SN/ABaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1892447SN/A{ 1902131SN/A BaseCPU::unserialize(cp, section); 1912447SN/A UNSERIALIZE_SCALAR(inst); 1922447SN/A thread->unserialize(cp, csprintf("%s.xc", section)); 1932447SN/A} 1942447SN/A 1952680Sktlim@umich.eduvoid 1962447SN/Achange_thread_state(int thread_number, int activate, int priority) 1972447SN/A{ 1982131SN/A} 1992447SN/A 2002131SN/AFault 2012447SN/ABaseSimpleCPU::copySrcTranslate(Addr src) 2022447SN/A{ 2032447SN/A#if 0 2042447SN/A static bool no_warn = true; 2052447SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 2062447SN/A // Only support block sizes of 64 atm. 2072131SN/A assert(blk_size == 64); 2082447SN/A int offset = src & (blk_size - 1); 2092447SN/A 2102447SN/A // Make sure block doesn't span page 2112447SN/A if (no_warn && 2122131SN/A (src & PageMask) != ((src + blk_size) & PageMask) && 2132447SN/A (src >> 40) != 0xfffffc) { 2142131SN/A warn("Copied block source spans pages %x.", src); 2152447SN/A no_warn = false; 2162447SN/A } 2172447SN/A 2182447SN/A memReq->reset(src & ~(blk_size - 1), blk_size); 2192131SN/A 2202447SN/A // translate to physical address 2212447SN/A Fault fault = thread->translateDataReadReq(req); 2222447SN/A 2232447SN/A if (fault == NoFault) { 2242131SN/A thread->copySrcAddr = src; 2252447SN/A thread->copySrcPhysAddr = memReq->paddr + offset; 2262131SN/A } else { 2272447SN/A assert(!fault->isAlignmentFault()); 2282447SN/A 2292447SN/A thread->copySrcAddr = 0; 2302447SN/A thread->copySrcPhysAddr = 0; 2312131SN/A } 2322447SN/A return fault; 2332447SN/A#else 2342447SN/A return NoFault; 2352447SN/A#endif 2362131SN/A} 2372447SN/A 2382131SN/AFault 2392447SN/ABaseSimpleCPU::copy(Addr dest) 2402447SN/A{ 2412447SN/A#if 0 2422447SN/A static bool no_warn = true; 2432131SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 2442447SN/A // Only support block sizes of 64 atm. 2452447SN/A assert(blk_size == 64); 2462447SN/A uint8_t data[blk_size]; 2472447SN/A //assert(thread->copySrcAddr); 2482131SN/A int offset = dest & (blk_size - 1); 2492447SN/A 2502131SN/A // Make sure block doesn't span page 2512447SN/A if (no_warn && 2522447SN/A (dest & PageMask) != ((dest + blk_size) & PageMask) && 2532447SN/A (dest >> 40) != 0xfffffc) { 2542447SN/A no_warn = false; 2552131SN/A warn("Copied block destination spans pages %x. ", dest); 2562447SN/A } 2572447SN/A 2582447SN/A memReq->reset(dest & ~(blk_size -1), blk_size); 2592447SN/A // translate to physical address 2602131SN/A Fault fault = thread->translateDataWriteReq(req); 2612447SN/A 2622131SN/A if (fault == NoFault) { 2632447SN/A Addr dest_addr = memReq->paddr + offset; 2642447SN/A // Need to read straight from memory since we have more than 8 bytes. 2652447SN/A memReq->paddr = thread->copySrcPhysAddr; 2662447SN/A thread->mem->read(memReq, data); 2672131SN/A memReq->paddr = dest_addr; 2682447SN/A thread->mem->write(memReq, data); 2692447SN/A if (dcacheInterface) { 2702447SN/A memReq->cmd = Copy; 2712447SN/A memReq->completionEvent = NULL; 2722131SN/A memReq->paddr = thread->copySrcPhysAddr; 2732447SN/A memReq->dest = dest_addr; 2742131SN/A memReq->size = 64; 2752447SN/A memReq->time = curTick; 2762447SN/A memReq->flags &= ~INST_READ; 2772447SN/A dcacheInterface->access(memReq); 2782447SN/A } 2792131SN/A } 2802447SN/A else 2812447SN/A assert(!fault->isAlignmentFault()); 2822447SN/A 2832447SN/A return fault; 2842131SN/A#else 2852447SN/A panic("copy not implemented"); 2862131SN/A return NoFault; 2872447SN/A#endif 2882447SN/A} 2892447SN/A 2902447SN/A#if FULL_SYSTEM 2912131SN/AAddr 2922447SN/ABaseSimpleCPU::dbg_vtophys(Addr addr) 2932447SN/A{ 2942447SN/A return vtophys(tc, addr); 2952447SN/A} 2962131SN/A#endif // FULL_SYSTEM 2972447SN/A 2982131SN/A#if FULL_SYSTEM 2992447SN/Avoid 3002447SN/ABaseSimpleCPU::post_interrupt(int int_num, int index) 3012447SN/A{ 3022447SN/A BaseCPU::post_interrupt(int_num, index); 3032131SN/A 3042447SN/A if (thread->status() == ThreadContext::Suspended) { 3052447SN/A DPRINTF(IPI,"Suspended Processor awoke\n"); 3062447SN/A thread->activate(); 3072447SN/A } 3082131SN/A} 3092447SN/A#endif // FULL_SYSTEM 3102447SN/A 3112447SN/Avoid 3122447SN/ABaseSimpleCPU::checkForInterrupts() 3132447SN/A{ 3142447SN/A#if FULL_SYSTEM 3152447SN/A if (checkInterrupts && check_interrupts() && !thread->inPalMode()) { 3162447SN/A int ipl = 0; 3172447SN/A int summary = 0; 3182447SN/A checkInterrupts = false; 3192447SN/A 3202447SN/A if (thread->readMiscReg(IPR_SIRR)) { 3214661Sksewell@umich.edu for (int i = INTLEVEL_SOFTWARE_MIN; 3224661Sksewell@umich.edu i < INTLEVEL_SOFTWARE_MAX; i++) { 3234661Sksewell@umich.edu if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { 3244661Sksewell@umich.edu // See table 4-19 of 21164 hardware reference 3254661Sksewell@umich.edu ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; 3264661Sksewell@umich.edu summary |= (ULL(1) << i); 3274661Sksewell@umich.edu } 3284661Sksewell@umich.edu } 3294661Sksewell@umich.edu } 3304661Sksewell@umich.edu 3314661Sksewell@umich.edu uint64_t interrupts = thread->cpu->intr_status(); 3324661Sksewell@umich.edu for (int i = INTLEVEL_EXTERNAL_MIN; 3334661Sksewell@umich.edu i < INTLEVEL_EXTERNAL_MAX; i++) { 3342447SN/A if (interrupts & (ULL(1) << i)) { 3352131SN/A // See table 4-19 of 21164 hardware reference 3362131SN/A ipl = i; 337 summary |= (ULL(1) << i); 338 } 339 } 340 341 if (thread->readMiscReg(IPR_ASTRR)) 342 panic("asynchronous traps not implemented\n"); 343 344 if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { 345 thread->setMiscReg(IPR_ISR, summary); 346 thread->setMiscReg(IPR_INTID, ipl); 347 348 Fault(new InterruptFault)->invoke(tc); 349 350 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 351 thread->readMiscReg(IPR_IPLR), ipl, summary); 352 } 353 } 354#endif 355} 356 357 358Fault 359BaseSimpleCPU::setupFetchRequest(Request *req) 360{ 361 // set up memory request for instruction fetch 362#if THE_ISA == ALPHA_ISA 363 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(), 364 thread->readNextPC()); 365#else 366 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(), 367 thread->readNextPC(),thread->readNextNPC()); 368#endif 369 370 req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst), 371 (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0, 372 thread->readPC()); 373 374 Fault fault = thread->translateInstReq(req); 375 376 return fault; 377} 378 379 380void 381BaseSimpleCPU::preExecute() 382{ 383 // maintain $r0 semantics 384 thread->setIntReg(ZeroReg, 0); 385#if THE_ISA == ALPHA_ISA 386 thread->setFloatReg(ZeroReg, 0.0); 387#endif // ALPHA_ISA 388 389 // keep an instruction count 390 numInst++; 391 numInsts++; 392 393 thread->funcExeInst++; 394 395 // check for instruction-count-based events 396 comInstEventQueue[0]->serviceEvents(numInst); 397 398 // decode the instruction 399 inst = gtoh(inst); 400 curStaticInst = StaticInst::decode(makeExtMI(inst, thread->readPC())); 401 402 traceData = Trace::getInstRecord(curTick, tc, this, curStaticInst, 403 thread->readPC()); 404 405 DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", 406 curStaticInst->getName(), curStaticInst->getOpcode(), 407 curStaticInst->machInst); 408 409#if FULL_SYSTEM 410 thread->setInst(inst); 411#endif // FULL_SYSTEM 412} 413 414void 415BaseSimpleCPU::postExecute() 416{ 417#if FULL_SYSTEM 418 if (system->kernelBinning->fnbin) { 419 assert(thread->getKernelStats()); 420 system->kernelBinning->execute(tc, inst); 421 } 422 423 if (thread->profile) { 424 bool usermode = 425 (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; 426 thread->profilePC = usermode ? 1 : thread->readPC(); 427 ProfileNode *node = thread->profile->consume(tc, inst); 428 if (node) 429 thread->profileNode = node; 430 } 431#endif 432 433 if (curStaticInst->isMemRef()) { 434 numMemRefs++; 435 } 436 437 if (curStaticInst->isLoad()) { 438 ++numLoad; 439 comLoadEventQueue[0]->serviceEvents(numLoad); 440 } 441 442 traceFunctions(thread->readPC()); 443 444 if (traceData) { 445 traceData->finalize(); 446 } 447} 448 449 450void 451BaseSimpleCPU::advancePC(Fault fault) 452{ 453 if (fault != NoFault) { 454#if FULL_SYSTEM 455 fault->invoke(tc); 456#else // !FULL_SYSTEM 457 fatal("fault (%s) detected @ PC %08p", fault->name(), thread->readPC()); 458#endif // FULL_SYSTEM 459 } 460 else { 461 // go to the next instruction 462 thread->setPC(thread->readNextPC()); 463#if THE_ISA == ALPHA_ISA 464 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 465#else 466 thread->setNextPC(thread->readNextNPC()); 467 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 468#endif 469 470 } 471 472#if FULL_SYSTEM 473 Addr oldpc; 474 do { 475 oldpc = thread->readPC(); 476 system->pcEventQueue.service(tc); 477 } while (oldpc != thread->readPC()); 478#endif 479} 480 481