base.cc
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 530 行
CC
530 行
/* * Copyright (c) 2002, 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * 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. * * Authors: Steven K. Reinhardt */#include "arch/utility.hh"#include "arch/faults.hh"#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/exetrace.hh"#include "cpu/profile.hh"#include "cpu/simple/base.hh"#include "cpu/simple_thread.hh"#include "cpu/smt.hh"#include "cpu/static_inst.hh"#include "cpu/thread_context.hh"#include "mem/packet.hh"#include "sim/byteswap.hh"#include "sim/debug.hh"#include "sim/host.hh"#include "sim/sim_events.hh"#include "sim/sim_object.hh"#include "sim/stats.hh"#include "sim/system.hh"#if FULL_SYSTEM#include "arch/kernel_stats.hh"#include "arch/stacktrace.hh"#include "arch/tlb.hh"#include "arch/vtophys.hh"#include "base/remote_gdb.hh"#else // !FULL_SYSTEM#include "mem/mem_object.hh"#endif // FULL_SYSTEMusing namespace std;using namespace TheISA;BaseSimpleCPU::BaseSimpleCPU(Params *p) : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL){#if FULL_SYSTEM thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);#else thread = new SimpleThread(this, /* thread_num */ 0, p->process, p->itb, p->dtb, /* asid */ 0);#endif // !FULL_SYSTEM thread->setStatus(ThreadContext::Unallocated); tc = thread->getTC(); numInst = 0; startNumInst = 0; numLoad = 0; startNumLoad = 0; lastIcacheStall = 0; lastDcacheStall = 0; threadContexts.push_back(tc); fetchOffset = 0; stayAtPC = false;}BaseSimpleCPU::~BaseSimpleCPU(){}voidBaseSimpleCPU::deallocateContext(int thread_num){ // for now, these are equivalent suspendContext(thread_num);}voidBaseSimpleCPU::haltContext(int thread_num){ // for now, these are equivalent suspendContext(thread_num);}voidBaseSimpleCPU::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) ; icacheRetryCycles .name(name() + ".icache_retry_cycles") .desc("ICache total retry cycles") .prereq(icacheRetryCycles) ; dcacheRetryCycles .name(name() + ".dcache_retry_cycles") .desc("DCache total retry cycles") .prereq(dcacheRetryCycles) ; idleFraction = constant(1.0) - notIdleFraction;}voidBaseSimpleCPU::resetStats(){// startNumInst = numInst; // notIdleFraction = (_status != Idle);}voidBaseSimpleCPU::serialize(ostream &os){ BaseCPU::serialize(os);// SERIALIZE_SCALAR(inst); nameOut(os, csprintf("%s.xc.0", name())); thread->serialize(os);}voidBaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion){ BaseCPU::unserialize(cp, section);// UNSERIALIZE_SCALAR(inst); thread->unserialize(cp, csprintf("%s.xc.0", section));}voidchange_thread_state(int thread_number, int activate, int priority){}FaultBaseSimpleCPU::copySrcTranslate(Addr src){#if 0 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 & PageMask) != ((src + blk_size) & 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 = thread->translateDataReadReq(req); if (fault == NoFault) { thread->copySrcAddr = src; thread->copySrcPhysAddr = memReq->paddr + offset; } else { assert(!fault->isAlignmentFault()); thread->copySrcAddr = 0; thread->copySrcPhysAddr = 0; } return fault;#else return NoFault;#endif}FaultBaseSimpleCPU::copy(Addr dest){#if 0 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(thread->copySrcAddr); int offset = dest & (blk_size - 1); // Make sure block doesn't span page if (no_warn && (dest & PageMask) != ((dest + blk_size) & 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 = thread->translateDataWriteReq(req); if (fault == NoFault) { Addr dest_addr = memReq->paddr + offset; // Need to read straight from memory since we have more than 8 bytes. memReq->paddr = thread->copySrcPhysAddr; thread->mem->read(memReq, data); memReq->paddr = dest_addr; thread->mem->write(memReq, data); if (dcacheInterface) { memReq->cmd = Copy; memReq->completionEvent = NULL; memReq->paddr = thread->copySrcPhysAddr; memReq->dest = dest_addr; memReq->size = 64; memReq->time = curTick; memReq->flags &= ~INST_READ; dcacheInterface->access(memReq); } } else assert(!fault->isAlignmentFault()); return fault;#else panic("copy not implemented"); return NoFault;#endif}#if FULL_SYSTEMAddrBaseSimpleCPU::dbg_vtophys(Addr addr){ return vtophys(tc, addr);}#endif // FULL_SYSTEM#if FULL_SYSTEMvoidBaseSimpleCPU::post_interrupt(int int_num, int index){ BaseCPU::post_interrupt(int_num, index); if (thread->status() == ThreadContext::Suspended) { DPRINTF(Quiesce,"Suspended Processor awoke\n"); thread->activate(); }}#endif // FULL_SYSTEMvoidBaseSimpleCPU::checkForInterrupts(){#if FULL_SYSTEM if (check_interrupts(tc)) { Fault interrupt = interrupts.getInterrupt(tc); if (interrupt != NoFault) { interrupts.updateIntrInfo(tc); interrupt->invoke(tc); } }#endif}FaultBaseSimpleCPU::setupFetchRequest(Request *req){ Addr threadPC = thread->readPC(); // set up memory request for instruction fetch#if ISA_HAS_DELAY_SLOT DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",threadPC, thread->readNextPC(),thread->readNextNPC());#else DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p\n",threadPC, thread->readNextPC());#endif Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); Fault fault = thread->translateInstReq(req); return fault;}voidBaseSimpleCPU::preExecute(){ // maintain $r0 semantics thread->setIntReg(ZeroReg, 0);#if THE_ISA == ALPHA_ISA thread->setFloatReg(ZeroReg, 0.0);#endif // ALPHA_ISA // check for instruction-count-based events comInstEventQueue[0]->serviceEvents(numInst); // decode the instruction inst = gtoh(inst); //If we're not in the middle of a macro instruction if (!curMacroStaticInst) { StaticInstPtr instPtr = NULL; //Predecode, ie bundle up an ExtMachInst //This should go away once the constructor can be set up properly predecoder.setTC(thread->getTC()); //If more fetch data is needed, pass it in. Addr fetchPC = (thread->readPC() & PCMask) + fetchOffset; //if(predecoder.needMoreBytes()) predecoder.moreBytes(thread->readPC(), fetchPC, inst); //else // predecoder.process(); //If an instruction is ready, decode it. Otherwise, we'll have to //fetch beyond the MachInst at the current pc. if (predecoder.extMachInstReady()) { stayAtPC = false; instPtr = StaticInst::decode(predecoder.getExtMachInst(), thread->readPC()); } else { stayAtPC = true; fetchOffset += sizeof(MachInst); } //If we decoded an instruction and it's microcoded, start pulling //out micro ops if (instPtr && instPtr->isMacroop()) { curMacroStaticInst = instPtr; curStaticInst = curMacroStaticInst-> fetchMicroop(thread->readMicroPC()); } else { curStaticInst = instPtr; } } else { //Read the next micro op from the macro op curStaticInst = curMacroStaticInst-> fetchMicroop(thread->readMicroPC()); } //If we decoded an instruction this "tick", record information about it. if(curStaticInst) {#if TRACING_ON traceData = tracer->getInstRecord(curTick, tc, curStaticInst, thread->readPC()); DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", curStaticInst->getName(), curStaticInst->machInst);#endif // TRACING_ON#if FULL_SYSTEM thread->setInst(inst);#endif // FULL_SYSTEM }}voidBaseSimpleCPU::postExecute(){#if FULL_SYSTEM if (thread->profile && curStaticInst) { bool usermode = TheISA::inUserMode(tc); thread->profilePC = usermode ? 1 : thread->readPC(); ProfileNode *node = thread->profile->consume(tc, curStaticInst); if (node) thread->profileNode = node; }#endif if (curStaticInst->isMemRef()) { numMemRefs++; } if (curStaticInst->isLoad()) { ++numLoad; comLoadEventQueue[0]->serviceEvents(numLoad); } traceFunctions(thread->readPC()); if (traceData) { traceData->dump(); delete traceData; traceData = NULL; }}voidBaseSimpleCPU::advancePC(Fault fault){ //Since we're moving to a new pc, zero out the offset fetchOffset = 0; if (fault != NoFault) { curMacroStaticInst = StaticInst::nullStaticInstPtr; predecoder.reset(); thread->setMicroPC(0); thread->setNextMicroPC(1); fault->invoke(tc); } else { //If we're at the last micro op for this instruction if (curStaticInst && curStaticInst->isLastMicroop()) { //We should be working with a macro op assert(curMacroStaticInst); //Close out this macro op, and clean up the //microcode state curMacroStaticInst = StaticInst::nullStaticInstPtr; thread->setMicroPC(0); thread->setNextMicroPC(1); } //If we're still in a macro op if (curMacroStaticInst) { //Advance the micro pc thread->setMicroPC(thread->readNextMicroPC()); //Advance the "next" micro pc. Note that there are no delay //slots, and micro ops are "word" addressed. thread->setNextMicroPC(thread->readNextMicroPC() + 1); } else { // go to the next instruction thread->setPC(thread->readNextPC()); thread->setNextPC(thread->readNextNPC()); thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); assert(thread->readNextPC() != thread->readNextNPC()); } }}/*FaultBaseSimpleCPU::CacheOp(uint8_t Op, Addr EffAddr){ // translate to physical address Fault fault = NoFault; int CacheID = Op & 0x3; // Lower 3 bits identify Cache int CacheOP = Op >> 2; // Upper 3 bits identify Cache Operation if(CacheID > 1) { warn("CacheOps not implemented for secondary/tertiary caches\n"); } else { switch(CacheOP) { // Fill Packet Type case 0: warn("Invalidate Cache Op\n"); break; case 1: warn("Index Load Tag Cache Op\n"); break; case 2: warn("Index Store Tag Cache Op\n"); break; case 4: warn("Hit Invalidate Cache Op\n"); break; case 5: warn("Fill/Hit Writeback Invalidate Cache Op\n"); break; case 6: warn("Hit Writeback\n"); break; case 7: warn("Fetch & Lock Cache Op\n"); break; default: warn("Unimplemented Cache Op\n"); } } return fault;}*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?