base.cc revision 2036
19793Sakash.bagdia@arm.com/*
28706Sandreas.hansson@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
38706Sandreas.hansson@arm.com * All rights reserved.
48706Sandreas.hansson@arm.com *
58706Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68706Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78706Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88706Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98706Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108706Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118706Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128706Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
135369Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from
143005Sstever@eecs.umich.edu * this software without specific prior written permission.
153005Sstever@eecs.umich.edu *
163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu */
283005Sstever@eecs.umich.edu
293005Sstever@eecs.umich.edu#include <cmath>
303005Sstever@eecs.umich.edu#include <cstdio>
313005Sstever@eecs.umich.edu#include <cstdlib>
323005Sstever@eecs.umich.edu#include <iostream>
333005Sstever@eecs.umich.edu#include <iomanip>
343005Sstever@eecs.umich.edu#include <list>
353005Sstever@eecs.umich.edu#include <sstream>
363005Sstever@eecs.umich.edu#include <string>
373005Sstever@eecs.umich.edu
383005Sstever@eecs.umich.edu#include "base/cprintf.hh"
393005Sstever@eecs.umich.edu#include "base/inifile.hh"
403005Sstever@eecs.umich.edu#include "base/loader/symtab.hh"
412710SN/A#include "base/misc.hh"
422710SN/A#include "base/pollevent.hh"
433005Sstever@eecs.umich.edu#include "base/range.hh"
442889SN/A#include "base/stats/events.hh"
4512564Sgabeblack@google.com#include "base/trace.hh"
4613774Sandreas.sandberg@arm.com#include "cpu/base.hh"
4712564Sgabeblack@google.com#include "cpu/exec_context.hh"
486654Snate@binkert.org#include "cpu/exetrace.hh"
496654Snate@binkert.org#include "cpu/profile.hh"
509907Snilay@cs.wisc.edu#include "cpu/sampler/sampler.hh"
516654Snate@binkert.org#include "cpu/simple/cpu.hh"
522667SN/A#include "cpu/smt.hh"
536654Snate@binkert.org#include "cpu/static_inst.hh"
546654Snate@binkert.org#include "kern/kernel_stats.hh"
5512395Sswapnilster@gmail.com#include "mem/base_mem.hh"
565457Ssaidi@eecs.umich.edu#include "mem/mem_interface.hh"
5711670Sandreas.hansson@arm.com#include "sim/byteswap.hh"
5811670Sandreas.hansson@arm.com#include "sim/builder.hh"
5911670Sandreas.hansson@arm.com#include "sim/debug.hh"
608169SLisa.Hsu@amd.com#include "sim/host.hh"
6111682Sandreas.hansson@arm.com#include "sim/sim_events.hh"
6211682Sandreas.hansson@arm.com#include "sim/sim_object.hh"
6311682Sandreas.hansson@arm.com#include "sim/stats.hh"
6411682Sandreas.hansson@arm.com
6513432Spau.cabre@metempsy.com#if FULL_SYSTEM
6611682Sandreas.hansson@arm.com#include "base/remote_gdb.hh"
6713883Sdavid.hashe@amd.com#include "mem/functional/memory_control.hh"
6811682Sandreas.hansson@arm.com#include "mem/functional/physical.hh"
6911682Sandreas.hansson@arm.com#include "sim/system.hh"
703394Shsul@eecs.umich.edu#include "targetarch/alpha_memory.hh"
719197Snilay@cs.wisc.edu#include "targetarch/stacktrace.hh"
729197Snilay@cs.wisc.edu#include "targetarch/vtophys.hh"
739197Snilay@cs.wisc.edu#else // !FULL_SYSTEM
749197Snilay@cs.wisc.edu#include "mem/functional/functional.hh"
759197Snilay@cs.wisc.edu#endif // FULL_SYSTEM
769197Snilay@cs.wisc.edu
779197Snilay@cs.wisc.eduusing namespace std;
789197Snilay@cs.wisc.edu//The SimpleCPU does alpha only
799197Snilay@cs.wisc.eduusing namespace LittleEndianGuest;
809197Snilay@cs.wisc.edu
819197Snilay@cs.wisc.edu
829197Snilay@cs.wisc.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
839197Snilay@cs.wisc.edu    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
849197Snilay@cs.wisc.edu{
859197Snilay@cs.wisc.edu}
869197Snilay@cs.wisc.edu
879197Snilay@cs.wisc.eduvoid
889197Snilay@cs.wisc.eduSimpleCPU::TickEvent::process()
899197Snilay@cs.wisc.edu{
909197Snilay@cs.wisc.edu    int count = width;
919197Snilay@cs.wisc.edu    do {
9212146Spau.cabre@metempsy.com        cpu->tick();
939197Snilay@cs.wisc.edu    } while (--count > 0 && cpu->status() == Running);
949907Snilay@cs.wisc.edu}
959197Snilay@cs.wisc.edu
9610803Sbrandon.potter@amd.comconst char *
9710803Sbrandon.potter@amd.comSimpleCPU::TickEvent::description()
9810803Sbrandon.potter@amd.com{
9910803Sbrandon.potter@amd.com    return "SimpleCPU tick event";
1009197Snilay@cs.wisc.edu}
1019217Snilay@cs.wisc.edu
1029197Snilay@cs.wisc.edu
1039197Snilay@cs.wisc.eduSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
1049197Snilay@cs.wisc.edu    : Event(&mainEventQueue), cpu(_cpu)
1059197Snilay@cs.wisc.edu{
1069197Snilay@cs.wisc.edu}
1079197Snilay@cs.wisc.edu
1089197Snilay@cs.wisc.eduvoid SimpleCPU::CacheCompletionEvent::process()
1099197Snilay@cs.wisc.edu{
1109197Snilay@cs.wisc.edu    cpu->processCacheCompletion();
1119197Snilay@cs.wisc.edu}
1129197Snilay@cs.wisc.edu
1139197Snilay@cs.wisc.educonst char *
1149197Snilay@cs.wisc.eduSimpleCPU::CacheCompletionEvent::description()
1159197Snilay@cs.wisc.edu{
11612014Sgabeblack@google.com    return "SimpleCPU cache completion event";
1179197Snilay@cs.wisc.edu}
1189197Snilay@cs.wisc.edu
1199197Snilay@cs.wisc.eduSimpleCPU::SimpleCPU(Params *p)
1209197Snilay@cs.wisc.edu    : BaseCPU(p), tickEvent(this, p->width), xc(NULL),
1219197Snilay@cs.wisc.edu      cacheCompletionEvent(this)
1222957SN/A{
1238920Snilay@cs.wisc.edu    _status = Idle;
1248920Snilay@cs.wisc.edu#if FULL_SYSTEM
1252957SN/A    xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
1268862Snilay@cs.wisc.edu
1278862Snilay@cs.wisc.edu    // initialize CPU, including PC
1288467Snilay@cs.wisc.edu    TheISA::initCPU(&xc->regs);
1292957SN/A#else
1302957SN/A    xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0);
1312957SN/A#endif // !FULL_SYSTEM
13212564Sgabeblack@google.com
1332957SN/A    icacheInterface = p->icache_interface;
1342957SN/A    dcacheInterface = p->dcache_interface;
1358167SLisa.Hsu@amd.com
1369197Snilay@cs.wisc.edu    memReq = new MemReq();
1378167SLisa.Hsu@amd.com    memReq->xc = xc;
1385369Ssaidi@eecs.umich.edu    memReq->asid = 0;
1398167SLisa.Hsu@amd.com    memReq->data = new uint8_t[64];
1408167SLisa.Hsu@amd.com
14112564Sgabeblack@google.com    numInst = 0;
1428167SLisa.Hsu@amd.com    startNumInst = 0;
1438167SLisa.Hsu@amd.com    numLoad = 0;
1448167SLisa.Hsu@amd.com    startNumLoad = 0;
1458167SLisa.Hsu@amd.com    lastIcacheStall = 0;
1468168SLisa.Hsu@amd.com    lastDcacheStall = 0;
14710037SARM gem5 Developers
14810037SARM gem5 Developers    execContexts.push_back(xc);
14910037SARM gem5 Developers}
15010037SARM gem5 Developers
15110037SARM gem5 DevelopersSimpleCPU::~SimpleCPU()
1528168SLisa.Hsu@amd.com{
15310037SARM gem5 Developers}
15410037SARM gem5 Developers
15511851Sbrandon.potter@amd.comvoid
1568167SLisa.Hsu@amd.comSimpleCPU::switchOut(Sampler *s)
15712564Sgabeblack@google.com{
15812564Sgabeblack@google.com    sampler = s;
15912564Sgabeblack@google.com    if (status() == DcacheMissStall) {
1605369Ssaidi@eecs.umich.edu        DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
1618920Snilay@cs.wisc.edu        _status = DcacheMissSwitch;
1629197Snilay@cs.wisc.edu    }
1638920Snilay@cs.wisc.edu    else {
16412564Sgabeblack@google.com        _status = SwitchedOut;
1658920Snilay@cs.wisc.edu
1665369Ssaidi@eecs.umich.edu        if (tickEvent.scheduled())
1675369Ssaidi@eecs.umich.edu            tickEvent.squash();
1688718Snilay@cs.wisc.edu
1699197Snilay@cs.wisc.edu        sampler->signalSwitched();
1709197Snilay@cs.wisc.edu    }
1719197Snilay@cs.wisc.edu}
1729197Snilay@cs.wisc.edu
1739197Snilay@cs.wisc.edu
1743005Sstever@eecs.umich.eduvoid
1753395Shsul@eecs.umich.eduSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
17613731Sandreas.sandberg@arm.com{
1779793Sakash.bagdia@arm.com    BaseCPU::takeOverFrom(oldCPU);
1789836Sandreas.hansson@arm.com
1799815SAndreas Hansson <andreas.hansson>    assert(!tickEvent.scheduled());
1809793Sakash.bagdia@arm.com
18111147Smitch.hayenga@arm.com    // if any of this CPU's ExecContexts are active, mark the CPU as
18211147Smitch.hayenga@arm.com    // running and schedule its tick event.
18311147Smitch.hayenga@arm.com    for (int i = 0; i < execContexts.size(); ++i) {
1849827Sakash.bagdia@arm.com        ExecContext *xc = execContexts[i];
1859827Sakash.bagdia@arm.com        if (xc->status() == ExecContext::Active && _status != Running) {
1869827Sakash.bagdia@arm.com            _status = Running;
1879827Sakash.bagdia@arm.com            tickEvent.schedule(curTick);
1889827Sakash.bagdia@arm.com        }
1899827Sakash.bagdia@arm.com    }
1909827Sakash.bagdia@arm.com}
1919827Sakash.bagdia@arm.com
1929827Sakash.bagdia@arm.com
1939827Sakash.bagdia@arm.comvoid
1949793Sakash.bagdia@arm.comSimpleCPU::activateContext(int thread_num, int delay)
1959827Sakash.bagdia@arm.com{
1969827Sakash.bagdia@arm.com    assert(thread_num == 0);
1979827Sakash.bagdia@arm.com    assert(xc);
1989793Sakash.bagdia@arm.com
19911251Sradhika.jagtap@ARM.com    assert(_status == Idle);
20011251Sradhika.jagtap@ARM.com    notIdleFraction++;
20111251Sradhika.jagtap@ARM.com    scheduleTickEvent(delay);
20211251Sradhika.jagtap@ARM.com    _status = Running;
20311251Sradhika.jagtap@ARM.com}
2049793Sakash.bagdia@arm.com
2059793Sakash.bagdia@arm.com
2069793Sakash.bagdia@arm.comvoid
2079793Sakash.bagdia@arm.comSimpleCPU::suspendContext(int thread_num)
2083395Shsul@eecs.umich.edu{
20912941Sandreas.sandberg@arm.com    assert(thread_num == 0);
21010555Salexandru.dutu@amd.com    assert(xc);
21111839SCurtis.Dunham@arm.com
21210555Salexandru.dutu@amd.com    assert(_status == Running);
21310555Salexandru.dutu@amd.com    notIdleFraction--;
21410555Salexandru.dutu@amd.com    unscheduleTickEvent();
21510555Salexandru.dutu@amd.com    _status = Idle;
21610555Salexandru.dutu@amd.com}
21710555Salexandru.dutu@amd.com
2188926Sandreas.hansson@arm.com
2199647Sdam.sunwoo@arm.comvoid
22013684Sgiacomo.travaglini@arm.comSimpleCPU::deallocateContext(int thread_num)
22113012Sandreas.sandberg@arm.com{
2229647Sdam.sunwoo@arm.com    // for now, these are equivalent
2239647Sdam.sunwoo@arm.com    suspendContext(thread_num);
2249647Sdam.sunwoo@arm.com}
22513731Sandreas.sandberg@arm.com
2269197Snilay@cs.wisc.edu
2279197Snilay@cs.wisc.eduvoid
2289197Snilay@cs.wisc.eduSimpleCPU::haltContext(int thread_num)
2298957Sjayneel@cs.wisc.edu{
2308957Sjayneel@cs.wisc.edu    // for now, these are equivalent
2318957Sjayneel@cs.wisc.edu    suspendContext(thread_num);
2323005Sstever@eecs.umich.edu}
2339647Sdam.sunwoo@arm.com
23410381Sdam.sunwoo@arm.com
2359647Sdam.sunwoo@arm.comvoid
2368887Sgeoffrey.blake@arm.comSimpleCPU::regStats()
2378887Sgeoffrey.blake@arm.com{
2388887Sgeoffrey.blake@arm.com    using namespace Stats;
23913432Spau.cabre@metempsy.com
24013432Spau.cabre@metempsy.com    BaseCPU::regStats();
24113432Spau.cabre@metempsy.com
24213432Spau.cabre@metempsy.com    numInsts
24313958Sjairo.balart@metempsy.com        .name(name() + ".num_insts")
24413958Sjairo.balart@metempsy.com        .desc("Number of instructions executed")
24513958Sjairo.balart@metempsy.com        ;
24613958Sjairo.balart@metempsy.com
2479384SAndreas.Sandberg@arm.com    numMemRefs
2489384SAndreas.Sandberg@arm.com        .name(name() + ".num_refs")
24913883Sdavid.hashe@amd.com        .desc("Number of memory references")
25013883Sdavid.hashe@amd.com        ;
25113883Sdavid.hashe@amd.com
2528887Sgeoffrey.blake@arm.com    notIdleFraction
25310519Snilay@cs.wisc.edu        .name(name() + ".not_idle_fraction")
25410120Snilay@cs.wisc.edu        .desc("Percentage of non-idle cycles")
2558896Snilay@cs.wisc.edu        ;
25610300Scastilloe@unican.es
25710300Scastilloe@unican.es    idleFraction
25813731Sandreas.sandberg@arm.com        .name(name() + ".idle_fraction")
25910120Snilay@cs.wisc.edu        .desc("Percentage of idle cycles")
2608896Snilay@cs.wisc.edu        ;
2618896Snilay@cs.wisc.edu
2629268Smalek.musleh@gmail.com    icacheStallCycles
2639268Smalek.musleh@gmail.com        .name(name() + ".icache_stall_cycles")
2648896Snilay@cs.wisc.edu        .desc("ICache total stall cycles")
2658896Snilay@cs.wisc.edu        .prereq(icacheStallCycles)
2668896Snilay@cs.wisc.edu        ;
2678896Snilay@cs.wisc.edu
2688896Snilay@cs.wisc.edu    dcacheStallCycles
2699222Shestness@cs.wisc.edu        .name(name() + ".dcache_stall_cycles")
27011150Smitch.hayenga@arm.com        .desc("DCache total stall cycles")
27111150Smitch.hayenga@arm.com        .prereq(dcacheStallCycles)
27211150Smitch.hayenga@arm.com        ;
2739222Shestness@cs.wisc.edu
2749222Shestness@cs.wisc.edu    idleFraction = constant(1.0) - notIdleFraction;
2758887Sgeoffrey.blake@arm.com}
27610150Snilay@cs.wisc.edu
27710720Sandreas.hansson@arm.comvoid
2788887Sgeoffrey.blake@arm.comSimpleCPU::resetStats()
2798887Sgeoffrey.blake@arm.com{
2809836Sandreas.hansson@arm.com    startNumInst = numInst;
2818887Sgeoffrey.blake@arm.com    notIdleFraction = (_status != Idle);
2828801Sgblack@eecs.umich.edu}
2833481Shsul@eecs.umich.edu
284void
285SimpleCPU::serialize(ostream &os)
286{
287    BaseCPU::serialize(os);
288    SERIALIZE_ENUM(_status);
289    SERIALIZE_SCALAR(inst);
290    nameOut(os, csprintf("%s.xc", name()));
291    xc->serialize(os);
292    nameOut(os, csprintf("%s.tickEvent", name()));
293    tickEvent.serialize(os);
294    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
295    cacheCompletionEvent.serialize(os);
296}
297
298void
299SimpleCPU::unserialize(Checkpoint *cp, const string &section)
300{
301    BaseCPU::unserialize(cp, section);
302    UNSERIALIZE_ENUM(_status);
303    UNSERIALIZE_SCALAR(inst);
304    xc->unserialize(cp, csprintf("%s.xc", section));
305    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
306    cacheCompletionEvent
307        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
308}
309
310void
311change_thread_state(int thread_number, int activate, int priority)
312{
313}
314
315Fault
316SimpleCPU::copySrcTranslate(Addr src)
317{
318    static bool no_warn = true;
319    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
320    // Only support block sizes of 64 atm.
321    assert(blk_size == 64);
322    int offset = src & (blk_size - 1);
323
324    // Make sure block doesn't span page
325    if (no_warn &&
326        (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
327        (src >> 40) != 0xfffffc) {
328        warn("Copied block source spans pages %x.", src);
329        no_warn = false;
330    }
331
332    memReq->reset(src & ~(blk_size - 1), blk_size);
333
334    // translate to physical address
335    Fault fault = xc->translateDataReadReq(memReq);
336
337    assert(fault != Alignment_Fault);
338
339    if (fault == No_Fault) {
340        xc->copySrcAddr = src;
341        xc->copySrcPhysAddr = memReq->paddr + offset;
342    } else {
343        xc->copySrcAddr = 0;
344        xc->copySrcPhysAddr = 0;
345    }
346    return fault;
347}
348
349Fault
350SimpleCPU::copy(Addr dest)
351{
352    static bool no_warn = true;
353    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
354    // Only support block sizes of 64 atm.
355    assert(blk_size == 64);
356    uint8_t data[blk_size];
357    //assert(xc->copySrcAddr);
358    int offset = dest & (blk_size - 1);
359
360    // Make sure block doesn't span page
361    if (no_warn &&
362        (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
363        (dest >> 40) != 0xfffffc) {
364        no_warn = false;
365        warn("Copied block destination spans pages %x. ", dest);
366    }
367
368    memReq->reset(dest & ~(blk_size -1), blk_size);
369    // translate to physical address
370    Fault fault = xc->translateDataWriteReq(memReq);
371
372    assert(fault != Alignment_Fault);
373
374    if (fault == No_Fault) {
375        Addr dest_addr = memReq->paddr + offset;
376        // Need to read straight from memory since we have more than 8 bytes.
377        memReq->paddr = xc->copySrcPhysAddr;
378        xc->mem->read(memReq, data);
379        memReq->paddr = dest_addr;
380        xc->mem->write(memReq, data);
381        if (dcacheInterface) {
382            memReq->cmd = Copy;
383            memReq->completionEvent = NULL;
384            memReq->paddr = xc->copySrcPhysAddr;
385            memReq->dest = dest_addr;
386            memReq->size = 64;
387            memReq->time = curTick;
388            memReq->flags &= ~INST_READ;
389            dcacheInterface->access(memReq);
390        }
391    }
392    return fault;
393}
394
395// precise architected memory state accessor macros
396template <class T>
397Fault
398SimpleCPU::read(Addr addr, T &data, unsigned flags)
399{
400    if (status() == DcacheMissStall || status() == DcacheMissSwitch) {
401        Fault fault = xc->read(memReq,data);
402
403        if (traceData) {
404            traceData->setAddr(addr);
405        }
406        return fault;
407    }
408
409    memReq->reset(addr, sizeof(T), flags);
410
411    // translate to physical address
412    Fault fault = xc->translateDataReadReq(memReq);
413
414    // if we have a cache, do cache access too
415    if (fault == No_Fault && dcacheInterface) {
416        memReq->cmd = Read;
417        memReq->completionEvent = NULL;
418        memReq->time = curTick;
419        memReq->flags &= ~INST_READ;
420        MemAccessResult result = dcacheInterface->access(memReq);
421
422        // Ugly hack to get an event scheduled *only* if the access is
423        // a miss.  We really should add first-class support for this
424        // at some point.
425        if (result != MA_HIT && dcacheInterface->doEvents()) {
426            memReq->completionEvent = &cacheCompletionEvent;
427            lastDcacheStall = curTick;
428            unscheduleTickEvent();
429            _status = DcacheMissStall;
430        } else {
431            // do functional access
432            fault = xc->read(memReq, data);
433
434        }
435    } else if(fault == No_Fault) {
436        // do functional access
437        fault = xc->read(memReq, data);
438
439    }
440
441    if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
442        recordEvent("Uncached Read");
443
444    return fault;
445}
446
447#ifndef DOXYGEN_SHOULD_SKIP_THIS
448
449template
450Fault
451SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
452
453template
454Fault
455SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
456
457template
458Fault
459SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
460
461template
462Fault
463SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
464
465#endif //DOXYGEN_SHOULD_SKIP_THIS
466
467template<>
468Fault
469SimpleCPU::read(Addr addr, double &data, unsigned flags)
470{
471    return read(addr, *(uint64_t*)&data, flags);
472}
473
474template<>
475Fault
476SimpleCPU::read(Addr addr, float &data, unsigned flags)
477{
478    return read(addr, *(uint32_t*)&data, flags);
479}
480
481
482template<>
483Fault
484SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
485{
486    return read(addr, (uint32_t&)data, flags);
487}
488
489
490template <class T>
491Fault
492SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
493{
494    memReq->reset(addr, sizeof(T), flags);
495
496    // translate to physical address
497    Fault fault = xc->translateDataWriteReq(memReq);
498
499    // do functional access
500    if (fault == No_Fault)
501        fault = xc->write(memReq, data);
502
503    if (fault == No_Fault && dcacheInterface) {
504        memReq->cmd = Write;
505        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
506        memReq->completionEvent = NULL;
507        memReq->time = curTick;
508        memReq->flags &= ~INST_READ;
509        MemAccessResult result = dcacheInterface->access(memReq);
510
511        // Ugly hack to get an event scheduled *only* if the access is
512        // a miss.  We really should add first-class support for this
513        // at some point.
514        if (result != MA_HIT && dcacheInterface->doEvents()) {
515            memReq->completionEvent = &cacheCompletionEvent;
516            lastDcacheStall = curTick;
517            unscheduleTickEvent();
518            _status = DcacheMissStall;
519        }
520    }
521
522    if (res && (fault == No_Fault))
523        *res = memReq->result;
524
525    if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
526        recordEvent("Uncached Write");
527
528    return fault;
529}
530
531
532#ifndef DOXYGEN_SHOULD_SKIP_THIS
533template
534Fault
535SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
536
537template
538Fault
539SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
540
541template
542Fault
543SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
544
545template
546Fault
547SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
548
549#endif //DOXYGEN_SHOULD_SKIP_THIS
550
551template<>
552Fault
553SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
554{
555    return write(*(uint64_t*)&data, addr, flags, res);
556}
557
558template<>
559Fault
560SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
561{
562    return write(*(uint32_t*)&data, addr, flags, res);
563}
564
565
566template<>
567Fault
568SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
569{
570    return write((uint32_t)data, addr, flags, res);
571}
572
573
574#if FULL_SYSTEM
575Addr
576SimpleCPU::dbg_vtophys(Addr addr)
577{
578    return vtophys(xc, addr);
579}
580#endif // FULL_SYSTEM
581
582void
583SimpleCPU::processCacheCompletion()
584{
585    switch (status()) {
586      case IcacheMissStall:
587        icacheStallCycles += curTick - lastIcacheStall;
588        _status = IcacheMissComplete;
589        scheduleTickEvent(1);
590        break;
591      case DcacheMissStall:
592        if (memReq->cmd.isRead()) {
593            curStaticInst->execute(this,traceData);
594            if (traceData)
595                traceData->finalize();
596        }
597        dcacheStallCycles += curTick - lastDcacheStall;
598        _status = Running;
599        scheduleTickEvent(1);
600        break;
601      case DcacheMissSwitch:
602        if (memReq->cmd.isRead()) {
603            curStaticInst->execute(this,traceData);
604            if (traceData)
605                traceData->finalize();
606        }
607        _status = SwitchedOut;
608        sampler->signalSwitched();
609      case SwitchedOut:
610        // If this CPU has been switched out due to sampling/warm-up,
611        // ignore any further status changes (e.g., due to cache
612        // misses outstanding at the time of the switch).
613        return;
614      default:
615        panic("SimpleCPU::processCacheCompletion: bad state");
616        break;
617    }
618}
619
620#if FULL_SYSTEM
621void
622SimpleCPU::post_interrupt(int int_num, int index)
623{
624    BaseCPU::post_interrupt(int_num, index);
625
626    if (xc->status() == ExecContext::Suspended) {
627                DPRINTF(IPI,"Suspended Processor awoke\n");
628        xc->activate();
629    }
630}
631#endif // FULL_SYSTEM
632
633/* start simulation, program loaded, processor precise state initialized */
634void
635SimpleCPU::tick()
636{
637    numCycles++;
638
639    traceData = NULL;
640
641    Fault fault = No_Fault;
642
643#if FULL_SYSTEM
644    if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
645        status() != IcacheMissComplete) {
646        int ipl = 0;
647        int summary = 0;
648        checkInterrupts = false;
649        IntReg *ipr = xc->regs.ipr;
650
651        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
652            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
653                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
654                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
655                    // See table 4-19 of 21164 hardware reference
656                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
657                    summary |= (ULL(1) << i);
658                }
659            }
660        }
661
662        uint64_t interrupts = xc->cpu->intr_status();
663        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
664            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
665            if (interrupts & (ULL(1) << i)) {
666                // See table 4-19 of 21164 hardware reference
667                ipl = i;
668                summary |= (ULL(1) << i);
669            }
670        }
671
672        if (ipr[TheISA::IPR_ASTRR])
673            panic("asynchronous traps not implemented\n");
674
675        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
676            ipr[TheISA::IPR_ISR] = summary;
677            ipr[TheISA::IPR_INTID] = ipl;
678            xc->ev5_trap(Interrupt_Fault);
679
680            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
681                    ipr[TheISA::IPR_IPLR], ipl, summary);
682        }
683    }
684#endif
685
686    // maintain $r0 semantics
687    xc->regs.intRegFile[ZeroReg] = 0;
688#ifdef TARGET_ALPHA
689    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
690#endif // TARGET_ALPHA
691
692    if (status() == IcacheMissComplete) {
693        // We've already fetched an instruction and were stalled on an
694        // I-cache miss.  No need to fetch it again.
695
696        // Set status to running; tick event will get rescheduled if
697        // necessary at end of tick() function.
698        _status = Running;
699    }
700    else {
701        // Try to fetch an instruction
702
703        // set up memory request for instruction fetch
704#if FULL_SYSTEM
705#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
706#else
707#define IFETCH_FLAGS(pc)	0
708#endif
709
710        memReq->cmd = Read;
711        memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
712                     IFETCH_FLAGS(xc->regs.pc));
713
714        fault = xc->translateInstReq(memReq);
715
716        if (fault == No_Fault)
717            fault = xc->mem->read(memReq, inst);
718
719        if (icacheInterface && fault == No_Fault) {
720            memReq->completionEvent = NULL;
721
722            memReq->time = curTick;
723            memReq->flags |= INST_READ;
724            MemAccessResult result = icacheInterface->access(memReq);
725
726            // Ugly hack to get an event scheduled *only* if the access is
727            // a miss.  We really should add first-class support for this
728            // at some point.
729            if (result != MA_HIT && icacheInterface->doEvents()) {
730                memReq->completionEvent = &cacheCompletionEvent;
731                lastIcacheStall = curTick;
732                unscheduleTickEvent();
733                _status = IcacheMissStall;
734                return;
735            }
736        }
737    }
738
739    // If we've got a valid instruction (i.e., no fault on instruction
740    // fetch), then execute it.
741    if (fault == No_Fault) {
742
743        // keep an instruction count
744        numInst++;
745        numInsts++;
746
747        // check for instruction-count-based events
748        comInstEventQueue[0]->serviceEvents(numInst);
749
750        // decode the instruction
751        inst = gtoh(inst);
752        curStaticInst = StaticInst<TheISA>::decode(inst);
753
754        traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
755                                         xc->regs.pc);
756
757#if FULL_SYSTEM
758        xc->setInst(inst);
759#endif // FULL_SYSTEM
760
761        xc->func_exe_inst++;
762
763        fault = curStaticInst->execute(this, traceData);
764
765#if FULL_SYSTEM
766        if (xc->fnbin) {
767            assert(xc->kernelStats);
768            system->kernelBinning->execute(xc, inst);
769        }
770
771        if (xc->profile) {
772            bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
773            xc->profilePC = usermode ? 1 : xc->regs.pc;
774            ProfileNode *node = xc->profile->consume(xc, inst);
775            if (node)
776                xc->profileNode = node;
777        }
778#endif
779
780        if (curStaticInst->isMemRef()) {
781            numMemRefs++;
782        }
783
784        if (curStaticInst->isLoad()) {
785            ++numLoad;
786            comLoadEventQueue[0]->serviceEvents(numLoad);
787        }
788
789        // If we have a dcache miss, then we can't finialize the instruction
790        // trace yet because we want to populate it with the data later
791        if (traceData &&
792                !(status() == DcacheMissStall && memReq->cmd.isRead())) {
793            traceData->finalize();
794        }
795
796        traceFunctions(xc->regs.pc);
797
798    }	// if (fault == No_Fault)
799
800    if (fault != No_Fault) {
801#if FULL_SYSTEM
802        xc->ev5_trap(fault);
803#else // !FULL_SYSTEM
804        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
805#endif // FULL_SYSTEM
806    }
807    else {
808        // go to the next instruction
809        xc->regs.pc = xc->regs.npc;
810        xc->regs.npc += sizeof(MachInst);
811    }
812
813#if FULL_SYSTEM
814    Addr oldpc;
815    do {
816        oldpc = xc->regs.pc;
817        system->pcEventQueue.service(xc);
818    } while (oldpc != xc->regs.pc);
819#endif
820
821    assert(status() == Running ||
822           status() == Idle ||
823           status() == DcacheMissStall);
824
825    if (status() == Running && !tickEvent.scheduled())
826        tickEvent.schedule(curTick + cycles(1));
827}
828
829////////////////////////////////////////////////////////////////////////
830//
831//  SimpleCPU Simulation Object
832//
833BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
834
835    Param<Counter> max_insts_any_thread;
836    Param<Counter> max_insts_all_threads;
837    Param<Counter> max_loads_any_thread;
838    Param<Counter> max_loads_all_threads;
839
840#if FULL_SYSTEM
841    SimObjectParam<AlphaITB *> itb;
842    SimObjectParam<AlphaDTB *> dtb;
843    SimObjectParam<FunctionalMemory *> mem;
844    SimObjectParam<System *> system;
845    Param<int> cpu_id;
846    Param<Tick> profile;
847#else
848    SimObjectParam<Process *> workload;
849#endif // FULL_SYSTEM
850
851    Param<int> clock;
852    SimObjectParam<BaseMem *> icache;
853    SimObjectParam<BaseMem *> dcache;
854
855    Param<bool> defer_registration;
856    Param<int> width;
857    Param<bool> function_trace;
858    Param<Tick> function_trace_start;
859
860END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
861
862BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
863
864    INIT_PARAM(max_insts_any_thread,
865               "terminate when any thread reaches this inst count"),
866    INIT_PARAM(max_insts_all_threads,
867               "terminate when all threads have reached this inst count"),
868    INIT_PARAM(max_loads_any_thread,
869               "terminate when any thread reaches this load count"),
870    INIT_PARAM(max_loads_all_threads,
871               "terminate when all threads have reached this load count"),
872
873#if FULL_SYSTEM
874    INIT_PARAM(itb, "Instruction TLB"),
875    INIT_PARAM(dtb, "Data TLB"),
876    INIT_PARAM(mem, "memory"),
877    INIT_PARAM(system, "system object"),
878    INIT_PARAM(cpu_id, "processor ID"),
879    INIT_PARAM(profile, ""),
880#else
881    INIT_PARAM(workload, "processes to run"),
882#endif // FULL_SYSTEM
883
884    INIT_PARAM(clock, "clock speed"),
885    INIT_PARAM(icache, "L1 instruction cache object"),
886    INIT_PARAM(dcache, "L1 data cache object"),
887    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
888    INIT_PARAM(width, "cpu width"),
889    INIT_PARAM(function_trace, "Enable function trace"),
890    INIT_PARAM(function_trace_start, "Cycle to start function trace")
891
892END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
893
894
895CREATE_SIM_OBJECT(SimpleCPU)
896{
897    SimpleCPU::Params *params = new SimpleCPU::Params();
898    params->name = getInstanceName();
899    params->numberOfThreads = 1;
900    params->max_insts_any_thread = max_insts_any_thread;
901    params->max_insts_all_threads = max_insts_all_threads;
902    params->max_loads_any_thread = max_loads_any_thread;
903    params->max_loads_all_threads = max_loads_all_threads;
904    params->deferRegistration = defer_registration;
905    params->clock = clock;
906    params->functionTrace = function_trace;
907    params->functionTraceStart = function_trace_start;
908    params->icache_interface = (icache) ? icache->getInterface() : NULL;
909    params->dcache_interface = (dcache) ? dcache->getInterface() : NULL;
910    params->width = width;
911
912#if FULL_SYSTEM
913    params->itb = itb;
914    params->dtb = dtb;
915    params->mem = mem;
916    params->system = system;
917    params->cpu_id = cpu_id;
918    params->profile = profile;
919#else
920    params->process = workload;
921#endif
922
923    SimpleCPU *cpu = new SimpleCPU(params);
924    return cpu;
925}
926
927REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
928
929