CheckerCPU: Re-factor CheckerCPU to be compatible with current gem5
authorGeoffrey Blake <geoffrey.blake@arm.com>
Tue, 31 Jan 2012 15:46:03 +0000 (07:46 -0800)
committerGeoffrey Blake <geoffrey.blake@arm.com>
Tue, 31 Jan 2012 15:46:03 +0000 (07:46 -0800)
Brings the CheckerCPU back to life to allow FS and SE checking of the
O3CPU.  These changes have only been tested with the ARM ISA.  Other
ISAs potentially require modification.

38 files changed:
src/arch/arm/isa.cc
src/arch/arm/isa/insts/m5ops.isa
src/arch/arm/isa/insts/misc.isa
src/arch/arm/table_walker.cc
src/arch/arm/table_walker.hh
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh
src/arch/arm/utility.cc
src/cpu/BaseCPU.py
src/cpu/CheckerCPU.py
src/cpu/DummyChecker.py [new file with mode: 0644]
src/cpu/SConscript
src/cpu/base.cc
src/cpu/base_dyn_inst.hh
src/cpu/base_dyn_inst_impl.hh
src/cpu/checker/cpu.cc
src/cpu/checker/cpu.hh
src/cpu/checker/cpu_impl.hh
src/cpu/checker/thread_context.hh
src/cpu/dummy_checker_builder.cc [new file with mode: 0644]
src/cpu/o3/O3CPU.py
src/cpu/o3/O3Checker.py
src/cpu/o3/checker_builder.cc
src/cpu/o3/commit_impl.hh
src/cpu/o3/cpu.cc
src/cpu/o3/cpu.hh
src/cpu/o3/dyn_inst_impl.hh
src/cpu/o3/fetch_impl.hh
src/cpu/o3/iew_impl.hh
src/cpu/o3/lsq_unit_impl.hh
src/cpu/o3/thread_context.hh
src/cpu/o3/thread_context_impl.hh
src/cpu/simple/BaseSimpleCPU.py
src/cpu/simple/base.cc
src/cpu/simple/base.hh
src/cpu/simple_thread.hh
src/cpu/thread_context.hh
src/mem/bus.cc

index b504550a1d304372fa6476bfc039bb07de88dc6b..5c2478946717e7fd37cfa10f2f6985e798c3f8df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  */
 
 #include "arch/arm/isa.hh"
+#include "config/use_checker.hh"
 #include "debug/Arm.hh"
 #include "debug/MiscRegs.hh"
 #include "sim/faults.hh"
 #include "sim/stat_control.hh"
 #include "sim/system.hh"
 
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
 namespace ArmISA
 {
 
@@ -279,7 +284,11 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
         PCState pc = tc->pcState();
         pc.nextThumb(cpsr.t);
         pc.nextJazelle(cpsr.j);
+#if USE_CHECKER
+        tc->pcStateNoRecord(pc);
+#else
         tc->pcState(pc);
+#endif //USE_CHECKER
     } else if (misc_reg >= MISCREG_CP15_UNIMP_START &&
         misc_reg < MISCREG_CP15_END) {
         panic("Unimplemented CP15 register %s wrote with %#x.\n",
@@ -382,6 +391,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                     oc = sys->getThreadContext(x);
                     oc->getDTBPtr()->allCpusCaching();
                     oc->getITBPtr()->allCpusCaching();
+#if USE_CHECKER
+                    CheckerCPU *checker =
+                        dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                    if (checker) {
+                        checker->getDTBPtr()->allCpusCaching();
+                        checker->getITBPtr()->allCpusCaching();
+                    }
+#endif
                 }
                 return;
             }
@@ -399,6 +416,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                 assert(oc->getITBPtr() && oc->getDTBPtr());
                 oc->getITBPtr()->flushAll();
                 oc->getDTBPtr()->flushAll();
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushAll();
+                    checker->getDTBPtr()->flushAll();
+                }
+#endif
             }
             return;
           case MISCREG_ITLBIALL:
@@ -417,6 +442,16 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                         bits(newVal, 7,0));
                 oc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
                         bits(newVal, 7,0));
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                            bits(newVal, 7,0));
+                    checker->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+                            bits(newVal, 7,0));
+                }
+#endif
             }
             return;
           case MISCREG_TLBIASIDIS:
@@ -427,6 +462,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                 assert(oc->getITBPtr() && oc->getDTBPtr());
                 oc->getITBPtr()->flushAsid(bits(newVal, 7,0));
                 oc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushAsid(bits(newVal, 7,0));
+                    checker->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+                }
+#endif
             }
             return;
           case MISCREG_TLBIMVAAIS:
@@ -437,6 +480,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
                 assert(oc->getITBPtr() && oc->getDTBPtr());
                 oc->getITBPtr()->flushMva(mbits(newVal, 31,12));
                 oc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+#if USE_CHECKER
+                CheckerCPU *checker =
+                    dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+                if (checker) {
+                    checker->getITBPtr()->flushMva(mbits(newVal, 31,12));
+                    checker->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+                }
+#endif
             }
             return;
           case MISCREG_ITLBIMVA:
index f20908d4f835b18d11c4bff515a761f808ee071e..222ecc6474d818983101e286a0e61f9623ef8df4 100644 (file)
@@ -247,7 +247,7 @@ let {{
     m5checkpointIop = InstObjParams("m5checkpoint", "M5checkpoint", "PredOp",
                            { "code": m5checkpoint_code,
                              "predicate_test": predicateTest },
-                             ["IsNonSpeculative"])
+                             ["IsNonSpeculative", "IsUnverifiable"])
     header_output += BasicDeclare.subst(m5checkpointIop)
     decoder_output += BasicConstructor.subst(m5checkpointIop)
     exec_output += PredOpExecute.subst(m5checkpointIop)
@@ -260,7 +260,7 @@ let {{
     m5readfileIop = InstObjParams("m5readfile", "M5readfile", "PredOp",
                            { "code": m5readfileCode,
                              "predicate_test": predicateTest },
-                             ["IsNonSpeculative"])
+                             ["IsNonSpeculative", "IsUnverifiable"])
     header_output += BasicDeclare.subst(m5readfileIop)
     decoder_output += BasicConstructor.subst(m5readfileIop)
     exec_output += PredOpExecute.subst(m5readfileIop)
index 870f037d0321ce38a64bcd9ee9bf2339ab949e8b..45d5d8d32c21231b5e2c590ede759c2d0b9d182e 100644 (file)
@@ -525,7 +525,8 @@ let {{
             { "code" : wfeCode,
               "pred_fixup" : wfePredFixUpCode,
               "predicate_test" : predicateTest },
-            ["IsNonSpeculative", "IsQuiesce", "IsSerializeAfter"])
+            ["IsNonSpeculative", "IsQuiesce",
+             "IsSerializeAfter", "IsUnverifiable"])
     header_output += BasicDeclare.subst(wfeIop)
     decoder_output += BasicConstructor.subst(wfeIop)
     exec_output += QuiescePredOpExecuteWithFixup.subst(wfeIop)
@@ -542,7 +543,8 @@ let {{
     '''
     wfiIop = InstObjParams("wfi", "WfiInst", "PredOp", \
             { "code" : wfiCode, "predicate_test" : predicateTest },
-            ["IsNonSpeculative", "IsQuiesce", "IsSerializeAfter"])
+            ["IsNonSpeculative", "IsQuiesce",
+             "IsSerializeAfter", "IsUnverifiable"])
     header_output += BasicDeclare.subst(wfiIop)
     decoder_output += BasicConstructor.subst(wfiIop)
     exec_output += QuiescePredOpExecute.subst(wfiIop)
@@ -565,7 +567,7 @@ let {{
     '''
     sevIop = InstObjParams("sev", "SevInst", "PredOp", \
             { "code" : sevCode, "predicate_test" : predicateTest },
-            ["IsNonSpeculative", "IsSquashAfter"])
+            ["IsNonSpeculative", "IsSquashAfter", "IsUnverifiable"])
     header_output += BasicDeclare.subst(sevIop)
     decoder_output += BasicConstructor.subst(sevIop)
     exec_output += PredOpExecute.subst(sevIop)
index b2ab010c0d9373e49ba401ac1ae7dadd3546603d..9c92ebdf6a33feaac48d898d59b8680cadf4addf 100644 (file)
@@ -107,8 +107,9 @@ TableWalker::getPort(const std::string &if_name, int idx)
 
 Fault
 TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode,
-            TLB::Translation *_trans, bool _timing)
+            TLB::Translation *_trans, bool _timing, bool _functional)
 {
+    assert(!(_functional && _timing));
     if (!currState) {
         // For atomic mode, a new WalkerState instance should be only created
         // once per TLB. For timing mode, a new instance is generated for every
@@ -136,6 +137,7 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
     currState->fault = NoFault;
     currState->contextId = _cid;
     currState->timing = _timing;
+    currState->functional = _functional;
     currState->mode = _mode;
 
     /** @todo These should be cached or grabbed from cached copies in
@@ -230,12 +232,21 @@ TableWalker::processWalk()
                 stateQueueL1.size());
         stateQueueL1.push_back(currState);
         currState = NULL;
-    } else {
+    } else if (!currState->functional) {
         port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
                 NULL, (uint8_t*)&currState->l1Desc.data,
                 currState->tc->getCpuPtr()->ticks(1), flag);
         doL1Descriptor();
         f = currState->fault;
+    } else {
+        RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag);
+        PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
+        pkt->dataStatic((uint8_t*)&currState->l1Desc.data);
+        port->sendFunctional(pkt);
+        doL1Descriptor();
+        delete req;
+        delete pkt;
+        f = currState->fault;
     }
 
     return f;
@@ -566,11 +577,19 @@ TableWalker::doL1Descriptor()
             port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
                     &doL2DescEvent, (uint8_t*)&currState->l2Desc.data,
                     currState->tc->getCpuPtr()->ticks(1));
-        } else {
+        } else if (!currState->functional) {
             port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
                     NULL, (uint8_t*)&currState->l2Desc.data,
                     currState->tc->getCpuPtr()->ticks(1));
             doL2Descriptor();
+        } else {
+            RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0);
+            PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
+            pkt->dataStatic((uint8_t*)&currState->l2Desc.data);
+            port->sendFunctional(pkt);
+            doL2Descriptor();
+            delete req;
+            delete pkt;
         }
         return;
       default:
index 85db1fa777f868974edbacde12a4b5256ad0127b..d4a2e87b5ca682fd089967ea27f64d02a2cace73 100644 (file)
@@ -294,6 +294,9 @@ class TableWalker : public MemObject
         /** If the mode is timing or atomic */
         bool timing;
 
+        /** If the atomic mode should be functional */
+        bool functional;
+
         /** Save mode for use in delayed response */
         BaseTLB::Mode mode;
 
@@ -354,7 +357,7 @@ class TableWalker : public MemObject
     virtual Port *getPort(const std::string &if_name, int idx = -1);
 
     Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
-            TLB::Translation *_trans, bool timing);
+            TLB::Translation *_trans, bool timing, bool functional = false);
 
     void setTlb(TLB *_tlb) { tlb = _tlb; }
     void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
index a03e445cfa578fe3aa5cfb503ca5011b0b832758..f4dc476552882dc50118bc833ba48c597f1d60ce 100644 (file)
@@ -453,8 +453,11 @@ TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
 
 Fault
 TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
-        Translation *translation, bool &delay, bool timing)
+        Translation *translation, bool &delay, bool timing, bool functional)
 {
+    // No such thing as a functional timing access
+    assert(!(timing && functional));
+
     if (!miscRegValid) {
         updateMiscReg(tc);
         DPRINTF(TLBVerbose, "TLB variables changed!\n");
@@ -541,7 +544,7 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
         DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
                 vaddr, contextId);
         fault = tableWalker->walk(req, tc, contextId, mode, translation,
-                timing);
+                                  timing, functional);
         if (timing && fault == NoFault) {
             delay = true;
             // for timing mode, return and wait for table walk
@@ -700,6 +703,20 @@ TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
     return fault;
 }
 
