base.cc revision 2090
11689SN/A/*
22329SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
31689SN/A * All rights reserved.
41689SN/A *
51689SN/A * Redistribution and use in source and binary forms, with or without
61689SN/A * modification, are permitted provided that the following conditions are
71689SN/A * met: redistributions of source code must retain the above copyright
81689SN/A * notice, this list of conditions and the following disclaimer;
91689SN/A * redistributions in binary form must reproduce the above copyright
101689SN/A * notice, this list of conditions and the following disclaimer in the
111689SN/A * documentation and/or other materials provided with the distribution;
121689SN/A * neither the name of the copyright holders nor the names of its
131689SN/A * contributors may be used to endorse or promote products derived from
141689SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292935Sksewell@umich.edu#include <cmath>
301689SN/A#include <cstdio>
311689SN/A#include <cstdlib>
321060SN/A#include <iostream>
331060SN/A#include <iomanip>
343773Sgblack@eecs.umich.edu#include <list>
353773Sgblack@eecs.umich.edu#include <sstream>
361858SN/A#include <string>
371717SN/A
381060SN/A#include "base/cprintf.hh"
391061SN/A#include "base/inifile.hh"
404329Sktlim@umich.edu#include "base/loader/symtab.hh"
414329Sktlim@umich.edu#include "base/misc.hh"
424329Sktlim@umich.edu#include "base/pollevent.hh"
432292SN/A#include "base/range.hh"
442292SN/A#include "base/stats/events.hh"
452292SN/A#include "base/trace.hh"
462292SN/A#include "cpu/base.hh"
473788Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
483798Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
492361SN/A#include "cpu/profile.hh"
502361SN/A#include "cpu/sampler/sampler.hh"
511060SN/A#include "cpu/simple/cpu.hh"
522292SN/A#include "cpu/smt.hh"
532292SN/A#include "cpu/static_inst.hh"
542292SN/A#include "kern/kernel_stats.hh"
552292SN/A#include "mem/base_mem.hh"
562292SN/A#include "mem/mem_interface.hh"
572292SN/A#include "sim/byteswap.hh"
582292SN/A#include "sim/builder.hh"
592292SN/A#include "sim/debug.hh"
602292SN/A#include "sim/host.hh"
612292SN/A#include "sim/sim_events.hh"
622292SN/A#include "sim/sim_object.hh"
632301SN/A#include "sim/stats.hh"
642292SN/A
652292SN/A#if FULL_SYSTEM
662292SN/A#include "base/remote_gdb.hh"
672292SN/A#include "mem/functional/memory_control.hh"
682292SN/A#include "mem/functional/physical.hh"
692292SN/A#include "sim/system.hh"
702292SN/A#include "targetarch/alpha_memory.hh"
712292SN/A#include "targetarch/stacktrace.hh"
722292SN/A#include "targetarch/vtophys.hh"
732292SN/A#else // !FULL_SYSTEM
742292SN/A#include "mem/functional/functional.hh"
752292SN/A#endif // FULL_SYSTEM
762292SN/A
772292SN/Ausing namespace std;
782292SN/A//The SimpleCPU does alpha only
792292SN/Ausing namespace LittleEndianGuest;
802292SN/A
811060SN/A
821060SN/ASimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
831061SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
841060SN/A{
852292SN/A}
861062SN/A
871062SN/Avoid
882301SN/ASimpleCPU::TickEvent::process()
891062SN/A{
901062SN/A    int count = width;
911062SN/A    do {
922301SN/A        cpu->tick();
931062SN/A    } while (--count > 0 && cpu->status() == Running);
941062SN/A}
951062SN/A
962301SN/Aconst char *
971062SN/ASimpleCPU::TickEvent::description()
981062SN/A{
992301SN/A    return "SimpleCPU tick event";
1002301SN/A}
1012301SN/A
1022301SN/A
1032292SN/ASimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
1042301SN/A    : Event(&mainEventQueue), cpu(_cpu)
1052292SN/A{
1062292SN/A}
1071062SN/A
1082301SN/Avoid SimpleCPU::CacheCompletionEvent::process()
1091062SN/A{
1101062SN/A    cpu->processCacheCompletion();
1111062SN/A}
1122301SN/A
1131062SN/Aconst char *
1141062SN/ASimpleCPU::CacheCompletionEvent::description()
1151062SN/A{
1162301SN/A    return "SimpleCPU cache completion event";
1171062SN/A}
1181062SN/A
1191062SN/ASimpleCPU::SimpleCPU(Params *p)
1202301SN/A    : BaseCPU(p), tickEvent(this, p->width), xc(NULL),
1212292SN/A      cacheCompletionEvent(this)
1221062SN/A{
1231062SN/A    _status = Idle;
1242301SN/A#if FULL_SYSTEM
1252292SN/A    xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
1261062SN/A
1272292SN/A    // initialize CPU, including PC
1282301SN/A    TheISA::initCPU(&xc->regs);
1292292SN/A#else
1302292SN/A    xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0);
1311062SN/A#endif // !FULL_SYSTEM
1322301SN/A
1331062SN/A    icacheInterface = p->icache_interface;
1341062SN/A    dcacheInterface = p->dcache_interface;
1351062SN/A
1362301SN/A    memReq = new MemReq();
1371062SN/A    memReq->xc = xc;
1381062SN/A    memReq->asid = 0;
1391062SN/A    memReq->data = new uint8_t[64];
1402301SN/A
1411062SN/A    numInst = 0;
1421062SN/A    startNumInst = 0;
1431062SN/A    numLoad = 0;
1442301SN/A    startNumLoad = 0;
1451062SN/A    lastIcacheStall = 0;
1461062SN/A    lastDcacheStall = 0;
1471062SN/A
1482301SN/A    execContexts.push_back(xc);
1491062SN/A}
1501062SN/A
1512301SN/ASimpleCPU::~SimpleCPU()
1522301SN/A{
1532301SN/A}
1542301SN/A
1552301SN/Avoid
1562301SN/ASimpleCPU::switchOut(Sampler *s)
1572301SN/A{
1582301SN/A    sampler = s;
1592301SN/A    if (status() == DcacheMissStall) {
1602301SN/A        DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
1612307SN/A        _status = DcacheMissSwitch;
1622307SN/A    }
1632307SN/A    else {
1642307SN/A        _status = SwitchedOut;
1652307SN/A
1661062SN/A        if (tickEvent.scheduled())
1671062SN/A            tickEvent.squash();
1681062SN/A
1691062SN/A        sampler->signalSwitched();
1702292SN/A    }
1711060SN/A}
1721060SN/A
1731060SN/A
1741060SN/Avoid
1751060SN/ASimpleCPU::takeOverFrom(BaseCPU *oldCPU)
1761060SN/A{
1771060SN/A    BaseCPU::takeOverFrom(oldCPU);
1781060SN/A
1791060SN/A    assert(!tickEvent.scheduled());
1801060SN/A
1811060SN/A    // if any of this CPU's ExecContexts are active, mark the CPU as
1821060SN/A    // running and schedule its tick event.
1831060SN/A    for (int i = 0; i < execContexts.size(); ++i) {
1841061SN/A        ExecContext *xc = execContexts[i];
1851060SN/A        if (xc->status() == ExecContext::Active && _status != Running) {
1862292SN/A            _status = Running;
1871060SN/A            tickEvent.schedule(curTick);
1881060SN/A        }
1891060SN/A    }
1901060SN/A}
1911060SN/A
1921060SN/A
1931060SN/Avoid
1941061SN/ASimpleCPU::activateContext(int thread_num, int delay)
1951060SN/A{
1962292SN/A    assert(thread_num == 0);
1971060SN/A    assert(xc);
1981060SN/A
1991060SN/A    assert(_status == Idle);
2001060SN/A    notIdleFraction++;
2011060SN/A    scheduleTickEvent(delay);
2021060SN/A    _status = Running;
2031060SN/A}
2041061SN/A
2051060SN/A
2062292SN/Avoid
2071060SN/ASimpleCPU::suspendContext(int thread_num)
2082329SN/A{
2092292SN/A    assert(thread_num == 0);
2102292SN/A    assert(xc);
2112292SN/A
2122292SN/A    assert(_status == Running);
2132292SN/A    notIdleFraction--;
2142292SN/A    unscheduleTickEvent();
2151060SN/A    _status = Idle;
2161060SN/A}
2172292SN/A
2182292SN/A
2192980Sgblack@eecs.umich.eduvoid
2202292SN/ASimpleCPU::deallocateContext(int thread_num)
2212292SN/A{
2222292SN/A    // for now, these are equivalent
2232292SN/A    suspendContext(thread_num);
2242292SN/A}
2251061SN/A
2261060SN/A
2272292SN/Avoid
2281060SN/ASimpleCPU::haltContext(int thread_num)
2292292SN/A{
2302292SN/A    // for now, these are equivalent
2311060SN/A    suspendContext(thread_num);
2321060SN/A}
2331060SN/A
2341061SN/A
2351060SN/Avoid
2362292SN/ASimpleCPU::regStats()
2371060SN/A{
2382292SN/A    using namespace Stats;
2392292SN/A
2401060SN/A    BaseCPU::regStats();
2412292SN/A
2422292SN/A    numInsts
2432292SN/A        .name(name() + ".num_insts")
2442292SN/A        .desc("Number of instructions executed")
2452292SN/A        ;
2461060SN/A
2471060SN/A    numMemRefs
2481061SN/A        .name(name() + ".num_refs")
2492863Sktlim@umich.edu        .desc("Number of memory references")
2502843Sktlim@umich.edu        ;
2511060SN/A
2522348SN/A    notIdleFraction
2532843Sktlim@umich.edu        .name(name() + ".not_idle_fraction")
2542863Sktlim@umich.edu        .desc("Percentage of non-idle cycles")
2552316SN/A        ;
2561060SN/A
2572316SN/A    idleFraction
2582316SN/A        .name(name() + ".idle_fraction")
2592843Sktlim@umich.edu        .desc("Percentage of idle cycles")
2602316SN/A        ;
2612348SN/A
2622307SN/A    icacheStallCycles
2632980Sgblack@eecs.umich.edu        .name(name() + ".icache_stall_cycles")
2642980Sgblack@eecs.umich.edu        .desc("ICache total stall cycles")
2652307SN/A        .prereq(icacheStallCycles)
2662307SN/A        ;
2672307SN/A
2682307SN/A    dcacheStallCycles
2692307SN/A        .name(name() + ".dcache_stall_cycles")
2702307SN/A        .desc("DCache total stall cycles")
2712307SN/A        .prereq(dcacheStallCycles)
2722307SN/A        ;
2732307SN/A
2742307SN/A    idleFraction = constant(1.0) - notIdleFraction;
2752307SN/A}
2762307SN/A
2772307SN/Avoid
2782307SN/ASimpleCPU::resetStats()
2792361SN/A{
2802361SN/A    startNumInst = numInst;
2812361SN/A    notIdleFraction = (_status != Idle);
2822361SN/A}
2832361SN/A
2842307SN/Avoid
2852307SN/ASimpleCPU::serialize(ostream &os)
2862307SN/A{
2872307SN/A    BaseCPU::serialize(os);
2881060SN/A    SERIALIZE_ENUM(_status);
2891060SN/A    SERIALIZE_SCALAR(inst);
2901060SN/A    nameOut(os, csprintf("%s.xc", name()));
2911061SN/A    xc->serialize(os);
2921060SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
2932307SN/A    tickEvent.serialize(os);
2941060SN/A    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
2952307SN/A    cacheCompletionEvent.serialize(os);
2962307SN/A}
2971060SN/A
2982329SN/Avoid
2992307SN/ASimpleCPU::unserialize(Checkpoint *cp, const string &section)
3002307SN/A{
3011060SN/A    BaseCPU::unserialize(cp, section);
3022307SN/A    UNSERIALIZE_ENUM(_status);
3032307SN/A    UNSERIALIZE_SCALAR(inst);
3042307SN/A    xc->unserialize(cp, csprintf("%s.xc", section));
3052307SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
3062307SN/A    cacheCompletionEvent
3072307SN/A        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
3082307SN/A}
3092307SN/A
3102307SN/Avoid
3112307SN/Achange_thread_state(int thread_number, int activate, int priority)
3122307SN/A{
3132307SN/A}
3142307SN/A
3152307SN/AFault *
3162935Sksewell@umich.eduSimpleCPU::copySrcTranslate(Addr src)
3171858SN/A{
3182292SN/A    static bool no_warn = true;
3191858SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3202292SN/A    // Only support block sizes of 64 atm.
3212292SN/A    assert(blk_size == 64);
3222292SN/A    int offset = src & (blk_size - 1);
3232292SN/A
3243788Sgblack@eecs.umich.edu    // Make sure block doesn't span page
3252292SN/A    if (no_warn &&
3262698Sktlim@umich.edu        (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
3273788Sgblack@eecs.umich.edu        (src >> 40) != 0xfffffc) {
3282301SN/A        warn("Copied block source spans pages %x.", src);
3293788Sgblack@eecs.umich.edu        no_warn = false;
3303788Sgblack@eecs.umich.edu    }
3313788Sgblack@eecs.umich.edu
3323788Sgblack@eecs.umich.edu    memReq->reset(src & ~(blk_size - 1), blk_size);
3333788Sgblack@eecs.umich.edu
3343788Sgblack@eecs.umich.edu    // translate to physical address
3353788Sgblack@eecs.umich.edu    Fault * fault = xc->translateDataReadReq(memReq);
3363788Sgblack@eecs.umich.edu
3373788Sgblack@eecs.umich.edu    assert(fault != AlignmentFault);
3383788Sgblack@eecs.umich.edu
3393788Sgblack@eecs.umich.edu    if (fault == NoFault) {
3402292SN/A        xc->copySrcAddr = src;
3412292SN/A        xc->copySrcPhysAddr = memReq->paddr + offset;
3422292SN/A    } else {
3432292SN/A        xc->copySrcAddr = 0;
3442292SN/A        xc->copySrcPhysAddr = 0;
3452329SN/A    }
3462292SN/A    return fault;
3472292SN/A}
3482292SN/A
3492935Sksewell@umich.eduFault *
3502935Sksewell@umich.eduSimpleCPU::copy(Addr dest)
3512731Sktlim@umich.edu{
3522292SN/A    static bool no_warn = true;
3532292SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3542292SN/A    // Only support block sizes of 64 atm.
3552935Sksewell@umich.edu    assert(blk_size == 64);
3562292SN/A    uint8_t data[blk_size];
3572292SN/A    //assert(xc->copySrcAddr);
3582935Sksewell@umich.edu    int offset = dest & (blk_size - 1);
3594632Sgblack@eecs.umich.edu
3603093Sksewell@umich.edu    // Make sure block doesn't span page
3612292SN/A    if (no_warn &&
3622292SN/A        (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
3633093Sksewell@umich.edu        (dest >> 40) != 0xfffffc) {
3644632Sgblack@eecs.umich.edu        no_warn = false;
3652935Sksewell@umich.edu        warn("Copied block destination spans pages %x. ", dest);
3662292SN/A    }
3672292SN/A
3682292SN/A    memReq->reset(dest & ~(blk_size -1), blk_size);
3692292SN/A    // translate to physical address
3702292SN/A    Fault * fault = xc->translateDataWriteReq(memReq);
3712292SN/A
3722292SN/A    assert(fault != AlignmentFault);
3732292SN/A
3742292SN/A    if (fault == NoFault) {
3752292SN/A        Addr dest_addr = memReq->paddr + offset;
3762292SN/A        // Need to read straight from memory since we have more than 8 bytes.
3772292SN/A        memReq->paddr = xc->copySrcPhysAddr;
3782292SN/A        xc->mem->read(memReq, data);
3792292SN/A        memReq->paddr = dest_addr;
3802292SN/A        xc->mem->write(memReq, data);
3812292SN/A        if (dcacheInterface) {
3823867Sbinkertn@umich.edu            memReq->cmd = Copy;
3833867Sbinkertn@umich.edu            memReq->completionEvent = NULL;
3842292SN/A            memReq->paddr = xc->copySrcPhysAddr;
3852292SN/A            memReq->dest = dest_addr;
3863867Sbinkertn@umich.edu            memReq->size = 64;
3872292SN/A            memReq->time = curTick;
3882292SN/A            memReq->flags &= ~INST_READ;
3892292SN/A            dcacheInterface->access(memReq);
3902292SN/A        }
3912292SN/A    }
3922292SN/A    return fault;
3932292SN/A}
3942292SN/A
3952292SN/A// precise architected memory state accessor macros
3962292SN/Atemplate <class T>
3972292SN/AFault *
3982292SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags)
3992292SN/A{
4002292SN/A    if (status() == DcacheMissStall || status() == DcacheMissSwitch) {
4012292SN/A        Fault * fault = xc->read(memReq,data);
4022292SN/A
4032292SN/A        if (traceData) {
4042292SN/A            traceData->setAddr(addr);
4053867Sbinkertn@umich.edu        }
4062292SN/A        return fault;
4073867Sbinkertn@umich.edu    }
4082292SN/A
4092292SN/A    memReq->reset(addr, sizeof(T), flags);
4102292SN/A
4112292SN/A    // translate to physical address
4122292SN/A    Fault * fault = xc->translateDataReadReq(memReq);
4132292SN/A
4142292SN/A    // if we have a cache, do cache access too
4152292SN/A    if (fault == NoFault && dcacheInterface) {
4162292SN/A        memReq->cmd = Read;
4172292SN/A        memReq->completionEvent = NULL;
4182292SN/A        memReq->time = curTick;
4192292SN/A        memReq->flags &= ~INST_READ;
4202292SN/A        MemAccessResult result = dcacheInterface->access(memReq);
4212292SN/A
4222292SN/A        // Ugly hack to get an event scheduled *only* if the access is
4232292SN/A        // a miss.  We really should add first-class support for this
4242292SN/A        // at some point.
4252292SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
4262292SN/A            memReq->completionEvent = &cacheCompletionEvent;
4272292SN/A            lastDcacheStall = curTick;
4282292SN/A            unscheduleTickEvent();
4292292SN/A            _status = DcacheMissStall;
4302292SN/A        } else {
4312292SN/A            // do functional access
4322292SN/A            fault = xc->read(memReq, data);
4332292SN/A
4342292SN/A        }
4352292SN/A    } else if(fault == NoFault) {
4362292SN/A        // do functional access
4372292SN/A        fault = xc->read(memReq, data);
4382292SN/A
4392292SN/A    }
4402292SN/A
4412292SN/A    if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
4422292SN/A        recordEvent("Uncached Read");
4432292SN/A
4442301SN/A    return fault;
4452301SN/A}
4463788Sgblack@eecs.umich.edu
4473788Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
4483788Sgblack@eecs.umich.edu
4493788Sgblack@eecs.umich.edutemplate
4503788Sgblack@eecs.umich.eduFault *
4513788Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
4523788Sgblack@eecs.umich.edu
4533788Sgblack@eecs.umich.edutemplate
4543798Sgblack@eecs.umich.eduFault *
4553798Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
4563798Sgblack@eecs.umich.edu
4573798Sgblack@eecs.umich.edutemplate
4583798Sgblack@eecs.umich.eduFault *
4593798Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
4602292SN/A
4612292SN/Atemplate
4622292SN/AFault *
4632292SN/ASimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
4642292SN/A
4652292SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
4662292SN/A
4672292SN/Atemplate<>
4682292SN/AFault *
4692292SN/ASimpleCPU::read(Addr addr, double &data, unsigned flags)
4702292SN/A{
4712292SN/A    return read(addr, *(uint64_t*)&data, flags);
4722292SN/A}
4732292SN/A
4742292SN/Atemplate<>
4752292SN/AFault *
4762292SN/ASimpleCPU::read(Addr addr, float &data, unsigned flags)
4772292SN/A{
4782292SN/A    return read(addr, *(uint32_t*)&data, flags);
4792292SN/A}
4801858SN/A
4811858SN/A
4821858SN/Atemplate<>
4831858SN/AFault *
4841858SN/ASimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
4852292SN/A{
4861858SN/A    return read(addr, (uint32_t&)data, flags);
4872292SN/A}
4882292SN/A
4892292SN/A
4902292SN/Atemplate <class T>
4911858SN/AFault *
4922292SN/ASimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
4932292SN/A{
4942292SN/A    memReq->reset(addr, sizeof(T), flags);
4952292SN/A
4962292SN/A    // translate to physical address
4972292SN/A    Fault * fault = xc->translateDataWriteReq(memReq);
4982292SN/A
4992292SN/A    // do functional access
5002292SN/A    if (fault == NoFault)
5012292SN/A        fault = xc->write(memReq, data);
5022292SN/A
5032292SN/A    if (fault == NoFault && dcacheInterface) {
5042292SN/A        memReq->cmd = Write;
5051858SN/A        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
5062292SN/A        memReq->completionEvent = NULL;
5072292SN/A        memReq->time = curTick;
5082292SN/A        memReq->flags &= ~INST_READ;
5092292SN/A        MemAccessResult result = dcacheInterface->access(memReq);
5102292SN/A
5112292SN/A        // Ugly hack to get an event scheduled *only* if the access is
5122292SN/A        // a miss.  We really should add first-class support for this
5132292SN/A        // at some point.
5142292SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
5152292SN/A            memReq->completionEvent = &cacheCompletionEvent;
5162292SN/A            lastDcacheStall = curTick;
5172292SN/A            unscheduleTickEvent();
5182292SN/A            _status = DcacheMissStall;
5192292SN/A        }
5202292SN/A    }
5212292SN/A
5222292SN/A    if (res && (fault == NoFault))
5232292SN/A        *res = memReq->result;
5242292SN/A
5252292SN/A    if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
5262292SN/A        recordEvent("Uncached Write");
5272292SN/A
5282292SN/A    return fault;
5292292SN/A}
5302292SN/A
5312292SN/A
5322292SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
5332292SN/Atemplate
5342292SN/AFault *
5352292SN/ASimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
5362292SN/A
5372292SN/Atemplate
5382292SN/AFault *
5392292SN/ASimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
5402292SN/A
5412292SN/Atemplate
5422292SN/AFault *
5432292SN/ASimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
5442292SN/A
5452292SN/Atemplate
5462292SN/AFault *
5472292SN/ASimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
5482292SN/A
5492292SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
5502292SN/A
5512292SN/Atemplate<>
5522292SN/AFault *
5532292SN/ASimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
5542292SN/A{
5552292SN/A    return write(*(uint64_t*)&data, addr, flags, res);
5562292SN/A}
5572292SN/A
5582292SN/Atemplate<>
5592292SN/AFault *
5602292SN/ASimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
5612292SN/A{
5622292SN/A    return write(*(uint32_t*)&data, addr, flags, res);
5632292SN/A}
5642292SN/A
5652292SN/A
5662292SN/Atemplate<>
5672292SN/AFault *
5682292SN/ASimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
5692292SN/A{
5702292SN/A    return write((uint32_t)data, addr, flags, res);
5712292SN/A}
5722292SN/A
5732292SN/A
5742292SN/A#if FULL_SYSTEM
5752292SN/AAddr
5762292SN/ASimpleCPU::dbg_vtophys(Addr addr)
5772292SN/A{
5782292SN/A    return vtophys(xc, addr);
5792292SN/A}
5802292SN/A#endif // FULL_SYSTEM
5812292SN/A
5822292SN/Avoid
5832292SN/ASimpleCPU::processCacheCompletion()
5842292SN/A{
5852292SN/A    switch (status()) {
5862292SN/A      case IcacheMissStall:
5872292SN/A        icacheStallCycles += curTick - lastIcacheStall;
5882292SN/A        _status = IcacheMissComplete;
5892292SN/A        scheduleTickEvent(1);
5902292SN/A        break;
5912292SN/A      case DcacheMissStall:
5922292SN/A        if (memReq->cmd.isRead()) {
5932292SN/A            curStaticInst->execute(this,traceData);
5942292SN/A            if (traceData)
5952292SN/A                traceData->finalize();
5962292SN/A        }
5972292SN/A        dcacheStallCycles += curTick - lastDcacheStall;
5982292SN/A        _status = Running;
5992935Sksewell@umich.edu        scheduleTickEvent(1);
6002292SN/A        break;
6012292SN/A      case DcacheMissSwitch:
6022292SN/A        if (memReq->cmd.isRead()) {
6032292SN/A            curStaticInst->execute(this,traceData);
6042292SN/A            if (traceData)
6052292SN/A                traceData->finalize();
6062292SN/A        }
6072292SN/A        _status = SwitchedOut;
6082292SN/A        sampler->signalSwitched();
6092292SN/A      case SwitchedOut:
6102292SN/A        // If this CPU has been switched out due to sampling/warm-up,
6112292SN/A        // ignore any further status changes (e.g., due to cache
6122292SN/A        // misses outstanding at the time of the switch).
6132292SN/A        return;
6142292SN/A      default:
6152292SN/A        panic("SimpleCPU::processCacheCompletion: bad state");
6162292SN/A        break;
6172336SN/A    }
6182336SN/A}
6192336SN/A
6202336SN/A#if FULL_SYSTEM
6212336SN/Avoid
6222336SN/ASimpleCPU::post_interrupt(int int_num, int index)
6232336SN/A{
6242336SN/A    BaseCPU::post_interrupt(int_num, index);
6252292SN/A
6262292SN/A    if (xc->status() == ExecContext::Suspended) {
6272301SN/A                DPRINTF(IPI,"Suspended Processor awoke\n");
6282301SN/A        xc->activate();
6292292SN/A    }
6302301SN/A}
6312301SN/A#endif // FULL_SYSTEM
6322301SN/A
6332292SN/A/* start simulation, program loaded, processor precise state initialized */
6342301SN/Avoid
6352292SN/ASimpleCPU::tick()
6362301SN/A{
6372292SN/A    numCycles++;
6382301SN/A
6392292SN/A    traceData = NULL;
6402292SN/A
6412292SN/A    Fault * fault = NoFault;
6422292SN/A
6432336SN/A#if FULL_SYSTEM
6442336SN/A    if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
6452292SN/A        status() != IcacheMissComplete) {
6462292SN/A        int ipl = 0;
6472307SN/A        int summary = 0;
6482307SN/A        checkInterrupts = false;
6492292SN/A        IntReg *ipr = xc->regs.ipr;
6502292SN/A
6512292SN/A        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
6522292SN/A            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
6532292SN/A                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
6542292SN/A                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
6552292SN/A                    // See table 4-19 of 21164 hardware reference
6562292SN/A                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
6572292SN/A                    summary |= (ULL(1) << i);
6582292SN/A                }
6592292SN/A            }
6604345Sktlim@umich.edu        }
6612292SN/A
6622292SN/A        uint64_t interrupts = xc->cpu->intr_status();
6632292SN/A        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
6642292SN/A            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
6652292SN/A            if (interrupts & (ULL(1) << i)) {
6662292SN/A                // See table 4-19 of 21164 hardware reference
6672292SN/A                ipl = i;
6682292SN/A                summary |= (ULL(1) << i);
6692292SN/A            }
6702292SN/A        }
6712292SN/A
6722292SN/A        if (ipr[TheISA::IPR_ASTRR])
6732292SN/A            panic("asynchronous traps not implemented\n");
6742292SN/A
6752292SN/A        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
6762292SN/A            ipr[TheISA::IPR_ISR] = summary;
6772292SN/A            ipr[TheISA::IPR_INTID] = ipl;
6782292SN/A            xc->ev5_trap(InterruptFault);
6792292SN/A
6802292SN/A            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
6812292SN/A                    ipr[TheISA::IPR_IPLR], ipl, summary);
6822292SN/A        }
6832292SN/A    }
6842307SN/A#endif
6852292SN/A
6862292SN/A    // maintain $r0 semantics
6872292SN/A    xc->regs.intRegFile[ZeroReg] = 0;
6882292SN/A#ifdef TARGET_ALPHA
6892292SN/A    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
6902292SN/A#endif // TARGET_ALPHA
6912292SN/A
6922292SN/A    if (status() == IcacheMissComplete) {
6932292SN/A        // We've already fetched an instruction and were stalled on an
6942292SN/A        // I-cache miss.  No need to fetch it again.
6952292SN/A
6962292SN/A        // Set status to running; tick event will get rescheduled if
6972292SN/A        // necessary at end of tick() function.
6982292SN/A        _status = Running;
6992292SN/A    }
7002292SN/A    else {
7012292SN/A        // Try to fetch an instruction
7022292SN/A
7032292SN/A        // set up memory request for instruction fetch
7042292SN/A#if FULL_SYSTEM
7052292SN/A#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
7062292SN/A#else
7072292SN/A#define IFETCH_FLAGS(pc)	0
7082292SN/A#endif
7092292SN/A
7102292SN/A        memReq->cmd = Read;
7112292SN/A        memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
7122292SN/A                     IFETCH_FLAGS(xc->regs.pc));
7132292SN/A
7142292SN/A        fault = xc->translateInstReq(memReq);
7152292SN/A
7162292SN/A        if (fault == NoFault)
7172292SN/A            fault = xc->mem->read(memReq, inst);
7182292SN/A
7192307SN/A        if (icacheInterface && fault == NoFault) {
7202307SN/A            memReq->completionEvent = NULL;
7212292SN/A
7222292SN/A            memReq->time = curTick;
7232292SN/A            memReq->flags |= INST_READ;
7242292SN/A            MemAccessResult result = icacheInterface->access(memReq);
7253798Sgblack@eecs.umich.edu
7263798Sgblack@eecs.umich.edu            // Ugly hack to get an event scheduled *only* if the access is
7273798Sgblack@eecs.umich.edu            // a miss.  We really should add first-class support for this
7283798Sgblack@eecs.umich.edu            // at some point.
7293798Sgblack@eecs.umich.edu            if (result != MA_HIT && icacheInterface->doEvents()) {
7303798Sgblack@eecs.umich.edu                memReq->completionEvent = &cacheCompletionEvent;
7313798Sgblack@eecs.umich.edu                lastIcacheStall = curTick;
7323798Sgblack@eecs.umich.edu                unscheduleTickEvent();
7333798Sgblack@eecs.umich.edu                _status = IcacheMissStall;
7342292SN/A                return;
7353798Sgblack@eecs.umich.edu            }
7362292SN/A        }
7372292SN/A    }
7382292SN/A
7392292SN/A    // If we've got a valid instruction (i.e., no fault on instruction
7402292SN/A    // fetch), then execute it.
7412292SN/A    if (fault == NoFault) {
7422292SN/A
7432329SN/A        // keep an instruction count
7442292SN/A        numInst++;
7452292SN/A        numInsts++;
7462329SN/A
7472292SN/A        // check for instruction-count-based events
7482292SN/A        comInstEventQueue[0]->serviceEvents(numInst);
7492292SN/A
7502292SN/A        // decode the instruction
7512292SN/A        inst = gtoh(inst);
7522292SN/A        curStaticInst = StaticInst<TheISA>::decode(inst);
7532292SN/A
7542292SN/A        traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
7552292SN/A                                         xc->regs.pc);
7562292SN/A
7573867Sbinkertn@umich.edu#if FULL_SYSTEM
7583867Sbinkertn@umich.edu        xc->setInst(inst);
7592292SN/A#endif // FULL_SYSTEM
7603867Sbinkertn@umich.edu
7613867Sbinkertn@umich.edu        xc->func_exe_inst++;
7623867Sbinkertn@umich.edu
7633867Sbinkertn@umich.edu        fault = curStaticInst->execute(this, traceData);
7642292SN/A
7652292SN/A#if FULL_SYSTEM
7662292SN/A        if (xc->fnbin) {
7672292SN/A            assert(xc->kernelStats);
7682292SN/A            system->kernelBinning->execute(xc, inst);
7692292SN/A        }
7702292SN/A
7712292SN/A        if (xc->profile) {
7722292SN/A            bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
7732292SN/A            xc->profilePC = usermode ? 1 : xc->regs.pc;
7742292SN/A            ProfileNode *node = xc->profile->consume(xc, inst);
7752292SN/A            if (node)
7763867Sbinkertn@umich.edu                xc->profileNode = node;
7773867Sbinkertn@umich.edu        }
7782292SN/A#endif
7793867Sbinkertn@umich.edu
7802292SN/A        if (curStaticInst->isMemRef()) {
7812292SN/A            numMemRefs++;
7822292SN/A        }
7832292SN/A
7842292SN/A        if (curStaticInst->isLoad()) {
7852292SN/A            ++numLoad;
7862292SN/A            comLoadEventQueue[0]->serviceEvents(numLoad);
7872292SN/A        }
7882292SN/A
7892292SN/A        // If we have a dcache miss, then we can't finialize the instruction
7902292SN/A        // trace yet because we want to populate it with the data later
7912292SN/A        if (traceData &&
7922292SN/A                !(status() == DcacheMissStall && memReq->cmd.isRead())) {
7932292SN/A            traceData->finalize();
7942292SN/A        }
7952733Sktlim@umich.edu
7962292SN/A        traceFunctions(xc->regs.pc);
7972292SN/A
7982292SN/A    }	// if (fault == NoFault)
7992292SN/A
8002292SN/A    if (fault != NoFault) {
8012292SN/A#if FULL_SYSTEM
8022292SN/A        xc->ev5_trap(fault);
8032292SN/A#else // !FULL_SYSTEM
8042733Sktlim@umich.edu        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
8052292SN/A#endif // FULL_SYSTEM
8062292SN/A    }
8072292SN/A    else {
8082292SN/A        // go to the next instruction
8092292SN/A        xc->regs.pc = xc->regs.npc;
8102292SN/A        xc->regs.npc += sizeof(MachInst);
8112292SN/A    }
8122292SN/A
8132292SN/A#if FULL_SYSTEM
8142292SN/A    Addr oldpc;
8152292SN/A    do {
8162292SN/A        oldpc = xc->regs.pc;
8172292SN/A        system->pcEventQueue.service(xc);
8182292SN/A    } while (oldpc != xc->regs.pc);
8192292SN/A#endif
8202292SN/A
8212292SN/A    assert(status() == Running ||
8223798Sgblack@eecs.umich.edu           status() == Idle ||
8233798Sgblack@eecs.umich.edu           status() == DcacheMissStall);
8243798Sgblack@eecs.umich.edu
8253798Sgblack@eecs.umich.edu    if (status() == Running && !tickEvent.scheduled())
8262292SN/A        tickEvent.schedule(curTick + cycles(1));
8272292SN/A}
8282292SN/A
8292292SN/A////////////////////////////////////////////////////////////////////////
8302292SN/A//
8312329SN/A//  SimpleCPU Simulation Object
8322329SN/A//
8332301SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
8342292SN/A
8352292SN/A    Param<Counter> max_insts_any_thread;
8362292SN/A    Param<Counter> max_insts_all_threads;
8372292SN/A    Param<Counter> max_loads_any_thread;
8382292SN/A    Param<Counter> max_loads_all_threads;
8392292SN/A
8402292SN/A#if FULL_SYSTEM
8412292SN/A    SimObjectParam<AlphaITB *> itb;
8422292SN/A    SimObjectParam<AlphaDTB *> dtb;
8432292SN/A    SimObjectParam<FunctionalMemory *> mem;
8442292SN/A    SimObjectParam<System *> system;
8452292SN/A    Param<int> cpu_id;
8462292SN/A    Param<Tick> profile;
8472292SN/A#else
8482292SN/A    SimObjectParam<Process *> workload;
8492292SN/A#endif // FULL_SYSTEM
8502301SN/A
8512292SN/A    Param<int> clock;
8522292SN/A    SimObjectParam<BaseMem *> icache;
8532292SN/A    SimObjectParam<BaseMem *> dcache;
8542292SN/A
8552292SN/A    Param<bool> defer_registration;
8562292SN/A    Param<int> width;
8572292SN/A    Param<bool> function_trace;
8582292SN/A    Param<Tick> function_trace_start;
8592292SN/A
8602292SN/AEND_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
8612292SN/A
8622292SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
8632292SN/A
8642292SN/A    INIT_PARAM(max_insts_any_thread,
8652292SN/A               "terminate when any thread reaches this inst count"),
8662935Sksewell@umich.edu    INIT_PARAM(max_insts_all_threads,
8672292SN/A               "terminate when all threads have reached this inst count"),
8682980Sgblack@eecs.umich.edu    INIT_PARAM(max_loads_any_thread,
8692980Sgblack@eecs.umich.edu               "terminate when any thread reaches this load count"),
8702292SN/A    INIT_PARAM(max_loads_all_threads,
8711060SN/A               "terminate when all threads have reached this load count"),
8721060SN/A
8732292SN/A#if FULL_SYSTEM
8741060SN/A    INIT_PARAM(itb, "Instruction TLB"),
8751060SN/A    INIT_PARAM(dtb, "Data TLB"),
8761060SN/A    INIT_PARAM(mem, "memory"),
8771060SN/A    INIT_PARAM(system, "system object"),
8781060SN/A    INIT_PARAM(cpu_id, "processor ID"),
8792292SN/A    INIT_PARAM(profile, ""),
8802292SN/A#else
8812292SN/A    INIT_PARAM(workload, "processes to run"),
8821062SN/A#endif // FULL_SYSTEM
8832292SN/A
8842292SN/A    INIT_PARAM(clock, "clock speed"),
8851060SN/A    INIT_PARAM(icache, "L1 instruction cache object"),
8862292SN/A    INIT_PARAM(dcache, "L1 data cache object"),
8872292SN/A    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
8882292SN/A    INIT_PARAM(width, "cpu width"),
8891060SN/A    INIT_PARAM(function_trace, "Enable function trace"),
8902292SN/A    INIT_PARAM(function_trace_start, "Cycle to start function trace")
8912292SN/A
8921062SN/AEND_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
8932367SN/A
8942367SN/A
8952367SN/ACREATE_SIM_OBJECT(SimpleCPU)
8962367SN/A{
8972367SN/A    SimpleCPU::Params *params = new SimpleCPU::Params();
8982292SN/A    params->name = getInstanceName();
8991061SN/A    params->numberOfThreads = 1;
9001062SN/A    params->max_insts_any_thread = max_insts_any_thread;
9011060SN/A    params->max_insts_all_threads = max_insts_all_threads;
9021060SN/A    params->max_loads_any_thread = max_loads_any_thread;
9031060SN/A    params->max_loads_all_threads = max_loads_all_threads;
9041060SN/A    params->deferRegistration = defer_registration;
9051060SN/A    params->clock = clock;
9062292SN/A    params->functionTrace = function_trace;
9071060SN/A    params->functionTraceStart = function_trace_start;
9082292SN/A    params->icache_interface = (icache) ? icache->getInterface() : NULL;
9092292SN/A    params->dcache_interface = (dcache) ? dcache->getInterface() : NULL;
9102292SN/A    params->width = width;
9112292SN/A
9122980Sgblack@eecs.umich.edu#if FULL_SYSTEM
9132980Sgblack@eecs.umich.edu    params->itb = itb;
9141060SN/A    params->dtb = dtb;
9151061SN/A    params->mem = mem;
9161060SN/A    params->system = system;
9172292SN/A    params->cpu_id = cpu_id;
9182292SN/A    params->profile = profile;
9192292SN/A#else
9202292SN/A    params->process = workload;
9212292SN/A#endif
9222292SN/A
9231060SN/A    SimpleCPU *cpu = new SimpleCPU(params);
9241060SN/A    return cpu;
9251060SN/A}
9262292SN/A
9272292SN/AREGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
9282292SN/A
9292292SN/A