Checker updates.

src/cpu/checker/cpu.cc:
src/cpu/checker/cpu.hh:
    Updates for checker.  Output more informative messages on error.  Rename some functions.  Add in option to warn (and not exit) on load results being incorrect.
src/cpu/checker/cpu_builder.cc:
src/cpu/checker/o3_cpu_builder.cc:
    Add in parameter to warn (and not exit) on load result errors.
src/cpu/o3/commit_impl.hh:
src/cpu/o3/lsq_unit_impl.hh:
    Renamed checker functin.

--HG--
extra : convert_revision : d7aa28b8462691d20600f97a7213e2acd91c5665
This commit is contained in:
Kevin Lim 2006-06-16 13:10:47 -04:00
parent 5d11e8bff6
commit 720e6c4145
6 changed files with 96 additions and 25 deletions

View file

@ -78,6 +78,7 @@ CheckerCPU::CheckerCPU(Params *p)
changedPC = willChangePC = changedNextPC = false; changedPC = willChangePC = changedNextPC = false;
exitOnError = p->exitOnError; exitOnError = p->exitOnError;
warnOnlyOnLoadError = p->warnOnlyOnLoadError;
#if FULL_SYSTEM #if FULL_SYSTEM
itb = p->itb; itb = p->itb;
dtb = p->dtb; dtb = p->dtb;
@ -409,9 +410,17 @@ CheckerCPU::checkFlags(Request *req)
} }
} }
void
CheckerCPU::dumpAndExit()
{
warn("%lli: Checker PC:%#x, next PC:%#x",
curTick, thread->readPC(), thread->readNextPC());
panic("Checker found an error!");
}
template <class DynInstPtr> template <class DynInstPtr>
void void
Checker<DynInstPtr>::tick(DynInstPtr &completed_inst) Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
{ {
DynInstPtr inst; DynInstPtr inst;
@ -485,7 +494,7 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
warn("%lli: Changed PC does not match expected PC, " warn("%lli: Changed PC does not match expected PC, "
"changed: %#x, expected: %#x", "changed: %#x, expected: %#x",
curTick, thread->readPC(), newPC); curTick, thread->readPC(), newPC);
handleError(); CheckerCPU::handleError();
} }
willChangePC = false; willChangePC = false;
} }
@ -524,7 +533,7 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
// possible that its ITB entry was kicked out. // possible that its ITB entry was kicked out.
warn("%lli: Instruction PC %#x was not found in the ITB!", warn("%lli: Instruction PC %#x was not found in the ITB!",
curTick, thread->readPC()); curTick, thread->readPC());
handleError(); handleError(inst);
// go to the next instruction // go to the next instruction
thread->setPC(thread->readNextPC()); thread->setPC(thread->readNextPC());
@ -676,7 +685,7 @@ Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
warn("%lli: Changed PCs recently, may not be an error", warn("%lli: Changed PCs recently, may not be an error",
curTick); curTick);
} else { } else {
handleError(); handleError(inst);
} }
} }
@ -686,7 +695,7 @@ Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
warn("%lli: Binary instructions do not match! Inst: %#x, " warn("%lli: Binary instructions do not match! Inst: %#x, "
"checker: %#x", "checker: %#x",
curTick, mi, machInst); curTick, mi, machInst);
handleError(); handleError(inst);
} }
} }
@ -694,25 +703,33 @@ template <class DynInstPtr>
void void
Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
{ {
bool result_mismatch = false;
if (inst->numDestRegs()) { if (inst->numDestRegs()) {
// @todo: Support more destination registers. // @todo: Support more destination registers.
if (inst->isUnverifiable()) { if (inst->isUnverifiable()) {
// Unverifiable instructions assume they were executed // Unverifiable instructions assume they were executed
// properly by the CPU. Grab the result from the // properly by the CPU. Grab the result from the
// instruction and write it to the register. // instruction and write it to the register.
RegIndex idx = inst->destRegIdx(0); copyResult(inst);
if (idx < TheISA::FP_Base_DepTag) {
thread->setIntReg(idx, inst->readIntResult());
} else if (idx < TheISA::Fpcr_DepTag) {
thread->setFloatRegBits(idx, inst->readIntResult());
} else {
thread->setMiscReg(idx, inst->readIntResult());
}
} else if (result.integer != inst->readIntResult()) { } else if (result.integer != inst->readIntResult()) {
result_mismatch = true;
}
}
if (result_mismatch) {
warn("%lli: Instruction results do not match! (Values may not " warn("%lli: Instruction results do not match! (Values may not "
"actually be integers) Inst: %#x, checker: %#x", "actually be integers) Inst: %#x, checker: %#x",
curTick, inst->readIntResult(), result.integer); curTick, inst->readIntResult(), result.integer);
handleError();
// 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.
if (inst->isLoad() && warnOnlyOnLoadError) {
copyResult(inst);
} else {
handleError(inst);
} }
} }
@ -720,7 +737,7 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
warn("%lli: Instruction next PCs do not match! Inst: %#x, " warn("%lli: Instruction next PCs do not match! Inst: %#x, "
"checker: %#x", "checker: %#x",
curTick, inst->readNextPC(), thread->readNextPC()); curTick, inst->readNextPC(), thread->readNextPC());
handleError(); handleError(inst);
} }
// Checking side effect registers can be difficult if they are not // Checking side effect registers can be difficult if they are not
@ -739,7 +756,7 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
curTick, misc_reg_idx, curTick, misc_reg_idx,
inst->tcBase()->readMiscReg(misc_reg_idx), inst->tcBase()->readMiscReg(misc_reg_idx),
thread->readMiscReg(misc_reg_idx)); thread->readMiscReg(misc_reg_idx));
handleError(); handleError(inst);
} }
} }
} }
@ -750,6 +767,36 @@ Checker<DynInstPtr>::validateState()
{ {
} }
template <class DynInstPtr>
void
Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
{
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->setMiscReg(idx, inst->readIntResult());
}
}
template <class DynInstPtr>
void
Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
{
cprintf("Error detected, instruction information:\n");
cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
"Completed:%i\n",
inst->readPC(),
inst->readNextPC(),
inst->seqNum,
inst->threadNumber,
inst->isCompleted());
inst->dump();
CheckerCPU::dumpAndExit();
}
template <class DynInstPtr> template <class DynInstPtr>
void void
Checker<DynInstPtr>::dumpInsts() Checker<DynInstPtr>::dumpInsts()