+Fault
+TLB::translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode)
+{
+    bool delay = false;
+    Fault fault;
+#if FULL_SYSTEM
+    fault = translateFs(req, tc, mode, NULL, delay, false, true);
+#else
+    fault = translateSe(req, tc, mode, NULL, delay, false);
+#endif
+    assert(!delay);
+    return fault;
+}
+
 Fault
 TLB::translateTiming(RequestPtr req, ThreadContext *tc,
         Translation *translation, Mode mode)
index 3464e42b3a2412e5bcc745e696fb5827a5aee2ed..bdfa2fc9fdc032b0bcc3715d6bd3054ae9750324 100644 (file)
@@ -182,6 +182,12 @@ class TLB : public BaseTLB
      */
     bool translateFunctional(ThreadContext *tc, Addr vaddr, Addr &paddr);
 
+    /**
+     * Do a functional lookup on the TLB (for checker cpu) that
+     * behaves like a normal lookup without modifying any page table state.
+     */
+    Fault translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode);
+
     /** Accessor functions for memory attributes for last accessed TLB entry
      */
     void
@@ -197,7 +203,8 @@ class TLB : public BaseTLB
 
 #if FULL_SYSTEM
     Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
-            Translation *translation, bool &delay, bool timing);
+            Translation *translation, bool &delay,
+            bool timing, bool functional = false);
 #else
     Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
             Translation *translation, bool &delay, bool timing);
index 98195ab04ccdd0efb91f69deaafa20e55d476d98..b31dc432425b50b13b80d2abf9e243f85e92f1f2 100644 (file)
@@ -41,6 +41,7 @@
 #include "arch/arm/faults.hh"
 #include "arch/arm/isa_traits.hh"
 #include "arch/arm/utility.hh"
+#include "config/use_checker.hh"
 #include "cpu/thread_context.hh"
 
 #if FULL_SYSTEM
@@ -116,7 +117,11 @@ skipFunction(ThreadContext *tc)
 {
     TheISA::PCState newPC = tc->pcState();
     newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1));
+#if USE_CHECKER
+    tc->pcStateNoRecord(newPC);
+#else
     tc->pcState(newPC);
+#endif
 }
 
 void
index 6800b4c9199def74ef8d67562b62cb6e1c7e62a1..77ba35b19d40a4f0ee53e36c51681f84e7be1a14 100644 (file)
@@ -178,7 +178,6 @@ class BaseCPU(MemObject):
         self.connectUncachedPorts(uncached_bus)
 
     def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None):
-        assert(len(self._cached_ports) < 7)
         self.icache = ic
         self.dcache = dc
         self.icache_port = ic.cpu_side
@@ -195,6 +194,11 @@ class BaseCPU(MemObject):
                                            "dtb_walker_cache.mem_side"]
                 else:
                     self._cached_ports += ["itb.walker.port", "dtb.walker.port"]
+                # Checker doesn't need its own tlb caches because it does
+                # functional accesses only
+                if buildEnv['USE_CHECKER']:
+                    self._cached_ports += ["checker.itb.walker.port", \
+                                           "checker.dtb.walker.port"]
 
     def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
         self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
index 132254413fded21070e5e0721bbfa1cbcfaf4b2c..c144c467890033c6a46f6ef9435b7a3d174239bb 100644 (file)
@@ -35,7 +35,7 @@ class CheckerCPU(BaseCPU):
     exitOnError = Param.Bool(False, "Exit on an error")
     updateOnError = Param.Bool(False,
         "Update the checker with the main CPU's state on an error")
-    warnOnlyOnLoadError = Param.Bool(False,
+    warnOnlyOnLoadError = Param.Bool(True,
         "If a load result is incorrect, only print a warning and do not exit")
     function_trace = Param.Bool(False, "Enable function trace")
     function_trace_start = Param.Tick(0, "Cycle to start function trace")
diff --git a/src/cpu/DummyChecker.py b/src/cpu/DummyChecker.py
new file mode 100644 (file)
index 0000000..3c276e1
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2010-2011 ARM Limited
+# All rights reserved
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# 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.
+#
+# Authors: Geoffrey Blake
+
+from m5.params import *
+from BaseCPU import BaseCPU
+
+class DummyChecker(BaseCPU):
+    type = 'DummyChecker'
index a1074cb8b6bb73c51b405d2895a482158949fff7..5b276380eb0a27ae52315920b67587a2cf37caef 100644 (file)
@@ -137,7 +137,9 @@ if env['FULL_SYSTEM']:
         Source('legiontrace.cc')
 
 if env['USE_CHECKER']:
+    SimObject('DummyChecker.py')
     Source('checker/cpu.cc')
+    Source('dummy_checker_builder.cc')
     DebugFlag('Checker')
     checker_supports = False
     for i in CheckerSupportedCPUList:
index 370be7ee1e7cef126c75c56674fe5f514095f46e..fe840cd3561bcda7d19f4ee7e7607c83a7c71bee 100644 (file)
@@ -53,6 +53,7 @@
 #include "base/misc.hh"
 #include "base/output.hh"
 #include "base/trace.hh"
+#include "config/use_checker.hh"
 #include "cpu/base.hh"
 #include "cpu/cpuevent.hh"
 #include "cpu/profile.hh"
 #include "sim/sim_exit.hh"
 #include "sim/system.hh"
 
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
 // Hack
 #include "sim/stat_control.hh"
 
@@ -219,7 +224,10 @@ BaseCPU::BaseCPU(Params *p)
         }
     }
 #if FULL_SYSTEM
-    interrupts->setCPU(this);
+    // Check if CPU model has interrupts connected. The CheckerCPU
+    // cannot take interrupts directly for example.
+    if (interrupts)
+        interrupts->setCPU(this);
 
     profileEvent = NULL;
     if (params()->profile)
@@ -408,6 +416,35 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
             new_dtb_port->setPeer(peer);
             peer->setPeer(new_dtb_port);
         }
+
+#if USE_CHECKER
+        Port *old_checker_itb_port, *old_checker_dtb_port;
+        Port *new_checker_itb_port, *new_checker_dtb_port;
+
+        CheckerCPU *oldChecker =
+            dynamic_cast<CheckerCPU*>(oldTC->getCheckerCpuPtr());
+        CheckerCPU *newChecker =
+            dynamic_cast<CheckerCPU*>(newTC->getCheckerCpuPtr());
+        old_checker_itb_port = oldChecker->getITBPtr()->getPort();
+        old_checker_dtb_port = oldChecker->getDTBPtr()->getPort();
+        new_checker_itb_port = newChecker->getITBPtr()->getPort();
+        new_checker_dtb_port = newChecker->getDTBPtr()->getPort();
+
+        // Move over any table walker ports if they exist for checker
+        if (new_checker_itb_port && !new_checker_itb_port->isConnected()) {
+            assert(old_checker_itb_port);
+            Port *peer = old_checker_itb_port->getPeer();;
+            new_checker_itb_port->setPeer(peer);
+            peer->setPeer(new_checker_itb_port);
+        }
+        if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) {
+            assert(old_checker_dtb_port);
+            Port *peer = old_checker_dtb_port->getPeer();;
+            new_checker_dtb_port->setPeer(peer);
+            peer->setPeer(new_checker_dtb_port);
+        }
+#endif
+
     }
 
 #if FULL_SYSTEM
index 5719fc84da30f7ad04ac98a039eba185fb497b6f..14889a206d1d458e05419a972cd159888549ac5c 100644 (file)
@@ -48,6 +48,7 @@
 #include <bitset>
 #include <list>
 #include <string>
+#include <queue>
 
 #include "arch/faults.hh"
 #include "arch/utility.hh"
@@ -55,6 +56,7 @@
 #include "base/trace.hh"
 #include "config/full_system.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/o3/comm.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/inst_seq.hh"
@@ -176,6 +178,11 @@ class BaseDynInst : public FastAlloc, public RefCounted
     RequestPtr savedSreqLow;
     RequestPtr savedSreqHigh;
 
+#if USE_CHECKER
+    // Need a copy of main request pointer to verify on writes.
+    RequestPtr reqToVerify;
+#endif //USE_CHECKER
+
     /** @todo: Consider making this private. */
   public:
     /** The sequence number of the instruction. */
@@ -248,14 +255,17 @@ class BaseDynInst : public FastAlloc, public RefCounted
 
     union Result {
         uint64_t integer;
-//        float fp;
         double dbl;
+        void set(uint64_t i) { integer = i; }
+        void set(double d) { dbl = d; }
+        void get(uint64_t& i) { i = integer; }
+        void get(double& d) { d = dbl; }
     };
 
-    /** The result of the instruction; assumes for now that there's only one
-     *  destination register.
+    /** The result of the instruction; assumes an instruction can have many
+     *  destination registers.
      */
-    Result instResult;
+    std::queue<Result> instResult;
 
     /** Records changes to result? */
     bool recordResult;
@@ -558,56 +568,68 @@ class BaseDynInst : public FastAlloc, public RefCounted
     /** Returns the logical register index of the i'th source register. */
     RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); }
 
-    /** Returns the result of an integer instruction. */
-    uint64_t readIntResult() { return instResult.integer; }
+    /** Pops a result off the instResult queue */
+    template <class T>
+    void popResult(T& t)
+    {
+        if (!instResult.empty()) {
+            instResult.front().get(t);
+            instResult.pop();
+        }
+    }
 
-    /** Returns the result of a floating point instruction. */
-    float readFloatResult() { return (float)instResult.dbl; }
+    /** Read the most recent result stored by this instruction */
+    template <class T>
+    void readResult(T& t)
+    {
+        instResult.back().get(t);
+    }
 
-    /** Returns the result of a floating point (double) instruction. */
-    double readDoubleResult() { return instResult.dbl; }
+    /** Pushes a result onto the instResult queue */
+    template <class T>
+    void setResult(T t)
+    {
+        if (recordResult) {
+            Result instRes;
+            instRes.set(t);
+            instResult.push(instRes);
+        }
+    }
 
     /** Records an integer register being set to a value. */
     void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
     {
-        if (recordResult)
-            instResult.integer = val;
+        setResult<uint64_t>(val);
     }
 
     /** Records an fp register being set to a value. */
     void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
                             int width)
     {
-        if (recordResult) {
-            if (width == 32)
-                instResult.dbl = (double)val;
-            else if (width == 64)
-                instResult.dbl = val;
-            else
-                panic("Unsupported width!");
+        if (width == 32 || width == 64) {
+            setResult<double>(val);
+        } else {
+            panic("Unsupported width!");
         }
     }
 
     /** Records an fp register being set to a value. */
     void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
     {
-        if (recordResult)
-            instResult.dbl = (double)val;
+        setResult<double>(val);
     }
 
     /** Records an fp register being set to an integer value. */
     void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val,
                                 int width)
     {
-        if (recordResult)
-            instResult.integer = val;
+        setResult<uint64_t>(val);
     }
 
     /** Records an fp register being set to an integer value. */
     void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val)
     {
-        if (recordResult)
-            instResult.integer = val;
+        setResult<uint64_t>(val);
     }
 
     /** Records that one of the source registers is ready. */
