/*
+ * Copyright (c) 2010-2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Authors: Steve Reinhardt
*/
+#include "arch/kernel_stats.hh"
+#include "arch/stacktrace.hh"
+#include "arch/tlb.hh"
#include "arch/utility.hh"
-#include "arch/faults.hh"
-#include "base/cprintf.hh"
+#include "arch/vtophys.hh"
+#include "base/loader/symtab.hh"
#include "base/cp_annotate.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 "base/types.hh"
+#include "config/the_isa.hh"
+#include "cpu/simple/base.hh"
#include "cpu/base.hh"
+#include "cpu/checker/cpu.hh"
+#include "cpu/checker/thread_context.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 "debug/Decode.hh"
+#include "debug/Fetch.hh"
+#include "debug/Quiesce.hh"
+#include "mem/mem_object.hh"
#include "mem/packet.hh"
+#include "mem/request.hh"
+#include "params/BaseSimpleCPU.hh"
#include "sim/byteswap.hh"
#include "sim/debug.hh"
-#include "sim/host.hh"
+#include "sim/faults.hh"
+#include "sim/full_system.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_SYSTEM
-
-#include "params/BaseSimpleCPU.hh"
-
using namespace std;
using namespace TheISA;
BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
- : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
+ : BaseCPU(p), traceData(NULL), thread(NULL)
{
-#if FULL_SYSTEM
- thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
-#else
- thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0],
- p->itb, p->dtb, /* asid */ 0);
-#endif // !FULL_SYSTEM
+ if (FullSystem)
+ thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
+ else
+ thread = new SimpleThread(this, /* thread_num */ 0, p->system,
+ p->workload[0], p->itb, p->dtb);
- thread->setStatus(ThreadContext::Unallocated);
+ thread->setStatus(ThreadContext::Halted);
tc = thread->getTC();
+ if (p->checker) {
+ BaseCPU *temp_checker = p->checker;
+ checker = dynamic_cast<CheckerCPU *>(temp_checker);
+ checker->setSystem(p->system);
+ // Manipulate thread context
+ ThreadContext *cpu_tc = tc;
+ tc = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker);
+ } else {
+ checker = NULL;
+ }
+
numInst = 0;
startNumInst = 0;
+ numOp = 0;
+ startNumOp = 0;
numLoad = 0;
startNumLoad = 0;
lastIcacheStall = 0;
}
void
-BaseSimpleCPU::deallocateContext(int thread_num)
+BaseSimpleCPU::deallocateContext(ThreadID thread_num)
{
// for now, these are equivalent
suspendContext(thread_num);
void
-BaseSimpleCPU::haltContext(int thread_num)
+BaseSimpleCPU::haltContext(ThreadID thread_num)
{
// for now, these are equivalent
suspendContext(thread_num);
BaseCPU::regStats();
numInsts
- .name(name() + ".num_insts")
- .desc("Number of instructions executed")
+ .name(name() + ".committedInsts")
+ .desc("Number of instructions committed")
+ ;
+
+ numOps
+ .name(name() + ".committedOps")
+ .desc("Number of ops (including micro ops) committed")
+ ;
+
+ numIntAluAccesses
+ .name(name() + ".num_int_alu_accesses")
+ .desc("Number of integer alu accesses")
+ ;
+
+ numFpAluAccesses
+ .name(name() + ".num_fp_alu_accesses")
+ .desc("Number of float alu accesses")
+ ;
+
+ numCallsReturns
+ .name(name() + ".num_func_calls")
+ .desc("number of times a function call or return occured")
+ ;
+
+ numCondCtrlInsts
+ .name(name() + ".num_conditional_control_insts")
+ .desc("number of instructions that are conditional controls")
+ ;
+
+ numIntInsts
+ .name(name() + ".num_int_insts")
+ .desc("number of integer instructions")
+ ;
+
+ numFpInsts
+ .name(name() + ".num_fp_insts")
+ .desc("number of float instructions")
+ ;
+
+ numIntRegReads
+ .name(name() + ".num_int_register_reads")
+ .desc("number of times the integer registers were read")
+ ;
+
+ numIntRegWrites
+ .name(name() + ".num_int_register_writes")
+ .desc("number of times the integer registers were written")
+ ;
+
+ numFpRegReads
+ .name(name() + ".num_fp_register_reads")
+ .desc("number of times the floating registers were read")
+ ;
+
+ numFpRegWrites
+ .name(name() + ".num_fp_register_writes")
+ .desc("number of times the floating registers were written")
;
numMemRefs
- .name(name() + ".num_refs")
- .desc("Number of memory references")
+ .name(name()+".num_mem_refs")
+ .desc("number of memory refs")
+ ;
+
+ numStoreInsts
+ .name(name() + ".num_store_insts")
+ .desc("Number of store instructions")
+ ;
+
+ numLoadInsts
+ .name(name() + ".num_load_insts")
+ .desc("Number of load instructions")
;
notIdleFraction
.desc("Percentage of idle cycles")
;
+ numBusyCycles
+ .name(name() + ".num_busy_cycles")
+ .desc("Number of busy cycles")
+ ;
+
+ numIdleCycles
+ .name(name()+".num_idle_cycles")
+ .desc("Number of idle cycles")
+ ;
+
icacheStallCycles
.name(name() + ".icache_stall_cycles")
.desc("ICache total stall cycles")
;
idleFraction = constant(1.0) - notIdleFraction;
+ numIdleCycles = idleFraction * numCycles;
+ numBusyCycles = (notIdleFraction)*numCycles;
}
void
}
void
-change_thread_state(int thread_number, int activate, int priority)
-{
-}
-
-Fault
-BaseSimpleCPU::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
-}
-
-Fault
-BaseSimpleCPU::copy(Addr dest)
+change_thread_state(ThreadID tid, int activate, int priority)
{
-#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_SYSTEM
Addr
BaseSimpleCPU::dbg_vtophys(Addr addr)
{
return vtophys(tc, addr);
}
-#endif // FULL_SYSTEM
-#if FULL_SYSTEM
void
BaseSimpleCPU::wakeup()
{
DPRINTF(Quiesce,"Suspended Processor awoke\n");
thread->activate();
}
-#endif // FULL_SYSTEM
void
BaseSimpleCPU::checkForInterrupts()
{
-#if FULL_SYSTEM
if (checkInterrupts(tc)) {
Fault interrupt = interrupts->getInterrupt(tc);
if (interrupt != NoFault) {
- predecoder.reset();
+ fetchOffset = 0;
interrupts->updateIntrInfo(tc);
interrupt->invoke(tc);
+ thread->decoder.reset();
}
}
-#endif
}
void
BaseSimpleCPU::setupFetchRequest(Request *req)
{
- Addr threadPC = thread->readPC();
+ Addr instAddr = thread->instAddr();
// 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);
+ DPRINTF(Fetch, "Fetch: PC:%08p\n", instAddr);
+
+ Addr fetchPC = (instAddr & PCMask) + fetchOffset;
+ req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, instMasterId(),
+ instAddr);
}
// check for instruction-count-based events
comInstEventQueue[0]->serviceEvents(numInst);
+ system->instEventQueue.serviceEvents(system->totalNumInsts);
// decode the instruction
inst = gtoh(inst);
- MicroPC upc = thread->readMicroPC();
+ TheISA::PCState pcState = thread->pcState();
- if (isRomMicroPC(upc)) {
+ if (isRomMicroPC(pcState.microPC())) {
stayAtPC = false;
- curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst);
+ curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(),
+ curMacroStaticInst);
} else if (!curMacroStaticInst) {
//We're not in the middle of a macro instruction
StaticInstPtr instPtr = NULL;
+ TheISA::Decoder *decoder = &(thread->decoder);
+
//Predecode, ie bundle up an ExtMachInst
//This should go away once the constructor can be set up properly
- predecoder.setTC(thread->getTC());
+ decoder->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);
+ Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
+ //if(decoder->needMoreBytes())
+ decoder->moreBytes(pcState, fetchPC, inst);
//else
- // predecoder.process();
+ // decoder->process();
- //If an instruction is ready, decode it. Otherwise, we'll have to
+ //Decode an instruction if one is ready. Otherwise, we'll have to
//fetch beyond the MachInst at the current pc.
- if (predecoder.extMachInstReady()) {
-#if THE_ISA == X86_ISA
- thread->setNextPC(thread->readPC() + predecoder.getInstSize());
-#endif // X86_ISA
+ instPtr = decoder->decode(pcState);
+ if (instPtr) {
stayAtPC = false;
- instPtr = StaticInst::decode(predecoder.getExtMachInst(),
- thread->readPC());
+ thread->pcState(pcState);
} else {
stayAtPC = true;
fetchOffset += sizeof(MachInst);
//out micro ops
if (instPtr && instPtr->isMacroop()) {
curMacroStaticInst = instPtr;
- curStaticInst = curMacroStaticInst->fetchMicroop(upc);
+ curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
} else {
curStaticInst = instPtr;
}
} else {
//Read the next micro op from the macro op
- curStaticInst = curMacroStaticInst->fetchMicroop(upc);
+ curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
}
//If we decoded an instruction this "tick", record information about it.
- if(curStaticInst)
- {
+ if (curStaticInst) {
#if TRACING_ON
- traceData = tracer->getInstRecord(curTick, tc,
- curStaticInst, thread->readPC(),
- curMacroStaticInst, thread->readMicroPC());
+ traceData = tracer->getInstRecord(curTick(), tc,
+ curStaticInst, thread->pcState(), curMacroStaticInst);
- DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
+ DPRINTF(Decode,"Decode: Decoded %s instruction: %#x\n",
curStaticInst->getName(), curStaticInst->machInst);
#endif // TRACING_ON
-
-#if FULL_SYSTEM
- thread->setInst(inst);
-#endif // FULL_SYSTEM
}
}
void
BaseSimpleCPU::postExecute()
{
-#if FULL_SYSTEM
- if (thread->profile && curStaticInst) {
+ assert(curStaticInst);
+
+ TheISA::PCState pc = tc->pcState();
+ Addr instAddr = pc.instAddr();
+ if (FullSystem && thread->profile) {
bool usermode = TheISA::inUserMode(tc);
- thread->profilePC = usermode ? 1 : thread->readPC();
+ thread->profilePC = usermode ? 1 : instAddr;
ProfileNode *node = thread->profile->consume(tc, curStaticInst);
if (node)
thread->profileNode = node;
}
-#endif
if (curStaticInst->isMemRef()) {
numMemRefs++;
}
if (CPA::available()) {
- CPA::cpa()->swAutoBegin(tc, thread->readNextPC());
+ CPA::cpa()->swAutoBegin(tc, pc.nextInstAddr());
}
- traceFunctions(thread->readPC());
+ /* Power model statistics */
+ //integer alu accesses
+ if (curStaticInst->isInteger()){
+ numIntAluAccesses++;
+ numIntInsts++;
+ }
+
+ //float alu accesses
+ if (curStaticInst->isFloating()){
+ numFpAluAccesses++;
+ numFpInsts++;
+ }
+
+ //number of function calls/returns to get window accesses
+ if (curStaticInst->isCall() || curStaticInst->isReturn()){
+ numCallsReturns++;
+ }
+
+ //the number of branch predictions that will be made
+ if (curStaticInst->isCondCtrl()){
+ numCondCtrlInsts++;
+ }
+
+ //result bus acceses
+ if (curStaticInst->isLoad()){
+ numLoadInsts++;
+ }
+
+ if (curStaticInst->isStore()){
+ numStoreInsts++;
+ }
+ /* End power model statistics */
+
+ if (FullSystem)
+ traceFunctions(instAddr);
if (traceData) {
traceData->dump();
fetchOffset = 0;
if (fault != NoFault) {
curMacroStaticInst = StaticInst::nullStaticInstPtr;
- predecoder.reset();
- fault->invoke(tc);
+ fault->invoke(tc, curStaticInst);
+ thread->decoder.reset();
} else {
- //If we're at the last micro op for this instruction
- if (curStaticInst && curStaticInst->isLastMicroop()) {
- //We should be working with a macro op or be in the ROM
- assert(curMacroStaticInst ||
- isRomMicroPC(thread->readMicroPC()));
- //Close out this macro op, and clean up the
- //microcode state
- curMacroStaticInst = StaticInst::nullStaticInstPtr;
- thread->setMicroPC(normalMicroPC(0));
- thread->setNextMicroPC(normalMicroPC(1));
- }
- //If we're still in a macro op
- if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) {
- //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());
+ if (curStaticInst) {
+ if (curStaticInst->isLastMicroop())
+ curMacroStaticInst = StaticInst::nullStaticInstPtr;
+ TheISA::PCState pcState = thread->pcState();
+ TheISA::advancePC(pcState, curStaticInst);
+ thread->pcState(pcState);
}
}
}