Add in checker. Supports dynamically verifying the execution of instructions, as...
authorKevin Lim <ktlim@umich.edu>
Tue, 16 May 2006 17:59:29 +0000 (13:59 -0400)
committerKevin Lim <ktlim@umich.edu>
Tue, 16 May 2006 17:59:29 +0000 (13:59 -0400)
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

base/traceflags.py
build/SConstruct
cpu/SConscript
cpu/base.cc
cpu/base.hh
cpu/checker/cpu.cc [new file with mode: 0644]
cpu/checker/cpu.hh [new file with mode: 0644]
cpu/checker/cpu_builder.cc [new file with mode: 0644]
cpu/checker/exec_context.hh [new file with mode: 0644]
cpu/checker/o3_cpu_builder.cc [new file with mode: 0644]
cpu/cpu_models.py

index bd0f258a02f2ec5559f1c8de7bf3348e1550c4ac..47ed59c3ad9775d814ff4171edb44126a6d840fa 100644 (file)
@@ -150,7 +150,8 @@ baseFlags = [
     'DependGraph',
     'Activity',
     'Scoreboard',
-    'Writeback'
+    'Writeback',
+    'Checker'
     ]
 
 #
index c40f59bc23c947f59b3db2295ec9c3425517ccc1..110a0f2501ef5e5e467738523723720ce5e6b26f 100644 (file)
@@ -223,7 +223,7 @@ env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips']
 
 # Define the universe of supported CPU models
 env['ALL_CPU_LIST'] = ['SimpleCPU', 'FastCPU', 'FullCPU', 'AlphaFullCPU',
-                       'OzoneSimpleCPU', 'OzoneCPU']
+                       'OzoneSimpleCPU', 'OzoneCPU', 'CheckerCPU']
 
 
 # Sticky options get saved in the options file so they persist from
index c34971acfcc16f9a0502172fb398ae74b6e0bc6f..5d727bd25c54ccd5842d28d690fcab47b81e41f7 100644 (file)
@@ -150,6 +150,13 @@ if 'OzoneCPU' in env['CPU_MODELS']:
         ozone/lw_lsq.cc
         ''')
 
+if 'CheckerCPU' in env['CPU_MODELS']:
+    sources += Split('''
+        checker/cpu.cc
+        checker/cpu_builder.cc
+        checker/o3_cpu_builder.cc
+        ''')
+
 # FullCPU sources are included from m5/SConscript since they're not
 # below this point in the file hierarchy.
 
index 2eb5f7fd310b2ab9ab0470c311564a0da4fd9c4f..74b679d5d542c016a6883675732c13df7be09efa 100644 (file)
@@ -164,6 +164,7 @@ BaseCPU::Params::Params()
 #if FULL_SYSTEM
     profile = false;
 #endif
+    checker = NULL;
 }
 
 void
@@ -229,15 +230,18 @@ BaseCPU::registerExecContexts()
 {
     for (int i = 0; i < execContexts.size(); ++i) {
         ExecContext *xc = execContexts[i];
+
+        if (xc->status() == ExecContext::Suspended) {
 #if FULL_SYSTEM
-        int id = params->cpu_id;
-        if (id != -1)
-            id += i;
+            int id = params->cpu_id;
+            if (id != -1)
+                id += i;
 
         xc->setCpuId(system->registerExecContext(xc, id));
 #else
         xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc));
 #endif
+        }
     }
 }
 
index d9d5d2b8853a6b19da31355ed1bd928076376e67..20166d7eece06cac84337ec17e846c92c1df9708 100644 (file)
@@ -44,6 +44,7 @@ namespace Kernel { class Statistics; }
 #endif
 
 class BranchPred;
+class CheckerCPU;
 class ExecContext;
 
 class BaseCPU : public SimObject
@@ -128,6 +129,7 @@ class BaseCPU : public SimObject
         int cpu_id;
         Tick profile;
 #endif
+        BaseCPU *checker;
 
         Params();
     };
diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc
new file mode 100644 (file)
index 0000000..f1b43f6
--- /dev/null
@@ -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> > >;
diff --git a/cpu/checker/cpu.hh b/cpu/checker/cpu.hh
new file mode 100644 (file)
index 0000000..678e888
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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.
+ */
+
+#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/sampler/sampler.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 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:
+    void post_interrupt(int int_num, int index);
+
+    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);
+
+    bool interval_stats;
+#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;
+
+    // Pointer to the sampler that is telling us to switchover.
+    // Used to signal the completion of the pipe drain and schedule
+    // the next switchover
+    Sampler *sampler;
+
+    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.
+    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;
+//    std::map<Addr, uint64_t> storeBuff;
+//    typedef std::map<Addr, uint64_t>::iterator map_it;
+};
+
+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 (file)
index 0000000..397ccab
--- /dev/null
@@ -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 (file)
index 0000000..4843d1c
--- /dev/null
@@ -0,0 +1,225 @@
+#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;
+
+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(); }
+#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);
+    }
+
+//    void syscall() { actualXC->syscall(); }
+
+    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 (file)
index 0000000..125bfa3
--- /dev/null
@@ -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)
index 8912673f72b5eb8b89570a820ad2149facf3e566..2b1ae627737244122260a0c683a33bdd2e0fd0cf 100644 (file)
@@ -74,4 +74,7 @@ CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc',
 CpuModel('OzoneCPU', 'ozone_exec.cc',
          '#include "cpu/ozone/dyn_inst.hh"',
          { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' })
+CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
+         '#include "cpu/checker/cpu.hh"',
+         { 'CPU_exec_context': 'CheckerCPU' })