@@ -872,6 +894,12 @@ BaseDynInst<Impl>::readMem(Addr addr, uint8_t *data,
             effAddr = req->getVaddr();
             effSize = size;
             effAddrValid = true;
+#if USE_CHECKER
+            if (reqToVerify != NULL) {
+                delete reqToVerify;
+            }
+            reqToVerify = new Request(*req);
+#endif //USE_CHECKER
             fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx);
         } else {
             // Commit will have to clean up whatever happened.  Set this
@@ -927,6 +955,12 @@ BaseDynInst<Impl>::writeMem(uint8_t *data, unsigned size,
         effAddr = req->getVaddr();
         effSize = size;
         effAddrValid = true;
+#if USE_CHECKER
+        if (reqToVerify != NULL) {
+            delete reqToVerify;
+        }
+        reqToVerify = new Request(*req);
+#endif // USE_CHECKER
         fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx);
     }
 
index a37ec5e258f95d72a17deea63f757c87c0848970..d2ecd01ff01552755ffd2094f4689ff43892f379 100644 (file)
@@ -48,6 +48,7 @@
 #include "base/cprintf.hh"
 #include "base/trace.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/base_dyn_inst.hh"
 #include "cpu/exetrace.hh"
 #include "debug/DynInst.hh"
@@ -117,7 +118,6 @@ BaseDynInst<Impl>::initVars()
     reqMade = false;
     readyRegs = 0;
 
-    instResult.integer = 0;
     recordResult = true;
 
     status.reset();
@@ -157,6 +157,10 @@ BaseDynInst<Impl>::initVars()
 #ifdef DEBUG
     cpu->snList.insert(seqNum);
 #endif
+
+#if USE_CHECKER
+    reqToVerify = NULL;
+#endif
 }
 
 template <class Impl>
@@ -182,6 +186,11 @@ BaseDynInst<Impl>::~BaseDynInst()
 #ifdef DEBUG
     cpu->snList.erase(seqNum);
 #endif
+
+#if USE_CHECKER
+    if (reqToVerify)
+        delete reqToVerify;
+#endif // USE_CHECKER
 }
 
 #ifdef DEBUG
index 0c7fe66bf91587546dfe5c5c62ffb8c80c403267..7c9e4f78158dddcfbc288281da781d4d6138010e 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -26,6 +38,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Authors: Kevin Lim
+ *          Geoffrey Blake
  */
 
 #include <list>
@@ -36,6 +49,8 @@
 #include "cpu/simple_thread.hh"
 #include "cpu/static_inst.hh"
 #include "cpu/thread_context.hh"
+#include "params/CheckerCPU.hh"
+#include "sim/tlb.hh"
 
 #if FULL_SYSTEM
 #include "arch/kernel_stats.hh"
@@ -43,8 +58,7 @@
 #endif // FULL_SYSTEM
 
 using namespace std;
-//The CheckerCPU does alpha only
-using namespace AlphaISA;
+using namespace TheISA;
 
 void
 CheckerCPU::init()
@@ -55,6 +69,8 @@ CheckerCPU::CheckerCPU(Params *p)
     : BaseCPU(p), thread(NULL), tc(NULL)
 {
     memReq = NULL;
+    curStaticInst = NULL;
+    curMacroStaticInst = NULL;
 
     numInst = 0;
     startNumInst = 0;
@@ -66,19 +82,20 @@ CheckerCPU::CheckerCPU(Params *p)
 
     exitOnError = p->exitOnError;
     warnOnlyOnLoadError = p->warnOnlyOnLoadError;
-#if FULL_SYSTEM
     itb = p->itb;
     dtb = p->dtb;
+#if FULL_SYSTEM
     systemPtr = NULL;
 #else
-    process = p->process;
-    thread = new SimpleThread(this, /* thread_num */ 0, process);
+    workload = p->workload;
+    // XXX: This is a hack to get this to work some
+    thread = new SimpleThread(this, /* thread_num */ 0, workload[0], itb, dtb);
 
     tc = thread->getTC();
     threadContexts.push_back(tc);
 #endif
 
-    result.integer = 0;
+    updateOnError = true;
 }
 
 CheckerCPU::~CheckerCPU()
@@ -115,192 +132,194 @@ CheckerCPU::setDcachePort(Port *dcache_port)
 void
 CheckerCPU::serialize(ostream &os)
 {
-/*
-    BaseCPU::serialize(os);
-    SERIALIZE_SCALAR(inst);
-    nameOut(os, csprintf("%s.xc", name()));
-    thread->serialize(os);
-    cacheCompletionEvent.serialize(os);
-*/
 }
 
 void
 CheckerCPU::unserialize(Checkpoint *cp, const string &section)
 {
-/*
-    BaseCPU::unserialize(cp, section);
-    UNSERIALIZE_SCALAR(inst);
-    thread->unserialize(cp, csprintf("%s.xc", section));
-*/
 }
 
-template <class T>
 Fault
-CheckerCPU::read(Addr addr, T &data, unsigned flags)
+CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
 {
-    // need to fill in CPU & thread IDs here
-    memReq = new Request();
+    Fault fault = NoFault;
+    unsigned blockSize = dcachePort->peerBlockSize();
+    int fullSize = size;
+    Addr secondAddr = roundDown(addr + size - 1, blockSize);
+    bool checked_flags = false;
+    bool flags_match = true;
+    Addr pAddr = 0x0;
+
+
+    if (secondAddr > addr)
+       size = secondAddr - addr;
+
+    // Need to account for multiple accesses like the Atomic and TimingSimple
+    while (1) {
+        memReq = new Request();
+        memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
+
+        // translate to physical address
+        fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
+
+        if (!checked_flags && fault == NoFault && unverifiedReq) {
+            flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
+                                     memReq->getPaddr(), memReq->getFlags());
+            pAddr = memReq->getPaddr();
+            checked_flags = true;
+        }
 
-    memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
+        // Now do the access
+        if (fault == NoFault &&
+            !memReq->getFlags().isSet(Request::NO_ACCESS)) {
+            PacketPtr pkt = new Packet(memReq,
+                              memReq->isLLSC() ?
+                              MemCmd::LoadLockedReq : MemCmd::ReadReq,
+                              Packet::Broadcast);
+
+            pkt->dataStatic(data);
+
+            if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) {
+                // Access memory to see if we have the same data
+                dcachePort->sendFunctional(pkt);
+            } else {
+                // Assume the data is correct if it's an uncached access
+                memcpy(data, unverifiedMemData, size);
+            }
+
+            delete memReq;
+            memReq = NULL;
+            delete pkt;
+        }
 
-    // translate to physical address
-    dtb->translateAtomic(memReq, tc, false);
+        if (fault != NoFault) {
+            if (memReq->isPrefetch()) {
+                fault = NoFault;
+            }
+            delete memReq;
+            memReq = NULL;
+            break;
+        }
 
-    PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
+        if (memReq != NULL) {
+            delete memReq;
+        }
 
-    pkt->dataStatic(&data);
+        //If we don't need to access a second cache line, stop now.
+        if (secondAddr <= addr)
+        {
+            break;
+        }
 
-    if (!(memReq->isUncacheable())) {
-        // Access memory to see if we have the same data
-        dcachePort->sendFunctional(pkt);
-    } else {
-        // Assume the data is correct if it's an uncached access
-        memcpy(&data, &unverifiedResult.integer, sizeof(T));
+        // Setup for accessing next cache line
+        data += size;
+        unverifiedMemData += size;
+        size = addr + fullSize - secondAddr;
+        addr = secondAddr;
     }
 
-    delete pkt;
+    if (!flags_match) {
+        warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
+             curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
+             unverifiedReq->getFlags(), addr, pAddr, flags);
+        handleError();
+    }
 
-    return NoFault;
+    return fault;
 }
 
-#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)
+CheckerCPU::writeMem(uint8_t *data, unsigned size,
+                     Addr addr, unsigned flags, uint64_t *res)
 {
-    return read(addr, *(uint64_t*)&data, flags);
-}
+    Fault fault = NoFault;
+    bool checked_flags = false;
+    bool flags_match = true;
+    Addr pAddr = 0x0;
 
-template<>
-Fault
-CheckerCPU::read(Addr addr, float &data, unsigned flags)
-{
-    return read(addr, *(uint32_t*)&data, flags);
-}
+    unsigned blockSize = dcachePort->peerBlockSize();
+    int fullSize = size;
 
-template<>
-Fault
-CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
-{
-    return read(addr, (uint32_t&)data, flags);
-}
+    Addr secondAddr = roundDown(addr + size - 1, blockSize);
 
-template <class T>
-Fault
-CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
-{
-    // need to fill in CPU & thread IDs here
-    memReq = new Request();
-
-    memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
-
-    // translate to physical address
-    dtb->translateAtomic(memReq, tc, true);
-
-    // 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->isUncacheable()) &&
-        (!(unverifiedReq->isLLSC()) ||
-         ((unverifiedReq->isLLSC()) &&
-          unverifiedReq->getExtraData() == 1))) {
-        T inst_data;
-/*
-        // This code would work if the LSQ allowed for snooping.
-        PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
-        pkt.dataStatic(&inst_data);
+    if (secondAddr > addr)
+        size = secondAddr - addr;
 
-        dcachePort->sendFunctional(pkt);
+    // Need to account for a multiple access like Atomic and Timing CPUs
+    while (1) {
+        memReq = new Request();
+        memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
 
-        delete pkt;
-*/
-        memcpy(&inst_data, unverifiedMemData, sizeof(T));
+        // translate to physical address
+        fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
 
-        if (data != inst_data) {
-            warn("%lli: Store value does not match value in memory! "
-                 "Instruction: %#x, memory: %#x",
-                 curTick(), inst_data, data);
-            handleError();
+        if (!checked_flags && fault == NoFault && unverifiedReq) {
+           flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
+                                    memReq->getPaddr(), memReq->getFlags());
+           pAddr = memReq->getPaddr();
+           checked_flags = true;
         }
-    }
-
-    // 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 && unverifiedReq->scResultValid())
-        *res = unverifiedReq->getExtraData();
-
-    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);
-}
+        /*
+         * We don't actually check memory for the store because there
+         * is no guarantee it has left the lsq yet, and therefore we
+         * can't verify the memory on stores without lsq snooping
+         * enabled.  This is left as future work for the Checker: LSQ snooping
+         * and memory validation after stores have committed.
+         */
+
+        delete memReq;
+
+        //If we don't need to access a second cache line, stop now.
+        if (fault != NoFault || secondAddr <= addr)
+        {
+            if (fault != NoFault && memReq->isPrefetch()) {
+              fault = NoFault;
+            }
+            break;
+        }
 
-template<>
-Fault
-CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
-{
-    return write((uint32_t)data, addr, flags, res);
+        //Update size and access address
+        size = addr + fullSize - secondAddr;
+        //And access the right address.
+        addr = secondAddr;
+   }
+
+   if (!flags_match) {
+       warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
+            curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
+            unverifiedReq->getFlags(), addr, pAddr, flags);
+       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 (unverifiedReq && res && unverifiedReq->extraDataValid())
+       *res = unverifiedReq->getExtraData();
+
+   // Entire purpose here is to make sure we are getting the
+   // same data to send to the mem system as the CPU did.
+   // Cannot check this is actually what went to memory because
+   // there stores can be in ld/st queue or coherent operations
+   // overwriting values.
+   bool extraData;
+   if (unverifiedReq) {
+       extraData = unverifiedReq->extraDataValid() ?
+                        unverifiedReq->getExtraData() : 1;
+   }
+
+   if (unverifiedReq && unverifiedMemData &&
+       memcmp(data, unverifiedMemData, fullSize) && extraData) {
+           warn("%lli: Store value does not match value sent to memory!\
+                  data: %#x inst_data: %#x", curTick(), data,
+                  unverifiedMemData);
+       handleError();
+   }
+
+   return fault;
 }
 
-
 #if FULL_SYSTEM
 Addr
 CheckerCPU::dbg_vtophys(Addr addr)
@@ -309,24 +328,30 @@ CheckerCPU::dbg_vtophys(Addr addr)
 }
 #endif // FULL_SYSTEM
 
+/**
+ * Checks if the flags set by the Checker and Checkee match.
+ */
 bool
