Cleanup checker.

cpu/checker/cpu.cc:
    Cleanup checker, give more useful warning messages.
    Also fix bug
cpu/checker/cpu.hh:
    Cleanup checker, use forward declaration instead of include.

--HG--
extra : convert_revision : 8f231199a0a75788218320cdbcc7f70441e5d574
This commit is contained in:
Kevin Lim
2006-05-23 16:59:13 -04:00
parent 6c386396fa
commit c9ad4a15d6
2 changed files with 111 additions and 226 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,41 +26,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include <cmath>
#include <cstdio>
//#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <list>
//#include <sstream>
#include <string>
//#include "base/cprintf.hh"
//#include "base/inifile.hh"
//#include "base/loader/symtab.hh"
#include "base/misc.hh"
//#include "base/pollevent.hh"
//#include "base/range.hh"
#include "base/refcnt.hh"
//#include "base/stats/events.hh"
#include "cpu/base.hh"
#include "cpu/base_dyn_inst.hh"
#include "cpu/checker/cpu.hh"
#include "cpu/cpu_exec_context.hh"
#include "cpu/exec_context.hh"
//#include "cpu/exetrace.hh"
//#include "cpu/profile.hh"
#include "cpu/sampler/sampler.hh"
//#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
//#include "kern/kernel_stats.hh"
#include "mem/base_mem.hh"
#include "mem/mem_interface.hh"
#include "sim/byteswap.hh"
#include "sim/builder.hh"
//#include "sim/debug.hh"
//#include "sim/host.hh"
//#include "sim/sim_events.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
@@ -72,15 +48,8 @@
#include "cpu/ozone/simple_impl.hh"
#if FULL_SYSTEM
#include "base/remote_gdb.hh"
#include "mem/functional/memory_control.hh"
#include "mem/functional/physical.hh"
#include "sim/system.hh"
#include "arch/tlb.hh"
#include "arch/stacktrace.hh"
#include "arch/vtophys.hh"
#else // !FULL_SYSTEM
#include "mem/functional/functional.hh"
#endif // FULL_SYSTEM
using namespace std;
@@ -90,17 +59,6 @@ using namespace AlphaISA;
void
CheckerCPU::init()
{
/*
BaseCPU::init();
#if FULL_SYSTEM
for (int i = 0; i < execContexts.size(); ++i) {
ExecContext *xc = execContexts[i];
// initialize CPU, including PC
TheISA::initCPU(xc, xc->readCpuId());
}
#endif
*/
}
CheckerCPU::CheckerCPU(Params *p)
@@ -151,6 +109,8 @@ CheckerCPU::setMemory(FunctionalMemory *mem)
xcProxy = cpuXC->getProxy();
execContexts.push_back(xcProxy);
memReq->xc = xcProxy;
delete cpuXC->kernelStats;
cpuXC->kernelStats = NULL;
}
#endif
}
@@ -168,6 +128,8 @@ CheckerCPU::setSystem(System *system)
xcProxy = cpuXC->getProxy();
execContexts.push_back(xcProxy);
memReq->xc = xcProxy;
delete cpuXC->kernelStats;
cpuXC->kernelStats = NULL;
}
}
#endif
@@ -197,82 +159,15 @@ CheckerCPU::unserialize(Checkpoint *cp, const string &section)
Fault
CheckerCPU::copySrcTranslate(Addr src)
{
static bool no_warn = true;
int blk_size = 64;
// Only support block sizes of 64 atm.
assert(blk_size == 64);
int offset = src & (blk_size - 1);
// Make sure block doesn't span page
if (no_warn &&
(src & PageMask) != ((src + blk_size) & PageMask) &&
(src >> 40) != 0xfffffc) {
warn("Copied block source spans pages %x.", src);
no_warn = false;
}
memReq->reset(src & ~(blk_size - 1), blk_size);
// translate to physical address
Fault fault = cpuXC->translateDataReadReq(memReq);
if (fault == NoFault) {
cpuXC->copySrcAddr = src;
cpuXC->copySrcPhysAddr = memReq->paddr + offset;
} else {
assert(!fault->isAlignmentFault());
cpuXC->copySrcAddr = 0;
cpuXC->copySrcPhysAddr = 0;
}
return fault;
panic("Unimplemented!");
}
Fault
CheckerCPU::copy(Addr dest)
{
static bool no_warn = true;
int blk_size = 64;
// Only support block sizes of 64 atm.
assert(blk_size == 64);
uint8_t data[blk_size];
//assert(cpuXC->copySrcAddr);
int offset = dest & (blk_size - 1);
// Make sure block doesn't span page
if (no_warn &&
(dest & PageMask) != ((dest + blk_size) & PageMask) &&
(dest >> 40) != 0xfffffc) {
no_warn = false;
warn("Copied block destination spans pages %x. ", dest);
}
memReq->reset(dest & ~(blk_size -1), blk_size);
// translate to physical address
Fault fault = cpuXC->translateDataWriteReq(memReq);
if (fault == NoFault) {
Addr dest_addr = memReq->paddr + offset;
// Need to read straight from memory since we have more than 8 bytes.
memReq->paddr = cpuXC->copySrcPhysAddr;
cpuXC->mem->read(memReq, data);
memReq->paddr = dest_addr;
cpuXC->mem->write(memReq, data);
memReq->cmd = Copy;
memReq->completionEvent = NULL;
memReq->paddr = cpuXC->copySrcPhysAddr;
memReq->dest = dest_addr;
memReq->size = 64;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
}
else
assert(!fault->isAlignmentFault());
return fault;
panic("Unimplemented!");
}
// precise architected memory state accessor macros
template <class T>
Fault
CheckerCPU::read(Addr addr, T &data, unsigned flags)
@@ -280,17 +175,15 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags)
memReq->reset(addr, sizeof(T), flags);
// translate to physical address
// Should I probe the DTB? Or should I just take the physical address
// and assume correct translation?
translateDataReadReq(memReq);
// if we have a cache, do cache access too
memReq->cmd = Read;
memReq->completionEvent = NULL;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
if (!(memReq->flags & UNCACHEABLE)) {
// Access memory to see if we have the same data
cpuXC->read(memReq, data);
} else {
// Assume the data is correct if it's an uncached access
@@ -350,29 +243,34 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
// translate to physical address
cpuXC->translateDataWriteReq(memReq);
if ((!(unverifiedReq->flags & LOCKED) ||
((unverifiedReq->flags & LOCKED) &&
unverifiedReq->result == 1)) &&
!(unverifiedReq->flags & UNCACHEABLE)) {
// do functional access
// cpuXC->read(memReq, data);
memReq->cmd = Write;
// memcpy(memReq->data,(uint8_t *)&data,memReq->size);
T inst_data;
memcpy(&inst_data, unverifiedReq->data, sizeof(T));
// 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->flags & UNCACHEABLE) &&
(!(unverifiedReq->flags & LOCKED) ||
((unverifiedReq->flags & LOCKED) &&
unverifiedReq->result == 1))) {
#if 0
memReq->cmd = Read;
memReq->completionEvent = NULL;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
cpuXC->read(memReq, inst_data);
#endif
T inst_data;
memcpy(&inst_data, unverifiedReq->data, sizeof(T));
// Hard to verify this as the data writes back after the
// instruction commits. May only be able to check that the
// value produced from execute() matches the value produced
// from the instruction's first execution.
if (data != inst_data) {
warn("Store value does not match value in memory! "
warn("%lli: Store value does not match value in memory! "
"Instruction: %#x, memory: %#x",
inst_data, data);
curTick, inst_data, data);
handleError();
}
}
@@ -436,19 +334,6 @@ CheckerCPU::dbg_vtophys(Addr addr)
}
#endif // FULL_SYSTEM
#if FULL_SYSTEM
void
CheckerCPU::post_interrupt(int int_num, int index)
{
BaseCPU::post_interrupt(int_num, index);
if (cpuXC->status() == ExecContext::Suspended) {
DPRINTF(IPI,"Suspended Processor awoke\n");
cpuXC->activate();
}
}
#endif // FULL_SYSTEM
bool
CheckerCPU::translateInstReq(MemReqPtr &req)
{
@@ -466,15 +351,16 @@ CheckerCPU::translateDataReadReq(MemReqPtr &req)
cpuXC->translateDataReadReq(req);
if (req->vaddr != unverifiedReq->vaddr) {
warn("Request virtual addresses do not match! Inst: %#x, checker:"
" %#x",
unverifiedReq->vaddr, req->vaddr);
warn("%lli: Request virtual addresses do not match! Inst: %#x, "
"checker: %#x",
curTick, unverifiedReq->vaddr, req->vaddr);
handleError();
}
req->paddr = unverifiedReq->paddr;
if (checkFlags(req)) {
warn("Request flags do not match! Inst: %#x, checker: %#x",
unverifiedReq->flags, req->flags);
warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
curTick, unverifiedReq->flags, req->flags);
handleError();
}
}
@@ -485,15 +371,16 @@ CheckerCPU::translateDataWriteReq(MemReqPtr &req)
cpuXC->translateDataWriteReq(req);
if (req->vaddr != unverifiedReq->vaddr) {
warn("Request virtual addresses do not match! Inst: %#x, checker:"
" %#x",
unverifiedReq->vaddr, req->vaddr);
warn("%lli: Request virtual addresses do not match! Inst: %#x, "
"checker: %#x",
curTick, unverifiedReq->vaddr, req->vaddr);
handleError();
}
req->paddr = unverifiedReq->paddr;
if (checkFlags(req)) {
warn("Request flags do not match! Inst: %#x, checker: %#x",
unverifiedReq->flags, req->flags);
warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
curTick, unverifiedReq->flags, req->flags);
handleError();
}
}
@@ -512,13 +399,17 @@ CheckerCPU::checkFlags(MemReqPtr &req)
}
}
/* start simulation, program loaded, processor precise state initialized */
template <class DynInstPtr>
void
Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
{
DynInstPtr inst;
// 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
// completed, there may be some instructions that are waiting
// 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",
@@ -547,16 +438,17 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
inst = completed_inst;
youngestSN = completed_inst->seqNum;
} else {
// panic("SN already seen yet the list is empty!");
return;
}
}
}
// 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());
// verifyInst = completed_inst;
unverifiedResult.integer = inst->readIntResult();
unverifiedReq = inst->req;
numCycles++;
@@ -569,15 +461,9 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
cpuXC->setFloatRegDouble(ZeroReg, 0.0);
#endif // TARGET_ALPHA
// Try to fetch an instruction
// set up memory request for instruction fetch
#if FULL_SYSTEM
#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
#else
#define IFETCH_FLAGS(pc) 0
#endif
// Check if any recent PC changes match up with anything we
// 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",
cpuXC->readPC());
@@ -585,9 +471,9 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
if (newPC == cpuXC->readPC()) {
DPRINTF(Checker, "Changed PC matches expected PC\n");
} else {
warn("Changed PC does not match expected PC, changed: %#x, "
"expected: %#x",
cpuXC->readPC(), newPC);
warn("%lli: Changed PC does not match expected PC, "
"changed: %#x, expected: %#x",
curTick, cpuXC->readPC(), newPC);
handleError();
}
willChangePC = false;
@@ -600,6 +486,15 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
changedNextPC = false;
}
// Try to fetch the instruction
#if FULL_SYSTEM
#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
#else
#define IFETCH_FLAGS(pc) 0
#endif
// set up memory request for instruction fetch
memReq->cmd = Read;
memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t),
IFETCH_FLAGS(cpuXC->readPC()));
@@ -608,8 +503,13 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
if (!succeeded) {
if (inst->getFault() == NoFault) {
warn("Instruction PC %#x was not found in the ITB!",
cpuXC->readPC());
// 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, cpuXC->readPC());
handleError();
// go to the next instruction
@@ -618,20 +518,18 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
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 = inst->getFault();
}
}
if (fault == NoFault) {
// fault = cpuXC->mem->read(memReq, machInst);
cpuXC->mem->read(memReq, machInst);
// If we've got a valid instruction (i.e., no fault on instruction
// fetch), then execute it.
// keep an instruction count
// keep an instruction count
numInst++;
// numInsts++;
// decode the instruction
machInst = gtoh(machInst);
@@ -639,7 +537,8 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
// Checks both the machine instruction and the PC.
validateInst(inst);
curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC()));
curStaticInst = StaticInst::decode(makeExtMI(machInst,
cpuXC->readPC()));
#if FULL_SYSTEM
cpuXC->setInst(machInst);
@@ -660,10 +559,6 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
// Checks to make sure instrution results are correct.
validateExecution(inst);
// if (curStaticInst->isMemRef()) {
// numMemRefs++;
// }
if (curStaticInst->isLoad()) {
++numLoad;
}
@@ -693,6 +588,9 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
}
#if FULL_SYSTEM
// @todo: Determine if these should happen only if the
// instruction hasn't faulted. In the SimpleCPU case this may
// not be true, but in the O3 or Ozone case this may be true.
Addr oldpc;
int count = 0;
do {
@@ -707,10 +605,12 @@ Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
}
#endif
// Checks PC, next PC. Optionally can check all registers. (Or just those
// @todo: Optionally can check all registers. (Or just those
// that have been modified).
validateState();
// Continue verifying instructions if there's another completed
// instruction waiting to be verified.
if (instList.empty()) {
break;
} else if (instList.front()->isCompleted()) {
@@ -726,7 +626,6 @@ template <class DynInstPtr>
void
Checker<DynInstPtr>::switchOut(Sampler *s)
{
sampler = s;
instList.clear();
}
@@ -734,15 +633,6 @@ template <class DynInstPtr>
void
Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
{
// BaseCPU::takeOverFrom(oldCPU);
// if any of this CPU's ExecContexts are active, mark the CPU as
// running and schedule its tick event.
/*
for (int i = 0; i < execContexts.size(); ++i) {
ExecContext *xc = execContexts[i];
}
*/
}
template <class DynInstPtr>
@@ -750,20 +640,22 @@ void
Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
{
if (inst->readPC() != cpuXC->readPC()) {
warn("PCs do not match! Inst: %#x, checker: %#x",
inst->readPC(), cpuXC->readPC());
warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
curTick, inst->readPC(), cpuXC->readPC());
if (changedPC) {
warn("Changed PCs recently, may not be an error");
warn("%lli: Changed PCs recently, may not be an error",
curTick);
} else {
handleError();
}
}
if (static_cast<MachInst>(inst->staticInst->machInst) !=
machInst) {
warn("Binary instructions do not match! Inst: %#x, checker: %#x",
static_cast<MachInst>(inst->staticInst->machInst),
machInst);
MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
if (mi != machInst) {
warn("%lli: Binary instructions do not match! Inst: %#x, "
"checker: %#x",
curTick, mi, machInst);
handleError();
}
}
@@ -773,10 +665,11 @@ void
Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
{
if (inst->numDestRegs()) {
// @todo: Support more destination registers.
if (inst->isUnverifiable()) {
// @todo: Support more destination registers.
// Grab the result from the instruction and write it to the
// register.
// Unverifiable instructions assume they were executed
// properly by the CPU. Grab the result from the
// instruction and write it to the register.
RegIndex idx = inst->destRegIdx(0);
if (idx < TheISA::FP_Base_DepTag) {
cpuXC->setIntReg(idx, inst->readIntResult());
@@ -786,16 +679,17 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
cpuXC->setMiscReg(idx, inst->readIntResult());
}
} else if (result.integer != inst->readIntResult()) {
warn("Instruction results do not match! (May not be integer results) "
"Inst: %#x, checker: %#x",
inst->readIntResult(), result.integer);
warn("%lli: Instruction results do not match! (Results may not "
"actually be integers) Inst: %#x, checker: %#x",
curTick, inst->readIntResult(), result.integer);
handleError();
}
}
if (inst->readNextPC() != cpuXC->readNextPC()) {
warn("Instruction next PCs do not match! Inst: %#x, checker: %#x",
inst->readNextPC(), cpuXC->readNextPC());
warn("%lli: Instruction next PCs do not match! Inst: %#x, "
"checker: %#x",
curTick, inst->readNextPC(), cpuXC->readNextPC());
handleError();
}
@@ -810,9 +704,10 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
if (inst->xcBase()->readMiscReg(misc_reg_idx) !=
cpuXC->readMiscReg(misc_reg_idx)) {
warn("Misc reg idx %i (side effect) does not match! Inst: %#x, "
"checker: %#x",
misc_reg_idx, inst->xcBase()->readMiscReg(misc_reg_idx),
warn("%lli: Misc reg idx %i (side effect) does not match! "
"Inst: %#x, checker: %#x",
curTick, misc_reg_idx,
inst->xcBase()->readMiscReg(misc_reg_idx),
cpuXC->readMiscReg(misc_reg_idx));
handleError();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,6 @@
#include "cpu/base_dyn_inst.hh"
#include "cpu/cpu_exec_context.hh"
#include "cpu/pc_event.hh"
#include "cpu/sampler/sampler.hh"
#include "cpu/static_inst.hh"
#include "sim/eventq.hh"
@@ -63,6 +62,7 @@ class BaseDynInst;
class ExecContext;
class MemInterface;
class Checkpoint;
class Sampler;
class CheckerCPU : public BaseCPU
{
@@ -86,8 +86,6 @@ class CheckerCPU : public BaseCPU
};
public:
void post_interrupt(int int_num, int index);
CheckerCPU(Params *p);
virtual ~CheckerCPU();
@@ -111,8 +109,6 @@ class CheckerCPU : public BaseCPU
#if FULL_SYSTEM
Addr dbg_vtophys(Addr addr);
bool interval_stats;
#endif
union Result {
@@ -129,11 +125,6 @@ class CheckerCPU : public BaseCPU
// Refcounted pointer to the one memory request.
MemReqPtr memReq;
// Pointer to the sampler that is telling us to switchover.
// Used to signal the completion of the pipe drain and schedule
// the next switchover
Sampler *sampler;
StaticInstPtr curStaticInst;
// number of simulated instructions
@@ -284,6 +275,7 @@ class CheckerCPU : public BaseCPU
bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); }
#else
// Assume that the normal CPU's call to syscall was successful.
// The checker's state would have already been updated by the syscall.
void syscall() { }
#endif
@@ -307,8 +299,6 @@ class CheckerCPU : public BaseCPU
bool exitOnError;
InstSeqNum youngestSN;
// std::map<Addr, uint64_t> storeBuff;
// typedef std::map<Addr, uint64_t>::iterator map_it;
};
template <class DynInstPtr>