Adding gem5 source to svn.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1819 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
35
simulators/gem5/src/cpu/checker/SConsopts
Normal file
35
simulators/gem5/src/cpu/checker/SConsopts
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- mode:python -*-
|
||||
|
||||
# Copyright (c) 2003-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.
|
||||
#
|
||||
# Authors: Steve Reinhardt
|
||||
|
||||
Import('*')
|
||||
|
||||
CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
|
||||
'#include "cpu/checker/cpu.hh"',
|
||||
{ 'CPU_exec_context': 'CheckerCPU' })
|
||||
353
simulators/gem5/src/cpu/checker/cpu.cc
Normal file
353
simulators/gem5/src/cpu/checker/cpu.cc
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Authors: Kevin Lim
|
||||
* Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "arch/kernel_stats.hh"
|
||||
#include "arch/vtophys.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "params/CheckerCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/tlb.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
void
|
||||
CheckerCPU::init()
|
||||
{
|
||||
masterId = systemPtr->getMasterId(name());
|
||||
}
|
||||
|
||||
CheckerCPU::CheckerCPU(Params *p)
|
||||
: BaseCPU(p, true), thread(NULL), tc(NULL)
|
||||
{
|
||||
memReq = NULL;
|
||||
curStaticInst = NULL;
|
||||
curMacroStaticInst = NULL;
|
||||
|
||||
numInst = 0;
|
||||
startNumInst = 0;
|
||||
numLoad = 0;
|
||||
startNumLoad = 0;
|
||||
youngestSN = 0;
|
||||
|
||||
changedPC = willChangePC = changedNextPC = false;
|
||||
|
||||
exitOnError = p->exitOnError;
|
||||
warnOnlyOnLoadError = p->warnOnlyOnLoadError;
|
||||
itb = p->itb;
|
||||
dtb = p->dtb;
|
||||
systemPtr = NULL;
|
||||
workload = p->workload;
|
||||
thread = NULL;
|
||||
|
||||
updateOnError = true;
|
||||
}
|
||||
|
||||
CheckerCPU::~CheckerCPU()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::setSystem(System *system)
|
||||
{
|
||||
systemPtr = system;
|
||||
|
||||
if (FullSystem) {
|
||||
thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false);
|
||||
} else {
|
||||
thread = new SimpleThread(this, 0, systemPtr,
|
||||
workload.size() ? workload[0] : NULL,
|
||||
itb, dtb);
|
||||
}
|
||||
|
||||
tc = thread->getTC();
|
||||
threadContexts.push_back(tc);
|
||||
thread->kernelStats = NULL;
|
||||
// Thread should never be null after this
|
||||
assert(thread != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::setIcachePort(CpuPort *icache_port)
|
||||
{
|
||||
icachePort = icache_port;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::setDcachePort(CpuPort *dcache_port)
|
||||
{
|
||||
dcachePort = dcache_port;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::serialize(ostream &os)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::unserialize(Checkpoint *cp, const string §ion)
|
||||
{
|
||||
}
|
||||
|
||||
Fault
|
||||
CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
|
||||
{
|
||||
Fault fault = NoFault;
|
||||
unsigned blockSize = dcachePort->peerBlockSize();
|
||||
int fullSize = size;
|
||||
Addr secondAddr = roundDown(addr + size - 1, blockSize);
|
||||
bool checked_flags = false;
|
||||
bool flags_match = true;
|
||||
Addr pAddr = 0x0;
|
||||
|
||||
|
||||
if (secondAddr > addr)
|
||||
size = secondAddr - addr;
|
||||
|
||||
// Need to account for multiple accesses like the Atomic and TimingSimple
|
||||
while (1) {
|
||||
memReq = new Request();
|
||||
memReq->setVirt(0, addr, size, flags, masterId, thread->pcState().instAddr());
|
||||
|
||||
// translate to physical address
|
||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
|
||||
|
||||
if (!checked_flags && fault == NoFault && unverifiedReq) {
|
||||
flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
|
||||
memReq->getPaddr(), memReq->getFlags());
|
||||
pAddr = memReq->getPaddr();
|
||||
checked_flags = true;
|
||||
}
|
||||
|
||||
// Now do the access
|
||||
if (fault == NoFault &&
|
||||
!memReq->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
PacketPtr pkt = new Packet(memReq,
|
||||
memReq->isLLSC() ?
|
||||
MemCmd::LoadLockedReq :
|
||||
MemCmd::ReadReq);
|
||||
|
||||
pkt->dataStatic(data);
|
||||
|
||||
if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) {
|
||||
// Access memory to see if we have the same data
|
||||
dcachePort->sendFunctional(pkt);
|
||||
} else {
|
||||
// Assume the data is correct if it's an uncached access
|
||||
memcpy(data, unverifiedMemData, size);
|
||||
}
|
||||
|
||||
delete memReq;
|
||||
memReq = NULL;
|
||||
delete pkt;
|
||||
}
|
||||
|
||||
if (fault != NoFault) {
|
||||
if (memReq->isPrefetch()) {
|
||||
fault = NoFault;
|
||||
}
|
||||
delete memReq;
|
||||
memReq = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (memReq != NULL) {
|
||||
delete memReq;
|
||||
}
|
||||
|
||||
//If we don't need to access a second cache line, stop now.
|
||||
if (secondAddr <= addr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup for accessing next cache line
|
||||
data += size;
|
||||
unverifiedMemData += size;
|
||||
size = addr + fullSize - secondAddr;
|
||||
addr = secondAddr;
|
||||
}
|
||||
|
||||
if (!flags_match) {
|
||||
warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
|
||||
curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
|
||||
unverifiedReq->getFlags(), addr, pAddr, flags);
|
||||
handleError();
|
||||
}
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
Fault
|
||||
CheckerCPU::writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
Fault fault = NoFault;
|
||||
bool checked_flags = false;
|
||||
bool flags_match = true;
|
||||
Addr pAddr = 0x0;
|
||||
|
||||
unsigned blockSize = dcachePort->peerBlockSize();
|
||||
int fullSize = size;
|
||||
|
||||
Addr secondAddr = roundDown(addr + size - 1, blockSize);
|
||||
|
||||
if (secondAddr > addr)
|
||||
size = secondAddr - addr;
|
||||
|
||||
// Need to account for a multiple access like Atomic and Timing CPUs
|
||||
while (1) {
|
||||
memReq = new Request();
|
||||
memReq->setVirt(0, addr, size, flags, masterId, thread->pcState().instAddr());
|
||||
|
||||
// translate to physical address
|
||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
|
||||
|
||||
if (!checked_flags && fault == NoFault && unverifiedReq) {
|
||||
flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
|
||||
memReq->getPaddr(), memReq->getFlags());
|
||||
pAddr = memReq->getPaddr();
|
||||
checked_flags = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't actually check memory for the store because there
|
||||
* is no guarantee it has left the lsq yet, and therefore we
|
||||
* can't verify the memory on stores without lsq snooping
|
||||
* enabled. This is left as future work for the Checker: LSQ snooping
|
||||
* and memory validation after stores have committed.
|
||||
*/
|
||||
bool was_prefetch = memReq->isPrefetch();
|
||||
|
||||
delete memReq;
|
||||
|
||||
//If we don't need to access a second cache line, stop now.
|
||||
if (fault != NoFault || secondAddr <= addr)
|
||||
{
|
||||
if (fault != NoFault && was_prefetch) {
|
||||
fault = NoFault;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//Update size and access address
|
||||
size = addr + fullSize - secondAddr;
|
||||
//And access the right address.
|
||||
addr = secondAddr;
|
||||
}
|
||||
|
||||
if (!flags_match) {
|
||||
warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
|
||||
curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
|
||||
unverifiedReq->getFlags(), addr, pAddr, flags);
|
||||
handleError();
|
||||
}
|
||||
|
||||
// Assume the result was the same as the one passed in. This checker
|
||||
// doesn't check if the SC should succeed or fail, it just checks the
|
||||
// value.
|
||||
if (unverifiedReq && res && unverifiedReq->extraDataValid())
|
||||
*res = unverifiedReq->getExtraData();
|
||||
|
||||
// Entire purpose here is to make sure we are getting the
|
||||
// same data to send to the mem system as the CPU did.
|
||||
// Cannot check this is actually what went to memory because
|
||||
// there stores can be in ld/st queue or coherent operations
|
||||
// overwriting values.
|
||||
bool extraData;
|
||||
if (unverifiedReq) {
|
||||
extraData = unverifiedReq->extraDataValid() ?
|
||||
unverifiedReq->getExtraData() : 1;
|
||||
}
|
||||
|
||||
if (unverifiedReq && unverifiedMemData &&
|
||||
memcmp(data, unverifiedMemData, fullSize) && extraData) {
|
||||
warn("%lli: Store value does not match value sent to memory!\
|
||||
data: %#x inst_data: %#x", curTick(), data,
|
||||
unverifiedMemData);
|
||||
handleError();
|
||||
}
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
Addr
|
||||
CheckerCPU::dbg_vtophys(Addr addr)
|
||||
{
|
||||
return vtophys(tc, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the flags set by the Checker and Checkee match.
|
||||
*/
|
||||
bool
|
||||
CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr,
|
||||
Addr pAddr, int flags)
|
||||
{
|
||||
Addr unverifiedVAddr = unverified_req->getVaddr();
|
||||
Addr unverifiedPAddr = unverified_req->getPaddr();
|
||||
int unverifiedFlags = unverified_req->getFlags();
|
||||
|
||||
if (unverifiedVAddr != vAddr ||
|
||||
unverifiedPAddr != pAddr ||
|
||||
unverifiedFlags != flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::dumpAndExit()
|
||||
{
|
||||
warn("%lli: Checker PC:%s",
|
||||
curTick(), thread->pcState());
|
||||
panic("Checker found an error!");
|
||||
}
|
||||
438
simulators/gem5/src/cpu/checker/cpu.hh
Normal file
438
simulators/gem5/src/cpu/checker/cpu.hh
Normal file
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Authors: Kevin Lim
|
||||
*/
|
||||
|
||||
#ifndef __CPU_CHECKER_CPU_HH__
|
||||
#define __CPU_CHECKER_CPU_HH__
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include "arch/types.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/pc_event.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "debug/Checker.hh"
|
||||
#include "params/CheckerCPU.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
// forward declarations
|
||||
namespace TheISA
|
||||
{
|
||||
class TLB;
|
||||
}
|
||||
|
||||
template <class>
|
||||
class BaseDynInst;
|
||||
class ThreadContext;
|
||||
class Request;
|
||||
|
||||
/**
|
||||
* CheckerCPU class. Dynamically verifies instructions as they are
|
||||
* completed by making sure that the instruction and its results match
|
||||
* the independent execution of the benchmark inside the checker. The
|
||||
* checker verifies instructions in order, regardless of the order in
|
||||
* which instructions complete. There are certain results that can
|
||||
* not be verified, specifically the result of a store conditional or
|
||||
* the values of uncached accesses. In these cases, and with
|
||||
* instructions marked as "IsUnverifiable", the checker assumes that
|
||||
* the value from the main CPU's execution is correct and simply
|
||||
* copies that value. It provides a CheckerThreadContext (see
|
||||
* checker/thread_context.hh) that provides hooks for updating the
|
||||
* Checker's state through any ThreadContext accesses. This allows the
|
||||
* checker to be able to correctly verify instructions, even with
|
||||
* external accesses to the ThreadContext that change state.
|
||||
*/
|
||||
class CheckerCPU : public BaseCPU
|
||||
{
|
||||
protected:
|
||||
typedef TheISA::MachInst MachInst;
|
||||
typedef TheISA::FloatReg FloatReg;
|
||||
typedef TheISA::FloatRegBits FloatRegBits;
|
||||
typedef TheISA::MiscReg MiscReg;
|
||||
|
||||
/** id attached to all issued requests */
|
||||
MasterID masterId;
|
||||
public:
|
||||
virtual void init();
|
||||
|
||||
public:
|
||||
typedef CheckerCPUParams Params;
|
||||
const Params *params() const
|
||||
{ return reinterpret_cast<const Params *>(_params); }
|
||||
CheckerCPU(Params *p);
|
||||
virtual ~CheckerCPU();
|
||||
|
||||
std::vector<Process*> workload;
|
||||
|
||||
void setSystem(System *system);
|
||||
|
||||
System *systemPtr;
|
||||
|
||||
void setIcachePort(CpuPort *icache_port);
|
||||
|
||||
CpuPort *icachePort;
|
||||
|
||||
void setDcachePort(CpuPort *dcache_port);
|
||||
|
||||
CpuPort *dcachePort;
|
||||
|
||||
CpuPort &getDataPort()
|
||||
{
|
||||
panic("Not supported on checker!");
|
||||
return *dcachePort;
|
||||
}
|
||||
|
||||
CpuPort &getInstPort()
|
||||
{
|
||||
panic("Not supported on checker!");
|
||||
return *icachePort;
|
||||
}
|
||||
|
||||
public:
|
||||
// Primary thread being run.
|
||||
SimpleThread *thread;
|
||||
|
||||
ThreadContext *tc;
|
||||
|
||||
TheISA::TLB *itb;
|
||||
TheISA::TLB *dtb;
|
||||
|
||||
Addr dbg_vtophys(Addr addr);
|
||||
|
||||
union Result {
|
||||
uint64_t integer;
|
||||
double dbl;
|
||||
void set(uint64_t i) { integer = i; }
|
||||
void set(double d) { dbl = d; }
|
||||
void get(uint64_t& i) { i = integer; }
|
||||
void get(double& d) { d = dbl; }
|
||||
};
|
||||
|
||||
// ISAs like ARM can have multiple destination registers to check,
|
||||
// keep them all in a std::queue
|
||||
std::queue<Result> result;
|
||||
|
||||
// Pointer to the one memory request.
|
||||
RequestPtr memReq;
|
||||
|
||||
StaticInstPtr curStaticInst;
|
||||
StaticInstPtr curMacroStaticInst;
|
||||
|
||||
// number of simulated instructions
|
||||
Counter numInst;
|
||||
Counter startNumInst;
|
||||
|
||||
std::queue<int> miscRegIdxs;
|
||||
|
||||
TheISA::TLB* getITBPtr() { return itb; }
|
||||
TheISA::TLB* getDTBPtr() { return dtb; }
|
||||
|
||||
virtual Counter totalInsts() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Counter totalOps() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// number of simulated loads
|
||||
Counter numLoad;
|
||||
Counter startNumLoad;
|
||||
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
// These functions are only used in CPU models that split
|
||||
// effective address computation from the actual memory access.
|
||||
void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
|
||||
Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
|
||||
|
||||
// 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
|
||||
// renaming. We find the architectural register index by indexing
|
||||
// into the instruction's own operand index table. Note that a
|
||||
// raw pointer to the StaticInst is provided instead of a
|
||||
// ref-counted StaticInstPtr to redice overhead. This is fine as
|
||||
// long as these methods don't copy the pointer into any long-term
|
||||
// storage (which is pretty hard to imagine they would have reason
|
||||
// to do).
|
||||
|
||||
uint64_t readIntRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
return thread->readIntReg(si->srcRegIdx(idx));
|
||||
}
|
||||
|
||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
return thread->readFloatReg(reg_idx);
|
||||
}
|
||||
|
||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
return thread->readFloatRegBits(reg_idx);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void setResult(T t)
|
||||
{
|
||||
Result instRes;
|
||||
instRes.set(t);
|
||||
result.push(instRes);
|
||||
}
|
||||
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
thread->setIntReg(si->destRegIdx(idx), val);
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
thread->setFloatReg(reg_idx, val);
|
||||
setResult<double>(val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
FloatRegBits val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
thread->setFloatRegBits(reg_idx, val);
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
bool readPredicate() { return thread->readPredicate(); }
|
||||
void setPredicate(bool val)
|
||||
{
|
||||
thread->setPredicate(val);
|
||||
}
|
||||
|
||||
TheISA::PCState pcState() { return thread->pcState(); }
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{
|
||||
DPRINTF(Checker, "Changing PC to %s, old PC %s.\n",
|
||||
val, thread->pcState());
|
||||
thread->pcState(val);
|
||||
}
|
||||
Addr instAddr() { return thread->instAddr(); }
|
||||
Addr nextInstAddr() { return thread->nextInstAddr(); }
|
||||
MicroPC microPC() { return thread->microPC(); }
|
||||
//////////////////////////////////////////
|
||||
|
||||
MiscReg readMiscRegNoEffect(int misc_reg)
|
||||
{
|
||||
return thread->readMiscRegNoEffect(misc_reg);
|
||||
}
|
||||
|
||||
MiscReg readMiscReg(int misc_reg)
|
||||
{
|
||||
return thread->readMiscReg(misc_reg);
|
||||
}
|
||||
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
miscRegIdxs.push(misc_reg);
|
||||
return thread->setMiscRegNoEffect(misc_reg, val);
|
||||
}
|
||||
|
||||
void setMiscReg(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
miscRegIdxs.push(misc_reg);
|
||||
return thread->setMiscReg(misc_reg, val);
|
||||
}
|
||||
|
||||
MiscReg readMiscRegOperand(const StaticInst *si, int idx)
|
||||
{
|
||||
int reg_idx = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->readMiscReg(reg_idx);
|
||||
}
|
||||
|
||||
void setMiscRegOperand(
|
||||
const StaticInst *si, int idx, const MiscReg &val)
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
|
||||
return thread->setMiscReg(reg_idx, val);
|
||||
}
|
||||
|
||||
#if THE_ISA == MIPS_ISA
|
||||
uint64_t readRegOtherThread(int misc_reg)
|
||||
{
|
||||
panic("MIPS MT not defined for CheckerCPU.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
|
||||
{
|
||||
panic("MIPS MT not defined for CheckerCPU.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
void recordPCChange(const TheISA::PCState &val)
|
||||
{
|
||||
changedPC = true;
|
||||
newPCState = val;
|
||||
}
|
||||
|
||||
void demapPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
this->itb->demapPage(vaddr, asn);
|
||||
this->dtb->demapPage(vaddr, asn);
|
||||
}
|
||||
|
||||
void demapInstPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
this->itb->demapPage(vaddr, asn);
|
||||
}
|
||||
|
||||
void demapDataPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
this->dtb->demapPage(vaddr, asn);
|
||||
}
|
||||
|
||||
Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
|
||||
Fault writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
void setStCondFailures(unsigned sc_failures)
|
||||
{}
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
Fault hwrei() { return thread->hwrei(); }
|
||||
bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
|
||||
void wakeup() { }
|
||||
// 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(uint64_t callnum) { }
|
||||
|
||||
void handleError()
|
||||
{
|
||||
if (exitOnError)
|
||||
dumpAndExit();
|
||||
}
|
||||
|
||||
bool checkFlags(Request *unverified_req, Addr vAddr,
|
||||
Addr pAddr, int flags);
|
||||
|
||||
void dumpAndExit();
|
||||
|
||||
ThreadContext *tcBase() { return tc; }
|
||||
SimpleThread *threadBase() { return thread; }
|
||||
|
||||
Result unverifiedResult;
|
||||
Request *unverifiedReq;
|
||||
uint8_t *unverifiedMemData;
|
||||
|
||||
bool changedPC;
|
||||
bool willChangePC;
|
||||
TheISA::PCState newPCState;
|
||||
bool changedNextPC;
|
||||
bool exitOnError;
|
||||
bool updateOnError;
|
||||
bool warnOnlyOnLoadError;
|
||||
|
||||
InstSeqNum youngestSN;
|
||||
};
|
||||
|
||||
/**
|
||||
* Templated Checker class. This Checker class is templated on the
|
||||
* DynInstPtr of the instruction type that will be verified. Proper
|
||||
* template instantiations of the Checker must be placed at the bottom
|
||||
* of checker/cpu.cc.
|
||||
*/
|
||||
template <class Impl>
|
||||
class Checker : public CheckerCPU
|
||||
{
|
||||
private:
|
||||
typedef typename Impl::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
Checker(Params *p)
|
||||
: CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
|
||||
{ }
|
||||
|
||||
void switchOut();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
void advancePC(Fault fault);
|
||||
|
||||
void verify(DynInstPtr &inst);
|
||||
|
||||
void validateInst(DynInstPtr &inst);
|
||||
void validateExecution(DynInstPtr &inst);
|
||||
void validateState();
|
||||
|
||||
void copyResult(DynInstPtr &inst, uint64_t mismatch_val, int start_idx);
|
||||
void handlePendingInt();
|
||||
|
||||
private:
|
||||
void handleError(DynInstPtr &inst)
|
||||
{
|
||||
if (exitOnError) {
|
||||
dumpAndExit(inst);
|
||||
} else if (updateOnError) {
|
||||
updateThisCycle = true;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpAndExit(DynInstPtr &inst);
|
||||
|
||||
bool updateThisCycle;
|
||||
|
||||
DynInstPtr unverifiedInst;
|
||||
|
||||
std::list<DynInstPtr> instList;
|
||||
typedef typename std::list<DynInstPtr>::iterator InstListIt;
|
||||
void dumpInsts();
|
||||
};
|
||||
|
||||
#endif // __CPU_CHECKER_CPU_HH__
|
||||
670
simulators/gem5/src/cpu/checker/cpu_impl.hh
Normal file
670
simulators/gem5/src/cpu/checker/cpu_impl.hh
Normal file
@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Authors: Kevin Lim
|
||||
* Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/vtophys.hh"
|
||||
#include "base/refcnt.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "debug/Checker.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/stats.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::advancePC(Fault fault)
|
||||
{
|
||||
if (fault != NoFault) {
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
fault->invoke(tc, curStaticInst);
|
||||
thread->decoder.reset();
|
||||
} else {
|
||||
if (curStaticInst) {
|
||||
if (curStaticInst->isLastMicroop())
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
TheISA::PCState pcState = thread->pcState();
|
||||
TheISA::advancePC(pcState, curStaticInst);
|
||||
thread->pcState(pcState);
|
||||
DPRINTF(Checker, "Advancing PC to %s.\n", thread->pcState());
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::handlePendingInt()
|
||||
{
|
||||
DPRINTF(Checker, "IRQ detected at PC: %s with %d insts in buffer\n",
|
||||
thread->pcState(), instList.size());
|
||||
DynInstPtr boundaryInst = NULL;
|
||||
if (!instList.empty()) {
|
||||
// Set the instructions as completed and verify as much as possible.
|
||||
DynInstPtr inst;
|
||||
typename std::list<DynInstPtr>::iterator itr;
|
||||
|
||||
for (itr = instList.begin(); itr != instList.end(); itr++) {
|
||||
(*itr)->setCompleted();
|
||||
}
|
||||
|
||||
inst = instList.front();
|
||||
boundaryInst = instList.back();
|
||||
verify(inst); // verify the instructions
|
||||
inst = NULL;
|
||||
}
|
||||
if ((!boundaryInst && curMacroStaticInst &&
|
||||
curStaticInst->isDelayedCommit() &&
|
||||
!curStaticInst->isLastMicroop()) ||
|
||||
(boundaryInst && boundaryInst->isDelayedCommit() &&
|
||||
!boundaryInst->isLastMicroop())) {
|
||||
panic("%lli: Trying to take an interrupt in middle of "
|
||||
"a non-interuptable instruction!", curTick());
|
||||
}
|
||||
boundaryInst = NULL;
|
||||
thread->decoder.reset();
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::verify(DynInstPtr &completed_inst)
|
||||
{
|
||||
DynInstPtr inst;
|
||||
|
||||
// Make sure serializing instructions are actually
|
||||
// seen as serializing to commit. instList should be
|
||||
// empty in these cases.
|
||||
if ((completed_inst->isSerializing() ||
|
||||
completed_inst->isSerializeBefore()) &&
|
||||
(!instList.empty() ?
|
||||
(instList.front()->seqNum != completed_inst->seqNum) : 0)) {
|
||||
panic("%lli: Instruction sn:%lli at PC %s is serializing before but is"
|
||||
" entering instList with other instructions\n", curTick(),
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
}
|
||||
|
||||
// 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:%s to list\n",
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
instList.push_back(completed_inst);
|
||||
youngestSN = completed_inst->seqNum;
|
||||
}
|
||||
|
||||
if (!instList.front()->isCompleted()) {
|
||||
return;
|
||||
} else {
|
||||
inst = instList.front();
|
||||
instList.pop_front();
|
||||
}
|
||||
} else {
|
||||
if (!completed_inst->isCompleted()) {
|
||||
if (youngestSN < completed_inst->seqNum) {
|
||||
DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
instList.push_back(completed_inst);
|
||||
youngestSN = completed_inst->seqNum;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (youngestSN < completed_inst->seqNum) {
|
||||
inst = completed_inst;
|
||||
youngestSN = completed_inst->seqNum;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure a serializing instruction is actually seen as
|
||||
// serializing. instList should be empty here
|
||||
if (inst->isSerializeAfter() && !instList.empty()) {
|
||||
panic("%lli: Instruction sn:%lli at PC %s is serializing after but is"
|
||||
" exiting instList with other instructions\n", curTick(),
|
||||
completed_inst->seqNum, completed_inst->pcState());
|
||||
}
|
||||
unverifiedInst = inst;
|
||||
inst = NULL;
|
||||
|
||||
// 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:%s.\n",
|
||||
unverifiedInst->seqNum, unverifiedInst->pcState());
|
||||
unverifiedReq = NULL;
|
||||
unverifiedReq = unverifiedInst->reqToVerify;
|
||||
unverifiedMemData = unverifiedInst->memData;
|
||||
// Make sure results queue is empty
|
||||
while (!result.empty()) {
|
||||
result.pop();
|
||||
}
|
||||
numCycles++;
|
||||
|
||||
Fault fault = NoFault;
|
||||
|
||||
// maintain $r0 semantics
|
||||
thread->setIntReg(ZeroReg, 0);
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
thread->setFloatReg(ZeroReg, 0.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 %s\n",
|
||||
thread->pcState());
|
||||
if (willChangePC) {
|
||||
if (newPCState == thread->pcState()) {
|
||||
DPRINTF(Checker, "Changed PC matches expected PC\n");
|
||||
} else {
|
||||
warn("%lli: Changed PC does not match expected PC, "
|
||||
"changed: %s, expected: %s",
|
||||
curTick(), thread->pcState(), newPCState);
|
||||
CheckerCPU::handleError();
|
||||
}
|
||||
willChangePC = false;
|
||||
}
|
||||
changedPC = false;
|
||||
}
|
||||
if (changedNextPC) {
|
||||
DPRINTF(Checker, "Changed NextPC recently to %#x\n",
|
||||
thread->nextInstAddr());
|
||||
changedNextPC = false;
|
||||
}
|
||||
|
||||
// Try to fetch the instruction
|
||||
uint64_t fetchOffset = 0;
|
||||
bool fetchDone = false;
|
||||
|
||||
while (!fetchDone) {
|
||||
Addr fetch_PC = thread->instAddr();
|
||||
fetch_PC = (fetch_PC & PCMask) + fetchOffset;
|
||||
|
||||
MachInst machInst;
|
||||
|
||||
// If not in the middle of a macro instruction
|
||||
if (!curMacroStaticInst) {
|
||||
// set up memory request for instruction fetch
|
||||
memReq = new Request(unverifiedInst->threadNumber, fetch_PC,
|
||||
sizeof(MachInst),
|
||||
0,
|
||||
masterId,
|
||||
fetch_PC, thread->contextId(),
|
||||
unverifiedInst->threadNumber);
|
||||
memReq->setVirt(0, fetch_PC, sizeof(MachInst),
|
||||
Request::INST_FETCH, masterId, thread->instAddr());
|
||||
|
||||
|
||||
fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute);
|
||||
|
||||
if (fault != NoFault) {
|
||||
if (unverifiedInst->getFault() == NoFault) {
|
||||
// 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 %s was not found in the "
|
||||
"ITB!", curTick(), thread->pcState());
|
||||
handleError(unverifiedInst);
|
||||
|
||||
// go to the next instruction
|
||||
advancePC(NoFault);
|
||||
|
||||
// Give up on an ITB fault..
|
||||
delete memReq;
|
||||
unverifiedInst = NULL;
|
||||
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 = unverifiedInst->getFault();
|
||||
delete memReq;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
PacketPtr pkt = new Packet(memReq, MemCmd::ReadReq);
|
||||
|
||||
pkt->dataStatic(&machInst);
|
||||
icachePort->sendFunctional(pkt);
|
||||
machInst = gtoh(machInst);
|
||||
|
||||
delete memReq;
|
||||
delete pkt;
|
||||
}
|
||||
}
|
||||
|
||||
if (fault == NoFault) {
|
||||
TheISA::PCState pcState = thread->pcState();
|
||||
|
||||
if (isRomMicroPC(pcState.microPC())) {
|
||||
fetchDone = true;
|
||||
curStaticInst =
|
||||
microcodeRom.fetchMicroop(pcState.microPC(), NULL);
|
||||
} else if (!curMacroStaticInst) {
|
||||
//We're not in the middle of a macro instruction
|
||||
StaticInstPtr instPtr = NULL;
|
||||
|
||||
//Predecode, ie bundle up an ExtMachInst
|
||||
thread->decoder.setTC(thread->getTC());
|
||||
//If more fetch data is needed, pass it in.
|
||||
Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
|
||||
thread->decoder.moreBytes(pcState, fetchPC, machInst);
|
||||
|
||||
//If an instruction is ready, decode it.
|
||||
//Otherwise, we'll have to fetch beyond the
|
||||
//MachInst at the current pc.
|
||||
if (thread->decoder.instReady()) {
|
||||
fetchDone = true;
|
||||
instPtr = thread->decoder.decode(pcState);
|
||||
thread->pcState(pcState);
|
||||
} else {
|
||||
fetchDone = false;
|
||||
fetchOffset += sizeof(TheISA::MachInst);
|
||||
}
|
||||
|
||||
//If we decoded an instruction and it's microcoded,
|
||||
//start pulling out micro ops
|
||||
if (instPtr && instPtr->isMacroop()) {
|
||||
curMacroStaticInst = instPtr;
|
||||
curStaticInst =
|
||||
instPtr->fetchMicroop(pcState.microPC());
|
||||
} else {
|
||||
curStaticInst = instPtr;
|
||||
}
|
||||
} else {
|
||||
// Read the next micro op from the macro-op
|
||||
curStaticInst =
|
||||
curMacroStaticInst->fetchMicroop(pcState.microPC());
|
||||
fetchDone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reset decoder on Checker
|
||||
thread->decoder.reset();
|
||||
|
||||
// Check Checker and CPU get same instruction, and record
|
||||
// any faults the CPU may have had.
|
||||
Fault unverifiedFault;
|
||||
if (fault == NoFault) {
|
||||
unverifiedFault = unverifiedInst->getFault();
|
||||
|
||||
// Checks that the instruction matches what we expected it to be.
|
||||
// Checks both the machine instruction and the PC.
|
||||
validateInst(unverifiedInst);
|
||||
}
|
||||
|
||||
// keep an instruction count
|
||||
numInst++;
|
||||
|
||||
|
||||
// Either the instruction was a fault and we should process the fault,
|
||||
// or we should just go ahead execute the instruction. This assumes
|
||||
// that the instruction is properly marked as a fault.
|
||||
if (fault == NoFault) {
|
||||
// Execute Checker instruction and trace
|
||||
if (!unverifiedInst->isUnverifiable()) {
|
||||
Trace::InstRecord *traceData = tracer->getInstRecord(curTick(),
|
||||
tc,
|
||||
curStaticInst,
|
||||
pcState(),
|
||||
curMacroStaticInst);
|
||||
fault = curStaticInst->execute(this, traceData);
|
||||
if (traceData) {
|
||||
traceData->dump();
|
||||
delete traceData;
|
||||
}
|
||||
}
|
||||
|
||||
if (fault == NoFault && unverifiedFault == NoFault) {
|
||||
thread->funcExeInst++;
|
||||
// Checks to make sure instrution results are correct.
|
||||
validateExecution(unverifiedInst);
|
||||
|
||||
if (curStaticInst->isLoad()) {
|
||||
++numLoad;
|
||||
}
|
||||
} else if (fault != NoFault && unverifiedFault == NoFault) {
|
||||
panic("%lli: sn: %lli at PC: %s took a fault in checker "
|
||||
"but not in driver CPU\n", curTick(),
|
||||
unverifiedInst->seqNum, unverifiedInst->pcState());
|
||||
} else if (fault == NoFault && unverifiedFault != NoFault) {
|
||||
panic("%lli: sn: %lli at PC: %s took a fault in driver "
|
||||
"CPU but not in checker\n", curTick(),
|
||||
unverifiedInst->seqNum, unverifiedInst->pcState());
|
||||
}
|
||||
}
|
||||
|
||||
// Take any faults here
|
||||
if (fault != NoFault) {
|
||||
if (FullSystem) {
|
||||
fault->invoke(tc, curStaticInst);
|
||||
willChangePC = true;
|
||||
newPCState = thread->pcState();
|
||||
DPRINTF(Checker, "Fault, PC is now %s\n", newPCState);
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
}
|
||||
} else {
|
||||
advancePC(fault);
|
||||
}
|
||||
|
||||
if (FullSystem) {
|
||||
// @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 {
|
||||
oldpc = thread->instAddr();
|
||||
system->pcEventQueue.service(tc);
|
||||
count++;
|
||||
} while (oldpc != thread->instAddr());
|
||||
if (count > 1) {
|
||||
willChangePC = true;
|
||||
newPCState = thread->pcState();
|
||||
DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
|
||||
}
|
||||
}
|
||||
|
||||
// @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()) {
|
||||
unverifiedInst = NULL;
|
||||
unverifiedInst = instList.front();
|
||||
instList.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
unverifiedInst = NULL;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::switchOut()
|
||||
{
|
||||
instList.clear();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::validateInst(DynInstPtr &inst)
|
||||
{
|
||||
if (inst->instAddr() != thread->instAddr()) {
|
||||
warn("%lli: PCs do not match! Inst: %s, checker: %s",
|
||||
curTick(), inst->pcState(), thread->pcState());
|
||||
if (changedPC) {
|
||||
warn("%lli: Changed PCs recently, may not be an error",
|
||||
curTick());
|
||||
} else {
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
|
||||
if (curStaticInst != inst->staticInst) {
|
||||
warn("%lli: StaticInstPtrs don't match. (%s, %s).\n", curTick(),
|
||||
curStaticInst->getName(), inst->staticInst->getName());
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::validateExecution(DynInstPtr &inst)
|
||||
{
|
||||
uint64_t checker_val;
|
||||
uint64_t inst_val;
|
||||
int idx = -1;
|
||||
bool result_mismatch = false;
|
||||
|
||||
if (inst->isUnverifiable()) {
|
||||
// Unverifiable instructions assume they were executed
|
||||
// properly by the CPU. Grab the result from the
|
||||
// instruction and write it to the register.
|
||||
copyResult(inst, 0, idx);
|
||||
} else if (inst->numDestRegs() > 0 && !result.empty()) {
|
||||
DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n",
|
||||
inst->numDestRegs(), result.size());
|
||||
for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) {
|
||||
result.front().get(checker_val);
|
||||
result.pop();
|
||||
inst_val = 0;
|
||||
inst->template popResult<uint64_t>(inst_val);
|
||||
if (checker_val != inst_val) {
|
||||
result_mismatch = true;
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // Checker CPU checks all the saved results in the dyninst passed by
|
||||
// the cpu model being checked against the saved results present in
|
||||
// the static inst executed in the Checker. Sometimes the number
|
||||
// of saved results differs between the dyninst and static inst, but
|
||||
// this is ok and not a bug. May be worthwhile to try and correct this.
|
||||
|
||||
if (result_mismatch) {
|
||||
warn("%lli: Instruction results do not match! (Values may not "
|
||||
"actually be integers) Inst: %#x, checker: %#x",
|
||||
curTick(), inst_val, checker_val);
|
||||
|
||||
// It's useful to verify load values from memory, but in MP
|
||||
// systems the value obtained at execute may be different than
|
||||
// the value obtained at completion. Similarly DMA can
|
||||
// present the same problem on even UP systems. Thus there is
|
||||
// the option to only warn on loads having a result error.
|
||||
// The load/store queue in Detailed CPU can also cause problems
|
||||
// if load/store forwarding is allowed.
|
||||
if (inst->isLoad() && warnOnlyOnLoadError) {
|
||||
copyResult(inst, inst_val, idx);
|
||||
} else {
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->nextInstAddr() != thread->nextInstAddr()) {
|
||||
warn("%lli: Instruction next PCs do not match! Inst: %#x, "
|
||||
"checker: %#x",
|
||||
curTick(), inst->nextInstAddr(), thread->nextInstAddr());
|
||||
handleError(inst);
|
||||
}
|
||||
|
||||
// Checking side effect registers can be difficult if they are not
|
||||
// checked simultaneously with the execution of the instruction.
|
||||
// This is because other valid instructions may have modified
|
||||
// these registers in the meantime, and their values are not
|
||||
// stored within the DynInst.
|
||||
while (!miscRegIdxs.empty()) {
|
||||
int misc_reg_idx = miscRegIdxs.front();
|
||||
miscRegIdxs.pop();
|
||||
|
||||
if (inst->tcBase()->readMiscRegNoEffect(misc_reg_idx) !=
|
||||
thread->readMiscRegNoEffect(misc_reg_idx)) {
|
||||
warn("%lli: Misc reg idx %i (side effect) does not match! "
|
||||
"Inst: %#x, checker: %#x",
|
||||
curTick(), misc_reg_idx,
|
||||
inst->tcBase()->readMiscRegNoEffect(misc_reg_idx),
|
||||
thread->readMiscRegNoEffect(misc_reg_idx));
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function is weird, if it is called it means the Checker and
|
||||
// O3 have diverged, so panic is called for now. It may be useful
|
||||
// to resynch states and continue if the divergence is a false positive
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::validateState()
|
||||
{
|
||||
if (updateThisCycle) {
|
||||
// Change this back to warn if divergences end up being false positives
|
||||
panic("%lli: Instruction PC %#x results didn't match up, copying all "
|
||||
"registers from main CPU", curTick(), unverifiedInst->instAddr());
|
||||
|
||||
// Terribly convoluted way to make sure O3 model does not implode
|
||||
bool inSyscall = unverifiedInst->thread->inSyscall;
|
||||
unverifiedInst->thread->inSyscall = true;
|
||||
|
||||
// Heavy-weight copying of all registers
|
||||
thread->copyArchRegs(unverifiedInst->tcBase());
|
||||
unverifiedInst->thread->inSyscall = inSyscall;
|
||||
|
||||
// Set curStaticInst to unverifiedInst->staticInst
|
||||
curStaticInst = unverifiedInst->staticInst;
|
||||
// Also advance the PC. Hopefully no PC-based events happened.
|
||||
advancePC(NoFault);
|
||||
updateThisCycle = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
|
||||
int start_idx)
|
||||
{
|
||||
// We've already popped one dest off the queue,
|
||||
// so do the fix-up then start with the next dest reg;
|
||||
if (start_idx >= 0) {
|
||||
RegIndex idx = inst->destRegIdx(start_idx);
|
||||
if (idx < TheISA::FP_Base_DepTag) {
|
||||
thread->setIntReg(idx, mismatch_val);
|
||||
} else if (idx < TheISA::Ctrl_Base_DepTag) {
|
||||
thread->setFloatRegBits(idx, mismatch_val);
|
||||
} else if (idx < TheISA::Max_DepTag) {
|
||||
thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag,
|
||||
mismatch_val);
|
||||
}
|
||||
}
|
||||
start_idx++;
|
||||
uint64_t res = 0;
|
||||
for (int i = start_idx; i < inst->numDestRegs(); i++) {
|
||||
RegIndex idx = inst->destRegIdx(i);
|
||||
inst->template popResult<uint64_t>(res);
|
||||
if (idx < TheISA::FP_Base_DepTag) {
|
||||
thread->setIntReg(idx, res);
|
||||
} else if (idx < TheISA::Ctrl_Base_DepTag) {
|
||||
thread->setFloatRegBits(idx, res);
|
||||
} else if (idx < TheISA::Max_DepTag) {
|
||||
// Try to get the proper misc register index for ARM here...
|
||||
thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag, res);
|
||||
} // else Register is out of range...
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::dumpAndExit(DynInstPtr &inst)
|
||||
{
|
||||
cprintf("Error detected, instruction information:\n");
|
||||
cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
|
||||
"Completed:%i\n",
|
||||
inst->pcState(),
|
||||
inst->nextInstAddr(),
|
||||
inst->seqNum,
|
||||
inst->threadNumber,
|
||||
inst->isCompleted());
|
||||
inst->dump();
|
||||
CheckerCPU::dumpAndExit();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<Impl>::dumpInsts()
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
InstListIt inst_list_it = --(instList.end());
|
||||
|
||||
cprintf("Inst list size: %i\n", instList.size());
|
||||
|
||||
while (inst_list_it != instList.end())
|
||||
{
|
||||
cprintf("Instruction:%i\n",
|
||||
num);
|
||||
|
||||
cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n"
|
||||
"Completed:%i\n",
|
||||
(*inst_list_it)->pcState(),
|
||||
(*inst_list_it)->seqNum,
|
||||
(*inst_list_it)->threadNumber,
|
||||
(*inst_list_it)->isCompleted());
|
||||
|
||||
cprintf("\n");
|
||||
|
||||
inst_list_it--;
|
||||
++num;
|
||||
}
|
||||
|
||||
}
|
||||
306
simulators/gem5/src/cpu/checker/thread_context.hh
Normal file
306
simulators/gem5/src/cpu/checker/thread_context.hh
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Authors: Kevin Lim
|
||||
*/
|
||||
|
||||
#ifndef __CPU_CHECKER_THREAD_CONTEXT_HH__
|
||||
#define __CPU_CHECKER_THREAD_CONTEXT_HH__
|
||||
|
||||
#include "arch/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Checker.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
namespace TheISA {
|
||||
namespace Kernel {
|
||||
class Statistics;
|
||||
};
|
||||
class Decoder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Derived ThreadContext class for use with the Checker. The template
|
||||
* parameter is the ThreadContext class used by the specific CPU being
|
||||
* verified. This CheckerThreadContext is then used by the main CPU
|
||||
* in place of its usual ThreadContext class. It handles updating the
|
||||
* checker's state any time state is updated externally through the
|
||||
* ThreadContext.
|
||||
*/
|
||||
template <class TC>
|
||||
class CheckerThreadContext : public ThreadContext
|
||||
{
|
||||
public:
|
||||
CheckerThreadContext(TC *actual_tc,
|
||||
CheckerCPU *checker_cpu)
|
||||
: actualTC(actual_tc), checkerTC(checker_cpu->thread),
|
||||
checkerCPU(checker_cpu)
|
||||
{ }
|
||||
|
||||
private:
|
||||
/** The main CPU's ThreadContext, or class that implements the
|
||||
* ThreadContext interface. */
|
||||
TC *actualTC;
|
||||
/** The checker's own SimpleThread. Will be updated any time
|
||||
* anything uses this ThreadContext to externally update a
|
||||
* thread's state. */
|
||||
SimpleThread *checkerTC;
|
||||
/** Pointer to the checker CPU. */
|
||||
CheckerCPU *checkerCPU;
|
||||
|
||||
public:
|
||||
|
||||
BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
|
||||
|
||||
int cpuId() { return actualTC->cpuId(); }
|
||||
|
||||
int contextId() { return actualTC->contextId(); }
|
||||
|
||||
void setContextId(int id)
|
||||
{
|
||||
actualTC->setContextId(id);
|
||||
checkerTC->setContextId(id);
|
||||
}
|
||||
|
||||
/** Returns this thread's ID number. */
|
||||
int threadId() { return actualTC->threadId(); }
|
||||
void setThreadId(int id)
|
||||
{
|
||||
checkerTC->setThreadId(id);
|
||||
actualTC->setThreadId(id);
|
||||
}
|
||||
|
||||
TheISA::TLB *getITBPtr() { return actualTC->getITBPtr(); }
|
||||
|
||||
TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); }
|
||||
|
||||
CheckerCPU *getCheckerCpuPtr()
|
||||
{
|
||||
return checkerCPU;
|
||||
}
|
||||
|
||||
TheISA::Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
|
||||
|
||||
System *getSystemPtr() { return actualTC->getSystemPtr(); }
|
||||
|
||||
TheISA::Kernel::Statistics *getKernelStats()
|
||||
{ return actualTC->getKernelStats(); }
|
||||
|
||||
Process *getProcessPtr() { return actualTC->getProcessPtr(); }
|
||||
|
||||
PortProxy &getPhysProxy() { return actualTC->getPhysProxy(); }
|
||||
|
||||
FSTranslatingPortProxy &getVirtProxy()
|
||||
{ return actualTC->getVirtProxy(); }
|
||||
|
||||
void initMemProxies(ThreadContext *tc)
|
||||
{ actualTC->initMemProxies(tc); }
|
||||
|
||||
void connectMemPorts(ThreadContext *tc)
|
||||
{
|
||||
actualTC->connectMemPorts(tc);
|
||||
}
|
||||
|
||||
SETranslatingPortProxy &getMemProxy() { return actualTC->getMemProxy(); }
|
||||
|
||||
/** Executes a syscall in SE mode. */
|
||||
void syscall(int64_t callnum)
|
||||
{ return actualTC->syscall(callnum); }
|
||||
|
||||
Status status() const { return actualTC->status(); }
|
||||
|
||||
void setStatus(Status new_status)
|
||||
{
|
||||
actualTC->setStatus(new_status);
|
||||
checkerTC->setStatus(new_status);
|
||||
}
|
||||
|
||||
/// Set the status to Active. Optional delay indicates number of
|
||||
/// cycles to wait before beginning execution.
|
||||
void activate(int delay = 1) { actualTC->activate(delay); }
|
||||
|
||||
/// Set the status to Suspended.
|
||||
void suspend(int delay) { actualTC->suspend(delay); }
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt(int delay) { actualTC->halt(delay); }
|
||||
|
||||
void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
|
||||
|
||||
void takeOverFrom(ThreadContext *oldContext)
|
||||
{
|
||||
actualTC->takeOverFrom(oldContext);
|
||||
checkerTC->copyState(oldContext);
|
||||
}
|
||||
|
||||
void regStats(const std::string &name)
|
||||
{
|
||||
actualTC->regStats(name);
|
||||
checkerTC->regStats(name);
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) { actualTC->serialize(os); }
|
||||
void unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{ actualTC->unserialize(cp, section); }
|
||||
|
||||
EndQuiesceEvent *getQuiesceEvent() { return actualTC->getQuiesceEvent(); }
|
||||
|
||||
Tick readLastActivate() { return actualTC->readLastActivate(); }
|
||||
Tick readLastSuspend() { return actualTC->readLastSuspend(); }
|
||||
|
||||
void profileClear() { return actualTC->profileClear(); }
|
||||
void profileSample() { return actualTC->profileSample(); }
|
||||
|
||||
// @todo: Do I need this?
|
||||
void copyArchRegs(ThreadContext *tc)
|
||||
{
|
||||
actualTC->copyArchRegs(tc);
|
||||
checkerTC->copyArchRegs(tc);
|
||||
}
|
||||
|
||||
void clearArchRegs()
|
||||
{
|
||||
actualTC->clearArchRegs();
|
||||
checkerTC->clearArchRegs();
|
||||
}
|
||||
|
||||
//
|
||||
// New accessors for new decoder.
|
||||
//
|
||||
uint64_t readIntReg(int reg_idx)
|
||||
{ return actualTC->readIntReg(reg_idx); }
|
||||
|
||||
FloatReg readFloatReg(int reg_idx)
|
||||
{ return actualTC->readFloatReg(reg_idx); }
|
||||
|
||||
FloatRegBits readFloatRegBits(int reg_idx)
|
||||
{ return actualTC->readFloatRegBits(reg_idx); }
|
||||
|
||||
void setIntReg(int reg_idx, uint64_t val)
|
||||
{
|
||||
actualTC->setIntReg(reg_idx, val);
|
||||
checkerTC->setIntReg(reg_idx, val);
|
||||
}
|
||||
|
||||
void setFloatReg(int reg_idx, FloatReg val)
|
||||
{
|
||||
actualTC->setFloatReg(reg_idx, val);
|
||||
checkerTC->setFloatReg(reg_idx, val);
|
||||
}
|
||||
|
||||
void setFloatRegBits(int reg_idx, FloatRegBits val)
|
||||
{
|
||||
actualTC->setFloatRegBits(reg_idx, val);
|
||||
checkerTC->setFloatRegBits(reg_idx, val);
|
||||
}
|
||||
|
||||
/** Reads this thread's PC state. */
|
||||
TheISA::PCState pcState()
|
||||
{ return actualTC->pcState(); }
|
||||
|
||||
/** Sets this thread's PC state. */
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{
|
||||
DPRINTF(Checker, "Changing PC to %s, old PC %s\n",
|
||||
val, checkerTC->pcState());
|
||||
checkerTC->pcState(val);
|
||||
checkerCPU->recordPCChange(val);
|
||||
return actualTC->pcState(val);
|
||||
}
|
||||
|
||||
void pcStateNoRecord(const TheISA::PCState &val)
|
||||
{
|
||||
return actualTC->pcState(val);
|
||||
}
|
||||
|
||||
/** Reads this thread's PC. */
|
||||
Addr instAddr()
|
||||
{ return actualTC->instAddr(); }
|
||||
|
||||
/** Reads this thread's next PC. */
|
||||
Addr nextInstAddr()
|
||||
{ return actualTC->nextInstAddr(); }
|
||||
|
||||
/** Reads this thread's next PC. */
|
||||
MicroPC microPC()
|
||||
{ return actualTC->microPC(); }
|
||||
|
||||
MiscReg readMiscRegNoEffect(int misc_reg)
|
||||
{ return actualTC->readMiscRegNoEffect(misc_reg); }
|
||||
|
||||
MiscReg readMiscReg(int misc_reg)
|
||||
{ return actualTC->readMiscReg(misc_reg); }
|
||||
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
DPRINTF(Checker, "Setting misc reg with no effect: %d to both Checker"
|
||||
" and O3..\n", misc_reg);
|
||||
checkerTC->setMiscRegNoEffect(misc_reg, val);
|
||||
actualTC->setMiscRegNoEffect(misc_reg, val);
|
||||
}
|
||||
|
||||
void setMiscReg(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
DPRINTF(Checker, "Setting misc reg with effect: %d to both Checker"
|
||||
" and O3..\n", misc_reg);
|
||||
checkerTC->setMiscReg(misc_reg, val);
|
||||
actualTC->setMiscReg(misc_reg, val);
|
||||
}
|
||||
|
||||
int flattenIntIndex(int reg) { return actualTC->flattenIntIndex(reg); }
|
||||
int flattenFloatIndex(int reg) { return actualTC->flattenFloatIndex(reg); }
|
||||
|
||||
unsigned readStCondFailures()
|
||||
{ return actualTC->readStCondFailures(); }
|
||||
|
||||
void setStCondFailures(unsigned sc_failures)
|
||||
{
|
||||
actualTC->setStCondFailures(sc_failures);
|
||||
}
|
||||
|
||||
// @todo: Fix this!
|
||||
bool misspeculating() { return actualTC->misspeculating(); }
|
||||
|
||||
Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
|
||||
};
|
||||
|
||||
#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__
|
||||
Reference in New Issue
Block a user