-CheckerCPU::checkFlags(Request *req)
+CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr,
+                       Addr pAddr, int flags)
 {
-    // Remove any dynamic flags that don't have to do with the request itself.
-    unsigned flags = unverifiedReq->getFlags();
-    unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | PREFETCH;
-    flags = flags & (mask);
-    if (flags == req->getFlags()) {
+    Addr unverifiedVAddr = unverified_req->getVaddr();
+    Addr unverifiedPAddr = unverified_req->getPaddr();
+    int unverifiedFlags = unverified_req->getFlags();
+
+    if (unverifiedVAddr != vAddr ||
+        unverifiedPAddr != pAddr ||
+        unverifiedFlags != flags) {
         return false;
-    } else {
-        return true;
     }
+
+    return true;
 }
 
 void
 CheckerCPU::dumpAndExit()
 {
-    warn("%lli: Checker PC:%#x, next PC:%#x",
-         curTick(), thread->readPC(), thread->readNextPC());
+    warn("%lli: Checker PC:%s",
+         curTick(), thread->pcState());
     panic("Checker found an error!");
 }
index 1e3a17a349d6d058bcb0ec72b97c413ccabde108..1419051a62846b911a31ec59c232237c6eff3405 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -35,6 +47,7 @@
 #include <map>
 #include <queue>
 
+#include "arch/predecoder.hh"
 #include "arch/types.hh"
 #include "base/statistics.hh"
 #include "config/full_system.hh"
@@ -43,6 +56,8 @@
 #include "cpu/pc_event.hh"
 #include "cpu/simple_thread.hh"
 #include "cpu/static_inst.hh"
+#include "debug/Checker.hh"
+#include "params/CheckerCPU.hh"
 #include "sim/eventq.hh"
 
 // forward declarations
@@ -61,7 +76,6 @@ class Process;
 #endif // FULL_SYSTEM
 template <class>
 class BaseDynInst;
-class CheckerCPUParams;
 class ThreadContext;
 class MemInterface;
 class Checkpoint;
@@ -96,11 +110,11 @@ class CheckerCPU : public BaseCPU
   public:
     typedef CheckerCPUParams Params;
     const Params *params() const
-    { return reinterpret_cast<const Params *>(_params); }    
+    { return reinterpret_cast<const Params *>(_params); }
     CheckerCPU(Params *p);
     virtual ~CheckerCPU();
 
-    Process *process;
+    std::vector<Process*> workload;
 
     void setSystem(System *system);
 
@@ -135,19 +149,25 @@ class CheckerCPU : public BaseCPU
 
     union Result {
         uint64_t integer;
-//        float fp;
         double dbl;
+        void set(uint64_t i) { integer = i; }
+        void set(double d) { dbl = d; }
+        void get(uint64_t& i) { i = integer; }
+        void get(double& d) { d = dbl; }
     };
 
-    Result result;
+    // ISAs like ARM can have multiple destination registers to check,
+    // keep them all in a std::queue
+    std::queue<Result> result;
 
     // current instruction
-    MachInst machInst;
+    TheISA::MachInst machInst;
 
     // Pointer to the one memory request.
     RequestPtr memReq;
 
     StaticInstPtr curStaticInst;
+    StaticInstPtr curMacroStaticInst;
 
     // number of simulated instructions
     Counter numInst;
@@ -155,6 +175,9 @@ class CheckerCPU : public BaseCPU
 
     std::queue<int> miscRegIdxs;
 
+    TheISA::TLB* getITBPtr() { return itb; }
+    TheISA::TLB* getDTBPtr() { return dtb; }
+
     virtual Counter totalInstructions() const
     {
         return 0;
@@ -167,12 +190,6 @@ class CheckerCPU : public BaseCPU
     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"); }
@@ -206,17 +223,25 @@ class CheckerCPU : public BaseCPU
         return thread->readFloatRegBits(reg_idx);
     }
 
+    template <class T>
+    void setResult(T t)
+    {
+        Result instRes;
+        instRes.set(t);
+        result.push(instRes);
+    }
+
     void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
     {
         thread->setIntReg(si->destRegIdx(idx), val);
-        result.integer = val;
+        setResult<uint64_t>(val);
     }
 
     void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
     {
         int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
         thread->setFloatReg(reg_idx, val);
-        result.dbl = (double)val;
+        setResult<double>(val);
     }
 
     void setFloatRegOperandBits(const StaticInst *si, int idx,
@@ -224,12 +249,26 @@ class CheckerCPU : public BaseCPU
     {
         int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
         thread->setFloatRegBits(reg_idx, val);
-        result.integer = val;
+        setResult<uint64_t>(val);
     }
 
-    uint64_t instAddr() { return thread->instAddr(); }
+    bool readPredicate() { return thread->readPredicate(); }
+    void setPredicate(bool val)
+    {
+        thread->setPredicate(val);
+    }
 
-    uint64_t nextInstAddr() { return thread->nextInstAddr(); }
+    TheISA::PCState pcState() { return thread->pcState(); }
+    void pcState(const TheISA::PCState &val)
+    {
+        DPRINTF(Checker, "Changing PC to %s, old PC %s.\n",
+                         val, thread->pcState());
+        thread->pcState(val);
+    }
+    Addr instAddr() { return thread->instAddr(); }
+    Addr nextInstAddr() { return thread->nextInstAddr(); }
+    MicroPC microPC() { return thread->microPC(); }
+    //////////////////////////////////////////
 
     MiscReg readMiscRegNoEffect(int misc_reg)
     {
@@ -243,7 +282,6 @@ class CheckerCPU : public BaseCPU
 
     void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
     {
-        result.integer = val;
         miscRegIdxs.push(misc_reg);
         return thread->setMiscRegNoEffect(misc_reg, val);
     }
@@ -254,8 +292,25 @@ class CheckerCPU : public BaseCPU
         return thread->setMiscReg(misc_reg, val);
     }
 
-    void recordPCChange(uint64_t val) { changedPC = true; newPC = val; }
-    void recordNextPCChange(uint64_t val) { changedNextPC = true; }
+    MiscReg readMiscRegOperand(const StaticInst *si, int idx)
+    {
+        int reg_idx = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
+        return thread->readMiscReg(reg_idx);
+    }
+
+    void setMiscRegOperand(
+            const StaticInst *si, int idx, const MiscReg &val)
+    {
+        int reg_idx = si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
+        return thread->setMiscReg(reg_idx, val);
+    }
+    /////////////////////////////////////////
+
+    void recordPCChange(const TheISA::PCState &val)
+    {
+       changedPC = true;
+       newPCState = val;
+    }
 
     void demapPage(Addr vaddr, uint64_t asn)
     {
@@ -273,9 +328,18 @@ class CheckerCPU : public BaseCPU
         this->dtb->demapPage(vaddr, asn);
     }
 
+    Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+    Fault writeMem(uint8_t *data, unsigned size,
+                   Addr addr, unsigned flags, uint64_t *res);
+
+    void setStCondFailures(unsigned sc_failures)
+    {}
+    /////////////////////////////////////////////////////
+
 #if FULL_SYSTEM
     Fault hwrei() { return thread->hwrei(); }
     bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
+    void wakeup() { }
 #else
     // Assume that the normal CPU's call to syscall was successful.
     // The checker's state would have already been updated by the syscall.
@@ -288,7 +352,8 @@ class CheckerCPU : public BaseCPU
             dumpAndExit();
     }
 
-    bool checkFlags(Request *req);
+    bool checkFlags(Request *unverified_req, Addr vAddr,
+                    Addr pAddr, int flags);
 
     void dumpAndExit();
 
@@ -301,7 +366,7 @@ class CheckerCPU : public BaseCPU
 
     bool changedPC;
     bool willChangePC;
-    uint64_t newPC;
+    TheISA::PCState newPCState;
     bool changedNextPC;
     bool exitOnError;
     bool updateOnError;
@@ -316,24 +381,31 @@ class CheckerCPU : public BaseCPU
  * template instantiations of the Checker must be placed at the bottom
  * of checker/cpu.cc.
  */
-template <class DynInstPtr>
+template <class Impl>
 class Checker : public CheckerCPU
 {
+  private:
+    typedef typename Impl::DynInstPtr DynInstPtr;
+
   public:
     Checker(Params *p)
-        : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
+        : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL),
+          predecoder(NULL)
     { }
 
     void switchOut();
     void takeOverFrom(BaseCPU *oldCPU);
 
+    void advancePC(Fault fault);
+
     void verify(DynInstPtr &inst);
 
     void validateInst(DynInstPtr &inst);
     void validateExecution(DynInstPtr &inst);
     void validateState();
 
-    void copyResult(DynInstPtr &inst);
+    void copyResult(DynInstPtr &inst, uint64_t mismatch_val, int start_idx);
+    void handlePendingInt();
 
   private:
     void handleError(DynInstPtr &inst)
@@ -350,6 +422,7 @@ class Checker : public CheckerCPU
     bool updateThisCycle;
 
     DynInstPtr unverifiedInst;
+    TheISA::Predecoder predecoder;
 
     std::list<DynInstPtr> instList;
     typedef typename std::list<DynInstPtr>::iterator InstListIt;
index 8694dae2108bd77be9c974dd173de3f6825eaa5c..8c8789cb6b679fa7886349a8e79f76ba37376459 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -26,6 +38,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Authors: Kevin Lim
+ *          Geoffrey Blake
  */
 
 #include <list>
 
 #include "base/refcnt.hh"
 #include "config/the_isa.hh"
-#include "cpu/checker/cpu.hh"
 #include "cpu/base_dyn_inst.hh"
+#include "cpu/exetrace.hh"
 #include "cpu/simple_thread.hh"
 #include "cpu/static_inst.hh"
 #include "cpu/thread_context.hh"
+#include "cpu/checker/cpu.hh"
+#include "debug/Checker.hh"
 #include "sim/sim_object.hh"
 #include "sim/stats.hh"
 
 #endif // FULL_SYSTEM
 
 using namespace std;
-//The CheckerCPU does alpha only
-using namespace AlphaISA;
+using namespace TheISA;
+
+template <class Impl>
+void
+Checker<Impl>::advancePC(Fault fault)
+{
+    if (fault != NoFault) {
+        curMacroStaticInst = StaticInst::nullStaticInstPtr;
+        fault->invoke(tc, curStaticInst);
+        predecoder.reset();
+    } else {
+        if (curStaticInst) {
+            if (curStaticInst->isLastMicroop())
+                curMacroStaticInst = StaticInst::nullStaticInstPtr;
+            TheISA::PCState pcState = thread->pcState();
+            TheISA::advancePC(pcState, curStaticInst);
+            thread->pcState(pcState);
+            DPRINTF(Checker, "Advancing PC to %s.\n", thread->pcState());
+        }
+    }
+}
+//////////////////////////////////////////////////
+
+template <class Impl>
+void
+Checker<Impl>::handlePendingInt()
+{
+    DPRINTF(Checker, "IRQ detected at PC: %s with %d insts in buffer\n",
+                     thread->pcState(), instList.size());
+    DynInstPtr boundaryInst = NULL;
+    if (!instList.empty()) {
+        // Set the instructions as completed and verify as much as possible.
+        DynInstPtr inst;
+        typename std::list<DynInstPtr>::iterator itr;
+
+        for (itr = instList.begin(); itr != instList.end(); itr++) {
+            (*itr)->setCompleted();
+        }
 
-template <class DynInstPtr>
+        inst = instList.front();
+        boundaryInst = instList.back();
+        verify(inst); // verify the instructions
+        inst = NULL;
+    }
+    if ((!boundaryInst && curMacroStaticInst &&
+          curStaticInst->isDelayedCommit() &&
+          !curStaticInst->isLastMicroop()) ||
+        (boundaryInst && boundaryInst->isDelayedCommit() &&
+         !boundaryInst->isLastMicroop())) {
+        panic("%lli: Trying to take an interrupt in middle of "
+              "a non-interuptable instruction!", curTick());
+    }
+    boundaryInst = NULL;
+    predecoder.reset();
+    curMacroStaticInst = StaticInst::nullStaticInstPtr;
+}
+
+template <class Impl>
 void
-Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
+Checker<Impl>::verify(DynInstPtr &completed_inst)
 {
     DynInstPtr inst;
 
+    // Make sure serializing instructions are actually
+    // seen as serializing to commit. instList should be
+    // empty in these cases.
+    if ((completed_inst->isSerializing() ||
+        completed_inst->isSerializeBefore()) &&
+        (!instList.empty() ?
+         (instList.front()->seqNum != completed_inst->seqNum) : 0)) {
+        panic("%lli: Instruction sn:%lli at PC %s is serializing before but is"
+              " entering instList with other instructions\n", curTick(),
+              completed_inst->seqNum, completed_inst->pcState());
+    }
+
     // 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
@@ -62,8 +143,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
     // 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());
+            DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
+                    completed_inst->seqNum, completed_inst->pcState());
             instList.push_back(completed_inst);
             youngestSN = completed_inst->seqNum;
         }
