Merge ktlim@zizzer:/bk/m5

into  zamp.eecs.umich.edu:/z/ktlim2/clean/m5-o3

--HG--
extra : convert_revision : 0a6140f3f5e7c454981c5aa2b221224f076e50eb
This commit is contained in:
Kevin Lim 2006-05-23 17:04:25 -04:00
commit b414c9e736
31 changed files with 551 additions and 782 deletions

View file

@ -146,7 +146,7 @@ CPUExecContext::hwrei()
setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR));
if (!misspeculating()) {
cpu->kernelStats->hwrei();
kernelStats->hwrei();
cpu->checkInterrupts = true;
}
@ -336,7 +336,8 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
// write entire quad w/ no side-effect
old = ipr[idx];
ipr[idx] = val;
xc->getCpuPtr()->kernelStats->context(old, val, xc);
if (xc->getKernelStats())
xc->getKernelStats()->context(old, val, xc);
break;
case AlphaISA::IPR_DTB_PTE:
@ -363,14 +364,19 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
// only write least significant five bits - interrupt level
ipr[idx] = val & 0x1f;
xc->getCpuPtr()->kernelStats->swpipl(ipr[idx]);
if (xc->getKernelStats())
xc->getKernelStats()->swpipl(ipr[idx]);
break;
case AlphaISA::IPR_DTB_CM:
if (val & 0x18)
xc->getCpuPtr()->kernelStats->mode(Kernel::user, xc);
else
xc->getCpuPtr()->kernelStats->mode(Kernel::kernel, xc);
if (val & 0x18) {
if (xc->getKernelStats())
xc->getKernelStats()->mode(Kernel::user, xc);
else {
if (xc->getKernelStats())
xc->getKernelStats()->mode(Kernel::kernel, xc);
}
}
case AlphaISA::IPR_ICM:
// only write two mode bits - processor mode
@ -556,7 +562,7 @@ AlphaISA::MiscRegFile::copyIprs(ExecContext *xc)
bool
CPUExecContext::simPalCheck(int palFunc)
{
cpu->kernelStats->callpal(palFunc, proxy);
kernelStats->callpal(palFunc, proxy);
switch (palFunc) {
case PAL::halt:

View file

@ -45,10 +45,6 @@
#include "base/trace.hh"
#if FULL_SYSTEM
#include "kern/kernel_stats.hh"
#endif
using namespace std;
vector<BaseCPU *> BaseCPU::cpuList;
@ -153,8 +149,6 @@ BaseCPU::BaseCPU(Params *p)
profileEvent = NULL;
if (params->profile)
profileEvent = new ProfileEvent(this, params->profile);
kernelStats = new Kernel::Statistics(system);
#endif
}
@ -175,10 +169,6 @@ BaseCPU::enableFunctionTrace()
BaseCPU::~BaseCPU()
{
#if FULL_SYSTEM
if (kernelStats)
delete kernelStats;
#endif
}
void
@ -219,8 +209,6 @@ BaseCPU::regStats()
execContexts[0]->regStats(name());
#if FULL_SYSTEM
if (kernelStats)
kernelStats->regStats(name() + ".kern");
#endif
}
@ -348,12 +336,6 @@ BaseCPU::serialize(std::ostream &os)
{
SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
SERIALIZE_SCALAR(intstatus);
#if FULL_SYSTEM
if (kernelStats)
kernelStats->serialize(os);
#endif
}
void
@ -361,11 +343,6 @@ BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
UNSERIALIZE_SCALAR(intstatus);
#if FULL_SYSTEM
if (kernelStats)
kernelStats->unserialize(cp, section);
#endif
}
#endif // FULL_SYSTEM

View file

@ -38,14 +38,10 @@
#include "sim/sim_object.hh"
#include "arch/isa_traits.hh"
#if FULL_SYSTEM
class System;
namespace Kernel { class Statistics; }
#endif
class BranchPred;
class CheckerCPU;
class ExecContext;
class System;
class BaseCPU : public SimObject
{
@ -237,10 +233,6 @@ class BaseCPU : public SimObject
public:
// Number of CPU cycles simulated
Stats::Scalar<> numCycles;
#if FULL_SYSTEM
Kernel::Statistics *kernelStats;
#endif
};
#endif // __CPU_BASE_HH__

View file

@ -450,13 +450,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
instResult.integer = val;
}
//Push to .cc file.
/** Records that one of the source registers is ready. */
void markSrcRegReady();
/** Marks a specific register as ready.
* @todo: Move this to .cc file.
*/
/** Marks a specific register as ready. */
void markSrcRegReady(RegIndex src_idx);
/** Returns if a source register is ready. */

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>

View file

@ -1,3 +1,31 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#ifndef __CPU_CHECKER_EXEC_CONTEXT_HH__
#define __CPU_CHECKER_EXEC_CONTEXT_HH__
@ -6,6 +34,9 @@
#include "cpu/exec_context.hh"
class EndQuiesceEvent;
namespace Kernel {
class Statistics;
};
template <class XC>
class CheckerExecContext : public ExecContext
@ -13,7 +44,8 @@ class CheckerExecContext : public ExecContext
public:
CheckerExecContext(XC *actual_xc,
CheckerCPU *checker_cpu)
: actualXC(actual_xc), checkerXC(checker_cpu->cpuXC), checkerCPU(checker_cpu)
: actualXC(actual_xc), checkerXC(checker_cpu->cpuXC),
checkerCPU(checker_cpu)
{ }
private:
@ -43,6 +75,8 @@ class CheckerExecContext : public ExecContext
AlphaITB *getITBPtr() { return actualXC->getITBPtr(); }
AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); }
Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); }
#else
Process *getProcessPtr() { return actualXC->getProcessPtr(); }
#endif
@ -50,8 +84,10 @@ class CheckerExecContext : public ExecContext
Status status() const { return actualXC->status(); }
void setStatus(Status new_status)
{ actualXC->setStatus(new_status);
checkerXC->setStatus(new_status); }
{
actualXC->setStatus(new_status);
checkerXC->setStatus(new_status);
}
/// Set the status to Active. Optional delay indicates number of
/// cycles to wait before beginning execution.
@ -216,8 +252,6 @@ class CheckerExecContext : public ExecContext
actualXC->setSyscallReturn(return_value);
}
// void syscall() { actualXC->syscall(); }
Counter readFuncExeInst() { return actualXC->readFuncExeInst(); }
#endif
};

View file

@ -188,7 +188,8 @@ CPUExecContext::serialize(ostream &os)
if (quiesceEvent->scheduled())
quiesceEndTick = quiesceEvent->when();
SERIALIZE_SCALAR(quiesceEndTick);
if (kernelStats)
kernelStats->serialize(os);
#endif
}
@ -207,6 +208,8 @@ CPUExecContext::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(quiesceEndTick);
if (quiesceEndTick)
quiesceEvent->schedule(quiesceEndTick);
if (kernelStats)
kernelStats->unserialize(cp, section);
#endif
}
@ -275,6 +278,10 @@ CPUExecContext::halt()
void
CPUExecContext::regStats(const string &name)
{
#if FULL_SYSTEM
kernelStats = new Kernel::Statistics(system);
kernelStats->regStats(name + ".kern");
#endif
}
void

View file