View file

@ -103,6 +103,7 @@ class CheckerCPU : public BaseCPU
Process *process; Process *process;
#endif #endif
bool exitOnError; bool exitOnError;
bool warnOnlyOnLoadError;
}; };
public: public:
@ -335,10 +336,13 @@ class CheckerCPU : public BaseCPU
void handleError() void handleError()
{ {
if (exitOnError) if (exitOnError)
panic("Checker found error!"); dumpAndExit();
} }
bool checkFlags(Request *req); bool checkFlags(Request *req);
void dumpAndExit();
ThreadContext *tcBase() { return tc; } ThreadContext *tcBase() { return tc; }
SimpleThread *threadBase() { return thread; } SimpleThread *threadBase() { return thread; }
@ -351,6 +355,7 @@ class CheckerCPU : public BaseCPU
uint64_t newPC; uint64_t newPC;
bool changedNextPC; bool changedNextPC;
bool exitOnError; bool exitOnError;
bool warnOnlyOnLoadError;
InstSeqNum youngestSN; InstSeqNum youngestSN;
}; };
@ -372,12 +377,23 @@ class Checker : public CheckerCPU
void switchOut(Sampler *s); void switchOut(Sampler *s);
void takeOverFrom(BaseCPU *oldCPU); void takeOverFrom(BaseCPU *oldCPU);
void tick(DynInstPtr &inst); void verify(DynInstPtr &inst);
void validateInst(DynInstPtr &inst); void validateInst(DynInstPtr &inst);
void validateExecution(DynInstPtr &inst); void validateExecution(DynInstPtr &inst);
void validateState(); void validateState();
void copyResult(DynInstPtr &inst);
private:
void handleError(DynInstPtr &inst)
{
if (exitOnError)
dumpAndExit(inst);
}
void dumpAndExit(DynInstPtr &inst);
std::list<DynInstPtr> instList; std::list<DynInstPtr> instList;
typedef typename std::list<DynInstPtr>::iterator InstListIt; typedef typename std::list<DynInstPtr>::iterator InstListIt;
void dumpInsts(); void dumpInsts();

View file

