CheckerCPU: Re-factor CheckerCPU to be compatible with current gem5

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.
This commit is contained in:
Geoffrey Blake 2012-01-31 07:46:03 -08:00
parent ade53def92
commit af6aaf2581
38 changed files with 1347 additions and 475 deletions

View 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
@ -39,12 +39,17 @@
*/
#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:

View 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)

View 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)

View 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:

View 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,

View 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)

View 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);

View 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

View 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)

View 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")

42
src/cpu/DummyChecker.py Normal file
View file

@ -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'

View 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:

View 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"
@ -64,6 +65,10 @@
#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

View 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);
}

View 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

View 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,191 +132,193 @@ 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;
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));
}
delete pkt;
return NoFault;
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
Fault
CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
template
Fault
CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
template
Fault
CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
template
Fault
CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
#endif //DOXYGEN_SHOULD_SKIP_THIS
template<>
Fault
CheckerCPU::read(Addr addr, double &data, unsigned flags)
{
return read(addr, *(uint64_t*)&data, flags);
}
template<>
Fault
CheckerCPU::read(Addr addr, float &data, unsigned flags)
{
return read(addr, *(uint32_t*)&data, flags);
}
template<>
Fault
CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
{
return read(addr, (uint32_t&)data, flags);
}
template <class T>
Fault
CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
// 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();
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;
memReq = NULL;
delete pkt;
}
if (fault != NoFault) {
if (memReq->isPrefetch()) {
fault = NoFault;
}
delete memReq;
memReq = NULL;
break;
}
if (memReq != NULL) {
delete memReq;
}
//If we don't need to access a second cache line, stop now.
if (secondAddr <= addr)
{
break;
}
// Setup for accessing next cache line
data += size;
unverifiedMemData += size;
size = addr + fullSize - secondAddr;
addr = secondAddr;
}
// 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();
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::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)
CheckerCPU::writeMem(uint8_t *data, unsigned size,
Addr addr, unsigned flags, uint64_t *res)
{
return write(*(uint64_t*)&data, addr, flags, res);
}
Fault fault = NoFault;
bool checked_flags = false;
bool flags_match = true;
Addr pAddr = 0x0;
template<>
Fault
CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
{
return write(*(uint32_t*)&data, addr, flags, res);
}
unsigned blockSize = dcachePort->peerBlockSize();
int fullSize = size;
template<>
Fault
CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
{
return write((uint32_t)data, addr, flags, res);
}
Addr secondAddr = roundDown(addr + size - 1, blockSize);
if (secondAddr > addr)
size = secondAddr - addr;
// 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());
// translate to physical address
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
if (!checked_flags && fault == NoFault && unverifiedReq) {
flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
memReq->getPaddr(), memReq->getFlags());
pAddr = memReq->getPaddr();
checked_flags = true;
}
/*
* 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;
}
//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
@ -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!");
}

View 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;

View 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>
@ -33,11 +46,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 +61,81 @@
#endif // FULL_SYSTEM
using namespace std;
//The CheckerCPU does alpha only
using namespace AlphaISA;
using namespace TheISA;
template <class DynInstPtr>
template <class Impl>
void
Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
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();
}
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<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;
#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);
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;
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);
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::InstRecord *traceData = tracer->getInstRecord(curTick(),
tc,
curStaticInst,
pcState(),
curMacroStaticInst);
fault = curStaticInst->execute(this, traceData);
if (traceData) {
traceData->dump();
delete traceData;
}
}
thread->funcExeInst++;
if (fault == NoFault && unverifiedFault == 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 +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());

View 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);
}

View file

@ -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;
}

View 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

View 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")

View 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"
@ -41,16 +53,16 @@
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);

View 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

View 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);

View 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. */

View 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;

View 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"
@ -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<class Impl>

View 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"
@ -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<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);
}

View 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;

View 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) 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()); }

View 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
@ -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)

View file

@ -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

View 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"
@ -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 @@ 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;

View 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"
@ -48,6 +61,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 +137,10 @@ class BaseSimpleCPU : public BaseCPU
* objects to modify this thread's state.
*/
ThreadContext *tc;
#if USE_CHECKER
CheckerCPU *checker;
#endif
protected:
enum Status {

View 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()
{

View 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(); }

View 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);
}