@ -53,6 +53,10 @@ class FunctionProfile;
class ProfileNode;
class MemoryController;
namespace Kernel {
class Statistics;
};
#else // !FULL_SYSTEM
#include "sim/process.hh"
@ -147,6 +151,9 @@ class CPUExecContext
void profileSample();
Kernel::Statistics *getKernelStats() { return kernelStats; }
Kernel::Statistics *kernelStats;
#else
Process *process;

View file

@ -48,6 +48,9 @@ class FunctionalMemory;
class PhysicalMemory;
class Process;
class System;
namespace Kernel {
class Statistics;
};
class ExecContext
{
@ -98,6 +101,8 @@ class ExecContext
virtual AlphaITB *getITBPtr() = 0;
virtual AlphaDTB * getDTBPtr() = 0;
virtual Kernel::Statistics *getKernelStats() = 0;
#else
virtual Process *getProcessPtr() = 0;
#endif
@ -243,6 +248,8 @@ class ProxyExecContext : public ExecContext
AlphaITB *getITBPtr() { return actualXC->getITBPtr(); }
AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); }
Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); }
#else
Process *getProcessPtr() { return actualXC->getProcessPtr(); }
#endif

View file

@ -35,6 +35,9 @@
#include "sim/byteswap.hh"
class EndQuiesceEvent;
namespace Kernel {
class Statistics;
};
template <class Impl>
class AlphaFullCPU : public FullO3CPU<Impl>
@ -60,11 +63,6 @@ class AlphaFullCPU : public FullO3CPU<Impl>
O3ThreadState<Impl> *thread;
Tick lastActivate;
Tick lastSuspend;
EndQuiesceEvent *quiesceEvent;
virtual BaseCPU *getCpuPtr() { return cpu; }
virtual void setCpuId(int id) { cpu->cpu_id = id; }
@ -81,6 +79,9 @@ class AlphaFullCPU : public FullO3CPU<Impl>
virtual AlphaITB *getITBPtr() { return cpu->itb; }
virtual AlphaDTB * getDTBPtr() { return cpu->dtb; }
virtual Kernel::Statistics *getKernelStats()
{ return thread->kernelStats; }
#else
virtual Process *getProcessPtr() { return thread->process; }
#endif

View file

