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