@@ -77,8 +158,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
     } 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());
+                DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
+                        completed_inst->seqNum, completed_inst->pcState());
                 instList.push_back(completed_inst);
                 youngestSN = completed_inst->seqNum;
             }
@@ -93,17 +174,29 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         }
     }
 
+    // Make sure a serializing instruction is actually seen as
+    // serializing. instList should be empty here
+    if (inst->isSerializeAfter() && !instList.empty()) {
+        panic("%lli: Instruction sn:%lli at PC %s is serializing after but is"
+             " exiting instList with other instructions\n", curTick(),
+             completed_inst->seqNum, completed_inst->pcState());
+    }
     unverifiedInst = inst;
+    inst = NULL;
 
     // 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;
-        unverifiedMemData = inst->memData;
+        DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%s.\n",
+                unverifiedInst->seqNum, unverifiedInst->pcState());
+        unverifiedReq = NULL;
+        unverifiedReq = unverifiedInst->reqToVerify;
+        unverifiedMemData = unverifiedInst->memData;
+        // Make sure results queue is empty
+        while (!result.empty()) {
+            result.pop();
+        }
         numCycles++;
 
         Fault fault = NoFault;
@@ -118,15 +211,15 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         // 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",
-                    thread->readPC());
+            DPRINTF(Checker, "Changed PC recently to %s\n",
+                    thread->pcState());
             if (willChangePC) {
-                if (newPC == thread->readPC()) {
+                if (newPCState == thread->pcState()) {
                     DPRINTF(Checker, "Changed PC matches expected PC\n");
                 } else {
                     warn("%lli: Changed PC does not match expected PC, "
-                         "changed: %#x, expected: %#x",
-                         curTick(), thread->readPC(), newPC);
+                         "changed: %s, expected: %s",
+                         curTick(), thread->pcState(), newPCState);
                     CheckerCPU::handleError();
                 }
                 willChangePC = false;
@@ -135,124 +228,188 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         }
         if (changedNextPC) {
             DPRINTF(Checker, "Changed NextPC recently to %#x\n",
-                    thread->readNextPC());
+                    thread->nextInstAddr());
             changedNextPC = false;
         }
 
         // Try to fetch the instruction
+        uint64_t fetchOffset = 0;
+        bool fetchDone = false;
+
+        while (!fetchDone) {
+            Addr fetch_PC = thread->instAddr();
+            fetch_PC = (fetch_PC & PCMask) + fetchOffset;
+
+            // If not in the middle of a macro instruction
+            if (!curMacroStaticInst) {
+                // set up memory request for instruction fetch
+                memReq = new Request(unverifiedInst->threadNumber, fetch_PC,
+                                     sizeof(MachInst),
+                                     0,
+                                     fetch_PC, thread->contextId(),
+                                     unverifiedInst->threadNumber);
+                memReq->setVirt(0, fetch_PC, sizeof(MachInst),
+                                Request::INST_FETCH, thread->instAddr());
+
+
+                fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute);
+
+                if (fault != NoFault) {
+                    if (unverifiedInst->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 %s was not found in the "
+                             "ITB!", curTick(), thread->pcState());
+                        handleError(unverifiedInst);
+
+                        // go to the next instruction
+                        advancePC(NoFault);
+
+                        // Give up on an ITB fault..
+                        delete memReq;
+                        unverifiedInst = NULL;
+                        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 = unverifiedInst->getFault();
+                        delete memReq;
+                        break;
+                    }
+                } else {
+                    PacketPtr pkt = new Packet(memReq,
+                                               MemCmd::ReadReq,
+                                               Packet::Broadcast);
 
-#if FULL_SYSTEM
-#define IFETCH_FLAGS(pc)        ((pc) & 1) ? PHYSICAL : 0
-#else
-#define IFETCH_FLAGS(pc)        0
-#endif
-
-        uint64_t fetch_PC = thread->readPC() & ~3;
-
-        // set up memory request for instruction fetch
-        memReq = new Request(inst->threadNumber, fetch_PC,
-                             sizeof(uint32_t),
-                             IFETCH_FLAGS(thread->readPC()),
-                             fetch_PC, thread->contextId(),
-                             inst->threadNumber);
-
-        bool succeeded = itb->translateAtomic(memReq, thread);
-
-        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(), thread->readPC());
-                handleError(inst);
+                    pkt->dataStatic(&machInst);
+                    icachePort->sendFunctional(pkt);
+                    machInst = gtoh(machInst);
 
-                // go to the next instruction
-                thread->setPC(thread->readNextPC());
-                thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
+                    delete memReq;
+                    delete pkt;
+                }
+            }
 
-                break;
-            } 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) {
+                TheISA::PCState pcState = thread->pcState();
+
+                if (isRomMicroPC(pcState.microPC())) {
+                    fetchDone = true;
+                    curStaticInst =
+                        microcodeRom.fetchMicroop(pcState.microPC(), NULL);
+                } else if (!curMacroStaticInst) {
+                    //We're not in the middle of a macro instruction
+                    StaticInstPtr instPtr = NULL;
+
+                    //Predecode, ie bundle up an ExtMachInst
+                    predecoder.setTC(thread->getTC());
+                    //If more fetch data is needed, pass it in.
+                    Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
+                    predecoder.moreBytes(pcState, fetchPC, machInst);
+
+                    //If an instruction is ready, decode it.
+                    //Otherwise, we'll have to fetch beyond the
+                    //MachInst at the current pc.
+                    if (predecoder.extMachInstReady()) {
+                        fetchDone = true;
+                        ExtMachInst newMachInst =
+                            predecoder.getExtMachInst(pcState);
+                        thread->pcState(pcState);
+                        instPtr = thread->decoder.decode(newMachInst,
+                                                         pcState.instAddr());
+                        machInst = newMachInst;
+                    } else {
+                        fetchDone = false;
+                        fetchOffset += sizeof(TheISA::MachInst);
+                    }
+
+                    //If we decoded an instruction and it's microcoded,
+                    //start pulling out micro ops
+                    if (instPtr && instPtr->isMacroop()) {
+                        curMacroStaticInst = instPtr;
+                        curStaticInst =
+                            instPtr->fetchMicroop(pcState.microPC());
+                    } else {
+                        curStaticInst = instPtr;
+                    }
+                } else {
+                    // Read the next micro op from the macro-op
+                    curStaticInst =
+                        curMacroStaticInst->fetchMicroop(pcState.microPC());
+                    fetchDone = true;
+                }
             }
         }
+        // reset predecoder on Checker
+        predecoder.reset();
 
+        // Check Checker and CPU get same instruction, and record
+        // any faults the CPU may have had.
+        Fault unverifiedFault;
         if (fault == NoFault) {
-            PacketPtr pkt = new Packet(memReq, Packet::ReadReq,
-                                     Packet::Broadcast);
-
-            pkt->dataStatic(&machInst);
+            unverifiedFault = unverifiedInst->getFault();
 
-            icachePort->sendFunctional(pkt);
-
-            delete pkt;
-
-            // 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);
-
-#if THE_ISA == ALPHA_ISA
-            curStaticInst = StaticInst::decode(makeExtMI(machInst,
-                                                         thread->readPC()));
-#elif THE_ISA == SPARC_ISA
-            curStaticInst = StaticInst::decode(makeExtMI(machInst,
-                                                         thread->getTC()));
-#endif
-
-            fault = inst->getFault();
+            validateInst(unverifiedInst);
         }
 
-        // Discard fetch's memReq.
-        delete memReq;
-        memReq = NULL;
+        // keep an instruction count
+        numInst++;
+
 
         // 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) {
+            // Execute Checker instruction and trace
+            if (!unverifiedInst->isUnverifiable()) {
+                Trace::InstRecord *traceData = tracer->getInstRecord(curTick(),
+                                                           tc,
+                                                           curStaticInst,
+                                                           pcState(),
+                                                           curMacroStaticInst);
+                fault = curStaticInst->execute(this, traceData);
+                if (traceData) {
+                    traceData->dump();
+                    delete traceData;
+                }
+            }
 
-            thread->funcExeInst++;
-
-            if (!inst->isUnverifiable())
-                fault = curStaticInst->execute(this, NULL);
-
-            // Checks to make sure instrution results are correct.
-            validateExecution(inst);
+            if (fault == NoFault && unverifiedFault == NoFault) {
+                thread->funcExeInst++;
+                // Checks to make sure instrution results are correct.
+                validateExecution(unverifiedInst);
 
-            if (curStaticInst->isLoad()) {
-                ++numLoad;
+                if (curStaticInst->isLoad()) {
+                    ++numLoad;
+                }
+            } else if (fault != NoFault && unverifiedFault == NoFault) {
+                panic("%lli: sn: %lli at PC: %s took a fault in checker "
+                      "but not in driver CPU\n", curTick(),
+                      unverifiedInst->seqNum, unverifiedInst->pcState());
+            } else if (fault == NoFault && unverifiedFault != NoFault) {
+                panic("%lli: sn: %lli at PC: %s took a fault in driver "
+                      "CPU but not in checker\n", curTick(),
+                      unverifiedInst->seqNum, unverifiedInst->pcState());
             }
         }
 
+        // Take any faults here
         if (fault != NoFault) {
 #if FULL_SYSTEM
             fault->invoke(tc, curStaticInst);
             willChangePC = true;
-            newPC = thread->readPC();
-            DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
+            newPCState = thread->pcState();
+            DPRINTF(Checker, "Fault, PC is now %s\n", newPCState);
+            curMacroStaticInst = StaticInst::nullStaticInstPtr;
 #endif
         } else {
-#if THE_ISA != MIPS_ISA
-            // go to the next instruction
-            thread->setPC(thread->readNextPC());
-            thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
-#else
-            // go to the next instruction
-            thread->setPC(thread->readNextPC());
-            thread->setNextPC(thread->readNextNPC());
-            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
-#endif
-
+           advancePC(fault);
         }
 
 #if FULL_SYSTEM
@@ -262,14 +419,14 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         Addr oldpc;
         int count = 0;
         do {
-            oldpc = thread->readPC();
+            oldpc = thread->instAddr();
             system->pcEventQueue.service(tc);
             count++;
-        } while (oldpc != thread->readPC());
+        } while (oldpc != thread->instAddr());
         if (count > 1) {
             willChangePC = true;
-            newPC = thread->readPC();
-            DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
+            newPCState = thread->pcState();
+            DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
         }
 #endif
 
@@ -277,17 +434,13 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         // that have been modified).
         validateState();
 
-        if (memReq) {
-            delete memReq;
-            memReq = NULL;
-        }
-
         // 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();
