base.cc revision 2420
11689SN/A/*
21689SN/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
292756Sksewell@umich.edu#include <cmath>
301689SN/A#include <cstdio>
311689SN/A#include <cstdlib>
322325SN/A#include <iostream>
332325SN/A#include <iomanip>
341060SN/A#include <list>
351060SN/A#include <sstream>
361060SN/A#include <string>
372292SN/A
382292SN/A#include "base/cprintf.hh"
391681SN/A#include "base/inifile.hh"
401060SN/A#include "base/loader/symtab.hh"
412980Sgblack@eecs.umich.edu#include "base/misc.hh"
421060SN/A#include "base/pollevent.hh"
431060SN/A#include "base/range.hh"
441858SN/A#include "base/stats/events.hh"
454598Sbinkertn@umich.edu#include "base/trace.hh"
462325SN/A#include "cpu/base.hh"
471717SN/A#include "cpu/exec_context.hh"
482683Sktlim@umich.edu#include "cpu/exetrace.hh"
491717SN/A#include "cpu/profile.hh"
501717SN/A#include "cpu/sampler/sampler.hh"
512292SN/A#include "cpu/simple/cpu.hh"
522292SN/A#include "cpu/smt.hh"
532817Sksewell@umich.edu#include "cpu/static_inst.hh"
541060SN/A#include "kern/kernel_stats.hh"
551060SN/A#include "sim/builder.hh"
565529Snate@binkert.org#include "sim/debug.hh"
575529Snate@binkert.org#include "sim/host.hh"
582316SN/A#include "sim/sim_events.hh"
592316SN/A#include "sim/sim_object.hh"
602680Sktlim@umich.edu#include "sim/stats.hh"
612817Sksewell@umich.edu
622817Sksewell@umich.edu#if FULL_SYSTEM
632843Sktlim@umich.edu#include "base/remote_gdb.hh"
642843Sktlim@umich.edu#include "mem/functional/memory_control.hh"
652669Sktlim@umich.edu#include "mem/functional/physical.hh"
661060SN/A#include "sim/system.hh"
671060SN/A#include "targetarch/alpha_memory.hh"
685529Snate@binkert.org#include "targetarch/stacktrace.hh"
695529Snate@binkert.org#include "targetarch/vtophys.hh"
702733Sktlim@umich.edu#else // !FULL_SYSTEM
711060SN/A#include "mem/memory.hh"
721060SN/A#endif // FULL_SYSTEM
731060SN/A
745529Snate@binkert.orgusing namespace std;
752292SN/A
762292SN/A
772632Sstever@eecs.umich.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
782817Sksewell@umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
792817Sksewell@umich.edu{
802817Sksewell@umich.edu}
812817Sksewell@umich.edu
822669Sktlim@umich.eduvoid
831681SN/ASimpleCPU::TickEvent::process()
841685SN/A{
851681SN/A    int count = width;
861060SN/A    do {
871060SN/A        cpu->tick();
882348SN/A    } while (--count > 0 && cpu->status() == Running);
892348SN/A}
902348SN/A
912348SN/Aconst char *
922348SN/ASimpleCPU::TickEvent::description()
931060SN/A{
942733Sktlim@umich.edu    return "SimpleCPU tick event";
951060SN/A}
961060SN/A
972325SN/A
981060SN/Abool
991061SN/ASimpleCPU::CpuPort::recvTiming(Packet &pkt)
1004329Sktlim@umich.edu{
1011060SN/A    cpu->processResponse(pkt);
1022292SN/A    return true;
1032292SN/A}
1042292SN/A
1052292SN/ATick
1062817Sksewell@umich.eduSimpleCPU::CpuPort::recvAtomic(Packet &pkt)
1072829Sksewell@umich.edu{
1081060SN/A    panic("CPU doesn't expect callback!");
1091060SN/A    return curTick;
1101060SN/A}
1111060SN/A
1121060SN/Avoid
1132307SN/ASimpleCPU::CpuPort::recvFunctional(Packet &pkt)
1142307SN/A{
1151060SN/A    panic("CPU doesn't expect callback!");
1161060SN/A}
1173781Sgblack@eecs.umich.edu
1183781Sgblack@eecs.umich.eduvoid
1193781Sgblack@eecs.umich.eduSimpleCPU::CpuPort::recvStatusChange(Status status)
1202292SN/A{
1211060SN/A    cpu->recvStatusChange(status);
1221060SN/A}
1232829Sksewell@umich.edu
1242829Sksewell@umich.eduPacket *
1252829Sksewell@umich.eduSimpleCPU::CpuPort::recvRetry()
1261060SN/A{
1271060SN/A    return cpu->processRetry();
1281060SN/A}
1291060SN/A
1302292SN/ASimpleCPU::SimpleCPU(Params *p)
1311755SN/A    : BaseCPU(p), icachePort(this),
1321060SN/A      dcachePort(this), tickEvent(this, p->width), xc(NULL)
1331060SN/A{
1342292SN/A    _status = Idle;
1351755SN/A
1362292SN/A    //Create Memory Ports (conect them up)
1372292SN/A    p->mem->addPort("DCACHE");
1381060SN/A    dcachePort.setPeer(p->mem->getPort("DCACHE"));
1392292SN/A    (p->mem->getPort("DCACHE"))->setPeer(&dcachePort);
1405336Shines@cs.fsu.edu
1411060SN/A    p->mem->addPort("ICACHE");
1421060SN/A    icachePort.setPeer(p->mem->getPort("ICACHE"));
1432292SN/A    (p->mem->getPort("ICACHE"))->setPeer(&icachePort);
1441060SN/A
1451060SN/A#if FULL_SYSTEM
1462292SN/A    xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
1471060SN/A
1481060SN/A    // initialize CPU, including PC
1491060SN/A    TheISA::initCPU(&xc->regs);
1505100Ssaidi@eecs.umich.edu#else
1511060SN/A    xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0,
1525100Ssaidi@eecs.umich.edu                         &dcachePort);
1531060SN/A#endif // !FULL_SYSTEM
1541060SN/A
1552292SN/A#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
1561060SN/A    ifetch_req = new CpuRequest;
1571060SN/A    ifetch_req->asid = 0;
1581060SN/A    ifetch_req->size = sizeof(MachInst);
1591060SN/A    ifetch_pkt = new Packet;
1601060SN/A    ifetch_pkt->cmd = Read;
1611060SN/A    ifetch_pkt->data = (uint8_t *)&inst;
1622829Sksewell@umich.edu    ifetch_pkt->req = ifetch_req;
1632829Sksewell@umich.edu    ifetch_pkt->size = sizeof(MachInst);
1642829Sksewell@umich.edu
1652829Sksewell@umich.edu    data_read_req = new CpuRequest;
1662829Sksewell@umich.edu    data_read_req->asid = 0;
1672829Sksewell@umich.edu    data_read_pkt = new Packet;
1682829Sksewell@umich.edu    data_read_pkt->cmd = Read;
1692829Sksewell@umich.edu    data_read_pkt->data = new uint8_t[8];
1702829Sksewell@umich.edu    data_read_pkt->req = data_read_req;
1712829Sksewell@umich.edu
1722829Sksewell@umich.edu    data_write_req = new CpuRequest;
1732829Sksewell@umich.edu    data_write_req->asid = 0;
1742829Sksewell@umich.edu    data_write_pkt = new Packet;
1752829Sksewell@umich.edu    data_write_pkt->cmd = Write;
1762829Sksewell@umich.edu    data_write_pkt->req = data_write_req;
1772829Sksewell@umich.edu#endif
1782829Sksewell@umich.edu
1792829Sksewell@umich.edu    numInst = 0;
1802829Sksewell@umich.edu    startNumInst = 0;
1812829Sksewell@umich.edu    numLoad = 0;
1825336Shines@cs.fsu.edu    startNumLoad = 0;
1832829Sksewell@umich.edu    lastIcacheStall = 0;
1842829Sksewell@umich.edu    lastDcacheStall = 0;
1852829Sksewell@umich.edu
1862829Sksewell@umich.edu    execContexts.push_back(xc);
1872829Sksewell@umich.edu}
1882829Sksewell@umich.edu
1892829Sksewell@umich.eduSimpleCPU::~SimpleCPU()
1904030Sktlim@umich.edu{
1915100Ssaidi@eecs.umich.edu}
1922829Sksewell@umich.edu
1934030Sktlim@umich.eduvoid
1945100Ssaidi@eecs.umich.eduSimpleCPU::switchOut(Sampler *s)
1952829Sksewell@umich.edu{
1962829Sksewell@umich.edu    sampler = s;
1972829Sksewell@umich.edu    if (status() == DcacheWaitResponse) {
1982829Sksewell@umich.edu        DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
1992829Sksewell@umich.edu        _status = DcacheWaitSwitch;
2002829Sksewell@umich.edu    }
2012829Sksewell@umich.edu    else {
2022829Sksewell@umich.edu        _status = SwitchedOut;
2032829Sksewell@umich.edu
2042829Sksewell@umich.edu        if (tickEvent.scheduled())
2052829Sksewell@umich.edu            tickEvent.squash();
2062829Sksewell@umich.edu
2072875Sksewell@umich.edu        sampler->signalSwitched();
2082875Sksewell@umich.edu    }
2092875Sksewell@umich.edu}
2103221Sktlim@umich.edu
2112875Sksewell@umich.edu
2122875Sksewell@umich.eduvoid
2133221Sktlim@umich.eduSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2143221Sktlim@umich.edu{
2153221Sktlim@umich.edu    BaseCPU::takeOverFrom(oldCPU);
2162875Sksewell@umich.edu
2172875Sksewell@umich.edu    assert(!tickEvent.scheduled());
2182875Sksewell@umich.edu
2192875Sksewell@umich.edu    // if any of this CPU's ExecContexts are active, mark the CPU as
2202875Sksewell@umich.edu    // running and schedule its tick event.
2212875Sksewell@umich.edu    for (int i = 0; i < execContexts.size(); ++i) {
2222875Sksewell@umich.edu        ExecContext *xc = execContexts[i];
2232875Sksewell@umich.edu        if (xc->status() == ExecContext::Active && _status != Running) {
2242875Sksewell@umich.edu            _status = Running;
2252875Sksewell@umich.edu            tickEvent.schedule(curTick);
2262875Sksewell@umich.edu        }
2272875Sksewell@umich.edu    }
2282875Sksewell@umich.edu}
2293221Sktlim@umich.edu
2303221Sktlim@umich.edu
2313221Sktlim@umich.eduvoid
2322875Sksewell@umich.eduSimpleCPU::activateContext(int thread_num, int delay)
2335336Shines@cs.fsu.edu{
2342875Sksewell@umich.edu    assert(thread_num == 0);
2352875Sksewell@umich.edu    assert(xc);
2362875Sksewell@umich.edu
2373221Sktlim@umich.edu    assert(_status == Idle);
2382875Sksewell@umich.edu    notIdleFraction++;
2392875Sksewell@umich.edu    scheduleTickEvent(delay);
2402875Sksewell@umich.edu    _status = Running;
2414030Sktlim@umich.edu}
2425100Ssaidi@eecs.umich.edu
2432875Sksewell@umich.edu
2444030Sktlim@umich.eduvoid
2455100Ssaidi@eecs.umich.eduSimpleCPU::suspendContext(int thread_num)
2462875Sksewell@umich.edu{
2472875Sksewell@umich.edu    assert(thread_num == 0);
2482875Sksewell@umich.edu    assert(xc);
2492875Sksewell@umich.edu
2502875Sksewell@umich.edu    assert(_status == Running);
2512875Sksewell@umich.edu    notIdleFraction--;
2522875Sksewell@umich.edu    unscheduleTickEvent();
2532875Sksewell@umich.edu    _status = Idle;
2542875Sksewell@umich.edu}
2552875Sksewell@umich.edu
2562875Sksewell@umich.edu
2572875Sksewell@umich.eduvoid
2581060SN/ASimpleCPU::deallocateContext(int thread_num)
2592292SN/A{
2605529Snate@binkert.org    // for now, these are equivalent
2612292SN/A    suspendContext(thread_num);
2621755SN/A}
2631060SN/A
2642292SN/A
2651684SN/Avoid
2661684SN/ASimpleCPU::haltContext(int thread_num)
2675358Sgblack@eecs.umich.edu{
2685358Sgblack@eecs.umich.edu    // for now, these are equivalent
2695358Sgblack@eecs.umich.edu    suspendContext(thread_num);
2705358Sgblack@eecs.umich.edu}
2715358Sgblack@eecs.umich.edu
2725358Sgblack@eecs.umich.edu
2735358Sgblack@eecs.umich.eduvoid
2745358Sgblack@eecs.umich.eduSimpleCPU::regStats()
2755358Sgblack@eecs.umich.edu{
2765358Sgblack@eecs.umich.edu    using namespace Stats;
2775358Sgblack@eecs.umich.edu
2785358Sgblack@eecs.umich.edu    BaseCPU::regStats();
2795358Sgblack@eecs.umich.edu
2805358Sgblack@eecs.umich.edu    numInsts
2815358Sgblack@eecs.umich.edu        .name(name() + ".num_insts")
2825358Sgblack@eecs.umich.edu        .desc("Number of instructions executed")
2834988Sgblack@eecs.umich.edu        ;
2844988Sgblack@eecs.umich.edu
2854988Sgblack@eecs.umich.edu    numMemRefs
2864988Sgblack@eecs.umich.edu        .name(name() + ".num_refs")
2874988Sgblack@eecs.umich.edu        .desc("Number of memory references")
2884988Sgblack@eecs.umich.edu        ;
2894988Sgblack@eecs.umich.edu
2904988Sgblack@eecs.umich.edu    notIdleFraction
2914988Sgblack@eecs.umich.edu        .name(name() + ".not_idle_fraction")
2924988Sgblack@eecs.umich.edu        .desc("Percentage of non-idle cycles")
2934988Sgblack@eecs.umich.edu        ;
2944988Sgblack@eecs.umich.edu
2954988Sgblack@eecs.umich.edu    idleFraction
2964988Sgblack@eecs.umich.edu        .name(name() + ".idle_fraction")
2974988Sgblack@eecs.umich.edu        .desc("Percentage of idle cycles")
2984988Sgblack@eecs.umich.edu        ;
2994988Sgblack@eecs.umich.edu
3004988Sgblack@eecs.umich.edu    icacheStallCycles
3012871Sktlim@umich.edu        .name(name() + ".icache_stall_cycles")
3022871Sktlim@umich.edu        .desc("ICache total stall cycles")
3032871Sktlim@umich.edu        .prereq(icacheStallCycles)
3042292SN/A        ;
3052292SN/A
3062292SN/A    dcacheStallCycles
3071684SN/A        .name(name() + ".dcache_stall_cycles")
3081684SN/A        .desc("DCache total stall cycles")
3092292SN/A        .prereq(dcacheStallCycles)
3101060SN/A        ;
3111060SN/A
3122834Sksewell@umich.edu    icacheRetryCycles
3132834Sksewell@umich.edu        .name(name() + ".icache_retry_cycles")
3142834Sksewell@umich.edu        .desc("ICache total retry cycles")
3152834Sksewell@umich.edu        .prereq(icacheRetryCycles)
3162829Sksewell@umich.edu        ;
3172875Sksewell@umich.edu
3182875Sksewell@umich.edu    dcacheRetryCycles
3192875Sksewell@umich.edu        .name(name() + ".dcache_retry_cycles")
3202875Sksewell@umich.edu        .desc("DCache total retry cycles")
3212829Sksewell@umich.edu        .prereq(dcacheRetryCycles)
3222292SN/A        ;
3232292SN/A
3241060SN/A    idleFraction = constant(1.0) - notIdleFraction;
3252292SN/A}
3262292SN/A
3272292SN/Avoid
3282292SN/ASimpleCPU::resetStats()
3292292SN/A{
3302292SN/A    startNumInst = numInst;
3312292SN/A    notIdleFraction = (_status != Idle);
3322292SN/A}
3332292SN/A
3342292SN/Avoid
3352292SN/ASimpleCPU::serialize(ostream &os)
3362292SN/A{
3372292SN/A    BaseCPU::serialize(os);
3382292SN/A    SERIALIZE_ENUM(_status);
3392292SN/A    SERIALIZE_SCALAR(inst);
3402292SN/A    nameOut(os, csprintf("%s.xc", name()));
3412292SN/A    xc->serialize(os);
3422292SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
3432292SN/A    tickEvent.serialize(os);
3442292SN/A    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
3452292SN/A}
3463221Sktlim@umich.edu
3472292SN/Avoid
3483221Sktlim@umich.eduSimpleCPU::unserialize(Checkpoint *cp, const string &section)
3492292SN/A{
3502292SN/A    BaseCPU::unserialize(cp, section);
3512292SN/A    UNSERIALIZE_ENUM(_status);
3522292SN/A    UNSERIALIZE_SCALAR(inst);
3532292SN/A    xc->unserialize(cp, csprintf("%s.xc", section));
3542292SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
3552292SN/A}
3562292SN/A
3572292SN/Avoid
3582292SN/Achange_thread_state(int thread_number, int activate, int priority)
3592292SN/A{
3602292SN/A}
3612292SN/A
3622292SN/AFault
3632292SN/ASimpleCPU::copySrcTranslate(Addr src)
3642864Sktlim@umich.edu{
3652864Sktlim@umich.edu#if 0
3662864Sktlim@umich.edu    static bool no_warn = true;
3672864Sktlim@umich.edu    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3682864Sktlim@umich.edu    // Only support block sizes of 64 atm.
3692864Sktlim@umich.edu    assert(blk_size == 64);
3702864Sktlim@umich.edu    int offset = src & (blk_size - 1);
3712292SN/A
3722292SN/A    // Make sure block doesn't span page
3732292SN/A    if (no_warn &&
3742292SN/A        (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
3752292SN/A        (src >> 40) != 0xfffffc) {
3762325SN/A        warn("Copied block source spans pages %x.", src);
3772292SN/A        no_warn = false;
3782843Sktlim@umich.edu    }
3792843Sktlim@umich.edu
3802905Sktlim@umich.edu    memReq->reset(src & ~(blk_size - 1), blk_size);
3812843Sktlim@umich.edu
3822843Sktlim@umich.edu    // translate to physical address
3832843Sktlim@umich.edu    Fault fault = xc->translateDataReadReq(req);
3842292SN/A
3852348SN/A    assert(fault != Alignment_Fault);
3862843Sktlim@umich.edu
3872843Sktlim@umich.edu    if (fault == No_Fault) {
3882843Sktlim@umich.edu        xc->copySrcAddr = src;
3892843Sktlim@umich.edu        xc->copySrcPhysAddr = memReq->paddr + offset;
3902316SN/A    } else {
3912348SN/A        xc->copySrcAddr = 0;
3922843Sktlim@umich.edu        xc->copySrcPhysAddr = 0;
3931060SN/A    }
3941060SN/A    return fault;
3952316SN/A#else
3962316SN/A    return No_Fault;
3971060SN/A#endif
3981858SN/A}
3994192Sktlim@umich.edu
4004192Sktlim@umich.eduFault
4014192Sktlim@umich.eduSimpleCPU::copy(Addr dest)
4024192Sktlim@umich.edu{
4031060SN/A#if 0
4041060SN/A    static bool no_warn = true;
4051060SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
4061060SN/A    // Only support block sizes of 64 atm.
4071060SN/A    assert(blk_size == 64);
4081060SN/A    uint8_t data[blk_size];
4091060SN/A    //assert(xc->copySrcAddr);
4102292SN/A    int offset = dest & (blk_size - 1);
4112292SN/A
4121060SN/A    // Make sure block doesn't span page
4131060SN/A    if (no_warn &&
4142292SN/A        (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
4152292SN/A        (dest >> 40) != 0xfffffc) {
4161060SN/A        no_warn = false;
4172292SN/A        warn("Copied block destination spans pages %x. ", dest);
4182292SN/A    }
4192683Sktlim@umich.edu
4201060SN/A    memReq->reset(dest & ~(blk_size -1), blk_size);
4212292SN/A    // translate to physical address
4222292SN/A    Fault fault = xc->translateDataWriteReq(req);
4232683Sktlim@umich.edu
4241060SN/A    assert(fault != Alignment_Fault);
4251060SN/A
4261060SN/A    if (fault == No_Fault) {
4272348SN/A        Addr dest_addr = memReq->paddr + offset;
4281060SN/A        // Need to read straight from memory since we have more than 8 bytes.
4291060SN/A        memReq->paddr = xc->copySrcPhysAddr;
4303781Sgblack@eecs.umich.edu        xc->mem->read(memReq, data);
4311060SN/A        memReq->paddr = dest_addr;
4323781Sgblack@eecs.umich.edu        xc->mem->write(memReq, data);
4331060SN/A        if (dcacheInterface) {
4343781Sgblack@eecs.umich.edu            memReq->cmd = Copy;
4352455SN/A            memReq->completionEvent = NULL;
4363781Sgblack@eecs.umich.edu            memReq->paddr = xc->copySrcPhysAddr;
4371060SN/A            memReq->dest = dest_addr;
4381060SN/A            memReq->size = 64;
4391060SN/A            memReq->time = curTick;
4403781Sgblack@eecs.umich.edu            memReq->flags &= ~INST_READ;
4411060SN/A            dcacheInterface->access(memReq);
4423781Sgblack@eecs.umich.edu        }
4431060SN/A    }
4443781Sgblack@eecs.umich.edu    return fault;
4452455SN/A#else
4463781Sgblack@eecs.umich.edu    panic("copy not implemented");
4471060SN/A    return No_Fault;
4482292SN/A#endif
4491060SN/A}
4502292SN/A
4511060SN/A// precise architected memory state accessor macros
4522292SN/Atemplate <class T>
4532292SN/AFault
4542292SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags)
4552292SN/A{
4562348SN/A    if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) {
4572348SN/A//	Fault fault = xc->read(memReq,data);
4582348SN/A        // Not sure what to check for no fault...
4592348SN/A        if (data_read_pkt->result == Success) {
4602348SN/A            memcpy(&data, data_read_pkt->data, sizeof(T));
4612292SN/A        }
4622292SN/A
4632292SN/A        if (traceData) {
4642292SN/A            traceData->setAddr(addr);
4652292SN/A        }
4662292SN/A
4672292SN/A        // @todo: Figure out a way to create a Fault from the packet result.
4682292SN/A        return No_Fault;
4692348SN/A    }
4704636Sgblack@eecs.umich.edu
4712292SN/A//    memReq->reset(addr, sizeof(T), flags);
4722348SN/A
4732348SN/A#if SIMPLE_CPU_MEM_TIMING
4742292SN/A    CpuRequest *data_read_req = new CpuRequest;
4754636Sgblack@eecs.umich.edu#endif
4764636Sgblack@eecs.umich.edu
4774636Sgblack@eecs.umich.edu    data_read_req->vaddr = addr;
4784636Sgblack@eecs.umich.edu    data_read_req->size = sizeof(T);
4794636Sgblack@eecs.umich.edu    data_read_req->flags = flags;
4804636Sgblack@eecs.umich.edu    data_read_req->time = curTick;
4812348SN/A
4824636Sgblack@eecs.umich.edu    // translate to physical address
4832292SN/A    Fault fault = xc->translateDataReadReq(data_read_req);
4842348SN/A
4854636Sgblack@eecs.umich.edu    // Now do the access.
4861060SN/A    if (fault == No_Fault) {
4872756Sksewell@umich.edu#if SIMPLE_CPU_MEM_TIMING
4884636Sgblack@eecs.umich.edu        data_read_pkt = new Packet;
4892756Sksewell@umich.edu        data_read_pkt->cmd = Read;
4902756Sksewell@umich.edu        data_read_pkt->req = data_read_req;
4914636Sgblack@eecs.umich.edu        data_read_pkt->data = new uint8_t[8];
4924636Sgblack@eecs.umich.edu#endif
4934636Sgblack@eecs.umich.edu        data_read_pkt->addr = data_read_req->paddr;
4944636Sgblack@eecs.umich.edu        data_read_pkt->size = sizeof(T);
4954636Sgblack@eecs.umich.edu
4964636Sgblack@eecs.umich.edu        sendDcacheRequest(data_read_pkt);
4974636Sgblack@eecs.umich.edu
4982756Sksewell@umich.edu#if SIMPLE_CPU_MEM_IMMEDIATE
4991060SN/A        // Need to find a way to not duplicate code above.
5001060SN/A
5011060SN/A        if (data_read_pkt->result == Success) {
5022292SN/A            memcpy(&data, data_read_pkt->data, sizeof(T));
5031060SN/A        }
5041060SN/A
5052292SN/A        if (traceData) {
5061060SN/A            traceData->setAddr(addr);
5072292SN/A        }
5082292SN/A
5091060SN/A        // @todo: Figure out a way to create a Fault from the packet result.
5102325SN/A        return No_Fault;
5112325SN/A#endif
5121060SN/A    }
5131061SN/A/*
5141060SN/A        memReq->cmd = Read;
5152935Sksewell@umich.edu        memReq->completionEvent = NULL;
5162935Sksewell@umich.edu        memReq->time = curTick;
5174632Sgblack@eecs.umich.edu        memReq->flags &= ~INST_READ;
5181060SN/A        MemAccessResult result = dcacheInterface->access(memReq);
5191062SN/A
5202292SN/A        // Ugly hack to get an event scheduled *only* if the access is
5212292SN/A        // a miss.  We really should add first-class support for this
5222348SN/A        // at some point.
5232292SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
5242292SN/A            memReq->completionEvent = &cacheCompletionEvent;
5252348SN/A            lastDcacheStall = curTick;
5262292SN/A            unscheduleTickEvent();
5271062SN/A            _status = DcacheMissStall;
5282348SN/A        } else {
5291060SN/A            // do functional access
5301060SN/A            fault = xc->read(memReq, data);
5311060SN/A
5321060SN/A        }
5332292SN/A
5341060SN/A    } else if(fault == No_Fault) {
5352292SN/A        // do functional access
5362292SN/A        fault = xc->read(memReq, data);
5372292SN/A
5382292SN/A    }
5392292SN/A*/
5402325SN/A    // This will need a new way to tell if it has a dcache attached.
5412348SN/A    if (data_read_req->flags & UNCACHEABLE)
5422348SN/A        recordEvent("Uncached Read");
5432348SN/A
5442292SN/A    return fault;
5452325SN/A}
5462292SN/A
5472325SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
5482325SN/A
5492292SN/Atemplate
5502292SN/AFault
5512292SN/ASimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
5521060SN/A
5531060SN/Atemplate
5541060SN/AFault
5551060SN/ASimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
5561060SN/A
5571060SN/Atemplate
5581060SN/AFault
5591060SN/ASimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
5601060SN/A
5611060SN/Atemplate
5621060SN/AFault
5631060SN/ASimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
5641060SN/A
5651060SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
5661060SN/A
5671060SN/Atemplate<>
5681060SN/AFault
5691060SN/ASimpleCPU::read(Addr addr, double &data, unsigned flags)
5701060SN/A{
5711060SN/A    return read(addr, *(uint64_t*)&data, flags);
5721060SN/A}
5731060SN/A
5741060SN/Atemplate<>
5752292SN/AFault
5762292SN/ASimpleCPU::read(Addr addr, float &data, unsigned flags)
5772292SN/A{
5782292SN/A    return read(addr, *(uint32_t*)&data, flags);
5791060SN/A}
5801060SN/A
5811060SN/A
5821060SN/Atemplate<>
5832292SN/AFault
5842292SN/ASimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
5852292SN/A{
5862292SN/A    return read(addr, (uint32_t&)data, flags);
5872292SN/A}
5882292SN/A
5891060SN/A
5902292SN/Atemplate <class T>
5912292SN/AFault
5922292SN/ASimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
5932292SN/A{
5942292SN/A    data_write_req->vaddr = addr;
5952292SN/A    data_write_req->time = curTick;
5962292SN/A    data_write_req->size = sizeof(T);
5972292SN/A    data_write_req->flags = flags;
5982292SN/A
5992292SN/A    // translate to physical address
6002292SN/A    Fault fault = xc->translateDataWriteReq(data_write_req);
6012292SN/A
6021060SN/A    // Now do the access.
6031060SN/A    if (fault == No_Fault) {
6041060SN/A#if SIMPLE_CPU_MEM_TIMING
6051061SN/A        data_write_pkt = new Packet;
6061060SN/A        data_write_pkt->cmd = Write;
6071061SN/A        data_write_pkt->req = data_write_req;
6081060SN/A        data_write_pkt->data = new uint8_t[64];
6091061SN/A        memcpy(data_write_pkt->data, &data, sizeof(T));
6101060SN/A#else
6111061SN/A        data_write_pkt->data = (uint8_t *)&data;
6121060SN/A#endif
6131061SN/A        data_write_pkt->addr = data_write_req->paddr;
6141060SN/A        data_write_pkt->size = sizeof(T);
6151060SN/A
6161060SN/A        sendDcacheRequest(data_write_pkt);
6171060SN/A    }
6181060SN/A
6191060SN/A/*
6201060SN/A    // do functional access
6211060SN/A    if (fault == No_Fault)
6221060SN/A        fault = xc->write(memReq, data);
6231060SN/A
6241060SN/A    if (fault == No_Fault && dcacheInterface) {
6251060SN/A        memReq->cmd = Write;
6261060SN/A        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
6271060SN/A        memReq->completionEvent = NULL;
6281060SN/A        memReq->time = curTick;
6291060SN/A        memReq->flags &= ~INST_READ;
6302348SN/A        MemAccessResult result = dcacheInterface->access(memReq);
6312348SN/A
6322348SN/A        // Ugly hack to get an event scheduled *only* if the access is
6332348SN/A        // a miss.  We really should add first-class support for this
6342348SN/A        // at some point.
6352325SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
6361060SN/A            memReq->completionEvent = &cacheCompletionEvent;
6372348SN/A            lastDcacheStall = curTick;
6382348SN/A            unscheduleTickEvent();
6392325SN/A            _status = DcacheMissStall;
6402292SN/A        }
6412348SN/A    }
6422325SN/A*/
6432325SN/A    if (res && (fault == No_Fault))
6442292SN/A        *res = data_write_pkt->result;
6452348SN/A
6462325SN/A    // This will need a new way to tell if it's hooked up to a cache or not.
6472325SN/A    if (data_write_req->flags & UNCACHEABLE)
6482292SN/A        recordEvent("Uncached Write");
6492292SN/A
6502292SN/A    // If the write needs to have a fault on the access, consider calling
6512260SN/A    // changeStatus() and changing it to "bad addr write" or something.
6522292SN/A    return fault;
6532292SN/A}
6542292SN/A
6552292SN/A
6562680Sktlim@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
6572680Sktlim@umich.edutemplate
6581681SN/AFault
6592680Sktlim@umich.eduSimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
6602190SN/A
6612190SN/Atemplate
6622292SN/AFault
6633093Sksewell@umich.eduSimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
6641060SN/A
6654598Sbinkertn@umich.edutemplate
6662348SN/AFault
6672348SN/ASimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
6682348SN/A
6692348SN/Atemplate
6702316SN/AFault
6714598Sbinkertn@umich.eduSimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
6722316SN/A
6731858SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
6742292SN/A
6751060SN/Atemplate<>
6761060SN/AFault
6772292SN/ASimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
6781060SN/A{
6792292SN/A    return write(*(uint64_t*)&data, addr, flags, res);
6801060SN/A}
6812843Sktlim@umich.edu
6822843Sktlim@umich.edutemplate<>
6832843Sktlim@umich.eduFault
6842843Sktlim@umich.eduSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
6852843Sktlim@umich.edu{
6862316SN/A    return write(*(uint32_t*)&data, addr, flags, res);
6872348SN/A}
6882292SN/A
6892260SN/A
6902292SN/Atemplate<>
6911060SN/AFault
6921060SN/ASimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
6932292SN/A{
6942292SN/A    return write((uint32_t)data, addr, flags, res);
6951060SN/A}
6962292SN/A
6972292SN/A
6982292SN/A#if FULL_SYSTEM
6992292SN/AAddr
7002292SN/ASimpleCPU::dbg_vtophys(Addr addr)
7012292SN/A{
7022829Sksewell@umich.edu    return vtophys(xc, addr);
7032829Sksewell@umich.edu}
7042829Sksewell@umich.edu#endif // FULL_SYSTEM
7052292SN/A
7062292SN/Avoid
7072292SN/ASimpleCPU::sendIcacheRequest(Packet *pkt)
7082292SN/A{
7092292SN/A    assert(!tickEvent.scheduled());
7102292SN/A#if SIMPLE_CPU_MEM_TIMING
7112292SN/A    retry_pkt = pkt;
7122292SN/A    bool success = icachePort.sendTiming(*pkt);
7132292SN/A
7142292SN/A    unscheduleTickEvent();
7152292SN/A
7162292SN/A    lastIcacheStall = curTick;
7172292SN/A
7182292SN/A    if (!success) {
7192292SN/A        // Need to wait for retry
7202292SN/A        _status = IcacheRetry;
7212292SN/A    } else {
7222292SN/A        // Need to wait for cache to respond
7232292SN/A        _status = IcacheWaitResponse;
7242292SN/A    }
7252292SN/A#elif SIMPLE_CPU_MEM_ATOMIC
7262292SN/A    Tick latency = icachePort.sendAtomic(*pkt);
7272292SN/A
7282292SN/A    unscheduleTickEvent();
7292292SN/A    scheduleTickEvent(latency);
7301060SN/A
7311060SN/A    // Note that Icache miss cycles will be incorrect.  Unless
7322325SN/A    // we check the status of the packet sent (is this valid?),
733    // we won't know if the latency is a hit or a miss.
734    icacheStallCycles += latency;
735
736    _status = IcacheAccessComplete;
737#elif SIMPLE_CPU_MEM_IMMEDIATE
738    icachePort.sendAtomic(*pkt);
739#else
740#error "SimpleCPU has no mem model set"
741#endif
742}
743
744void
745SimpleCPU::sendDcacheRequest(Packet *pkt)
746{
747    assert(!tickEvent.scheduled());
748#if SIMPLE_CPU_MEM_TIMING
749    unscheduleTickEvent();
750
751    retry_pkt = pkt;
752    bool success = dcachePort.sendTiming(*pkt);
753
754    lastDcacheStall = curTick;
755
756    if (!success) {
757        _status = DcacheRetry;
758    } else {
759        _status = DcacheWaitResponse;
760    }
761#elif SIMPLE_CPU_MEM_ATOMIC
762    unscheduleTickEvent();
763
764    Tick latency = dcachePort.sendAtomic(*pkt);
765
766    scheduleTickEvent(latency);
767
768    // Note that Dcache miss cycles will be incorrect.  Unless
769    // we check the status of the packet sent (is this valid?),
770    // we won't know if the latency is a hit or a miss.
771    dcacheStallCycles += latency;
772#elif SIMPLE_CPU_MEM_IMMEDIATE
773    dcachePort.sendAtomic(*pkt);
774#else
775#error "SimpleCPU has no mem model set"
776#endif
777}
778
779void
780SimpleCPU::processResponse(Packet &response)
781{
782    assert(SIMPLE_CPU_MEM_TIMING);
783
784    // For what things is the CPU the consumer of the packet it sent
785    // out?  This may create a memory leak if that's the case and it's
786    // expected of the SimpleCPU to delete its own packet.
787    Packet *pkt = &response;
788
789    switch (status()) {
790      case IcacheWaitResponse:
791        icacheStallCycles += curTick - lastIcacheStall;
792
793        _status = IcacheAccessComplete;
794        scheduleTickEvent(1);
795
796        // Copy the icache data into the instruction itself.
797        memcpy(&inst, pkt->data, sizeof(inst));
798
799        delete pkt;
800        break;
801      case DcacheWaitResponse:
802        if (pkt->cmd == Read) {
803            curStaticInst->execute(this,traceData);
804            if (traceData)
805                traceData->finalize();
806        }
807
808        delete pkt;
809
810        dcacheStallCycles += curTick - lastDcacheStall;
811        _status = Running;
812        scheduleTickEvent(1);
813        break;
814      case DcacheWaitSwitch:
815        if (pkt->cmd == Read) {
816            curStaticInst->execute(this,traceData);
817            if (traceData)
818                traceData->finalize();
819        }
820
821        delete pkt;
822
823        _status = SwitchedOut;
824        sampler->signalSwitched();
825      case SwitchedOut:
826        // If this CPU has been switched out due to sampling/warm-up,
827        // ignore any further status changes (e.g., due to cache
828        // misses outstanding at the time of the switch).
829        delete pkt;
830
831        return;
832      default:
833        panic("SimpleCPU::processCacheCompletion: bad state");
834        break;
835    }
836}
837
838Packet *
839SimpleCPU::processRetry()
840{
841#if SIMPLE_CPU_MEM_TIMING
842    switch(status()) {
843      case IcacheRetry:
844        icacheRetryCycles += curTick - lastIcacheStall;
845        return retry_pkt;
846        break;
847      case DcacheRetry:
848        dcacheRetryCycles += curTick - lastDcacheStall;
849        return retry_pkt;
850        break;
851      default:
852        panic("SimpleCPU::processRetry: bad state");
853        break;
854    }
855#else
856    panic("shouldn't be here");
857#endif
858}
859
860#if FULL_SYSTEM
861void
862SimpleCPU::post_interrupt(int int_num, int index)
863{
864    BaseCPU::post_interrupt(int_num, index);
865
866    if (xc->status() == ExecContext::Suspended) {
867                DPRINTF(IPI,"Suspended Processor awoke\n");
868        xc->activate();
869    }
870}
871#endif // FULL_SYSTEM
872
873/* start simulation, program loaded, processor precise state initialized */
874void
875SimpleCPU::tick()
876{
877    numCycles++;
878
879    traceData = NULL;
880
881    Fault fault = No_Fault;
882
883#if FULL_SYSTEM
884    if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
885        status() != IcacheMissComplete) {
886        int ipl = 0;
887        int summary = 0;
888        checkInterrupts = false;
889        IntReg *ipr = xc->regs.ipr;
890
891        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
892            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
893                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
894                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
895                    // See table 4-19 of 21164 hardware reference
896                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
897                    summary |= (ULL(1) << i);
898                }
899            }
900        }
901
902        uint64_t interrupts = xc->cpu->intr_status();
903        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
904            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
905            if (interrupts & (ULL(1) << i)) {
906                // See table 4-19 of 21164 hardware reference
907                ipl = i;
908                summary |= (ULL(1) << i);
909            }
910        }
911
912        if (ipr[TheISA::IPR_ASTRR])
913            panic("asynchronous traps not implemented\n");
914
915        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
916            ipr[TheISA::IPR_ISR] = summary;
917            ipr[TheISA::IPR_INTID] = ipl;
918            xc->ev5_trap(Interrupt_Fault);
919
920            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
921                    ipr[TheISA::IPR_IPLR], ipl, summary);
922        }
923    }
924#endif
925
926    // maintain $r0 semantics
927    xc->regs.intRegFile[ZeroReg] = 0;
928#ifdef TARGET_ALPHA
929    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
930#endif // TARGET_ALPHA
931
932    if (status() == IcacheAccessComplete) {
933        // We've already fetched an instruction and were stalled on an
934        // I-cache miss.  No need to fetch it again.
935
936        // Set status to running; tick event will get rescheduled if
937        // necessary at end of tick() function.
938        _status = Running;
939    } else {
940        // Try to fetch an instruction
941
942        // set up memory request for instruction fetch
943#if FULL_SYSTEM
944#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
945#else
946#define IFETCH_FLAGS(pc)	0
947#endif
948
949#if SIMPLE_CPU_MEM_TIMING
950        CpuRequest *ifetch_req = new CpuRequest();
951        ifetch_req->size = sizeof(MachInst);
952#endif
953
954        ifetch_req->vaddr = xc->regs.pc & ~3;
955        ifetch_req->time = curTick;
956
957/*	memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
958                     IFETCH_FLAGS(xc->regs.pc));
959*/
960
961        fault = xc->translateInstReq(ifetch_req);
962
963        if (fault == No_Fault) {
964#if SIMPLE_CPU_MEM_TIMING
965            Packet *ifetch_pkt = new Packet;
966            ifetch_pkt->cmd = Read;
967            ifetch_pkt->data = (uint8_t *)&inst;
968            ifetch_pkt->req = ifetch_req;
969            ifetch_pkt->size = sizeof(MachInst);
970#endif
971            ifetch_pkt->addr = ifetch_req->paddr;
972
973            sendIcacheRequest(ifetch_pkt);
974#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC
975            return;
976#endif
977/*
978        if (icacheInterface && fault == No_Fault) {
979            memReq->completionEvent = NULL;
980
981            memReq->time = curTick;
982            memReq->flags |= INST_READ;
983            MemAccessResult result = icacheInterface->access(memReq);
984
985            // Ugly hack to get an event scheduled *only* if the access is
986            // a miss.  We really should add first-class support for this
987            // at some point.
988                if (result != MA_HIT && icacheInterface->doEvents()) {
989                memReq->completionEvent = &cacheCompletionEvent;
990                lastIcacheStall = curTick;
991                unscheduleTickEvent();
992                _status = IcacheMissStall;
993                return;
994            }
995        }
996*/
997        }
998    }
999
1000    // If we've got a valid instruction (i.e., no fault on instruction
1001    // fetch), then execute it.
1002    if (fault == No_Fault) {
1003
1004        // keep an instruction count
1005        numInst++;
1006        numInsts++;
1007
1008        // check for instruction-count-based events
1009        comInstEventQueue[0]->serviceEvents(numInst);
1010
1011        // decode the instruction
1012        inst = gtoh(inst);
1013        curStaticInst = StaticInst<TheISA>::decode(inst);
1014
1015        traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
1016                                         xc->regs.pc);
1017
1018#if FULL_SYSTEM
1019        xc->setInst(inst);
1020#endif // FULL_SYSTEM
1021
1022        xc->func_exe_inst++;
1023
1024        fault = curStaticInst->execute(this, traceData);
1025
1026#if FULL_SYSTEM
1027        if (xc->fnbin) {
1028            assert(xc->kernelStats);
1029            system->kernelBinning->execute(xc, inst);
1030        }
1031
1032        if (xc->profile) {
1033            bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
1034            xc->profilePC = usermode ? 1 : xc->regs.pc;
1035            ProfileNode *node = xc->profile->consume(xc, inst);
1036            if (node)
1037                xc->profileNode = node;
1038        }
1039#endif
1040
1041        if (curStaticInst->isMemRef()) {
1042            numMemRefs++;
1043        }
1044
1045        if (curStaticInst->isLoad()) {
1046            ++numLoad;
1047            comLoadEventQueue[0]->serviceEvents(numLoad);
1048        }
1049
1050        // If we have a dcache miss, then we can't finialize the instruction
1051        // trace yet because we want to populate it with the data later
1052        if (traceData && (status() != DcacheWaitResponse)) {
1053            traceData->finalize();
1054        }
1055
1056        traceFunctions(xc->regs.pc);
1057
1058    }	// if (fault == No_Fault)
1059
1060    if (fault != No_Fault) {
1061#if FULL_SYSTEM
1062        xc->ev5_trap(fault);
1063#else // !FULL_SYSTEM
1064        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
1065#endif // FULL_SYSTEM
1066    }
1067    else {
1068        // go to the next instruction
1069        xc->regs.pc = xc->regs.npc;
1070        xc->regs.npc += sizeof(MachInst);
1071    }
1072
1073#if FULL_SYSTEM
1074    Addr oldpc;
1075    do {
1076        oldpc = xc->regs.pc;
1077        system->pcEventQueue.service(xc);
1078    } while (oldpc != xc->regs.pc);
1079#endif
1080
1081    assert(status() == Running ||
1082           status() == Idle ||
1083           status() == DcacheWaitResponse);
1084
1085    if (status() == Running && !tickEvent.scheduled())
1086        tickEvent.schedule(curTick + cycles(1));
1087}
1088
1089////////////////////////////////////////////////////////////////////////
1090//
1091//  SimpleCPU Simulation Object
1092//
1093BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1094
1095    Param<Counter> max_insts_any_thread;
1096    Param<Counter> max_insts_all_threads;
1097    Param<Counter> max_loads_any_thread;
1098    Param<Counter> max_loads_all_threads;
1099
1100#if FULL_SYSTEM
1101    SimObjectParam<AlphaITB *> itb;
1102    SimObjectParam<AlphaDTB *> dtb;
1103    SimObjectParam<System *> system;
1104    Param<int> cpu_id;
1105    Param<Tick> profile;
1106#else
1107    SimObjectParam<Memory *> mem;
1108    SimObjectParam<Process *> workload;
1109#endif // FULL_SYSTEM
1110
1111    Param<int> clock;
1112
1113    Param<bool> defer_registration;
1114    Param<int> width;
1115    Param<bool> function_trace;
1116    Param<Tick> function_trace_start;
1117
1118END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1119
1120BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1121
1122    INIT_PARAM(max_insts_any_thread,
1123               "terminate when any thread reaches this inst count"),
1124    INIT_PARAM(max_insts_all_threads,
1125               "terminate when all threads have reached this inst count"),
1126    INIT_PARAM(max_loads_any_thread,
1127               "terminate when any thread reaches this load count"),
1128    INIT_PARAM(max_loads_all_threads,
1129               "terminate when all threads have reached this load count"),
1130
1131#if FULL_SYSTEM
1132    INIT_PARAM(itb, "Instruction TLB"),
1133    INIT_PARAM(dtb, "Data TLB"),
1134    INIT_PARAM(system, "system object"),
1135    INIT_PARAM(cpu_id, "processor ID"),
1136    INIT_PARAM(profile, ""),
1137#else
1138    INIT_PARAM(mem, "memory"),
1139    INIT_PARAM(workload, "processes to run"),
1140#endif // FULL_SYSTEM
1141
1142    INIT_PARAM(clock, "clock speed"),
1143    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
1144    INIT_PARAM(width, "cpu width"),
1145    INIT_PARAM(function_trace, "Enable function trace"),
1146    INIT_PARAM(function_trace_start, "Cycle to start function trace")
1147
1148END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1149
1150
1151CREATE_SIM_OBJECT(SimpleCPU)
1152{
1153    SimpleCPU::Params *params = new SimpleCPU::Params();
1154    params->name = getInstanceName();
1155    params->numberOfThreads = 1;
1156    params->max_insts_any_thread = max_insts_any_thread;
1157    params->max_insts_all_threads = max_insts_all_threads;
1158    params->max_loads_any_thread = max_loads_any_thread;
1159    params->max_loads_all_threads = max_loads_all_threads;
1160    params->deferRegistration = defer_registration;
1161    params->clock = clock;
1162    params->functionTrace = function_trace;
1163    params->functionTraceStart = function_trace_start;
1164    params->width = width;
1165
1166#if FULL_SYSTEM
1167    params->itb = itb;
1168    params->dtb = dtb;
1169    params->system = system;
1170    params->cpu_id = cpu_id;
1171    params->profile = profile;
1172#else
1173    params->mem = mem;
1174    params->process = workload;
1175#endif
1176
1177    SimpleCPU *cpu = new SimpleCPU(params);
1178    return cpu;
1179}
1180
1181REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
1182
1183