base.cc revision 2090
11689SN/A/* 22329SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 31689SN/A * All rights reserved. 41689SN/A * 51689SN/A * Redistribution and use in source and binary forms, with or without 61689SN/A * modification, are permitted provided that the following conditions are 71689SN/A * met: redistributions of source code must retain the above copyright 81689SN/A * notice, this list of conditions and the following disclaimer; 91689SN/A * redistributions in binary form must reproduce the above copyright 101689SN/A * notice, this list of conditions and the following disclaimer in the 111689SN/A * documentation and/or other materials provided with the distribution; 121689SN/A * neither the name of the copyright holders nor the names of its 131689SN/A * contributors may be used to endorse or promote products derived from 141689SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292935Sksewell@umich.edu#include <cmath> 301689SN/A#include <cstdio> 311689SN/A#include <cstdlib> 321060SN/A#include <iostream> 331060SN/A#include <iomanip> 343773Sgblack@eecs.umich.edu#include <list> 353773Sgblack@eecs.umich.edu#include <sstream> 361858SN/A#include <string> 371717SN/A 381060SN/A#include "base/cprintf.hh" 391061SN/A#include "base/inifile.hh" 404329Sktlim@umich.edu#include "base/loader/symtab.hh" 414329Sktlim@umich.edu#include "base/misc.hh" 424329Sktlim@umich.edu#include "base/pollevent.hh" 432292SN/A#include "base/range.hh" 442292SN/A#include "base/stats/events.hh" 452292SN/A#include "base/trace.hh" 462292SN/A#include "cpu/base.hh" 473788Sgblack@eecs.umich.edu#include "cpu/exec_context.hh" 483798Sgblack@eecs.umich.edu#include "cpu/exetrace.hh" 492361SN/A#include "cpu/profile.hh" 502361SN/A#include "cpu/sampler/sampler.hh" 511060SN/A#include "cpu/simple/cpu.hh" 522292SN/A#include "cpu/smt.hh" 532292SN/A#include "cpu/static_inst.hh" 542292SN/A#include "kern/kernel_stats.hh" 552292SN/A#include "mem/base_mem.hh" 562292SN/A#include "mem/mem_interface.hh" 572292SN/A#include "sim/byteswap.hh" 582292SN/A#include "sim/builder.hh" 592292SN/A#include "sim/debug.hh" 602292SN/A#include "sim/host.hh" 612292SN/A#include "sim/sim_events.hh" 622292SN/A#include "sim/sim_object.hh" 632301SN/A#include "sim/stats.hh" 642292SN/A 652292SN/A#if FULL_SYSTEM 662292SN/A#include "base/remote_gdb.hh" 672292SN/A#include "mem/functional/memory_control.hh" 682292SN/A#include "mem/functional/physical.hh" 692292SN/A#include "sim/system.hh" 702292SN/A#include "targetarch/alpha_memory.hh" 712292SN/A#include "targetarch/stacktrace.hh" 722292SN/A#include "targetarch/vtophys.hh" 732292SN/A#else // !FULL_SYSTEM 742292SN/A#include "mem/functional/functional.hh" 752292SN/A#endif // FULL_SYSTEM 762292SN/A 772292SN/Ausing namespace std; 782292SN/A//The SimpleCPU does alpha only 792292SN/Ausing namespace LittleEndianGuest; 802292SN/A 811060SN/A 821060SN/ASimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) 831061SN/A : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) 841060SN/A{ 852292SN/A} 861062SN/A 871062SN/Avoid 882301SN/ASimpleCPU::TickEvent::process() 891062SN/A{ 901062SN/A int count = width; 911062SN/A do { 922301SN/A cpu->tick(); 931062SN/A } while (--count > 0 && cpu->status() == Running); 941062SN/A} 951062SN/A 962301SN/Aconst char * 971062SN/ASimpleCPU::TickEvent::description() 981062SN/A{ 992301SN/A return "SimpleCPU tick event"; 1002301SN/A} 1012301SN/A 1022301SN/A 1032292SN/ASimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 1042301SN/A : Event(&mainEventQueue), cpu(_cpu) 1052292SN/A{ 1062292SN/A} 1071062SN/A 1082301SN/Avoid SimpleCPU::CacheCompletionEvent::process() 1091062SN/A{ 1101062SN/A cpu->processCacheCompletion(); 1111062SN/A} 1122301SN/A 1131062SN/Aconst char * 1141062SN/ASimpleCPU::CacheCompletionEvent::description() 1151062SN/A{ 1162301SN/A return "SimpleCPU cache completion event"; 1171062SN/A} 1181062SN/A 1191062SN/ASimpleCPU::SimpleCPU(Params *p) 1202301SN/A : BaseCPU(p), tickEvent(this, p->width), xc(NULL), 1212292SN/A cacheCompletionEvent(this) 1221062SN/A{ 1231062SN/A _status = Idle; 1242301SN/A#if FULL_SYSTEM 1252292SN/A xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); 1261062SN/A 1272292SN/A // initialize CPU, including PC 1282301SN/A TheISA::initCPU(&xc->regs); 1292292SN/A#else 1302292SN/A xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0); 1311062SN/A#endif // !FULL_SYSTEM 1322301SN/A 1331062SN/A icacheInterface = p->icache_interface; 1341062SN/A dcacheInterface = p->dcache_interface; 1351062SN/A 1362301SN/A memReq = new MemReq(); 1371062SN/A memReq->xc = xc; 1381062SN/A memReq->asid = 0; 1391062SN/A memReq->data = new uint8_t[64]; 1402301SN/A 1411062SN/A numInst = 0; 1421062SN/A startNumInst = 0; 1431062SN/A numLoad = 0; 1442301SN/A startNumLoad = 0; 1451062SN/A lastIcacheStall = 0; 1461062SN/A lastDcacheStall = 0; 1471062SN/A 1482301SN/A execContexts.push_back(xc); 1491062SN/A} 1501062SN/A 1512301SN/ASimpleCPU::~SimpleCPU() 1522301SN/A{ 1532301SN/A} 1542301SN/A 1552301SN/Avoid 1562301SN/ASimpleCPU::switchOut(Sampler *s) 1572301SN/A{ 1582301SN/A sampler = s; 1592301SN/A if (status() == DcacheMissStall) { 1602301SN/A DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); 1612307SN/A _status = DcacheMissSwitch; 1622307SN/A } 1632307SN/A else { 1642307SN/A _status = SwitchedOut; 1652307SN/A 1661062SN/A if (tickEvent.scheduled()) 1671062SN/A tickEvent.squash(); 1681062SN/A 1691062SN/A sampler->signalSwitched(); 1702292SN/A } 1711060SN/A} 1721060SN/A 1731060SN/A 1741060SN/Avoid 1751060SN/ASimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1761060SN/A{ 1771060SN/A BaseCPU::takeOverFrom(oldCPU); 1781060SN/A 1791060SN/A assert(!tickEvent.scheduled()); 1801060SN/A 1811060SN/A // if any of this CPU's ExecContexts are active, mark the CPU as 1821060SN/A // running and schedule its tick event. 1831060SN/A for (int i = 0; i < execContexts.size(); ++i) { 1841061SN/A ExecContext *xc = execContexts[i]; 1851060SN/A if (xc->status() == ExecContext::Active && _status != Running) { 1862292SN/A _status = Running; 1871060SN/A tickEvent.schedule(curTick); 1881060SN/A } 1891060SN/A } 1901060SN/A} 1911060SN/A 1921060SN/A 1931060SN/Avoid 1941061SN/ASimpleCPU::activateContext(int thread_num, int delay) 1951060SN/A{ 1962292SN/A assert(thread_num == 0); 1971060SN/A assert(xc); 1981060SN/A 1991060SN/A assert(_status == Idle); 2001060SN/A notIdleFraction++; 2011060SN/A scheduleTickEvent(delay); 2021060SN/A _status = Running; 2031060SN/A} 2041061SN/A 2051060SN/A 2062292SN/Avoid 2071060SN/ASimpleCPU::suspendContext(int thread_num) 2082329SN/A{ 2092292SN/A assert(thread_num == 0); 2102292SN/A assert(xc); 2112292SN/A 2122292SN/A assert(_status == Running); 2132292SN/A notIdleFraction--; 2142292SN/A unscheduleTickEvent(); 2151060SN/A _status = Idle; 2161060SN/A} 2172292SN/A 2182292SN/A 2192980Sgblack@eecs.umich.eduvoid 2202292SN/ASimpleCPU::deallocateContext(int thread_num) 2212292SN/A{ 2222292SN/A // for now, these are equivalent 2232292SN/A suspendContext(thread_num); 2242292SN/A} 2251061SN/A 2261060SN/A 2272292SN/Avoid 2281060SN/ASimpleCPU::haltContext(int thread_num) 2292292SN/A{ 2302292SN/A // for now, these are equivalent 2311060SN/A suspendContext(thread_num); 2321060SN/A} 2331060SN/A 2341061SN/A 2351060SN/Avoid 2362292SN/ASimpleCPU::regStats() 2371060SN/A{ 2382292SN/A using namespace Stats; 2392292SN/A 2401060SN/A BaseCPU::regStats(); 2412292SN/A 2422292SN/A numInsts 2432292SN/A .name(name() + ".num_insts") 2442292SN/A .desc("Number of instructions executed") 2452292SN/A ; 2461060SN/A 2471060SN/A numMemRefs 2481061SN/A .name(name() + ".num_refs") 2492863Sktlim@umich.edu .desc("Number of memory references") 2502843Sktlim@umich.edu ; 2511060SN/A 2522348SN/A notIdleFraction 2532843Sktlim@umich.edu .name(name() + ".not_idle_fraction") 2542863Sktlim@umich.edu .desc("Percentage of non-idle cycles") 2552316SN/A ; 2561060SN/A 2572316SN/A idleFraction 2582316SN/A .name(name() + ".idle_fraction") 2592843Sktlim@umich.edu .desc("Percentage of idle cycles") 2602316SN/A ; 2612348SN/A 2622307SN/A icacheStallCycles 2632980Sgblack@eecs.umich.edu .name(name() + ".icache_stall_cycles") 2642980Sgblack@eecs.umich.edu .desc("ICache total stall cycles") 2652307SN/A .prereq(icacheStallCycles) 2662307SN/A ; 2672307SN/A 2682307SN/A dcacheStallCycles 2692307SN/A .name(name() + ".dcache_stall_cycles") 2702307SN/A .desc("DCache total stall cycles") 2712307SN/A .prereq(dcacheStallCycles) 2722307SN/A ; 2732307SN/A 2742307SN/A idleFraction = constant(1.0) - notIdleFraction; 2752307SN/A} 2762307SN/A 2772307SN/Avoid 2782307SN/ASimpleCPU::resetStats() 2792361SN/A{ 2802361SN/A startNumInst = numInst; 2812361SN/A notIdleFraction = (_status != Idle); 2822361SN/A} 2832361SN/A 2842307SN/Avoid 2852307SN/ASimpleCPU::serialize(ostream &os) 2862307SN/A{ 2872307SN/A BaseCPU::serialize(os); 2881060SN/A SERIALIZE_ENUM(_status); 2891060SN/A SERIALIZE_SCALAR(inst); 2901060SN/A nameOut(os, csprintf("%s.xc", name())); 2911061SN/A xc->serialize(os); 2921060SN/A nameOut(os, csprintf("%s.tickEvent", name())); 2932307SN/A tickEvent.serialize(os); 2941060SN/A nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 2952307SN/A cacheCompletionEvent.serialize(os); 2962307SN/A} 2971060SN/A 2982329SN/Avoid 2992307SN/ASimpleCPU::unserialize(Checkpoint *cp, const string §ion) 3002307SN/A{ 3011060SN/A BaseCPU::unserialize(cp, section); 3022307SN/A UNSERIALIZE_ENUM(_status); 3032307SN/A UNSERIALIZE_SCALAR(inst); 3042307SN/A xc->unserialize(cp, csprintf("%s.xc", section)); 3052307SN/A tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 3062307SN/A cacheCompletionEvent 3072307SN/A .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); 3082307SN/A} 3092307SN/A 3102307SN/Avoid 3112307SN/Achange_thread_state(int thread_number, int activate, int priority) 3122307SN/A{ 3132307SN/A} 3142307SN/A 3152307SN/AFault * 3162935Sksewell@umich.eduSimpleCPU::copySrcTranslate(Addr src) 3171858SN/A{ 3182292SN/A static bool no_warn = true; 3191858SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3202292SN/A // Only support block sizes of 64 atm. 3212292SN/A assert(blk_size == 64); 3222292SN/A int offset = src & (blk_size - 1); 3232292SN/A 3243788Sgblack@eecs.umich.edu // Make sure block doesn't span page 3252292SN/A if (no_warn && 3262698Sktlim@umich.edu (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && 3273788Sgblack@eecs.umich.edu (src >> 40) != 0xfffffc) { 3282301SN/A warn("Copied block source spans pages %x.", src); 3293788Sgblack@eecs.umich.edu no_warn = false; 3303788Sgblack@eecs.umich.edu } 3313788Sgblack@eecs.umich.edu 3323788Sgblack@eecs.umich.edu memReq->reset(src & ~(blk_size - 1), blk_size); 3333788Sgblack@eecs.umich.edu 3343788Sgblack@eecs.umich.edu // translate to physical address 3353788Sgblack@eecs.umich.edu Fault * fault = xc->translateDataReadReq(memReq); 3363788Sgblack@eecs.umich.edu 3373788Sgblack@eecs.umich.edu assert(fault != AlignmentFault); 3383788Sgblack@eecs.umich.edu 3393788Sgblack@eecs.umich.edu if (fault == NoFault) { 3402292SN/A xc->copySrcAddr = src; 3412292SN/A xc->copySrcPhysAddr = memReq->paddr + offset; 3422292SN/A } else { 3432292SN/A xc->copySrcAddr = 0; 3442292SN/A xc->copySrcPhysAddr = 0; 3452329SN/A } 3462292SN/A return fault; 3472292SN/A} 3482292SN/A 3492935Sksewell@umich.eduFault * 3502935Sksewell@umich.eduSimpleCPU::copy(Addr dest) 3512731Sktlim@umich.edu{ 3522292SN/A static bool no_warn = true; 3532292SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3542292SN/A // Only support block sizes of 64 atm. 3552935Sksewell@umich.edu assert(blk_size == 64); 3562292SN/A uint8_t data[blk_size]; 3572292SN/A //assert(xc->copySrcAddr); 3582935Sksewell@umich.edu int offset = dest & (blk_size - 1); 3594632Sgblack@eecs.umich.edu 3603093Sksewell@umich.edu // Make sure block doesn't span page 3612292SN/A if (no_warn && 3622292SN/A (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && 3633093Sksewell@umich.edu (dest >> 40) != 0xfffffc) { 3644632Sgblack@eecs.umich.edu no_warn = false; 3652935Sksewell@umich.edu warn("Copied block destination spans pages %x. ", dest); 3662292SN/A } 3672292SN/A 3682292SN/A memReq->reset(dest & ~(blk_size -1), blk_size); 3692292SN/A // translate to physical address 3702292SN/A Fault * fault = xc->translateDataWriteReq(memReq); 3712292SN/A 3722292SN/A assert(fault != AlignmentFault); 3732292SN/A 3742292SN/A if (fault == NoFault) { 3752292SN/A Addr dest_addr = memReq->paddr + offset; 3762292SN/A // Need to read straight from memory since we have more than 8 bytes. 3772292SN/A memReq->paddr = xc->copySrcPhysAddr; 3782292SN/A xc->mem->read(memReq, data); 3792292SN/A memReq->paddr = dest_addr; 3802292SN/A xc->mem->write(memReq, data); 3812292SN/A if (dcacheInterface) { 3823867Sbinkertn@umich.edu memReq->cmd = Copy; 3833867Sbinkertn@umich.edu memReq->completionEvent = NULL; 3842292SN/A memReq->paddr = xc->copySrcPhysAddr; 3852292SN/A memReq->dest = dest_addr; 3863867Sbinkertn@umich.edu memReq->size = 64; 3872292SN/A memReq->time = curTick; 3882292SN/A memReq->flags &= ~INST_READ; 3892292SN/A dcacheInterface->access(memReq); 3902292SN/A } 3912292SN/A } 3922292SN/A return fault; 3932292SN/A} 3942292SN/A 3952292SN/A// precise architected memory state accessor macros 3962292SN/Atemplate <class T> 3972292SN/AFault * 3982292SN/ASimpleCPU::read(Addr addr, T &data, unsigned flags) 3992292SN/A{ 4002292SN/A if (status() == DcacheMissStall || status() == DcacheMissSwitch) { 4012292SN/A Fault * fault = xc->read(memReq,data); 4022292SN/A 4032292SN/A if (traceData) { 4042292SN/A traceData->setAddr(addr); 4053867Sbinkertn@umich.edu } 4062292SN/A return fault; 4073867Sbinkertn@umich.edu } 4082292SN/A 4092292SN/A memReq->reset(addr, sizeof(T), flags); 4102292SN/A 4112292SN/A // translate to physical address 4122292SN/A Fault * fault = xc->translateDataReadReq(memReq); 4132292SN/A 4142292SN/A // if we have a cache, do cache access too 4152292SN/A if (fault == NoFault && dcacheInterface) { 4162292SN/A memReq->cmd = Read; 4172292SN/A memReq->completionEvent = NULL; 4182292SN/A memReq->time = curTick; 4192292SN/A memReq->flags &= ~INST_READ; 4202292SN/A MemAccessResult result = dcacheInterface->access(memReq); 4212292SN/A 4222292SN/A // Ugly hack to get an event scheduled *only* if the access is 4232292SN/A // a miss. We really should add first-class support for this 4242292SN/A // at some point. 4252292SN/A if (result != MA_HIT && dcacheInterface->doEvents()) { 4262292SN/A memReq->completionEvent = &cacheCompletionEvent; 4272292SN/A lastDcacheStall = curTick; 4282292SN/A unscheduleTickEvent(); 4292292SN/A _status = DcacheMissStall; 4302292SN/A } else { 4312292SN/A // do functional access 4322292SN/A fault = xc->read(memReq, data); 4332292SN/A 4342292SN/A } 4352292SN/A } else if(fault == NoFault) { 4362292SN/A // do functional access 4372292SN/A fault = xc->read(memReq, data); 4382292SN/A 4392292SN/A } 4402292SN/A 4412292SN/A if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 4422292SN/A recordEvent("Uncached Read"); 4432292SN/A 4442301SN/A return fault; 4452301SN/A} 4463788Sgblack@eecs.umich.edu 4473788Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 4483788Sgblack@eecs.umich.edu 4493788Sgblack@eecs.umich.edutemplate 4503788Sgblack@eecs.umich.eduFault * 4513788Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 4523788Sgblack@eecs.umich.edu 4533788Sgblack@eecs.umich.edutemplate 4543798Sgblack@eecs.umich.eduFault * 4553798Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 4563798Sgblack@eecs.umich.edu 4573798Sgblack@eecs.umich.edutemplate 4583798Sgblack@eecs.umich.eduFault * 4593798Sgblack@eecs.umich.eduSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 4602292SN/A 4612292SN/Atemplate 4622292SN/AFault * 4632292SN/ASimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 4642292SN/A 4652292SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 4662292SN/A 4672292SN/Atemplate<> 4682292SN/AFault * 4692292SN/ASimpleCPU::read(Addr addr, double &data, unsigned flags) 4702292SN/A{ 4712292SN/A return read(addr, *(uint64_t*)&data, flags); 4722292SN/A} 4732292SN/A 4742292SN/Atemplate<> 4752292SN/AFault * 4762292SN/ASimpleCPU::read(Addr addr, float &data, unsigned flags) 4772292SN/A{ 4782292SN/A return read(addr, *(uint32_t*)&data, flags); 4792292SN/A} 4801858SN/A 4811858SN/A 4821858SN/Atemplate<> 4831858SN/AFault * 4841858SN/ASimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 4852292SN/A{ 4861858SN/A return read(addr, (uint32_t&)data, flags); 4872292SN/A} 4882292SN/A 4892292SN/A 4902292SN/Atemplate <class T> 4911858SN/AFault * 4922292SN/ASimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 4932292SN/A{ 4942292SN/A memReq->reset(addr, sizeof(T), flags); 4952292SN/A 4962292SN/A // translate to physical address 4972292SN/A Fault * fault = xc->translateDataWriteReq(memReq); 4982292SN/A 4992292SN/A // do functional access 5002292SN/A if (fault == NoFault) 5012292SN/A fault = xc->write(memReq, data); 5022292SN/A 5032292SN/A if (fault == NoFault && dcacheInterface) { 5042292SN/A memReq->cmd = Write; 5051858SN/A memcpy(memReq->data,(uint8_t *)&data,memReq->size); 5062292SN/A memReq->completionEvent = NULL; 5072292SN/A memReq->time = curTick; 5082292SN/A memReq->flags &= ~INST_READ; 5092292SN/A MemAccessResult result = dcacheInterface->access(memReq); 5102292SN/A 5112292SN/A // Ugly hack to get an event scheduled *only* if the access is 5122292SN/A // a miss. We really should add first-class support for this 5132292SN/A // at some point. 5142292SN/A if (result != MA_HIT && dcacheInterface->doEvents()) { 5152292SN/A memReq->completionEvent = &cacheCompletionEvent; 5162292SN/A lastDcacheStall = curTick; 5172292SN/A unscheduleTickEvent(); 5182292SN/A _status = DcacheMissStall; 5192292SN/A } 5202292SN/A } 5212292SN/A 5222292SN/A if (res && (fault == NoFault)) 5232292SN/A *res = memReq->result; 5242292SN/A 5252292SN/A if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 5262292SN/A recordEvent("Uncached Write"); 5272292SN/A 5282292SN/A return fault; 5292292SN/A} 5302292SN/A 5312292SN/A 5322292SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS 5332292SN/Atemplate 5342292SN/AFault * 5352292SN/ASimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 5362292SN/A 5372292SN/Atemplate 5382292SN/AFault * 5392292SN/ASimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 5402292SN/A 5412292SN/Atemplate 5422292SN/AFault * 5432292SN/ASimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 5442292SN/A 5452292SN/Atemplate 5462292SN/AFault * 5472292SN/ASimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 5482292SN/A 5492292SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 5502292SN/A 5512292SN/Atemplate<> 5522292SN/AFault * 5532292SN/ASimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 5542292SN/A{ 5552292SN/A return write(*(uint64_t*)&data, addr, flags, res); 5562292SN/A} 5572292SN/A 5582292SN/Atemplate<> 5592292SN/AFault * 5602292SN/ASimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 5612292SN/A{ 5622292SN/A return write(*(uint32_t*)&data, addr, flags, res); 5632292SN/A} 5642292SN/A 5652292SN/A 5662292SN/Atemplate<> 5672292SN/AFault * 5682292SN/ASimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 5692292SN/A{ 5702292SN/A return write((uint32_t)data, addr, flags, res); 5712292SN/A} 5722292SN/A 5732292SN/A 5742292SN/A#if FULL_SYSTEM 5752292SN/AAddr 5762292SN/ASimpleCPU::dbg_vtophys(Addr addr) 5772292SN/A{ 5782292SN/A return vtophys(xc, addr); 5792292SN/A} 5802292SN/A#endif // FULL_SYSTEM 5812292SN/A 5822292SN/Avoid 5832292SN/ASimpleCPU::processCacheCompletion() 5842292SN/A{ 5852292SN/A switch (status()) { 5862292SN/A case IcacheMissStall: 5872292SN/A icacheStallCycles += curTick - lastIcacheStall; 5882292SN/A _status = IcacheMissComplete; 5892292SN/A scheduleTickEvent(1); 5902292SN/A break; 5912292SN/A case DcacheMissStall: 5922292SN/A if (memReq->cmd.isRead()) { 5932292SN/A curStaticInst->execute(this,traceData); 5942292SN/A if (traceData) 5952292SN/A traceData->finalize(); 5962292SN/A } 5972292SN/A dcacheStallCycles += curTick - lastDcacheStall; 5982292SN/A _status = Running; 5992935Sksewell@umich.edu scheduleTickEvent(1); 6002292SN/A break; 6012292SN/A case DcacheMissSwitch: 6022292SN/A if (memReq->cmd.isRead()) { 6032292SN/A curStaticInst->execute(this,traceData); 6042292SN/A if (traceData) 6052292SN/A traceData->finalize(); 6062292SN/A } 6072292SN/A _status = SwitchedOut; 6082292SN/A sampler->signalSwitched(); 6092292SN/A case SwitchedOut: 6102292SN/A // If this CPU has been switched out due to sampling/warm-up, 6112292SN/A // ignore any further status changes (e.g., due to cache 6122292SN/A // misses outstanding at the time of the switch). 6132292SN/A return; 6142292SN/A default: 6152292SN/A panic("SimpleCPU::processCacheCompletion: bad state"); 6162292SN/A break; 6172336SN/A } 6182336SN/A} 6192336SN/A 6202336SN/A#if FULL_SYSTEM 6212336SN/Avoid 6222336SN/ASimpleCPU::post_interrupt(int int_num, int index) 6232336SN/A{ 6242336SN/A BaseCPU::post_interrupt(int_num, index); 6252292SN/A 6262292SN/A if (xc->status() == ExecContext::Suspended) { 6272301SN/A DPRINTF(IPI,"Suspended Processor awoke\n"); 6282301SN/A xc->activate(); 6292292SN/A } 6302301SN/A} 6312301SN/A#endif // FULL_SYSTEM 6322301SN/A 6332292SN/A/* start simulation, program loaded, processor precise state initialized */ 6342301SN/Avoid 6352292SN/ASimpleCPU::tick() 6362301SN/A{ 6372292SN/A numCycles++; 6382301SN/A 6392292SN/A traceData = NULL; 6402292SN/A 6412292SN/A Fault * fault = NoFault; 6422292SN/A 6432336SN/A#if FULL_SYSTEM 6442336SN/A if (checkInterrupts && check_interrupts() && !xc->inPalMode() && 6452292SN/A status() != IcacheMissComplete) { 6462292SN/A int ipl = 0; 6472307SN/A int summary = 0; 6482307SN/A checkInterrupts = false; 6492292SN/A IntReg *ipr = xc->regs.ipr; 6502292SN/A 6512292SN/A if (xc->regs.ipr[TheISA::IPR_SIRR]) { 6522292SN/A for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 6532292SN/A i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 6542292SN/A if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 6552292SN/A // See table 4-19 of 21164 hardware reference 6562292SN/A ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 6572292SN/A summary |= (ULL(1) << i); 6582292SN/A } 6592292SN/A } 6604345Sktlim@umich.edu } 6612292SN/A 6622292SN/A uint64_t interrupts = xc->cpu->intr_status(); 6632292SN/A for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 6642292SN/A i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 6652292SN/A if (interrupts & (ULL(1) << i)) { 6662292SN/A // See table 4-19 of 21164 hardware reference 6672292SN/A ipl = i; 6682292SN/A summary |= (ULL(1) << i); 6692292SN/A } 6702292SN/A } 6712292SN/A 6722292SN/A if (ipr[TheISA::IPR_ASTRR]) 6732292SN/A panic("asynchronous traps not implemented\n"); 6742292SN/A 6752292SN/A if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 6762292SN/A ipr[TheISA::IPR_ISR] = summary; 6772292SN/A ipr[TheISA::IPR_INTID] = ipl; 6782292SN/A xc->ev5_trap(InterruptFault); 6792292SN/A 6802292SN/A DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 6812292SN/A ipr[TheISA::IPR_IPLR], ipl, summary); 6822292SN/A } 6832292SN/A } 6842307SN/A#endif 6852292SN/A 6862292SN/A // maintain $r0 semantics 6872292SN/A xc->regs.intRegFile[ZeroReg] = 0; 6882292SN/A#ifdef TARGET_ALPHA 6892292SN/A xc->regs.floatRegFile.d[ZeroReg] = 0.0; 6902292SN/A#endif // TARGET_ALPHA 6912292SN/A 6922292SN/A if (status() == IcacheMissComplete) { 6932292SN/A // We've already fetched an instruction and were stalled on an 6942292SN/A // I-cache miss. No need to fetch it again. 6952292SN/A 6962292SN/A // Set status to running; tick event will get rescheduled if 6972292SN/A // necessary at end of tick() function. 6982292SN/A _status = Running; 6992292SN/A } 7002292SN/A else { 7012292SN/A // Try to fetch an instruction 7022292SN/A 7032292SN/A // set up memory request for instruction fetch 7042292SN/A#if FULL_SYSTEM 7052292SN/A#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 7062292SN/A#else 7072292SN/A#define IFETCH_FLAGS(pc) 0 7082292SN/A#endif 7092292SN/A 7102292SN/A memReq->cmd = Read; 7112292SN/A memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 7122292SN/A IFETCH_FLAGS(xc->regs.pc)); 7132292SN/A 7142292SN/A fault = xc->translateInstReq(memReq); 7152292SN/A 7162292SN/A if (fault == NoFault) 7172292SN/A fault = xc->mem->read(memReq, inst); 7182292SN/A 7192307SN/A if (icacheInterface && fault == NoFault) { 7202307SN/A memReq->completionEvent = NULL; 7212292SN/A 7222292SN/A memReq->time = curTick; 7232292SN/A memReq->flags |= INST_READ; 7242292SN/A MemAccessResult result = icacheInterface->access(memReq); 7253798Sgblack@eecs.umich.edu 7263798Sgblack@eecs.umich.edu // Ugly hack to get an event scheduled *only* if the access is 7273798Sgblack@eecs.umich.edu // a miss. We really should add first-class support for this 7283798Sgblack@eecs.umich.edu // at some point. 7293798Sgblack@eecs.umich.edu if (result != MA_HIT && icacheInterface->doEvents()) { 7303798Sgblack@eecs.umich.edu memReq->completionEvent = &cacheCompletionEvent; 7313798Sgblack@eecs.umich.edu lastIcacheStall = curTick; 7323798Sgblack@eecs.umich.edu unscheduleTickEvent(); 7333798Sgblack@eecs.umich.edu _status = IcacheMissStall; 7342292SN/A return; 7353798Sgblack@eecs.umich.edu } 7362292SN/A } 7372292SN/A } 7382292SN/A 7392292SN/A // If we've got a valid instruction (i.e., no fault on instruction 7402292SN/A // fetch), then execute it. 7412292SN/A if (fault == NoFault) { 7422292SN/A 7432329SN/A // keep an instruction count 7442292SN/A numInst++; 7452292SN/A numInsts++; 7462329SN/A 7472292SN/A // check for instruction-count-based events 7482292SN/A comInstEventQueue[0]->serviceEvents(numInst); 7492292SN/A 7502292SN/A // decode the instruction 7512292SN/A inst = gtoh(inst); 7522292SN/A curStaticInst = StaticInst<TheISA>::decode(inst); 7532292SN/A 7542292SN/A traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst, 7552292SN/A xc->regs.pc); 7562292SN/A 7573867Sbinkertn@umich.edu#if FULL_SYSTEM 7583867Sbinkertn@umich.edu xc->setInst(inst); 7592292SN/A#endif // FULL_SYSTEM 7603867Sbinkertn@umich.edu 7613867Sbinkertn@umich.edu xc->func_exe_inst++; 7623867Sbinkertn@umich.edu 7633867Sbinkertn@umich.edu fault = curStaticInst->execute(this, traceData); 7642292SN/A 7652292SN/A#if FULL_SYSTEM 7662292SN/A if (xc->fnbin) { 7672292SN/A assert(xc->kernelStats); 7682292SN/A system->kernelBinning->execute(xc, inst); 7692292SN/A } 7702292SN/A 7712292SN/A if (xc->profile) { 7722292SN/A bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0; 7732292SN/A xc->profilePC = usermode ? 1 : xc->regs.pc; 7742292SN/A ProfileNode *node = xc->profile->consume(xc, inst); 7752292SN/A if (node) 7763867Sbinkertn@umich.edu xc->profileNode = node; 7773867Sbinkertn@umich.edu } 7782292SN/A#endif 7793867Sbinkertn@umich.edu 7802292SN/A if (curStaticInst->isMemRef()) { 7812292SN/A numMemRefs++; 7822292SN/A } 7832292SN/A 7842292SN/A if (curStaticInst->isLoad()) { 7852292SN/A ++numLoad; 7862292SN/A comLoadEventQueue[0]->serviceEvents(numLoad); 7872292SN/A } 7882292SN/A 7892292SN/A // If we have a dcache miss, then we can't finialize the instruction 7902292SN/A // trace yet because we want to populate it with the data later 7912292SN/A if (traceData && 7922292SN/A !(status() == DcacheMissStall && memReq->cmd.isRead())) { 7932292SN/A traceData->finalize(); 7942292SN/A } 7952733Sktlim@umich.edu 7962292SN/A traceFunctions(xc->regs.pc); 7972292SN/A 7982292SN/A } // if (fault == NoFault) 7992292SN/A 8002292SN/A if (fault != NoFault) { 8012292SN/A#if FULL_SYSTEM 8022292SN/A xc->ev5_trap(fault); 8032292SN/A#else // !FULL_SYSTEM 8042733Sktlim@umich.edu fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 8052292SN/A#endif // FULL_SYSTEM 8062292SN/A } 8072292SN/A else { 8082292SN/A // go to the next instruction 8092292SN/A xc->regs.pc = xc->regs.npc; 8102292SN/A xc->regs.npc += sizeof(MachInst); 8112292SN/A } 8122292SN/A 8132292SN/A#if FULL_SYSTEM 8142292SN/A Addr oldpc; 8152292SN/A do { 8162292SN/A oldpc = xc->regs.pc; 8172292SN/A system->pcEventQueue.service(xc); 8182292SN/A } while (oldpc != xc->regs.pc); 8192292SN/A#endif 8202292SN/A 8212292SN/A assert(status() == Running || 8223798Sgblack@eecs.umich.edu status() == Idle || 8233798Sgblack@eecs.umich.edu status() == DcacheMissStall); 8243798Sgblack@eecs.umich.edu 8253798Sgblack@eecs.umich.edu if (status() == Running && !tickEvent.scheduled()) 8262292SN/A tickEvent.schedule(curTick + cycles(1)); 8272292SN/A} 8282292SN/A 8292292SN/A//////////////////////////////////////////////////////////////////////// 8302292SN/A// 8312329SN/A// SimpleCPU Simulation Object 8322329SN/A// 8332301SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 8342292SN/A 8352292SN/A Param<Counter> max_insts_any_thread; 8362292SN/A Param<Counter> max_insts_all_threads; 8372292SN/A Param<Counter> max_loads_any_thread; 8382292SN/A Param<Counter> max_loads_all_threads; 8392292SN/A 8402292SN/A#if FULL_SYSTEM 8412292SN/A SimObjectParam<AlphaITB *> itb; 8422292SN/A SimObjectParam<AlphaDTB *> dtb; 8432292SN/A SimObjectParam<FunctionalMemory *> mem; 8442292SN/A SimObjectParam<System *> system; 8452292SN/A Param<int> cpu_id; 8462292SN/A Param<Tick> profile; 8472292SN/A#else 8482292SN/A SimObjectParam<Process *> workload; 8492292SN/A#endif // FULL_SYSTEM 8502301SN/A 8512292SN/A Param<int> clock; 8522292SN/A SimObjectParam<BaseMem *> icache; 8532292SN/A SimObjectParam<BaseMem *> dcache; 8542292SN/A 8552292SN/A Param<bool> defer_registration; 8562292SN/A Param<int> width; 8572292SN/A Param<bool> function_trace; 8582292SN/A Param<Tick> function_trace_start; 8592292SN/A 8602292SN/AEND_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 8612292SN/A 8622292SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 8632292SN/A 8642292SN/A INIT_PARAM(max_insts_any_thread, 8652292SN/A "terminate when any thread reaches this inst count"), 8662935Sksewell@umich.edu INIT_PARAM(max_insts_all_threads, 8672292SN/A "terminate when all threads have reached this inst count"), 8682980Sgblack@eecs.umich.edu INIT_PARAM(max_loads_any_thread, 8692980Sgblack@eecs.umich.edu "terminate when any thread reaches this load count"), 8702292SN/A INIT_PARAM(max_loads_all_threads, 8711060SN/A "terminate when all threads have reached this load count"), 8721060SN/A 8732292SN/A#if FULL_SYSTEM 8741060SN/A INIT_PARAM(itb, "Instruction TLB"), 8751060SN/A INIT_PARAM(dtb, "Data TLB"), 8761060SN/A INIT_PARAM(mem, "memory"), 8771060SN/A INIT_PARAM(system, "system object"), 8781060SN/A INIT_PARAM(cpu_id, "processor ID"), 8792292SN/A INIT_PARAM(profile, ""), 8802292SN/A#else 8812292SN/A INIT_PARAM(workload, "processes to run"), 8821062SN/A#endif // FULL_SYSTEM 8832292SN/A 8842292SN/A INIT_PARAM(clock, "clock speed"), 8851060SN/A INIT_PARAM(icache, "L1 instruction cache object"), 8862292SN/A INIT_PARAM(dcache, "L1 data cache object"), 8872292SN/A INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 8882292SN/A INIT_PARAM(width, "cpu width"), 8891060SN/A INIT_PARAM(function_trace, "Enable function trace"), 8902292SN/A INIT_PARAM(function_trace_start, "Cycle to start function trace") 8912292SN/A 8921062SN/AEND_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 8932367SN/A 8942367SN/A 8952367SN/ACREATE_SIM_OBJECT(SimpleCPU) 8962367SN/A{ 8972367SN/A SimpleCPU::Params *params = new SimpleCPU::Params(); 8982292SN/A params->name = getInstanceName(); 8991061SN/A params->numberOfThreads = 1; 9001062SN/A params->max_insts_any_thread = max_insts_any_thread; 9011060SN/A params->max_insts_all_threads = max_insts_all_threads; 9021060SN/A params->max_loads_any_thread = max_loads_any_thread; 9031060SN/A params->max_loads_all_threads = max_loads_all_threads; 9041060SN/A params->deferRegistration = defer_registration; 9051060SN/A params->clock = clock; 9062292SN/A params->functionTrace = function_trace; 9071060SN/A params->functionTraceStart = function_trace_start; 9082292SN/A params->icache_interface = (icache) ? icache->getInterface() : NULL; 9092292SN/A params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; 9102292SN/A params->width = width; 9112292SN/A 9122980Sgblack@eecs.umich.edu#if FULL_SYSTEM 9132980Sgblack@eecs.umich.edu params->itb = itb; 9141060SN/A params->dtb = dtb; 9151061SN/A params->mem = mem; 9161060SN/A params->system = system; 9172292SN/A params->cpu_id = cpu_id; 9182292SN/A params->profile = profile; 9192292SN/A#else 9202292SN/A params->process = workload; 9212292SN/A#endif 9222292SN/A 9231060SN/A SimpleCPU *cpu = new SimpleCPU(params); 9241060SN/A return cpu; 9251060SN/A} 9262292SN/A 9272292SN/AREGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 9282292SN/A 9292292SN/A