+            unverifiedInst = NULL;
+            unverifiedInst = instList.front();
             instList.pop_front();
         } else {
             break;
@@ -296,26 +449,26 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
     unverifiedInst = NULL;
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::switchOut()
+Checker<Impl>::switchOut()
 {
     instList.clear();
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
+Checker<Impl>::takeOverFrom(BaseCPU *oldCPU)
 {
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
+Checker<Impl>::validateInst(DynInstPtr &inst)
 {
-    if (inst->readPC() != thread->readPC()) {
-        warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
-             curTick(), inst->readPC(), thread->readPC());
+    if (inst->instAddr() != thread->instAddr()) {
+        warn("%lli: PCs do not match! Inst: %s, checker: %s",
+             curTick(), inst->pcState(), thread->pcState());
         if (changedPC) {
             warn("%lli: Changed PCs recently, may not be an error",
                  curTick());
@@ -327,51 +480,70 @@ Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
     MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
 
     if (mi != machInst) {
-        warn("%lli: Binary instructions do not match! Inst: %#x, "
+        panic("%lli: Binary instructions do not match! Inst: %#x, "
              "checker: %#x",
              curTick(), mi, machInst);
         handleError(inst);
     }
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
+Checker<Impl>::validateExecution(DynInstPtr &inst)
 {
+    uint64_t checker_val;
+    uint64_t inst_val;
+    int idx = -1;
     bool result_mismatch = false;
-    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.
-            copyResult(inst);
-        } else if (result.integer != inst->readIntResult()) {
-            result_mismatch = true;
+
+    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.
+        copyResult(inst, 0, idx);
+    } else if (inst->numDestRegs() > 0 && !result.empty()) {
+        DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n",
+                         inst->numDestRegs(), result.size());
+        for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) {
+            result.front().get(checker_val);
+            result.pop();
+            inst_val = 0;
+            inst->template popResult<uint64_t>(inst_val);
+            if (checker_val != inst_val) {
+                result_mismatch = true;
+                idx = i;
+                break;
+            }
         }
-    }
+    } // Checker CPU checks all the saved results in the dyninst passed by
+      // the cpu model being checked against the saved results present in
+      // the static inst executed in the Checker.  Sometimes the number
+      // of saved results differs between the dyninst and static inst, but
+      // this is ok and not a bug.  May be worthwhile to try and correct this.
 
     if (result_mismatch) {
         warn("%lli: Instruction results do not match! (Values may not "
              "actually be integers) Inst: %#x, checker: %#x",
-             curTick(), inst->readIntResult(), result.integer);
+             curTick(), inst_val, checker_val);
 
         // It's useful to verify load values from memory, but in MP
         // systems the value obtained at execute may be different than
         // the value obtained at completion.  Similarly DMA can
         // present the same problem on even UP systems.  Thus there is
         // the option to only warn on loads having a result error.
+        // The load/store queue in Detailed CPU can also cause problems
+        // if load/store forwarding is allowed.
         if (inst->isLoad() && warnOnlyOnLoadError) {
-            copyResult(inst);
+            copyResult(inst, inst_val, idx);
         } else {
             handleError(inst);
         }
     }
 
-    if (inst->readNextPC() != thread->readNextPC()) {
+    if (inst->nextInstAddr() != thread->nextInstAddr()) {
         warn("%lli: Instruction next PCs do not match! Inst: %#x, "
              "checker: %#x",
-             curTick(), inst->readNextPC(), thread->readNextPC());
+             curTick(), inst->nextInstAddr(), thread->nextInstAddr());
         handleError(inst);
     }
 
@@ -396,53 +568,78 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
     }
 }
 
-template <class DynInstPtr>
+
+// This function is weird, if it is called it means the Checker and
+// O3 have diverged, so panic is called for now.  It may be useful
+// to resynch states and continue if the divergence is a false positive
+template <class Impl>
 void
-Checker<DynInstPtr>::validateState()
+Checker<Impl>::validateState()
 {
     if (updateThisCycle) {
-        warn("%lli: Instruction PC %#x results didn't match up, copying all "
-             "registers from main CPU", curTick(), unverifiedInst->readPC());
+        // Change this back to warn if divergences end up being false positives
+        panic("%lli: Instruction PC %#x results didn't match up, copying all "
+             "registers from main CPU", curTick(), unverifiedInst->instAddr());
+
+        // Terribly convoluted way to make sure O3 model does not implode
+        bool inSyscall = unverifiedInst->thread->inSyscall;
+        unverifiedInst->thread->inSyscall = true;
+
         // Heavy-weight copying of all registers
         thread->copyArchRegs(unverifiedInst->tcBase());
+        unverifiedInst->thread->inSyscall = inSyscall;
+
+        // Set curStaticInst to unverifiedInst->staticInst
+        curStaticInst = unverifiedInst->staticInst;
         // Also advance the PC.  Hopefully no PC-based events happened.
-#if THE_ISA != MIPS_ISA
-        // go to the next instruction
-        thread->setPC(thread->readNextPC());
-        thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
-#else
-        // go to the next instruction
-        thread->setPC(thread->readNextPC());
-        thread->setNextPC(thread->readNextNPC());
-        thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
-#endif
+        advancePC(NoFault);
         updateThisCycle = false;
     }
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
+Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
+                          int start_idx)
 {
-    RegIndex idx = inst->destRegIdx(0);
-    if (idx < TheISA::FP_Base_DepTag) {
-        thread->setIntReg(idx, inst->readIntResult());
-    } else if (idx < TheISA::Fpcr_DepTag) {
-        thread->setFloatRegBits(idx, inst->readIntResult());
-    } else {
-        thread->setMiscRegNoEffect(idx, inst->readIntResult());
+    // We've already popped one dest off the queue,
+    // so do the fix-up then start with the next dest reg;
+    if (start_idx >= 0) {
+        RegIndex idx = inst->destRegIdx(start_idx);
+        if (idx < TheISA::FP_Base_DepTag) {
+            thread->setIntReg(idx, mismatch_val);
+        } else if (idx < TheISA::Ctrl_Base_DepTag) {
+            thread->setFloatRegBits(idx, mismatch_val);
+        } else if (idx < TheISA::Max_DepTag) {
+            thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag,
+                               mismatch_val);
+        }
+    }
+    start_idx++;
+    uint64_t res = 0;
+    for (int i = start_idx; i < inst->numDestRegs(); i++) {
+        RegIndex idx = inst->destRegIdx(i);
+        inst->template popResult<uint64_t>(res);
+        if (idx < TheISA::FP_Base_DepTag) {
+            thread->setIntReg(idx, res);
+        } else if (idx < TheISA::Ctrl_Base_DepTag) {
+            thread->setFloatRegBits(idx, res);
+        } else if (idx < TheISA::Max_DepTag) {
+            // Try to get the proper misc register index for ARM here...
+            thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag, res);
+        } // else Register is out of range...
     }
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
+Checker<Impl>::dumpAndExit(DynInstPtr &inst)
 {
     cprintf("Error detected, instruction information:\n");
-    cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
+    cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
             "Completed:%i\n",
-            inst->readPC(),
-            inst->readNextPC(),
+            inst->pcState(),
+            inst->nextInstAddr(),
             inst->seqNum,
             inst->threadNumber,
             inst->isCompleted());
@@ -450,9 +647,9 @@ Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
     CheckerCPU::dumpAndExit();
 }
 
-template <class DynInstPtr>
+template <class Impl>
 void
-Checker<DynInstPtr>::dumpInsts()
+Checker<Impl>::dumpInsts()
 {
     int num = 0;
 
@@ -465,9 +662,9 @@ Checker<DynInstPtr>::dumpInsts()
         cprintf("Instruction:%i\n",
                 num);
 
-        cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+        cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n"
                 "Completed:%i\n",
-                (*inst_list_it)->readPC(),
+                (*inst_list_it)->pcState(),
                 (*inst_list_it)->seqNum,
                 (*inst_list_it)->threadNumber,
                 (*inst_list_it)->isCompleted());
index 4eb3eabfd1589823381232e72422f5b171c89f6b..d66854b23cba3e2a1527a26f5652ac745ba16025 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -36,6 +48,7 @@
 #include "cpu/checker/cpu.hh"
 #include "cpu/simple_thread.hh"
 #include "cpu/thread_context.hh"
+#include "debug/Checker.hh"
 
 class EndQuiesceEvent;
 namespace TheISA {
@@ -77,21 +90,35 @@ class CheckerThreadContext : public ThreadContext
 
     BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
 
-    void setCpuId(int id)
+    int cpuId() { return actualTC->cpuId(); }
+
+    int contextId() { return actualTC->contextId(); }
+
+    void setContextId(int id)
     {
-        actualTC->setCpuId(id);
-        checkerTC->setCpuId(id);
+       actualTC->setContextId(id);
+       checkerTC->setContextId(id);
     }
 
-    int cpuId() { return actualTC->cpuId(); }
+    /** Returns this thread's ID number. */
+    int threadId() { return actualTC->threadId(); }
+    void setThreadId(int id)
+    {
+        checkerTC->setThreadId(id);
+        actualTC->setThreadId(id);
+    }
 
     TheISA::TLB *getITBPtr() { return actualTC->getITBPtr(); }
 
     TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); }
 
-#if FULL_SYSTEM
+    BaseCPU *getCheckerCpuPtr() { return checkerTC->getCpuPtr(); }
+
+    Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
+
     System *getSystemPtr() { return actualTC->getSystemPtr(); }
 
+#if FULL_SYSTEM
     PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); }
 
     TheISA::Kernel::Statistics *getKernelStats()
@@ -101,10 +128,23 @@ class CheckerThreadContext : public ThreadContext
 
     FSTranslatingPortProxy* getVirtProxy()
     { return actualTC->getVirtProxy(); }
+
+    //XXX: How does this work now?
+    void initMemProxies(ThreadContext *tc)
+    { actualTC->initMemProxies(tc); }
+
+    void connectMemPorts(ThreadContext *tc)
+    {
+        actualTC->connectMemPorts(tc);
+    }
 #else
     SETranslatingPortProxy* getMemProxy() { return actualTC->getMemProxy(); }
 
     Process *getProcessPtr() { return actualTC->getProcessPtr(); }
+
+    /** Executes a syscall in SE mode. */
+    void syscall(int64_t callnum)
+    { return actualTC->syscall(callnum); }
 #endif
 
     Status status() const { return actualTC->status(); }
@@ -120,10 +160,10 @@ class CheckerThreadContext : public ThreadContext
     void activate(int delay = 1) { actualTC->activate(delay); }
 
     /// Set the status to Suspended.
-    void suspend() { actualTC->suspend(); }
+    void suspend(int delay) { actualTC->suspend(delay); }
 
     /// Set the status to Halted.
-    void halt() { actualTC->halt(); }
+    void halt(int delay) { actualTC->halt(delay); }
 
 #if FULL_SYSTEM
     void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
@@ -135,7 +175,11 @@ class CheckerThreadContext : public ThreadContext
         checkerTC->copyState(oldContext);
     }
 
-    void regStats(const std::string &name) { actualTC->regStats(name); }
+    void regStats(const std::string &name)
+    {
+        actualTC->regStats(name);
+        checkerTC->regStats(name);
+    }
 
     void serialize(std::ostream &os) { actualTC->serialize(os); }
     void unserialize(Checkpoint *cp, const std::string &section)
@@ -151,8 +195,6 @@ class CheckerThreadContext : public ThreadContext
     void profileSample() { return actualTC->profileSample(); }
 #endif
 
-    int threadId() { return actualTC->threadId(); }
-
     // @todo: Do I need this?
     void copyArchRegs(ThreadContext *tc)
     {
@@ -196,32 +238,36 @@ class CheckerThreadContext : public ThreadContext
         checkerTC->setFloatRegBits(reg_idx, val);
     }
 
