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:
parent
5d11e8bff6
commit
720e6c4145
6 changed files with 96 additions and 25 deletions
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue