diff -r 5b26772d5cc8 -r ba16e16299fb build_opts/ARM_wCHECKER_FS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_opts/ARM_wCHECKER_FS Mon Nov 28 12:03:47 2011 -0600 @@ -0,0 +1,5 @@ +TARGET_ISA = 'arm' +CPU_MODELS = 'AtomicSimpleCPU,TimingSimpleCPU,O3CPU' +FULL_SYSTEM = 1 +PROTOCOL = 'MI_example' +USE_CHECKER = 1 diff -r 5b26772d5cc8 -r ba16e16299fb build_opts/ARM_wCHECKER_SE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build_opts/ARM_wCHECKER_SE Mon Nov 28 12:03:47 2011 -0600 @@ -0,0 +1,5 @@ +TARGET_ISA = 'arm' +FULL_SYSTEM = 0 +CPU_MODELS = 'AtomicSimpleCPU,TimingSimpleCPU,O3CPU' +PROTOCOL = 'MI_example' +USE_CHECKER = 1 diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/isa.cc --- a/src/arch/arm/isa.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/isa.cc Mon Nov 28 12:03:47 2011 -0600 @@ -39,6 +39,7 @@ */ #include "arch/arm/isa.hh" +#include "config/use_checker.hh" #include "debug/Arm.hh" #include "debug/MiscRegs.hh" #include "sim/faults.hh" @@ -281,7 +282,11 @@ 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", @@ -384,6 +389,12 @@ oc = sys->getThreadContext(x); oc->getDTBPtr()->allCpusCaching(); oc->getITBPtr()->allCpusCaching(); +#if USE_CHECKER + if (oc->getCheckerCpuPtr()) { + oc->getCheckerDTBPtr()->allCpusCaching(); + oc->getCheckerITBPtr()->allCpusCaching(); + } +#endif } return; } @@ -401,6 +412,12 @@ assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushAll(); oc->getDTBPtr()->flushAll(); +#if USE_CHECKER + if (oc->getCheckerCpuPtr()) { + oc->getCheckerITBPtr()->flushAll(); + oc->getCheckerDTBPtr()->flushAll(); + } +#endif } return; case MISCREG_ITLBIALL: @@ -419,6 +436,14 @@ bits(newVal, 7,0)); oc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), bits(newVal, 7,0)); +#if USE_CHECKER + if (oc->getCheckerCpuPtr()) { + oc->getCheckerITBPtr()->flushMvaAsid(mbits(newVal, 31, 12), + bits(newVal, 7,0)); + oc->getCheckerDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), + bits(newVal, 7,0)); + } +#endif } return; case MISCREG_TLBIASIDIS: @@ -429,6 +454,12 @@ assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushAsid(bits(newVal, 7,0)); oc->getDTBPtr()->flushAsid(bits(newVal, 7,0)); +#if USE_CHECKER + if (oc->getCheckerCpuPtr()) { + oc->getCheckerITBPtr()->flushAsid(bits(newVal, 7,0)); + oc->getCheckerDTBPtr()->flushAsid(bits(newVal, 7,0)); + } +#endif } return; case MISCREG_TLBIMVAAIS: @@ -439,6 +470,12 @@ assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushMva(mbits(newVal, 31,12)); oc->getDTBPtr()->flushMva(mbits(newVal, 31,12)); +#if USE_CHECKER + if (oc->getCheckerCpuPtr()) { + oc->getCheckerITBPtr()->flushMva(mbits(newVal, 31,12)); + oc->getCheckerDTBPtr()->flushMva(mbits(newVal, 31,12)); + } +#endif } return; case MISCREG_ITLBIMVA: diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/isa/insts/m5ops.isa --- a/src/arch/arm/isa/insts/m5ops.isa Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/isa/insts/m5ops.isa Mon Nov 28 12:03:47 2011 -0600 @@ -254,7 +254,7 @@ 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) @@ -269,7 +269,7 @@ 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) diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/isa/insts/misc.isa --- a/src/arch/arm/isa/insts/misc.isa Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/isa/insts/misc.isa Mon Nov 28 12:03:47 2011 -0600 @@ -525,7 +525,7 @@ { "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 +542,7 @@ ''' 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 +565,7 @@ ''' 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) diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/table_walker.hh --- a/src/arch/arm/table_walker.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/table_walker.hh Mon Nov 28 12:03:47 2011 -0600 @@ -294,6 +294,9 @@ /** 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 @@ 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, diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/table_walker.cc --- a/src/arch/arm/table_walker.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/table_walker.cc Mon Nov 28 12:03:47 2011 -0600 @@ -107,8 +107,11 @@ 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) { + if (_timing) { + assert(!_functional); + } 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 +139,7 @@ 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 +234,21 @@ 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 +579,19 @@ 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: diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/tlb.hh --- a/src/arch/arm/tlb.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/tlb.hh Mon Nov 28 12:03:47 2011 -0600 @@ -182,6 +182,12 @@ */ 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 @@ #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); diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/tlb.cc --- a/src/arch/arm/tlb.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/tlb.cc Mon Nov 28 12:03:47 2011 -0600 @@ -49,6 +49,7 @@ #include "arch/arm/pagetable.hh" #include "arch/arm/tlb.hh" #include "arch/arm/utility.hh" +#include "arch/arm/vtophys.hh" #include "base/inifile.hh" #include "base/str.hh" #include "base/trace.hh" @@ -453,8 +454,13 @@ 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 + if (timing) { + assert(!functional); + } + if (!miscRegValid) { updateMiscReg(tc); DPRINTF(TLBVerbose, "TLB variables changed!\n"); @@ -541,7 +547,7 @@ 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 @@ -701,6 +707,20 @@ } 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) { diff -r 5b26772d5cc8 -r ba16e16299fb src/arch/arm/utility.cc --- a/src/arch/arm/utility.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/arch/arm/utility.cc Mon Nov 28 12:03:47 2011 -0600 @@ -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 @@ { TheISA::PCState newPC = tc->pcState(); newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1)); +#if USE_CHECKER + tc->pcStateNoRecord(newPC); // Need to be careful here and keep checker as independent as possible +#else tc->pcState(newPC); +#endif } void diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/BaseCPU.py --- a/src/cpu/BaseCPU.py Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/BaseCPU.py Mon Nov 28 12:03:47 2011 -0600 @@ -175,7 +175,6 @@ 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 @@ -191,6 +190,8 @@ "dtb_walker_cache.mem_side"] elif buildEnv['TARGET_ISA'] in ['x86', 'arm']: self._cached_ports += ["itb.walker.port", "dtb.walker.port"] + 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) diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/CheckerCPU.py --- a/src/cpu/CheckerCPU.py Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/CheckerCPU.py Mon Nov 28 12:03:47 2011 -0600 @@ -35,7 +35,7 @@ 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 -r 5b26772d5cc8 -r ba16e16299fb src/cpu/DummyChecker.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/DummyChecker.py Mon Nov 28 12:03:47 2011 -0600 @@ -0,0 +1,45 @@ + # Copyright (c) 2010 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) 2009 The Regents of The University of Michigan + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are + # met: redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer; + # redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution; + # neither the name of the copyright holders nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # Author: Geoffrey Blake + +from m5.params import * +from BaseCPU import BaseCPU + +class DummyChecker(BaseCPU): + type = 'DummyChecker' diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/SConscript --- a/src/cpu/SConscript Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/SConscript Mon Nov 28 12:03:47 2011 -0600 @@ -137,7 +137,9 @@ 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: diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/base.cc --- a/src/cpu/base.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/base.cc Mon Nov 28 12:03:47 2011 -0600 @@ -41,6 +41,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" @@ -207,7 +208,10 @@ } } #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) @@ -379,10 +383,20 @@ */ Port *old_itb_port, *old_dtb_port, *new_itb_port, *new_dtb_port; +#if USE_CHECKER + Port *old_checker_itb_port, *old_checker_dtb_port; + Port *new_checker_itb_port, *new_checker_dtb_port; +#endif old_itb_port = oldTC->getITBPtr()->getPort(); old_dtb_port = oldTC->getDTBPtr()->getPort(); new_itb_port = newTC->getITBPtr()->getPort(); new_dtb_port = newTC->getDTBPtr()->getPort(); +#if USE_CHECKER + old_checker_itb_port = oldTC->getCheckerITBPtr()->getPort(); + old_checker_dtb_port = oldTC->getCheckerDTBPtr()->getPort(); + new_checker_itb_port = newTC->getCheckerITBPtr()->getPort(); + new_checker_dtb_port = newTC->getCheckerDTBPtr()->getPort(); +#endif // Move over any table walker ports if they exist if (new_itb_port && !new_itb_port->isConnected()) { @@ -397,6 +411,22 @@ new_dtb_port->setPeer(peer); peer->setPeer(new_dtb_port); } +#if USE_CHECKER + // 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 diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/base_dyn_inst.hh --- a/src/cpu/base_dyn_inst.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/base_dyn_inst.hh Mon Nov 28 12:03:47 2011 -0600 @@ -48,6 +48,7 @@ #include #include #include +#include #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 @@ 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. */ @@ -252,10 +259,10 @@ double 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 instResult; /** Records changes to result? */ bool recordResult; @@ -558,20 +565,53 @@ /** Returns the logical register index of the i'th source register. */ RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } + uint64_t popIntResult() + { + uint64_t ret = 0; + if (!instResult.empty()) { + ret = instResult.front().integer; + instResult.pop(); + } + return ret; + } + + float popFloatResult() + { + float ret = 0.0; + if (!instResult.empty()) { + ret = (float)instResult.front().dbl; + instResult.pop(); + } + return ret; + } + + double popDoubleResult() + { + double ret = 0.0; + if (!instResult.empty()) { + ret = instResult.front().dbl; + instResult.pop(); + } + return ret; + } + /** Returns the result of an integer instruction. */ - uint64_t readIntResult() { return instResult.integer; } + uint64_t readIntResult() { return instResult.back().integer; } /** Returns the result of a floating point instruction. */ - float readFloatResult() { return (float)instResult.dbl; } + float readFloatResult() { return (float)instResult.back().dbl; } /** Returns the result of a floating point (double) instruction. */ - double readDoubleResult() { return instResult.dbl; } + double readDoubleResult() { return instResult.back().dbl; } /** Records an integer register being set to a value. */ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) { - if (recordResult) - instResult.integer = val; + if (recordResult) { + Result instRes; + instRes.integer = val; + instResult.push(instRes); + } } /** Records an fp register being set to a value. */ @@ -579,35 +619,49 @@ int width) { if (recordResult) { - if (width == 32) - instResult.dbl = (double)val; - else if (width == 64) - instResult.dbl = val; - else + if (width == 32) { + Result instRes; + instRes.dbl = (double)val; + instResult.push(instRes); + } else if (width == 64) { + Result instRes; + instRes.dbl = val; + instResult.push(instRes); + } 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; + if (recordResult) { + Result instRes; + instRes.dbl = (double)val; + instResult.push(instRes); + } } /** 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; + if (recordResult) { + Result instRes; + instRes.integer = val; + instResult.push(instRes); + } } /** 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; + if (recordResult) { + Result instRes; + instRes.integer = val; + instResult.push(instRes); + } } /** Records that one of the source registers is ready. */ @@ -872,6 +926,9 @@ effAddr = req->getVaddr(); effSize = size; effAddrValid = true; +#if USE_CHECKER + 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 +984,9 @@ effAddr = req->getVaddr(); effSize = size; effAddrValid = true; +#if USE_CHECKER + reqToVerify = new Request(*req); +#endif // USE_CHECKER fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx); } diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/base_dyn_inst_impl.hh --- a/src/cpu/base_dyn_inst_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/base_dyn_inst_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -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 @@ reqMade = false; readyRegs = 0; - instResult.integer = 0; recordResult = true; status.reset(); @@ -157,6 +157,10 @@ #ifdef DEBUG cpu->snList.insert(seqNum); #endif + +#if USE_CHECKER + reqToVerify = NULL; +#endif } template @@ -182,6 +186,10 @@ #ifdef DEBUG cpu->snList.erase(seqNum); #endif + +#if USE_CHECKER + if (reqToVerify) delete reqToVerify; +#endif // USE_CHECKER } #ifdef DEBUG diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/checker/cpu.hh --- a/src/cpu/checker/cpu.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/checker/cpu.hh Mon Nov 28 12:03:47 2011 -0600 @@ -35,6 +35,7 @@ #include #include +#include "arch/predecoder.hh" #include "arch/types.hh" #include "base/statistics.hh" #include "config/full_system.hh" @@ -43,6 +44,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 +64,6 @@ #endif // FULL_SYSTEM template class BaseDynInst; -class CheckerCPUParams; class ThreadContext; class MemInterface; class Checkpoint; @@ -100,7 +102,7 @@ CheckerCPU(Params *p); virtual ~CheckerCPU(); - Process *process; + std::vector workload; void setSystem(System *system); @@ -139,15 +141,18 @@ double dbl; }; - Result result; + // ISAs like ARM can have multiple destination registers to check, keep them + // all in a std::queue + std::queue 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; @@ -167,12 +172,6 @@ virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - template - Fault read(Addr addr, T &data, unsigned flags); - - template - 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"); } @@ -209,14 +208,18 @@ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) { thread->setIntReg(si->destRegIdx(idx), val); - result.integer = val; + Result res; + res.integer = val; + result.push(res); } 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; + Result res; + res.dbl = (double)val; + result.push(res); } void setFloatRegOperandBits(const StaticInst *si, int idx, @@ -224,12 +227,28 @@ { int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; thread->setFloatRegBits(reg_idx, val); - result.integer = val; + Result res; + res.integer = val; + result.push(res); } - 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 +262,6 @@ void setMiscRegNoEffect(int misc_reg, const MiscReg &val) { - result.integer = val; miscRegIdxs.push(misc_reg); return thread->setMiscRegNoEffect(misc_reg, val); } @@ -254,8 +272,25 @@ 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 +308,15 @@ 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); + ///////////////////////////////////////////////////// + #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 +329,7 @@ dumpAndExit(); } - bool checkFlags(Request *req); + bool checkFlags(Request *unverified_req, Addr vAddr, Addr pAddr, int flags); void dumpAndExit(); @@ -301,7 +342,7 @@ bool changedPC; bool willChangePC; - uint64_t newPC; + TheISA::PCState newPCState; bool changedNextPC; bool exitOnError; bool updateOnError; @@ -316,24 +357,31 @@ * template instantiations of the Checker must be placed at the bottom * of checker/cpu.cc. */ -template +template 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 handlePendingIrq(); private: void handleError(DynInstPtr &inst) @@ -350,6 +398,7 @@ bool updateThisCycle; DynInstPtr unverifiedInst; + TheISA::Predecoder predecoder; std::list instList; typedef typename std::list::iterator InstListIt; diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/checker/cpu.cc --- a/src/cpu/checker/cpu.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/checker/cpu.cc Mon Nov 28 12:03:47 2011 -0600 @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim + * Geoffrey Blake */ #include @@ -36,6 +37,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 +46,7 @@ #endif // FULL_SYSTEM using namespace std; -//The CheckerCPU does alpha only -using namespace AlphaISA; +using namespace TheISA; void CheckerCPU::init() @@ -55,6 +57,8 @@ : BaseCPU(p), thread(NULL), tc(NULL) { memReq = NULL; + curStaticInst = NULL; + curMacroStaticInst = NULL; numInst = 0; startNumInst = 0; @@ -66,19 +70,20 @@ 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() @@ -134,173 +139,200 @@ */ } -template 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; - memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); - // translate to physical address - dtb->translateAtomic(memReq, tc, false); + if (secondAddr > addr) + size = secondAddr - addr; - PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); + // 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()); - pkt->dataStatic(&data); + // translate to physical address + fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read); - 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)); + if (!checked_flags && fault == NoFault && unverifiedReq) { + flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), memReq->getPaddr(), memReq->getFlags()); + pAddr = memReq->getPaddr(); + checked_flags = true; + } + + // 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; + delete pkt; + } + + if (fault != NoFault) { + if (memReq->isPrefetch()) { + delete memReq; + return NoFault; + } else { + delete memReq; + return fault; + } + } + + //If we don't need to access a second cache line, stop now. + if (secondAddr <= addr) + { + return fault; + } + + // 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 +// XXX: Make this look more like the atomicCPU model +Fault +CheckerCPU::writeMem(uint8_t *data, unsigned size, + Addr addr, unsigned flags, uint64_t *res) +{ + Fault fault = NoFault; + bool checked_flags = false; + bool flags_match = true; + Addr pAddr = 0x0; -template -Fault -CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); + unsigned blockSize = dcachePort->peerBlockSize(); + int fullSize = size; -template -Fault -CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); + Addr secondAddr = roundDown(addr + size - 1, blockSize); -template -Fault -CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); + if (secondAddr > addr) + size = secondAddr - addr; -template -Fault -CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); + // 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()); -#endif //DOXYGEN_SHOULD_SKIP_THIS + // translate to physical address + fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write); -template<> -Fault -CheckerCPU::read(Addr addr, double &data, unsigned flags) -{ - return read(addr, *(uint64_t*)&data, flags); + if (!checked_flags && fault == NoFault && unverifiedReq) { + flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), memReq->getPaddr(), memReq->getFlags()); + pAddr = memReq->getPaddr(); + checked_flags = true; + } + + // Leaving this here in case someone devises a way to check stores + // reached memory correctly. +#if 0 + // Can't check the store in memory unless we can snoop the lds/st queue + if (fault == NoFault) { + // 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 && + // unverifiedMemData && + // !(unverifiedReq->isUncacheable()) && + // (!(unverifiedReq->isLLSC()) || + // ((unverifiedReq->isLLSC()) && + // unverifiedReq->getExtraData() == 1))) { + + /* + // This code would work if the LSQ allowed for snooping. + PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); + pkt.dataStatic(&inst_data); + + dcachePort->sendFunctional(pkt); + + delete pkt; + */ + } + } +#endif + + 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; + } + + //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. + if (unverifiedReq && unverifiedMemData && + memcmp(data,unverifiedMemData,fullSize) && + (unverifiedReq->extraDataValid() ? unverifiedReq->getExtraData() : 1)) { + warn("%lli: Store value does not match value sent to memory!\ + data: %#x inst_data: %#x", curTick(), data, unverifiedMemData); + handleError(); + } + + return fault; } -template<> -Fault -CheckerCPU::read(Addr addr, float &data, unsigned flags) -{ - return read(addr, *(uint32_t*)&data, flags); -} - -template<> -Fault -CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} - -template -Fault -CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - // 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); - - dcachePort->sendFunctional(pkt); - - delete pkt; -*/ - memcpy(&inst_data, unverifiedMemData, sizeof(T)); - - if (data != inst_data) { - warn("%lli: Store value does not match value in memory! " - "Instruction: %#x, memory: %#x", - curTick(), inst_data, data); - handleError(); - } - } - - // Assume the result was the same as the one passed in. This checker - // doesn't check if the SC should succeed or fail, it just checks the - // value. - if (res && 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); -} - -template<> -Fault -CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); -} - - #if FULL_SYSTEM Addr CheckerCPU::dbg_vtophys(Addr addr) @@ -309,24 +341,29 @@ } #endif // FULL_SYSTEM +// TODO: Eventually this should check to make sure requests +// are going to the right addresses etc in readMem and writeMem. +// Not used in Checker currently. 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!"); } diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/checker/cpu_impl.hh --- a/src/cpu/checker/cpu_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/checker/cpu_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim + * Geoffrey Blake */ #include @@ -33,11 +34,13 @@ #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" @@ -46,15 +49,78 @@ #endif // FULL_SYSTEM using namespace std; -//The CheckerCPU does alpha only -using namespace AlphaISA; +using namespace TheISA; -template +template void -Checker::verify(DynInstPtr &completed_inst) +Checker::advancePC(Fault fault) +{ + //Since we're moving to a new pc, zero out the offset + 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 +void +Checker::handlePendingIrq() +{ + 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::iterator itr; + + for (itr = instList.begin(); itr != instList.end(); itr++) { + (*itr)->setCompleted(); + } + + inst = instList.front(); + boundaryInst = instList.back(); + verify(inst); // verify the instructions + } + if (!boundaryInst && curMacroStaticInst && + curStaticInst->isDelayedCommit() && !curStaticInst->isLastMicroop()) { + panic("%lli: Trying to take an interrupt in middle of non-interuptable instruction!", + curTick()); + } else if (boundaryInst && boundaryInst->isDelayedCommit() && !boundaryInst->isLastMicroop()) { + panic("%lli: Trying to take an interrupt in middle of non-interuptable instruction!", + curTick()); + } + predecoder.reset(); + curMacroStaticInst = StaticInst::nullStaticInstPtr; +} + +template +void +Checker::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 +128,8 @@ // 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 +143,8 @@ } 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,22 +159,31 @@ } } + // 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; // 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 = unverifiedInst->reqToVerify; + unverifiedMemData = unverifiedInst->memData; + // Make sure results queue is empty + while (!result.empty()) { result.pop(); } numCycles++; Fault fault = NoFault; + Fault ckFault = NoFault; - // maintain $r0 semantics + //maintain $r0 semantics thread->setIntReg(ZeroReg, 0); #ifdef TARGET_ALPHA thread->setFloatRegDouble(ZeroReg, 0.0); @@ -118,15 +193,15 @@ // 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 +210,180 @@ } 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; -#if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 -#else -#define IFETCH_FLAGS(pc) 0 -#endif + while (!fetchDone) { + Addr fetch_PC = thread->instAddr(); + fetch_PC = (fetch_PC & PCMask) + fetchOffset; - uint64_t fetch_PC = thread->readPC() & ~3; + // 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()); - // 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); + fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute); - 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); + 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 - thread->setPC(thread->readNextPC()); - thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); + // go to the next instruction + advancePC(NoFault); - 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(); + // 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); + + pkt->dataStatic(&machInst); + icachePort->sendFunctional(pkt); + + // decode the instruction + machInst = gtoh(machInst); + delete memReq; + delete pkt; + } + } + + 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; + //if(predecoder.needMoreBytes()) + predecoder.moreBytes(pcState, fetchPC, machInst); + //else + // predecoder.process(); + + //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); + unverifiedFault = unverifiedInst->getFault(); - pkt->dataStatic(&machInst); - - 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::ExeTracerRecord *tracer = + new Trace::ExeTracerRecord(curTick(), tc, curStaticInst, + pcState(), false, NULL); + fault = curStaticInst->execute(this, tracer); + tracer->traceInst(curStaticInst, true); + delete tracer; + } - thread->funcExeInst++; + if (fault == NoFault) { + thread->funcExeInst++; + // Checks to make sure instrution results are correct. + validateExecution(unverifiedInst); - if (!inst->isUnverifiable()) - fault = curStaticInst->execute(this, NULL); - - // Checks to make sure instrution results are correct. - validateExecution(inst); - - 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 +393,14 @@ 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 +408,12 @@ // 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 = instList.front(); instList.pop_front(); } else { break; @@ -296,26 +422,26 @@ unverifiedInst = NULL; } -template +template void -Checker::switchOut() +Checker::switchOut() { instList.clear(); } -template +template void -Checker::takeOverFrom(BaseCPU *oldCPU) +Checker::takeOverFrom(BaseCPU *oldCPU) { } -template +template void -Checker::validateInst(DynInstPtr &inst) +Checker::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 +453,71 @@ MachInst mi = static_cast(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 +template void -Checker::validateExecution(DynInstPtr &inst) +Checker::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++) { + checker_val = result.front().integer; + result.pop(); + inst_val = inst->popIntResult(); + if (checker_val != inst_val) { + result_mismatch = true; + idx = i; + break; + } } - } + } // Checker CPU isn't completely exact in matching desitination registers + // for some reasons due to the vagarities of ISAs like ARM where the PC + // is sometimes a destination register and sometimes not which is hard + // to extract out and log in a general manner. So this is an approximate + // matching of register state to try and catch errors as soon as possible. + // If the state diverges then the CheckerCPU should catch it as + // errors propogate... 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 +542,79 @@ } } -template + +// 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 void -Checker::validateState() +Checker::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 +template void -Checker::copyResult(DynInstPtr &inst) +Checker::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++; + for (int i = start_idx; i < inst->numDestRegs(); i++) { + RegIndex idx = inst->destRegIdx(i); + if (idx < TheISA::FP_Base_DepTag) { + thread->setIntReg(idx, inst->popIntResult()); + } else if (idx < TheISA::Ctrl_Base_DepTag) { + thread->setFloatRegBits(idx, inst->popIntResult()); + } else if (idx < TheISA::Max_DepTag) { + // Try to get the proper misc register index for ARM here... + thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag, + inst->popIntResult()); + } else { + inst->popIntResult(); // Register is out of range... + } } } -template +template void -Checker::dumpAndExit(DynInstPtr &inst) +Checker::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 +622,9 @@ CheckerCPU::dumpAndExit(); } -template +template void -Checker::dumpInsts() +Checker::dumpInsts() { int num = 0; @@ -465,9 +637,9 @@ 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()); diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/checker/thread_context.hh --- a/src/cpu/checker/thread_context.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/checker/thread_context.hh Mon Nov 28 12:03:47 2011 -0600 @@ -36,6 +36,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 +78,37 @@ 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(); } + TheISA::TLB *getCheckerITBPtr() { return checkerTC->getITBPtr(); } + TheISA::TLB *getCheckerDTBPtr() { return checkerTC->getDTBPtr(); } + + Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); } + System *getSystemPtr() { return actualTC->getSystemPtr(); } +#if FULL_SYSTEM PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); } TheISA::Kernel::Statistics *getKernelStats() @@ -101,10 +118,19 @@ VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } + + void connectMemPorts(ThreadContext *tc) + { + actualTC->connectMemPorts(tc); + } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } 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 +146,10 @@ 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 +161,11 @@ 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 §ion) @@ -151,8 +181,6 @@ void profileSample() { return actualTC->profileSample(); } #endif - int threadId() { return actualTC->threadId(); } - // @todo: Do I need this? void copyArchRegs(ThreadContext *tc) { @@ -196,32 +224,36 @@ 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,16 +263,23 @@ 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(); } diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/dummy_checker_builder.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cpu/dummy_checker_builder.cc Mon Nov 28 12:03:47 2011 -0600 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010 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) 2009 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Geoffrey Blake + */ + +#include + +#include "cpu/checker/cpu_impl.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; +} diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/O3CPU.py --- a/src/cpu/o3/O3CPU.py Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/O3CPU.py Mon Nov 28 12:03:47 2011 -0600 @@ -41,14 +41,15 @@ if buildEnv['USE_CHECKER']: if not buildEnv['FULL_SYSTEM']: - checker = Param.BaseCPU(O3Checker(workload=Parent.workload, + # XXX This is an ugly hack to prevent python from making it a double array + 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") + warnOnlyOnLoadError=True), "checker") checker.itb = Parent.itb checker.dtb = Parent.dtb diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/O3Checker.py --- a/src/cpu/o3/O3Checker.py Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/O3Checker.py Mon Nov 28 12:03:47 2011 -0600 @@ -34,7 +34,7 @@ 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 -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/checker_builder.cc --- a/src/cpu/o3/checker_builder.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/checker_builder.cc Mon Nov 28 12:03:47 2011 -0600 @@ -31,8 +31,8 @@ #include #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" @@ -41,16 +41,16 @@ class MemObject; template -class Checker > >; +class Checker; /** * Specific non-templated derived class used for SimObject configuration. */ -class O3Checker : public Checker > > +class O3Checker : public Checker { public: O3Checker(Params *p) - : Checker > >(p) + : Checker(p) { } }; @@ -63,7 +63,7 @@ { 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,9 +71,6 @@ 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; // Hack to touch all parameters. Consider not deriving Checker // from BaseCPU..it's not really a CPU in the end. @@ -92,8 +89,9 @@ 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); diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/commit_impl.hh --- a/src/cpu/o3/commit_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/commit_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -735,6 +735,12 @@ assert(!thread[0]->inSyscall); thread[0]->inSyscall = true; +#if USE_CHECKER + if (cpu->checker) { + cpu->checker->handlePendingIrq(); + } +#endif + // CPU will handle interrupt. cpu->processInterrupts(interrupt); @@ -1143,7 +1149,8 @@ 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 diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/cpu.hh --- a/src/cpu/o3/cpu.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/cpu.hh Mon Nov 28 12:03:47 2011 -0600 @@ -656,7 +656,7 @@ * instruction results at run time. This can be set to NULL if it * is not being used. */ - Checker *checker; + Checker *checker; #endif /** Pointer to the system. */ diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/cpu.cc --- a/src/cpu/o3/cpu.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/cpu.cc Mon Nov 28 12:03:47 2011 -0600 @@ -56,6 +56,7 @@ #if USE_CHECKER #include "cpu/checker/cpu.hh" +#include "cpu/checker/thread_context.hh" #endif #if THE_ISA == ALPHA_ISA @@ -217,7 +218,7 @@ #if USE_CHECKER if (params->checker) { BaseCPU *temp_checker = params->checker; - checker = dynamic_cast *>(temp_checker); + checker = dynamic_cast *>(temp_checker); #if FULL_SYSTEM checker->setSystem(params->system); #endif diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/dyn_inst_impl.hh --- a/src/cpu/o3/dyn_inst_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/dyn_inst_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -41,6 +41,7 @@ */ #include "base/cp_annotate.hh" +#include "config/use_checker.hh" #include "cpu/o3/dyn_inst.hh" template @@ -136,6 +137,11 @@ 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; diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/fetch_impl.hh --- a/src/cpu/o3/fetch_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/fetch_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -43,6 +43,9 @@ #include #include +#include +#include +#include #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" @@ -68,6 +70,10 @@ #include "sim/system.hh" #endif // FULL_SYSTEM +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif // USE_CHECKER + using namespace std; template @@ -196,12 +202,6 @@ icachePort = new IcachePort(this); icachePort->snoopRangeSent = false; - -#if USE_CHECKER - if (cpu->checker) { - cpu->checker->setIcachePort(icachePort); - } -#endif } template @@ -392,6 +392,14 @@ stalls[tid].commit = false; } + // Setup checker's access to the Icache here as it gets + // constructed rather late in the game. +#if USE_CHECKER + if (cpu->checker) { + cpu->checker->setIcachePort(icachePort); + } +#endif + // Schedule fetch to get the correct PC from the CPU // scheduleFetchStartupEvent(1); diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/iew_impl.hh --- a/src/cpu/o3/iew_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/iew_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -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" @@ -56,6 +57,10 @@ #include "debug/IEW.hh" #include "params/DerivO3CPU.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif // USE_CHECKER + using namespace std; template @@ -294,6 +299,13 @@ ldstQueue.numFreeEntries(tid); } +// Initialize the checker's dcache port here +#if USE_CHECKER + if (cpu->checker) { + cpu->checker->setDcachePort(getDcachePort()); + } +#endif + cpu->activateStage(O3CPU::IEWIdx); } diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/lsq_unit_impl.hh --- a/src/cpu/o3/lsq_unit_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/lsq_unit_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -44,7 +44,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" @@ -244,12 +243,6 @@ LSQUnit::setDcachePort(Port *dcache_port) { dcachePort = dcache_port; - -#if USE_CHECKER - if (cpu->checker) { - cpu->checker->setDcachePort(dcachePort); - } -#endif } template @@ -870,6 +863,11 @@ 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; diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/thread_context.hh --- a/src/cpu/o3/thread_context.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/thread_context.hh Mon Nov 28 12:03:47 2011 -0600 @@ -32,6 +32,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" @@ -73,6 +74,20 @@ /** Returns a pointer to the DTB. */ TheISA::TLB *getDTBPtr() { return cpu->dtb; } +#if USE_CHECKER + BaseCPU *getCheckerCpuPtr() { return NULL; } + TheISA::TLB *getCheckerITBPtr() + { + panic("No checker connected here!\n"); + return NULL; + } + TheISA::TLB *getCheckerDTBPtr() + { + panic("No checker connected here!\n"); + return NULL; + } +#endif + Decoder *getDecoderPtr() { return &cpu->fetch.decoder; } /** Returns a pointer to this CPU. */ @@ -181,6 +196,10 @@ /** 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()); } diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/o3/thread_context_impl.hh --- a/src/cpu/o3/thread_context_impl.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/o3/thread_context_impl.hh Mon Nov 28 12:03:47 2011 -0600 @@ -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 @@ } } +#if USE_CHECKER +template +void +O3ThreadContext::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 int O3ThreadContext::flattenIntIndex(int reg) diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/simple/BaseSimpleCPU.py --- a/src/cpu/simple/BaseSimpleCPU.py Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/simple/BaseSimpleCPU.py Mon Nov 28 12:03:47 2011 -0600 @@ -26,9 +26,18 @@ # # 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 diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/simple/base.hh --- a/src/cpu/simple/base.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/simple/base.hh Mon Nov 28 12:03:47 2011 -0600 @@ -37,6 +37,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" @@ -48,6 +49,10 @@ #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 +125,10 @@ * objects to modify this thread's state. */ ThreadContext *tc; + +#if USE_CHECKER + CheckerCPU *checker; +#endif protected: enum Status { diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/simple/base.cc --- a/src/cpu/simple/base.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/simple/base.cc Mon Nov 28 12:03:47 2011 -0600 @@ -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" @@ -82,6 +83,11 @@ #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 @@ tc = thread->getTC(); +#if USE_CHECKER + if (p->checker) { + BaseCPU *temp_checker = p->checker; + checker = dynamic_cast(temp_checker); +#if FULL_SYSTEM + checker->setSystem(p->system); +#endif + // Manipulate thread context + ThreadContext *cpu_tc = tc; + tc = new CheckerThreadContext(cpu_tc, this->checker); + } else { + checker = NULL; + } +#endif + numInst = 0; startNumInst = 0; numLoad = 0; diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/simple_thread.hh --- a/src/cpu/simple_thread.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/simple_thread.hh Mon Nov 28 12:03:47 2011 -0600 @@ -40,6 +40,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" @@ -203,6 +204,14 @@ TheISA::TLB *getDTBPtr() { return dtb; } +#if USE_CHECKER + BaseCPU *getCheckerCpuPtr() { return NULL; } + TheISA::TLB *getCheckerITBPtr() { panic("No Checker connected here!\n"); +return NULL; } + TheISA::TLB *getCheckerDTBPtr() { panic("No Checker connected here!\n"); +return NULL; } +#endif + Decoder *getDecoderPtr() { return &decoder; } System *getSystemPtr() { return system; } @@ -298,7 +307,10 @@ { 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]); } @@ -315,6 +327,14 @@ _pcState = val; } +#if USE_CHECKER + void + pcStateNoRecord(const TheISA::PCState &val) + { + _pcState = val; + } +#endif + Addr instAddr() { diff -r 5b26772d5cc8 -r ba16e16299fb src/cpu/thread_context.hh --- a/src/cpu/thread_context.hh Mon Nov 28 11:07:17 2011 -0600 +++ b/src/cpu/thread_context.hh Mon Nov 28 12:03:47 2011 -0600 @@ -39,6 +39,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 +122,12 @@ virtual TheISA::TLB *getDTBPtr() = 0; +#if USE_CHECKER + virtual BaseCPU *getCheckerCpuPtr() = 0; + virtual TheISA::TLB *getCheckerITBPtr() = 0; + virtual TheISA::TLB *getCheckerDTBPtr() = 0; +#endif + virtual Decoder *getDecoderPtr() = 0; virtual System *getSystemPtr() = 0; @@ -199,6 +206,10 @@ 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; @@ -290,6 +301,13 @@ TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); } +#if USE_CHECKER + BaseCPU *getCheckerCpuPtr() { return actualTC->getCheckerCpuPtr(); } + TheISA::TLB *getCheckerITBPtr() { return actualTC->getCheckerITBPtr(); } + + TheISA::TLB *getCheckerDTBPtr() { return actualTC->getCheckerDTBPtr(); } +#endif + Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); } System *getSystemPtr() { return actualTC->getSystemPtr(); } @@ -376,6 +394,10 @@ 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(); } diff -r 5b26772d5cc8 -r ba16e16299fb src/mem/bus.cc --- a/src/mem/bus.cc Mon Nov 28 11:07:17 2011 -0600 +++ b/src/mem/bus.cc Mon Nov 28 12:03:47 2011 -0600 @@ -477,7 +477,8 @@ } // If the snooping hasn't found what we were looking for, keep going. - if (!pkt->isResponse() && port_id != pkt->getSrc()) { + // If our destination is the default port, stop looking. + if (!pkt->isResponse() && port_id != pkt->getSrc() && port_id != defaultId) { port->sendFunctional(pkt); } }