@ -77,6 +77,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker)
Param<bool> defer_registration; Param<bool> defer_registration;
Param<bool> exitOnError; Param<bool> exitOnError;
Param<bool> warnOnlyOnLoadError;
Param<bool> function_trace; Param<bool> function_trace;
Param<Tick> function_trace_start; Param<Tick> function_trace_start;
@ -110,6 +111,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(OzoneChecker)
INIT_PARAM(defer_registration, "defer system registration (for sampling)"), INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
INIT_PARAM(exitOnError, "exit on error"), INIT_PARAM(exitOnError, "exit on error"),
INIT_PARAM_DFLT(warnOnlyOnLoadError, "warn, but don't exit, if a load "
"result errors", false),
INIT_PARAM(function_trace, "Enable function trace"), INIT_PARAM(function_trace, "Enable function trace"),
INIT_PARAM(function_trace_start, "Cycle to start function trace") INIT_PARAM(function_trace_start, "Cycle to start function trace")
@ -126,6 +129,7 @@ CREATE_SIM_OBJECT(OzoneChecker)
params->max_loads_any_thread = 0; params->max_loads_any_thread = 0;
params->max_loads_all_threads = 0; params->max_loads_all_threads = 0;
params->exitOnError = exitOnError; params->exitOnError = exitOnError;
params->warnOnlyOnLoadError = warnOnlyOnLoadError;
params->deferRegistration = defer_registration; params->deferRegistration = defer_registration;
params->functionTrace = function_trace; params->functionTrace = function_trace;
params->functionTraceStart = function_trace_start; params->functionTraceStart = function_trace_start;

View file

@ -75,6 +75,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(O3Checker)
Param<bool> defer_registration; Param<bool> defer_registration;
Param<bool> exitOnError; Param<bool> exitOnError;
Param<bool> warnOnlyOnLoadError;
Param<bool> function_trace; Param<bool> function_trace;
Param<Tick> function_trace_start; Param<Tick> function_trace_start;
@ -105,6 +106,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(O3Checker)
INIT_PARAM(defer_registration, "defer system registration (for sampling)"), INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
INIT_PARAM(exitOnError, "exit on error"), INIT_PARAM(exitOnError, "exit on error"),
INIT_PARAM_DFLT(warnOnlyOnLoadError, "warn, but don't exit, if a load "
"result errors", false),
INIT_PARAM(function_trace, "Enable function trace"), INIT_PARAM(function_trace, "Enable function trace"),
INIT_PARAM(function_trace_start, "Cycle to start function trace") INIT_PARAM(function_trace_start, "Cycle to start function trace")
@ -121,6 +124,7 @@ CREATE_SIM_OBJECT(O3Checker)
params->max_loads_any_thread = 0; params->max_loads_any_thread = 0;
params->max_loads_all_threads = 0; params->max_loads_all_threads = 0;
params->exitOnError = exitOnError; params->exitOnError = exitOnError;
params->warnOnlyOnLoadError = warnOnlyOnLoadError;
params->deferRegistration = defer_registration; params->deferRegistration = defer_registration;
params->functionTrace = function_trace; params->functionTrace = function_trace;
params->functionTraceStart = function_trace_start; params->functionTraceStart = function_trace_start;

View file

@ -975,7 +975,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
// Use checker prior to updating anything due to traps or PC // Use checker prior to updating anything due to traps or PC
// based events. // based events.
if (cpu->checker) { if (cpu->checker) {
cpu->checker->tick(head_inst); cpu->checker->verify(head_inst);
} }
// Check if the instruction caused a fault. If so, trap. // Check if the instruction caused a fault. If so, trap.
@ -993,7 +993,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
} }
if (cpu->checker && head_inst->isStore()) { if (cpu->checker && head_inst->isStore()) {
cpu->checker->tick(head_inst); cpu->checker->verify(head_inst);
} }
assert(!thread[tid]->inSyscall); assert(!thread[tid]->inSyscall);

View file

@ -789,7 +789,7 @@ LSQUnit<Impl>::storePostSend(Packet *pkt)
// verify the value in memory for stores. // verify the value in memory for stores.
storeQueue[storeWBIdx].inst->setCompleted(); storeQueue[storeWBIdx].inst->setCompleted();
if (cpu->checker) { if (cpu->checker) {
cpu->checker->tick(storeQueue[storeWBIdx].inst); cpu->checker->verify(storeQueue[storeWBIdx].inst);
} }
} }
@ -885,7 +885,7 @@ LSQUnit<Impl>::completeStore(int store_idx)
// may get reported twice to the checker, but the checker can // may get reported twice to the checker, but the checker can
// handle that case. // handle that case.
if (cpu->checker) { if (cpu->checker) {
cpu->checker->tick(storeQueue[store_idx].inst); cpu->checker->verify(storeQueue[store_idx].inst);
} }
} }