/*
- * 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
* 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"
#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;
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)
xcProxy = cpuXC->getProxy();
execContexts.push_back(xcProxy);
memReq->xc = xcProxy;
+ delete cpuXC->kernelStats;
+ cpuXC->kernelStats = NULL;
}
#endif
}
xcProxy = cpuXC->getProxy();
execContexts.push_back(xcProxy);
memReq->xc = xcProxy;
+ delete cpuXC->kernelStats;
+ cpuXC->kernelStats = NULL;
}
}
#endif
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)
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
// 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();
}
}
}
#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)
{
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();
}
}
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();
}
}
}
}
-/* 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",
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++;
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());
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;
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()));
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
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);
// 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);
// Checks to make sure instrution results are correct.
validateExecution(inst);
-// if (curStaticInst->isMemRef()) {
-// numMemRefs++;
-// }
-
if (curStaticInst->isLoad()) {
++numLoad;
}
}
#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 {
}
#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()) {
void
Checker<DynInstPtr>::switchOut(Sampler *s)
{
- sampler = s;
instList.clear();
}
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>
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();
}
}
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());
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();
}
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();
}