base.cc revision 2462
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.
272SN/A */
282SN/A
292439SN/A#include <cmath>
30146SN/A#include <cstdio>
31146SN/A#include <cstdlib>
32146SN/A#include <iostream>
33146SN/A#include <iomanip>
34146SN/A#include <list>
35146SN/A#include <sstream>
361717SN/A#include <string>
37146SN/A
381717SN/A#include "arch/utility.hh"
392190SN/A#include "base/cprintf.hh"
40146SN/A#include "base/inifile.hh"
41146SN/A#include "base/loader/symtab.hh"
421977SN/A#include "base/misc.hh"
431717SN/A#include "base/pollevent.hh"
442623SN/A#include "base/range.hh"
451717SN/A#include "base/stats/events.hh"
46146SN/A#include "base/trace.hh"
471917SN/A#include "cpu/base.hh"
482592SN/A#include "cpu/cpu_exec_context.hh"
492036SN/A#include "cpu/exec_context.hh"
50146SN/A#include "cpu/exetrace.hh"
51146SN/A#include "cpu/profile.hh"
5256SN/A#include "cpu/sampler/sampler.hh"
5356SN/A#include "cpu/simple/cpu.hh"
5456SN/A#include "cpu/smt.hh"
55695SN/A#include "cpu/static_inst.hh"
562SN/A#include "kern/kernel_stats.hh"
571858SN/A#include "sim/byteswap.hh"
5856SN/A#include "sim/builder.hh"
59146SN/A#include "sim/debug.hh"
602171SN/A#include "sim/host.hh"
612170SN/A#include "sim/sim_events.hh"
622170SN/A#include "sim/sim_object.hh"
63146SN/A#include "sim/stats.hh"
642462SN/A
65146SN/A#if FULL_SYSTEM
662SN/A#include "base/remote_gdb.hh"
672SN/A#include "mem/functional/memory_control.hh"
682449SN/A#include "mem/functional/physical.hh"
691355SN/A#include "sim/system.hh"
702623SN/A#include "arch/tlb.hh"
712623SN/A#include "arch/stacktrace.hh"
72224SN/A#include "arch/vtophys.hh"
731858SN/A#else // !FULL_SYSTEM
742518SN/A#include "mem/mem_object.hh"
752420SN/A#endif // FULL_SYSTEM
762519SN/A
772520SN/Ausing namespace std;
782420SN/Ausing namespace TheISA;
792SN/A
802190SN/ASimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
812SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
822SN/A{
83334SN/A}
84140SN/A
85334SN/A
862SN/Avoid
872SN/ASimpleCPU::init()
882SN/A{
892190SN/A    BaseCPU::init();
902SN/A#if FULL_SYSTEM
912SN/A    for (int i = 0; i < execContexts.size(); ++i) {
922623SN/A        ExecContext *xc = execContexts[i];
932SN/A
942SN/A        // initialize CPU, including PC
952SN/A        TheISA::initCPU(xc, xc->readCpuId());
96180SN/A    }
972623SN/A#endif
98393SN/A}
99393SN/A
100393SN/Avoid
101393SN/ASimpleCPU::TickEvent::process()
102384SN/A{
103384SN/A    int count = width;
104393SN/A    do {
1052623SN/A        cpu->tick();
106393SN/A    } while (--count > 0 && cpu->status() == Running);
107393SN/A}
108393SN/A
109393SN/Aconst char *
110384SN/ASimpleCPU::TickEvent::description()
111189SN/A{
112189SN/A    return "SimpleCPU tick event";
1132623SN/A}
1142SN/A
115729SN/A
116334SN/Abool
1172SN/ASimpleCPU::CpuPort::recvTiming(Packet &pkt)
1182SN/A{
1192SN/A    cpu->processResponse(pkt);
1202SN/A    return true;
1212SN/A}
1222SN/A
1232SN/ATick
1242SN/ASimpleCPU::CpuPort::recvAtomic(Packet &pkt)
1252SN/A{
1262SN/A    panic("CPU doesn't expect callback!");
1272SN/A    return curTick;
1282SN/A}
1291001SN/A
1301001SN/Avoid
1311001SN/ASimpleCPU::CpuPort::recvFunctional(Packet &pkt)
1321001SN/A{
1331001SN/A    panic("CPU doesn't expect callback!");
1342SN/A}
1352SN/A
1362SN/Avoid
1372SN/ASimpleCPU::CpuPort::recvStatusChange(Status status)
1382SN/A{
1392SN/A    cpu->recvStatusChange(status);
1402SN/A}
1412SN/A
1422SN/APacket *
1432SN/ASimpleCPU::CpuPort::recvRetry()
1442SN/A{
1452SN/A    return cpu->processRetry();
1462SN/A}
1472SN/A
1482SN/ASimpleCPU::SimpleCPU(Params *p)
1492SN/A    : BaseCPU(p), icachePort(this),
1502SN/A      dcachePort(this), tickEvent(this, p->width), cpuXC(NULL)
1512390SN/A{
1522390SN/A    _status = Idle;
1532390SN/A
1542390SN/A    //Create Memory Ports (conect them up)
1552390SN/A    Port *mem_dport = p->mem->getPort();
1562390SN/A    dcachePort.setPeer(mem_dport);
1572390SN/A    mem_dport->setPeer(&dcachePort);
1582390SN/A
1592390SN/A    Port *mem_iport = p->mem->getPort();
1602390SN/A    icachePort.setPeer(mem_iport);
1612390SN/A    mem_iport->setPeer(&icachePort);
1622390SN/A
163385SN/A#if FULL_SYSTEM
1642SN/A    cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
1652SN/A#else
1662SN/A    cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0,
1672623SN/A                         &dcachePort);
168334SN/A#endif // !FULL_SYSTEM
169334SN/A
1702623SN/A    xcProxy = cpuXC->getProxy();
171334SN/A
172334SN/A#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
173334SN/A    ifetch_req = new CpuRequest;
1742623SN/A    ifetch_req->asid = 0;
1752SN/A    ifetch_req->size = sizeof(MachInst);
176921SN/A    ifetch_pkt = new Packet;
177224SN/A    ifetch_pkt->cmd = Read;
178237SN/A    ifetch_pkt->data = (uint8_t *)&inst;
1792190SN/A    ifetch_pkt->req = ifetch_req;
1802SN/A    ifetch_pkt->size = sizeof(MachInst);
1812SN/A
1822SN/A    data_read_req = new CpuRequest;
1832623SN/A    data_read_req->asid = 0;
1842SN/A    data_read_pkt = new Packet;
185921SN/A    data_read_pkt->cmd = Read;
186224SN/A    data_read_pkt->data = new uint8_t[8];
1872190SN/A    data_read_pkt->req = data_read_req;
1882SN/A
1892SN/A    data_write_req = new CpuRequest;
1902SN/A    data_write_req->asid = 0;
1912SN/A    data_write_pkt = new Packet;
1922SN/A    data_write_pkt->cmd = Write;
1932SN/A    data_write_pkt->req = data_write_req;
1942SN/A#endif
195595SN/A
1962623SN/A    numInst = 0;
197595SN/A    startNumInst = 0;
1982390SN/A    numLoad = 0;
1991080SN/A    startNumLoad = 0;
2001080SN/A    lastIcacheStall = 0;
2011080SN/A    lastDcacheStall = 0;
2021080SN/A
2031080SN/A    execContexts.push_back(xcProxy);
2041080SN/A}
2051080SN/A
2061121SN/ASimpleCPU::~SimpleCPU()
2072107SN/A{
2081089SN/A}
2091089SN/A
2101080SN/Avoid
2111080SN/ASimpleCPU::switchOut(Sampler *s)
2121080SN/A{
2131080SN/A    sampler = s;
214595SN/A    if (status() == DcacheWaitResponse) {
2152623SN/A        DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
2162623SN/A        _status = DcacheWaitSwitch;
217595SN/A    }
2182090SN/A    else {
2192190SN/A        _status = SwitchedOut;
2202190SN/A
221595SN/A        if (tickEvent.scheduled())
2222205SN/A            tickEvent.squash();
2232205SN/A
2242190SN/A        sampler->signalSwitched();
2252190SN/A    }
226595SN/A}
227595SN/A
2282390SN/A
2292423SN/Avoid
2302390SN/ASimpleCPU::takeOverFrom(BaseCPU *oldCPU)
231595SN/A{
232595SN/A    BaseCPU::takeOverFrom(oldCPU);
233595SN/A
2342623SN/A    assert(!tickEvent.scheduled());
235595SN/A
2362390SN/A    // if any of this CPU's ExecContexts are active, mark the CPU as
2371080SN/A    // running and schedule its tick event.
238595SN/A    for (int i = 0; i < execContexts.size(); ++i) {
2391080SN/A        ExecContext *xc = execContexts[i];
2401080SN/A        if (xc->status() == ExecContext::Active && _status != Running) {
241595SN/A            _status = Running;
2422190SN/A            tickEvent.schedule(curTick);
2431080SN/A        }
2441080SN/A    }
2451080SN/A}
2461121SN/A
2472107SN/A
2481089SN/Avoid
2491080SN/ASimpleCPU::activateContext(int thread_num, int delay)
2501089SN/A{
2511080SN/A    assert(thread_num == 0);
2521080SN/A    assert(cpuXC);
2531080SN/A
254595SN/A    assert(_status == Idle);
2552422SN/A    notIdleFraction++;
2561080SN/A    scheduleTickEvent(delay);
2572090SN/A    _status = Running;
2581080SN/A}
259595SN/A
2602190SN/A
2612190SN/Avoid
262595SN/ASimpleCPU::suspendContext(int thread_num)
2632190SN/A{
2641098SN/A    assert(thread_num == 0);
2651098SN/A    assert(cpuXC);
2661098SN/A
2672190SN/A    assert(_status == Running);
2681098SN/A    notIdleFraction--;
2691098SN/A    unscheduleTickEvent();
2701098SN/A    _status = Idle;
2712012SN/A}
2721098SN/A
2731098SN/A
274595SN/Avoid
2752205SN/ASimpleCPU::deallocateContext(int thread_num)
2762205SN/A{
2772205SN/A    // for now, these are equivalent
278595SN/A    suspendContext(thread_num);
2792390SN/A}
2802420SN/A
2812423SN/A
2822390SN/Avoid
283595SN/ASimpleCPU::haltContext(int thread_num)
284595SN/A{
2851858SN/A    // for now, these are equivalent
2862SN/A    suspendContext(thread_num);
2872623SN/A}
2882SN/A
2892190SN/A
2902SN/Avoid
2912SN/ASimpleCPU::regStats()
2922SN/A{
2931858SN/A    using namespace Stats;
2942SN/A
2952623SN/A    BaseCPU::regStats();
2962SN/A
2972SN/A    numInsts
2982SN/A        .name(name() + ".num_insts")
2992190SN/A        .desc("Number of instructions executed")
3002SN/A        ;
3012190SN/A
3022SN/A    numMemRefs
3032SN/A        .name(name() + ".num_refs")
3042SN/A        .desc("Number of memory references")
3052SN/A        ;
3062SN/A
3072623SN/A    notIdleFraction
3082SN/A        .name(name() + ".not_idle_fraction")
3091858SN/A        .desc("Percentage of non-idle cycles")
3102626SN/A        ;
3112SN/A
3122SN/A    idleFraction
3131133SN/A        .name(name() + ".idle_fraction")
3142SN/A        .desc("Percentage of idle cycles")
3152190SN/A        ;
3162107SN/A
3172107SN/A    icacheStallCycles
3182190SN/A        .name(name() + ".icache_stall_cycles")
3192SN/A        .desc("ICache total stall cycles")
3202107SN/A        .prereq(icacheStallCycles)
3212SN/A        ;
3222SN/A
3232SN/A    dcacheStallCycles
3242SN/A        .name(name() + ".dcache_stall_cycles")
3252SN/A        .desc("DCache total stall cycles")
3262190SN/A        .prereq(dcacheStallCycles)
3272107SN/A        ;
3282107SN/A
3292SN/A    icacheRetryCycles
3302SN/A        .name(name() + ".icache_retry_cycles")
3312SN/A        .desc("ICache total retry cycles")
3322SN/A        .prereq(icacheRetryCycles)
3332SN/A        ;
3342SN/A
3352SN/A    dcacheRetryCycles
3362190SN/A        .name(name() + ".dcache_retry_cycles")
3372SN/A        .desc("DCache total retry cycles")
3382SN/A        .prereq(dcacheRetryCycles)
3392190SN/A        ;
3402190SN/A
3412190SN/A    idleFraction = constant(1.0) - notIdleFraction;
3422234SN/A}
3432234SN/A
3442SN/Avoid
3452SN/ASimpleCPU::resetStats()
3462190SN/A{
3472SN/A    startNumInst = numInst;
3482SN/A    notIdleFraction = (_status != Idle);
3492SN/A}
3502623SN/A
3512SN/Avoid
3522623SN/ASimpleCPU::serialize(ostream &os)
3532623SN/A{
3542623SN/A    BaseCPU::serialize(os);
3552623SN/A    SERIALIZE_ENUM(_status);
3562623SN/A    SERIALIZE_SCALAR(inst);
3572623SN/A    nameOut(os, csprintf("%s.xc", name()));
3582623SN/A    cpuXC->serialize(os);
3592623SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
3602623SN/A    tickEvent.serialize(os);
3612623SN/A    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
3622623SN/A}
3632623SN/A
3642623SN/Avoid
3652623SN/ASimpleCPU::unserialize(Checkpoint *cp, const string &section)
3662623SN/A{
3672623SN/A    BaseCPU::unserialize(cp, section);
3682623SN/A    UNSERIALIZE_ENUM(_status);
3692623SN/A    UNSERIALIZE_SCALAR(inst);
3702623SN/A    cpuXC->unserialize(cp, csprintf("%s.xc", section));
3712623SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
3722623SN/A}
3732623SN/A
3742623SN/Avoid
3752641Sstever@eecs.umich.educhange_thread_state(int thread_number, int activate, int priority)
3762623SN/A{
3772623SN/A}
3782623SN/A
3792623SN/AFault
3802623SN/ASimpleCPU::copySrcTranslate(Addr src)
3812623SN/A{
3822623SN/A#if 0
3832623SN/A    static bool no_warn = true;
3842623SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3852SN/A    // Only support block sizes of 64 atm.
3862190SN/A    assert(blk_size == 64);
3872427SN/A    int offset = src & (blk_size - 1);
3882455SN/A
3892427SN/A    // Make sure block doesn't span page
3902SN/A    if (no_warn &&
3912623SN/A        (src & PageMask) != ((src + blk_size) & PageMask) &&
3922623SN/A        (src >> 40) != 0xfffffc) {
3932623SN/A        warn("Copied block source spans pages %x.", src);
3942SN/A        no_warn = false;
3952623SN/A    }
3962SN/A
3972623SN/A    memReq->reset(src & ~(blk_size - 1), blk_size);
3982623SN/A
3992SN/A    // translate to physical address    Fault fault = cpuXC->translateDataReadReq(req);
4002623SN/A
4012623SN/A    if (fault == NoFault) {
4022623SN/A        cpuXC->copySrcAddr = src;
4032470SN/A        cpuXC->copySrcPhysAddr = memReq->paddr + offset;
4042623SN/A    } else {
4052623SN/A        assert(!fault->isAlignmentFault());
4062623SN/A
4072623SN/A        cpuXC->copySrcAddr = 0;
4082623SN/A        cpuXC->copySrcPhysAddr = 0;
4092623SN/A    }
4102623SN/A    return fault;
4112623SN/A#else
4122623SN/A    return NoFault;
4132623SN/A#endif
4142623SN/A}
4152623SN/A
4162623SN/AFault
4172623SN/ASimpleCPU::copy(Addr dest)
4182623SN/A{
4192623SN/A#if 0
4202623SN/A    static bool no_warn = true;
4212623SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
4222623SN/A    // Only support block sizes of 64 atm.
4232623SN/A    assert(blk_size == 64);
4242623SN/A    uint8_t data[blk_size];
4252623SN/A    //assert(cpuXC->copySrcAddr);
4262623SN/A    int offset = dest & (blk_size - 1);
4272623SN/A
4282623SN/A    // Make sure block doesn't span page
4292623SN/A    if (no_warn &&
4302623SN/A        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
4312623SN/A        (dest >> 40) != 0xfffffc) {
4322623SN/A        no_warn = false;
4332420SN/A        warn("Copied block destination spans pages %x. ", dest);
4342SN/A    }
4352623SN/A
4362623SN/A    memReq->reset(dest & ~(blk_size -1), blk_size);
4372SN/A    // translate to physical address
4382SN/A    Fault fault = cpuXC->translateDataWriteReq(req);
4392623SN/A
4402623SN/A    if (fault == NoFault) {
4412623SN/A        Addr dest_addr = memReq->paddr + offset;
4422623SN/A        // Need to read straight from memory since we have more than 8 bytes.
4432SN/A        memReq->paddr = cpuXC->copySrcPhysAddr;
4442623SN/A        cpuXC->mem->read(memReq, data);
4452644Sstever@eecs.umich.edu        memReq->paddr = dest_addr;
4462644Sstever@eecs.umich.edu        cpuXC->mem->write(memReq, data);
4472644Sstever@eecs.umich.edu        if (dcacheInterface) {
4482644Sstever@eecs.umich.edu            memReq->cmd = Copy;
4492623SN/A            memReq->completionEvent = NULL;
4502SN/A            memReq->paddr = cpuXC->copySrcPhysAddr;
4512SN/A            memReq->dest = dest_addr;
4522623SN/A            memReq->size = 64;
4532623SN/A            memReq->time = curTick;
4542623SN/A            memReq->flags &= ~INST_READ;
4552090SN/A            dcacheInterface->access(memReq);
4561858SN/A        }
4572234SN/A    }
4582SN/A    else
4592470SN/A        assert(!fault->isAlignmentFault());
4602SN/A
4612SN/A    return fault;
4622SN/A#else
4632SN/A    panic("copy not implemented");
4642190SN/A    return NoFault;
4652623SN/A#endif
4662190SN/A}
4672251SN/A
4682262SN/A// precise architected memory state accessor macros
4692262SN/Atemplate <class T>
4702251SN/AFault
4712251SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags)
4722SN/A{
4732SN/A    if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) {
4741858SN/A//	Fault fault = xc->read(memReq,data);
4752SN/A        // Not sure what to check for no fault...
4762SN/A        if (data_read_pkt->result == Success) {
4772190SN/A            memcpy(&data, data_read_pkt->data, sizeof(T));
4782190SN/A        }
4792190SN/A
4802SN/A        if (traceData) {
4812SN/A            traceData->setAddr(addr);
4822SN/A        }
483
484        // @todo: Figure out a way to create a Fault from the packet result.
485        return NoFault;
486    }
487
488//    memReq->reset(addr, sizeof(T), flags);
489
490#if SIMPLE_CPU_MEM_TIMING
491    CpuRequest *data_read_req = new CpuRequest;
492#endif
493
494    data_read_req->vaddr = addr;
495    data_read_req->size = sizeof(T);
496    data_read_req->flags = flags;
497    data_read_req->time = curTick;
498
499    // translate to physical address
500    Fault fault = cpuXC->translateDataReadReq(data_read_req);
501
502    // Now do the access.
503    if (fault == NoFault) {
504#if SIMPLE_CPU_MEM_TIMING
505        data_read_pkt = new Packet;
506        data_read_pkt->cmd = Read;
507        data_read_pkt->req = data_read_req;
508        data_read_pkt->data = new uint8_t[8];
509#endif
510        data_read_pkt->addr = data_read_req->paddr;
511        data_read_pkt->size = sizeof(T);
512
513        sendDcacheRequest(data_read_pkt);
514
515#if SIMPLE_CPU_MEM_IMMEDIATE
516        // Need to find a way to not duplicate code above.
517
518        if (data_read_pkt->result == Success) {
519            memcpy(&data, data_read_pkt->data, sizeof(T));
520        }
521
522        if (traceData) {
523            traceData->setAddr(addr);
524        }
525
526        // @todo: Figure out a way to create a Fault from the packet result.
527        return NoFault;
528#endif
529    }
530/*
531        memReq->cmd = Read;
532        memReq->completionEvent = NULL;
533        memReq->time = curTick;
534        memReq->flags &= ~INST_READ;
535        MemAccessResult result = dcacheInterface->access(memReq);
536
537        // Ugly hack to get an event scheduled *only* if the access is
538        // a miss.  We really should add first-class support for this
539        // at some point.
540        if (result != MA_HIT && dcacheInterface->doEvents()) {
541            memReq->completionEvent = &cacheCompletionEvent;
542            lastDcacheStall = curTick;
543            unscheduleTickEvent();
544            _status = DcacheMissStall;
545        } else {
546            // do functional access
547            fault = cpuXC->read(memReq, data);
548
549        }
550    } else if(fault == NoFault) {
551        // do functional access
552        fault = cpuXC->read(memReq, data);
553
554    }
555*/
556    // This will need a new way to tell if it has a dcache attached.
557    if (data_read_req->flags & UNCACHEABLE)
558        recordEvent("Uncached Read");
559
560    return fault;
561}
562
563#ifndef DOXYGEN_SHOULD_SKIP_THIS
564
565template
566Fault
567SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
568
569template
570Fault
571SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
572
573template
574Fault
575SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
576
577template
578Fault
579SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
580
581#endif //DOXYGEN_SHOULD_SKIP_THIS
582
583template<>
584Fault
585SimpleCPU::read(Addr addr, double &data, unsigned flags)
586{
587    return read(addr, *(uint64_t*)&data, flags);
588}
589
590template<>
591Fault
592SimpleCPU::read(Addr addr, float &data, unsigned flags)
593{
594    return read(addr, *(uint32_t*)&data, flags);
595}
596
597
598template<>
599Fault
600SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
601{
602    return read(addr, (uint32_t&)data, flags);
603}
604
605
606template <class T>
607Fault
608SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
609{
610    data_write_req->vaddr = addr;
611    data_write_req->time = curTick;
612    data_write_req->size = sizeof(T);
613    data_write_req->flags = flags;
614
615    // translate to physical address
616    Fault fault = cpuXC->translateDataWriteReq(data_write_req);
617    // Now do the access.
618    if (fault == NoFault) {
619#if SIMPLE_CPU_MEM_TIMING
620        data_write_pkt = new Packet;
621        data_write_pkt->cmd = Write;
622        data_write_pkt->req = data_write_req;
623        data_write_pkt->data = new uint8_t[64];
624        memcpy(data_write_pkt->data, &data, sizeof(T));
625#else
626        data_write_pkt->data = (uint8_t *)&data;
627#endif
628        data_write_pkt->addr = data_write_req->paddr;
629        data_write_pkt->size = sizeof(T);
630
631        sendDcacheRequest(data_write_pkt);
632    }
633
634/*
635    // do functional access
636    if (fault == NoFault)
637        fault = cpuXC->write(memReq, data);
638
639    if (fault == NoFault && dcacheInterface) {
640        memReq->cmd = Write;
641        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
642        memReq->completionEvent = NULL;
643        memReq->time = curTick;
644        memReq->flags &= ~INST_READ;
645        MemAccessResult result = dcacheInterface->access(memReq);
646
647        // Ugly hack to get an event scheduled *only* if the access is
648        // a miss.  We really should add first-class support for this
649        // at some point.
650        if (result != MA_HIT && dcacheInterface->doEvents()) {
651            memReq->completionEvent = &cacheCompletionEvent;
652            lastDcacheStall = curTick;
653            unscheduleTickEvent();
654            _status = DcacheMissStall;
655        }
656    }
657*/
658    if (res && (fault == NoFault))
659        *res = data_write_pkt->result;
660
661    // This will need a new way to tell if it's hooked up to a cache or not.
662    if (data_write_req->flags & UNCACHEABLE)
663        recordEvent("Uncached Write");
664
665    // If the write needs to have a fault on the access, consider calling
666    // changeStatus() and changing it to "bad addr write" or something.
667    return fault;
668}
669
670
671#ifndef DOXYGEN_SHOULD_SKIP_THIS
672template
673Fault
674SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
675
676template
677Fault
678SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
679
680template
681Fault
682SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
683
684template
685Fault
686SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
687
688#endif //DOXYGEN_SHOULD_SKIP_THIS
689
690template<>
691Fault
692SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
693{
694    return write(*(uint64_t*)&data, addr, flags, res);
695}
696
697template<>
698Fault
699SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
700{
701    return write(*(uint32_t*)&data, addr, flags, res);
702}
703
704
705template<>
706Fault
707SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
708{
709    return write((uint32_t)data, addr, flags, res);
710}
711
712
713#if FULL_SYSTEM
714Addr
715SimpleCPU::dbg_vtophys(Addr addr)
716{
717    return vtophys(xcProxy, addr);
718}
719#endif // FULL_SYSTEM
720
721void
722SimpleCPU::sendIcacheRequest(Packet *pkt)
723{
724    assert(!tickEvent.scheduled());
725#if SIMPLE_CPU_MEM_TIMING
726    retry_pkt = pkt;
727    bool success = icachePort.sendTiming(*pkt);
728
729    unscheduleTickEvent();
730
731    lastIcacheStall = curTick;
732
733    if (!success) {
734        // Need to wait for retry
735        _status = IcacheRetry;
736    } else {
737        // Need to wait for cache to respond
738        _status = IcacheWaitResponse;
739    }
740#elif SIMPLE_CPU_MEM_ATOMIC
741    Tick latency = icachePort.sendAtomic(*pkt);
742
743    unscheduleTickEvent();
744    scheduleTickEvent(latency);
745
746    // Note that Icache miss cycles will be incorrect.  Unless
747    // we check the status of the packet sent (is this valid?),
748    // we won't know if the latency is a hit or a miss.
749    icacheStallCycles += latency;
750
751    _status = IcacheAccessComplete;
752#elif SIMPLE_CPU_MEM_IMMEDIATE
753    icachePort.sendAtomic(*pkt);
754#else
755#error "SimpleCPU has no mem model set"
756#endif
757}
758
759void
760SimpleCPU::sendDcacheRequest(Packet *pkt)
761{
762    assert(!tickEvent.scheduled());
763#if SIMPLE_CPU_MEM_TIMING
764    unscheduleTickEvent();
765
766    retry_pkt = pkt;
767    bool success = dcachePort.sendTiming(*pkt);
768
769    lastDcacheStall = curTick;
770
771    if (!success) {
772        _status = DcacheRetry;
773    } else {
774        _status = DcacheWaitResponse;
775    }
776#elif SIMPLE_CPU_MEM_ATOMIC
777    unscheduleTickEvent();
778
779    Tick latency = dcachePort.sendAtomic(*pkt);
780
781    scheduleTickEvent(latency);
782
783    // Note that Dcache miss cycles will be incorrect.  Unless
784    // we check the status of the packet sent (is this valid?),
785    // we won't know if the latency is a hit or a miss.
786    dcacheStallCycles += latency;
787#elif SIMPLE_CPU_MEM_IMMEDIATE
788    dcachePort.sendAtomic(*pkt);
789#else
790#error "SimpleCPU has no mem model set"
791#endif
792}
793
794void
795SimpleCPU::processResponse(Packet &response)
796{
797    assert(SIMPLE_CPU_MEM_TIMING);
798
799    // For what things is the CPU the consumer of the packet it sent
800    // out?  This may create a memory leak if that's the case and it's
801    // expected of the SimpleCPU to delete its own packet.
802    Packet *pkt = &response;
803
804    switch (status()) {
805      case IcacheWaitResponse:
806        icacheStallCycles += curTick - lastIcacheStall;
807
808        _status = IcacheAccessComplete;
809        scheduleTickEvent(1);
810
811        // Copy the icache data into the instruction itself.
812        memcpy(&inst, pkt->data, sizeof(inst));
813
814        delete pkt;
815        break;
816      case DcacheWaitResponse:
817        if (pkt->cmd == Read) {
818            curStaticInst->execute(this,traceData);
819            if (traceData)
820                traceData->finalize();
821        }
822
823        delete pkt;
824
825        dcacheStallCycles += curTick - lastDcacheStall;
826        _status = Running;
827        scheduleTickEvent(1);
828        break;
829      case DcacheWaitSwitch:
830        if (pkt->cmd == Read) {
831            curStaticInst->execute(this,traceData);
832            if (traceData)
833                traceData->finalize();
834        }
835
836        delete pkt;
837
838        _status = SwitchedOut;
839        sampler->signalSwitched();
840      case SwitchedOut:
841        // If this CPU has been switched out due to sampling/warm-up,
842        // ignore any further status changes (e.g., due to cache
843        // misses outstanding at the time of the switch).
844        delete pkt;
845
846        return;
847      default:
848        panic("SimpleCPU::processCacheCompletion: bad state");
849        break;
850    }
851}
852
853Packet *
854SimpleCPU::processRetry()
855{
856#if SIMPLE_CPU_MEM_TIMING
857    switch(status()) {
858      case IcacheRetry:
859        icacheRetryCycles += curTick - lastIcacheStall;
860        return retry_pkt;
861        break;
862      case DcacheRetry:
863        dcacheRetryCycles += curTick - lastDcacheStall;
864        return retry_pkt;
865        break;
866      default:
867        panic("SimpleCPU::processRetry: bad state");
868        break;
869    }
870#else
871    panic("shouldn't be here");
872#endif
873}
874
875#if FULL_SYSTEM
876void
877SimpleCPU::post_interrupt(int int_num, int index)
878{
879    BaseCPU::post_interrupt(int_num, index);
880
881    if (cpuXC->status() == ExecContext::Suspended) {
882                DPRINTF(IPI,"Suspended Processor awoke\n");
883        cpuXC->activate();
884    }
885}
886#endif // FULL_SYSTEM
887
888/* start simulation, program loaded, processor precise state initialized */
889void
890SimpleCPU::tick()
891{
892    numCycles++;
893
894    traceData = NULL;
895
896    Fault fault = NoFault;
897
898#if FULL_SYSTEM
899    if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode() &&
900        status() != IcacheMissComplete) {
901        int ipl = 0;
902        int summary = 0;
903        checkInterrupts = false;
904
905        if (cpuXC->readMiscReg(IPR_SIRR)) {
906            for (int i = INTLEVEL_SOFTWARE_MIN;
907                 i < INTLEVEL_SOFTWARE_MAX; i++) {
908                if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
909                    // See table 4-19 of 21164 hardware reference
910                    ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
911                    summary |= (ULL(1) << i);
912                }
913            }
914        }
915
916        uint64_t interrupts = cpuXC->cpu->intr_status();
917        for (int i = INTLEVEL_EXTERNAL_MIN;
918            i < INTLEVEL_EXTERNAL_MAX; i++) {
919            if (interrupts & (ULL(1) << i)) {
920                // See table 4-19 of 21164 hardware reference
921                ipl = i;
922                summary |= (ULL(1) << i);
923            }
924        }
925
926        if (cpuXC->readMiscReg(IPR_ASTRR))
927            panic("asynchronous traps not implemented\n");
928
929        if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) {
930            cpuXC->setMiscReg(IPR_ISR, summary);
931            cpuXC->setMiscReg(IPR_INTID, ipl);
932
933            Fault(new InterruptFault)->invoke(xcProxy);
934
935            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
936                    cpuXC->readMiscReg(IPR_IPLR), ipl, summary);
937        }
938    }
939#endif
940
941    // maintain $r0 semantics
942    cpuXC->setIntReg(ZeroReg, 0);
943#if THE_ISA == ALPHA_ISA
944    cpuXC->setFloatRegDouble(ZeroReg, 0.0);
945#endif // ALPHA_ISA
946
947    if (status() == IcacheAccessComplete) {
948        // We've already fetched an instruction and were stalled on an
949        // I-cache miss.  No need to fetch it again.
950
951        // Set status to running; tick event will get rescheduled if
952        // necessary at end of tick() function.
953        _status = Running;
954    } else {
955        // Try to fetch an instruction
956
957        // set up memory request for instruction fetch
958#if FULL_SYSTEM
959#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
960#else
961#define IFETCH_FLAGS(pc)	0
962#endif
963
964#if SIMPLE_CPU_MEM_TIMING
965        CpuRequest *ifetch_req = new CpuRequest();
966        ifetch_req->size = sizeof(MachInst);
967#endif
968
969        ifetch_req->vaddr = cpuXC->readPC() & ~3;
970        ifetch_req->time = curTick;
971
972/*	memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
973                     IFETCH_FLAGS(xc->regs.pc));
974*/
975
976        fault = cpuXC->translateInstReq(ifetch_req);
977
978        if (fault == NoFault) {
979#if SIMPLE_CPU_MEM_TIMING
980            Packet *ifetch_pkt = new Packet;
981            ifetch_pkt->cmd = Read;
982            ifetch_pkt->data = (uint8_t *)&inst;
983            ifetch_pkt->req = ifetch_req;
984            ifetch_pkt->size = sizeof(MachInst);
985#endif
986            ifetch_pkt->addr = ifetch_req->paddr;
987
988            sendIcacheRequest(ifetch_pkt);
989#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC
990            return;
991#endif
992/*
993        if (icacheInterface && fault == NoFault) {
994            memReq->completionEvent = NULL;
995
996            memReq->time = curTick;
997            memReq->flags |= INST_READ;
998            MemAccessResult result = icacheInterface->access(memReq);
999
1000            // Ugly hack to get an event scheduled *only* if the access is
1001            // a miss.  We really should add first-class support for this
1002            // at some point.
1003                if (result != MA_HIT && icacheInterface->doEvents()) {
1004                memReq->completionEvent = &cacheCompletionEvent;
1005                lastIcacheStall = curTick;
1006                unscheduleTickEvent();
1007                _status = IcacheMissStall;
1008                return;
1009            }
1010        }
1011*/
1012        }
1013    }
1014
1015    // If we've got a valid instruction (i.e., no fault on instruction
1016    // fetch), then execute it.
1017    if (fault == NoFault) {
1018
1019        // keep an instruction count
1020        numInst++;
1021        numInsts++;
1022
1023        // check for instruction-count-based events
1024        comInstEventQueue[0]->serviceEvents(numInst);
1025
1026        // decode the instruction
1027        inst = gtoh(inst);
1028        curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC()));
1029
1030        traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst,
1031                                         cpuXC->readPC());
1032
1033#if FULL_SYSTEM
1034        cpuXC->setInst(inst);
1035#endif // FULL_SYSTEM
1036
1037        cpuXC->func_exe_inst++;
1038
1039        fault = curStaticInst->execute(this, traceData);
1040
1041#if FULL_SYSTEM
1042        if (system->kernelBinning->fnbin) {
1043            assert(kernelStats);
1044            system->kernelBinning->execute(xcProxy, inst);
1045        }
1046
1047        if (cpuXC->profile) {
1048            bool usermode =
1049                (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
1050            cpuXC->profilePC = usermode ? 1 : cpuXC->readPC();
1051            ProfileNode *node = cpuXC->profile->consume(xcProxy, inst);
1052            if (node)
1053                cpuXC->profileNode = node;
1054        }
1055#endif
1056
1057        if (curStaticInst->isMemRef()) {
1058            numMemRefs++;
1059        }
1060
1061        if (curStaticInst->isLoad()) {
1062            ++numLoad;
1063            comLoadEventQueue[0]->serviceEvents(numLoad);
1064        }
1065
1066        // If we have a dcache miss, then we can't finialize the instruction
1067        // trace yet because we want to populate it with the data later
1068        if (traceData && (status() != DcacheWaitResponse)) {
1069            traceData->finalize();
1070        }
1071
1072        traceFunctions(cpuXC->readPC());
1073
1074    }	// if (fault == NoFault)
1075
1076    if (fault != NoFault) {
1077#if FULL_SYSTEM
1078        fault->invoke(xcProxy);
1079#else // !FULL_SYSTEM
1080        fatal("fault (%d) detected @ PC %08p", fault, cpuXC->readPC());
1081#endif // FULL_SYSTEM
1082    }
1083    else {
1084#if THE_ISA != MIPS_ISA
1085        // go to the next instruction
1086        cpuXC->setPC(cpuXC->readNextPC());
1087        cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
1088#else
1089        // go to the next instruction
1090        cpuXC->setPC(cpuXC->readNextPC());
1091        cpuXC->setNextPC(cpuXC->readNextNPC());
1092        cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
1093#endif
1094
1095    }
1096
1097#if FULL_SYSTEM
1098    Addr oldpc;
1099    do {
1100        oldpc = cpuXC->readPC();
1101        system->pcEventQueue.service(xcProxy);
1102    } while (oldpc != cpuXC->readPC());
1103#endif
1104
1105    assert(status() == Running ||
1106           status() == Idle ||
1107           status() == DcacheWaitResponse);
1108
1109    if (status() == Running && !tickEvent.scheduled())
1110        tickEvent.schedule(curTick + cycles(1));
1111}
1112
1113////////////////////////////////////////////////////////////////////////
1114//
1115//  SimpleCPU Simulation Object
1116//
1117BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1118
1119    Param<Counter> max_insts_any_thread;
1120    Param<Counter> max_insts_all_threads;
1121    Param<Counter> max_loads_any_thread;
1122    Param<Counter> max_loads_all_threads;
1123
1124#if FULL_SYSTEM
1125    SimObjectParam<AlphaITB *> itb;
1126    SimObjectParam<AlphaDTB *> dtb;
1127    SimObjectParam<System *> system;
1128    Param<int> cpu_id;
1129    Param<Tick> profile;
1130#else
1131    SimObjectParam<MemObject *> mem;
1132    SimObjectParam<Process *> workload;
1133#endif // FULL_SYSTEM
1134
1135    Param<int> clock;
1136
1137    Param<bool> defer_registration;
1138    Param<int> width;
1139    Param<bool> function_trace;
1140    Param<Tick> function_trace_start;
1141
1142END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1143
1144BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1145
1146    INIT_PARAM(max_insts_any_thread,
1147               "terminate when any thread reaches this inst count"),
1148    INIT_PARAM(max_insts_all_threads,
1149               "terminate when all threads have reached this inst count"),
1150    INIT_PARAM(max_loads_any_thread,
1151               "terminate when any thread reaches this load count"),
1152    INIT_PARAM(max_loads_all_threads,
1153               "terminate when all threads have reached this load count"),
1154
1155#if FULL_SYSTEM
1156    INIT_PARAM(itb, "Instruction TLB"),
1157    INIT_PARAM(dtb, "Data TLB"),
1158    INIT_PARAM(system, "system object"),
1159    INIT_PARAM(cpu_id, "processor ID"),
1160    INIT_PARAM(profile, ""),
1161#else
1162    INIT_PARAM(mem, "memory"),
1163    INIT_PARAM(workload, "processes to run"),
1164#endif // FULL_SYSTEM
1165
1166    INIT_PARAM(clock, "clock speed"),
1167    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
1168    INIT_PARAM(width, "cpu width"),
1169    INIT_PARAM(function_trace, "Enable function trace"),
1170    INIT_PARAM(function_trace_start, "Cycle to start function trace")
1171
1172END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1173
1174
1175CREATE_SIM_OBJECT(SimpleCPU)
1176{
1177    SimpleCPU::Params *params = new SimpleCPU::Params();
1178    params->name = getInstanceName();
1179    params->numberOfThreads = 1;
1180    params->max_insts_any_thread = max_insts_any_thread;
1181    params->max_insts_all_threads = max_insts_all_threads;
1182    params->max_loads_any_thread = max_loads_any_thread;
1183    params->max_loads_all_threads = max_loads_all_threads;
1184    params->deferRegistration = defer_registration;
1185    params->clock = clock;
1186    params->functionTrace = function_trace;
1187    params->functionTraceStart = function_trace_start;
1188    params->width = width;
1189
1190#if FULL_SYSTEM
1191    params->itb = itb;
1192    params->dtb = dtb;
1193    params->system = system;
1194    params->cpu_id = cpu_id;
1195    params->profile = profile;
1196#else
1197    params->mem = mem;
1198    params->process = workload;
1199#endif
1200
1201    SimpleCPU *cpu = new SimpleCPU(params);
1202    return cpu;
1203}
1204
1205REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
1206
1207