summaryrefslogtreecommitdiff
path: root/cpu/checker
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/checker')
-rw-r--r--cpu/checker/cpu.cc757
-rw-r--r--cpu/checker/cpu.hh326
-rw-r--r--cpu/checker/cpu_builder.cc126
-rw-r--r--cpu/checker/exec_context.hh259
-rw-r--r--cpu/checker/o3_cpu_builder.cc126
5 files changed, 1594 insertions, 0 deletions
diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc
new file mode 100644
index 000000000..41ff6e769
--- /dev/null
+++ b/cpu/checker/cpu.cc
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 2006 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 <list>
+#include <string>
+
+#include "base/refcnt.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/static_inst.hh"
+#include "sim/byteswap.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 "sim/system.hh"
+#include "arch/vtophys.hh"
+#endif // FULL_SYSTEM
+
+using namespace std;
+//The CheckerCPU does alpha only
+using namespace AlphaISA;
+
+void
+CheckerCPU::init()
+{
+}
+
+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, false);
+
+ cpuXC->setStatus(ExecContext::Suspended);
+ xcProxy = cpuXC->getProxy();
+ execContexts.push_back(xcProxy);
+ memReq->xc = xcProxy;
+ delete cpuXC->kernelStats;
+ cpuXC->kernelStats = NULL;
+ }
+#endif
+}
+
+#if FULL_SYSTEM
+void
+CheckerCPU::setSystem(System *system)
+{
+ systemPtr = system;
+
+ if (memPtr) {
+ cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false);
+
+ cpuXC->setStatus(ExecContext::Suspended);
+ xcProxy = cpuXC->getProxy();
+ execContexts.push_back(xcProxy);
+ memReq->xc = xcProxy;
+ delete cpuXC->kernelStats;
+ cpuXC->kernelStats = NULL;
+ }
+}
+#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)
+{
+ panic("Unimplemented!");
+}
+
+Fault
+CheckerCPU::copy(Addr dest)
+{
+ panic("Unimplemented!");
+}
+
+template <class T>
+Fault
+CheckerCPU::read(Addr addr, T &data, unsigned flags)
+{
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ translateDataReadReq(memReq);
+
+ 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
+ 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);
+
+ // 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));
+
+ if (data != inst_data) {
+ warn("%lli: Store value does not match value in memory! "
+ "Instruction: %#x, memory: %#x",
+ curTick, 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
+
+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("%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("%lli: Request flags do not match! Inst: %#x, checker: %#x",
+ curTick, unverifiedReq->flags, req->flags);
+ handleError();
+ }
+}
+
+void
+CheckerCPU::translateDataWriteReq(MemReqPtr &req)
+{
+ cpuXC->translateDataWriteReq(req);
+
+ if (req->vaddr != unverifiedReq->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("%lli: Request flags do not match! Inst: %#x, checker: %#x",
+ curTick, 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;
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::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",
+ 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 {
+ 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());
+ 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
+
+ // 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());
+ if (willChangePC) {
+ if (newPC == cpuXC->readPC()) {
+ DPRINTF(Checker, "Changed PC matches expected PC\n");
+ } else {
+ warn("%lli: Changed PC does not match expected PC, "
+ "changed: %#x, expected: %#x",
+ curTick, cpuXC->readPC(), newPC);
+ handleError();
+ }
+ willChangePC = false;
+ }
+ changedPC = false;
+ }
+ if (changedNextPC) {
+ DPRINTF(Checker, "Changed NextPC recently to %#x\n",
+ cpuXC->readNextPC());
+ 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()));
+
+ bool succeeded = translateInstReq(memReq);
+
+ if (!succeeded) {
+ if (inst->getFault() == NoFault) {
+ // 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
+ cpuXC->setPC(cpuXC->readNextPC());
+ cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
+
+ 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) {
+ cpuXC->mem->read(memReq, machInst);
+
+ // keep an instruction count
+ numInst++;
+
+ // 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->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
+ // @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 {
+ 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
+
+ // @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()) {
+ inst = instList.front();
+ instList.pop_front();
+ } else {
+ break;
+ }
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::switchOut(Sampler *s)
+{
+ instList.clear();
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
+{
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
+{
+ if (inst->readPC() != cpuXC->readPC()) {
+ warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
+ curTick, inst->readPC(), cpuXC->readPC());
+ if (changedPC) {
+ warn("%lli: Changed PCs recently, may not be an error",
+ curTick);
+ } else {
+ handleError();
+ }
+ }
+
+ MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
+
+ if (mi != machInst) {
+ warn("%lli: Binary instructions do not match! Inst: %#x, "
+ "checker: %#x",
+ curTick, mi, machInst);
+ handleError();
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
+{
+ if (inst->numDestRegs()) {
+ // @todo: Support more destination registers.
+ if (inst->isUnverifiable()) {
+ // 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());
+ } else if (idx < TheISA::Fpcr_DepTag) {
+ cpuXC->setFloatRegInt(idx, inst->readIntResult());
+ } else {
+ cpuXC->setMiscReg(idx, inst->readIntResult());
+ }
+ } else if (result.integer != inst->readIntResult()) {
+ 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("%lli: Instruction next PCs do not match! Inst: %#x, "
+ "checker: %#x",
+ curTick, 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("%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();
+ }
+ }
+}
+
+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> > >;
diff --git a/cpu/checker/cpu.hh b/cpu/checker/cpu.hh
new file mode 100644
index 000000000..37fe59d95
--- /dev/null
+++ b/cpu/checker/cpu.hh
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2006 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.
+ */
+
+#ifndef __CPU_CHECKER_CPU_HH__
+#define __CPU_CHECKER_CPU_HH__
+
+#include <list>
+#include <queue>
+#include <map>
+
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/pc_event.hh"
+#include "cpu/static_inst.hh"
+#include "sim/eventq.hh"
+
+// forward declarations
+#if FULL_SYSTEM
+class Processor;
+class AlphaITB;
+class AlphaDTB;
+class PhysicalMemory;
+
+class RemoteGDB;
+class GDBListener;
+
+#else
+
+class Process;
+
+#endif // FULL_SYSTEM
+template <class>
+class BaseDynInst;
+class ExecContext;
+class MemInterface;
+class Checkpoint;
+class Sampler;
+
+class CheckerCPU : public BaseCPU
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::MiscReg MiscReg;
+ public:
+ // main simulation loop (one cycle)
+ virtual void init();
+
+ struct Params : public BaseCPU::Params
+ {
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+ FunctionalMemory *mem;
+#else
+ Process *process;
+#endif
+ bool exitOnError;
+ };
+
+ public:
+ CheckerCPU(Params *p);
+ virtual ~CheckerCPU();
+
+ void setMemory(FunctionalMemory *mem);
+
+ FunctionalMemory *memPtr;
+
+#if FULL_SYSTEM
+ void setSystem(System *system);
+
+ System *systemPtr;
+#endif
+ public:
+ // execution context
+ CPUExecContext *cpuXC;
+
+ ExecContext *xcProxy;
+
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+
+#if FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
+#endif
+
+ union Result {
+ uint64_t integer;
+ float fp;
+ double dbl;
+ };
+
+ Result result;
+
+ // current instruction
+ MachInst machInst;
+
+ // Refcounted pointer to the one memory request.
+ MemReqPtr memReq;
+
+ StaticInstPtr curStaticInst;
+
+ // number of simulated instructions
+ Counter numInst;
+ Counter startNumInst;
+
+ std::queue<int> miscRegIdxs;
+
+ virtual Counter totalInstructions() const
+ {
+ return numInst - startNumInst;
+ }
+
+ // number of simulated loads
+ Counter numLoad;
+ Counter startNumLoad;
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+
+ // These functions are only used in CPU models that split
+ // effective address computation from the actual memory access.
+ void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
+ Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
+
+ void prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ void writeHint(Addr addr, int size, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ Fault copySrcTranslate(Addr src);
+
+ Fault copy(Addr dest);
+
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ uint64_t readIntReg(const StaticInst *si, int idx)
+ {
+ return cpuXC->readIntReg(si->srcRegIdx(idx));
+ }
+
+ float readFloatRegSingle(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatRegSingle(reg_idx);
+ }
+
+ double readFloatRegDouble(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatRegDouble(reg_idx);
+ }
+
+ uint64_t readFloatRegInt(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatRegInt(reg_idx);
+ }
+
+ void setIntReg(const StaticInst *si, int idx, uint64_t val)
+ {
+ cpuXC->setIntReg(si->destRegIdx(idx), val);
+ result.integer = val;
+ }
+
+ void setFloatRegSingle(const StaticInst *si, int idx, float val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatRegSingle(reg_idx, val);
+ result.fp = val;
+ }
+
+ void setFloatRegDouble(const StaticInst *si, int idx, double val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatRegDouble(reg_idx, val);
+ result.dbl = val;
+ }
+
+ void setFloatRegInt(const StaticInst *si, int idx, uint64_t val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatRegInt(reg_idx, val);
+ result.integer = val;
+ }
+
+ uint64_t readPC() { return cpuXC->readPC(); }
+ void setNextPC(uint64_t val) {
+ cpuXC->setNextPC(val);
+ }
+
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return cpuXC->readMiscReg(misc_reg);
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ return cpuXC->readMiscRegWithEffect(misc_reg, fault);
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ result.integer = val;
+ miscRegIdxs.push(misc_reg);
+ return cpuXC->setMiscReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ miscRegIdxs.push(misc_reg);
+ return cpuXC->setMiscRegWithEffect(misc_reg, val);
+ }
+
+ void recordPCChange(uint64_t val) { changedPC = true; }
+ void recordNextPCChange(uint64_t val) { changedNextPC = true; }
+
+ bool translateInstReq(MemReqPtr &req);
+ void translateDataWriteReq(MemReqPtr &req);
+ void translateDataReadReq(MemReqPtr &req);
+
+#if FULL_SYSTEM
+ Fault hwrei() { return cpuXC->hwrei(); }
+ int readIntrFlag() { return cpuXC->readIntrFlag(); }
+ void setIntrFlag(int val) { cpuXC->setIntrFlag(val); }
+ bool inPalMode() { return cpuXC->inPalMode(); }
+ void ev5_trap(Fault fault) { fault->invoke(xcProxy); }
+ bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); }
+#else
+ // Assume that the normal CPU's call to syscall was successful.
+ // The checker's state would have already been updated by the syscall.
+ void syscall() { }
+#endif
+
+ void handleError()
+ {
+ if (exitOnError)
+ panic("Checker found error!");
+ }
+ bool checkFlags(MemReqPtr &req);
+
+ ExecContext *xcBase() { return xcProxy; }
+ CPUExecContext *cpuXCBase() { return cpuXC; }
+
+ Result unverifiedResult;
+ MemReqPtr unverifiedReq;
+
+ bool changedPC;
+ bool willChangePC;
+ uint64_t newPC;
+ bool changedNextPC;
+ bool exitOnError;
+
+ InstSeqNum youngestSN;
+};
+
+template <class DynInstPtr>
+class Checker : public CheckerCPU
+{
+ public:
+ Checker(Params *p)
+ : CheckerCPU(p)
+ { }
+
+ void switchOut(Sampler *s);
+ void takeOverFrom(BaseCPU *oldCPU);
+
+ void tick(DynInstPtr &inst);
+
+ void validateInst(DynInstPtr &inst);
+ void validateExecution(DynInstPtr &inst);
+ void validateState();
+
+ std::list<DynInstPtr> instList;
+ typedef typename std::list<DynInstPtr>::iterator InstListIt;
+ void dumpInsts();
+};
+
+#endif // __CPU_CHECKER_CPU_HH__
diff --git a/cpu/checker/cpu_builder.cc b/cpu/checker/cpu_builder.cc
new file mode 100644
index 000000000..397ccab14
--- /dev/null
+++ b/cpu/checker/cpu_builder.cc
@@ -0,0 +1,126 @@
+
+#include <string>
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/dyn_inst.hh"
+#include "cpu/ozone/ozone_impl.hh"
+#include "mem/base_mem.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+class OzoneChecker : public Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >
+{
+ public:
+ OzoneChecker(Params *p)
+ : Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >(p)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// CheckerCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+ Param<Counter> max_loads_any_thread;
+ Param<Counter> max_loads_all_threads;
+
+#if FULL_SYSTEM
+ SimObjectParam<AlphaITB *> itb;
+ SimObjectParam<AlphaDTB *> dtb;
+ SimObjectParam<FunctionalMemory *> mem;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<Tick> profile;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+ Param<int> clock;
+ SimObjectParam<BaseMem *> icache;
+ SimObjectParam<BaseMem *> dcache;
+
+ Param<bool> defer_registration;
+ Param<bool> exitOnError;
+ Param<bool> function_trace;
+ Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(OzoneChecker)
+
+ INIT_PARAM(max_insts_any_thread,
+ "terminate when any thread reaches this inst count"),
+ INIT_PARAM(max_insts_all_threads,
+ "terminate when all threads have reached this inst count"),
+ INIT_PARAM(max_loads_any_thread,
+ "terminate when any thread reaches this load count"),
+ INIT_PARAM(max_loads_all_threads,
+ "terminate when all threads have reached this load count"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(mem, "memory"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(icache, "L1 instruction cache object"),
+ INIT_PARAM(dcache, "L1 data cache object"),
+
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+ INIT_PARAM(exitOnError, "exit on error"),
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(OzoneChecker)
+
+
+CREATE_SIM_OBJECT(OzoneChecker)
+{
+ OzoneChecker::Params *params = new OzoneChecker::Params();
+ params->name = getInstanceName();
+ params->numberOfThreads = 1;
+ params->max_insts_any_thread = 0;
+ params->max_insts_all_threads = 0;
+ params->max_loads_any_thread = 0;
+ params->max_loads_all_threads = 0;
+ params->exitOnError = exitOnError;
+ params->deferRegistration = defer_registration;
+ params->functionTrace = function_trace;
+ params->functionTraceStart = function_trace_start;
+ params->clock = clock;
+ // Hack to touch all parameters. Consider not deriving Checker
+ // from BaseCPU..it's not really a CPU in the end.
+ Counter temp;
+ temp = max_insts_any_thread;
+ temp = max_insts_all_threads;
+ temp = max_loads_any_thread;
+ temp = max_loads_all_threads;
+ BaseMem *cache = icache;
+ cache = dcache;
+
+#if FULL_SYSTEM
+ params->itb = itb;
+ params->dtb = dtb;
+ params->mem = mem;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->profile = profile;
+#else
+ params->process = workload;
+#endif
+
+ OzoneChecker *cpu = new OzoneChecker(params);
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("OzoneChecker", OzoneChecker)
diff --git a/cpu/checker/exec_context.hh b/cpu/checker/exec_context.hh
new file mode 100644
index 000000000..38784867d
--- /dev/null
+++ b/cpu/checker/exec_context.hh
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2006 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.
+ */
+
+#ifndef __CPU_CHECKER_EXEC_CONTEXT_HH__
+#define __CPU_CHECKER_EXEC_CONTEXT_HH__
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/exec_context.hh"
+
+class EndQuiesceEvent;
+namespace Kernel {
+ class Statistics;
+};
+
+template <class XC>
+class CheckerExecContext : public ExecContext
+{
+ public:
+ CheckerExecContext(XC *actual_xc,
+ CheckerCPU *checker_cpu)
+ : actualXC(actual_xc), checkerXC(checker_cpu->cpuXC),
+ checkerCPU(checker_cpu)
+ { }
+
+ private:
+ XC *actualXC;
+ CPUExecContext *checkerXC;
+ CheckerCPU *checkerCPU;
+
+ public:
+
+ BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); }
+
+ void setCpuId(int id)
+ {
+ actualXC->setCpuId(id);
+ checkerXC->setCpuId(id);
+ }
+
+ int readCpuId() { return actualXC->readCpuId(); }
+
+ FunctionalMemory *getMemPtr() { return actualXC->getMemPtr(); }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return actualXC->getSystemPtr(); }
+
+ PhysicalMemory *getPhysMemPtr() { return actualXC->getPhysMemPtr(); }
+
+ AlphaITB *getITBPtr() { return actualXC->getITBPtr(); }
+
+ AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); }
+
+ Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); }
+#else
+ Process *getProcessPtr() { return actualXC->getProcessPtr(); }
+#endif
+
+ Status status() const { return actualXC->status(); }
+
+ void setStatus(Status new_status)
+ {
+ actualXC->setStatus(new_status);
+ checkerXC->setStatus(new_status);
+ }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1) { actualXC->activate(delay); }
+
+ /// Set the status to Suspended.
+ void suspend() { actualXC->suspend(); }
+
+ /// Set the status to Unallocated.
+ void deallocate() { actualXC->deallocate(); }
+
+ /// Set the status to Halted.
+ void halt() { actualXC->halt(); }
+
+#if FULL_SYSTEM
+ void dumpFuncProfile() { actualXC->dumpFuncProfile(); }
+#endif
+
+ void takeOverFrom(ExecContext *oldContext)
+ {
+ actualXC->takeOverFrom(oldContext);
+ checkerXC->takeOverFrom(oldContext);
+ }
+
+ void regStats(const std::string &name) { actualXC->regStats(name); }
+
+ void serialize(std::ostream &os) { actualXC->serialize(os); }
+ void unserialize(Checkpoint *cp, const std::string &section)
+ { actualXC->unserialize(cp, section); }
+
+#if FULL_SYSTEM
+ EndQuiesceEvent *getQuiesceEvent() { return actualXC->getQuiesceEvent(); }
+
+ Tick readLastActivate() { return actualXC->readLastActivate(); }
+ Tick readLastSuspend() { return actualXC->readLastSuspend(); }
+
+ void profileClear() { return actualXC->profileClear(); }
+ void profileSample() { return actualXC->profileSample(); }
+#endif
+
+ int getThreadNum() { return actualXC->getThreadNum(); }
+
+ // @todo: Do I need this?
+ MachInst getInst() { return actualXC->getInst(); }
+
+ // @todo: Do I need this?
+ void copyArchRegs(ExecContext *xc)
+ {
+ actualXC->copyArchRegs(xc);
+ checkerXC->copyArchRegs(xc);
+ }
+
+ void clearArchRegs()
+ {
+ actualXC->clearArchRegs();
+ checkerXC->clearArchRegs();
+ }
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ { return actualXC->readIntReg(reg_idx); }
+
+ float readFloatRegSingle(int reg_idx)
+ { return actualXC->readFloatRegSingle(reg_idx); }
+
+ double readFloatRegDouble(int reg_idx)
+ { return actualXC->readFloatRegDouble(reg_idx); }
+
+ uint64_t readFloatRegInt(int reg_idx)
+ { return actualXC->readFloatRegInt(reg_idx); }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ {
+ actualXC->setIntReg(reg_idx, val);
+ checkerXC->setIntReg(reg_idx, val);
+ }
+
+ void setFloatRegSingle(int reg_idx, float val)
+ {
+ actualXC->setFloatRegSingle(reg_idx, val);
+ checkerXC->setFloatRegSingle(reg_idx, val);
+ }
+
+ void setFloatRegDouble(int reg_idx, double val)
+ {
+ actualXC->setFloatRegDouble(reg_idx, val);
+ checkerXC->setFloatRegSingle(reg_idx, val);
+ }
+
+ void setFloatRegInt(int reg_idx, uint64_t val)
+ {
+ actualXC->setFloatRegInt(reg_idx, val);
+ checkerXC->setFloatRegInt(reg_idx, val);
+ }
+
+ uint64_t readPC() { return actualXC->readPC(); }
+
+ void setPC(uint64_t val)
+ {
+ actualXC->setPC(val);
+ checkerXC->setPC(val);
+ checkerCPU->recordPCChange(val);
+ }
+
+ uint64_t readNextPC() { return actualXC->readNextPC(); }
+
+ void setNextPC(uint64_t val)
+ {
+ actualXC->setNextPC(val);
+ checkerXC->setNextPC(val);
+ checkerCPU->recordNextPCChange(val);
+ }
+
+ MiscReg readMiscReg(int misc_reg)
+ { return actualXC->readMiscReg(misc_reg); }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ { return actualXC->readMiscRegWithEffect(misc_reg, fault); }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ checkerXC->setMiscReg(misc_reg, val);
+ return actualXC->setMiscReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ checkerXC->setMiscRegWithEffect(misc_reg, val);
+ return actualXC->setMiscRegWithEffect(misc_reg, val);
+ }
+
+ unsigned readStCondFailures()
+ { return actualXC->readStCondFailures(); }
+
+ void setStCondFailures(unsigned sc_failures)
+ {
+ checkerXC->setStCondFailures(sc_failures);
+ actualXC->setStCondFailures(sc_failures);
+ }
+#if FULL_SYSTEM
+ bool inPalMode() { return actualXC->inPalMode(); }
+#endif
+
+ // @todo: Fix this!
+ bool misspeculating() { return actualXC->misspeculating(); }
+
+#if !FULL_SYSTEM
+ IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); }
+
+ // used to shift args for indirect syscall
+ void setSyscallArg(int i, IntReg val)
+ {
+ checkerXC->setSyscallArg(i, val);
+ actualXC->setSyscallArg(i, val);
+ }
+
+ void setSyscallReturn(SyscallReturn return_value)
+ {
+ checkerXC->setSyscallReturn(return_value);
+ actualXC->setSyscallReturn(return_value);
+ }
+
+ Counter readFuncExeInst() { return actualXC->readFuncExeInst(); }
+#endif
+};
+
+#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__
diff --git a/cpu/checker/o3_cpu_builder.cc b/cpu/checker/o3_cpu_builder.cc
new file mode 100644
index 000000000..125bfa398
--- /dev/null
+++ b/cpu/checker/o3_cpu_builder.cc
@@ -0,0 +1,126 @@
+
+#include <string>
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "mem/base_mem.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >
+{
+ public:
+ O3Checker(Params *p)
+ : Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// CheckerCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(O3Checker)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+ Param<Counter> max_loads_any_thread;
+ Param<Counter> max_loads_all_threads;
+
+#if FULL_SYSTEM
+ SimObjectParam<AlphaITB *> itb;
+ SimObjectParam<AlphaDTB *> dtb;
+ SimObjectParam<FunctionalMemory *> mem;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<Tick> profile;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+ Param<int> clock;
+ SimObjectParam<BaseMem *> icache;
+ SimObjectParam<BaseMem *> dcache;
+
+ Param<bool> defer_registration;
+ Param<bool> exitOnError;
+ Param<bool> function_trace;
+ Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(O3Checker)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(O3Checker)
+
+ INIT_PARAM(max_insts_any_thread,
+ "terminate when any thread reaches this inst count"),
+ INIT_PARAM(max_insts_all_threads,
+ "terminate when all threads have reached this inst count"),
+ INIT_PARAM(max_loads_any_thread,
+ "terminate when any thread reaches this load count"),
+ INIT_PARAM(max_loads_all_threads,
+ "terminate when all threads have reached this load count"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(mem, "memory"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(icache, "L1 instruction cache object"),
+ INIT_PARAM(dcache, "L1 data cache object"),
+
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+ INIT_PARAM(exitOnError, "exit on error"),
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(O3Checker)
+
+
+CREATE_SIM_OBJECT(O3Checker)
+{
+ O3Checker::Params *params = new O3Checker::Params();
+ params->name = getInstanceName();
+ params->numberOfThreads = 1;
+ params->max_insts_any_thread = 0;
+ params->max_insts_all_threads = 0;
+ params->max_loads_any_thread = 0;
+ params->max_loads_all_threads = 0;
+ params->exitOnError = exitOnError;
+ params->deferRegistration = defer_registration;
+ params->functionTrace = function_trace;
+ params->functionTraceStart = function_trace_start;
+ params->clock = clock;
+ // Hack to touch all parameters. Consider not deriving Checker
+ // from BaseCPU..it's not really a CPU in the end.
+ Counter temp;
+ temp = max_insts_any_thread;
+ temp = max_insts_all_threads;
+ temp = max_loads_any_thread;
+ temp = max_loads_all_threads;
+ BaseMem *cache = icache;
+ cache = dcache;
+
+#if FULL_SYSTEM
+ params->itb = itb;
+ params->dtb = dtb;
+ params->mem = mem;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->profile = profile;
+#else
+ params->process = workload;
+#endif
+
+ O3Checker *cpu = new O3Checker(params);
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("O3Checker", O3Checker)