@ -31,7 +31,6 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/checker/exec_context.hh"
#include "cpu/quiesce_event.hh"
#include "mem/mem_interface.hh"
#include "sim/sim_events.hh"
#include "sim/stats.hh"
@ -44,6 +43,8 @@
#if FULL_SYSTEM
#include "arch/alpha/osfpal.hh"
#include "arch/isa_traits.hh"
#include "cpu/quiesce_event.hh"
#include "kern/kernel_stats.hh"
#endif
using namespace TheISA;
@ -101,11 +102,12 @@ AlphaFullCPU<Impl>::AlphaFullCPU(Params *params)
alpha_xc_proxy->cpu = this;
alpha_xc_proxy->thread = this->thread[i];
alpha_xc_proxy->quiesceEvent =
#if FULL_SYSTEM
this->thread[i]->quiesceEvent =
new EndQuiesceEvent(xc_proxy);
alpha_xc_proxy->lastActivate = 0;
alpha_xc_proxy->lastSuspend = 0;
this->thread[i]->lastActivate = 0;
this->thread[i]->lastSuspend = 0;
#endif
this->thread[i]->xcProxy = xc_proxy;
this->execContexts.push_back(xc_proxy);
@ -181,6 +183,9 @@ AlphaFullCPU<Impl>::AlphaXC::takeOverFrom(ExecContext *old_context)
if (thread->quiesceEvent) {
thread->quiesceEvent->xc = this;
}
// Transfer kernel stats from one CPU to the other.
thread->kernelStats = old_context->getKernelStats();
// storeCondFailures = 0;
cpu->lockFlag = false;
#endif
@ -200,7 +205,9 @@ AlphaFullCPU<Impl>::AlphaXC::activate(int delay)
if (thread->status() == ExecContext::Active)
return;
lastActivate = curTick;
#if FULL_SYSTEM
thread->lastActivate = curTick;
#endif
if (thread->status() == ExecContext::Unallocated) {
cpu->activateWhenReady(thread->tid);
@ -222,8 +229,10 @@ AlphaFullCPU<Impl>::AlphaXC::suspend()
if (thread->status() == ExecContext::Suspended)
return;
lastActivate = curTick;
lastSuspend = curTick;
#if FULL_SYSTEM
thread->lastActivate = curTick;
thread->lastSuspend = curTick;
#endif
/*
#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
@ -266,38 +275,55 @@ AlphaFullCPU<Impl>::AlphaXC::halt()
template <class Impl>
void
AlphaFullCPU<Impl>::AlphaXC::regStats(const std::string &name)
{}
{
#if FULL_SYSTEM
thread->kernelStats = new Kernel::Statistics(cpu->system);
thread->kernelStats->regStats(name + ".kern");
#endif
}
template <class Impl>
void
AlphaFullCPU<Impl>::AlphaXC::serialize(std::ostream &os)
{}
{
#if FULL_SYSTEM
if (thread->kernelStats)
thread->kernelStats->serialize(os);
#endif
}
template <class Impl>
void
AlphaFullCPU<Impl>::AlphaXC::unserialize(Checkpoint *cp, const std::string &section)
{}
{
#if FULL_SYSTEM
if (thread->kernelStats)
thread->kernelStats->unserialize(cp, section);
#endif
}
#if FULL_SYSTEM
template <class Impl>
EndQuiesceEvent *
AlphaFullCPU<Impl>::AlphaXC::getQuiesceEvent()
{
return quiesceEvent;
return thread->quiesceEvent;
}
template <class Impl>
Tick
AlphaFullCPU<Impl>::AlphaXC::readLastActivate()
{
return lastActivate;
return thread->lastActivate;
}
template <class Impl>
Tick
AlphaFullCPU<Impl>::AlphaXC::readLastSuspend()
{
return lastSuspend;
return thread->lastSuspend;
}
template <class Impl>
@ -595,7 +621,7 @@ AlphaFullCPU<Impl>::hwrei(unsigned tid)
// Need to clear the lock flag upon returning from an interrupt.
this->lockFlag = false;
this->kernelStats->hwrei();
this->thread[tid]->kernelStats->hwrei();
this->checkInterrupts = true;
@ -607,9 +633,9 @@ template <class Impl>
bool
AlphaFullCPU<Impl>::simPalCheck(int palFunc, unsigned tid)
{
if (this->kernelStats)
this->kernelStats->callpal(palFunc,
this->execContexts[tid]);
if (this->thread[tid]->kernelStats)
this->thread[tid]->kernelStats->callpal(palFunc,
this->execContexts[tid]);
switch (palFunc) {
case PAL::halt:

View file

@ -1232,13 +1232,14 @@ DefaultIEW<Impl>::executeInsts()
#endif
// Execute/writeback any instructions that are available.
int insts_to_execute = fromIssue->size;
int inst_num = 0;
for ( ; inst_num < issueWidth && fromIssue->insts[inst_num];
for (; inst_num < insts_to_execute;
++inst_num) {
DPRINTF(IEW, "Execute: Executing instructions from IQ.\n");
DynInstPtr inst = fromIssue->insts[inst_num];
DynInstPtr inst = instQueue.getInstToExecute();
DPRINTF(IEW, "Execute: Processing PC %#x, [tid:%i] [sn:%i].\n",
inst->readPC(), inst->threadNumber,inst->seqNum);

View file

@ -171,6 +171,8 @@ class InstructionQueue
*/
void insertBarrier(DynInstPtr &barr_inst);
DynInstPtr getInstToExecute();
/**
* Records the instruction as the producer of a register without
* adding it to the rest of the IQ.
@ -272,6 +274,8 @@ class InstructionQueue
/** List of all the instructions in the IQ (some of which may be issued). */
std::list<DynInstPtr> instList[Impl::MaxThreads];
std::list<DynInstPtr> instsToExecute;
/**
* Struct for comparing entries to be added to the priority queue. This
* gives reverse ordering to the instructions in terms of sequence

View file

@ -588,6 +588,16 @@ InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst)
insertNonSpec(barr_inst);
}
template <class Impl>
typename Impl::DynInstPtr
InstructionQueue<Impl>::getInstToExecute()
{
assert(!instsToExecute.empty());
DynInstPtr inst = instsToExecute.front();
instsToExecute.pop_front();
return inst;
}
template <class Impl>
void
InstructionQueue<Impl>::addToOrderList(OpClass op_class)
@ -662,9 +672,11 @@ InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx)
// @todo: This could break if there's multiple multi-cycle ops
// finishing on this cycle. Maybe implement something like
// instToCommit in iew_impl.hh.
int &size = issueToExecuteQueue->access(0)->size;
issueToExecuteQueue->access(0)->size++;
instsToExecute.push_back(inst);
// int &size = issueToExecuteQueue->access(0)->size;
issueToExecuteQueue->access(0)->insts[size++] = inst;
// issueToExecuteQueue->access(0)->insts[size++] = inst;
}
// @todo: Figure out a better way to remove the squashed items from the
@ -690,9 +702,8 @@ InstructionQueue<Impl>::scheduleReadyInsts()
ListOrderIt order_it = listOrder.begin();
ListOrderIt order_end_it = listOrder.end();
int total_issued = 0;
int exec_queue_slot = i2e_info->size;
while (exec_queue_slot < totalWidth && total_issued < totalWidth &&
while (total_issued < totalWidth &&
order_it != order_end_it) {
OpClass op_class = (*order_it).queueType;
@ -733,8 +744,9 @@ InstructionQueue<Impl>::scheduleReadyInsts()
if (idx == -2 || idx != -1) {
if (op_latency == 1) {
i2e_info->insts[exec_queue_slot++] = issuing_inst;
// i2e_info->insts[exec_queue_slot++] = issuing_inst;
i2e_info->size++;
instsToExecute.push_back(issuing_inst);
// Add the FU onto the list of FU's to be freed next
// cycle if we used one.

View file

@ -57,6 +57,10 @@ class Sampler;
class RemoteGDB;
class GDBListener;
namespace Kernel {
class Statistics;
};
#else
class Process;
@ -116,6 +120,8 @@ class OzoneCPU : public BaseCPU
AlphaITB *getITBPtr() { return cpu->itb; }
AlphaDTB * getDTBPtr() { return cpu->dtb; }
Kernel::Statistics *getKernelStats() { return thread->kernelStats; }
#else
Process *getProcessPtr() { return thread->process; }
#endif
@ -238,14 +244,7 @@ class OzoneCPU : public BaseCPU
private:
OzoneThreadState<Impl> thread;
/*
// Squash event for when the XC needs to squash all inflight instructions.
struct XCSquashEvent : public Event
{
void process();
const char *description();
};
*/
public:
// main simulation loop (one cycle)
void tick();
@ -288,7 +287,6 @@ class OzoneCPU : public BaseCPU
void trace_data(T data);
public:
//
enum Status {
Running,
Idle,
@ -325,8 +323,6 @@ class OzoneCPU : public BaseCPU
int readCpuId() { return cpuId; }
// FunctionalMemory *getMemPtr() { return mem; }
int cpuId;
void switchOut(Sampler *sampler);
@ -369,8 +365,6 @@ class OzoneCPU : public BaseCPU
Status status() const { return _status; }
void setStatus(Status new_status) { _status = new_status; }
// Not sure what an activate() call on the CPU's proxy XC would mean...
virtual void activateContext(int thread_num, int delay);
virtual void suspendContext(int thread_num);
virtual void deallocateContext(int thread_num);
@ -384,7 +378,6 @@ class OzoneCPU : public BaseCPU
public:
Counter numInst;
Counter startNumInst;
// Stats::Scalar<> numInsts;
virtual Counter totalInstructions() const
{
@ -392,9 +385,6 @@ class OzoneCPU : public BaseCPU
}
private:
// number of simulated memory references
// Stats::Scalar<> numMemRefs;
// number of simulated loads
Counter numLoad;
Counter startNumLoad;
@ -472,7 +462,6 @@ class OzoneCPU : public BaseCPU
template <class T>
Fault read(MemReqPtr &req, T &data)
{
// panic("CPU READ NOT IMPLEMENTED W/NEW MEMORY\n");
#if 0
#if FULL_SYSTEM && defined(TARGET_ALPHA)
if (req->flags & LOCKED) {
@ -483,7 +472,6 @@ class OzoneCPU : public BaseCPU
#endif
Fault error;
if (req->flags & LOCKED) {
// lockAddr = req->paddr;
lockAddrList.insert(req->paddr);
lockFlag = true;
}
@ -558,7 +546,7 @@ class OzoneCPU : public BaseCPU
if (req->flags & UNCACHEABLE) {
req->result = 2;
} else {
if (this->lockFlag/* && this->lockAddr == req->paddr*/) {
if (this->lockFlag) {
if (lockAddrList.find(req->paddr) !=
lockAddrList.end()) {
req->result = 1;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 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,8 +26,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdio>
#include <cstdlib>
//#include <cstdio>
//#include <cstdlib>
#include "arch/isa_traits.hh" // For MachInst
#include "base/trace.hh"
@ -39,7 +39,7 @@
#include "cpu/ozone/cpu.hh"
#include "cpu/quiesce_event.hh"
#include "cpu/static_inst.hh"
#include "mem/base_mem.hh"
//#include "mem/base_mem.hh"
#include "mem/mem_interface.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
@ -50,7 +50,7 @@
#include "arch/alpha/tlb.hh"
#include "arch/vtophys.hh"
#include "base/callback.hh"
#include "base/remote_gdb.hh"
//#include "base/remote_gdb.hh"
#include "cpu/profile.hh"
#include "kern/kernel_stats.hh"
#include "mem/functional/memory_control.hh"
@ -94,80 +94,26 @@ OzoneCPU<Impl>::TickEvent::description()
{
return "OzoneCPU tick event";
}
/*
template <class Impl>
OzoneCPU<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(OzoneCPU *_cpu)
: Event(&mainEventQueue),
cpu(_cpu)
{
}
template <class Impl>
void
OzoneCPU<Impl>::ICacheCompletionEvent::process()
{
cpu->processICacheCompletion();
}
template <class Impl>
const char *
OzoneCPU<Impl>::ICacheCompletionEvent::description()
{
return "OzoneCPU I-cache completion event";
}
template <class Impl>
OzoneCPU<Impl>::DCacheCompletionEvent::
DCacheCompletionEvent(OzoneCPU *_cpu,
DynInstPtr &_inst,
DCacheCompEventIt &_dcceIt)
: Event(&mainEventQueue),
cpu(_cpu),
inst(_inst),
dcceIt(_dcceIt)
{
this->setFlags(Event::AutoDelete);
}
template <class Impl>
void
OzoneCPU<Impl>::DCacheCompletionEvent::process()
{
inst->setCompleted();
// Maybe remove the EA from the list of addrs?
cpu->eaList.clearAddr(inst->seqNum, inst->getEA());
cpu->dCacheCompList.erase(this->dcceIt);
}
template <class Impl>
const char *
OzoneCPU<Impl>::DCacheCompletionEvent::description()
{
return "OzoneCPU D-cache completion event";
}
*/
template <class Impl>
OzoneCPU<Impl>::OzoneCPU(Params *p)
#if FULL_SYSTEM
: BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width), mem(p->mem),
: BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width),
mem(p->mem),
#else
: BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width),
mem(p->workload[0]->getMemory()),
#endif
comm(5, 5)
{
if (p->checker) {
BaseCPU *temp_checker = p->checker;
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
} else {
checker = NULL;
}
frontEnd = new FrontEnd(p);
backEnd = new BackEnd(p);
_status = Idle;
if (checker) {
if (p->checker) {
BaseCPU *temp_checker = p->checker;
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
checker->setMemory(mem);
#if FULL_SYSTEM
checker->setSystem(p->system);
@ -176,19 +122,18 @@ OzoneCPU<Impl>::OzoneCPU(Params *p)
thread.xcProxy = checkerXC;
xcProxy = checkerXC;
} else {
checker = NULL;
thread.xcProxy = &ozoneXC;
xcProxy = &ozoneXC;
}
thread.inSyscall = false;
ozoneXC.cpu = this;
ozoneXC.thread = &thread;
thread.inSyscall = false;
thread.setStatus(ExecContext::Suspended);
#if FULL_SYSTEM
// xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
/***** All thread state stuff *****/
thread.cpu = this;
thread.tid = 0;
@ -217,31 +162,15 @@ OzoneCPU<Impl>::OzoneCPU(Params *p)
thread.profileNode = &dummyNode;
thread.profilePC = 3;
#else
// xc = new ExecContext(this, /* thread_num */ 0, p->workload[0], /* asid */ 0);
thread.cpu = this;
thread.tid = 0;
thread.process = p->workload[0];
// thread.mem = thread.process->getMemory();
thread.asid = 0;
#endif // !FULL_SYSTEM
/*
icacheInterface = p->icache_interface;
dcacheInterface = p->dcache_interface;
cacheMemReq = new MemReq();
cacheMemReq->xc = xc;
cacheMemReq->asid = 0;
cacheMemReq->data = new uint8_t[64];
*/
numInst = 0;
startNumInst = 0;
/* numLoad = 0;
startNumLoad = 0;
lastIcacheStall = 0;
lastDcacheStall = 0;
issueWidth = p->issueWidth;
*/
execContexts.push_back(xcProxy);
frontEnd->setCPU(this);
@ -286,47 +215,7 @@ template <class Impl>
OzoneCPU<Impl>::~OzoneCPU()
{
}
/*
template <class Impl>
void
OzoneCPU<Impl>::copyFromXC()
{
for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
if (i < TheISA::NumIntRegs) {
renameTable[i]->setIntResult(xc->readIntReg(i));
} else if (i < TheISA::NumFloatRegs) {
renameTable[i]->setDoubleResult(xc->readFloatRegDouble(i));
}
}
DPRINTF(OzoneCPU, "Func Exe inst is: %i\n", xc->func_exe_inst);
backEnd->funcExeInst = xc->func_exe_inst;
// PC = xc->readPC();
// nextPC = xc->regs.npc;
}
template <class Impl>
void
OzoneCPU<Impl>::copyToXC()
{
for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
if (i < TheISA::NumIntRegs) {
xc->setIntReg(i, renameTable[i]->readIntResult());
} else if (i < TheISA::NumFloatRegs) {
xc->setFloatRegDouble(i, renameTable[i]->readDoubleResult());
}
}
this->xc->regs.miscRegs.fpcr = this->regFile.miscRegs[tid].fpcr;
this->xc->regs.miscRegs.uniq = this->regFile.miscRegs[tid].uniq;
this->xc->regs.miscRegs.lock_flag = this->regFile.miscRegs[tid].lock_flag;
this->xc->regs.miscRegs.lock_addr = this->regFile.miscRegs[tid].lock_addr;
xc->func_exe_inst = backEnd->funcExeInst;
xc->regs.pc = PC;
xc->regs.npc = nextPC;
}
*/
template <class Impl>
void
OzoneCPU<Impl>::switchOut(Sampler *_sampler)
@ -394,7 +283,6 @@ OzoneCPU<Impl>::activateContext(int thread_num, int delay)
{
// Eventually change this in SMT.
assert(thread_num == 0);
// assert(xcProxy);
assert(_status == Idle);
notIdleFraction++;
@ -410,8 +298,8 @@ OzoneCPU<Impl>::suspendContext(int thread_num)
{
// Eventually change this in SMT.
assert(thread_num == 0);
// assert(xcProxy);
// @todo: Figure out how to initially set the status properly so this is running.
// @todo: Figure out how to initially set the status properly so
// this is running.
// assert(_status == Running);
notIdleFraction--;
unscheduleTickEvent();
@ -486,14 +374,7 @@ void
OzoneCPU<Impl>::init()
{
BaseCPU::init();
/*
copyFromXC();
// ALso copy over PC/nextPC. This isn't normally copied in "copyFromXC()"
// so that the XC doesn't mess up the PC when returning from a syscall.
PC = xc->readPC();
nextPC = xc->regs.npc;
*/
// Mark this as in syscall so it won't need to squash
thread.inSyscall = true;
#if FULL_SYSTEM
@ -514,8 +395,6 @@ template <class Impl>
void
OzoneCPU<Impl>::serialize(std::ostream &os)
{
// At this point, all DCacheCompEvents should be processed.
BaseCPU::serialize(os);
SERIALIZE_ENUM(_status);
nameOut(os, csprintf("%s.xc", name()));
@ -631,31 +510,7 @@ OzoneCPU<Impl>::dbg_vtophys(Addr addr)
return vtophys(xcProxy, addr);
}
#endif // FULL_SYSTEM
/*
template <class Impl>
void
OzoneCPU<Impl>::processICacheCompletion()
{
switch (status()) {
case IcacheMiss:
DPRINTF(OzoneCPU, "OzoneCPU: Finished Icache miss.\n");
icacheStallCycles += curTick - lastIcacheStall;
_status = IcacheMissComplete;
cacheBlkValid = true;
// scheduleTickEvent(1);
break;
case SwitchedOut:
// If this CPU has been switched out due to sampling/warm-up,
// ignore any further status changes (e.g., due to cache
// misses outstanding at the time of the switch).
return;
default:
panic("OzoneCPU::processICacheCompletion: bad state");
break;
}
}
*/
#if FULL_SYSTEM
template <class Impl>
void
@ -663,7 +518,6 @@ OzoneCPU<Impl>::post_interrupt(int int_num, int index)
{
BaseCPU::post_interrupt(int_num, index);
// if (thread._status == ExecContext::Suspended) {
if (_status == Idle) {
DPRINTF(IPI,"Suspended Processor awoke\n");
// thread.activate();
@ -690,9 +544,6 @@ OzoneCPU<Impl>::tick()
frontEnd->tick();
backEnd->tick();
// Do this here? For now the front end will control the PC.
// PC = nextPC;
// check for instruction-count-based events
comInstEventQueue[0]->serviceEvents(numInst);
@ -742,11 +593,13 @@ OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
if (return_value.successful()) {
// no error
thread.renameTable[SyscallSuccessReg]->setIntResult(0);
thread.renameTable[ReturnValueReg]->setIntResult(return_value.value());
thread.renameTable[ReturnValueReg]->setIntResult(
return_value.value());
} else {
// got an error, return details
thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1);
thread.renameTable[ReturnValueReg]->setIntResult(-return_value.value());
thread.renameTable[ReturnValueReg]->setIntResult(
-return_value.value());
}
}
#else
@ -756,15 +609,10 @@ OzoneCPU<Impl>::hwrei()
{
// Need to move this to ISA code
// May also need to make this per thread
/*
if (!inPalMode())
return new UnimplementedOpcodeFault;
thread.setNextPC(thread.readMiscReg(AlphaISA::IPR_EXC_ADDR));
*/
lockFlag = false;
lockAddrList.clear();
kernelStats->hwrei();
thread.kernelStats->hwrei();
checkInterrupts = true;
@ -835,7 +683,7 @@ OzoneCPU<Impl>::simPalCheck(int palFunc)
{
// Need to move this to ISA code
// May also need to make this per thread
this->kernelStats->callpal(palFunc, xcProxy);
thread.kernelStats->callpal(palFunc, xcProxy);
switch (palFunc) {
case PAL::halt:
@ -874,7 +722,6 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneXC::setStatus(Status new_status)
{
// cpu->_status = new_status;
thread->_status = new_status;
}
@ -932,6 +779,7 @@ OzoneCPU<Impl>::OzoneXC::takeOverFrom(ExecContext *old_context)
setStatus(old_context->status());
copyArchRegs(old_context);
setCpuId(old_context->readCpuId());
#if !FULL_SYSTEM
setFuncExeInst(old_context->readFuncExeInst());
#else
@ -944,6 +792,8 @@ OzoneCPU<Impl>::OzoneXC::takeOverFrom(ExecContext *old_context)
if (thread->quiesceEvent) {
thread->quiesceEvent->xc = this;
}
thread->kernelStats = old_context->getKernelStats();
// storeCondFailures = 0;
cpu->lockFlag = false;
#endif
@ -954,7 +804,12 @@ OzoneCPU<Impl>::OzoneXC::takeOverFrom(ExecContext *old_context)
template <class Impl>
void
OzoneCPU<Impl>::OzoneXC::regStats(const std::string &name)
{ }
{
#if FULL_SYSTEM
thread->kernelStats = new Kernel::Statistics(cpu->system);
thread->kernelStats->regStats(name + ".kern");
#endif
}
template <class Impl>
void

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005 The Regents of The University of Michigan
* Copyright (c) 2005-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -52,8 +52,6 @@ class OzoneDynInst : public BaseDynInst<Impl>
// Typedef for DynInstPtr. This is really just a RefCountingPtr<OoODynInst>.
typedef typename Impl::DynInstPtr DynInstPtr;
// typedef typename Impl::BranchPred::BPredInfo BPredInfo;
typedef TheISA::ExtMachInst ExtMachInst;
typedef TheISA::MachInst MachInst;
typedef TheISA::MiscReg MiscReg;
@ -107,12 +105,6 @@ class OzoneDynInst : public BaseDynInst<Impl>
// up. In the future, you only really need a counter.
bool memDepReady() { return srcMemInsts.empty(); }
// void setBPredInfo(const BPredInfo &bp_info) { bpInfo = bp_info; }
// BPredInfo &getBPredInfo() { return bpInfo; }
// OzoneXC *thread;
private:
void initInstPtrs();
@ -133,20 +125,12 @@ class OzoneDynInst : public BaseDynInst<Impl>
*/
DynInstPtr prevDestInst[MaxInstSrcRegs];
// BPredInfo bpInfo;
public:
Fault initiateAcc();
Fault completeAcc();
/*
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);
*/
// The register accessor methods provide the index of the
// instruction's operand (e.g., 0 or 1), not the architectural
// register index, to simplify the implementation of register
@ -244,38 +228,4 @@ class OzoneDynInst : public BaseDynInst<Impl>
bool iqItValid;
};
/*
template<class Impl>
template<class T>
inline Fault
OzoneDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
{
Fault fault = this->cpu->read(addr, data, flags, this);
if (this->traceData) {
this->traceData->setAddr(addr);
this->traceData->setData(data);
}
return fault;
}
template<class Impl>
template<class T>
inline Fault
OzoneDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
Fault fault = this->cpu->write(data, addr, flags, res, this);
this->storeSize = sizeof(T);
this->storeData = data;
if (this->traceData) {
this->traceData->setAddr(addr);
this->traceData->setData(data);
}
return fault;
}
*/
#endif // __CPU_OZONE_DYN_INST_HH__

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005 The Regents of The University of Michigan
* Copyright (c) 2005-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -266,12 +266,7 @@ OzoneDynInst<Impl>::hwrei()
this->setNextPC(this->thread->readMiscReg(AlphaISA::IPR_EXC_ADDR));
this->cpu->hwrei();
/*
this->cpu->kernelStats->hwrei();
this->cpu->checkInterrupts = true;
this->cpu->lockFlag = false;
*/
// FIXME: XXX check for interrupts? XXX
return NoFault;
}

View file

@ -1,14 +1,39 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#ifndef __CPU_OZONE_FRONT_END_HH__
#define __CPU_OZONE_FRONT_END_HH__
#include <deque>
//#include "cpu/ozone/cpu.hh"
#include "cpu/inst_seq.hh"
#include "cpu/o3/bpred_unit.hh"
#include "cpu/ozone/rename_table.hh"
//#include "cpu/ozone/thread_state.hh"
#include "mem/mem_req.hh"
#include "sim/eventq.hh"
#include "sim/stats.hh"
@ -132,11 +157,6 @@ class FrontEnd
typedef typename Impl::BranchPred BranchPred;
// Typedef for semi-opaque type that holds any information the branch
// predictor needs to update itself. Only two fields are used outside of
// branch predictor, nextPC and isTaken.
// typedef typename BranchPred::BPredInfo BPredInfo;
BranchPred branchPred;
class ICacheCompletionEvent : public Event

View file

@ -1,3 +1,30 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#include "arch/faults.hh"
#include "arch/isa_traits.hh"
@ -26,14 +53,6 @@ FrontEnd<Impl>::FrontEnd(Params *params)
status = Idle;
// Setup branch predictor.
// Setup Memory Request
/*
memReq = new MemReq();
memReq->asid = 0;
memReq->data = new uint8_t[64];
*/
memReq = NULL;
// Size of cache block.
cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
@ -77,7 +96,6 @@ void
FrontEnd<Impl>::setXC(ExecContext *xc_ptr)
{
xc = xc_ptr;
// memReq->xc = xc;
}
template <class Impl>
@ -321,7 +339,6 @@ FrontEnd<Impl>::tick()
break;
}
// if (generalizeFetch) {
processInst(inst);
if (status == SerializeBlocked) {
@ -333,11 +350,6 @@ FrontEnd<Impl>::tick()
instBuffer.push_back(inst);
++instBufferSize;
++num_inst;
// } else {
// fetch(num_inst);
// decode(num_inst);
// rename(num_inst);
// }
#if FULL_SYSTEM
if (inst->isQuiesce()) {
@ -402,10 +414,6 @@ FrontEnd<Impl>::fetchCacheLine()
// Translate the instruction request.
fault = cpu->translateInstReq(memReq);
// In the case of faults, the fetch stage may need to stall and wait
// on what caused the fetch (ITB or Icache miss).
// assert(fault == NoFault);
// Now do the timing access to see whether or not the instruction
// exists within the cache.
if (icacheInterface && fault == NoFault) {
@ -466,7 +474,6 @@ FrontEnd<Impl>::processInst(DynInstPtr &inst)
Addr inst_PC = inst->readPC();
// BPredInfo bp_info = branchPred.lookup(inst_PC);
if (!inst->isControl()) {
inst->setPredTarg(inst->readNextPC());
} else {
@ -482,7 +489,6 @@ FrontEnd<Impl>::processInst(DynInstPtr &inst)
"%#x\n", inst->seqNum, inst_PC, next_PC);
// inst->setNextPC(next_PC);
// inst->setBPredInfo(bp_info);
// Not sure where I should set this
PC = next_PC;
@ -535,7 +541,7 @@ void
FrontEnd<Impl>::handleFault(Fault &fault)
{
DPRINTF(FE, "Fault at fetch, telling commit\n");
// backEnd->fetchFault(fault);
// We're blocked on the back end until it handles this fault.
status = TrapPending;
@ -586,9 +592,6 @@ FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
instBuffer.pop_back();
--instBufferSize;
// Fix up branch predictor if necessary.
// branchPred.undo(inst->getBPredInfo());
freeRegs+= inst->numDestRegs();
}
@ -607,7 +610,6 @@ FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
// Clear the icache miss if it's outstanding.
if (status == IcacheMissStall && icacheInterface) {
DPRINTF(FE, "Squashing outstanding Icache miss.\n");
// icacheInterface->squash(0);
memReq = NULL;
}
@ -693,17 +695,9 @@ template <class Impl>
bool
FrontEnd<Impl>::updateStatus()
{
// bool rename_block = freeRegs <= 0;
bool serialize_block = !backEnd->robEmpty() || instBufferSize;
bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
bool ret_val = false;
/*
// Should already be handled through addFreeRegs function
if (status == RenameBlocked && !rename_block) {
status = Running;
ret_val = true;
}
*/
if (status == SerializeBlocked && !serialize_block) {
status = SerializeComplete;
@ -753,10 +747,6 @@ FrontEnd<Impl>::getInstFromCacheline()
// PC of inst is not in this cache block
if (PC >= (cacheBlkPC + cacheBlkSize) || PC < cacheBlkPC || !cacheBlkValid) {
// DPRINTF(OoOCPU, "OoOCPU: PC is not in this cache block\n");
// DPRINTF(OoOCPU, "OoOCPU: PC: %#x, cacheBlkPC: %#x, cacheBlkValid: %i",
// PC, cacheBlkPC, cacheBlkValid);
// panic("Instruction not in cache line or cache line invalid!");
return NULL;
}

View file

@ -1,3 +1,30 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#ifndef __CPU_OZONE_LW_BACK_END_HH__
#define __CPU_OZONE_LW_BACK_END_HH__
@ -238,10 +265,6 @@ class LWBackEnd
Counter funcExeInst;
private:
// typedef typename Impl::InstQueue InstQueue;
// InstQueue IQ;
typedef typename Impl::LdstQueue LdstQueue;
LdstQueue LSQ;
@ -342,8 +365,6 @@ class LWBackEnd
bool exactFullStall;
// bool fetchRedirect[Impl::MaxThreads];
// number of cycles stalled for D-cache misses
/* Stats::Scalar<> dcacheStallCycles;
Counter lastDcacheStall;
@ -438,43 +459,6 @@ template <class T>
Fault
LWBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx)
{
/* memReq->reset(addr, sizeof(T), flags);
// translate to physical address
Fault fault = cpu->translateDataReadReq(memReq);
// if we have a cache, do cache access too
if (fault == NoFault && dcacheInterface) {
memReq->cmd = Read;
memReq->completionEvent = NULL;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
MemAccessResult result = dcacheInterface->access(memReq);
// Ugly hack to get an event scheduled *only* if the access is
// a miss. We really should add first-class support for this
// at some point.
if (result != MA_HIT && dcacheInterface->doEvents()) {
// Fix this hack for keeping funcExeInst correct with loads that
// are executed twice.
--funcExeInst;
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
// unscheduleTickEvent();
// status = DcacheMissStall;
DPRINTF(OzoneCPU, "Dcache miss stall!\n");
} else {
// do functional access
fault = thread->mem->read(memReq, data);
}
}
*/
/*
if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
recordEvent("Uncached Read");
*/
return LSQ.read(req, data, load_idx);
}
@ -483,39 +467,6 @@ template <class T>
Fault
LWBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx)
{
/*
memReq->reset(addr, sizeof(T), flags);
// translate to physical address
Fault fault = cpu->translateDataWriteReq(memReq);
if (fault == NoFault && dcacheInterface) {
memReq->cmd = Write;
memcpy(memReq->data,(uint8_t *)&data,memReq->size);
memReq->completionEvent = NULL;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
MemAccessResult result = dcacheInterface->access(memReq);
// Ugly hack to get an event scheduled *only* if the access is
// a miss. We really should add first-class support for this
// at some point.
if (result != MA_HIT && dcacheInterface->doEvents()) {
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
// unscheduleTickEvent();
// status = DcacheMissStall;
DPRINTF(OzoneCPU, "Dcache miss stall!\n");
}
}
if (res && (fault == NoFault))
*res = memReq->result;
*/
/*
if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
recordEvent("Uncached Write");
*/
return LSQ.write(req, data, store_idx);
}

View file

@ -1,7 +1,34 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#include "encumbered/cpu/full/op_class.hh"
#include "cpu/checker/cpu.hh"
#include "cpu/ozone/lw_back_end.hh"
#include "encumbered/cpu/full/op_class.hh"
template <class Impl>
void
@ -194,7 +221,6 @@ LWBackEnd<Impl>::LWBackEnd(Params *params)
switchedOut = false;
switchPending = false;
// IQ.setBE(this);
LSQ.setBE(this);
// Setup IQ and LSQ with their parameters here.
@ -202,8 +228,6 @@ LWBackEnd<Impl>::LWBackEnd(Params *params)
instsToExecute = i2e.getWire(-1);
// IQ.setIssueExecQueue(&i2e);
dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width;
issueWidth = params->issueWidth ? params->issueWidth : width;
wbWidth = params->wbWidth ? params->wbWidth : width;
@ -538,8 +562,6 @@ LWBackEnd<Impl>::regStats()
.desc("ROB Occupancy per cycle")
.flags(total | cdf)
;
// IQ.regStats();
}
template <class Impl>
@ -652,17 +674,7 @@ LWBackEnd<Impl>::tick()
squashFromTrap();
} else if (xcSquash) {
squashFromXC();
} /*else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) {
DPRINTF(BE, "ROB and front end empty, handling fetch fault\n");
Fault fetch_fault = frontEnd->getFault();
if (fetch_fault == NoFault) {
DPRINTF(BE, "Fetch no longer has a fault, cancelling out.\n");
fetchHasFault = false;
} else {
handleFault(fetch_fault);
fetchHasFault = false;
}
}*/
}
#endif
if (dispatchStatus != Blocked) {
@ -773,7 +785,8 @@ LWBackEnd<Impl>::dispatchInsts()
inst->iqItValid = true;
waitingInsts++;
} else {
DPRINTF(BE, "Instruction [sn:%lli] ready, addding to exeList.\n",
DPRINTF(BE, "Instruction [sn:%lli] ready, addding to "
"exeList.\n",
inst->seqNum);
exeList.push(inst);
}
@ -784,7 +797,8 @@ LWBackEnd<Impl>::dispatchInsts()
inst->setExecuted();
inst->setCanCommit();
} else {
DPRINTF(BE, "Instruction [sn:%lli] ready, addding to exeList.\n",
DPRINTF(BE, "Instruction [sn:%lli] ready, addding to "
"exeList.\n",
inst->seqNum);
exeList.push(inst);
}
@ -993,7 +1007,7 @@ LWBackEnd<Impl>::instToCommit(DynInstPtr &inst)
writeback_count[0]++;
}
#if 0
template <class Impl>
void
LWBackEnd<Impl>::writebackInsts()
@ -1040,7 +1054,7 @@ LWBackEnd<Impl>::writebackInsts()
consumer_inst[0]+= consumer_insts;
writeback_count[0]+= inst_num;
}
#endif
template <class Impl>
bool
LWBackEnd<Impl>::commitInst(int inst_num)
@ -1219,15 +1233,15 @@ LWBackEnd<Impl>::commitInst(int inst_num)
--numInsts;
++thread->funcExeInst;
// Maybe move this to where the fault is handled; if the fault is handled,
// don't try to set this myself as the fault will set it. If not, then
// I set thread->PC = thread->nextPC and thread->nextPC = thread->nextPC + 4.
// Maybe move this to where the fault is handled; if the fault is
// handled, don't try to set this myself as the fault will set it.
// If not, then I set thread->PC = thread->nextPC and
// thread->nextPC = thread->nextPC + 4.
thread->setPC(thread->readNextPC());
thread->setNextPC(thread->readNextPC() + sizeof(TheISA::MachInst));
updateComInstStats(inst);
// Write the done sequence number here.
// LSQ.commitLoads(inst->seqNum);
toIEW->doneSeqNum = inst->seqNum;
lastCommitCycle = curTick;
@ -1357,7 +1371,8 @@ LWBackEnd<Impl>::squash(const InstSeqNum &sn)
}
while (memBarrier && memBarrier->seqNum > sn) {
DPRINTF(BE, "[sn:%lli] Memory barrier squashed (or previously squashed)\n", memBarrier->seqNum);
DPRINTF(BE, "[sn:%lli] Memory barrier squashed (or previously "
"squashed)\n", memBarrier->seqNum);
memBarrier->clearMemDependents();
if (memBarrier->memDepReady()) {
DPRINTF(BE, "No previous barrier\n");

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -138,7 +138,6 @@ class OzoneLWLSQ {
/** Executes a load instruction. */
Fault executeLoad(DynInstPtr &inst);
// Fault executeLoad(int lq_idx);
/** Executes a store instruction. */
Fault executeStore(DynInstPtr &inst);
@ -304,10 +303,8 @@ class OzoneLWLSQ {
Status _status;
/** The store queue. */
// std::vector<SQEntry> storeQueue;
std::list<SQEntry> storeQueue;
/** The load queue. */
// std::vector<DynInstPtr> loadQueue;
std::list<DynInstPtr> loadQueue;
typedef typename std::list<SQEntry>::iterator SQIt;
@ -365,7 +362,6 @@ class OzoneLWLSQ {
*/
InstSeqNum stallingStoreIsn;
/** The index of the above store. */
// int stallingLoadIdx;
LQIt stallingLoad;
/** Whether or not a load is blocked due to the memory system. It is
@ -398,8 +394,6 @@ class OzoneLWLSQ {
template <class T>
Fault write(MemReqPtr &req, T &data, int store_idx);
/** Returns the index of the head load instruction. */
// int getLoadHead() { return loadHead; }
/** Returns the sequence number of the head load instruction. */
InstSeqNum getLoadHeadSeqNum()
{
@ -411,8 +405,6 @@ class OzoneLWLSQ {
}
/** Returns the index of the head store instruction. */
// int getStoreHead() { return storeHead; }
/** Returns the sequence number of the head store instruction. */
InstSeqNum getStoreHeadSeqNum()
{
@ -604,12 +596,7 @@ OzoneLWLSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx)
DPRINTF(OzoneLSQ, "D-cache: PC:%#x reading from paddr:%#x "
"vaddr:%#x flags:%i\n",
inst->readPC(), req->paddr, req->vaddr, req->flags);
/*
Addr debug_addr = ULL(0xfffffc0000be81a8);
if (req->vaddr == debug_addr) {
debug_break();
}
*/
assert(!req->completionEvent);
req->completionEvent =
new typename BackEnd::LdWritebackEvent(inst, be);
@ -631,9 +618,6 @@ OzoneLWLSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx)
_status = DcacheMissStall;
} else {
// DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
// inst->seqNum);
DPRINTF(OzoneLSQ, "D-cache hit!\n");
}
} else {
@ -664,12 +648,7 @@ OzoneLWLSQ<Impl>::write(MemReqPtr &req, T &data, int store_idx)
assert(!req->data);
req->data = new uint8_t[64];
memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size);
/*
Addr debug_addr = ULL(0xfffffc0000be81a8);
if (req->vaddr == debug_addr) {
debug_break();
}
*/
// This function only writes the data to the store queue, so no fault
// can happen here.
return NoFault;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -104,12 +104,6 @@ OzoneLWLSQ<Impl>::init(Params *params, unsigned maxLQEntries,
SQIndices.push(i);
}
// May want to initialize these entries to NULL
// loadHead = loadTail = 0;
// storeHead = storeWBIdx = storeTail = 0;
usedPorts = 0;
cachePorts = params->cachePorts;
@ -197,8 +191,6 @@ OzoneLWLSQ<Impl>::insert(DynInstPtr &inst)
} else {
insertStore(inst);
}
// inst->setInLSQ();
}
template <class Impl>
@ -569,12 +561,9 @@ OzoneLWLSQ<Impl>::writebackStores()
}
if (result != MA_HIT && dcacheInterface->doEvents()) {
// Event *wb = NULL;
store_event->miss = true;
typename BackEnd::LdWritebackEvent *wb = NULL;
if (req->flags & LOCKED) {
// Stx_C does not generate a system port transaction.
// req->result=1;
wb = new typename BackEnd::LdWritebackEvent(inst,
be);
store_event->wbEvent = wb;
@ -585,8 +574,6 @@ OzoneLWLSQ<Impl>::writebackStores()
// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
// inst->seqNum);
// Will stores need their own kind of writeback events?
// Do stores even need writeback events?
be->addDcacheMiss(inst);
lastDcacheStall = curTick;
@ -604,20 +591,16 @@ OzoneLWLSQ<Impl>::writebackStores()
// inst->seqNum);
if (req->flags & LOCKED) {
// Stx_C does not generate a system port transaction.
/* if (req->flags & UNCACHEABLE) {
req->result = 2;
} else {
req->result = 1;
}
*/
// Stx_C does not generate a system port
// transaction in the 21264, but that might be
// hard to accomplish in this model.
typename BackEnd::LdWritebackEvent *wb =
new typename BackEnd::LdWritebackEvent(inst,
be);
store_event->wbEvent = wb;
}
sq_it--;
// completeStore(inst->sqIdx);
}
} else {
panic("Must HAVE DCACHE!!!!!\n");
@ -780,7 +763,7 @@ OzoneLWLSQ<Impl>::completeStore(int store_idx)
SQIndices.push(inst->sqIdx);
storeQueue.erase(sq_it);
--stores;
// assert(!inst->isCompleted());
inst->setCompleted();
if (cpu->checker) {
cpu->checker->tick(inst);
@ -791,7 +774,6 @@ template <class Impl>
void
OzoneLWLSQ<Impl>::switchOut()
{
// assert(loads == 0);
assert(storesToWB == 0);
switchedOut = true;
SQIt sq_it = --(storeQueue.end());
@ -804,8 +786,6 @@ OzoneLWLSQ<Impl>::switchOut()
if ((*sq_it).size == 0 && !(*sq_it).completed) {
sq_it--;
// completeStore(inst->sqIdx);
continue;
}
@ -817,7 +797,8 @@ OzoneLWLSQ<Impl>::switchOut()
continue;
} else if ((*sq_it).req->flags & LOCKED) {
sq_it--;
assert(!(*sq_it).canWB || ((*sq_it).canWB && (*sq_it).req->flags & LOCKED));
assert(!(*sq_it).canWB ||
((*sq_it).canWB && (*sq_it).req->flags & LOCKED));
continue;
}
@ -886,12 +867,6 @@ OzoneLWLSQ<Impl>::takeOverFrom(ExecContext *old_xc)
SQIndices.push(i);
}
// May want to initialize these entries to NULL
// loadHead = loadTail = 0;
// storeHead = storeWBIdx = storeTail = 0;
usedPorts = 0;
loadFaultInst = storeFaultInst = memDepViolator = NULL;

View file

@ -1,3 +1,31 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#ifndef __CPU_OZONE_RENAME_TABLE_HH__
#define __CPU_OZONE_RENAME_TABLE_HH__

View file

@ -1,3 +1,30 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#ifndef __CPU_OZONE_THREAD_STATE_HH__
#define __CPU_OZONE_THREAD_STATE_HH__
@ -62,19 +89,14 @@ struct OzoneThreadState : public ThreadState {
void setStatus(Status new_status) { _status = new_status; }
RenameTable<Impl> renameTable; // Should I include backend and frontend
// tables here? For the ozone CPU, maybe, for the new full CPU, probably
// not...you wouldn't want threads just accessing the backend/frontend
// rename tables.
Addr PC; // What should these be set to? Probably the committed ones.
RenameTable<Impl> renameTable;
Addr PC;
Addr nextPC;
// Current instruction?
// Current instruction
TheISA::MachInst inst;
TheISA::RegFile regs;
// Front end? Back end?
// MemReqPtr memReq;
typename Impl::FullCPU *cpu;

View file

@ -782,7 +782,7 @@ SimpleCPU::tick()
#if FULL_SYSTEM
if (system->kernelBinning->fnbin) {
assert(kernelStats);
assert(cpuXC->getKernelStats());
system->kernelBinning->execute(xcProxy, inst);
}

View file

@ -1,3 +1,30 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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.
*/
#ifndef __CPU_THREAD_STATE_HH__
#define __CPU_THREAD_STATE_HH__
@ -8,11 +35,20 @@
class EndQuiesceEvent;
class FunctionProfile;
class ProfileNode;
namespace Kernel {
class Statistics;
};
#else
class Process;
class FunctionalMemory;
class Process;
#endif
/**
* Struct for holding general thread state that is needed across CPU
* models. This includes things such as pointers to the process,
* memory, quiesce events, and certain stats. This can be expanded
* to hold more thread-specific stats within it.
*/
struct ThreadState {
#if FULL_SYSTEM
ThreadState(int _cpuId, int _tid, FunctionalMemory *_mem)
@ -55,6 +91,7 @@ struct ThreadState {
EndQuiesceEvent *quiesceEvent;
Kernel::Statistics *kernelStats;
#else
Process *process;

View file

@ -67,15 +67,17 @@ FnEvent::process(ExecContext *xc)
void
IdleStartEvent::process(ExecContext *xc)
{
xc->getCpuPtr()->kernelStats->setIdleProcess(
xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc);
if (xc->getKernelStats())
xc->getKernelStats()->setIdleProcess(
xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc);
remove();
}
void
InterruptStartEvent::process(ExecContext *xc)
{
xc->getCpuPtr()->kernelStats->mode(Kernel::interrupt, xc);
if (xc->getKernelStats())
xc->getKernelStats()->mode(Kernel::interrupt, xc);
}
void
@ -83,5 +85,6 @@ InterruptEndEvent::process(ExecContext *xc)
{
// We go back to kernel, if we are user, inside the rti
// pal code we will get switched to user because of the ICM write
xc->getCpuPtr()->kernelStats->mode(Kernel::kernel, xc);
if (xc->getKernelStats())
xc->getKernelStats()->mode(Kernel::kernel, xc);
}

View file

@ -65,7 +65,8 @@ namespace AlphaPseudo
void
arm(ExecContext *xc)
{
xc->getCpuPtr()->kernelStats->arm();
if (xc->getKernelStats())
xc->getKernelStats()->arm();
}
void
@ -75,7 +76,8 @@ namespace AlphaPseudo
return;
xc->suspend();
xc->getCpuPtr()->kernelStats->quiesce();
if (xc->getKernelStats())
xc->getKernelStats()->arm();
}
void
@ -92,7 +94,8 @@ namespace AlphaPseudo
quiesceEvent->schedule(curTick + Clock::Int::ns * ns);
xc->suspend();
xc->getCpuPtr()->kernelStats->quiesce();
if (xc->getKernelStats())
xc->getKernelStats()->quiesce();
}
void
@ -111,7 +114,8 @@ namespace AlphaPseudo
xc->getCpuPtr()->cycles(cycles));
xc->suspend();
xc->getCpuPtr()->kernelStats->quiesce();
if (xc->getKernelStats())
xc->getKernelStats()->quiesce();
}
uint64_t
@ -123,7 +127,8 @@ namespace AlphaPseudo
void
ivlb(ExecContext *xc)
{
xc->getCpuPtr()->kernelStats->ivlb();
if (xc->getKernelStats())
xc->getKernelStats()->ivlb();
}
void