base.cc revision 1133
12SN/A/* 27338SAli.Saidi@ARM.com * Copyright (c) 2002-2004 The Regents of The University of Michigan 37338SAli.Saidi@ARM.com * All rights reserved. 47338SAli.Saidi@ARM.com * 57338SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 67338SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 77338SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 87338SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 97338SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 107338SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 117338SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 127338SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 137338SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 141762SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272SN/A */ 282SN/A 292SN/A#include <cmath> 302SN/A#include <cstdio> 312SN/A#include <cstdlib> 322SN/A#include <iostream> 332SN/A#include <iomanip> 342SN/A#include <list> 352SN/A#include <sstream> 362SN/A#include <string> 372SN/A 382SN/A#include "base/cprintf.hh" 392665Ssaidi@eecs.umich.edu#include "base/inifile.hh" 402665Ssaidi@eecs.umich.edu#include "base/loader/symtab.hh" 412SN/A#include "base/misc.hh" 422SN/A#include "base/pollevent.hh" 436216Snate@binkert.org#include "base/range.hh" 442439SN/A#include "base/trace.hh" 458229Snate@binkert.org#include "base/stats/events.hh" 466216Snate@binkert.org#include "cpu/base_cpu.hh" 47146SN/A#include "cpu/exec_context.hh" 48146SN/A#include "cpu/exetrace.hh" 49146SN/A#include "cpu/full_cpu/smt.hh" 50146SN/A#include "cpu/simple_cpu/simple_cpu.hh" 51146SN/A#include "cpu/static_inst.hh" 52146SN/A#include "mem/base_mem.hh" 536216Snate@binkert.org#include "mem/mem_interface.hh" 546658Snate@binkert.org#include "sim/builder.hh" 558229Snate@binkert.org#include "sim/debug.hh" 561717SN/A#include "sim/host.hh" 57146SN/A#include "sim/sim_events.hh" 581977SN/A#include "sim/sim_object.hh" 592683Sktlim@umich.edu#include "sim/stats.hh" 601717SN/A 61146SN/A#ifdef FULL_SYSTEM 622683Sktlim@umich.edu#include "base/remote_gdb.hh" 638232Snate@binkert.org#include "dev/alpha_access.h" 648232Snate@binkert.org#include "dev/pciareg.h" 658232Snate@binkert.org#include "mem/functional_mem/memory_control.hh" 663348Sbinkertn@umich.edu#include "mem/functional_mem/physical_memory.hh" 676105Ssteve.reinhardt@amd.com#include "sim/system.hh" 686216Snate@binkert.org#include "targetarch/alpha_memory.hh" 692036SN/A#include "targetarch/vtophys.hh" 70146SN/A#else // !FULL_SYSTEM 7156SN/A#include "eio/eio.hh" 7256SN/A#include "mem/functional_mem/functional_memory.hh" 73695SN/A#endif // FULL_SYSTEM 742901Ssaidi@eecs.umich.edu 752SN/Ausing namespace std; 761858SN/A 773565Sgblack@eecs.umich.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c) 783565Sgblack@eecs.umich.edu : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), multiplier(1) 792171SN/A{ 802170SN/A} 81146SN/A 822462SN/Avoid 83146SN/ASimpleCPU::TickEvent::process() 842SN/A{ 852SN/A int count = multiplier; 862449SN/A do { 871355SN/A cpu->tick(); 885529Snate@binkert.org } while (--count > 0 && cpu->status() == Running); 894495Sacolyte@umich.edu} 90224SN/A 911858SN/Aconst char * 922683Sktlim@umich.eduSimpleCPU::TickEvent::description() 932420SN/A{ 945529Snate@binkert.org return "SimpleCPU tick event"; 956331Sgblack@eecs.umich.edu} 962420SN/A 972SN/A 986029Ssteve.reinhardt@amd.comSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 992672Sktlim@umich.edu : Event(&mainEventQueue), 1002683Sktlim@umich.edu cpu(_cpu) 1012SN/A{ 1022SN/A} 103334SN/A 104140SN/Avoid SimpleCPU::CacheCompletionEvent::process() 105334SN/A{ 1062SN/A cpu->processCacheCompletion(); 1072SN/A} 1082SN/A 1092680Sktlim@umich.educonst char * 1104377Sgblack@eecs.umich.eduSimpleCPU::CacheCompletionEvent::description() 1115169Ssaidi@eecs.umich.edu{ 1124377Sgblack@eecs.umich.edu return "SimpleCPU cache completion event"; 1134377Sgblack@eecs.umich.edu} 1142SN/A 1152SN/A#ifdef FULL_SYSTEM 1162623SN/ASimpleCPU::SimpleCPU(const string &_name, 1172SN/A System *_system, 1182SN/A Counter max_insts_any_thread, 1192SN/A Counter max_insts_all_threads, 120180SN/A Counter max_loads_any_thread, 1212623SN/A Counter max_loads_all_threads, 122393SN/A AlphaITB *itb, AlphaDTB *dtb, 123393SN/A FunctionalMemory *mem, 124393SN/A MemInterface *icache_interface, 125393SN/A MemInterface *dcache_interface, 126384SN/A bool _def_reg, Tick freq) 127384SN/A : BaseCPU(_name, /* number_of_threads */ 1, _def_reg, 128393SN/A max_insts_any_thread, max_insts_all_threads, 1292623SN/A max_loads_any_thread, max_loads_all_threads, 130393SN/A _system, freq), 131393SN/A#else 132393SN/ASimpleCPU::SimpleCPU(const string &_name, Process *_process, 133393SN/A Counter max_insts_any_thread, 134384SN/A Counter max_insts_all_threads, 135189SN/A Counter max_loads_any_thread, 136189SN/A Counter max_loads_all_threads, 1372623SN/A MemInterface *icache_interface, 1382SN/A MemInterface *dcache_interface, 139729SN/A bool _def_reg) 140334SN/A : BaseCPU(_name, /* number_of_threads */ 1, _def_reg, 1412SN/A max_insts_any_thread, max_insts_all_threads, 1422SN/A max_loads_any_thread, max_loads_all_threads), 1432SN/A#endif 1442SN/A tickEvent(this), xc(NULL), cacheCompletionEvent(this) 1452SN/A{ 1462SN/A _status = Idle; 1472SN/A#ifdef FULL_SYSTEM 1487897Shestness@cs.utexas.edu xc = new ExecContext(this, 0, system, itb, dtb, mem); 1497897Shestness@cs.utexas.edu 1507897Shestness@cs.utexas.edu // initialize CPU, including PC 1517897Shestness@cs.utexas.edu TheISA::initCPU(&xc->regs); 1527897Shestness@cs.utexas.edu#else 1537897Shestness@cs.utexas.edu xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); 1547897Shestness@cs.utexas.edu#endif // !FULL_SYSTEM 1557897Shestness@cs.utexas.edu 1567897Shestness@cs.utexas.edu icacheInterface = icache_interface; 1577897Shestness@cs.utexas.edu dcacheInterface = dcache_interface; 1587897Shestness@cs.utexas.edu 1597897Shestness@cs.utexas.edu memReq = new MemReq(); 1607897Shestness@cs.utexas.edu memReq->xc = xc; 1617897Shestness@cs.utexas.edu memReq->asid = 0; 1627897Shestness@cs.utexas.edu memReq->data = new uint8_t[64]; 1637897Shestness@cs.utexas.edu 1647897Shestness@cs.utexas.edu numInst = 0; 1657897Shestness@cs.utexas.edu startNumInst = 0; 1667897Shestness@cs.utexas.edu numLoad = 0; 1677897Shestness@cs.utexas.edu startNumLoad = 0; 1687897Shestness@cs.utexas.edu lastIcacheStall = 0; 1697897Shestness@cs.utexas.edu lastDcacheStall = 0; 1707897Shestness@cs.utexas.edu 1717897Shestness@cs.utexas.edu execContexts.push_back(xc); 1727897Shestness@cs.utexas.edu} 1737897Shestness@cs.utexas.edu 1747897Shestness@cs.utexas.eduSimpleCPU::~SimpleCPU() 1757897Shestness@cs.utexas.edu{ 1767897Shestness@cs.utexas.edu} 1777897Shestness@cs.utexas.edu 1787897Shestness@cs.utexas.eduvoid 1797897Shestness@cs.utexas.eduSimpleCPU::switchOut() 1807897Shestness@cs.utexas.edu{ 1817897Shestness@cs.utexas.edu _status = SwitchedOut; 1827897Shestness@cs.utexas.edu if (tickEvent.scheduled()) 1837897Shestness@cs.utexas.edu tickEvent.squash(); 1847897Shestness@cs.utexas.edu} 1857897Shestness@cs.utexas.edu 1867897Shestness@cs.utexas.edu 1877897Shestness@cs.utexas.eduvoid 1887897Shestness@cs.utexas.eduSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1897897Shestness@cs.utexas.edu{ 1907897Shestness@cs.utexas.edu BaseCPU::takeOverFrom(oldCPU); 1917897Shestness@cs.utexas.edu 1927897Shestness@cs.utexas.edu assert(!tickEvent.scheduled()); 1937897Shestness@cs.utexas.edu 1947897Shestness@cs.utexas.edu // if any of this CPU's ExecContexts are active, mark the CPU as 1957897Shestness@cs.utexas.edu // running and schedule its tick event. 1967897Shestness@cs.utexas.edu for (int i = 0; i < execContexts.size(); ++i) { 1977897Shestness@cs.utexas.edu ExecContext *xc = execContexts[i]; 1982SN/A if (xc->status() == ExecContext::Active && _status != Running) { 1997897Shestness@cs.utexas.edu _status = Running; 2007897Shestness@cs.utexas.edu tickEvent.schedule(curTick); 2017897Shestness@cs.utexas.edu } 2027897Shestness@cs.utexas.edu } 2037897Shestness@cs.utexas.edu 2047897Shestness@cs.utexas.edu oldCPU->switchOut(); 2057897Shestness@cs.utexas.edu} 2067897Shestness@cs.utexas.edu 2077897Shestness@cs.utexas.edu 2087897Shestness@cs.utexas.eduvoid 2097897Shestness@cs.utexas.eduSimpleCPU::activateContext(int thread_num, int delay) 2107897Shestness@cs.utexas.edu{ 2112SN/A assert(thread_num == 0); 2122SN/A assert(xc); 2131001SN/A 2141001SN/A assert(_status == Idle); 2151001SN/A notIdleFraction++; 2161001SN/A scheduleTickEvent(delay); 2171001SN/A _status = Running; 2182SN/A} 2192SN/A 2202SN/A 2212SN/Avoid 2222SN/ASimpleCPU::suspendContext(int thread_num) 2237897Shestness@cs.utexas.edu{ 2247897Shestness@cs.utexas.edu assert(thread_num == 0); 2257897Shestness@cs.utexas.edu assert(xc); 2267897Shestness@cs.utexas.edu 2277897Shestness@cs.utexas.edu assert(_status == Running); 2287897Shestness@cs.utexas.edu notIdleFraction--; 2297897Shestness@cs.utexas.edu unscheduleTickEvent(); 2307897Shestness@cs.utexas.edu _status = Idle; 2317897Shestness@cs.utexas.edu} 2327897Shestness@cs.utexas.edu 2332SN/A 2342SN/Avoid 2352SN/ASimpleCPU::deallocateContext(int thread_num) 2362SN/A{ 2372SN/A // for now, these are equivalent 2382SN/A suspendContext(thread_num); 2392SN/A} 2402SN/A 2412SN/A 2422SN/Avoid 2432SN/ASimpleCPU::haltContext(int thread_num) 2442SN/A{ 2452390SN/A // for now, these are equivalent 2462390SN/A suspendContext(thread_num); 2472390SN/A} 2482390SN/A 2492390SN/A 2502390SN/Avoid 2512390SN/ASimpleCPU::regStats() 2522390SN/A{ 2532390SN/A using namespace Stats; 2542390SN/A 2552390SN/A BaseCPU::regStats(); 2562390SN/A 257385SN/A numInsts 2587897Shestness@cs.utexas.edu .name(name() + ".num_insts") 2597897Shestness@cs.utexas.edu .desc("Number of instructions executed") 2602SN/A ; 2612SN/A 2622SN/A numMemRefs 2632623SN/A .name(name() + ".num_refs") 264334SN/A .desc("Number of memory references") 2652361SN/A ; 2665496Ssaidi@eecs.umich.edu 267334SN/A notIdleFraction 268334SN/A .name(name() + ".not_idle_fraction") 269334SN/A .desc("Percentage of non-idle cycles") 2702623SN/A ; 2712SN/A 2725496Ssaidi@eecs.umich.edu idleFraction 273921SN/A .name(name() + ".idle_fraction") 2742915Sktlim@umich.edu .desc("Percentage of idle cycles") 2752915Sktlim@umich.edu ; 2762683Sktlim@umich.edu 2772SN/A icacheStallCycles 2782SN/A .name(name() + ".icache_stall_cycles") 2792SN/A .desc("ICache total stall cycles") 2802623SN/A .prereq(icacheStallCycles) 2812SN/A ; 2825496Ssaidi@eecs.umich.edu 283921SN/A dcacheStallCycles 2842915Sktlim@umich.edu .name(name() + ".dcache_stall_cycles") 2852915Sktlim@umich.edu .desc("DCache total stall cycles") 2862SN/A .prereq(dcacheStallCycles) 2872SN/A ; 2882SN/A 2896221Snate@binkert.org idleFraction = constant(1.0) - notIdleFraction; 2902SN/A} 2912SN/A 2922SN/Avoid 2931858SN/ASimpleCPU::resetStats() 2942SN/A{ 2952623SN/A startNumInst = numInst; 2962SN/A notIdleFraction = (_status != Idle); 2972680Sktlim@umich.edu} 2982SN/A 2992SN/Avoid 3002SN/ASimpleCPU::serialize(ostream &os) 3011858SN/A{ 3022SN/A BaseCPU::serialize(os); 3035807Snate@binkert.org SERIALIZE_ENUM(_status); 3042SN/A SERIALIZE_SCALAR(inst); 3055807Snate@binkert.org nameOut(os, csprintf("%s.xc", name())); 3065807Snate@binkert.org xc->serialize(os); 3072SN/A nameOut(os, csprintf("%s.tickEvent", name())); 3085807Snate@binkert.org tickEvent.serialize(os); 3095807Snate@binkert.org nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 3102SN/A cacheCompletionEvent.serialize(os); 3112SN/A} 3122SN/A 3132SN/Avoid 3142623SN/ASimpleCPU::unserialize(Checkpoint *cp, const string §ion) 3152SN/A{ 3161858SN/A BaseCPU::unserialize(cp, section); 3175704Snate@binkert.org UNSERIALIZE_ENUM(_status); 3185647Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(inst); 3192SN/A xc->unserialize(cp, csprintf("%s.xc", section)); 3203520Sgblack@eecs.umich.edu tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 3217338SAli.Saidi@ARM.com cacheCompletionEvent 3225647Sgblack@eecs.umich.edu .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); 3233520Sgblack@eecs.umich.edu} 3247408Sgblack@eecs.umich.edu 3252SN/Avoid 3262SN/Achange_thread_state(int thread_number, int activate, int priority) 3272SN/A{ 3282623SN/A} 3292SN/A 3302623SN/AFault 3315894Sgblack@eecs.umich.eduSimpleCPU::copySrcTranslate(Addr src) 3322662Sstever@eecs.umich.edu{ 3332623SN/A static bool no_warn = true; 3347720Sgblack@eecs.umich.edu int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3354495Sacolyte@umich.edu // Only support block sizes of 64 atm. 3362623SN/A assert(blk_size == 64); 3377720Sgblack@eecs.umich.edu int offset = src & (blk_size - 1); 3382623SN/A 3397720Sgblack@eecs.umich.edu // Make sure block doesn't span page 3407720Sgblack@eecs.umich.edu if (no_warn && 3412623SN/A (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && 3422623SN/A (src >> 40) != 0xfffffc) { 3432623SN/A warn("Copied block source spans pages %x.", src); 3442623SN/A no_warn = false; 3452623SN/A } 3462623SN/A 3472SN/A memReq->reset(src & ~(blk_size - 1), blk_size); 3482683Sktlim@umich.edu 3492427SN/A // translate to physical address 3502683Sktlim@umich.edu Fault fault = xc->translateDataReadReq(memReq); 3512427SN/A 3522SN/A assert(fault != Alignment_Fault); 3532623SN/A 3542623SN/A if (fault == No_Fault) { 3557897Shestness@cs.utexas.edu xc->copySrcAddr = src; 3562SN/A xc->copySrcPhysAddr = memReq->paddr + offset; 3572623SN/A } else { 3582623SN/A xc->copySrcAddr = 0; 3594377Sgblack@eecs.umich.edu xc->copySrcPhysAddr = 0; 3607720Sgblack@eecs.umich.edu } 3614377Sgblack@eecs.umich.edu return fault; 3627720Sgblack@eecs.umich.edu} 3635665Sgblack@eecs.umich.edu 3647720Sgblack@eecs.umich.eduFault 3657720Sgblack@eecs.umich.eduSimpleCPU::copy(Addr dest) 3665665Sgblack@eecs.umich.edu{ 3675665Sgblack@eecs.umich.edu static bool no_warn = true; 3684181Sgblack@eecs.umich.edu int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3694181Sgblack@eecs.umich.edu // Only support block sizes of 64 atm. 3704181Sgblack@eecs.umich.edu assert(blk_size == 64); 3714182Sgblack@eecs.umich.edu uint8_t data[blk_size]; 3724182Sgblack@eecs.umich.edu //assert(xc->copySrcAddr); 3734182Sgblack@eecs.umich.edu int offset = dest & (blk_size - 1); 3747720Sgblack@eecs.umich.edu 3754593Sgblack@eecs.umich.edu // Make sure block doesn't span page 3767720Sgblack@eecs.umich.edu if (no_warn && 3774593Sgblack@eecs.umich.edu (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && 3784593Sgblack@eecs.umich.edu (dest >> 40) != 0xfffffc) { 3794377Sgblack@eecs.umich.edu no_warn = false; 3804377Sgblack@eecs.umich.edu warn("Copied block destination spans pages %x. ", dest); 3814377Sgblack@eecs.umich.edu } 3824377Sgblack@eecs.umich.edu 3834377Sgblack@eecs.umich.edu memReq->reset(dest & ~(blk_size -1), blk_size); 3847720Sgblack@eecs.umich.edu // translate to physical address 3857720Sgblack@eecs.umich.edu Fault fault = xc->translateDataWriteReq(memReq); 3868541Sgblack@eecs.umich.edu 3874377Sgblack@eecs.umich.edu assert(fault != Alignment_Fault); 3884377Sgblack@eecs.umich.edu 3894377Sgblack@eecs.umich.edu if (fault == No_Fault) { 3904377Sgblack@eecs.umich.edu Addr dest_addr = memReq->paddr + offset; 3914181Sgblack@eecs.umich.edu // Need to read straight from memory since we have more than 8 bytes. 3924181Sgblack@eecs.umich.edu memReq->paddr = xc->copySrcPhysAddr; 3934181Sgblack@eecs.umich.edu xc->mem->read(memReq, data); 3944539Sgblack@eecs.umich.edu memReq->paddr = dest_addr; 3953276Sgblack@eecs.umich.edu xc->mem->write(memReq, data); 3967720Sgblack@eecs.umich.edu if (dcacheInterface) { 3973280Sgblack@eecs.umich.edu memReq->cmd = Copy; 3983280Sgblack@eecs.umich.edu memReq->completionEvent = NULL; 3993276Sgblack@eecs.umich.edu memReq->paddr = xc->copySrcPhysAddr; 4003276Sgblack@eecs.umich.edu memReq->dest = dest_addr; 4013276Sgblack@eecs.umich.edu memReq->size = 64; 4027720Sgblack@eecs.umich.edu memReq->time = curTick; 4033276Sgblack@eecs.umich.edu dcacheInterface->access(memReq); 4043276Sgblack@eecs.umich.edu } 4054181Sgblack@eecs.umich.edu } 4064181Sgblack@eecs.umich.edu return fault; 4074181Sgblack@eecs.umich.edu} 4084522Ssaidi@eecs.umich.edu 4097823Ssteve.reinhardt@amd.com// precise architected memory state accessor macros 4107720Sgblack@eecs.umich.edutemplate <class T> 4112470SN/AFault 4124181Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, T &data, unsigned flags) 4134181Sgblack@eecs.umich.edu{ 4144522Ssaidi@eecs.umich.edu memReq->reset(addr, sizeof(T), flags); 4154181Sgblack@eecs.umich.edu 4162623SN/A // translate to physical address 4172623SN/A Fault fault = xc->translateDataReadReq(memReq); 4182623SN/A 4192623SN/A // do functional access 4202623SN/A if (fault == No_Fault) 4217720Sgblack@eecs.umich.edu fault = xc->read(memReq, data); 4227720Sgblack@eecs.umich.edu 4237720Sgblack@eecs.umich.edu if (traceData) { 4247720Sgblack@eecs.umich.edu traceData->setAddr(addr); 4252623SN/A if (fault == No_Fault) 4267720Sgblack@eecs.umich.edu traceData->setData(data); 4273577Sgblack@eecs.umich.edu } 4287720Sgblack@eecs.umich.edu 4295086Sgblack@eecs.umich.edu // if we have a cache, do cache access too 4302623SN/A if (fault == No_Fault && dcacheInterface) { 4312683Sktlim@umich.edu memReq->cmd = Read; 4322623SN/A memReq->completionEvent = NULL; 4332420SN/A memReq->time = curTick; 4342SN/A MemAccessResult result = dcacheInterface->access(memReq); 4352623SN/A 4362623SN/A // Ugly hack to get an event scheduled *only* if the access is 4372SN/A // a miss. We really should add first-class support for this 4382SN/A // at some point. 4392623SN/A if (result != MA_HIT && dcacheInterface->doEvents()) { 4402623SN/A memReq->completionEvent = &cacheCompletionEvent; 4412623SN/A lastDcacheStall = curTick; 4422623SN/A unscheduleTickEvent(); 4432SN/A _status = DcacheMissStall; 4445953Ssaidi@eecs.umich.edu } 4457720Sgblack@eecs.umich.edu } 4465953Ssaidi@eecs.umich.edu 4475953Ssaidi@eecs.umich.edu if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 4487897Shestness@cs.utexas.edu recordEvent("Uncached Read"); 4497897Shestness@cs.utexas.edu 4507897Shestness@cs.utexas.edu return fault; 4517897Shestness@cs.utexas.edu} 4527897Shestness@cs.utexas.edu 4537897Shestness@cs.utexas.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 4547897Shestness@cs.utexas.edu 4557897Shestness@cs.utexas.edutemplate 4567897Shestness@cs.utexas.eduFault 4577897Shestness@cs.utexas.eduSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 4587897Shestness@cs.utexas.edu 4597897Shestness@cs.utexas.edutemplate 4607897Shestness@cs.utexas.eduFault 4617897Shestness@cs.utexas.eduSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 4627897Shestness@cs.utexas.edu 4637897Shestness@cs.utexas.edutemplate 4647897Shestness@cs.utexas.eduFault 4657897Shestness@cs.utexas.eduSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 4667897Shestness@cs.utexas.edu 4677897Shestness@cs.utexas.edutemplate 4687897Shestness@cs.utexas.eduFault 4697897Shestness@cs.utexas.eduSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 4707897Shestness@cs.utexas.edu 4717897Shestness@cs.utexas.edu#endif //DOXYGEN_SHOULD_SKIP_THIS 4727897Shestness@cs.utexas.edu 4737897Shestness@cs.utexas.edutemplate<> 4747897Shestness@cs.utexas.eduFault 4757897Shestness@cs.utexas.eduSimpleCPU::read(Addr addr, double &data, unsigned flags) 4767897Shestness@cs.utexas.edu{ 4777897Shestness@cs.utexas.edu return read(addr, *(uint64_t*)&data, flags); 4787897Shestness@cs.utexas.edu} 4797897Shestness@cs.utexas.edu 4807897Shestness@cs.utexas.edutemplate<> 4817720Sgblack@eecs.umich.eduFault 4822644Sstever@eecs.umich.eduSimpleCPU::read(Addr addr, float &data, unsigned flags) 4832644Sstever@eecs.umich.edu{ 4844046Sbinkertn@umich.edu return read(addr, *(uint32_t*)&data, flags); 4854046Sbinkertn@umich.edu} 4864046Sbinkertn@umich.edu 4872644Sstever@eecs.umich.edu 4882623SN/Atemplate<> 4892SN/AFault 4902SN/ASimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 4912623SN/A{ 4922623SN/A return read(addr, (uint32_t&)data, flags); 4932623SN/A} 4944377Sgblack@eecs.umich.edu 4954377Sgblack@eecs.umich.edu 4962090SN/Atemplate <class T> 4973905Ssaidi@eecs.umich.eduFault 4987678Sgblack@eecs.umich.eduSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 4995120Sgblack@eecs.umich.edu{ 5004377Sgblack@eecs.umich.edu if (traceData) { 5017720Sgblack@eecs.umich.edu traceData->setAddr(addr); 5027720Sgblack@eecs.umich.edu traceData->setData(data); 5037720Sgblack@eecs.umich.edu } 5047720Sgblack@eecs.umich.edu 5057720Sgblack@eecs.umich.edu memReq->reset(addr, sizeof(T), flags); 5067720Sgblack@eecs.umich.edu 5073276Sgblack@eecs.umich.edu // translate to physical address 5082SN/A Fault fault = xc->translateDataWriteReq(memReq); 5092SN/A 5102SN/A // do functional access 5115250Sksewell@umich.edu if (fault == No_Fault) 5125222Sksewell@umich.edu fault = xc->write(memReq, data); 5135222Sksewell@umich.edu 5145222Sksewell@umich.edu if (fault == No_Fault && dcacheInterface) { 5155222Sksewell@umich.edu memReq->cmd = Write; 5165222Sksewell@umich.edu memcpy(memReq->data,(uint8_t *)&data,memReq->size); 5175222Sksewell@umich.edu memReq->completionEvent = NULL; 5185222Sksewell@umich.edu memReq->time = curTick; 5195222Sksewell@umich.edu MemAccessResult result = dcacheInterface->access(memReq); 5205222Sksewell@umich.edu 5215222Sksewell@umich.edu // Ugly hack to get an event scheduled *only* if the access is 5225222Sksewell@umich.edu // a miss. We really should add first-class support for this 5235222Sksewell@umich.edu // at some point. 5245222Sksewell@umich.edu if (result != MA_HIT && dcacheInterface->doEvents()) { 5255222Sksewell@umich.edu memReq->completionEvent = &cacheCompletionEvent; 5265222Sksewell@umich.edu lastDcacheStall = curTick; 5275222Sksewell@umich.edu unscheduleTickEvent(); 5285222Sksewell@umich.edu _status = DcacheMissStall; 5295222Sksewell@umich.edu } 5305222Sksewell@umich.edu } 5315222Sksewell@umich.edu 5325222Sksewell@umich.edu if (res && (fault == No_Fault)) 5335222Sksewell@umich.edu *res = memReq->result; 5345222Sksewell@umich.edu 5355222Sksewell@umich.edu if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 5365222Sksewell@umich.edu recordEvent("Uncached Write"); 5375222Sksewell@umich.edu 5385222Sksewell@umich.edu return fault; 5395222Sksewell@umich.edu} 5405222Sksewell@umich.edu 5415222Sksewell@umich.edu 5425222Sksewell@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 5435222Sksewell@umich.edutemplate 5445250Sksewell@umich.eduFault 545SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 546 547template 548Fault 549SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 550 551template 552Fault 553SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 554 555template 556Fault 557SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 558 559#endif //DOXYGEN_SHOULD_SKIP_THIS 560 561template<> 562Fault 563SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 564{ 565 return write(*(uint64_t*)&data, addr, flags, res); 566} 567 568template<> 569Fault 570SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 571{ 572 return write(*(uint32_t*)&data, addr, flags, res); 573} 574 575 576template<> 577Fault 578SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 579{ 580 return write((uint32_t)data, addr, flags, res); 581} 582 583 584#ifdef FULL_SYSTEM 585Addr 586SimpleCPU::dbg_vtophys(Addr addr) 587{ 588 return vtophys(xc, addr); 589} 590#endif // FULL_SYSTEM 591 592Tick save_cycle = 0; 593 594 595void 596SimpleCPU::processCacheCompletion() 597{ 598 switch (status()) { 599 case IcacheMissStall: 600 icacheStallCycles += curTick - lastIcacheStall; 601 _status = IcacheMissComplete; 602 scheduleTickEvent(1); 603 break; 604 case DcacheMissStall: 605 dcacheStallCycles += curTick - lastDcacheStall; 606 _status = Running; 607 scheduleTickEvent(1); 608 break; 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#ifdef 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#ifdef 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#ifdef 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 MemAccessResult result = icacheInterface->access(memReq); 724 725 // Ugly hack to get an event scheduled *only* if the access is 726 // a miss. We really should add first-class support for this 727 // at some point. 728 if (result != MA_HIT && icacheInterface->doEvents()) { 729 memReq->completionEvent = &cacheCompletionEvent; 730 lastIcacheStall = curTick; 731 unscheduleTickEvent(); 732 _status = IcacheMissStall; 733 return; 734 } 735 } 736 } 737 738 // If we've got a valid instruction (i.e., no fault on instruction 739 // fetch), then execute it. 740 if (fault == No_Fault) { 741 742 // keep an instruction count 743 numInst++; 744 numInsts++; 745 746 // check for instruction-count-based events 747 comInstEventQueue[0]->serviceEvents(numInst); 748 749 // decode the instruction 750 inst = htoa(inst); 751 StaticInstPtr<TheISA> si(inst); 752 753 traceData = Trace::getInstRecord(curTick, xc, this, si, 754 xc->regs.pc); 755 756#ifdef FULL_SYSTEM 757 xc->setInst(inst); 758#endif // FULL_SYSTEM 759 760 xc->func_exe_inst++; 761 762 fault = si->execute(this, traceData); 763 764#ifdef FULL_SYSTEM 765 if (xc->fnbin) 766 xc->execute(si.get()); 767#endif 768 769 if (si->isMemRef()) { 770 numMemRefs++; 771 } 772 773 if (si->isLoad()) { 774 ++numLoad; 775 comLoadEventQueue[0]->serviceEvents(numLoad); 776 } 777 778 if (traceData) 779 traceData->finalize(); 780 781 } // if (fault == No_Fault) 782 783 if (fault != No_Fault) { 784#ifdef FULL_SYSTEM 785 xc->ev5_trap(fault); 786#else // !FULL_SYSTEM 787 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 788#endif // FULL_SYSTEM 789 } 790 else { 791 // go to the next instruction 792 xc->regs.pc = xc->regs.npc; 793 xc->regs.npc += sizeof(MachInst); 794 } 795 796#ifdef FULL_SYSTEM 797 Addr oldpc; 798 do { 799 oldpc = xc->regs.pc; 800 system->pcEventQueue.service(xc); 801 } while (oldpc != xc->regs.pc); 802#endif 803 804 assert(status() == Running || 805 status() == Idle || 806 status() == DcacheMissStall); 807 808 if (status() == Running && !tickEvent.scheduled()) 809 tickEvent.schedule(curTick + 1); 810} 811 812 813//////////////////////////////////////////////////////////////////////// 814// 815// SimpleCPU Simulation Object 816// 817BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 818 819 Param<Counter> max_insts_any_thread; 820 Param<Counter> max_insts_all_threads; 821 Param<Counter> max_loads_any_thread; 822 Param<Counter> max_loads_all_threads; 823 824#ifdef FULL_SYSTEM 825 SimObjectParam<AlphaITB *> itb; 826 SimObjectParam<AlphaDTB *> dtb; 827 SimObjectParam<FunctionalMemory *> mem; 828 SimObjectParam<System *> system; 829 Param<int> mult; 830#else 831 SimObjectParam<Process *> workload; 832#endif // FULL_SYSTEM 833 834 SimObjectParam<BaseMem *> icache; 835 SimObjectParam<BaseMem *> dcache; 836 837 Param<bool> defer_registration; 838 Param<int> multiplier; 839 840END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 841 842BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 843 844 INIT_PARAM_DFLT(max_insts_any_thread, 845 "terminate when any thread reaches this inst count", 846 0), 847 INIT_PARAM_DFLT(max_insts_all_threads, 848 "terminate when all threads have reached this inst count", 849 0), 850 INIT_PARAM_DFLT(max_loads_any_thread, 851 "terminate when any thread reaches this load count", 852 0), 853 INIT_PARAM_DFLT(max_loads_all_threads, 854 "terminate when all threads have reached this load count", 855 0), 856 857#ifdef FULL_SYSTEM 858 INIT_PARAM(itb, "Instruction TLB"), 859 INIT_PARAM(dtb, "Data TLB"), 860 INIT_PARAM(mem, "memory"), 861 INIT_PARAM(system, "system object"), 862 INIT_PARAM_DFLT(mult, "system clock multiplier", 1), 863#else 864 INIT_PARAM(workload, "processes to run"), 865#endif // FULL_SYSTEM 866 867 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), 868 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), 869 INIT_PARAM_DFLT(defer_registration, "defer registration with system " 870 "(for sampling)", false), 871 872 INIT_PARAM_DFLT(multiplier, "clock multiplier", 1) 873 874END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 875 876 877CREATE_SIM_OBJECT(SimpleCPU) 878{ 879 SimpleCPU *cpu; 880#ifdef FULL_SYSTEM 881 if (mult != 1) 882 panic("processor clock multiplier must be 1\n"); 883 884 cpu = new SimpleCPU(getInstanceName(), system, 885 max_insts_any_thread, max_insts_all_threads, 886 max_loads_any_thread, max_loads_all_threads, 887 itb, dtb, mem, 888 (icache) ? icache->getInterface() : NULL, 889 (dcache) ? dcache->getInterface() : NULL, 890 defer_registration, 891 ticksPerSecond * mult); 892#else 893 894 cpu = new SimpleCPU(getInstanceName(), workload, 895 max_insts_any_thread, max_insts_all_threads, 896 max_loads_any_thread, max_loads_all_threads, 897 (icache) ? icache->getInterface() : NULL, 898 (dcache) ? dcache->getInterface() : NULL, 899 defer_registration); 900 901#endif // FULL_SYSTEM 902 903 cpu->setTickMultiplier(multiplier); 904 905 return cpu; 906} 907 908REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 909 910