base.cc revision 595
16928SN/A/*
26928SN/A * Copyright (c) 2003 The Regents of The University of Michigan
36928SN/A * All rights reserved.
410036SN/A *
58940SN/A * Redistribution and use in source and binary forms, with or without
610036SN/A * modification, are permitted provided that the following conditions are
77939SN/A * met: redistributions of source code must retain the above copyright
87939SN/A * notice, this list of conditions and the following disclaimer;
97939SN/A * redistributions in binary form must reproduce the above copyright
106928SN/A * notice, this list of conditions and the following disclaimer in the
116928SN/A * documentation and/or other materials provided with the distribution;
126928SN/A * neither the name of the copyright holders nor the names of its
1310526SN/A * contributors may be used to endorse or promote products derived from
148940SN/A * this software without specific prior written permission.
159864SN/A *
169864SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711680SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810036SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
208940SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218940SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210315SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238940SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410229SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256928SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611680SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710526SN/A */
2810736SN/A
2911219SN/A#include <cmath>
308721SN/A#include <cstdio>
3111680SN/A#include <cstdlib>
3211680SN/A#include <iostream>
3311680SN/A#include <iomanip>
3411680SN/A#include <list>
358940SN/A#include <sstream>
368940SN/A#include <string>
3711440SN/A
3811440SN/A#include "base/cprintf.hh"
397939SN/A#include "base/inifile.hh"
407939SN/A#include "base/loader/symtab.hh"
417939SN/A#include "base/misc.hh"
427939SN/A#include "base/pollevent.hh"
437939SN/A#include "base/range.hh"
447939SN/A#include "base/trace.hh"
457939SN/A#include "cpu/base_cpu.hh"
468940SN/A#include "cpu/exec_context.hh"
476928SN/A#include "cpu/exetrace.hh"
489864SN/A#include "cpu/full_cpu/smt.hh"
499864SN/A#include "cpu/simple_cpu/simple_cpu.hh"
509864SN/A#include "cpu/static_inst.hh"
5110315SN/A#include "mem/base_mem.hh"
5210036SN/A#include "mem/mem_interface.hh"
5310315SN/A#include "sim/annotation.hh"
549864SN/A#include "sim/builder.hh"
559864SN/A#include "sim/debug.hh"
5610315SN/A#include "sim/host.hh"
5710315SN/A#include "sim/sim_events.hh"
5810315SN/A#include "sim/sim_object.hh"
5910315SN/A#include "sim/sim_stats.hh"
6010315SN/A
6110315SN/A#ifdef FULL_SYSTEM
6211680SN/A#include "base/remote_gdb.hh"
6310315SN/A#include "dev/alpha_access.h"
6410315SN/A#include "dev/pciareg.h"
6511680SN/A#include "mem/functional_mem/memory_control.hh"
6611680SN/A#include "mem/functional_mem/physical_memory.hh"
6711680SN/A#include "sim/system.hh"
6811680SN/A#include "targetarch/alpha_memory.hh"
6910315SN/A#include "targetarch/vtophys.hh"
7010315SN/A#else // !FULL_SYSTEM
7111268SN/A#include "eio/eio.hh"
7210315SN/A#include "mem/functional_mem/functional_memory.hh"
7310315SN/A#endif // FULL_SYSTEM
7410315SN/A
7510315SN/Ausing namespace std;
7610315SN/A
7710315SN/ASimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
7810315SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
7910315SN/A{
8010315SN/A}
8110526SN/A
8210526SN/Avoid
8311680SN/ASimpleCPU::TickEvent::process()
8410526SN/A{
8511680SN/A    cpu->tick();
8610526SN/A}
8710526SN/A
8810526SN/Aconst char *
8911680SN/ASimpleCPU::TickEvent::description()
9010526SN/A{
9111680SN/A    return "SimpleCPU tick event";
9210526SN/A}
9310526SN/A
9410526SN/A
9511680SN/ASimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
9610526SN/A    : Event(&mainEventQueue),
9711680SN/A      cpu(_cpu)
9810526SN/A{
9911680SN/A}
10010526SN/A
10111680SN/Avoid SimpleCPU::CacheCompletionEvent::process()
10210526SN/A{
10311680SN/A    cpu->processCacheCompletion();
10410526SN/A}
10510526SN/A
10610526SN/Aconst char *
10710526SN/ASimpleCPU::CacheCompletionEvent::description()
10810736SN/A{
10910526SN/A    return "SimpleCPU cache completion event";
11010526SN/A}
11110526SN/A
11210526SN/A#ifdef FULL_SYSTEM
1139864SN/ASimpleCPU::SimpleCPU(const string &_name,
1149864SN/A                     System *_system,
11511680SN/A                     Counter max_insts_any_thread,
11610526SN/A                     Counter max_insts_all_threads,
11710526SN/A                     Counter max_loads_any_thread,
11810526SN/A                     Counter max_loads_all_threads,
11910526SN/A                     AlphaItb *itb, AlphaDtb *dtb,
12010526SN/A                     FunctionalMemory *mem,
12110036SN/A                     MemInterface *icache_interface,
1229469SN/A                     MemInterface *dcache_interface,
12311680SN/A                     bool _def_reg, Tick freq)
12410526SN/A    : BaseCPU(_name, /* number_of_threads */ 1,
12510526SN/A              max_insts_any_thread, max_insts_all_threads,
12610526SN/A              max_loads_any_thread, max_loads_all_threads,
12710526SN/A              _system, freq),
12811680SN/A#else
12911680SN/ASimpleCPU::SimpleCPU(const string &_name, Process *_process,
13011680SN/A                     Counter max_insts_any_thread,
13110526SN/A                     Counter max_insts_all_threads,
13211680SN/A                     Counter max_loads_any_thread,
13311680SN/A                     Counter max_loads_all_threads,
13410526SN/A                     MemInterface *icache_interface,
13510526SN/A                     MemInterface *dcache_interface,
13610526SN/A                     bool _def_reg)
13710526SN/A    : BaseCPU(_name, /* number_of_threads */ 1,
13810526SN/A              max_insts_any_thread, max_insts_all_threads,
13910526SN/A              max_loads_any_thread, max_loads_all_threads),
14010526SN/A#endif
14110526SN/A      tickEvent(this), xc(NULL), defer_registration(_def_reg),
14210526SN/A      cacheCompletionEvent(this)
14310526SN/A{
14410526SN/A    _status = Idle;
14510526SN/A#ifdef FULL_SYSTEM
14610526SN/A    xc = new ExecContext(this, 0, system, itb, dtb, mem);
14710526SN/A
14810526SN/A    // initialize CPU, including PC
14910526SN/A    TheISA::initCPU(&xc->regs);
15010526SN/A#else
15110526SN/A    xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
15210526SN/A#endif // !FULL_SYSTEM
15310526SN/A
15410526SN/A    icacheInterface = icache_interface;
15511680SN/A    dcacheInterface = dcache_interface;
15610526SN/A
15711680SN/A    memReq = new MemReq();
15810526SN/A    memReq->xc = xc;
15910526SN/A    memReq->asid = 0;
16010526SN/A    memReq->data = new uint8_t[64];
16110526SN/A
16210526SN/A    numInst = 0;
1639469SN/A    startNumInst = 0;
1649469SN/A    numLoad = 0;
1659469SN/A    startNumLoad = 0;
16610036SN/A    lastIcacheStall = 0;
16710736SN/A    lastDcacheStall = 0;
16810036SN/A
1699469SN/A    execContexts.push_back(xc);
1709864SN/A}
17111680SN/A
17210036SN/ASimpleCPU::~SimpleCPU()
17310036SN/A{
17410526SN/A}
17510036SN/A
17611219SN/Avoid SimpleCPU::init()
17711680SN/A{
17811680SN/A    if (!defer_registration) {
17911680SN/A        this->registerExecContexts();
18010526SN/A    }
18111680SN/A}
1829469SN/A
1839469SN/Avoid
1849864SN/ASimpleCPU::switchOut()
1859864SN/A{
1869864SN/A    _status = SwitchedOut;
18710315SN/A    if (tickEvent.scheduled())
18810036SN/A        tickEvent.squash();
18910315SN/A}
1909864SN/A
1919864SN/A
1929469SN/Avoid
1937570SN/ASimpleCPU::takeOverFrom(BaseCPU *oldCPU)
19411023SN/A{
1957570SN/A    BaseCPU::takeOverFrom(oldCPU);
1969864SN/A
19710036SN/A    assert(!tickEvent.scheduled());
19811680SN/A
1999469SN/A    // if any of this CPU's ExecContexts are active, mark the CPU as
2007570SN/A    // running and schedule its tick event.
20110036SN/A    for (int i = 0; i < execContexts.size(); ++i) {
20211023SN/A        ExecContext *xc = execContexts[i];
2037570SN/A        if (xc->status() == ExecContext::Active && _status != Running) {
20411680SN/A            _status = Running;
20511680SN/A            tickEvent.schedule(curTick);
20611680SN/A        }
20711680SN/A    }
2087570SN/A
20911023SN/A    oldCPU->switchOut();
21011023SN/A}
21111023SN/A
21211023SN/A
2138721SN/Avoid
21410526SN/ASimpleCPU::activateContext(int thread_num, int delay)
21510526SN/A{
2167570SN/A    assert(thread_num == 0);
2177570SN/A    assert(xc);
21810526SN/A
2197570SN/A    assert(_status == Idle);
2209469SN/A    notIdleFraction++;
2217570SN/A    scheduleTickEvent(delay);
22210036SN/A    _status = Running;
2239469SN/A}
2249864SN/A
2257570SN/A
2267570SN/Avoid
22711023SN/ASimpleCPU::suspendContext(int thread_num)
22811023SN/A{
22911023SN/A    assert(thread_num == 0);
23011023SN/A    assert(xc);
23111023SN/A
23211023SN/A    assert(_status == Running);
23311023SN/A    notIdleFraction--;
23411023SN/A    unscheduleTickEvent();
23511023SN/A    _status = Idle;
23611023SN/A}
23711023SN/A
23811023SN/A
23911023SN/Avoid
24011023SN/ASimpleCPU::deallocateContext(int thread_num)
24111023SN/A{
24211023SN/A    // for now, these are equivalent
24311023SN/A    suspendContext(thread_num);
24411023SN/A}
24511023SN/A
24611023SN/A
24711023SN/Avoid
24811023SN/ASimpleCPU::haltContext(int thread_num)
24911023SN/A{
25011023SN/A    // for now, these are equivalent
25111023SN/A    suspendContext(thread_num);
25211023SN/A}
25311023SN/A
25411023SN/A
25511023SN/Avoid
25611023SN/ASimpleCPU::regStats()
25711023SN/A{
25811023SN/A    using namespace Statistics;
25911023SN/A
26011023SN/A    BaseCPU::regStats();
26111023SN/A
26211023SN/A    numInsts
26311023SN/A        .name(name() + ".num_insts")
26411023SN/A        .desc("Number of instructions executed")
26511023SN/A        ;
2669469SN/A
2677570SN/A    numMemRefs
26811023SN/A        .name(name() + ".num_refs")
2699698SN/A        .desc("Number of memory references")
2709698SN/A        ;
2717570SN/A
2729864SN/A    idleFraction
27310036SN/A        .name(name() + ".idle_fraction")
27411680SN/A        .desc("Percentage of idle cycles")
27510036SN/A        ;
2767570SN/A
27711023SN/A    icacheStallCycles
2787570SN/A        .name(name() + ".icache_stall_cycles")
27911680SN/A        .desc("ICache total stall cycles")
28011680SN/A        .prereq(icacheStallCycles)
28111680SN/A        ;
28211680SN/A
2837570SN/A    dcacheStallCycles
28411023SN/A        .name(name() + ".dcache_stall_cycles")
28511023SN/A        .desc("DCache total stall cycles")
2867570SN/A        .prereq(dcacheStallCycles)
28711023SN/A        ;
28811023SN/A
2898721SN/A    idleFraction = constant(1.0) - notIdleFraction;
2908940SN/A    numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst);
2919469SN/A    simInsts += numInsts;
29210526SN/A}
2937570SN/A
29411023SN/Avoid
2959605SN/ASimpleCPU::resetStats()
2967570SN/A{
2977570SN/A    startNumInst = numInst;
2989698SN/A    notIdleFraction = (_status != Idle);
2997570SN/A}
30011023SN/A
3017570SN/Avoid
30211312SN/ASimpleCPU::serialize(ostream &os)
3039136SN/A{
3049136SN/A    SERIALIZE_ENUM(_status);
30510036SN/A    SERIALIZE_SCALAR(inst);
3068721SN/A    nameOut(os, csprintf("%s.xc", name()));
30711023SN/A    xc->serialize(os);
3089136SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
30911023SN/A    tickEvent.serialize(os);
3107570SN/A    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
3117570SN/A    cacheCompletionEvent.serialize(os);
3129136SN/A}
3139136SN/A
3147570SN/Avoid
31511023SN/ASimpleCPU::unserialize(Checkpoint *cp, const string &section)
31611023SN/A{
31711023SN/A    UNSERIALIZE_ENUM(_status);
31811023SN/A    UNSERIALIZE_SCALAR(inst);
31911023SN/A    xc->unserialize(cp, csprintf("%s.xc", section));
32011023SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
32111023SN/A    cacheCompletionEvent
3229698SN/A        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
3237570SN/A}
32411023SN/A
3257570SN/Avoid
32611312SN/Achange_thread_state(int thread_number, int activate, int priority)
3279136SN/A{
3289136SN/A}
32910036SN/A
3309469SN/AFault
33111023SN/ASimpleCPU::copySrcTranslate(Addr src)
3329136SN/A{
33311023SN/A    memReq->reset(src, (dcacheInterface) ?
3347570SN/A                  dcacheInterface->getBlockSize()
3357570SN/A                  : 64);
3369136SN/A
3379136SN/A    // translate to physical address
3387570SN/A    Fault fault = xc->translateDataReadReq(memReq);
33911023SN/A
34011023SN/A    if (fault == No_Fault) {
34111023SN/A        xc->copySrcAddr = src;
34211023SN/A        xc->copySrcPhysAddr = memReq->paddr;
34311023SN/A    } else {
34411023SN/A        xc->copySrcAddr = 0;
34511023SN/A        xc->copySrcPhysAddr = 0;
34611023SN/A    }
34711023SN/A    return fault;
34811023SN/A}
34911023SN/A
35011023SN/AFault
35111023SN/ASimpleCPU::copy(Addr dest)
35211023SN/A{
35311023SN/A    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
35411023SN/A    uint8_t data[blk_size];
35511023SN/A    assert(xc->copySrcPhysAddr);
35611023SN/A    memReq->reset(dest, blk_size);
35711023SN/A    // translate to physical address
35811023SN/A    Fault fault = xc->translateDataWriteReq(memReq);
35911023SN/A    if (fault == No_Fault) {
36011023SN/A        Addr dest_addr = memReq->paddr;
36111023SN/A        // Need to read straight from memory since we have more than 8 bytes.
36211023SN/A        memReq->paddr = xc->copySrcPhysAddr;
36311023SN/A        xc->mem->read(memReq, data);
36411023SN/A        memReq->paddr = dest_addr;
36511023SN/A        xc->mem->write(memReq, data);
36611023SN/A    }
36711023SN/A    return fault;
36811023SN/A}
36911023SN/A
37011023SN/A// precise architected memory state accessor macros
37111023SN/Atemplate <class T>
37211023SN/AFault
37311023SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags)
37411023SN/A{
37511023SN/A    memReq->reset(addr, sizeof(T), flags);
37611023SN/A
37711023SN/A    // translate to physical address
37811023SN/A    Fault fault = xc->translateDataReadReq(memReq);
37911023SN/A
38011023SN/A    // do functional access
38111023SN/A    if (fault == No_Fault)
38211023SN/A        fault = xc->read(memReq, data);
38311023SN/A
38411023SN/A    if (traceData) {
3859469SN/A        traceData->setAddr(addr);
3868721SN/A        if (fault == No_Fault)
3879864SN/A            traceData->setData(data);
38811312SN/A    }
3899698SN/A
39011023SN/A    // if we have a cache, do cache access too
3918721SN/A    if (fault == No_Fault && dcacheInterface) {
39211680SN/A        memReq->cmd = Read;
39310036SN/A        memReq->completionEvent = NULL;
39411680SN/A        memReq->time = curTick;
3959698SN/A        MemAccessResult result = dcacheInterface->access(memReq);
39611023SN/A
39711312SN/A        // 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
39911268SN/A        // at some point.
40011680SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
40111680SN/A            memReq->completionEvent = &cacheCompletionEvent;
40211680SN/A            lastDcacheStall = curTick;
40311680SN/A            unscheduleTickEvent();
4048721SN/A            _status = DcacheMissStall;
4058940SN/A        }
4068940SN/A    }
4078940SN/A
4088721SN/A    return fault;
4098721SN/A}
41011268SN/A
4118721SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
41211023SN/A
41311023SN/Atemplate
41411023SN/AFault
41511023SN/ASimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
41611023SN/A
41711023SN/Atemplate
41811023SN/AFault
4199469SN/ASimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
4207570SN/A
42111023SN/Atemplate
42211023SN/AFault
42311023SN/ASimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
42411023SN/A
42511023SN/Atemplate
4269698SN/AFault
4277570SN/ASimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
4289864SN/A
42910036SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
43011680SN/A
43110036SN/Atemplate<>
4327570SN/AFault
43311680SN/ASimpleCPU::read(Addr addr, double &data, unsigned flags)
43411680SN/A{
43511680SN/A    return read(addr, *(uint64_t*)&data, flags);
43611680SN/A}
4377570SN/A
4387570SN/Atemplate<>
43911023SN/AFault
44011023SN/ASimpleCPU::read(Addr addr, float &data, unsigned flags)
4417570SN/A{
4428721SN/A    return read(addr, *(uint32_t*)&data, flags);
44310526SN/A}
4447570SN/A
44511023SN/A
4467570SN/Atemplate<>
44711023SN/AFault
44811023SN/ASimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
44911023SN/A{
45011023SN/A    return read(addr, (uint32_t&)data, flags);
45111023SN/A}
45211023SN/A
45311023SN/A
45411023SN/Atemplate <class T>
45511023SN/AFault
45611023SN/ASimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
45711023SN/A{
45811023SN/A    if (traceData) {
45911023SN/A        traceData->setAddr(addr);
46011023SN/A        traceData->setData(data);
46111023SN/A    }
46211023SN/A
46311023SN/A    memReq->reset(addr, sizeof(T), flags);
46411023SN/A
46511023SN/A    // translate to physical address
46611023SN/A    Fault fault = xc->translateDataWriteReq(memReq);
46711023SN/A
46811023SN/A    // do functional access
46911023SN/A    if (fault == No_Fault)
47011023SN/A        fault = xc->write(memReq, data);
47111023SN/A
47211023SN/A    if (fault == No_Fault && dcacheInterface) {
47311023SN/A        memReq->cmd = Write;
47411023SN/A        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
47511023SN/A        memReq->completionEvent = NULL;
47611023SN/A        memReq->time = curTick;
47711023SN/A        MemAccessResult result = dcacheInterface->access(memReq);
47811023SN/A
4797570SN/A        // Ugly hack to get an event scheduled *only* if the access is
4809698SN/A        // a miss.  We really should add first-class support for this
4817570SN/A        // at some point.
48211023SN/A        if (result != MA_HIT && dcacheInterface->doEvents()) {
4837570SN/A            memReq->completionEvent = &cacheCompletionEvent;
48411312SN/A            lastDcacheStall = curTick;
4859136SN/A            unscheduleTickEvent();
4869136SN/A            _status = DcacheMissStall;
48710036SN/A        }
4888721SN/A    }
48911023SN/A
4909136SN/A    if (res && (fault == No_Fault))
49111023SN/A        *res = memReq->result;
4927570SN/A
4937570SN/A    return fault;
4949136SN/A}
4959136SN/A
4967570SN/A
49711023SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
49811023SN/Atemplate
49911023SN/AFault
50011023SN/ASimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
50111023SN/A
50211023SN/Atemplate
50311023SN/AFault
50411023SN/ASimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
50511023SN/A
50611023SN/Atemplate
50711023SN/AFault
50811023SN/ASimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
50911023SN/A
51011023SN/Atemplate
51111023SN/AFault
51211023SN/ASimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
51311023SN/A
51411023SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
51511023SN/A
51611023SN/Atemplate<>
51711023SN/AFault
51811023SN/ASimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
51911023SN/A{
52011023SN/A    return write(*(uint64_t*)&data, addr, flags, res);
52111023SN/A}
52211023SN/A
52311023SN/Atemplate<>
52411023SN/AFault
52511023SN/ASimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
52611023SN/A{
5279864SN/A    return write(*(uint32_t*)&data, addr, flags, res);
5289864SN/A}
5299864SN/A
5309864SN/A
53110036SN/Atemplate<>
5329864SN/AFault
5336928SN/ASimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
5346928SN/A{
53511680SN/A    return write((uint32_t)data, addr, flags, res);
5367034SN/A}
5376928SN/A
5389864SN/A
5396928SN/A#ifdef FULL_SYSTEM
54011680SN/AAddr
5418264SN/ASimpleCPU::dbg_vtophys(Addr addr)
54210036SN/A{
5439605SN/A    return vtophys(xc, addr);
54411680SN/A}
54511680SN/A#endif // FULL_SYSTEM
54610229SN/A
54711066SN/ATick save_cycle = 0;
54811680SN/A
54911680SN/A
55011680SN/Avoid
55111680SN/ASimpleCPU::processCacheCompletion()
5529864SN/A{
5538721SN/A    switch (status()) {
5549605SN/A      case IcacheMissStall:
55511023SN/A        icacheStallCycles += curTick - lastIcacheStall;
55611023SN/A        _status = IcacheMissComplete;
5576928SN/A        scheduleTickEvent(1);
5589605SN/A        break;
5598264SN/A      case DcacheMissStall:
5608264SN/A        dcacheStallCycles += curTick - lastDcacheStall;
56110036SN/A        _status = Running;
5629469SN/A        scheduleTickEvent(1);
5639864SN/A        break;
5646928SN/A      case SwitchedOut:
5658264SN/A        // If this CPU has been switched out due to sampling/warm-up,
5666928SN/A        // ignore any further status changes (e.g., due to cache
5676928SN/A        // misses outstanding at the time of the switch).
5689605SN/A        return;
5698264SN/A      default:
5708264SN/A        panic("SimpleCPU::processCacheCompletion: bad state");
57110036SN/A        break;
5729469SN/A    }
5739864SN/A}
5746928SN/A
5758264SN/A#ifdef FULL_SYSTEM
5766928SN/Avoid
5776928SN/ASimpleCPU::post_interrupt(int int_num, int index)
5789605SN/A{
5798264SN/A    BaseCPU::post_interrupt(int_num, index);
5808264SN/A
58110036SN/A    if (xc->status() == ExecContext::Suspended) {
5829469SN/A                DPRINTF(IPI,"Suspended Processor awoke\n");
5839864SN/A        xc->activate();
5846928SN/A        Annotate::Resume(xc);
5858264SN/A    }
5866928SN/A}
5876928SN/A#endif // FULL_SYSTEM
58811023SN/A
58911023SN/A/* start simulation, program loaded, processor precise state initialized */
59011023SN/Avoid
59111023SN/ASimpleCPU::tick()
59211023SN/A{
59311023SN/A    traceData = NULL;
59411023SN/A
59511023SN/A    Fault fault = No_Fault;
59611023SN/A
59711023SN/A#ifdef FULL_SYSTEM
59811023SN/A    if (AlphaISA::check_interrupts &&
59911023SN/A        xc->cpu->check_interrupts() &&
60011023SN/A        !PC_PAL(xc->regs.pc) &&
60111023SN/A        status() != IcacheMissComplete) {
60211023SN/A        int ipl = 0;
60311023SN/A        int summary = 0;
60411023SN/A        AlphaISA::check_interrupts = 0;
60511023SN/A        IntReg *ipr = xc->regs.ipr;
60611023SN/A
60711023SN/A        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
60811023SN/A            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
60911023SN/A                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
61011023SN/A                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
61111023SN/A                    // See table 4-19 of 21164 hardware reference
61211023SN/A                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
61311023SN/A                    summary |= (ULL(1) << i);
61411023SN/A                }
61511023SN/A            }
61611023SN/A        }
61711023SN/A
61811023SN/A        uint64_t interrupts = xc->cpu->intr_status();
61911023SN/A        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
62011023SN/A            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
62111023SN/A            if (interrupts & (ULL(1) << i)) {
62211023SN/A                // See table 4-19 of 21164 hardware reference
62311023SN/A                ipl = i;
62411023SN/A                summary |= (ULL(1) << i);
62511023SN/A            }
62611023SN/A        }
62711023SN/A
62811023SN/A        if (ipr[TheISA::IPR_ASTRR])
62911023SN/A            panic("asynchronous traps not implemented\n");
63011023SN/A
63111023SN/A        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
63211023SN/A            ipr[TheISA::IPR_ISR] = summary;
63311023SN/A            ipr[TheISA::IPR_INTID] = ipl;
63411023SN/A            xc->ev5_trap(Interrupt_Fault);
63511023SN/A
63611023SN/A            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
63711023SN/A                    ipr[TheISA::IPR_IPLR], ipl, summary);
63811023SN/A        }
63911023SN/A    }
64011023SN/A#endif
64111023SN/A
64211023SN/A    // maintain $r0 semantics
64311023SN/A    xc->regs.intRegFile[ZeroReg] = 0;
64411023SN/A#ifdef TARGET_ALPHA
64511023SN/A    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
64611023SN/A#endif // TARGET_ALPHA
64711023SN/A
64811023SN/A    if (status() == IcacheMissComplete) {
64911023SN/A        // We've already fetched an instruction and were stalled on an
65011023SN/A        // I-cache miss.  No need to fetch it again.
65111023SN/A
65211023SN/A        // Set status to running; tick event will get rescheduled if
65311023SN/A        // necessary at end of tick() function.
65411023SN/A        _status = Running;
65511023SN/A    }
65611023SN/A    else {
65711023SN/A        // Try to fetch an instruction
65811023SN/A
65911023SN/A        // set up memory request for instruction fetch
66011023SN/A#ifdef FULL_SYSTEM
66111023SN/A#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
66211023SN/A#else
66311023SN/A#define IFETCH_FLAGS(pc)	0
66411023SN/A#endif
66511023SN/A
66611023SN/A        memReq->cmd = Read;
66711023SN/A        memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
66811023SN/A                     IFETCH_FLAGS(xc->regs.pc));
66911023SN/A
67011023SN/A        fault = xc->translateInstReq(memReq);
67111023SN/A
67211023SN/A        if (fault == No_Fault)
67311023SN/A            fault = xc->mem->read(memReq, inst);
67411023SN/A
67511023SN/A        if (icacheInterface && fault == No_Fault) {
67611023SN/A            memReq->completionEvent = NULL;
67711023SN/A
67811023SN/A            memReq->time = curTick;
67911023SN/A            MemAccessResult result = icacheInterface->access(memReq);
68011023SN/A
68111023SN/A            // Ugly hack to get an event scheduled *only* if the access is
68211023SN/A            // a miss.  We really should add first-class support for this
68311023SN/A            // at some point.
68411023SN/A            if (result != MA_HIT && icacheInterface->doEvents()) {
68511023SN/A                memReq->completionEvent = &cacheCompletionEvent;
68611023SN/A                lastIcacheStall = curTick;
68711023SN/A                unscheduleTickEvent();
68811023SN/A                _status = IcacheMissStall;
68911023SN/A                return;
69011023SN/A            }
69111023SN/A        }
69211023SN/A    }
69311023SN/A
69411023SN/A    // If we've got a valid instruction (i.e., no fault on instruction
69511023SN/A    // fetch), then execute it.
69611023SN/A    if (fault == No_Fault) {
69711023SN/A
69811023SN/A        // keep an instruction count
69911023SN/A        numInst++;
70011023SN/A
70111023SN/A        // check for instruction-count-based events
70211023SN/A        comInstEventQueue[0]->serviceEvents(numInst);
70311023SN/A
70411023SN/A        // decode the instruction
70511023SN/A        StaticInstPtr<TheISA> si(inst);
70611023SN/A
70711023SN/A        traceData = Trace::getInstRecord(curTick, xc, this, si,
70811023SN/A                                         xc->regs.pc);
70911023SN/A
71011023SN/A#ifdef FULL_SYSTEM
71111023SN/A        xc->regs.opcode = (inst >> 26) & 0x3f;
71211023SN/A        xc->regs.ra = (inst >> 21) & 0x1f;
71311023SN/A#endif // FULL_SYSTEM
71411680SN/A
71511680SN/A        xc->func_exe_inst++;
71611680SN/A
71711680SN/A        fault = si->execute(this, xc, traceData);
71811680SN/A#ifdef FS_MEASURE
71911680SN/A        if (!(xc->misspeculating()) && (xc->system->bin)) {
72011680SN/A            SWContext *ctx = xc->swCtx;
72111680SN/A            if (ctx && !ctx->callStack.empty()) {
72211680SN/A                if (si->isCall()) {
72311680SN/A                    ctx->calls++;
72411680SN/A                }
72511680SN/A                if (si->isReturn()) {
72611680SN/A                     if (ctx->calls == 0) {
72711680SN/A                        fnCall *top = ctx->callStack.top();
72811680SN/A                        DPRINTF(TCPIP, "Removing %s from callstack.\n", top->name);
72911680SN/A                        delete top;
73011680SN/A                        ctx->callStack.pop();
73111680SN/A                        if (ctx->callStack.empty())
73211680SN/A                            xc->system->nonPath->activate();
73311680SN/A                        else
73411680SN/A                            ctx->callStack.top()->myBin->activate();
73511680SN/A
73611680SN/A                        xc->system->dumpState(xc);
73711680SN/A                    } else {
73811680SN/A                        ctx->calls--;
73911680SN/A                    }
74011680SN/A                }
74111680SN/A            }
74211680SN/A        }
74311680SN/A#endif
74411680SN/A        if (si->isMemRef()) {
74511680SN/A            numMemRefs++;
74611680SN/A        }
74711680SN/A
74811680SN/A        if (si->isLoad()) {
74911680SN/A            ++numLoad;
75011680SN/A            comLoadEventQueue[0]->serviceEvents(numLoad);
75111680SN/A        }
75211680SN/A
75311680SN/A        if (traceData)
75411680SN/A            traceData->finalize();
75511680SN/A
75611680SN/A    }	// if (fault == No_Fault)
75711680SN/A
75811680SN/A    if (fault != No_Fault) {
75911680SN/A#ifdef FULL_SYSTEM
76011680SN/A        xc->ev5_trap(fault);
76111680SN/A#else // !FULL_SYSTEM
76211680SN/A        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
76311680SN/A#endif // FULL_SYSTEM
76411680SN/A    }
76511680SN/A    else {
76611680SN/A        // go to the next instruction
76711680SN/A        xc->regs.pc = xc->regs.npc;
76811680SN/A        xc->regs.npc += sizeof(MachInst);
76911680SN/A    }
77011680SN/A
77111680SN/A#ifdef FULL_SYSTEM
77211680SN/A    Addr oldpc;
77311680SN/A    do {
77411680SN/A        oldpc = xc->regs.pc;
77511680SN/A        system->pcEventQueue.service(xc);
77611680SN/A    } while (oldpc != xc->regs.pc);
77711680SN/A#endif
77811680SN/A
77911680SN/A    assert(status() == Running ||
78011680SN/A           status() == Idle ||
78111680SN/A           status() == DcacheMissStall);
78211680SN/A
78311680SN/A    if (status() == Running && !tickEvent.scheduled())
78411680SN/A        tickEvent.schedule(curTick + 1);
78511680SN/A}
78611680SN/A
78711680SN/A
78811680SN/A////////////////////////////////////////////////////////////////////////
78911680SN/A//
79011680SN/A//  SimpleCPU Simulation Object
79111680SN/A//
79211680SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
79311680SN/A
79411680SN/A    Param<Counter> max_insts_any_thread;
79511680SN/A    Param<Counter> max_insts_all_threads;
79611680SN/A    Param<Counter> max_loads_any_thread;
79711680SN/A    Param<Counter> max_loads_all_threads;
79811680SN/A
79911680SN/A#ifdef FULL_SYSTEM
80011680SN/A    SimObjectParam<AlphaItb *> itb;
80111680SN/A    SimObjectParam<AlphaDtb *> dtb;
80211680SN/A    SimObjectParam<FunctionalMemory *> mem;
80311680SN/A    SimObjectParam<System *> system;
80411680SN/A    Param<int> mult;
80511680SN/A#else
80611680SN/A    SimObjectParam<Process *> workload;
80711680SN/A#endif // FULL_SYSTEM
80811680SN/A
80911680SN/A    SimObjectParam<BaseMem *> icache;
81011680SN/A    SimObjectParam<BaseMem *> dcache;
81111680SN/A
81211680SN/A    Param<bool> defer_registration;
81311680SN/A
81411680SN/AEND_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
81511680SN/A
81611680SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
81711680SN/A
81811680SN/A    INIT_PARAM_DFLT(max_insts_any_thread,
81911680SN/A                    "terminate when any thread reaches this inst count",
82011680SN/A                    0),
82111680SN/A    INIT_PARAM_DFLT(max_insts_all_threads,
82211680SN/A                    "terminate when all threads have reached this inst count",
82311680SN/A                    0),
82411680SN/A    INIT_PARAM_DFLT(max_loads_any_thread,
82511680SN/A                    "terminate when any thread reaches this load count",
82611680SN/A                    0),
82711680SN/A    INIT_PARAM_DFLT(max_loads_all_threads,
82811680SN/A                    "terminate when all threads have reached this load count",
82911680SN/A                    0),
83011680SN/A
83111680SN/A#ifdef FULL_SYSTEM
83211680SN/A    INIT_PARAM(itb, "Instruction TLB"),
83311680SN/A    INIT_PARAM(dtb, "Data TLB"),
83411680SN/A    INIT_PARAM(mem, "memory"),
83511680SN/A    INIT_PARAM(system, "system object"),
83611680SN/A    INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
83711680SN/A#else
83811680SN/A    INIT_PARAM(workload, "processes to run"),
83911680SN/A#endif // FULL_SYSTEM
8409605SN/A
8418264SN/A    INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
8428264SN/A    INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
84311680SN/A    INIT_PARAM_DFLT(defer_registration, "defer registration with system "
84411680SN/A                    "(for sampling)", false)
84510036SN/A
8466928SN/AEND_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
8478264SN/A
84811680SN/A
84911680SN/ACREATE_SIM_OBJECT(SimpleCPU)
8506928SN/A{
8516928SN/A    SimpleCPU *cpu;
8529605SN/A#ifdef FULL_SYSTEM
8538264SN/A    if (mult != 1)
8548264SN/A        panic("processor clock multiplier must be 1\n");
85511680SN/A
85611680SN/A    cpu = new SimpleCPU(getInstanceName(), system,
85710036SN/A                        max_insts_any_thread, max_insts_all_threads,
8586928SN/A                        max_loads_any_thread, max_loads_all_threads,
8598264SN/A                        itb, dtb, mem,
86011680SN/A                        (icache) ? icache->getInterface() : NULL,
86111680SN/A                        (dcache) ? dcache->getInterface() : NULL,
8626928SN/A                        defer_registration,
8636928SN/A                        ticksPerSecond * mult);
8649605SN/A#else
8658264SN/A
8668264SN/A    cpu = new SimpleCPU(getInstanceName(), workload,
86711680SN/A                        max_insts_any_thread, max_insts_all_threads,
86811680SN/A                        max_loads_any_thread, max_loads_all_threads,
86910036SN/A                        (icache) ? icache->getInterface() : NULL,
8706928SN/A                        (dcache) ? dcache->getInterface() : NULL,
8718264SN/A                        defer_registration);
87211680SN/A
87311680SN/A#endif // FULL_SYSTEM
87411680SN/A#if 0
87511680SN/A    if (!defer_registration) {
87611680SN/A        cpu->registerExecContexts();
87711680SN/A    }
87811680SN/A#endif
87911680SN/A    return cpu;
88011680SN/A}
88111680SN/A
88211680SN/AREGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
88311680SN/A
88411680SN/A