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 &section)
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