-    uint64_t readPC() { return actualTC->readPC(); }
+    /** Reads this thread's PC state. */
+    TheISA::PCState pcState()
+    { return actualTC->pcState(); }
 
-    void setPC(uint64_t val)
+    /** Sets this thread's PC state. */
+    void pcState(const TheISA::PCState &val)
     {
-        actualTC->setPC(val);
-        checkerTC->setPC(val);
+        DPRINTF(Checker, "Changing PC to %s, old PC %s\n",
+                         val, checkerTC->pcState());
+        checkerTC->pcState(val);
         checkerCPU->recordPCChange(val);
+        return actualTC->pcState(val);
     }
 
-    uint64_t readNextPC() { return actualTC->readNextPC(); }
-
-    void setNextPC(uint64_t val)
+    void pcStateNoRecord(const TheISA::PCState &val)
     {
-        actualTC->setNextPC(val);
-        checkerTC->setNextPC(val);
-        checkerCPU->recordNextPCChange(val);
+        return actualTC->pcState(val);
     }
 
-    uint64_t readNextNPC() { return actualTC->readNextNPC(); }
+    /** Reads this thread's PC. */
+    Addr instAddr()
+    { return actualTC->instAddr(); }
 
-    void setNextNPC(uint64_t val)
-    {
-        actualTC->setNextNPC(val);
-        checkerTC->setNextNPC(val);
-        checkerCPU->recordNextPCChange(val);
-    }
+    /** Reads this thread's next PC. */
+    Addr nextInstAddr()
+    { return actualTC->nextInstAddr(); }
+
+    /** Reads this thread's next PC. */
+    MicroPC microPC()
+    { return actualTC->microPC(); }
 
     MiscReg readMiscRegNoEffect(int misc_reg)
     { return actualTC->readMiscRegNoEffect(misc_reg); }
@@ -231,22 +277,28 @@ class CheckerThreadContext : public ThreadContext
 
     void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
     {
+        DPRINTF(Checker, "Setting misc reg with no effect: %d to both Checker"
+                         " and O3..\n", misc_reg);
         checkerTC->setMiscRegNoEffect(misc_reg, val);
         actualTC->setMiscRegNoEffect(misc_reg, val);
     }
 
     void setMiscReg(int misc_reg, const MiscReg &val)
     {
+        DPRINTF(Checker, "Setting misc reg with effect: %d to both Checker"
+                         " and O3..\n", misc_reg);
         checkerTC->setMiscReg(misc_reg, val);
         actualTC->setMiscReg(misc_reg, val);
     }
 
+    int flattenIntIndex(int reg) { return actualTC->flattenIntIndex(reg); }
+    int flattenFloatIndex(int reg) { return actualTC->flattenFloatIndex(reg); }
+
     unsigned readStCondFailures()
     { return actualTC->readStCondFailures(); }
 
     void setStCondFailures(unsigned sc_failures)
     {
-        checkerTC->setStCondFailures(sc_failures);
         actualTC->setStCondFailures(sc_failures);
     }
 
diff --git a/src/cpu/dummy_checker_builder.cc b/src/cpu/dummy_checker_builder.cc
new file mode 100644 (file)
index 0000000..28f0609
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Geoffrey Blake
+ */
+
+#include <string>
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/inst_seq.hh"
+#include "params/DummyChecker.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+class MemObject;
+
+/**
+ * Specific non-templated derived class used for SimObject configuration.
+ */
+class DummyChecker : public CheckerCPU
+{
+  public:
+    DummyChecker(Params *p)
+          : CheckerCPU(p)
+    { }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+//  DummyChecker Simulation Object
+//
+DummyChecker *
+DummyCheckerParams::create()
+{
+    DummyChecker::Params *params = new DummyChecker::Params();
+    params->name = name;
+    params->numThreads = numThreads;
+    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->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;
+    Tick temp2 = progress_interval;
+    params->progress_interval = 0;
+    temp2++;
+
+    params->itb = itb;
+    params->dtb = dtb;
+    params->system = system;
+    params->cpu_id = cpu_id;
+#if FULL_SYSTEM
+    params->profile = profile;
+    params->interrupts = NULL;
+#else
+    params->workload = workload;
+#endif
+
+    DummyChecker *cpu = new DummyChecker(params);
+    return cpu;
+}
index 6f721a11bbfa5b894f5077f5932d47232360ccaa..edce7d8c791446c3f2682432a0bba13ca2617a03 100644 (file)
@@ -41,14 +41,20 @@ class DerivO3CPU(BaseCPU):
 
     if buildEnv['USE_CHECKER']:
         if not buildEnv['FULL_SYSTEM']:
-            checker = Param.BaseCPU(O3Checker(workload=Parent.workload,
+            # FIXME: Shouldn't need to derefernce Parent.workload
+            #        Somewhere in the param parsing code
+            #        src/python/m5/params.py is and error that
+            #        has trouble converting the workload parameter properly.
+            checker = Param.BaseCPU(O3Checker(workload=Parent.workload[0],
                                               exitOnError=False,
                                               updateOnError=True,
-                                              warnOnlyOnLoadError=False),
-                                    "checker")
+                                              warnOnlyOnLoadError=True),
+                                              "checker")
         else:
-            checker = Param.BaseCPU(O3Checker(exitOnError=False, updateOnError=True,
-                                              warnOnlyOnLoadError=False), "checker")
+            checker = Param.BaseCPU(O3Checker(exitOnError=False,
+                                              updateOnError=True,
+                                              warnOnlyOnLoadError=True),
+                                              "checker")
         checker.itb = Parent.itb
         checker.dtb = Parent.dtb
 
index d0c4ce537e2a7afeeb90c4ade32b9884b168e66c..d53e5e5277dc77c997dfc3b5601cb519be19f11f 100644 (file)
@@ -34,7 +34,7 @@ class O3Checker(BaseCPU):
     exitOnError = Param.Bool(False, "Exit on an error")
     updateOnError = Param.Bool(False,
         "Update the checker with the main CPU's state on an error")
-    warnOnlyOnLoadError = Param.Bool(False,
+    warnOnlyOnLoadError = Param.Bool(True,
         "If a load result is incorrect, only print a warning and do not exit")
     function_trace = Param.Bool(False, "Enable function trace")
     function_trace_start = Param.Tick(0, "Cycle to start function trace")
index 5d0bd2ed28e0c654a11f9634fa0c670ed0141dea..73e8b516226dc231f54ed8c829a2af367f1f8704 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -31,8 +43,8 @@
 #include <string>
 
 #include "cpu/checker/cpu_impl.hh"
-#include "cpu/o3/alpha/dyn_inst.hh"
-#include "cpu/o3/alpha/impl.hh"
+#include "cpu/o3/dyn_inst.hh"
+#include "cpu/o3/impl.hh"
 #include "cpu/inst_seq.hh"
 #include "params/O3Checker.hh"
 #include "sim/process.hh"
 class MemObject;
 
 template
-class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;
+class Checker<O3CPUImpl>;
 
 /**
  * Specific non-templated derived class used for SimObject configuration.
  */
-class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >
+class O3Checker : public Checker<O3CPUImpl>
 {
   public:
     O3Checker(Params *p)
-        : Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p)
+          : Checker<O3CPUImpl>(p)
     { }
 };
 
@@ -63,7 +75,7 @@ O3CheckerParams::create()
 {
     O3Checker::Params *params = new O3Checker::Params();
     params->name = name;
-    params->numberOfThreads = 1;
+    params->numThreads = numThreads;
     params->max_insts_any_thread = 0;
     params->max_insts_all_threads = 0;
     params->max_loads_any_thread = 0;
@@ -71,10 +83,8 @@ O3CheckerParams::create()
     params->exitOnError = exitOnError;
     params->updateOnError = updateOnError;
     params->warnOnlyOnLoadError = warnOnlyOnLoadError;
-    params->deferRegistration = defer_registration;
-    params->functionTrace = function_trace;
-    params->functionTraceStart = function_trace_start;
     params->clock = clock;
+    params->tracer = tracer;
     // Hack to touch all parameters.  Consider not deriving Checker
     // from BaseCPU..it's not really a CPU in the end.
     Counter temp;
@@ -92,8 +102,9 @@ O3CheckerParams::create()
     params->cpu_id = cpu_id;
 #if FULL_SYSTEM
     params->profile = profile;
+    params->interrupts = NULL;
 #else
-    params->process = workload;
+    params->workload = workload;
 #endif
 
     O3Checker *cpu = new O3Checker(params);
index 9ff31a6229433303de6d0445255d2054d2b31d8a..cb2f9a634dbb4be75e802e0ad694af8a238a7f02 100644 (file)
@@ -728,6 +728,12 @@ DefaultCommit<Impl>::handleInterrupt()
         assert(!thread[0]->inSyscall);
         thread[0]->inSyscall = true;
 
+#if USE_CHECKER
+        if (cpu->checker) {
+            cpu->checker->handlePendingInt();
+        }
+#endif
+
         // CPU will handle interrupt.
         cpu->processInterrupts(interrupt);
 
@@ -775,7 +781,8 @@ DefaultCommit<Impl>::commit()
 {
 
 #if FULL_SYSTEM
-    // Check for any interrupt that we've already squashed for and start processing it.
+    // Check for any interrupt that we've already squashed for and
+    // start processing it.
     if (interrupt != NoFault)
         handleInterrupt();
 
@@ -1133,7 +1140,8 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
         head_inst->setCompleted();
 
 #if USE_CHECKER
-        if (cpu->checker && head_inst->isStore()) {
+        if (cpu->checker) {
+            // Need to check the instruction before its fault is processed
             cpu->checker->verify(head_inst);
         }
 #endif
index 7e0b4cee7bd8c779ccc8ddc45dd9fb9d90b4a77e..49843ee9b76555af3137c55ea30dcdede27ae467 100644 (file)
@@ -68,6 +68,7 @@
 
 #if USE_CHECKER
 #include "cpu/checker/cpu.hh"
+#include "cpu/checker/thread_context.hh"
 #endif
 
 #if THE_ISA == ALPHA_ISA
@@ -268,7 +269,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
 #if USE_CHECKER
     if (params->checker) {
         BaseCPU *temp_checker = params->checker;
-        checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
+        checker = dynamic_cast<Checker<Impl> *>(temp_checker);
         checker->setIcachePort(&icachePort);
 #if FULL_SYSTEM
         checker->setSystem(params->system);
index 121253475603600dbed65d6961183e13e80b6470..a874b1e9f02cccc28f3e19439a7e57eefae74b4f 100644 (file)
@@ -732,7 +732,7 @@ class FullO3CPU : public BaseO3CPU
      * instruction results at run time.  This can be set to NULL if it
      * is not being used.
      */
-    Checker<DynInstPtr> *checker;
+    Checker<Impl> *checker;
 #endif
 
     /** Pointer to the system. */
index 500d63de88ba0d547301a34062ebdb3e2c928044..8a01b2575bf0500a814b0905cd0797cc07422899 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -41,6 +41,7 @@
  */
 
 #include "base/cp_annotate.hh"
+#include "config/use_checker.hh"
 #include "cpu/o3/dyn_inst.hh"
 
 template <class Impl>
@@ -136,6 +137,11 @@ BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt)
     bool in_syscall = this->thread->inSyscall;
     this->thread->inSyscall = true;
 
+#if USE_CHECKER
+    if (this->isStoreConditional()) {
+       this->reqToVerify->setExtraData(pkt->req->getExtraData());
+    }
+#endif
     this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
 
     this->thread->inSyscall = in_syscall;
index d145fb09904f40bdc385dabff51d96c78a46264f..463509cf178cc599ff5385a256aa0773471d21b6 100644 (file)
@@ -43,6 +43,9 @@
 
 #include <algorithm>
 #include <cstring>
+#include <list>
+#include <map>
+#include <queue>
 
 #include "arch/isa_traits.hh"
 #include "arch/utility.hh"
@@ -50,7 +53,6 @@
 #include "config/the_isa.hh"
 #include "config/use_checker.hh"
 #include "cpu/base.hh"
-#include "cpu/checker/cpu.hh"
 #include "cpu/o3/fetch.hh"
 #include "cpu/exetrace.hh"
 #include "debug/Activity.hh"
 #include "sim/system.hh"
 #endif // FULL_SYSTEM
 
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif // USE_CHECKER
+
 using namespace std;
 
 template<class Impl>
index 92c8875e4fa4dc3d5de95934b39a54bec0d15a98..698dd15c4ffce87330d366cead64799e5728a8c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -48,6 +48,7 @@
 
 #include "arch/utility.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/o3/fu_pool.hh"
 #include "cpu/o3/iew.hh"
 #include "cpu/timebuf.hh"
 #include "debug/IEW.hh"
 #include "params/DerivO3CPU.hh"
 
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif // USE_CHECKER
+
 using namespace std;
 
 template<class Impl>
@@ -294,6 +299,13 @@ DefaultIEW<Impl>::initStage()
             ldstQueue.numFreeEntries(tid);
     }
 
+// Initialize the checker's dcache port here
+#if USE_CHECKER
+    if (cpu->checker) {
+        cpu->checker->setDcachePort(cpu->getDcachePort());
+     }
+#endif
+
     cpu->activateStage(O3CPU::IEWIdx);
 }
 
index d0db6f6fe7a511077b7e6915a0728eba5d8f8b7c..facd88597af3170954c6f569f7a76727ed18f341 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -45,7 +45,6 @@
 #include "arch/locked_mem.hh"
 #include "base/str.hh"
 #include "config/the_isa.hh"
-#include "config/use_checker.hh"
 #include "cpu/o3/lsq.hh"
 #include "cpu/o3/lsq_unit.hh"
 #include "debug/Activity.hh"
@@ -246,12 +245,6 @@ void
 LSQUnit<Impl>::setDcachePort(Port *dcache_port)
 {
     dcachePort = dcache_port;
-
-#if USE_CHECKER
-    if (cpu->checker) {
-        cpu->checker->setDcachePort(dcachePort);
-    }
-#endif
 }
 
 template<class Impl>
@@ -878,6 +871,11 @@ LSQUnit<Impl>::writebackStores()
                         inst->seqNum);
                 WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
                 cpu->schedule(wb, curTick() + 1);
+#if USE_CHECKER
+                // Make sure to set the LLSC data for verification
+                inst->reqToVerify->setExtraData(0);
+                inst->completeAcc(data_pkt);
+#endif
                 completeStore(storeWBIdx);
                 incrStIdx(storeWBIdx);
                 continue;
index 0205c63efdacb4531a44554fb3b486e64f84583d..23f3830d37aac32876eb4fd9e08a1d8c9643b66c 100755 (executable)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2004-2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -32,6 +44,7 @@
 #define __CPU_O3_THREAD_CONTEXT_HH__
 
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/o3/isa_specific.hh"
 #include "cpu/thread_context.hh"
 
@@ -71,6 +84,10 @@ class O3ThreadContext : public ThreadContext
     /** Returns a pointer to the DTB. */
     TheISA::TLB *getDTBPtr() { return cpu->dtb; }
 
+#if USE_CHECKER
+    BaseCPU *getCheckerCpuPtr() { return NULL; }
+#endif
+
     Decoder *getDecoderPtr() { return &cpu->fetch.decoder; }
 
     /** Returns a pointer to this CPU. */
@@ -181,6 +198,10 @@ class O3ThreadContext : public ThreadContext
     /** Sets this thread's PC state. */
     virtual void pcState(const TheISA::PCState &val);
 
+#if USE_CHECKER
+    virtual void pcStateNoRecord(const TheISA::PCState &val);
+#endif
+
     /** Reads this thread's PC. */
     virtual Addr instAddr()
     { return cpu->instAddr(thread->threadId()); }
index 4c2fee22d57a0fa45ec028fbfaeb4cb42bbdf2a3..5a412c1618267e4c608507c3604ab625bd79f608 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -43,6 +43,7 @@
 
 #include "arch/registers.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/o3/thread_context.hh"
 #include "cpu/quiesce_event.hh"
 #include "debug/O3CPU.hh"
@@ -323,6 +324,20 @@ O3ThreadContext<Impl>::pcState(const TheISA::PCState &val)
     }
 }
 
