summaryrefslogtreecommitdiff
path: root/cpu/checker/cpu.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/checker/cpu.cc')
-rw-r--r--cpu/checker/cpu.cc857
1 files changed, 857 insertions, 0 deletions
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 <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/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 &section)
+{
+/*
+ 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 <class T>
+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 <class T>
+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 <class DynInstPtr>
+void
+Checker<DynInstPtr>::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 <class DynInstPtr>
+void
+Checker<DynInstPtr>::switchOut(Sampler *s)
+{
+ sampler = s;
+ instList.clear();
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::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 <class DynInstPtr>
+void
+Checker<DynInstPtr>::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<MachInst>(inst->staticInst->machInst) !=
+ machInst) {
+ warn("Binary instructions do not match! Inst: %#x, checker: %#x",
+ static_cast<MachInst>(inst->staticInst->machInst),
+ machInst);
+ handleError();
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::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 <class DynInstPtr>
+void
+Checker<DynInstPtr>::validateState()
+{
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::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<RefCountingPtr<OzoneDynInst<OzoneImpl> > >;
+
+template
+class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;