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