From c23b23f4e7f9f0faec555cb282c899b77223a110 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Tue, 16 May 2006 13:59:29 -0400 Subject: Add in checker. Supports dynamically verifying the execution of instructions, as well as limited amount of control path verification. It will verify anything within the program, but anything external (traps, interrupts, XC) it assumes is redirected properly by the CPU. Similarly it assumes the results of store conditionals, uncached loads, and instructions marked as "unverifiable" are correct from the CPU. base/traceflags.py: build/SConstruct: cpu/SConscript: cpu/cpu_models.py: Add in Checker. cpu/base.cc: Add in checker support. Also XC status starts off as suspended. cpu/base.hh: Add in checker. --HG-- extra : convert_revision : 091b5cc83e837858adb681ef0137a0beb30bd1b2 --- cpu/checker/cpu.cc | 857 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 857 insertions(+) create mode 100644 cpu/checker/cpu.cc (limited to 'cpu/checker/cpu.cc') diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc new file mode 100644 index 000000000..f1b43f601 --- /dev/null +++ b/cpu/checker/cpu.cc @@ -0,0 +1,857 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//#include +#include +//#include +#include +#include +#include +//#include +#include + +//#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/refcnt.hh" +//#include "base/stats/events.hh" +#include "cpu/base.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/checker/cpu.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" +//#include "cpu/exetrace.hh" +//#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +//#include "cpu/smt.hh" +#include "cpu/static_inst.hh" +//#include "kern/kernel_stats.hh" +#include "mem/base_mem.hh" +#include "mem/mem_interface.hh" +#include "sim/byteswap.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" + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" + +#include "cpu/ozone/dyn_inst.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/simple_impl.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 "arch/tlb.hh" +#include "arch/stacktrace.hh" +#include "arch/vtophys.hh" +#else // !FULL_SYSTEM +#include "mem/functional/functional.hh" +#endif // FULL_SYSTEM + +using namespace std; +//The CheckerCPU does alpha only +using namespace AlphaISA; + +void +CheckerCPU::init() +{ +/* + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(xc, xc->readCpuId()); + } +#endif +*/ +} + +CheckerCPU::CheckerCPU(Params *p) + : BaseCPU(p), cpuXC(NULL), xcProxy(NULL) +{ + memReq = new MemReq(); + memReq->xc = xcProxy; + memReq->asid = 0; + memReq->data = new uint8_t[64]; + + numInst = 0; + startNumInst = 0; + numLoad = 0; + startNumLoad = 0; + youngestSN = 0; + + changedPC = willChangePC = changedNextPC = false; + + exitOnError = p->exitOnError; +#if FULL_SYSTEM + itb = p->itb; + dtb = p->dtb; + systemPtr = NULL; + memPtr = NULL; +#endif +} + +CheckerCPU::~CheckerCPU() +{ +} + +void +CheckerCPU::setMemory(FunctionalMemory *mem) +{ + memPtr = mem; +#if !FULL_SYSTEM + cpuXC = new CPUExecContext(this, /* thread_num */ 0, mem, + /* asid */ 0); + + cpuXC->setStatus(ExecContext::Suspended); + xcProxy = cpuXC->getProxy(); + execContexts.push_back(xcProxy); +#else + if (systemPtr) { + cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr); + + cpuXC->setStatus(ExecContext::Suspended); + xcProxy = cpuXC->getProxy(); + execContexts.push_back(xcProxy); + memReq->xc = xcProxy; + } +#endif +} + +#if FULL_SYSTEM +void +CheckerCPU::setSystem(System *system) +{ + systemPtr = system; + + if (memPtr) { + cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr); + + cpuXC->setStatus(ExecContext::Suspended); + xcProxy = cpuXC->getProxy(); + execContexts.push_back(xcProxy); + memReq->xc = xcProxy; + } +} +#endif + +void +CheckerCPU::serialize(ostream &os) +{ +/* + BaseCPU::serialize(os); + SERIALIZE_SCALAR(inst); + nameOut(os, csprintf("%s.xc", name())); + cpuXC->serialize(os); + cacheCompletionEvent.serialize(os); +*/ +} + +void +CheckerCPU::unserialize(Checkpoint *cp, const string §ion) +{ +/* + BaseCPU::unserialize(cp, section); + UNSERIALIZE_SCALAR(inst); + cpuXC->unserialize(cp, csprintf("%s.xc", section)); +*/ +} + +Fault +CheckerCPU::copySrcTranslate(Addr src) +{ + static bool no_warn = true; + int blk_size = 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 = cpuXC->translateDataReadReq(memReq); + + if (fault == NoFault) { + cpuXC->copySrcAddr = src; + cpuXC->copySrcPhysAddr = memReq->paddr + offset; + } else { + assert(!fault->isAlignmentFault()); + + cpuXC->copySrcAddr = 0; + cpuXC->copySrcPhysAddr = 0; + } + return fault; +} + +Fault +CheckerCPU::copy(Addr dest) +{ + static bool no_warn = true; + int blk_size = 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + uint8_t data[blk_size]; + //assert(cpuXC->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 = cpuXC->translateDataWriteReq(memReq); + + if (fault == NoFault) { + Addr dest_addr = memReq->paddr + offset; + // Need to read straight from memory since we have more than 8 bytes. + memReq->paddr = cpuXC->copySrcPhysAddr; + cpuXC->mem->read(memReq, data); + memReq->paddr = dest_addr; + cpuXC->mem->write(memReq, data); + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = cpuXC->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + } + else + assert(!fault->isAlignmentFault()); + + return fault; +} + +// precise architected memory state accessor macros +template +Fault +CheckerCPU::read(Addr addr, T &data, unsigned flags) +{ + memReq->reset(addr, sizeof(T), flags); + + // translate to physical address + // Should I probe the DTB? Or should I just take the physical address + // and assume correct translation? + translateDataReadReq(memReq); + + // if we have a cache, do cache access too + memReq->cmd = Read; + memReq->completionEvent = NULL; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + + if (!(memReq->flags & UNCACHEABLE)) { + cpuXC->read(memReq, data); + } else { + // Assume the data is correct if it's an uncached access + memcpy(&data, &unverifiedResult.integer, sizeof(T)); + } + + return NoFault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +CheckerCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +CheckerCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + +template<> +Fault +CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + +template +Fault +CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + memReq->reset(addr, sizeof(T), flags); + + // translate to physical address + cpuXC->translateDataWriteReq(memReq); + + if ((!(unverifiedReq->flags & LOCKED) || + ((unverifiedReq->flags & LOCKED) && + unverifiedReq->result == 1)) && + !(unverifiedReq->flags & UNCACHEABLE)) { + // do functional access +// cpuXC->read(memReq, data); + + memReq->cmd = Write; +// memcpy(memReq->data,(uint8_t *)&data,memReq->size); + T inst_data; + memcpy(&inst_data, unverifiedReq->data, sizeof(T)); + memReq->completionEvent = NULL; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + + // Hard to verify this as the data writes back after the + // instruction commits. May only be able to check that the + // value produced from execute() matches the value produced + // from the instruction's first execution. + if (data != inst_data) { + warn("Store value does not match value in memory! " + "Instruction: %#x, memory: %#x", + inst_data, data); + handleError(); + } + } + + // Assume the result was the same as the one passed in. This checker + // doesn't check if the SC should succeed or fail, it just checks the + // value. + if (res) + *res = unverifiedReq->result; + + return NoFault; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); + +template +Fault +CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); + +template +Fault +CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); + +template +Fault +CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + +template<> +Fault +CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +#if FULL_SYSTEM +Addr +CheckerCPU::dbg_vtophys(Addr addr) +{ + return vtophys(xcProxy, addr); +} +#endif // FULL_SYSTEM + +#if FULL_SYSTEM +void +CheckerCPU::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (cpuXC->status() == ExecContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + cpuXC->activate(); + } +} +#endif // FULL_SYSTEM + +bool +CheckerCPU::translateInstReq(MemReqPtr &req) +{ +#if FULL_SYSTEM + return (cpuXC->translateInstReq(req) == NoFault); +#else + cpuXC->translateInstReq(req); + return true; +#endif +} + +void +CheckerCPU::translateDataReadReq(MemReqPtr &req) +{ + cpuXC->translateDataReadReq(req); + + if (req->vaddr != unverifiedReq->vaddr) { + warn("Request virtual addresses do not match! Inst: %#x, checker:" + " %#x", + unverifiedReq->vaddr, req->vaddr); + } + req->paddr = unverifiedReq->paddr; + + if (checkFlags(req)) { + warn("Request flags do not match! Inst: %#x, checker: %#x", + unverifiedReq->flags, req->flags); + handleError(); + } +} + +void +CheckerCPU::translateDataWriteReq(MemReqPtr &req) +{ + cpuXC->translateDataWriteReq(req); + + if (req->vaddr != unverifiedReq->vaddr) { + warn("Request virtual addresses do not match! Inst: %#x, checker:" + " %#x", + unverifiedReq->vaddr, req->vaddr); + } + req->paddr = unverifiedReq->paddr; + + if (checkFlags(req)) { + warn("Request flags do not match! Inst: %#x, checker: %#x", + unverifiedReq->flags, req->flags); + handleError(); + } +} + +bool +CheckerCPU::checkFlags(MemReqPtr &req) +{ + // Remove any dynamic flags that don't have to do with the request itself. + unsigned flags = unverifiedReq->flags; + unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT; + flags = flags & (mask); + if (flags == req->flags) { + return false; + } else { + return true; + } +} + +/* start simulation, program loaded, processor precise state initialized */ +template +void +Checker::tick(DynInstPtr &completed_inst) +{ + DynInstPtr inst; + + if (!instList.empty()) { + if (youngestSN < completed_inst->seqNum) { + DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", + completed_inst->seqNum, completed_inst->readPC()); + instList.push_back(completed_inst); + youngestSN = completed_inst->seqNum; + } + + if (!instList.front()->isCompleted()) { + return; + } else { + inst = instList.front(); + instList.pop_front(); + } + } else { + if (!completed_inst->isCompleted()) { + if (youngestSN < completed_inst->seqNum) { + DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", + completed_inst->seqNum, completed_inst->readPC()); + instList.push_back(completed_inst); + youngestSN = completed_inst->seqNum; + } + return; + } else { + if (youngestSN < completed_inst->seqNum) { + inst = completed_inst; + youngestSN = completed_inst->seqNum; + } else { +// panic("SN already seen yet the list is empty!"); + return; + } + } + } + + while (1) { + DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n", + inst->seqNum, inst->readPC()); +// verifyInst = completed_inst; + unverifiedResult.integer = inst->readIntResult(); + unverifiedReq = inst->req; + numCycles++; + + Fault fault = NoFault; + + // maintain $r0 semantics + cpuXC->setIntReg(ZeroReg, 0); +#ifdef TARGET_ALPHA + cpuXC->setFloatRegDouble(ZeroReg, 0.0); +#endif // TARGET_ALPHA + + // Try to fetch an instruction + + // set up memory request for instruction fetch +#if FULL_SYSTEM +#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 +#else +#define IFETCH_FLAGS(pc) 0 +#endif + + if (changedPC) { + DPRINTF(Checker, "Changed PC recently to %#x\n", + cpuXC->readPC()); + if (willChangePC) { + if (newPC == cpuXC->readPC()) { + DPRINTF(Checker, "Changed PC matches expected PC\n"); + } else { + warn("Changed PC does not match expected PC, changed: %#x, " + "expected: %#x", + cpuXC->readPC(), newPC); + handleError(); + } + willChangePC = false; + } + changedPC = false; + } + if (changedNextPC) { + DPRINTF(Checker, "Changed NextPC recently to %#x\n", + cpuXC->readNextPC()); + changedNextPC = false; + } + + memReq->cmd = Read; + memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), + IFETCH_FLAGS(cpuXC->readPC())); + + bool succeeded = translateInstReq(memReq); + + if (!succeeded) { + warn("Instruction PC %#x was not found in the ITB!", + cpuXC->readPC()); + handleError(); + + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); + cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); + + return; + } + +// if (fault == NoFault) +// fault = cpuXC->mem->read(memReq, machInst); + cpuXC->mem->read(memReq, machInst); + + // If we've got a valid instruction (i.e., no fault on instruction + // fetch), then execute it. + + // keep an instruction count + numInst++; +// numInsts++; + + // decode the instruction + machInst = gtoh(machInst); + // Checks that the instruction matches what we expected it to be. + // Checks both the machine instruction and the PC. + validateInst(inst); + + curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); + +#if FULL_SYSTEM + cpuXC->setInst(machInst); +#endif // FULL_SYSTEM + + fault = inst->getFault(); + + // Either the instruction was a fault and we should process the fault, + // or we should just go ahead execute the instruction. This assumes + // that the instruction is properly marked as a fault. + if (fault == NoFault) { + + cpuXC->func_exe_inst++; + + fault = curStaticInst->execute(this, NULL); + + // Checks to make sure instrution results are correct. + validateExecution(inst); + +// if (curStaticInst->isMemRef()) { +// numMemRefs++; +// } + + if (curStaticInst->isLoad()) { + ++numLoad; + } + } + + if (fault != NoFault) { +#if FULL_SYSTEM + fault->invoke(xcProxy); + willChangePC = true; + newPC = cpuXC->readPC(); + DPRINTF(Checker, "Fault, PC is now %#x\n", newPC); +#else // !FULL_SYSTEM + fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC()); +#endif // FULL_SYSTEM + } else { +#if THE_ISA != MIPS_ISA + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); + cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); +#else + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); + cpuXC->setNextPC(cpuXC->readNextNPC()); + cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); +#endif + + } + +#if FULL_SYSTEM + Addr oldpc; + int count = 0; + do { + oldpc = cpuXC->readPC(); + system->pcEventQueue.service(xcProxy); + count++; + } while (oldpc != cpuXC->readPC()); + if (count > 1) { + willChangePC = true; + newPC = cpuXC->readPC(); + DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC); + } +#endif + + // Checks PC, next PC. Optionally can check all registers. (Or just those + // that have been modified). + validateState(); + + if (instList.empty()) { + break; + } else if (instList.front()->isCompleted()) { + inst = instList.front(); + instList.pop_front(); + } else { + break; + } + } +} + +template +void +Checker::switchOut(Sampler *s) +{ + sampler = s; + instList.clear(); +} + +template +void +Checker::takeOverFrom(BaseCPU *oldCPU) +{ +// BaseCPU::takeOverFrom(oldCPU); + + // 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]; + } +*/ +} + +template +void +Checker::validateInst(DynInstPtr &inst) +{ + if (inst->readPC() != cpuXC->readPC()) { + warn("PCs do not match! Inst: %#x, checker: %#x", + inst->readPC(), cpuXC->readPC()); + if (changedPC) { + warn("Changed PCs recently, may not be an error"); + } else { + handleError(); + } + } + + if (static_cast(inst->staticInst->machInst) != + machInst) { + warn("Binary instructions do not match! Inst: %#x, checker: %#x", + static_cast(inst->staticInst->machInst), + machInst); + handleError(); + } +} + +template +void +Checker::validateExecution(DynInstPtr &inst) +{ + if (inst->numDestRegs()) { + if (inst->isUnverifiable()) { + // @todo: Support more destination registers. + // Grab the result from the instruction and write it to the + // register. + RegIndex idx = inst->destRegIdx(0); + if (idx < TheISA::FP_Base_DepTag) { + cpuXC->setIntReg(idx, inst->readIntResult()); + } else if (idx < TheISA::Fpcr_DepTag) { + cpuXC->setFloatRegInt(idx, inst->readIntResult()); + } else { + cpuXC->setMiscReg(idx, inst->readIntResult()); + } + } else if (result.integer != inst->readIntResult()) { + warn("Instruction results do not match! (May not be integer results) " + "Inst: %#x, checker: %#x", + inst->readIntResult(), result.integer); + handleError(); + } + } + + if (inst->readNextPC() != cpuXC->readNextPC()) { + warn("Instruction next PCs do not match! Inst: %#x, checker: %#x", + inst->readNextPC(), cpuXC->readNextPC()); + handleError(); + } + + // Checking side effect registers can be difficult if they are not + // checked simultaneously with the execution of the instruction. + // This is because other valid instructions may have modified + // these registers in the meantime, and their values are not + // stored within the DynInst. + while (!miscRegIdxs.empty()) { + int misc_reg_idx = miscRegIdxs.front(); + miscRegIdxs.pop(); + + if (inst->xcBase()->readMiscReg(misc_reg_idx) != + cpuXC->readMiscReg(misc_reg_idx)) { + warn("Misc reg idx %i (side effect) does not match! Inst: %#x, " + "checker: %#x", + misc_reg_idx, inst->xcBase()->readMiscReg(misc_reg_idx), + cpuXC->readMiscReg(misc_reg_idx)); + handleError(); + } + } +} + +template +void +Checker::validateState() +{ +} + +template +void +Checker::dumpInsts() +{ + int num = 0; + + InstListIt inst_list_it = --(instList.end()); + + cprintf("Inst list size: %i\n", instList.size()); + + while (inst_list_it != instList.end()) + { + cprintf("Instruction:%i\n", + num); + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Completed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isCompleted()); + + cprintf("\n"); + + inst_list_it--; + ++num; + } + +} + +template +class Checker > >; + +template +class Checker > >; -- cgit v1.2.3 From 36581a534240c322e1fc28b8bd6e8f13f2b0fefd Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Wed, 17 May 2006 14:25:10 -0400 Subject: Faults generated at fetch are passed to the backend by creating a dummy nop instruction and giving it the fault. This unifies front end faults and normal instruction faults. cpu/checker/cpu.cc: Fixups for fetch fault being sent with the instruction. cpu/o3/fetch_impl.hh: cpu/ozone/front_end_impl.hh: Send any faults generated at fetch along with a fake nop instruction to the back end. This avoids having to use direct communication to check if the entire front end has drained; it is naturally handled through the nop's fault being handled when it reaches the head of commit. cpu/ozone/front_end.hh: Add extra status TrapPending. cpu/ozone/lw_back_end_impl.hh: Fetch fault handled through a dummy nop carrying the fetch fault. Avoid putting Nops on the exeList. --HG-- extra : convert_revision : 8d9899748b34c204763a49c48a9b5113864f5789 --- cpu/checker/cpu.cc | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'cpu/checker/cpu.cc') diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc index f1b43f601..f76f1e063 100644 --- a/cpu/checker/cpu.cc +++ b/cpu/checker/cpu.cc @@ -607,41 +607,46 @@ Checker::tick(DynInstPtr &completed_inst) bool succeeded = translateInstReq(memReq); if (!succeeded) { - warn("Instruction PC %#x was not found in the ITB!", - cpuXC->readPC()); - handleError(); + if (inst->getFault() == NoFault) { + warn("Instruction PC %#x was not found in the ITB!", + cpuXC->readPC()); + handleError(); - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); + cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); - return; + return; + } else { + fault = inst->getFault(); + } } -// if (fault == NoFault) + if (fault == NoFault) { // fault = cpuXC->mem->read(memReq, machInst); - cpuXC->mem->read(memReq, machInst); + cpuXC->mem->read(memReq, machInst); - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. + // If we've got a valid instruction (i.e., no fault on instruction + // fetch), then execute it. // keep an instruction count - numInst++; + numInst++; // numInsts++; - // decode the instruction - machInst = gtoh(machInst); - // Checks that the instruction matches what we expected it to be. - // Checks both the machine instruction and the PC. - validateInst(inst); + // decode the instruction + machInst = gtoh(machInst); + // Checks that the instruction matches what we expected it to be. + // Checks both the machine instruction and the PC. + validateInst(inst); - curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); + curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); #if FULL_SYSTEM - cpuXC->setInst(machInst); + cpuXC->setInst(machInst); #endif // FULL_SYSTEM - fault = inst->getFault(); + fault = inst->getFault(); + } // Either the instruction was a fault and we should process the fault, // or we should just go ahead execute the instruction. This assumes -- cgit v1.2.3 From c9ad4a15d6b1460ea2b9c1515739f56f81ea9b57 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Tue, 23 May 2006 16:59:13 -0400 Subject: Cleanup checker. cpu/checker/cpu.cc: Cleanup checker, give more useful warning messages. Also fix bug cpu/checker/cpu.hh: Cleanup checker, use forward declaration instead of include. --HG-- extra : convert_revision : 8f231199a0a75788218320cdbcc7f70441e5d574 --- cpu/checker/cpu.cc | 321 ++++++++++++++++++----------------------------------- 1 file changed, 108 insertions(+), 213 deletions(-) (limited to 'cpu/checker/cpu.cc') diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc index f76f1e063..08ab5d5c8 100644 --- a/cpu/checker/cpu.cc +++ b/cpu/checker/cpu.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,41 +26,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -//#include -#include -//#include -#include -#include #include -//#include #include -//#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/refcnt.hh" -//#include "base/stats/events.hh" #include "cpu/base.hh" #include "cpu/base_dyn_inst.hh" #include "cpu/checker/cpu.hh" #include "cpu/cpu_exec_context.hh" #include "cpu/exec_context.hh" -//#include "cpu/exetrace.hh" -//#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -//#include "cpu/smt.hh" #include "cpu/static_inst.hh" -//#include "kern/kernel_stats.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" #include "sim/byteswap.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" @@ -72,15 +48,8 @@ #include "cpu/ozone/simple_impl.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 "arch/tlb.hh" -#include "arch/stacktrace.hh" #include "arch/vtophys.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" #endif // FULL_SYSTEM using namespace std; @@ -90,17 +59,6 @@ using namespace AlphaISA; void CheckerCPU::init() { -/* - BaseCPU::init(); -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif -*/ } CheckerCPU::CheckerCPU(Params *p) @@ -151,6 +109,8 @@ CheckerCPU::setMemory(FunctionalMemory *mem) xcProxy = cpuXC->getProxy(); execContexts.push_back(xcProxy); memReq->xc = xcProxy; + delete cpuXC->kernelStats; + cpuXC->kernelStats = NULL; } #endif } @@ -168,6 +128,8 @@ CheckerCPU::setSystem(System *system) xcProxy = cpuXC->getProxy(); execContexts.push_back(xcProxy); memReq->xc = xcProxy; + delete cpuXC->kernelStats; + cpuXC->kernelStats = NULL; } } #endif @@ -197,82 +159,15 @@ CheckerCPU::unserialize(Checkpoint *cp, const string §ion) Fault CheckerCPU::copySrcTranslate(Addr src) { - static bool no_warn = true; - int blk_size = 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 = cpuXC->translateDataReadReq(memReq); - - if (fault == NoFault) { - cpuXC->copySrcAddr = src; - cpuXC->copySrcPhysAddr = memReq->paddr + offset; - } else { - assert(!fault->isAlignmentFault()); - - cpuXC->copySrcAddr = 0; - cpuXC->copySrcPhysAddr = 0; - } - return fault; + panic("Unimplemented!"); } Fault CheckerCPU::copy(Addr dest) { - static bool no_warn = true; - int blk_size = 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(cpuXC->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 = cpuXC->translateDataWriteReq(memReq); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = cpuXC->copySrcPhysAddr; - cpuXC->mem->read(memReq, data); - memReq->paddr = dest_addr; - cpuXC->mem->write(memReq, data); - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = cpuXC->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - } - else - assert(!fault->isAlignmentFault()); - - return fault; + panic("Unimplemented!"); } -// precise architected memory state accessor macros template Fault CheckerCPU::read(Addr addr, T &data, unsigned flags) @@ -280,17 +175,15 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags) memReq->reset(addr, sizeof(T), flags); // translate to physical address - // Should I probe the DTB? Or should I just take the physical address - // and assume correct translation? translateDataReadReq(memReq); - // if we have a cache, do cache access too memReq->cmd = Read; memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; if (!(memReq->flags & UNCACHEABLE)) { + // Access memory to see if we have the same data cpuXC->read(memReq, data); } else { // Assume the data is correct if it's an uncached access @@ -350,29 +243,34 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) // translate to physical address cpuXC->translateDataWriteReq(memReq); - if ((!(unverifiedReq->flags & LOCKED) || - ((unverifiedReq->flags & LOCKED) && - unverifiedReq->result == 1)) && - !(unverifiedReq->flags & UNCACHEABLE)) { - // do functional access -// cpuXC->read(memReq, data); - - memReq->cmd = Write; -// memcpy(memReq->data,(uint8_t *)&data,memReq->size); - T inst_data; - memcpy(&inst_data, unverifiedReq->data, sizeof(T)); + // Can compare the write data and result only if it's cacheable, + // not a store conditional, or is a store conditional that + // succeeded. + // @todo: Verify that actual memory matches up with these values. + // Right now it only verifies that the instruction data is the + // same as what was in the request that got sent to memory; there + // is no verification that it is the same as what is in memory. + // This is because the LSQ would have to be snooped in the CPU to + // verify this data. + if (unverifiedReq && + !(unverifiedReq->flags & UNCACHEABLE) && + (!(unverifiedReq->flags & LOCKED) || + ((unverifiedReq->flags & LOCKED) && + unverifiedReq->result == 1))) { +#if 0 + memReq->cmd = Read; memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; + cpuXC->read(memReq, inst_data); +#endif + T inst_data; + memcpy(&inst_data, unverifiedReq->data, sizeof(T)); - // Hard to verify this as the data writes back after the - // instruction commits. May only be able to check that the - // value produced from execute() matches the value produced - // from the instruction's first execution. if (data != inst_data) { - warn("Store value does not match value in memory! " + warn("%lli: Store value does not match value in memory! " "Instruction: %#x, memory: %#x", - inst_data, data); + curTick, inst_data, data); handleError(); } } @@ -436,19 +334,6 @@ CheckerCPU::dbg_vtophys(Addr addr) } #endif // FULL_SYSTEM -#if FULL_SYSTEM -void -CheckerCPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (cpuXC->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - cpuXC->activate(); - } -} -#endif // FULL_SYSTEM - bool CheckerCPU::translateInstReq(MemReqPtr &req) { @@ -466,15 +351,16 @@ CheckerCPU::translateDataReadReq(MemReqPtr &req) cpuXC->translateDataReadReq(req); if (req->vaddr != unverifiedReq->vaddr) { - warn("Request virtual addresses do not match! Inst: %#x, checker:" - " %#x", - unverifiedReq->vaddr, req->vaddr); + warn("%lli: Request virtual addresses do not match! Inst: %#x, " + "checker: %#x", + curTick, unverifiedReq->vaddr, req->vaddr); + handleError(); } req->paddr = unverifiedReq->paddr; if (checkFlags(req)) { - warn("Request flags do not match! Inst: %#x, checker: %#x", - unverifiedReq->flags, req->flags); + warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", + curTick, unverifiedReq->flags, req->flags); handleError(); } } @@ -485,15 +371,16 @@ CheckerCPU::translateDataWriteReq(MemReqPtr &req) cpuXC->translateDataWriteReq(req); if (req->vaddr != unverifiedReq->vaddr) { - warn("Request virtual addresses do not match! Inst: %#x, checker:" - " %#x", - unverifiedReq->vaddr, req->vaddr); + warn("%lli: Request virtual addresses do not match! Inst: %#x, " + "checker: %#x", + curTick, unverifiedReq->vaddr, req->vaddr); + handleError(); } req->paddr = unverifiedReq->paddr; if (checkFlags(req)) { - warn("Request flags do not match! Inst: %#x, checker: %#x", - unverifiedReq->flags, req->flags); + warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", + curTick, unverifiedReq->flags, req->flags); handleError(); } } @@ -512,13 +399,17 @@ CheckerCPU::checkFlags(MemReqPtr &req) } } -/* start simulation, program loaded, processor precise state initialized */ template void Checker::tick(DynInstPtr &completed_inst) { DynInstPtr inst; + // Either check this instruction, or add it to a list of + // instructions waiting to be checked. Instructions must be + // checked in program order, so if a store has committed yet not + // completed, there may be some instructions that are waiting + // behind it that have completed and must be checked. if (!instList.empty()) { if (youngestSN < completed_inst->seqNum) { DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", @@ -547,16 +438,17 @@ Checker::tick(DynInstPtr &completed_inst) inst = completed_inst; youngestSN = completed_inst->seqNum; } else { -// panic("SN already seen yet the list is empty!"); return; } } } + // Try to check all instructions that are completed, ending if we + // run out of instructions to check or if an instruction is not + // yet completed. while (1) { DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n", inst->seqNum, inst->readPC()); -// verifyInst = completed_inst; unverifiedResult.integer = inst->readIntResult(); unverifiedReq = inst->req; numCycles++; @@ -569,15 +461,9 @@ Checker::tick(DynInstPtr &completed_inst) cpuXC->setFloatRegDouble(ZeroReg, 0.0); #endif // TARGET_ALPHA - // Try to fetch an instruction - - // set up memory request for instruction fetch -#if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 -#else -#define IFETCH_FLAGS(pc) 0 -#endif - + // Check if any recent PC changes match up with anything we + // expect to happen. This is mostly to check if traps or + // PC-based events have occurred in both the checker and CPU. if (changedPC) { DPRINTF(Checker, "Changed PC recently to %#x\n", cpuXC->readPC()); @@ -585,9 +471,9 @@ Checker::tick(DynInstPtr &completed_inst) if (newPC == cpuXC->readPC()) { DPRINTF(Checker, "Changed PC matches expected PC\n"); } else { - warn("Changed PC does not match expected PC, changed: %#x, " - "expected: %#x", - cpuXC->readPC(), newPC); + warn("%lli: Changed PC does not match expected PC, " + "changed: %#x, expected: %#x", + curTick, cpuXC->readPC(), newPC); handleError(); } willChangePC = false; @@ -600,6 +486,15 @@ Checker::tick(DynInstPtr &completed_inst) changedNextPC = false; } + // Try to fetch the instruction + +#if FULL_SYSTEM +#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 +#else +#define IFETCH_FLAGS(pc) 0 +#endif + + // set up memory request for instruction fetch memReq->cmd = Read; memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), IFETCH_FLAGS(cpuXC->readPC())); @@ -608,8 +503,13 @@ Checker::tick(DynInstPtr &completed_inst) if (!succeeded) { if (inst->getFault() == NoFault) { - warn("Instruction PC %#x was not found in the ITB!", - cpuXC->readPC()); + // In this case the instruction was not a dummy + // instruction carrying an ITB fault. In the single + // threaded case the ITB should still be able to + // translate this instruction; in the SMT case it's + // possible that its ITB entry was kicked out. + warn("%lli: Instruction PC %#x was not found in the ITB!", + curTick, cpuXC->readPC()); handleError(); // go to the next instruction @@ -618,20 +518,18 @@ Checker::tick(DynInstPtr &completed_inst) return; } else { + // The instruction is carrying an ITB fault. Handle + // the fault and see if our results match the CPU on + // the next tick(). fault = inst->getFault(); } } if (fault == NoFault) { -// fault = cpuXC->mem->read(memReq, machInst); cpuXC->mem->read(memReq, machInst); - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. - - // keep an instruction count + // keep an instruction count numInst++; -// numInsts++; // decode the instruction machInst = gtoh(machInst); @@ -639,7 +537,8 @@ Checker::tick(DynInstPtr &completed_inst) // Checks both the machine instruction and the PC. validateInst(inst); - curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); + curStaticInst = StaticInst::decode(makeExtMI(machInst, + cpuXC->readPC())); #if FULL_SYSTEM cpuXC->setInst(machInst); @@ -660,10 +559,6 @@ Checker::tick(DynInstPtr &completed_inst) // Checks to make sure instrution results are correct. validateExecution(inst); -// if (curStaticInst->isMemRef()) { -// numMemRefs++; -// } - if (curStaticInst->isLoad()) { ++numLoad; } @@ -693,6 +588,9 @@ Checker::tick(DynInstPtr &completed_inst) } #if FULL_SYSTEM + // @todo: Determine if these should happen only if the + // instruction hasn't faulted. In the SimpleCPU case this may + // not be true, but in the O3 or Ozone case this may be true. Addr oldpc; int count = 0; do { @@ -707,10 +605,12 @@ Checker::tick(DynInstPtr &completed_inst) } #endif - // Checks PC, next PC. Optionally can check all registers. (Or just those + // @todo: Optionally can check all registers. (Or just those // that have been modified). validateState(); + // Continue verifying instructions if there's another completed + // instruction waiting to be verified. if (instList.empty()) { break; } else if (instList.front()->isCompleted()) { @@ -726,7 +626,6 @@ template void Checker::switchOut(Sampler *s) { - sampler = s; instList.clear(); } @@ -734,15 +633,6 @@ template void Checker::takeOverFrom(BaseCPU *oldCPU) { -// BaseCPU::takeOverFrom(oldCPU); - - // 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]; - } -*/ } template @@ -750,20 +640,22 @@ void Checker::validateInst(DynInstPtr &inst) { if (inst->readPC() != cpuXC->readPC()) { - warn("PCs do not match! Inst: %#x, checker: %#x", - inst->readPC(), cpuXC->readPC()); + warn("%lli: PCs do not match! Inst: %#x, checker: %#x", + curTick, inst->readPC(), cpuXC->readPC()); if (changedPC) { - warn("Changed PCs recently, may not be an error"); + warn("%lli: Changed PCs recently, may not be an error", + curTick); } else { handleError(); } } - if (static_cast(inst->staticInst->machInst) != - machInst) { - warn("Binary instructions do not match! Inst: %#x, checker: %#x", - static_cast(inst->staticInst->machInst), - machInst); + MachInst mi = static_cast(inst->staticInst->machInst); + + if (mi != machInst) { + warn("%lli: Binary instructions do not match! Inst: %#x, " + "checker: %#x", + curTick, mi, machInst); handleError(); } } @@ -773,10 +665,11 @@ void Checker::validateExecution(DynInstPtr &inst) { if (inst->numDestRegs()) { + // @todo: Support more destination registers. if (inst->isUnverifiable()) { - // @todo: Support more destination registers. - // Grab the result from the instruction and write it to the - // register. + // Unverifiable instructions assume they were executed + // properly by the CPU. Grab the result from the + // instruction and write it to the register. RegIndex idx = inst->destRegIdx(0); if (idx < TheISA::FP_Base_DepTag) { cpuXC->setIntReg(idx, inst->readIntResult()); @@ -786,16 +679,17 @@ Checker::validateExecution(DynInstPtr &inst) cpuXC->setMiscReg(idx, inst->readIntResult()); } } else if (result.integer != inst->readIntResult()) { - warn("Instruction results do not match! (May not be integer results) " - "Inst: %#x, checker: %#x", - inst->readIntResult(), result.integer); + warn("%lli: Instruction results do not match! (Results may not " + "actually be integers) Inst: %#x, checker: %#x", + curTick, inst->readIntResult(), result.integer); handleError(); } } if (inst->readNextPC() != cpuXC->readNextPC()) { - warn("Instruction next PCs do not match! Inst: %#x, checker: %#x", - inst->readNextPC(), cpuXC->readNextPC()); + warn("%lli: Instruction next PCs do not match! Inst: %#x, " + "checker: %#x", + curTick, inst->readNextPC(), cpuXC->readNextPC()); handleError(); } @@ -810,9 +704,10 @@ Checker::validateExecution(DynInstPtr &inst) if (inst->xcBase()->readMiscReg(misc_reg_idx) != cpuXC->readMiscReg(misc_reg_idx)) { - warn("Misc reg idx %i (side effect) does not match! Inst: %#x, " - "checker: %#x", - misc_reg_idx, inst->xcBase()->readMiscReg(misc_reg_idx), + warn("%lli: Misc reg idx %i (side effect) does not match! " + "Inst: %#x, checker: %#x", + curTick, misc_reg_idx, + inst->xcBase()->readMiscReg(misc_reg_idx), cpuXC->readMiscReg(misc_reg_idx)); handleError(); } -- cgit v1.2.3 From 32509d83878816cd870cea1ccbb8a9eb46a1e3f6 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Thu, 25 May 2006 11:50:42 -0400 Subject: Fix up kernel stats, allow them to not be used as well. arch/alpha/ev5.cc: Fix up some stuff I missed in the last kernel stats checkin. cpu/checker/cpu.cc: Allow the checker to disable its kernel stats. cpu/cpu_exec_context.cc: Allow CPUExecContext to be created without kernelStats. cpu/cpu_exec_context.hh: Allow CPUExecContext to be created without kernelStats. Default usage leaves kernelStats on. --HG-- extra : convert_revision : 8ed5bffd3a5b6275baa07fb4ea385eeab1a0456a --- cpu/checker/cpu.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cpu/checker/cpu.cc') diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc index 08ab5d5c8..41ff6e769 100644 --- a/cpu/checker/cpu.cc +++ b/cpu/checker/cpu.cc @@ -103,7 +103,7 @@ CheckerCPU::setMemory(FunctionalMemory *mem) execContexts.push_back(xcProxy); #else if (systemPtr) { - cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr); + cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false); cpuXC->setStatus(ExecContext::Suspended); xcProxy = cpuXC->getProxy(); @@ -122,7 +122,7 @@ CheckerCPU::setSystem(System *system) systemPtr = system; if (memPtr) { - cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr); + cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false); cpuXC->setStatus(ExecContext::Suspended); xcProxy = cpuXC->getProxy(); -- cgit v1.2.3