base.cc revision 595
12968SN/A/*
22968SN/A * Copyright (c) 2003 The Regents of The University of Michigan
35520SN/A * All rights reserved.
45520SN/A *
58721SN/A * Redistribution and use in source and binary forms, with or without
68721SN/A * modification, are permitted provided that the following conditions are
78983Snate@binkert.org * met: redistributions of source code must retain the above copyright
88983Snate@binkert.org * notice, this list of conditions and the following disclaimer;
98983Snate@binkert.org * redistributions in binary form must reproduce the above copyright
108983Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
118983Snate@binkert.org * documentation and/or other materials provided with the distribution;
128721SN/A * neither the name of the copyright holders nor the names of its
138835SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
148721SN/A * this software without specific prior written permission.
158721SN/A *
168721SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
178721SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188721SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
198721SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
208721SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218721SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
228721SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238721SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248721SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258721SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268721SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278721SN/A */
288721SN/A
298721SN/A#include <cmath>
308835SAli.Saidi@ARM.com#include <cstdio>
318835SAli.Saidi@ARM.com#include <cstdlib>
328835SAli.Saidi@ARM.com#include <iostream>
338835SAli.Saidi@ARM.com#include <iomanip>
348835SAli.Saidi@ARM.com#include <list>
358835SAli.Saidi@ARM.com#include <sstream>
368835SAli.Saidi@ARM.com#include <string>
378835SAli.Saidi@ARM.com
388835SAli.Saidi@ARM.com#include "base/cprintf.hh"
398835SAli.Saidi@ARM.com#include "base/inifile.hh"
408835SAli.Saidi@ARM.com#include "base/loader/symtab.hh"
418835SAli.Saidi@ARM.com#include "base/misc.hh"
428835SAli.Saidi@ARM.com#include "base/pollevent.hh"
438835SAli.Saidi@ARM.com#include "base/range.hh"
448835SAli.Saidi@ARM.com#include "base/trace.hh"
458721SN/A#include "cpu/base_cpu.hh"
468835SAli.Saidi@ARM.com#include "cpu/exec_context.hh"
478721SN/A#include "cpu/exetrace.hh"
488835SAli.Saidi@ARM.com#include "cpu/full_cpu/smt.hh"
498835SAli.Saidi@ARM.com#include "cpu/simple_cpu/simple_cpu.hh"
508721SN/A#include "cpu/static_inst.hh"
518835SAli.Saidi@ARM.com#include "mem/base_mem.hh"
528835SAli.Saidi@ARM.com#include "mem/mem_interface.hh"
538721SN/A#include "sim/annotation.hh"
548835SAli.Saidi@ARM.com#include "sim/builder.hh"
558835SAli.Saidi@ARM.com#include "sim/debug.hh"
568721SN/A#include "sim/host.hh"
578835SAli.Saidi@ARM.com#include "sim/sim_events.hh"
588835SAli.Saidi@ARM.com#include "sim/sim_object.hh"
598835SAli.Saidi@ARM.com#include "sim/sim_stats.hh"
608835SAli.Saidi@ARM.com
618721SN/A#ifdef FULL_SYSTEM
628835SAli.Saidi@ARM.com#include "base/remote_gdb.hh"
638835SAli.Saidi@ARM.com#include "dev/alpha_access.h"
648835SAli.Saidi@ARM.com#include "dev/pciareg.h"
658835SAli.Saidi@ARM.com#include "mem/functional_mem/memory_control.hh"
668721SN/A#include "mem/functional_mem/physical_memory.hh"
678835SAli.Saidi@ARM.com#include "sim/system.hh"
688835SAli.Saidi@ARM.com#include "targetarch/alpha_memory.hh"
698835SAli.Saidi@ARM.com#include "targetarch/vtophys.hh"
708835SAli.Saidi@ARM.com#else // !FULL_SYSTEM
718721SN/A#include "eio/eio.hh"
728835SAli.Saidi@ARM.com#include "mem/functional_mem/functional_memory.hh"
738835SAli.Saidi@ARM.com#endif // FULL_SYSTEM
748721SN/A
758835SAli.Saidi@ARM.comusing namespace std;
768835SAli.Saidi@ARM.com
778721SN/ASimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
788835SAli.Saidi@ARM.com    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
798835SAli.Saidi@ARM.com{
808721SN/A}
818835SAli.Saidi@ARM.com
828835SAli.Saidi@ARM.comvoid
838835SAli.Saidi@ARM.comSimpleCPU::TickEvent::process()
848835SAli.Saidi@ARM.com{
858721SN/A    cpu->tick();
868835SAli.Saidi@ARM.com}
878835SAli.Saidi@ARM.com
888835SAli.Saidi@ARM.comconst char *
898835SAli.Saidi@ARM.comSimpleCPU::TickEvent::description()
908721SN/A{
918835SAli.Saidi@ARM.com    return "SimpleCPU tick event";
928835SAli.Saidi@ARM.com}
938835SAli.Saidi@ARM.com
948835SAli.Saidi@ARM.com
958721SN/ASimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
968835SAli.Saidi@ARM.com    : Event(&mainEventQueue),
978721SN/A      cpu(_cpu)
988835SAli.Saidi@ARM.com{
998835SAli.Saidi@ARM.com}
1008721SN/A
1018835SAli.Saidi@ARM.comvoid SimpleCPU::CacheCompletionEvent::process()
1028835SAli.Saidi@ARM.com{
1038721SN/A    cpu->processCacheCompletion();
1048835SAli.Saidi@ARM.com}
1058835SAli.Saidi@ARM.com
1068721SN/Aconst char *
1078835SAli.Saidi@ARM.comSimpleCPU::CacheCompletionEvent::description()
1088835SAli.Saidi@ARM.com{
1098835SAli.Saidi@ARM.com    return "SimpleCPU cache completion event";
1108835SAli.Saidi@ARM.com}
1118721SN/A
1128835SAli.Saidi@ARM.com#ifdef FULL_SYSTEM
1138835SAli.Saidi@ARM.comSimpleCPU::SimpleCPU(const string &_name,
1148835SAli.Saidi@ARM.com                     System *_system,
1158835SAli.Saidi@ARM.com                     Counter max_insts_any_thread,
1168721SN/A                     Counter max_insts_all_threads,
1178835SAli.Saidi@ARM.com                     Counter max_loads_any_thread,
1188835SAli.Saidi@ARM.com                     Counter max_loads_all_threads,
1198835SAli.Saidi@ARM.com                     AlphaItb *itb, AlphaDtb *dtb,
1208835SAli.Saidi@ARM.com                     FunctionalMemory *mem,
1218835SAli.Saidi@ARM.com                     MemInterface *icache_interface,
1228835SAli.Saidi@ARM.com                     MemInterface *dcache_interface,
1238835SAli.Saidi@ARM.com                     bool _def_reg, Tick freq)
1248835SAli.Saidi@ARM.com    : BaseCPU(_name, /* number_of_threads */ 1,
1258835SAli.Saidi@ARM.com              max_insts_any_thread, max_insts_all_threads,
1268835SAli.Saidi@ARM.com              max_loads_any_thread, max_loads_all_threads,
1278835SAli.Saidi@ARM.com              _system, freq),
1288835SAli.Saidi@ARM.com#else
1298835SAli.Saidi@ARM.comSimpleCPU::SimpleCPU(const string &_name, Process *_process,
1308835SAli.Saidi@ARM.com                     Counter max_insts_any_thread,
1318835SAli.Saidi@ARM.com                     Counter max_insts_all_threads,
1328835SAli.Saidi@ARM.com                     Counter max_loads_any_thread,
1338835SAli.Saidi@ARM.com                     Counter max_loads_all_threads,
1348835SAli.Saidi@ARM.com                     MemInterface *icache_interface,
1358721SN/A                     MemInterface *dcache_interface,
1368721SN/A                     bool _def_reg)
1378721SN/A    : BaseCPU(_name, /* number_of_threads */ 1,
1388721SN/A              max_insts_any_thread, max_insts_all_threads,
1398983Snate@binkert.org              max_loads_any_thread, max_loads_all_threads),
1408983Snate@binkert.org#endif
1418721SN/A      tickEvent(this), xc(NULL), defer_registration(_def_reg),
1428721SN/A      cacheCompletionEvent(this)
1438835SAli.Saidi@ARM.com{
1448835SAli.Saidi@ARM.com    _status = Idle;
1458721SN/A#ifdef FULL_SYSTEM
1468721SN/A    xc = new ExecContext(this, 0, system, itb, dtb, mem);
1478721SN/A
1488721SN/A    // initialize CPU, including PC
1498721SN/A    TheISA::initCPU(&xc->regs);
1508721SN/A#else
1518721SN/A    xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
1528835SAli.Saidi@ARM.com#endif // !FULL_SYSTEM
1538835SAli.Saidi@ARM.com
1548835SAli.Saidi@ARM.com    icacheInterface = icache_interface;
1558835SAli.Saidi@ARM.com    dcacheInterface = dcache_interface;
1568721SN/A
1578835SAli.Saidi@ARM.com    memReq = new MemReq();
1588721SN/A    memReq->xc = xc;
1598835SAli.Saidi@ARM.com    memReq->asid = 0;
1608721SN/A    memReq->data = new uint8_t[64];
1618835SAli.Saidi@ARM.com
1628721SN/A    numInst = 0;
1638835SAli.Saidi@ARM.com    startNumInst = 0;
1648721SN/A    numLoad = 0;
1658835SAli.Saidi@ARM.com    startNumLoad = 0;
1668721SN/A    lastIcacheStall = 0;
1678835SAli.Saidi@ARM.com    lastDcacheStall = 0;
1688721SN/A
1698835SAli.Saidi@ARM.com    execContexts.push_back(xc);
1708721SN/A}
1718835SAli.Saidi@ARM.com
1728835SAli.Saidi@ARM.comSimpleCPU::~SimpleCPU()
1738835SAli.Saidi@ARM.com{
1748835SAli.Saidi@ARM.com}
1758721SN/A
1768721SN/Avoid SimpleCPU::init()
1778721SN/A{
1788721SN/A    if (!defer_registration) {
1798983Snate@binkert.org        this->registerExecContexts();
1808983Snate@binkert.org    }
1818721SN/A}
1828721SN/A
1838835SAli.Saidi@ARM.comvoid
1848835SAli.Saidi@ARM.comSimpleCPU::switchOut()
1858721SN/A{
1868721SN/A    _status = SwitchedOut;
1878721SN/A    if (tickEvent.scheduled())
1888721SN/A        tickEvent.squash();
1898721SN/A}
1908721SN/A
1918721SN/A
1928721SN/Avoid
1938721SN/ASimpleCPU::takeOverFrom(BaseCPU *oldCPU)
1948721SN/A{
1958721SN/A    BaseCPU::takeOverFrom(oldCPU);
1968721SN/A
1978721SN/A    assert(!tickEvent.scheduled());
1988721SN/A
1998721SN/A    // if any of this CPU's ExecContexts are active, mark the CPU as
2008721SN/A    // running and schedule its tick event.
2018721SN/A    for (int i = 0; i < execContexts.size(); ++i) {
2028721SN/A        ExecContext *xc = execContexts[i];
2038721SN/A        if (xc->status() == ExecContext::Active && _status != Running) {
2048721SN/A            _status = Running;
2058721SN/A            tickEvent.schedule(curTick);
2068721SN/A        }
2078721SN/A    }
2088721SN/A
2098721SN/A    oldCPU->switchOut();
2106024SN/A}
2116024SN/A
2128721SN/A
2138721SN/Avoid
2148721SN/ASimpleCPU::activateContext(int thread_num, int delay)
2158721SN/A{
2168721SN/A    assert(thread_num == 0);
2178721SN/A    assert(xc);
2188721SN/A
2198721SN/A    assert(_status == Idle);
2208721SN/A    notIdleFraction++;
2218721SN/A    scheduleTickEvent(delay);
2228721SN/A    _status = Running;
2238721SN/A}
2248721SN/A
2258721SN/A
2266024SN/Avoid
2276024SN/ASimpleCPU::suspendContext(int thread_num)
2288721SN/A{
2298721SN/A    assert(thread_num == 0);
2308721SN/A    assert(xc);
2318721SN/A
2328721SN/A    assert(_status == Running);
2338835SAli.Saidi@ARM.com    notIdleFraction--;
2348835SAli.Saidi@ARM.com    unscheduleTickEvent();
2358721SN/A    _status = Idle;
2368721SN/A}
2378721SN/A
2388721SN/A
2398721SN/Avoid
2408721SN/ASimpleCPU::deallocateContext(int thread_num)
2418721SN/A{
2428721SN/A    // for now, these are equivalent
2438721SN/A    suspendContext(thread_num);
2448721SN/A}
2458721SN/A
2468721SN/A
2478721SN/Avoid
2488721SN/ASimpleCPU::haltContext(int thread_num)
2498721SN/A{
2508721SN/A    // for now, these are equivalent
2518721SN/A    suspendContext(thread_num);
2522968SN/A}
2538721SN/A
2545778SN/A
2556291SN/Avoid
2566291SN/ASimpleCPU::regStats()
2576291SN/A{
2586291SN/A    using namespace Statistics;
2596291SN/A
2606127SN/A    BaseCPU::regStats();
2616291SN/A
2626291SN/A    numInsts
2636291SN/A        .name(name() + ".num_insts")
2646291SN/A        .desc("Number of instructions executed")
2656291SN/A        ;
2666127SN/A
2676291SN/A    numMemRefs
2686291SN/A        .name(name() + ".num_refs")
2696291SN/A        .desc("Number of memory references")
2706291SN/A        ;
2716291SN/A
2726127SN/A    idleFraction
2736127SN/A        .name(name() + ".idle_fraction")
2746127SN/A        .desc("Percentage of idle cycles")
2756127SN/A        ;
2766127SN/A
2776127SN/A    icacheStallCycles
2786291SN/A        .name(name() + ".icache_stall_cycles")
2796291SN/A        .desc("ICache total stall cycles")
2806291SN/A        .prereq(icacheStallCycles)
2816291SN/A        ;
2826291SN/A
2836291SN/A    dcacheStallCycles
2846291SN/A        .name(name() + ".dcache_stall_cycles")
2856291SN/A        .desc("DCache total stall cycles")
2866291SN/A        .prereq(dcacheStallCycles)
2876291SN/A        ;
2886291SN/A
2896291SN/A    idleFraction = constant(1.0) - notIdleFraction;
2906291SN/A    numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst);
2916291SN/A    simInsts += numInsts;
2926291SN/A}
2936291SN/A
2946291SN/Avoid
2956291SN/ASimpleCPU::resetStats()
2966291SN/A{
2976291SN/A    startNumInst = numInst;
2986291SN/A    notIdleFraction = (_status != Idle);
2996291SN/A}
3006291SN/A
3016291SN/Avoid
3026291SN/ASimpleCPU::serialize(ostream &os)
3036291SN/A{
3046291SN/A    SERIALIZE_ENUM(_status);
3056291SN/A    SERIALIZE_SCALAR(inst);
3066291SN/A    nameOut(os, csprintf("%s.xc", name()));
3076291SN/A    xc->serialize(os);
3086127SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
3098721SN/A    tickEvent.serialize(os);
3108721SN/A    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
3118721SN/A    cacheCompletionEvent.serialize(os);
3128721SN/A}
3138721SN/A
3148721SN/Avoid
3158721SN/ASimpleCPU::unserialize(Checkpoint *cp, const string &section)
3168721SN/A{
3178721SN/A    UNSERIALIZE_ENUM(_status);
3188721SN/A    UNSERIALIZE_SCALAR(inst);
3198721SN/A    xc->unserialize(cp, csprintf("%s.xc", section));
3208721SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
3218721SN/A    cacheCompletionEvent
3228721SN/A        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
3238721SN/A}
3248721SN/A
3258721SN/Avoid
3268721SN/Achange_thread_state(int thread_number, int activate, int priority)
3278721SN/A{
3288721SN/A}
3298721SN/A
3308721SN/AFault
3318721SN/ASimpleCPU::copySrcTranslate(Addr src)
3328721SN/A{
3338721SN/A    memReq->reset(src, (dcacheInterface) ?
3348721SN/A                  dcacheInterface->getBlockSize()
3358983Snate@binkert.org                  : 64);
3368983Snate@binkert.org
3378721SN/A    // translate to physical address
3388721SN/A    Fault fault = xc->translateDataReadReq(memReq);
3398721SN/A
3408721SN/A    if (fault == No_Fault) {
3418721SN/A        xc->copySrcAddr = src;
3428721SN/A        xc->copySrcPhysAddr = memReq->paddr;
3438721SN/A    } else {
3448721SN/A        xc->copySrcAddr = 0;
3458721SN/A        xc->copySrcPhysAddr = 0;
3468983Snate@binkert.org    }
3478721SN/A    return fault;
3488721SN/A}
3498983Snate@binkert.org
3508721SN/AFault
3518721SN/ASimpleCPU::copy(Addr dest)
3528983Snate@binkert.org{
3538721SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
3548721SN/A    uint8_t data[blk_size];
3558983Snate@binkert.org    assert(xc->copySrcPhysAddr);
3568721SN/A    memReq->reset(dest, blk_size);
3578721SN/A    // translate to physical address
3588983Snate@binkert.org    Fault fault = xc->translateDataWriteReq(memReq);
3598721SN/A    if (fault == No_Fault) {
3608721SN/A        Addr dest_addr = memReq->paddr;
3618983Snate@binkert.org        // Need to read straight from memory since we have more than 8 bytes.
3628721SN/A        memReq->paddr = xc->copySrcPhysAddr;
3638721SN/A        xc->mem->read(memReq, data);
3648983Snate@binkert.org        memReq->paddr = dest_addr;
3658721SN/A        xc->mem->write(memReq, data);
3668721SN/A    }
3678983Snate@binkert.org    return fault;
3688721SN/A}
3698983Snate@binkert.org
3708721SN/A// precise architected memory state accessor macros
3718721SN/Atemplate <class T>
3728721SN/AFault
3738721SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags)
3748721SN/A{
3758721SN/A    memReq->reset(addr, sizeof(T), flags);
3768721SN/A
3778721SN/A    // translate to physical address
3788835SAli.Saidi@ARM.com    Fault fault = xc->translateDataReadReq(memReq);
3798835SAli.Saidi@ARM.com
3808835SAli.Saidi@ARM.com    // do functional access
3818835SAli.Saidi@ARM.com    if (fault == No_Fault)
3828721SN/A        fault = xc->read(memReq, data);
3838835SAli.Saidi@ARM.com
3848721SN/A    if (traceData) {
3858835SAli.Saidi@ARM.com        traceData->setAddr(addr);
3868721SN/A        if (fault == No_Fault)
3878835SAli.Saidi@ARM.com            traceData->setData(data);
3888721SN/A    }
3898835SAli.Saidi@ARM.com
3908721SN/A    // if we have a cache, do cache access too
3918835SAli.Saidi@ARM.com    if (fault == No_Fault && dcacheInterface) {
3928721SN/A        memReq->cmd = Read;
3938835SAli.Saidi@ARM.com        memReq->completionEvent = NULL;
3948721SN/A        memReq->time = curTick;
3958835SAli.Saidi@ARM.com        MemAccessResult result = dcacheInterface->access(memReq);
3968721SN/A
3978835SAli.Saidi@ARM.com        // Ugly hack to get an event scheduled *only* if the access is
3988721SN/A        // a miss.  We really should add first-class support for this
3998835SAli.Saidi@ARM.com        // at some point.
4008835SAli.Saidi@ARM.com        if (result != MA_HIT && dcacheInterface->doEvents()) {
4018835SAli.Saidi@ARM.com            memReq->completionEvent = &cacheCompletionEvent;
4028721SN/A            lastDcacheStall = curTick;
4038721SN/A            unscheduleTickEvent();
4048721SN/A            _status = DcacheMissStall;
4058721SN/A        }
4068983Snate@binkert.org    }
4078983Snate@binkert.org
4088721SN/A    return fault;
4098721SN/A}
4108835SAli.Saidi@ARM.com
4118835SAli.Saidi@ARM.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
4128721SN/A
4138721SN/Atemplate
4148721SN/AFault
4158721SN/ASimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
4168721SN/A
4178721SN/Atemplate
4188721SN/AFault
4198835SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
4208835SAli.Saidi@ARM.com
4218835SAli.Saidi@ARM.comtemplate
4228835SAli.Saidi@ARM.comFault
4238721SN/ASimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
4248835SAli.Saidi@ARM.com
4258721SN/Atemplate
4268835SAli.Saidi@ARM.comFault
4278721SN/ASimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
4288835SAli.Saidi@ARM.com
4298721SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
4308835SAli.Saidi@ARM.com
4318721SN/Atemplate<>
4328835SAli.Saidi@ARM.comFault
4338721SN/ASimpleCPU::read(Addr addr, double &data, unsigned flags)
4348835SAli.Saidi@ARM.com{
4358721SN/A    return read(addr, *(uint64_t*)&data, flags);
4368835SAli.Saidi@ARM.com}
4378721SN/A
4388835SAli.Saidi@ARM.comtemplate<>
4398721SN/AFault
4408835SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, float &data, unsigned flags)
4418721SN/A{
4428835SAli.Saidi@ARM.com    return read(addr, *(uint32_t*)&data, flags);
4438721SN/A}
4448835SAli.Saidi@ARM.com
4458721SN/A
4468835SAli.Saidi@ARM.comtemplate<>
4478721SN/AFault
4488835SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
4498721SN/A{
4508835SAli.Saidi@ARM.com    return read(addr, (uint32_t&)data, flags);
4518721SN/A}
4528835SAli.Saidi@ARM.com
4538721SN/A
4548835SAli.Saidi@ARM.comtemplate <class T>
4558721SN/AFault
4568835SAli.Saidi@ARM.comSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
4578721SN/A{
4588835SAli.Saidi@ARM.com    if (traceData) {
4598835SAli.Saidi@ARM.com        traceData->setAddr(addr);
4608835SAli.Saidi@ARM.com        traceData->setData(data);
4618835SAli.Saidi@ARM.com    }
4628835SAli.Saidi@ARM.com
4638835SAli.Saidi@ARM.com    memReq->reset(addr, sizeof(T), flags);
4648721SN/A
4658721SN/A    // translate to physical address
4668721SN/A    Fault fault = xc->translateDataWriteReq(memReq);
4678721SN/A
4688983Snate@binkert.org    // do functional access
4698983Snate@binkert.org    if (fault == No_Fault)
4708721SN/A        fault = xc->write(memReq, data);
4718721SN/A
4728835SAli.Saidi@ARM.com    if (fault == No_Fault && dcacheInterface) {
4738835SAli.Saidi@ARM.com        memReq->cmd = Write;
4748721SN/A        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
4758721SN/A        memReq->completionEvent = NULL;
4768721SN/A        memReq->time = curTick;
4778721SN/A        MemAccessResult result = dcacheInterface->access(memReq);
4788721SN/A
4798721SN/A        // Ugly hack to get an event scheduled *only* if the access is
4808721SN/A        // a miss.  We really should add first-class support for this
4818721SN/A        // at some point.
4828721SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
4838721SN/A            memReq->completionEvent = &cacheCompletionEvent;
4848721SN/A            lastDcacheStall = curTick;
4858721SN/A            unscheduleTickEvent();
4868721SN/A            _status = DcacheMissStall;
4876024SN/A        }
4886024SN/A    }
4898721SN/A
4908721SN/A    if (res && (fault == No_Fault))
4918721SN/A        *res = memReq->result;
4928721SN/A
4938721SN/A    return fault;
4948721SN/A}
4958721SN/A
4968721SN/A
4978721SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
4988721SN/Atemplate
4998721SN/AFault
5008721SN/ASimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
5018721SN/A
5028721SN/Atemplate
5036024SN/AFault
5046024SN/ASimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
5058721SN/A
5068721SN/Atemplate
5078721SN/AFault
5088721SN/ASimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
5098721SN/A
5108835SAli.Saidi@ARM.comtemplate
5118835SAli.Saidi@ARM.comFault
5128721SN/ASimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
5138721SN/A
5148721SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
5158721SN/A
5168721SN/Atemplate<>
5178721SN/AFault
5188721SN/ASimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
5198721SN/A{
5208721SN/A    return write(*(uint64_t*)&data, addr, flags, res);
5218721SN/A}
5228721SN/A
5238721SN/Atemplate<>
5248721SN/AFault
5258721SN/ASimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
5268721SN/A{
5278721SN/A    return write(*(uint32_t*)&data, addr, flags, res);
5288721SN/A}
5292968SN/A
5308721SN/A
5314463SN/Atemplate<>
5326291SN/AFault
5336291SN/ASimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
5346291SN/A{
5356291SN/A    return write((uint32_t)data, addr, flags, res);
5366127SN/A}
5376291SN/A
5386291SN/A
5396291SN/A#ifdef FULL_SYSTEM
5406291SN/AAddr
5416127SN/ASimpleCPU::dbg_vtophys(Addr addr)
5426291SN/A{
5436291SN/A    return vtophys(xc, addr);
5446291SN/A}
5456291SN/A#endif // FULL_SYSTEM
5466127SN/A
5476127SN/ATick save_cycle = 0;
5486127SN/A
5496127SN/A
5506127SN/Avoid
5516291SN/ASimpleCPU::processCacheCompletion()
5526291SN/A{
5536291SN/A    switch (status()) {
5546291SN/A      case IcacheMissStall:
5556291SN/A        icacheStallCycles += curTick - lastIcacheStall;
5566291SN/A        _status = IcacheMissComplete;
5576291SN/A        scheduleTickEvent(1);
5586291SN/A        break;
5596291SN/A      case DcacheMissStall:
5606291SN/A        dcacheStallCycles += curTick - lastDcacheStall;
5616291SN/A        _status = Running;
5626291SN/A        scheduleTickEvent(1);
5636291SN/A        break;
5646291SN/A      case SwitchedOut:
5656291SN/A        // If this CPU has been switched out due to sampling/warm-up,
5666291SN/A        // ignore any further status changes (e.g., due to cache
5676291SN/A        // misses outstanding at the time of the switch).
5686127SN/A        return;
5698721SN/A      default:
5708721SN/A        panic("SimpleCPU::processCacheCompletion: bad state");
5718721SN/A        break;
5728721SN/A    }
5738721SN/A}
5748721SN/A
5758721SN/A#ifdef FULL_SYSTEM
5768721SN/Avoid
5778721SN/ASimpleCPU::post_interrupt(int int_num, int index)
5788721SN/A{
5798721SN/A    BaseCPU::post_interrupt(int_num, index);
5808721SN/A
5818721SN/A    if (xc->status() == ExecContext::Suspended) {
5828721SN/A                DPRINTF(IPI,"Suspended Processor awoke\n");
5838721SN/A        xc->activate();
5848721SN/A        Annotate::Resume(xc);
5858721SN/A    }
5868721SN/A}
5878721SN/A#endif // FULL_SYSTEM
5888721SN/A
5898721SN/A/* start simulation, program loaded, processor precise state initialized */
5908721SN/Avoid
5918721SN/ASimpleCPU::tick()
5928721SN/A{
5938721SN/A    traceData = NULL;
5948721SN/A
5958721SN/A    Fault fault = No_Fault;
5968721SN/A
5978721SN/A#ifdef FULL_SYSTEM
5988721SN/A    if (AlphaISA::check_interrupts &&
5998721SN/A        xc->cpu->check_interrupts() &&
6008721SN/A        !PC_PAL(xc->regs.pc) &&
6018721SN/A        status() != IcacheMissComplete) {
6028721SN/A        int ipl = 0;
6038721SN/A        int summary = 0;
6048721SN/A        AlphaISA::check_interrupts = 0;
6058721SN/A        IntReg *ipr = xc->regs.ipr;
6068721SN/A
6078835SAli.Saidi@ARM.com        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
6088835SAli.Saidi@ARM.com            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
6098835SAli.Saidi@ARM.com                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
6108835SAli.Saidi@ARM.com                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
6118721SN/A                    // See table 4-19 of 21164 hardware reference
6128835SAli.Saidi@ARM.com                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
6138721SN/A                    summary |= (ULL(1) << i);
6148835SAli.Saidi@ARM.com                }
6158721SN/A            }
6168835SAli.Saidi@ARM.com        }
6178721SN/A
6188835SAli.Saidi@ARM.com        uint64_t interrupts = xc->cpu->intr_status();
6198721SN/A        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
6208835SAli.Saidi@ARM.com            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
6218721SN/A            if (interrupts & (ULL(1) << i)) {
6228835SAli.Saidi@ARM.com                // See table 4-19 of 21164 hardware reference
6238721SN/A                ipl = i;
6248835SAli.Saidi@ARM.com                summary |= (ULL(1) << i);
6258721SN/A            }
6268835SAli.Saidi@ARM.com        }
6278721SN/A
6288835SAli.Saidi@ARM.com        if (ipr[TheISA::IPR_ASTRR])
6298835SAli.Saidi@ARM.com            panic("asynchronous traps not implemented\n");
6308835SAli.Saidi@ARM.com
6318721SN/A        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
6328721SN/A            ipr[TheISA::IPR_ISR] = summary;
6338721SN/A            ipr[TheISA::IPR_INTID] = ipl;
6348721SN/A            xc->ev5_trap(Interrupt_Fault);
6358983Snate@binkert.org
6368983Snate@binkert.org            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
6378721SN/A                    ipr[TheISA::IPR_IPLR], ipl, summary);
6388721SN/A        }
6398835SAli.Saidi@ARM.com    }
6408835SAli.Saidi@ARM.com#endif
6418721SN/A
6428721SN/A    // maintain $r0 semantics
6438721SN/A    xc->regs.intRegFile[ZeroReg] = 0;
6448721SN/A#ifdef TARGET_ALPHA
6458721SN/A    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
6468721SN/A#endif // TARGET_ALPHA
6478721SN/A
6488835SAli.Saidi@ARM.com    if (status() == IcacheMissComplete) {
6498835SAli.Saidi@ARM.com        // We've already fetched an instruction and were stalled on an
6508835SAli.Saidi@ARM.com        // I-cache miss.  No need to fetch it again.
6518835SAli.Saidi@ARM.com
6528721SN/A        // Set status to running; tick event will get rescheduled if
6538835SAli.Saidi@ARM.com        // necessary at end of tick() function.
6548721SN/A        _status = Running;
6558835SAli.Saidi@ARM.com    }
6568721SN/A    else {
6578835SAli.Saidi@ARM.com        // Try to fetch an instruction
6588721SN/A
6598835SAli.Saidi@ARM.com        // set up memory request for instruction fetch
6608721SN/A#ifdef FULL_SYSTEM
6618835SAli.Saidi@ARM.com#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
6628721SN/A#else
6638835SAli.Saidi@ARM.com#define IFETCH_FLAGS(pc)	0
6648721SN/A#endif
6658835SAli.Saidi@ARM.com
6668721SN/A        memReq->cmd = Read;
6678835SAli.Saidi@ARM.com        memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
6688721SN/A                     IFETCH_FLAGS(xc->regs.pc));
6698835SAli.Saidi@ARM.com
6708721SN/A        fault = xc->translateInstReq(memReq);
6718835SAli.Saidi@ARM.com
6728721SN/A        if (fault == No_Fault)
6738835SAli.Saidi@ARM.com            fault = xc->mem->read(memReq, inst);
6748721SN/A
6758835SAli.Saidi@ARM.com        if (icacheInterface && fault == No_Fault) {
6768721SN/A            memReq->completionEvent = NULL;
6778835SAli.Saidi@ARM.com
6788721SN/A            memReq->time = curTick;
6798835SAli.Saidi@ARM.com            MemAccessResult result = icacheInterface->access(memReq);
6808721SN/A
6818835SAli.Saidi@ARM.com            // Ugly hack to get an event scheduled *only* if the access is
6828721SN/A            // a miss.  We really should add first-class support for this
6838835SAli.Saidi@ARM.com            // at some point.
6848721SN/A            if (result != MA_HIT && icacheInterface->doEvents()) {
6858835SAli.Saidi@ARM.com                memReq->completionEvent = &cacheCompletionEvent;
6868721SN/A                lastIcacheStall = curTick;
6878835SAli.Saidi@ARM.com                unscheduleTickEvent();
6888835SAli.Saidi@ARM.com                _status = IcacheMissStall;
6898835SAli.Saidi@ARM.com                return;
6908835SAli.Saidi@ARM.com            }
6918835SAli.Saidi@ARM.com        }
6928835SAli.Saidi@ARM.com    }
6938721SN/A
6948721SN/A    // If we've got a valid instruction (i.e., no fault on instruction
6958721SN/A    // fetch), then execute it.
6968721SN/A    if (fault == No_Fault) {
6978983Snate@binkert.org
6988983Snate@binkert.org        // keep an instruction count
6998721SN/A        numInst++;
7008721SN/A
7018835SAli.Saidi@ARM.com        // check for instruction-count-based events
7028835SAli.Saidi@ARM.com        comInstEventQueue[0]->serviceEvents(numInst);
7038721SN/A
7042968SN/A        // decode the instruction
7052968SN/A        StaticInstPtr<TheISA> si(inst);
706
707        traceData = Trace::getInstRecord(curTick, xc, this, si,
708                                         xc->regs.pc);
709
710#ifdef FULL_SYSTEM
711        xc->regs.opcode = (inst >> 26) & 0x3f;
712        xc->regs.ra = (inst >> 21) & 0x1f;
713#endif // FULL_SYSTEM
714
715        xc->func_exe_inst++;
716
717        fault = si->execute(this, xc, traceData);
718#ifdef FS_MEASURE
719        if (!(xc->misspeculating()) && (xc->system->bin)) {
720            SWContext *ctx = xc->swCtx;
721            if (ctx && !ctx->callStack.empty()) {
722                if (si->isCall()) {
723                    ctx->calls++;
724                }
725                if (si->isReturn()) {
726                     if (ctx->calls == 0) {
727                        fnCall *top = ctx->callStack.top();
728                        DPRINTF(TCPIP, "Removing %s from callstack.\n", top->name);
729                        delete top;
730                        ctx->callStack.pop();
731                        if (ctx->callStack.empty())
732                            xc->system->nonPath->activate();
733                        else
734                            ctx->callStack.top()->myBin->activate();
735
736                        xc->system->dumpState(xc);
737                    } else {
738                        ctx->calls--;
739                    }
740                }
741            }
742        }
743#endif
744        if (si->isMemRef()) {
745            numMemRefs++;
746        }
747
748        if (si->isLoad()) {
749            ++numLoad;
750            comLoadEventQueue[0]->serviceEvents(numLoad);
751        }
752
753        if (traceData)
754            traceData->finalize();
755
756    }	// if (fault == No_Fault)
757
758    if (fault != No_Fault) {
759#ifdef FULL_SYSTEM
760        xc->ev5_trap(fault);
761#else // !FULL_SYSTEM
762        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
763#endif // FULL_SYSTEM
764    }
765    else {
766        // go to the next instruction
767        xc->regs.pc = xc->regs.npc;
768        xc->regs.npc += sizeof(MachInst);
769    }
770
771#ifdef FULL_SYSTEM
772    Addr oldpc;
773    do {
774        oldpc = xc->regs.pc;
775        system->pcEventQueue.service(xc);
776    } while (oldpc != xc->regs.pc);
777#endif
778
779    assert(status() == Running ||
780           status() == Idle ||
781           status() == DcacheMissStall);
782
783    if (status() == Running && !tickEvent.scheduled())
784        tickEvent.schedule(curTick + 1);
785}
786
787
788////////////////////////////////////////////////////////////////////////
789//
790//  SimpleCPU Simulation Object
791//
792BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
793
794    Param<Counter> max_insts_any_thread;
795    Param<Counter> max_insts_all_threads;
796    Param<Counter> max_loads_any_thread;
797    Param<Counter> max_loads_all_threads;
798
799#ifdef FULL_SYSTEM
800    SimObjectParam<AlphaItb *> itb;
801    SimObjectParam<AlphaDtb *> dtb;
802    SimObjectParam<FunctionalMemory *> mem;
803    SimObjectParam<System *> system;
804    Param<int> mult;
805#else
806    SimObjectParam<Process *> workload;
807#endif // FULL_SYSTEM
808
809    SimObjectParam<BaseMem *> icache;
810    SimObjectParam<BaseMem *> dcache;
811
812    Param<bool> defer_registration;
813
814END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
815
816BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
817
818    INIT_PARAM_DFLT(max_insts_any_thread,
819                    "terminate when any thread reaches this inst count",
820                    0),
821    INIT_PARAM_DFLT(max_insts_all_threads,
822                    "terminate when all threads have reached this inst count",
823                    0),
824    INIT_PARAM_DFLT(max_loads_any_thread,
825                    "terminate when any thread reaches this load count",
826                    0),
827    INIT_PARAM_DFLT(max_loads_all_threads,
828                    "terminate when all threads have reached this load count",
829                    0),
830
831#ifdef FULL_SYSTEM
832    INIT_PARAM(itb, "Instruction TLB"),
833    INIT_PARAM(dtb, "Data TLB"),
834    INIT_PARAM(mem, "memory"),
835    INIT_PARAM(system, "system object"),
836    INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
837#else
838    INIT_PARAM(workload, "processes to run"),
839#endif // FULL_SYSTEM
840
841    INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
842    INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
843    INIT_PARAM_DFLT(defer_registration, "defer registration with system "
844                    "(for sampling)", false)
845
846END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
847
848
849CREATE_SIM_OBJECT(SimpleCPU)
850{
851    SimpleCPU *cpu;
852#ifdef FULL_SYSTEM
853    if (mult != 1)
854        panic("processor clock multiplier must be 1\n");
855
856    cpu = new SimpleCPU(getInstanceName(), system,
857                        max_insts_any_thread, max_insts_all_threads,
858                        max_loads_any_thread, max_loads_all_threads,
859                        itb, dtb, mem,
860                        (icache) ? icache->getInterface() : NULL,
861                        (dcache) ? dcache->getInterface() : NULL,
862                        defer_registration,
863                        ticksPerSecond * mult);
864#else
865
866    cpu = new SimpleCPU(getInstanceName(), workload,
867                        max_insts_any_thread, max_insts_all_threads,
868                        max_loads_any_thread, max_loads_all_threads,
869                        (icache) ? icache->getInterface() : NULL,
870                        (dcache) ? dcache->getInterface() : NULL,
871                        defer_registration);
872
873#endif // FULL_SYSTEM
874#if 0
875    if (!defer_registration) {
876        cpu->registerExecContexts();
877    }
878#endif
879    return cpu;
880}
881
882REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
883
884