+#if USE_CHECKER
+template <class Impl>
+void
+O3ThreadContext<Impl>::pcStateNoRecord(const TheISA::PCState &val)
+{
+    cpu->pcState(val, thread->threadId());
+
+    // Squash if we're not already in a state update mode.
+    if (!thread->trapPending && !thread->inSyscall) {
+        cpu->squashFromTC(thread->threadId());
+    }
+}
+#endif
+
 template <class Impl>
 int
 O3ThreadContext<Impl>::flattenIntIndex(int reg)
index 9f528bc20c891cbef335c51876211099126b2ba7..ea2c642e644597557d4c3321ead89d4c231d24cd 100644 (file)
 #
 # Authors: Gabe Black
 
+from m5.defines import buildEnv
 from m5.params import *
 from BaseCPU import BaseCPU
 
+if buildEnv['USE_CHECKER']:
+    from DummyChecker import DummyChecker
+
 class BaseSimpleCPU(BaseCPU):
     type = 'BaseSimpleCPU'
     abstract = True
+
+    if buildEnv['USE_CHECKER']:
+        checker = Param.BaseCPU(DummyChecker(), "checker")
+        checker.itb = BaseCPU.itb
+        checker.dtb = BaseCPU.dtb
index 70e2c39e65d213a607d6aa8853daaae6da59768a..2ec9e661f347bad52e9ced08f2946ae000ec5716 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -52,6 +52,7 @@
 #include "base/trace.hh"
 #include "base/types.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/simple/base.hh"
 #include "cpu/base.hh"
 #include "cpu/exetrace.hh"
 #include "mem/mem_object.hh"
 #endif // FULL_SYSTEM
 
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#include "cpu/checker/thread_context.hh"
+#endif
+
 using namespace std;
 using namespace TheISA;
 
@@ -99,6 +105,21 @@ BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
 
     tc = thread->getTC();
 
+#if USE_CHECKER
+    if (p->checker) {
+        BaseCPU *temp_checker = p->checker;
+        checker = dynamic_cast<CheckerCPU *>(temp_checker);
+#if FULL_SYSTEM
+        checker->setSystem(p->system);
+#endif
+        // Manipulate thread context
+        ThreadContext *cpu_tc = tc;
+        tc = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker);
+    } else {
+        checker = NULL;
+    }
+#endif
+
     numInst = 0;
     startNumInst = 0;
     numLoad = 0;
index ad281aa2b88b45ee7a91246fd0d021b48b677383..56e5e560894ad51ca44521e23c3846eeaad5d6a9 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2002-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -37,6 +49,7 @@
 #include "base/statistics.hh"
 #include "config/full_system.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/base.hh"
 #include "cpu/decode.hh"
 #include "cpu/pc_event.hh"
 #include "sim/eventq.hh"
 #include "sim/system.hh"
 
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
 // forward declarations
 #if FULL_SYSTEM
 class Processor;
@@ -120,6 +137,10 @@ class BaseSimpleCPU : public BaseCPU
      * objects to modify this thread's state.
      */
     ThreadContext *tc;
+
+#if USE_CHECKER
+    CheckerCPU *checker;
+#endif
   protected:
 
     enum Status {
index 57e83b4d133b14e8accf5e9b7f11da1391777e0c..b8dae5d01b939db354b320ba961859f1e57695ae 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2001-2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -40,6 +52,7 @@
 #include "base/types.hh"
 #include "config/full_system.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/decode.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/thread_state.hh"
@@ -200,6 +213,10 @@ class SimpleThread : public ThreadState
 
     TheISA::TLB *getDTBPtr() { return dtb; }
 
+#if USE_CHECKER
+    BaseCPU *getCheckerCpuPtr() { return NULL; }
+#endif
+
     Decoder *getDecoderPtr() { return &decoder; }
 
     System *getSystemPtr() { return system; }
@@ -295,7 +312,10 @@ class SimpleThread : public ThreadState
     {
         int flatIndex = isa.flattenFloatIndex(reg_idx);
         assert(flatIndex < TheISA::NumFloatRegs);
-        floatRegs.i[flatIndex] = val;
+        // XXX: Fix array out of bounds compiler error for gem5.fast
+        // when checkercpu enabled
+        if (flatIndex < TheISA::NumFloatRegs)
+            floatRegs.i[flatIndex] = val;
         DPRINTF(FloatRegs, "Setting float reg %d (%d) bits to %#x, %#f.\n",
                 reg_idx, flatIndex, val, floatRegs.f[flatIndex]);
     }
@@ -312,6 +332,14 @@ class SimpleThread : public ThreadState
         _pcState = val;
     }
 
+#if USE_CHECKER
+    void
+    pcStateNoRecord(const TheISA::PCState &val)
+    {
+        _pcState = val;
+    }
+#endif
+
     Addr
     instAddr()
     {
index d80d26e3d341d8b9d79a5e13ce86fc6fafa25923..946c35249426f77951bebd149f12d1523c6eecf6 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -39,6 +51,7 @@
 #include "base/types.hh"
 #include "config/full_system.hh"
 #include "config/the_isa.hh"
+#include "config/use_checker.hh"
 
 // @todo: Figure out a more architecture independent way to obtain the ITB and
 // DTB pointers.
@@ -121,6 +134,10 @@ class ThreadContext
 
     virtual TheISA::TLB *getDTBPtr() = 0;
 
+#if USE_CHECKER
+    virtual BaseCPU *getCheckerCpuPtr() = 0;
+#endif
+
     virtual Decoder *getDecoderPtr() = 0;
 
     virtual System *getSystemPtr() = 0;
@@ -205,6 +222,10 @@ class ThreadContext
 
     virtual void pcState(const TheISA::PCState &val) = 0;
 
+#if USE_CHECKER
+    virtual void pcStateNoRecord(const TheISA::PCState &val) = 0;
+#endif
+
     virtual Addr instAddr() = 0;
 
     virtual Addr nextInstAddr() = 0;
@@ -296,6 +317,10 @@ class ProxyThreadContext : public ThreadContext
 
     TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); }
 
+#if USE_CHECKER
+    BaseCPU *getCheckerCpuPtr() { return actualTC->getCheckerCpuPtr(); }
+#endif
+
     Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
 
     System *getSystemPtr() { return actualTC->getSystemPtr(); }
@@ -382,6 +407,10 @@ class ProxyThreadContext : public ThreadContext
 
     void pcState(const TheISA::PCState &val) { actualTC->pcState(val); }
 
+#if USE_CHECKER
+    void pcStateNoRecord(const TheISA::PCState &val) { actualTC->pcState(val); }
+#endif
+
     Addr instAddr() { return actualTC->instAddr(); }
     Addr nextInstAddr() { return actualTC->nextInstAddr(); }
     MicroPC microPC() { return actualTC->microPC(); }
index a20f90108e0c5367342884c7bed99ac2438a72e2..dfe4be3cc072ec5c1af56f3709ccc40a73318f1c 100644 (file)
@@ -436,7 +436,8 @@ Bus::recvFunctional(PacketPtr pkt)
         pkt->setSrc(src_id);
     }
 
-    // If the snooping hasn't found what we were looking for, keep going.
+    // If the snooping hasn't found what we were looking for and it is not
+    // a forwarded snoop from below, keep going.
     if (!pkt->isResponse() && port_id != pkt->getSrc()) {
         port->sendFunctional(pkt);
     }