base.cc revision 2390
12SN/A/*
21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292SN/A#include <cmath>
302SN/A#include <cstdio>
312439SN/A#include <cstdlib>
322984Sgblack@eecs.umich.edu#include <iostream>
33146SN/A#include <iomanip>
34146SN/A#include <list>
35146SN/A#include <sstream>
36146SN/A#include <string>
37146SN/A
38146SN/A#include "base/cprintf.hh"
391717SN/A#include "base/inifile.hh"
40146SN/A#include "base/loader/symtab.hh"
411717SN/A#include "base/misc.hh"
42146SN/A#include "base/pollevent.hh"
431977SN/A#include "base/range.hh"
442623SN/A#include "base/stats/events.hh"
452683Sktlim@umich.edu#include "base/trace.hh"
461717SN/A#include "cpu/base.hh"
47146SN/A#include "cpu/exec_context.hh"
482683Sktlim@umich.edu#include "cpu/exetrace.hh"
493348Sbinkertn@umich.edu#include "cpu/profile.hh"
502683Sktlim@umich.edu#include "cpu/sampler/sampler.hh"
512036SN/A#include "cpu/simple/cpu.hh"
52146SN/A#include "cpu/smt.hh"
5356SN/A#include "cpu/static_inst.hh"
5456SN/A#include "kern/kernel_stats.hh"
5556SN/A#include "mem/base_mem.hh"
56695SN/A#include "mem/mem_interface.hh"
572901Ssaidi@eecs.umich.edu#include "sim/builder.hh"
582SN/A#include "sim/debug.hh"
591858SN/A#include "sim/host.hh"
603565Sgblack@eecs.umich.edu#include "sim/sim_events.hh"
613565Sgblack@eecs.umich.edu#include "sim/sim_object.hh"
622171SN/A#include "sim/stats.hh"
632170SN/A
643562Sgblack@eecs.umich.edu#if FULL_SYSTEM
65146SN/A#include "base/remote_gdb.hh"
662462SN/A#include "mem/functional/memory_control.hh"
67146SN/A#include "mem/functional/physical.hh"
682SN/A#include "sim/system.hh"
692SN/A#include "targetarch/alpha_memory.hh"
702449SN/A#include "targetarch/stacktrace.hh"
711355SN/A#include "targetarch/vtophys.hh"
722623SN/A#else // !FULL_SYSTEM
733402Sktlim@umich.edu#include "mem/functional/functional.hh"
74224SN/A#endif // FULL_SYSTEM
751858SN/A
762683Sktlim@umich.eduusing namespace std;
772420SN/A
782683Sktlim@umich.edu
793402Sktlim@umich.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
802420SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
812SN/A{
822683Sktlim@umich.edu}
832672Sktlim@umich.edu
842683Sktlim@umich.eduvoid
852SN/ASimpleCPU::TickEvent::process()
862SN/A{
87334SN/A    int count = width;
88140SN/A    do {
89334SN/A        cpu->tick();
902SN/A    } while (--count > 0 && cpu->status() == Running);
912SN/A}
922SN/A
932680Sktlim@umich.educonst char *
942SN/ASimpleCPU::TickEvent::description()
952SN/A{
962623SN/A    return "SimpleCPU tick event";
972SN/A}
982SN/A
992SN/A
100180SN/ASimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
1012623SN/A    : Event(&mainEventQueue), cpu(_cpu)
102393SN/A{
103393SN/A}
104393SN/A
105393SN/Avoid SimpleCPU::CacheCompletionEvent::process()
106384SN/A{
107384SN/A    cpu->processCacheCompletion();
108393SN/A}
1092623SN/A
110393SN/Aconst char *
111393SN/ASimpleCPU::CacheCompletionEvent::description()
112393SN/A{
113393SN/A    return "SimpleCPU cache completion event";
114384SN/A}
115189SN/A
116189SN/ASimpleCPU::SimpleCPU(Params *p)
1172623SN/A    : BaseCPU(p), tickEvent(this, p->width), xc(NULL),
1182SN/A      cacheCompletionEvent(this), dcachePort(this), icachePort(this)
119729SN/A{
120334SN/A    _status = Idle;
1212SN/A#if FULL_SYSTEM
1222SN/A    xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
1232SN/A
1242SN/A    // initialize CPU, including PC
1252SN/A    TheISA::initCPU(&xc->regs);
1262SN/A#else
1272SN/A    xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0);
1282SN/A#endif // !FULL_SYSTEM
1292SN/A
1302SN/A    req = new CpuRequest;
1312SN/A
1322SN/A    req->asid = 0;
1331001SN/A
1341001SN/A    numInst = 0;
1351001SN/A    startNumInst = 0;
1361001SN/A    numLoad = 0;
1371001SN/A    startNumLoad = 0;
1382SN/A    lastIcacheStall = 0;
1392SN/A    lastDcacheStall = 0;
1402SN/A
1412SN/A    execContexts.push_back(xc);
1422SN/A}
1432SN/A
1442SN/ASimpleCPU::~SimpleCPU()
1452SN/A{
1462SN/A}
1472SN/A
1482SN/Avoid
1492SN/ASimpleCPU::switchOut(Sampler *s)
1502SN/A{
1512SN/A    sampler = s;
1522SN/A    if (status() == DcacheWaitResponse) {
1532SN/A        DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
1542SN/A        _status = DcacheWaitSwitch;
1552390SN/A    }
1562390SN/A    else {
1572390SN/A        _status = SwitchedOut;
1582390SN/A
1592390SN/A        if (tickEvent.scheduled())
1602390SN/A            tickEvent.squash();
1612390SN/A
1622390SN/A        sampler->signalSwitched();
1632390SN/A    }
1642390SN/A}
1652390SN/A
1662390SN/A
167385SN/Avoid
1682SN/ASimpleCPU::takeOverFrom(BaseCPU *oldCPU)
1692SN/A{
1702SN/A    BaseCPU::takeOverFrom(oldCPU);
1712623SN/A
172334SN/A    assert(!tickEvent.scheduled());
1732361SN/A
1742623SN/A    // if any of this CPU's ExecContexts are active, mark the CPU as
175334SN/A    // running and schedule its tick event.
176334SN/A    for (int i = 0; i < execContexts.size(); ++i) {
177334SN/A        ExecContext *xc = execContexts[i];
1782623SN/A        if (xc->status() == ExecContext::Active && _status != Running) {
1792SN/A            _status = Running;
180921SN/A            tickEvent.schedule(curTick);
1812915Sktlim@umich.edu        }
1822915Sktlim@umich.edu    }
1832683Sktlim@umich.edu}
1842SN/A
1852SN/A
1862SN/Avoid
1872623SN/ASimpleCPU::activateContext(int thread_num, int delay)
1882SN/A{
189921SN/A    assert(thread_num == 0);
1902915Sktlim@umich.edu    assert(xc);
1912915Sktlim@umich.edu
1922SN/A    assert(_status == Idle);
1932SN/A    notIdleFraction++;
1942SN/A    scheduleTickEvent(delay);
1952SN/A    _status = Running;
1962SN/A}
1972SN/A
1982SN/A
199595SN/Avoid
2002623SN/ASimpleCPU::suspendContext(int thread_num)
201595SN/A{
2022390SN/A    assert(thread_num == 0);
2031080SN/A    assert(xc);
2041080SN/A
2051080SN/A    assert(_status == Running);
2061080SN/A    notIdleFraction--;
2071080SN/A    unscheduleTickEvent();
2081080SN/A    _status = Idle;
2091080SN/A}
2101121SN/A
2112107SN/A
2121089SN/Avoid
2131089SN/ASimpleCPU::deallocateContext(int thread_num)
2141080SN/A{
2151080SN/A    // for now, these are equivalent
2161080SN/A    suspendContext(thread_num);
2171080SN/A}
218595SN/A
2192623SN/A
2202683Sktlim@umich.eduvoid
221595SN/ASimpleCPU::haltContext(int thread_num)
2222090SN/A{
2232683Sktlim@umich.edu    // for now, these are equivalent
2242683Sktlim@umich.edu    suspendContext(thread_num);
225595SN/A}
2262205SN/A
2272205SN/A
2282683Sktlim@umich.eduvoid
2292683Sktlim@umich.eduSimpleCPU::regStats()
230595SN/A{
231595SN/A    using namespace Stats;
2322390SN/A
2332423SN/A    BaseCPU::regStats();
2342390SN/A
235595SN/A    numInsts
236595SN/A        .name(name() + ".num_insts")
237595SN/A        .desc("Number of instructions executed")
2382623SN/A        ;
239595SN/A
2402390SN/A    numMemRefs
2411080SN/A        .name(name() + ".num_refs")
242595SN/A        .desc("Number of memory references")
2431080SN/A        ;
2441080SN/A
245595SN/A    notIdleFraction
2462683Sktlim@umich.edu        .name(name() + ".not_idle_fraction")
2471080SN/A        .desc("Percentage of non-idle cycles")
2481080SN/A        ;
2491080SN/A
2501121SN/A    idleFraction
2512107SN/A        .name(name() + ".idle_fraction")
2521089SN/A        .desc("Percentage of idle cycles")
2531080SN/A        ;
2541089SN/A
2551080SN/A    icacheStallCycles
2561080SN/A        .name(name() + ".icache_stall_cycles")
2571080SN/A        .desc("ICache total stall cycles")
258595SN/A        .prereq(icacheStallCycles)
2592683Sktlim@umich.edu        ;
2601080SN/A
2612090SN/A    dcacheStallCycles
2621080SN/A        .name(name() + ".dcache_stall_cycles")
263595SN/A        .desc("DCache total stall cycles")
2642683Sktlim@umich.edu        .prereq(dcacheStallCycles)
2652683Sktlim@umich.edu        ;
266595SN/A
2672683Sktlim@umich.edu    icacheRetryCycles
2681098SN/A        .name(name() + ".icache_retry_cycles")
2691098SN/A        .desc("ICache total retry cycles")
2701098SN/A        .prereq(icacheRetryCycles)
2712683Sktlim@umich.edu        ;
2721098SN/A
2731098SN/A    dcacheRetryCycles
2741098SN/A        .name(name() + ".dcache_retry_cycles")
2752012SN/A        .desc("DCache total retry cycles")
2761098SN/A        .prereq(dcacheRetryCycles)
2771098SN/A        ;
278595SN/A
2792205SN/A    idleFraction = constant(1.0) - notIdleFraction;
2802205SN/A}
2812205SN/A
282595SN/Avoid
2832390SN/ASimpleCPU::resetStats()
2842420SN/A{
2852423SN/A    startNumInst = numInst;
2862390SN/A    notIdleFraction = (_status != Idle);
287595SN/A}
288595SN/A
2891858SN/Avoid
2902SN/ASimpleCPU::serialize(ostream &os)
2912623SN/A{
2922SN/A    BaseCPU::serialize(os);
2932680Sktlim@umich.edu    SERIALIZE_ENUM(_status);
2942SN/A    SERIALIZE_SCALAR(inst);
2952SN/A    nameOut(os, csprintf("%s.xc", name()));
2962SN/A    xc->serialize(os);
2971858SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
2982SN/A    tickEvent.serialize(os);
2992623SN/A    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
3002SN/A    cacheCompletionEvent.serialize(os);
3012SN/A}
3022SN/A
3032683Sktlim@umich.eduvoid
3042SN/ASimpleCPU::unserialize(Checkpoint *cp, const string &section)
3052683Sktlim@umich.edu{
3062SN/A    BaseCPU::unserialize(cp, section);
3072SN/A    UNSERIALIZE_ENUM(_status);
3082SN/A    UNSERIALIZE_SCALAR(inst);
3092SN/A    xc->unserialize(cp, csprintf("%s.xc", section));
3102SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
3112623SN/A    cacheCompletionEvent
3122SN/A        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
3131858SN/A}
3143521Sgblack@eecs.umich.edu
3153520Sgblack@eecs.umich.eduvoid
3162SN/Achange_thread_state(int thread_number, int activate, int priority)
3173520Sgblack@eecs.umich.edu{
3183633Sktlim@umich.edu}
3193521Sgblack@eecs.umich.edu
3203520Sgblack@eecs.umich.eduFault
3212SN/ASimpleCPU::copySrcTranslate(Addr src)
3222SN/A{
3232SN/A#if 0
3242623SN/A    static bool no_warn = true;
3252SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3262623SN/A    // Only support block sizes of 64 atm.
3272623SN/A    assert(blk_size == 64);
3282662Sstever@eecs.umich.edu    int offset = src & (blk_size - 1);
3292623SN/A
3302623SN/A    // Make sure block doesn't span page
3313093Sksewell@umich.edu    if (no_warn &&
3323093Sksewell@umich.edu        (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
3333093Sksewell@umich.edu        (src >> 40) != 0xfffffc) {
3343093Sksewell@umich.edu        warn("Copied block source spans pages %x.", src);
3352741Sksewell@umich.edu        no_warn = false;
3362741Sksewell@umich.edu    }
3372741Sksewell@umich.edu
3382623SN/A    memReq->reset(src & ~(blk_size - 1), blk_size);
3392683Sktlim@umich.edu
3402683Sktlim@umich.edu    // translate to physical address
3412683Sktlim@umich.edu    Fault fault = xc->translateDataReadReq(memReq);
3422623SN/A
3432683Sktlim@umich.edu    assert(fault != Alignment_Fault);
3442623SN/A
3452623SN/A    if (fault == No_Fault) {
3462623SN/A        xc->copySrcAddr = src;
3472623SN/A        xc->copySrcPhysAddr = memReq->paddr + offset;
3482623SN/A    } else {
3492623SN/A        xc->copySrcAddr = 0;
3502623SN/A        xc->copySrcPhysAddr = 0;
3512623SN/A    }
3522SN/A    return fault;
3532683Sktlim@umich.edu#else
3542427SN/A    return No_Fault
3552683Sktlim@umich.edu#endif
3562427SN/A}
3572SN/A
3582623SN/AFault
3592623SN/ASimpleCPU::copy(Addr dest)
3602623SN/A{
3612SN/A#if 0
3622683Sktlim@umich.edu    static bool no_warn = true;
3632SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3642623SN/A    // Only support block sizes of 64 atm.
3652623SN/A    assert(blk_size == 64);
3662SN/A    uint8_t data[blk_size];
3672623SN/A    //assert(xc->copySrcAddr);
3682623SN/A    int offset = dest & (blk_size - 1);
3693276Sgblack@eecs.umich.edu
3703276Sgblack@eecs.umich.edu    // Make sure block doesn't span page
3713484Sktlim@umich.edu    if (no_warn &&
3723484Sktlim@umich.edu        (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
3733484Sktlim@umich.edu        (dest >> 40) != 0xfffffc) {
3743276Sgblack@eecs.umich.edu        no_warn = false;
3753521Sgblack@eecs.umich.edu        warn("Copied block destination spans pages %x. ", dest);
3763521Sgblack@eecs.umich.edu    }
3773521Sgblack@eecs.umich.edu
3783521Sgblack@eecs.umich.edu    memReq->reset(dest & ~(blk_size -1), blk_size);
3793484Sktlim@umich.edu    // translate to physical address
3803276Sgblack@eecs.umich.edu    Fault fault = xc->translateDataWriteReq(memReq);
3813276Sgblack@eecs.umich.edu
3823442Sgblack@eecs.umich.edu    assert(fault != Alignment_Fault);
3833442Sgblack@eecs.umich.edu
3843280Sgblack@eecs.umich.edu    if (fault == No_Fault) {
3853280Sgblack@eecs.umich.edu        Addr dest_addr = memReq->paddr + offset;
3863276Sgblack@eecs.umich.edu        // Need to read straight from memory since we have more than 8 bytes.
3873276Sgblack@eecs.umich.edu        memReq->paddr = xc->copySrcPhysAddr;
3883276Sgblack@eecs.umich.edu        xc->mem->read(memReq, data);
3893442Sgblack@eecs.umich.edu        memReq->paddr = dest_addr;
3903442Sgblack@eecs.umich.edu        xc->mem->write(memReq, data);
3913276Sgblack@eecs.umich.edu        if (dcacheInterface) {
3923276Sgblack@eecs.umich.edu            memReq->cmd = Copy;
3932470SN/A            memReq->completionEvent = NULL;
3943064Sgblack@eecs.umich.edu            memReq->paddr = xc->copySrcPhysAddr;
3952683Sktlim@umich.edu            memReq->dest = dest_addr;
3962623SN/A            memReq->size = 64;
3972623SN/A            memReq->time = curTick;
3982623SN/A            memReq->flags &= ~INST_READ;
3992623SN/A            dcacheInterface->access(memReq);
4002623SN/A        }
4012623SN/A    }
4022683Sktlim@umich.edu    return fault;
4032623SN/A#else
4042623SN/A    return No_Fault;
4052623SN/A#endif
4062623SN/A}
4072623SN/A
4082623SN/A// precise architected memory state accessor macros
4092623SN/Atemplate <class T>
4102683Sktlim@umich.eduFault
4113577Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, T &data, unsigned flags)
4122683Sktlim@umich.edu{
4132683Sktlim@umich.edu    if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) {
4142623SN/A//	Fault fault = xc->read(memReq,data);
4152683Sktlim@umich.edu        // Not sure what to check for no fault...
4162623SN/A        if (pkt->result == Success) {
4172420SN/A            memcpy(&data, pkt->data, sizeof(T));
4182SN/A        }
4192623SN/A
4202623SN/A        if (traceData) {
4212SN/A            traceData->setAddr(addr);
4222SN/A        }
4232623SN/A
4242623SN/A        // @todo: Figure out a way to create a Fault from the packet result.
4252623SN/A        return No_Fault;
4262623SN/A    }
4272SN/A
4282683Sktlim@umich.edu//    memReq->reset(addr, sizeof(T), flags);
4292644Sstever@eecs.umich.edu
4302644Sstever@eecs.umich.edu    // translate to physical address
4312644Sstever@eecs.umich.edu    // NEED NEW TRANSLATION HERE
4322644Sstever@eecs.umich.edu    Fault fault = xc->translateDataReadReq(memReq);
4332623SN/A
4342SN/A    // Now do the access.
4352SN/A    if (fault == No_Fault) {
4362623SN/A        pkt = new Packet;
4372623SN/A        pkt->cmd = Read;
4382623SN/A        req->paddr = addr;
4392090SN/A        pkt->size = sizeof(T);
4403905Ssaidi@eecs.umich.edu        pkt->req = req;
4412680Sktlim@umich.edu
4423929Ssaidi@eecs.umich.edu        sendDcacheRequest();
4433929Ssaidi@eecs.umich.edu    }
4443276Sgblack@eecs.umich.edu/*
4453276Sgblack@eecs.umich.edu        memReq->cmd = Read;
4463276Sgblack@eecs.umich.edu        memReq->completionEvent = NULL;
4473276Sgblack@eecs.umich.edu        memReq->time = curTick;
4483276Sgblack@eecs.umich.edu        memReq->flags &= ~INST_READ;
4493276Sgblack@eecs.umich.edu        MemAccessResult result = dcacheInterface->access(memReq);
4503276Sgblack@eecs.umich.edu
4513280Sgblack@eecs.umich.edu        // Ugly hack to get an event scheduled *only* if the access is
4523276Sgblack@eecs.umich.edu        // a miss.  We really should add first-class support for this
4533280Sgblack@eecs.umich.edu        // at some point.
4543276Sgblack@eecs.umich.edu        if (result != MA_HIT && dcacheInterface->doEvents()) {
4553276Sgblack@eecs.umich.edu            memReq->completionEvent = &cacheCompletionEvent;
4563276Sgblack@eecs.umich.edu            lastDcacheStall = curTick;
4573276Sgblack@eecs.umich.edu            unscheduleTickEvent();
4583280Sgblack@eecs.umich.edu            _status = DcacheMissStall;
4593276Sgblack@eecs.umich.edu        } else {
4603276Sgblack@eecs.umich.edu            // do functional access
4613280Sgblack@eecs.umich.edu            fault = xc->read(memReq, data);
4623276Sgblack@eecs.umich.edu
4633276Sgblack@eecs.umich.edu        }
4643276Sgblack@eecs.umich.edu
4653093Sksewell@umich.edu    } else if(fault == No_Fault) {
4663276Sgblack@eecs.umich.edu        // do functional access
4673276Sgblack@eecs.umich.edu        fault = xc->read(memReq, data);
4683276Sgblack@eecs.umich.edu
4693093Sksewell@umich.edu    }
4703276Sgblack@eecs.umich.edu*/
4712251SN/A    // This will need a new way to tell if it has a dcache attached.
4723276Sgblack@eecs.umich.edu    if (/*!dcacheInterface && */(memReq->flags & UNCACHEABLE))
4732SN/A        recordEvent("Uncached Read");
4742SN/A
4751858SN/A    return fault;
4762SN/A}
4772SN/A
4782683Sktlim@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
4792680Sktlim@umich.edu
4802683Sktlim@umich.edutemplate
4812SN/AFault
4822SN/ASimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
4832SN/A
484template
485Fault
486SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
487
488template
489Fault
490SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
491
492template
493Fault
494SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
495
496#endif //DOXYGEN_SHOULD_SKIP_THIS
497
498template<>
499Fault
500SimpleCPU::read(Addr addr, double &data, unsigned flags)
501{
502    return read(addr, *(uint64_t*)&data, flags);
503}
504
505template<>
506Fault
507SimpleCPU::read(Addr addr, float &data, unsigned flags)
508{
509    return read(addr, *(uint32_t*)&data, flags);
510}
511
512
513template<>
514Fault
515SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
516{
517    return read(addr, (uint32_t&)data, flags);
518}
519
520
521template <class T>
522Fault
523SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
524{
525//    memReq->reset(addr, sizeof(T), flags);
526    req->vaddr = addr;
527    req->time = curTick;
528    req->size = sizeof(T);
529
530    // translate to physical address
531    // NEED NEW TRANSLATION HERE
532    Fault fault = xc->translateDataWriteReq(memReq);
533
534    // Now do the access.
535    if (fault == No_Fault) {
536        pkt = new Packet;
537        pkt->cmd = Write;
538        pkt->size = sizeof(T);
539        pkt->req = req;
540
541        // Copy data into the packet.
542        pkt->data = new uint8_t[64];
543        memcpy(pkt->data, &data, sizeof(T));
544
545        sendDcacheRequest();
546    }
547
548/*
549    // do functional access
550    if (fault == No_Fault)
551        fault = xc->write(memReq, data);
552
553    if (fault == No_Fault && dcacheInterface) {
554        memReq->cmd = Write;
555        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
556        memReq->completionEvent = NULL;
557        memReq->time = curTick;
558        memReq->flags &= ~INST_READ;
559        MemAccessResult result = dcacheInterface->access(memReq);
560
561        // Ugly hack to get an event scheduled *only* if the access is
562        // a miss.  We really should add first-class support for this
563        // at some point.
564        if (result != MA_HIT && dcacheInterface->doEvents()) {
565            memReq->completionEvent = &cacheCompletionEvent;
566            lastDcacheStall = curTick;
567            unscheduleTickEvent();
568            _status = DcacheMissStall;
569        }
570    }
571*/
572    if (res && (fault == No_Fault))
573        *res = memReq->result;
574
575    // This will need a new way to tell if it's hooked up to a cache or not.
576    if (/*!dcacheInterface && */(memReq->flags & UNCACHEABLE))
577        recordEvent("Uncached Write");
578
579    // If the write needs to have a fault on the access, consider calling
580    // changeStatus() and changing it to "bad addr write" or something.
581    return fault;
582}
583
584
585#ifndef DOXYGEN_SHOULD_SKIP_THIS
586template
587Fault
588SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
589
590template
591Fault
592SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
593
594template
595Fault
596SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
597
598template
599Fault
600SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
601
602#endif //DOXYGEN_SHOULD_SKIP_THIS
603
604template<>
605Fault
606SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
607{
608    return write(*(uint64_t*)&data, addr, flags, res);
609}
610
611template<>
612Fault
613SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
614{
615    return write(*(uint32_t*)&data, addr, flags, res);
616}
617
618
619template<>
620Fault
621SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
622{
623    return write((uint32_t)data, addr, flags, res);
624}
625
626
627#if FULL_SYSTEM
628Addr
629SimpleCPU::dbg_vtophys(Addr addr)
630{
631    return vtophys(xc, addr);
632}
633#endif // FULL_SYSTEM
634
635void
636SimpleCPU::sendIcacheRequest()
637{
638#if 1
639    bool success = icachePort.sendTiming(pkt);
640
641    unscheduleTickEvent();
642
643    lastIcacheStall = curTick;
644
645    if (!success) {
646        // Need to wait for retry
647        _status = IcacheRetry;
648    } else {
649        // Need to wait for cache to respond
650        _status = IcacheWaitResponse;
651    }
652#else
653    Tick latency = icachePort.sendAtomic(pkt);
654
655    unscheduleTickEvent();
656    scheduleTickEvent(latency);
657
658    // Note that Icache miss cycles will be incorrect.  Unless
659    // we check the status of the packet sent (is this valid?),
660    // we won't know if the latency is a hit or a miss.
661    icacheStallCycles += latency;
662
663    _status = IcacheAccessComplete;
664#endif
665}
666
667void
668SimpleCPU::sendDcacheRequest()
669{
670    unscheduleTickEvent();
671
672#if 1
673    bool success = dcachePort.sendTiming(pkt);
674
675    lastDcacheStall = curTick;
676
677    if (!success) {
678        _status = DcacheRetry;
679    } else {
680        _status = DcacheWaitResponse;
681    }
682#else
683    Tick latency = dcachePort.sendAtomic(pkt);
684
685    scheduleTickEvent(latency);
686
687    // Note that Dcache miss cycles will be incorrect.  Unless
688    // we check the status of the packet sent (is this valid?),
689    // we won't know if the latency is a hit or a miss.
690    dcacheStallCycles += latency;
691
692    // Delete the packet right here?
693    delete pkt;
694#endif
695}
696
697void
698SimpleCPU::processResponse(Packet *response)
699{
700    // For what things is the CPU the consumer of the packet it sent out?
701    // This may create a memory leak if that's the case and it's expected of the
702    // SimpleCPU to delete its own packet.
703    pkt = response;
704
705    switch (status()) {
706      case IcacheWaitResponse:
707        icacheStallCycles += curTick - lastIcacheStall;
708
709        _status = IcacheAccessComplete;
710        scheduleTickEvent(1);
711
712        // Copy the icache data into the instruction itself.
713        memcpy(&inst, pkt->data, sizeof(inst));
714
715        delete pkt;
716        break;
717      case DcacheWaitResponse:
718        if (req->cmd.isRead()) {
719            curStaticInst->execute(this,traceData);
720            if (traceData)
721                traceData->finalize();
722        }
723
724        delete pkt;
725
726        dcacheStallCycles += curTick - lastDcacheStall;
727        _status = Running;
728        scheduleTickEvent(1);
729        break;
730      case DcacheWaitSwitch:
731        if (memReq->cmd.isRead()) {
732            curStaticInst->execute(this,traceData);
733            if (traceData)
734                traceData->finalize();
735        }
736
737        delete pkt;
738
739        _status = SwitchedOut;
740        sampler->signalSwitched();
741      case SwitchedOut:
742        // If this CPU has been switched out due to sampling/warm-up,
743        // ignore any further status changes (e.g., due to cache
744        // misses outstanding at the time of the switch).
745        delete pkt;
746
747        return;
748      default:
749        panic("SimpleCPU::processCacheCompletion: bad state");
750        break;
751    }
752}
753
754Packet *
755SimpleCPU::processRetry()
756{
757    switch(status()) {
758      case IcacheRetry:
759        icacheRetryCycles += curTick - lastIcacheStall;
760        return pkt;
761        break;
762      case DcacheRetry:
763        dcacheRetryCycles += curTick - lastDcacheStall;
764        return pkt;
765        break;
766      default:
767        panic("SimpleCPU::processRetry: bad state");
768        break;
769    }
770}
771
772#if FULL_SYSTEM
773void
774SimpleCPU::post_interrupt(int int_num, int index)
775{
776    BaseCPU::post_interrupt(int_num, index);
777
778    if (xc->status() == ExecContext::Suspended) {
779                DPRINTF(IPI,"Suspended Processor awoke\n");
780        xc->activate();
781    }
782}
783#endif // FULL_SYSTEM
784
785/* start simulation, program loaded, processor precise state initialized */
786void
787SimpleCPU::tick()
788{
789    numCycles++;
790
791    traceData = NULL;
792
793    Fault fault = No_Fault;
794
795#if FULL_SYSTEM
796    if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
797        status() != IcacheMissComplete) {
798        int ipl = 0;
799        int summary = 0;
800        checkInterrupts = false;
801        IntReg *ipr = xc->regs.ipr;
802
803        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
804            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
805                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
806                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
807                    // See table 4-19 of 21164 hardware reference
808                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
809                    summary |= (ULL(1) << i);
810                }
811            }
812        }
813
814        uint64_t interrupts = xc->cpu->intr_status();
815        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
816            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
817            if (interrupts & (ULL(1) << i)) {
818                // See table 4-19 of 21164 hardware reference
819                ipl = i;
820                summary |= (ULL(1) << i);
821            }
822        }
823
824        if (ipr[TheISA::IPR_ASTRR])
825            panic("asynchronous traps not implemented\n");
826
827        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
828            ipr[TheISA::IPR_ISR] = summary;
829            ipr[TheISA::IPR_INTID] = ipl;
830            xc->ev5_trap(Interrupt_Fault);
831
832            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
833                    ipr[TheISA::IPR_IPLR], ipl, summary);
834        }
835    }
836#endif
837
838    // maintain $r0 semantics
839    xc->regs.intRegFile[ZeroReg] = 0;
840#ifdef TARGET_ALPHA
841    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
842#endif // TARGET_ALPHA
843
844    if (status() == IcacheAccessComplete) {
845        // We've already fetched an instruction and were stalled on an
846        // I-cache miss.  No need to fetch it again.
847
848        // Set status to running; tick event will get rescheduled if
849        // necessary at end of tick() function.
850        _status = Running;
851    } else {
852        // Try to fetch an instruction
853
854        // set up memory request for instruction fetch
855#if FULL_SYSTEM
856#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
857#else
858#define IFETCH_FLAGS(pc)	0
859#endif
860
861        req->vaddr = xc->regs.pc & ~3;
862        req->time = curTick;
863        req->size = sizeof(MachInst);
864
865/*	memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
866                     IFETCH_FLAGS(xc->regs.pc));
867*/
868//NEED NEW TRANSLATION HERE
869        fault = xc->translateInstReq(memReq);
870
871        if (fault == No_Fault) {
872            pkt = new Packet;
873            pkt->cmd = Read;
874            pkt->addr = req->paddr;
875            pkt->size = sizeof(MachInst);
876            pkt->req = req;
877
878            sendIcacheRequest();
879/*	    fault = xc->mem->read(memReq, inst);
880
881        if (icacheInterface && fault == No_Fault) {
882            memReq->completionEvent = NULL;
883
884            memReq->time = curTick;
885            memReq->flags |= INST_READ;
886            MemAccessResult result = icacheInterface->access(memReq);
887
888            // Ugly hack to get an event scheduled *only* if the access is
889            // a miss.  We really should add first-class support for this
890            // at some point.
891                if (result != MA_HIT && icacheInterface->doEvents()) {
892                memReq->completionEvent = &cacheCompletionEvent;
893                lastIcacheStall = curTick;
894                unscheduleTickEvent();
895                _status = IcacheMissStall;
896                return;
897            }
898        }
899*/
900        }
901    }
902
903    // If we've got a valid instruction (i.e., no fault on instruction
904    // fetch), then execute it.
905    if (fault == No_Fault) {
906
907        // keep an instruction count
908        numInst++;
909        numInsts++;
910
911        // check for instruction-count-based events
912        comInstEventQueue[0]->serviceEvents(numInst);
913
914        // decode the instruction
915        inst = gtoh(inst);
916        curStaticInst = StaticInst<TheISA>::decode(inst);
917
918        traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
919                                         xc->regs.pc);
920
921#if FULL_SYSTEM
922        xc->setInst(inst);
923#endif // FULL_SYSTEM
924
925        xc->func_exe_inst++;
926
927        fault = curStaticInst->execute(this, traceData);
928
929#if FULL_SYSTEM
930        if (xc->fnbin) {
931            assert(xc->kernelStats);
932            system->kernelBinning->execute(xc, inst);
933        }
934
935        if (xc->profile) {
936            bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
937            xc->profilePC = usermode ? 1 : xc->regs.pc;
938            ProfileNode *node = xc->profile->consume(xc, inst);
939            if (node)
940                xc->profileNode = node;
941        }
942#endif
943
944        if (curStaticInst->isMemRef()) {
945            numMemRefs++;
946        }
947
948        if (curStaticInst->isLoad()) {
949            ++numLoad;
950            comLoadEventQueue[0]->serviceEvents(numLoad);
951        }
952
953        // If we have a dcache miss, then we can't finialize the instruction
954        // trace yet because we want to populate it with the data later
955        if (traceData &&
956                !(status() == DcacheWaitResponse && memReq->cmd.isRead())) {
957            traceData->finalize();
958        }
959
960        traceFunctions(xc->regs.pc);
961
962    }	// if (fault == No_Fault)
963
964    if (fault != No_Fault) {
965#if FULL_SYSTEM
966        xc->ev5_trap(fault);
967#else // !FULL_SYSTEM
968        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
969#endif // FULL_SYSTEM
970    }
971    else {
972        // go to the next instruction
973        xc->regs.pc = xc->regs.npc;
974        xc->regs.npc += sizeof(MachInst);
975    }
976
977#if FULL_SYSTEM
978    Addr oldpc;
979    do {
980        oldpc = xc->regs.pc;
981        system->pcEventQueue.service(xc);
982    } while (oldpc != xc->regs.pc);
983#endif
984
985    assert(status() == Running ||
986           status() == Idle ||
987           status() == DcacheWaitResponse);
988
989    if (status() == Running && !tickEvent.scheduled())
990        tickEvent.schedule(curTick + cycles(1));
991}
992
993////////////////////////////////////////////////////////////////////////
994//
995//  SimpleCPU Simulation Object
996//
997BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
998
999    Param<Counter> max_insts_any_thread;
1000    Param<Counter> max_insts_all_threads;
1001    Param<Counter> max_loads_any_thread;
1002    Param<Counter> max_loads_all_threads;
1003
1004#if FULL_SYSTEM
1005    SimObjectParam<AlphaITB *> itb;
1006    SimObjectParam<AlphaDTB *> dtb;
1007    SimObjectParam<FunctionalMemory *> mem;
1008    SimObjectParam<System *> system;
1009    Param<int> cpu_id;
1010    Param<Tick> profile;
1011#else
1012    SimObjectParam<Process *> workload;
1013#endif // FULL_SYSTEM
1014
1015    Param<int> clock;
1016    SimObjectParam<BaseMem *> icache;
1017    SimObjectParam<BaseMem *> dcache;
1018
1019    Param<bool> defer_registration;
1020    Param<int> width;
1021    Param<bool> function_trace;
1022    Param<Tick> function_trace_start;
1023
1024END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1025
1026BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1027
1028    INIT_PARAM(max_insts_any_thread,
1029               "terminate when any thread reaches this inst count"),
1030    INIT_PARAM(max_insts_all_threads,
1031               "terminate when all threads have reached this inst count"),
1032    INIT_PARAM(max_loads_any_thread,
1033               "terminate when any thread reaches this load count"),
1034    INIT_PARAM(max_loads_all_threads,
1035               "terminate when all threads have reached this load count"),
1036
1037#if FULL_SYSTEM
1038    INIT_PARAM(itb, "Instruction TLB"),
1039    INIT_PARAM(dtb, "Data TLB"),
1040    INIT_PARAM(mem, "memory"),
1041    INIT_PARAM(system, "system object"),
1042    INIT_PARAM(cpu_id, "processor ID"),
1043    INIT_PARAM(profile, ""),
1044#else
1045    INIT_PARAM(workload, "processes to run"),
1046#endif // FULL_SYSTEM
1047
1048    INIT_PARAM(clock, "clock speed"),
1049    INIT_PARAM(icache, "L1 instruction cache object"),
1050    INIT_PARAM(dcache, "L1 data cache object"),
1051    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
1052    INIT_PARAM(width, "cpu width"),
1053    INIT_PARAM(function_trace, "Enable function trace"),
1054    INIT_PARAM(function_trace_start, "Cycle to start function trace")
1055
1056END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1057
1058
1059CREATE_SIM_OBJECT(SimpleCPU)
1060{
1061    SimpleCPU::Params *params = new SimpleCPU::Params();
1062    params->name = getInstanceName();
1063    params->numberOfThreads = 1;
1064    params->max_insts_any_thread = max_insts_any_thread;
1065    params->max_insts_all_threads = max_insts_all_threads;
1066    params->max_loads_any_thread = max_loads_any_thread;
1067    params->max_loads_all_threads = max_loads_all_threads;
1068    params->deferRegistration = defer_registration;
1069    params->clock = clock;
1070    params->functionTrace = function_trace;
1071    params->functionTraceStart = function_trace_start;
1072    params->icache_interface = (icache) ? icache->getInterface() : NULL;
1073    params->dcache_interface = (dcache) ? dcache->getInterface() : NULL;
1074    params->width = width;
1075
1076#if FULL_SYSTEM
1077    params->itb = itb;
1078    params->dtb = dtb;
1079    params->mem = mem;
1080    params->system = system;
1081    params->cpu_id = cpu_id;
1082    params->profile = profile;
1083#else
1084    params->process = workload;
1085#endif
1086
1087    SimpleCPU *cpu = new SimpleCPU(params);
1088    return cpu;
1089}
1090
1091REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
1092
1093