📄 cpu.cc
字号:
/* * Copyright (c) 2002, 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator, developed by Nathan Binkert, * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions * from Ron Dreslinski, Dave Greene, Lisa Hsu, Kevin Lim, Ali Saidi, * and Andrew Schultz. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. */#include <cmath>#include <cstdio>#include <cstdlib>#include <iostream>#include <iomanip>#include <list>#include <sstream>#include <string>#include "base/cprintf.hh"#include "base/inifile.hh"#include "base/loader/symtab.hh"#include "base/misc.hh"#include "base/pollevent.hh"#include "base/range.hh"#include "base/stats/events.hh"#include "base/trace.hh"#include "cpu/base.hh"#include "cpu/exec_context.hh"#include "cpu/exetrace.hh"#include "cpu/sampler/sampler.hh"#include "cpu/simple/cpu.hh"#include "cpu/smt.hh"#include "cpu/static_inst.hh"#include "mem/base_mem.hh"#include "mem/mem_interface.hh"#include "sim/builder.hh"#include "sim/debug.hh"#include "sim/host.hh"#include "sim/sim_events.hh"#include "sim/sim_object.hh"#include "sim/stats.hh"#if FULL_SYSTEM#include "base/remote_gdb.hh"#include "mem/functional/memory_control.hh"#include "mem/functional/physical.hh"#include "sim/system.hh"#include "targetarch/alpha_memory.hh"#include "targetarch/vtophys.hh"#else // !FULL_SYSTEM#include "mem/functional/functional.hh"#endif // FULL_SYSTEMusing namespace std;SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w){}voidSimpleCPU::TickEvent::process(){ int count = width; do { cpu->tick(); } while (--count > 0 && cpu->status() == Running);}const char *SimpleCPU::TickEvent::description(){ return "SimpleCPU tick event";}SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) : Event(&mainEventQueue), cpu(_cpu){}void SimpleCPU::CacheCompletionEvent::process(){ cpu->processCacheCompletion();}const char *SimpleCPU::CacheCompletionEvent::description(){ return "SimpleCPU cache completion event";}SimpleCPU::SimpleCPU(Params *p) : BaseCPU(p), tickEvent(this, p->width), xc(NULL), cacheCompletionEvent(this){ _status = Idle;#if FULL_SYSTEM xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); // initialize CPU, including PC TheISA::initCPU(&xc->regs);#else xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0);#endif // !FULL_SYSTEM icacheInterface = p->icache_interface; dcacheInterface = p->dcache_interface; memReq = new MemReq(); memReq->xc = xc; memReq->asid = 0; memReq->data = new uint8_t[64]; numInst = 0; startNumInst = 0; numLoad = 0; startNumLoad = 0; lastIcacheStall = 0; lastDcacheStall = 0; execContexts.push_back(xc);}SimpleCPU::~SimpleCPU(){}voidSimpleCPU::switchOut(Sampler *s){ sampler = s; if (status() == DcacheMissStall) { DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); _status = DcacheMissSwitch; } else { _status = SwitchedOut; if (tickEvent.scheduled()) tickEvent.squash(); sampler->signalSwitched(); }}voidSimpleCPU::takeOverFrom(BaseCPU *oldCPU){ BaseCPU::takeOverFrom(oldCPU); assert(!tickEvent.scheduled()); // if any of this CPU's ExecContexts are active, mark the CPU as // running and schedule its tick event. for (int i = 0; i < execContexts.size(); ++i) { ExecContext *xc = execContexts[i]; if (xc->status() == ExecContext::Active && _status != Running) { _status = Running; tickEvent.schedule(curTick); } }}voidSimpleCPU::activateContext(int thread_num, int delay){ assert(thread_num == 0); assert(xc); assert(_status == Idle); notIdleFraction++; scheduleTickEvent(delay); _status = Running;}voidSimpleCPU::suspendContext(int thread_num){ assert(thread_num == 0); assert(xc); assert(_status == Running); notIdleFraction--; unscheduleTickEvent(); _status = Idle;}voidSimpleCPU::deallocateContext(int thread_num){ // for now, these are equivalent suspendContext(thread_num);}voidSimpleCPU::haltContext(int thread_num){ // for now, these are equivalent suspendContext(thread_num);}voidSimpleCPU::regStats(){ using namespace Stats; BaseCPU::regStats(); numInsts .name(name() + ".num_insts") .desc("Number of instructions executed") ; numMemRefs .name(name() + ".num_refs") .desc("Number of memory references") ; notIdleFraction .name(name() + ".not_idle_fraction") .desc("Percentage of non-idle cycles") ; idleFraction .name(name() + ".idle_fraction") .desc("Percentage of idle cycles") ; icacheStallCycles .name(name() + ".icache_stall_cycles") .desc("ICache total stall cycles") .prereq(icacheStallCycles) ; dcacheStallCycles .name(name() + ".dcache_stall_cycles") .desc("DCache total stall cycles") .prereq(dcacheStallCycles) ; idleFraction = constant(1.0) - notIdleFraction;}voidSimpleCPU::resetStats(){ startNumInst = numInst; notIdleFraction = (_status != Idle);}voidSimpleCPU::serialize(ostream &os){ BaseCPU::serialize(os); SERIALIZE_ENUM(_status); SERIALIZE_SCALAR(inst); nameOut(os, csprintf("%s.xc", name())); xc->serialize(os); nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); nameOut(os, csprintf("%s.cacheCompletionEvent", name())); cacheCompletionEvent.serialize(os);}voidSimpleCPU::unserialize(Checkpoint *cp, const string §ion){ BaseCPU::unserialize(cp, section); UNSERIALIZE_ENUM(_status); UNSERIALIZE_SCALAR(inst); xc->unserialize(cp, csprintf("%s.xc", section)); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); cacheCompletionEvent .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));}voidchange_thread_state(int thread_number, int activate, int priority){}FaultSimpleCPU::copySrcTranslate(Addr src){ static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; // Only support block sizes of 64 atm. assert(blk_size == 64); int offset = src & (blk_size - 1); // Make sure block doesn't span page if (no_warn && (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && (src >> 40) != 0xfffffc) { warn("Copied block source spans pages %x.", src); no_warn = false; } memReq->reset(src & ~(blk_size - 1), blk_size); // translate to physical address Fault fault = xc->translateDataReadReq(memReq); assert(fault != Alignment_Fault); if (fault == No_Fault) { xc->copySrcAddr = src; xc->copySrcPhysAddr = memReq->paddr + offset; } else { xc->copySrcAddr = 0; xc->copySrcPhysAddr = 0; } return fault;}FaultSimpleCPU::copy(Addr dest){ static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; // Only support block sizes of 64 atm. assert(blk_size == 64); uint8_t data[blk_size]; //assert(xc->copySrcAddr); int offset = dest & (blk_size - 1); // Make sure block doesn't span page if (no_warn && (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && (dest >> 40) != 0xfffffc) { no_warn = false; warn("Copied block destination spans pages %x. ", dest); } memReq->reset(dest & ~(blk_size -1), blk_size); // translate to physical address Fault fault = xc->translateDataWriteReq(memReq); assert(fault != Alignment_Fault); if (fault == No_Fault) { Addr dest_addr = memReq->paddr + offset; // Need to read straight from memory since we have more than 8 bytes. memReq->paddr = xc->copySrcPhysAddr; xc->mem->read(memReq, data); memReq->paddr = dest_addr; xc->mem->write(memReq, data); if (dcacheInterface) { memReq->cmd = Copy; memReq->completionEvent = NULL; memReq->paddr = xc->copySrcPhysAddr; memReq->dest = dest_addr; memReq->size = 64; memReq->time = curTick; dcacheInterface->access(memReq); } } return fault;}// precise architected memory state accessor macrostemplate <class T>FaultSimpleCPU::read(Addr addr, T &data, unsigned flags){ if (status() == DcacheMissStall || status() == DcacheMissSwitch) { Fault fault = xc->read(memReq,data); if (traceData) { traceData->setAddr(addr); } return fault; } memReq->reset(addr, sizeof(T), flags); // translate to physical address Fault fault = xc->translateDataReadReq(memReq); // if we have a cache, do cache access too if (fault == No_Fault && dcacheInterface) { memReq->cmd = Read; memReq->completionEvent = NULL; memReq->time = curTick; MemAccessResult result = dcacheInterface->access(memReq); // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. if (result != MA_HIT && dcacheInterface->doEvents()) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; unscheduleTickEvent(); _status = DcacheMissStall; } else { // do functional access fault = xc->read(memReq, data); } } else if(fault == No_Fault) { // do functional access fault = xc->read(memReq, data); } if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) recordEvent("Uncached Read"); return fault;}#ifndef DOXYGEN_SHOULD_SKIP_THIStemplateFaultSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);templateFaultSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);templateFaultSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -