Merge with head, hopefully the last time for this batch.
This commit is contained in:
@@ -164,7 +164,6 @@ class BaseCPU(MemObject):
|
||||
self.connectUncachedPorts(uncached_bus)
|
||||
|
||||
def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None):
|
||||
assert(len(self._cached_ports) < 7)
|
||||
self.icache = ic
|
||||
self.dcache = dc
|
||||
self.icache_port = ic.cpu_side
|
||||
@@ -180,6 +179,11 @@ class BaseCPU(MemObject):
|
||||
"dtb_walker_cache.mem_side"]
|
||||
else:
|
||||
self._cached_ports += ["itb.walker.port", "dtb.walker.port"]
|
||||
# Checker doesn't need its own tlb caches because it does
|
||||
# functional accesses only
|
||||
if buildEnv['USE_CHECKER']:
|
||||
self._cached_ports += ["checker.itb.walker.port", \
|
||||
"checker.dtb.walker.port"]
|
||||
|
||||
def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
|
||||
self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
|
||||
|
||||
@@ -35,7 +35,7 @@ class CheckerCPU(BaseCPU):
|
||||
exitOnError = Param.Bool(False, "Exit on an error")
|
||||
updateOnError = Param.Bool(False,
|
||||
"Update the checker with the main CPU's state on an error")
|
||||
warnOnlyOnLoadError = Param.Bool(False,
|
||||
warnOnlyOnLoadError = Param.Bool(True,
|
||||
"If a load result is incorrect, only print a warning and do not exit")
|
||||
function_trace = Param.Bool(False, "Enable function trace")
|
||||
function_trace_start = Param.Tick(0, "Cycle to start function trace")
|
||||
|
||||
42
src/cpu/DummyChecker.py
Normal file
42
src/cpu/DummyChecker.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2010-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.
|
||||
#
|
||||
# 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: Geoffrey Blake
|
||||
|
||||
from m5.params import *
|
||||
from BaseCPU import BaseCPU
|
||||
|
||||
class DummyChecker(BaseCPU):
|
||||
type = 'DummyChecker'
|
||||
@@ -134,7 +134,9 @@ if env['TARGET_ISA'] == 'sparc':
|
||||
Source('legiontrace.cc')
|
||||
|
||||
if env['USE_CHECKER']:
|
||||
SimObject('DummyChecker.py')
|
||||
Source('checker/cpu.cc')
|
||||
Source('dummy_checker_builder.cc')
|
||||
DebugFlag('Checker')
|
||||
checker_supports = False
|
||||
for i in CheckerSupportedCPUList:
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "base/misc.hh"
|
||||
#include "base/output.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/cpuevent.hh"
|
||||
#include "cpu/profile.hh"
|
||||
@@ -65,6 +66,10 @@
|
||||
#include "sim/sim_exit.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#if USE_CHECKER
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#endif
|
||||
|
||||
// Hack
|
||||
#include "sim/stat_control.hh"
|
||||
|
||||
@@ -212,7 +217,10 @@ BaseCPU::BaseCPU(Params *p)
|
||||
schedule(event, p->function_trace_start);
|
||||
}
|
||||
}
|
||||
interrupts->setCPU(this);
|
||||
// Check if CPU model has interrupts connected. The CheckerCPU
|
||||
// cannot take interrupts directly for example.
|
||||
if (interrupts)
|
||||
interrupts->setCPU(this);
|
||||
|
||||
if (FullSystem) {
|
||||
profileEvent = NULL;
|
||||
@@ -351,8 +359,10 @@ BaseCPU::switchOut()
|
||||
}
|
||||
|
||||
void
|
||||
BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
|
||||
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
Port *ic = getPort("icache_port");
|
||||
Port *dc = getPort("dcache_port");
|
||||
assert(threadContexts.size() == oldCPU->threadContexts.size());
|
||||
|
||||
_cpuId = oldCPU->cpuId();
|
||||
@@ -396,6 +406,35 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
|
||||
new_dtb_port->setPeer(peer);
|
||||
peer->setPeer(new_dtb_port);
|
||||
}
|
||||
|
||||
#if USE_CHECKER
|
||||
Port *old_checker_itb_port, *old_checker_dtb_port;
|
||||
Port *new_checker_itb_port, *new_checker_dtb_port;
|
||||
|
||||
CheckerCPU *oldChecker =
|
||||
dynamic_cast<CheckerCPU*>(oldTC->getCheckerCpuPtr());
|
||||
CheckerCPU *newChecker =
|
||||
dynamic_cast<CheckerCPU*>(newTC->getCheckerCpuPtr());
|
||||
old_checker_itb_port = oldChecker->getITBPtr()->getPort();
|
||||
old_checker_dtb_port = oldChecker->getDTBPtr()->getPort();
|
||||
new_checker_itb_port = newChecker->getITBPtr()->getPort();
|
||||
new_checker_dtb_port = newChecker->getDTBPtr()->getPort();
|
||||
|
||||
// Move over any table walker ports if they exist for checker
|
||||
if (new_checker_itb_port && !new_checker_itb_port->isConnected()) {
|
||||
assert(old_checker_itb_port);
|
||||
Port *peer = old_checker_itb_port->getPeer();;
|
||||
new_checker_itb_port->setPeer(peer);
|
||||
peer->setPeer(new_checker_itb_port);
|
||||
}
|
||||
if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) {
|
||||
assert(old_checker_dtb_port);
|
||||
Port *peer = old_checker_dtb_port->getPeer();;
|
||||
new_checker_dtb_port->setPeer(peer);
|
||||
peer->setPeer(new_checker_dtb_port);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
interrupts = oldCPU->interrupts;
|
||||
|
||||
@@ -237,16 +237,16 @@ class BaseCPU : public MemObject
|
||||
/// Notify the CPU that the indicated context is now active. The
|
||||
/// delay parameter indicates the number of ticks to wait before
|
||||
/// executing (typically 0 or 1).
|
||||
virtual void activateContext(int thread_num, int delay) {}
|
||||
virtual void activateContext(ThreadID thread_num, int delay) {}
|
||||
|
||||
/// Notify the CPU that the indicated context is now suspended.
|
||||
virtual void suspendContext(int thread_num) {}
|
||||
virtual void suspendContext(ThreadID thread_num) {}
|
||||
|
||||
/// Notify the CPU that the indicated context is now deallocated.
|
||||
virtual void deallocateContext(int thread_num) {}
|
||||
virtual void deallocateContext(ThreadID thread_num) {}
|
||||
|
||||
/// Notify the CPU that the indicated context is now halted.
|
||||
virtual void haltContext(int thread_num) {}
|
||||
virtual void haltContext(ThreadID thread_num) {}
|
||||
|
||||
/// Given a Thread Context pointer return the thread num
|
||||
int findContext(ThreadContext *tc);
|
||||
@@ -275,7 +275,7 @@ class BaseCPU : public MemObject
|
||||
|
||||
/// Take over execution from the given CPU. Used for warm-up and
|
||||
/// sampling.
|
||||
virtual void takeOverFrom(BaseCPU *, Port *ic, Port *dc);
|
||||
virtual void takeOverFrom(BaseCPU *);
|
||||
|
||||
/**
|
||||
* Number of threads we're actually simulating (<= SMT_MAX_THREADS).
|
||||
|
||||
@@ -48,12 +48,14 @@
|
||||
#include <bitset>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
#include "arch/faults.hh"
|
||||
#include "arch/utility.hh"
|
||||
#include "base/fast_alloc.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/o3/comm.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
@@ -175,6 +177,11 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
||||
RequestPtr savedSreqLow;
|
||||
RequestPtr savedSreqHigh;
|
||||
|
||||
#if USE_CHECKER
|
||||
// Need a copy of main request pointer to verify on writes.
|
||||
RequestPtr reqToVerify;
|
||||
#endif //USE_CHECKER
|
||||
|
||||
/** @todo: Consider making this private. */
|
||||
public:
|
||||
/** The sequence number of the instruction. */
|
||||
@@ -247,14 +254,17 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
||||
|
||||
union Result {
|
||||
uint64_t integer;
|
||||
// float fp;
|
||||
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; }
|
||||
};
|
||||
|
||||
/** The result of the instruction; assumes for now that there's only one
|
||||
* destination register.
|
||||
/** The result of the instruction; assumes an instruction can have many
|
||||
* destination registers.
|
||||
*/
|
||||
Result instResult;
|
||||
std::queue<Result> instResult;
|
||||
|
||||
/** Records changes to result? */
|
||||
bool recordResult;
|
||||
@@ -557,56 +567,68 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
||||
/** Returns the logical register index of the i'th source register. */
|
||||
RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); }
|
||||
|
||||
/** Returns the result of an integer instruction. */
|
||||
uint64_t readIntResult() { return instResult.integer; }
|
||||
/** Pops a result off the instResult queue */
|
||||
template <class T>
|
||||
void popResult(T& t)
|
||||
{
|
||||
if (!instResult.empty()) {
|
||||
instResult.front().get(t);
|
||||
instResult.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the result of a floating point instruction. */
|
||||
float readFloatResult() { return (float)instResult.dbl; }
|
||||
/** Read the most recent result stored by this instruction */
|
||||
template <class T>
|
||||
void readResult(T& t)
|
||||
{
|
||||
instResult.back().get(t);
|
||||
}
|
||||
|
||||
/** Returns the result of a floating point (double) instruction. */
|
||||
double readDoubleResult() { return instResult.dbl; }
|
||||
/** Pushes a result onto the instResult queue */
|
||||
template <class T>
|
||||
void setResult(T t)
|
||||
{
|
||||
if (recordResult) {
|
||||
Result instRes;
|
||||
instRes.set(t);
|
||||
instResult.push(instRes);
|
||||
}
|
||||
}
|
||||
|
||||
/** Records an integer register being set to a value. */
|
||||
void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
if (recordResult)
|
||||
instResult.integer = val;
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
/** Records an fp register being set to a value. */
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
|
||||
int width)
|
||||
{
|
||||
if (recordResult) {
|
||||
if (width == 32)
|
||||
instResult.dbl = (double)val;
|
||||
else if (width == 64)
|
||||
instResult.dbl = val;
|
||||
else
|
||||
panic("Unsupported width!");
|
||||
if (width == 32 || width == 64) {
|
||||
setResult<double>(val);
|
||||
} else {
|
||||
panic("Unsupported width!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Records an fp register being set to a value. */
|
||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||
{
|
||||
if (recordResult)
|
||||
instResult.dbl = (double)val;
|
||||
setResult<double>(val);
|
||||
}
|
||||
|
||||
/** Records an fp register being set to an integer value. */
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val,
|
||||
int width)
|
||||
{
|
||||
if (recordResult)
|
||||
instResult.integer = val;
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
/** Records an fp register being set to an integer value. */
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val)
|
||||
{
|
||||
if (recordResult)
|
||||
instResult.integer = val;
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
/** Records that one of the source registers is ready. */
|
||||
@@ -871,6 +893,12 @@ BaseDynInst<Impl>::readMem(Addr addr, uint8_t *data,
|
||||
effAddr = req->getVaddr();
|
||||
effSize = size;
|
||||
effAddrValid = true;
|
||||
#if USE_CHECKER
|
||||
if (reqToVerify != NULL) {
|
||||
delete reqToVerify;
|
||||
}
|
||||
reqToVerify = new Request(*req);
|
||||
#endif //USE_CHECKER
|
||||
fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx);
|
||||
} else {
|
||||
// Commit will have to clean up whatever happened. Set this
|
||||
@@ -926,6 +954,12 @@ BaseDynInst<Impl>::writeMem(uint8_t *data, unsigned size,
|
||||
effAddr = req->getVaddr();
|
||||
effSize = size;
|
||||
effAddrValid = true;
|
||||
#if USE_CHECKER
|
||||
if (reqToVerify != NULL) {
|
||||
delete reqToVerify;
|
||||
}
|
||||
reqToVerify = new Request(*req);
|
||||
#endif // USE_CHECKER
|
||||
fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "base/cprintf.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/base_dyn_inst.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/DynInst.hh"
|
||||
@@ -117,7 +118,6 @@ BaseDynInst<Impl>::initVars()
|
||||
reqMade = false;
|
||||
readyRegs = 0;
|
||||
|
||||
instResult.integer = 0;
|
||||
recordResult = true;
|
||||
|
||||
status.reset();
|
||||
@@ -157,6 +157,10 @@ BaseDynInst<Impl>::initVars()
|
||||
#ifdef DEBUG
|
||||
cpu->snList.insert(seqNum);
|
||||
#endif
|
||||
|
||||
#if USE_CHECKER
|
||||
reqToVerify = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
@@ -182,6 +186,11 @@ BaseDynInst<Impl>::~BaseDynInst()
|
||||
#ifdef DEBUG
|
||||
cpu->snList.erase(seqNum);
|
||||
#endif
|
||||
|
||||
#if USE_CHECKER
|
||||
if (reqToVerify)
|
||||
delete reqToVerify;
|
||||
#endif // USE_CHECKER
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -26,6 +38,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Kevin Lim
|
||||
* Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
@@ -38,10 +51,11 @@
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "params/CheckerCPU.hh"
|
||||
#include "sim/tlb.hh"
|
||||
|
||||
using namespace std;
|
||||
//The CheckerCPU does alpha only
|
||||
using namespace AlphaISA;
|
||||
using namespace TheISA;
|
||||
|
||||
void
|
||||
CheckerCPU::init()
|
||||
@@ -52,6 +66,8 @@ CheckerCPU::CheckerCPU(Params *p)
|
||||
: BaseCPU(p), thread(NULL), tc(NULL)
|
||||
{
|
||||
memReq = NULL;
|
||||
curStaticInst = NULL;
|
||||
curMacroStaticInst = NULL;
|
||||
|
||||
numInst = 0;
|
||||
startNumInst = 0;
|
||||
@@ -66,13 +82,14 @@ CheckerCPU::CheckerCPU(Params *p)
|
||||
itb = p->itb;
|
||||
dtb = p->dtb;
|
||||
systemPtr = NULL;
|
||||
process = p->process;
|
||||
thread = new SimpleThread(this, /* thread_num */ 0, process);
|
||||
workload = p->workload;
|
||||
// XXX: This is a hack to get this to work some
|
||||
thread = new SimpleThread(this, /* thread_num */ 0, workload[0], itb, dtb);
|
||||
|
||||
tc = thread->getTC();
|
||||
threadContexts.push_back(tc);
|
||||
|
||||
result.integer = 0;
|
||||
updateOnError = true;
|
||||
}
|
||||
|
||||
CheckerCPU::~CheckerCPU()
|
||||
@@ -107,191 +124,193 @@ CheckerCPU::setDcachePort(Port *dcache_port)
|
||||
void
|
||||
CheckerCPU::serialize(ostream &os)
|
||||
{
|
||||
/*
|
||||
BaseCPU::serialize(os);
|
||||
SERIALIZE_SCALAR(inst);
|
||||
nameOut(os, csprintf("%s.xc", name()));
|
||||
thread->serialize(os);
|
||||
cacheCompletionEvent.serialize(os);
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::unserialize(Checkpoint *cp, const string §ion)
|
||||
{
|
||||
/*
|
||||
BaseCPU::unserialize(cp, section);
|
||||
UNSERIALIZE_SCALAR(inst);
|
||||
thread->unserialize(cp, csprintf("%s.xc", section));
|
||||
*/
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, T &data, unsigned flags)
|
||||
CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
|
||||
{
|
||||
// need to fill in CPU & thread IDs here
|
||||
memReq = new Request();
|
||||
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;
|
||||
|
||||
memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
|
||||
|
||||
// translate to physical address
|
||||
dtb->translateAtomic(memReq, tc, false);
|
||||
if (secondAddr > addr)
|
||||
size = secondAddr - addr;
|
||||
|
||||
PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
|
||||
// Need to account for multiple accesses like the Atomic and TimingSimple
|
||||
while (1) {
|
||||
memReq = new Request();
|
||||
memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
|
||||
|
||||
pkt->dataStatic(&data);
|
||||
// translate to physical address
|
||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
|
||||
|
||||
if (!(memReq->isUncacheable())) {
|
||||
// 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, &unverifiedResult.integer, sizeof(T));
|
||||
}
|
||||
|
||||
delete pkt;
|
||||
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
|
||||
|
||||
#endif //DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
template<>
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, double &data, unsigned flags)
|
||||
{
|
||||
return read(addr, *(uint64_t*)&data, flags);
|
||||
}
|
||||
|
||||
template<>
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, float &data, unsigned flags)
|
||||
{
|
||||
return read(addr, *(uint32_t*)&data, flags);
|
||||
}
|
||||
|
||||
template<>
|
||||
Fault
|
||||
CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
|
||||
{
|
||||
return read(addr, (uint32_t&)data, flags);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Fault
|
||||
CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
// need to fill in CPU & thread IDs here
|
||||
memReq = new Request();
|
||||
|
||||
memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
|
||||
|
||||
// translate to physical address
|
||||
dtb->translateAtomic(memReq, tc, true);
|
||||
|
||||
// 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->isUncacheable()) &&
|
||||
(!(unverifiedReq->isLLSC()) ||
|
||||
((unverifiedReq->isLLSC()) &&
|
||||
unverifiedReq->getExtraData() == 1))) {
|
||||
T inst_data;
|
||||
/*
|
||||
// This code would work if the LSQ allowed for snooping.
|
||||
PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
|
||||
pkt.dataStatic(&inst_data);
|
||||
|
||||
dcachePort->sendFunctional(pkt);
|
||||
|
||||
delete pkt;
|
||||
*/
|
||||
memcpy(&inst_data, unverifiedMemData, sizeof(T));
|
||||
|
||||
if (data != inst_data) {
|
||||
warn("%lli: Store value does not match value in memory! "
|
||||
"Instruction: %#x, memory: %#x",
|
||||
curTick(), inst_data, data);
|
||||
handleError();
|
||||
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,
|
||||
Packet::Broadcast);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 (res && unverifiedReq->scResultValid())
|
||||
*res = unverifiedReq->getExtraData();
|
||||
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 NoFault;
|
||||
return fault;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
template
|
||||
Fault
|
||||
CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
#endif //DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
template<>
|
||||
Fault
|
||||
CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
|
||||
CheckerCPU::writeMem(uint8_t *data, unsigned size,
|
||||
Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
return write(*(uint64_t*)&data, addr, flags, res);
|
||||
}
|
||||
Fault fault = NoFault;
|
||||
bool checked_flags = false;
|
||||
bool flags_match = true;
|
||||
Addr pAddr = 0x0;
|
||||
|
||||
template<>
|
||||
Fault
|
||||
CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
return write(*(uint32_t*)&data, addr, flags, res);
|
||||
}
|
||||
unsigned blockSize = dcachePort->peerBlockSize();
|
||||
int fullSize = size;
|
||||
|
||||
template<>
|
||||
Fault
|
||||
CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
|
||||
{
|
||||
return write((uint32_t)data, addr, flags, res);
|
||||
}
|
||||
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, 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.
|
||||
*/
|
||||
|
||||
delete memReq;
|
||||
|
||||
//If we don't need to access a second cache line, stop now.
|
||||
if (fault != NoFault || secondAddr <= addr)
|
||||
{
|
||||
if (fault != NoFault && memReq->isPrefetch()) {
|
||||
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)
|
||||
@@ -299,24 +318,30 @@ CheckerCPU::dbg_vtophys(Addr addr)
|
||||
return vtophys(tc, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the flags set by the Checker and Checkee match.
|
||||
*/
|
||||
bool
|
||||
CheckerCPU::checkFlags(Request *req)
|
||||
CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr,
|
||||
Addr pAddr, int flags)
|
||||
{
|
||||
// Remove any dynamic flags that don't have to do with the request itself.
|
||||
unsigned flags = unverifiedReq->getFlags();
|
||||
unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | PREFETCH;
|
||||
flags = flags & (mask);
|
||||
if (flags == req->getFlags()) {
|
||||
Addr unverifiedVAddr = unverified_req->getVaddr();
|
||||
Addr unverifiedPAddr = unverified_req->getPaddr();
|
||||
int unverifiedFlags = unverified_req->getFlags();
|
||||
|
||||
if (unverifiedVAddr != vAddr ||
|
||||
unverifiedPAddr != pAddr ||
|
||||
unverifiedFlags != flags) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CheckerCPU::dumpAndExit()
|
||||
{
|
||||
warn("%lli: Checker PC:%#x, next PC:%#x",
|
||||
curTick(), thread->readPC(), thread->readNextPC());
|
||||
warn("%lli: Checker PC:%s",
|
||||
curTick(), thread->pcState());
|
||||
panic("Checker found an error!");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -35,6 +47,7 @@
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include "arch/predecoder.hh"
|
||||
#include "arch/types.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/base.hh"
|
||||
@@ -42,6 +55,8 @@
|
||||
#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
|
||||
@@ -52,12 +67,6 @@ namespace TheISA
|
||||
|
||||
template <class>
|
||||
class BaseDynInst;
|
||||
class CheckerCPUParams;
|
||||
class Checkpoint;
|
||||
class MemInterface;
|
||||
class PhysicalMemory;
|
||||
class Process;
|
||||
class Processor;
|
||||
class ThreadContext;
|
||||
class Request;
|
||||
|
||||
@@ -90,11 +99,11 @@ class CheckerCPU : public BaseCPU
|
||||
public:
|
||||
typedef CheckerCPUParams Params;
|
||||
const Params *params() const
|
||||
{ return reinterpret_cast<const Params *>(_params); }
|
||||
{ return reinterpret_cast<const Params *>(_params); }
|
||||
CheckerCPU(Params *p);
|
||||
virtual ~CheckerCPU();
|
||||
|
||||
Process *process;
|
||||
std::vector<Process*> workload;
|
||||
|
||||
void setSystem(System *system);
|
||||
|
||||
@@ -127,19 +136,25 @@ class CheckerCPU : public BaseCPU
|
||||
|
||||
union Result {
|
||||
uint64_t integer;
|
||||
// float fp;
|
||||
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; }
|
||||
};
|
||||
|
||||
Result result;
|
||||
// ISAs like ARM can have multiple destination registers to check,
|
||||
// keep them all in a std::queue
|
||||
std::queue<Result> result;
|
||||
|
||||
// current instruction
|
||||
MachInst machInst;
|
||||
TheISA::MachInst machInst;
|
||||
|
||||
// Pointer to the one memory request.
|
||||
RequestPtr memReq;
|
||||
|
||||
StaticInstPtr curStaticInst;
|
||||
StaticInstPtr curMacroStaticInst;
|
||||
|
||||
// number of simulated instructions
|
||||
Counter numInst;
|
||||
@@ -147,6 +162,9 @@ class CheckerCPU : public BaseCPU
|
||||
|
||||
std::queue<int> miscRegIdxs;
|
||||
|
||||
TheISA::TLB* getITBPtr() { return itb; }
|
||||
TheISA::TLB* getDTBPtr() { return dtb; }
|
||||
|
||||
virtual Counter totalInstructions() const
|
||||
{
|
||||
return 0;
|
||||
@@ -159,12 +177,6 @@ class CheckerCPU : public BaseCPU
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
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);
|
||||
|
||||
// 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"); }
|
||||
@@ -198,17 +210,25 @@ class CheckerCPU : public BaseCPU
|
||||
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);
|
||||
result.integer = 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);
|
||||
result.dbl = (double)val;
|
||||
setResult<double>(val);
|
||||
}
|
||||
|
||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||
@@ -216,12 +236,26 @@ class CheckerCPU : public BaseCPU
|
||||
{
|
||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
|
||||
thread->setFloatRegBits(reg_idx, val);
|
||||
result.integer = val;
|
||||
setResult<uint64_t>(val);
|
||||
}
|
||||
|
||||
uint64_t instAddr() { return thread->instAddr(); }
|
||||
bool readPredicate() { return thread->readPredicate(); }
|
||||
void setPredicate(bool val)
|
||||
{
|
||||
thread->setPredicate(val);
|
||||
}
|
||||
|
||||
uint64_t nextInstAddr() { return thread->nextInstAddr(); }
|
||||
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)
|
||||
{
|
||||
@@ -235,7 +269,6 @@ class CheckerCPU : public BaseCPU
|
||||
|
||||
void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
{
|
||||
result.integer = val;
|
||||
miscRegIdxs.push(misc_reg);
|
||||
return thread->setMiscRegNoEffect(misc_reg, val);
|
||||
}
|
||||
@@ -246,8 +279,25 @@ class CheckerCPU : public BaseCPU
|
||||
return thread->setMiscReg(misc_reg, val);
|
||||
}
|
||||
|
||||
void recordPCChange(uint64_t val) { changedPC = true; newPC = val; }
|
||||
void recordNextPCChange(uint64_t val) { changedNextPC = true; }
|
||||
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);
|
||||
}
|
||||
/////////////////////////////////////////
|
||||
|
||||
void recordPCChange(const TheISA::PCState &val)
|
||||
{
|
||||
changedPC = true;
|
||||
newPCState = val;
|
||||
}
|
||||
|
||||
void demapPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
@@ -265,8 +315,17 @@ class CheckerCPU : public BaseCPU
|
||||
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) { }
|
||||
@@ -277,7 +336,8 @@ class CheckerCPU : public BaseCPU
|
||||
dumpAndExit();
|
||||
}
|
||||
|
||||
bool checkFlags(Request *req);
|
||||
bool checkFlags(Request *unverified_req, Addr vAddr,
|
||||
Addr pAddr, int flags);
|
||||
|
||||
void dumpAndExit();
|
||||
|
||||
@@ -290,7 +350,7 @@ class CheckerCPU : public BaseCPU
|
||||
|
||||
bool changedPC;
|
||||
bool willChangePC;
|
||||
uint64_t newPC;
|
||||
TheISA::PCState newPCState;
|
||||
bool changedNextPC;
|
||||
bool exitOnError;
|
||||
bool updateOnError;
|
||||
@@ -305,24 +365,31 @@ class CheckerCPU : public BaseCPU
|
||||
* template instantiations of the Checker must be placed at the bottom
|
||||
* of checker/cpu.cc.
|
||||
*/
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
class Checker : public CheckerCPU
|
||||
{
|
||||
private:
|
||||
typedef typename Impl::DynInstPtr DynInstPtr;
|
||||
|
||||
public:
|
||||
Checker(Params *p)
|
||||
: CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
|
||||
: CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL),
|
||||
predecoder(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);
|
||||
void copyResult(DynInstPtr &inst, uint64_t mismatch_val, int start_idx);
|
||||
void handlePendingInt();
|
||||
|
||||
private:
|
||||
void handleError(DynInstPtr &inst)
|
||||
@@ -339,6 +406,7 @@ class Checker : public CheckerCPU
|
||||
bool updateThisCycle;
|
||||
|
||||
DynInstPtr unverifiedInst;
|
||||
TheISA::Predecoder predecoder;
|
||||
|
||||
std::list<DynInstPtr> instList;
|
||||
typedef typename std::list<DynInstPtr>::iterator InstListIt;
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -26,6 +38,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Kevin Lim
|
||||
* Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
@@ -34,25 +47,93 @@
|
||||
#include "arch/vtophys.hh"
|
||||
#include "base/refcnt.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/checker/cpu.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;
|
||||
//The CheckerCPU does alpha only
|
||||
using namespace AlphaISA;
|
||||
using namespace TheISA;
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
Checker<Impl>::advancePC(Fault fault)
|
||||
{
|
||||
if (fault != NoFault) {
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
fault->invoke(tc, curStaticInst);
|
||||
predecoder.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;
|
||||
predecoder.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
|
||||
@@ -60,8 +141,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
// 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",
|
||||
completed_inst->seqNum, completed_inst->readPC());
|
||||
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;
|
||||
}
|
||||
@@ -75,8 +156,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
} else {
|
||||
if (!completed_inst->isCompleted()) {
|
||||
if (youngestSN < completed_inst->seqNum) {
|
||||
DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
|
||||
completed_inst->seqNum, completed_inst->readPC());
|
||||
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;
|
||||
}
|
||||
@@ -91,17 +172,29 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
}
|
||||
}
|
||||
|
||||
// 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:%#x.\n",
|
||||
inst->seqNum, inst->readPC());
|
||||
unverifiedResult.integer = inst->readIntResult();
|
||||
unverifiedReq = inst->req;
|
||||
unverifiedMemData = inst->memData;
|
||||
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;
|
||||
@@ -116,15 +209,15 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
// 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",
|
||||
thread->readPC());
|
||||
DPRINTF(Checker, "Changed PC recently to %s\n",
|
||||
thread->pcState());
|
||||
if (willChangePC) {
|
||||
if (newPC == thread->readPC()) {
|
||||
if (newPCState == thread->pcState()) {
|
||||
DPRINTF(Checker, "Changed PC matches expected PC\n");
|
||||
} else {
|
||||
warn("%lli: Changed PC does not match expected PC, "
|
||||
"changed: %#x, expected: %#x",
|
||||
curTick(), thread->readPC(), newPC);
|
||||
"changed: %s, expected: %s",
|
||||
curTick(), thread->pcState(), newPCState);
|
||||
CheckerCPU::handleError();
|
||||
}
|
||||
willChangePC = false;
|
||||
@@ -133,118 +226,186 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
}
|
||||
if (changedNextPC) {
|
||||
DPRINTF(Checker, "Changed NextPC recently to %#x\n",
|
||||
thread->readNextPC());
|
||||
thread->nextInstAddr());
|
||||
changedNextPC = false;
|
||||
}
|
||||
|
||||
// Try to fetch the instruction
|
||||
uint64_t fetchOffset = 0;
|
||||
bool fetchDone = false;
|
||||
|
||||
#define IFETCH_FLAGS(pc) (FullSystem ? 0 : ((pc) & 1) ? PHYSICAL : 0)
|
||||
while (!fetchDone) {
|
||||
Addr fetch_PC = thread->instAddr();
|
||||
fetch_PC = (fetch_PC & PCMask) + fetchOffset;
|
||||
|
||||
uint64_t fetch_PC = thread->readPC() & ~3;
|
||||
// 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,
|
||||
fetch_PC, thread->contextId(),
|
||||
unverifiedInst->threadNumber);
|
||||
memReq->setVirt(0, fetch_PC, sizeof(MachInst),
|
||||
Request::INST_FETCH, thread->instAddr());
|
||||
|
||||
// set up memory request for instruction fetch
|
||||
memReq = new Request(inst->threadNumber, fetch_PC,
|
||||
sizeof(uint32_t),
|
||||
IFETCH_FLAGS(thread->readPC()),
|
||||
fetch_PC, thread->contextId(),
|
||||
inst->threadNumber);
|
||||
|
||||
bool succeeded = itb->translateAtomic(memReq, thread);
|
||||
fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute);
|
||||
|
||||
if (!succeeded) {
|
||||
if (inst->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 %#x was not found in the ITB!",
|
||||
curTick(), thread->readPC());
|
||||
handleError(inst);
|
||||
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
|
||||
thread->setPC(thread->readNextPC());
|
||||
thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
|
||||
// go to the next instruction
|
||||
advancePC(NoFault);
|
||||
|
||||
break;
|
||||
} 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();
|
||||
// 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,
|
||||
Packet::Broadcast);
|
||||
|
||||
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
|
||||
predecoder.setTC(thread->getTC());
|
||||
//If more fetch data is needed, pass it in.
|
||||
Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
|
||||
predecoder.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 (predecoder.extMachInstReady()) {
|
||||
fetchDone = true;
|
||||
ExtMachInst newMachInst =
|
||||
predecoder.getExtMachInst(pcState);
|
||||
thread->pcState(pcState);
|
||||
instPtr = thread->decoder.decode(newMachInst,
|
||||
pcState.instAddr());
|
||||
machInst = newMachInst;
|
||||
} 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 predecoder on Checker
|
||||
predecoder.reset();
|
||||
|
||||
// Check Checker and CPU get same instruction, and record
|
||||
// any faults the CPU may have had.
|
||||
Fault unverifiedFault;
|
||||
if (fault == NoFault) {
|
||||
PacketPtr pkt = new Packet(memReq, Packet::ReadReq,
|
||||
Packet::Broadcast);
|
||||
unverifiedFault = unverifiedInst->getFault();
|
||||
|
||||
pkt->dataStatic(&machInst);
|
||||
|
||||
icachePort->sendFunctional(pkt);
|
||||
|
||||
delete pkt;
|
||||
|
||||
// keep an instruction count
|
||||
numInst++;
|
||||
|
||||
// decode the instruction
|
||||
machInst = gtoh(machInst);
|
||||
// Checks that the instruction matches what we expected it to be.
|
||||
// Checks both the machine instruction and the PC.
|
||||
validateInst(inst);
|
||||
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
curStaticInst = StaticInst::decode(makeExtMI(machInst,
|
||||
thread->readPC()));
|
||||
#elif THE_ISA == SPARC_ISA
|
||||
curStaticInst = StaticInst::decode(makeExtMI(machInst,
|
||||
thread->getTC()));
|
||||
#endif
|
||||
|
||||
fault = inst->getFault();
|
||||
validateInst(unverifiedInst);
|
||||
}
|
||||
|
||||
// Discard fetch's memReq.
|
||||
delete memReq;
|
||||
memReq = NULL;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
thread->funcExeInst++;
|
||||
if (fault == NoFault && unverifiedFault == NoFault) {
|
||||
thread->funcExeInst++;
|
||||
// Checks to make sure instrution results are correct.
|
||||
validateExecution(unverifiedInst);
|
||||
|
||||
if (!inst->isUnverifiable())
|
||||
fault = curStaticInst->execute(this, NULL);
|
||||
|
||||
// Checks to make sure instrution results are correct.
|
||||
validateExecution(inst);
|
||||
|
||||
if (curStaticInst->isLoad()) {
|
||||
++numLoad;
|
||||
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) {
|
||||
fault->invoke(tc, curStaticInst);
|
||||
willChangePC = true;
|
||||
newPC = thread->readPC();
|
||||
DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
|
||||
newPCState = thread->pcState();
|
||||
DPRINTF(Checker, "Fault, PC is now %s\n", newPCState);
|
||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||
} else {
|
||||
#if THE_ISA != MIPS_ISA
|
||||
// go to the next instruction
|
||||
thread->setPC(thread->readNextPC());
|
||||
thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
|
||||
#else
|
||||
// go to the next instruction
|
||||
thread->setPC(thread->readNextPC());
|
||||
thread->setNextPC(thread->readNextNPC());
|
||||
thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
|
||||
#endif
|
||||
|
||||
advancePC(fault);
|
||||
}
|
||||
|
||||
if (FullSystem) {
|
||||
@@ -254,14 +415,14 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
Addr oldpc;
|
||||
int count = 0;
|
||||
do {
|
||||
oldpc = thread->readPC();
|
||||
oldpc = thread->instAddr();
|
||||
system->pcEventQueue.service(tc);
|
||||
count++;
|
||||
} while (oldpc != thread->readPC());
|
||||
} while (oldpc != thread->instAddr());
|
||||
if (count > 1) {
|
||||
willChangePC = true;
|
||||
newPC = thread->readPC();
|
||||
DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
|
||||
newPCState = thread->pcState();
|
||||
DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,17 +430,13 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
// that have been modified).
|
||||
validateState();
|
||||
|
||||
if (memReq) {
|
||||
delete memReq;
|
||||
memReq = NULL;
|
||||
}
|
||||
|
||||
// Continue verifying instructions if there's another completed
|
||||
// instruction waiting to be verified.
|
||||
if (instList.empty()) {
|
||||
break;
|
||||
} else if (instList.front()->isCompleted()) {
|
||||
inst = instList.front();
|
||||
unverifiedInst = NULL;
|
||||
unverifiedInst = instList.front();
|
||||
instList.pop_front();
|
||||
} else {
|
||||
break;
|
||||
@@ -288,26 +445,26 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
unverifiedInst = NULL;
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::switchOut()
|
||||
Checker<Impl>::switchOut()
|
||||
{
|
||||
instList.clear();
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
|
||||
Checker<Impl>::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
|
||||
Checker<Impl>::validateInst(DynInstPtr &inst)
|
||||
{
|
||||
if (inst->readPC() != thread->readPC()) {
|
||||
warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
|
||||
curTick(), inst->readPC(), thread->readPC());
|
||||
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());
|
||||
@@ -319,51 +476,70 @@ Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
|
||||
MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
|
||||
|
||||
if (mi != machInst) {
|
||||
warn("%lli: Binary instructions do not match! Inst: %#x, "
|
||||
panic("%lli: Binary instructions do not match! Inst: %#x, "
|
||||
"checker: %#x",
|
||||
curTick(), mi, machInst);
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
|
||||
Checker<Impl>::validateExecution(DynInstPtr &inst)
|
||||
{
|
||||
uint64_t checker_val;
|
||||
uint64_t inst_val;
|
||||
int idx = -1;
|
||||
bool result_mismatch = false;
|
||||
if (inst->numDestRegs()) {
|
||||
// @todo: Support more destination registers.
|
||||
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);
|
||||
} else if (result.integer != inst->readIntResult()) {
|
||||
result_mismatch = true;
|
||||
|
||||
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->readIntResult(), result.integer);
|
||||
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);
|
||||
copyResult(inst, inst_val, idx);
|
||||
} else {
|
||||
handleError(inst);
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->readNextPC() != thread->readNextPC()) {
|
||||
if (inst->nextInstAddr() != thread->nextInstAddr()) {
|
||||
warn("%lli: Instruction next PCs do not match! Inst: %#x, "
|
||||
"checker: %#x",
|
||||
curTick(), inst->readNextPC(), thread->readNextPC());
|
||||
curTick(), inst->nextInstAddr(), thread->nextInstAddr());
|
||||
handleError(inst);
|
||||
}
|
||||
|
||||
@@ -388,53 +564,78 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
|
||||
}
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
|
||||
// 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<DynInstPtr>::validateState()
|
||||
Checker<Impl>::validateState()
|
||||
{
|
||||
if (updateThisCycle) {
|
||||
warn("%lli: Instruction PC %#x results didn't match up, copying all "
|
||||
"registers from main CPU", curTick(), unverifiedInst->readPC());
|
||||
// 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.
|
||||
#if THE_ISA != MIPS_ISA
|
||||
// go to the next instruction
|
||||
thread->setPC(thread->readNextPC());
|
||||
thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
|
||||
#else
|
||||
// go to the next instruction
|
||||
thread->setPC(thread->readNextPC());
|
||||
thread->setNextPC(thread->readNextNPC());
|
||||
thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
|
||||
#endif
|
||||
advancePC(NoFault);
|
||||
updateThisCycle = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
|
||||
Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
|
||||
int start_idx)
|
||||
{
|
||||
RegIndex idx = inst->destRegIdx(0);
|
||||
if (idx < TheISA::FP_Base_DepTag) {
|
||||
thread->setIntReg(idx, inst->readIntResult());
|
||||
} else if (idx < TheISA::Fpcr_DepTag) {
|
||||
thread->setFloatRegBits(idx, inst->readIntResult());
|
||||
} else {
|
||||
thread->setMiscRegNoEffect(idx, inst->readIntResult());
|
||||
// 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 DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
|
||||
Checker<Impl>::dumpAndExit(DynInstPtr &inst)
|
||||
{
|
||||
cprintf("Error detected, instruction information:\n");
|
||||
cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
|
||||
cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
|
||||
"Completed:%i\n",
|
||||
inst->readPC(),
|
||||
inst->readNextPC(),
|
||||
inst->pcState(),
|
||||
inst->nextInstAddr(),
|
||||
inst->seqNum,
|
||||
inst->threadNumber,
|
||||
inst->isCompleted());
|
||||
@@ -442,9 +643,9 @@ Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
|
||||
CheckerCPU::dumpAndExit();
|
||||
}
|
||||
|
||||
template <class DynInstPtr>
|
||||
template <class Impl>
|
||||
void
|
||||
Checker<DynInstPtr>::dumpInsts()
|
||||
Checker<Impl>::dumpInsts()
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
@@ -457,9 +658,9 @@ Checker<DynInstPtr>::dumpInsts()
|
||||
cprintf("Instruction:%i\n",
|
||||
num);
|
||||
|
||||
cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
|
||||
cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n"
|
||||
"Completed:%i\n",
|
||||
(*inst_list_it)->readPC(),
|
||||
(*inst_list_it)->pcState(),
|
||||
(*inst_list_it)->seqNum,
|
||||
(*inst_list_it)->threadNumber,
|
||||
(*inst_list_it)->isCompleted());
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -36,6 +48,7 @@
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Checker.hh"
|
||||
|
||||
class EndQuiesceEvent;
|
||||
namespace TheISA {
|
||||
@@ -77,18 +90,32 @@ class CheckerThreadContext : public ThreadContext
|
||||
|
||||
BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
|
||||
|
||||
void setCpuId(int id)
|
||||
int cpuId() { return actualTC->cpuId(); }
|
||||
|
||||
int contextId() { return actualTC->contextId(); }
|
||||
|
||||
void setContextId(int id)
|
||||
{
|
||||
actualTC->setCpuId(id);
|
||||
checkerTC->setCpuId(id);
|
||||
actualTC->setContextId(id);
|
||||
checkerTC->setContextId(id);
|
||||
}
|
||||
|
||||
int cpuId() { return actualTC->cpuId(); }
|
||||
/** 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(); }
|
||||
|
||||
BaseCPU *getCheckerCpuPtr() { return checkerTC->getCpuPtr(); }
|
||||
|
||||
Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
|
||||
|
||||
System *getSystemPtr() { return actualTC->getSystemPtr(); }
|
||||
|
||||
PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); }
|
||||
@@ -103,8 +130,21 @@ class CheckerThreadContext : public ThreadContext
|
||||
FSTranslatingPortProxy* getVirtProxy()
|
||||
{ return actualTC->getVirtProxy(); }
|
||||
|
||||
//XXX: How does this work now?
|
||||
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)
|
||||
@@ -118,10 +158,10 @@ class CheckerThreadContext : public ThreadContext
|
||||
void activate(int delay = 1) { actualTC->activate(delay); }
|
||||
|
||||
/// Set the status to Suspended.
|
||||
void suspend() { actualTC->suspend(); }
|
||||
void suspend(int delay) { actualTC->suspend(delay); }
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt() { actualTC->halt(); }
|
||||
void halt(int delay) { actualTC->halt(delay); }
|
||||
|
||||
void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
|
||||
|
||||
@@ -131,7 +171,11 @@ class CheckerThreadContext : public ThreadContext
|
||||
checkerTC->copyState(oldContext);
|
||||
}
|
||||
|
||||
void regStats(const std::string &name) { actualTC->regStats(name); }
|
||||
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)
|
||||
@@ -145,8 +189,6 @@ class CheckerThreadContext : public ThreadContext
|
||||
void profileClear() { return actualTC->profileClear(); }
|
||||
void profileSample() { return actualTC->profileSample(); }
|
||||
|
||||
int threadId() { return actualTC->threadId(); }
|
||||
|
||||
// @todo: Do I need this?
|
||||
void copyArchRegs(ThreadContext *tc)
|
||||
{
|
||||
@@ -190,32 +232,36 @@ class CheckerThreadContext : public ThreadContext
|
||||
checkerTC->setFloatRegBits(reg_idx, val);
|
||||
}
|
||||
|
||||
uint64_t readPC() { return actualTC->readPC(); }
|
||||
/** Reads this thread's PC state. */
|
||||
TheISA::PCState pcState()
|
||||
{ return actualTC->pcState(); }
|
||||
|
||||
void setPC(uint64_t val)
|
||||
/** Sets this thread's PC state. */
|
||||
void pcState(const TheISA::PCState &val)
|
||||
{
|
||||
actualTC->setPC(val);
|
||||
checkerTC->setPC(val);
|
||||
DPRINTF(Checker, "Changing PC to %s, old PC %s\n",
|
||||
val, checkerTC->pcState());
|
||||
checkerTC->pcState(val);
|
||||
checkerCPU->recordPCChange(val);
|
||||
return actualTC->pcState(val);
|
||||
}
|
||||
|
||||
uint64_t readNextPC() { return actualTC->readNextPC(); }
|
||||
|
||||
void setNextPC(uint64_t val)
|
||||
void pcStateNoRecord(const TheISA::PCState &val)
|
||||
{
|
||||
actualTC->setNextPC(val);
|
||||
checkerTC->setNextPC(val);
|
||||
checkerCPU->recordNextPCChange(val);
|
||||
return actualTC->pcState(val);
|
||||
}
|
||||
|
||||
uint64_t readNextNPC() { return actualTC->readNextNPC(); }
|
||||
/** Reads this thread's PC. */
|
||||
Addr instAddr()
|
||||
{ return actualTC->instAddr(); }
|
||||
|
||||
void setNextNPC(uint64_t val)
|
||||
{
|
||||
actualTC->setNextNPC(val);
|
||||
checkerTC->setNextNPC(val);
|
||||
checkerCPU->recordNextPCChange(val);
|
||||
}
|
||||
/** 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); }
|
||||
@@ -225,22 +271,28 @@ class CheckerThreadContext : public ThreadContext
|
||||
|
||||
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)
|
||||
{
|
||||
checkerTC->setStCondFailures(sc_failures);
|
||||
actualTC->setStCondFailures(sc_failures);
|
||||
}
|
||||
|
||||
|
||||
97
src/cpu/dummy_checker_builder.cc
Normal file
97
src/cpu/dummy_checker_builder.cc
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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: Geoffrey Blake
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/DummyChecker.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class MemObject;
|
||||
|
||||
/**
|
||||
* Specific non-templated derived class used for SimObject configuration.
|
||||
*/
|
||||
class DummyChecker : public CheckerCPU
|
||||
{
|
||||
public:
|
||||
DummyChecker(Params *p)
|
||||
: CheckerCPU(p)
|
||||
{ }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DummyChecker Simulation Object
|
||||
//
|
||||
DummyChecker *
|
||||
DummyCheckerParams::create()
|
||||
{
|
||||
DummyChecker::Params *params = new DummyChecker::Params();
|
||||
params->name = name;
|
||||
params->numThreads = numThreads;
|
||||
params->max_insts_any_thread = 0;
|
||||
params->max_insts_all_threads = 0;
|
||||
params->max_loads_any_thread = 0;
|
||||
params->max_loads_all_threads = 0;
|
||||
params->clock = clock;
|
||||
// Hack to touch all parameters. Consider not deriving Checker
|
||||
// from BaseCPU..it's not really a CPU in the end.
|
||||
Counter temp;
|
||||
temp = max_insts_any_thread;
|
||||
temp = max_insts_all_threads;
|
||||
temp = max_loads_any_thread;
|
||||
temp = max_loads_all_threads;
|
||||
Tick temp2 = progress_interval;
|
||||
params->progress_interval = 0;
|
||||
temp2++;
|
||||
|
||||
params->itb = itb;
|
||||
params->dtb = dtb;
|
||||
params->system = system;
|
||||
params->cpu_id = cpu_id;
|
||||
params->profile = profile;
|
||||
params->interrupts = NULL;
|
||||
params->workload = workload;
|
||||
|
||||
DummyChecker *cpu = new DummyChecker(params);
|
||||
return cpu;
|
||||
}
|
||||
@@ -47,8 +47,9 @@
|
||||
//
|
||||
//
|
||||
|
||||
struct OpDesc : public SimObject
|
||||
class OpDesc : public SimObject
|
||||
{
|
||||
public:
|
||||
OpClass opClass;
|
||||
unsigned opLat;
|
||||
unsigned issueLat;
|
||||
@@ -58,8 +59,9 @@ struct OpDesc : public SimObject
|
||||
issueLat(p->issueLat) {};
|
||||
};
|
||||
|
||||
struct FUDesc : public SimObject
|
||||
class FUDesc : public SimObject
|
||||
{
|
||||
public:
|
||||
std::vector<OpDesc *> opDescList;
|
||||
unsigned number;
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ InOrderCPU::TickEvent::process()
|
||||
|
||||
|
||||
const char *
|
||||
InOrderCPU::TickEvent::description()
|
||||
InOrderCPU::TickEvent::description() const
|
||||
{
|
||||
return "InOrderCPU tick event";
|
||||
}
|
||||
@@ -165,7 +165,7 @@ InOrderCPU::CPUEvent::process()
|
||||
|
||||
|
||||
const char *
|
||||
InOrderCPU::CPUEvent::description()
|
||||
InOrderCPU::CPUEvent::description() const
|
||||
{
|
||||
return "InOrderCPU event";
|
||||
}
|
||||
@@ -1156,11 +1156,11 @@ InOrderCPU::activateNextReadyContext(int delay)
|
||||
}
|
||||
|
||||
void
|
||||
InOrderCPU::haltContext(ThreadID tid, int delay)
|
||||
InOrderCPU::haltContext(ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderCPU, "[tid:%i]: Calling Halt Context...\n", tid);
|
||||
|
||||
scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid], delay);
|
||||
scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid]);
|
||||
|
||||
activityRec.activity();
|
||||
}
|
||||
@@ -1181,9 +1181,9 @@ InOrderCPU::haltThread(ThreadID tid)
|
||||
}
|
||||
|
||||
void
|
||||
InOrderCPU::suspendContext(ThreadID tid, int delay)
|
||||
InOrderCPU::suspendContext(ThreadID tid)
|
||||
{
|
||||
scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid], delay);
|
||||
scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid]);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -147,7 +147,7 @@ class InOrderCPU : public BaseCPU
|
||||
void process();
|
||||
|
||||
/** Returns the description of the tick event. */
|
||||
const char *description();
|
||||
const char *description() const;
|
||||
};
|
||||
|
||||
/** The tick event used for scheduling CPU ticks. */
|
||||
@@ -229,7 +229,7 @@ class InOrderCPU : public BaseCPU
|
||||
void process();
|
||||
|
||||
/** Returns the description of the CPU event. */
|
||||
const char *description();
|
||||
const char *description() const;
|
||||
|
||||
/** Schedule Event */
|
||||
void scheduleEvent(int delay);
|
||||
@@ -469,13 +469,13 @@ class InOrderCPU : public BaseCPU
|
||||
void deactivateThread(ThreadID tid);
|
||||
|
||||
/** Schedule a thread suspension on the CPU */
|
||||
void suspendContext(ThreadID tid, int delay = 0);
|
||||
void suspendContext(ThreadID tid);
|
||||
|
||||
/** Suspend Thread, Remove from Active Threads List, Add to Suspend List */
|
||||
void suspendThread(ThreadID tid);
|
||||
|
||||
/** Schedule a thread halt on the CPU */
|
||||
void haltContext(ThreadID tid, int delay = 0);
|
||||
void haltContext(ThreadID tid);
|
||||
|
||||
/** Halt Thread, Remove from Active Thread List, Place Thread on Halted
|
||||
* Threads List
|
||||
|
||||
@@ -512,7 +512,7 @@ ResourceEvent::process()
|
||||
}
|
||||
|
||||
const char *
|
||||
ResourceEvent::description()
|
||||
ResourceEvent::description() const
|
||||
{
|
||||
string desc = resource->name() + "-event:slot[" + to_string(slotIdx)
|
||||
+ "]";
|
||||
|
||||
@@ -51,6 +51,9 @@ class ResourceRequest;
|
||||
typedef ResourceRequest ResReq;
|
||||
typedef ResourceRequest* ResReqPtr;
|
||||
|
||||
class CacheRequest;
|
||||
typedef CacheRequest* CacheReqPtr;
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
typedef ThePipeline::DynInstPtr DynInstPtr;
|
||||
@@ -154,8 +157,9 @@ class Resource {
|
||||
* if instruction is actually in resource before
|
||||
* trying to do access.Needs to be defined for derived units.
|
||||
*/
|
||||
virtual Fault doCacheAccess(DynInstPtr inst, uint64_t *res=NULL)
|
||||
{ panic("doCacheAccess undefined for %s", name()); return NoFault; }
|
||||
virtual void doCacheAccess(DynInstPtr inst, uint64_t *write_result = NULL,
|
||||
CacheReqPtr split_req = NULL)
|
||||
{ panic("doCacheAccess undefined for %s", name()); }
|
||||
|
||||
/** Setup Squash to be sent out to pipeline and resource pool */
|
||||
void setupSquash(DynInstPtr inst, int stage_num, ThreadID tid);
|
||||
@@ -283,7 +287,7 @@ class ResourceEvent : public Event
|
||||
virtual void process();
|
||||
|
||||
/** Returns the description of the resource event. */
|
||||
const char *description();
|
||||
const char *description() const;
|
||||
|
||||
/** Set slot idx for event */
|
||||
void setSlot(int slot) { slotIdx = slot; }
|
||||
@@ -320,7 +324,7 @@ class ResourceRequest
|
||||
|
||||
int reqID;
|
||||
|
||||
virtual void setRequest(DynInstPtr _inst, int stage_num,
|
||||
void setRequest(DynInstPtr _inst, int stage_num,
|
||||
int res_idx, int slot_num, unsigned _cmd);
|
||||
|
||||
virtual void clearRequest();
|
||||
|
||||
@@ -485,7 +485,7 @@ ResourcePool::ResPoolEvent::process()
|
||||
|
||||
|
||||
const char *
|
||||
ResourcePool::ResPoolEvent::description()
|
||||
ResourcePool::ResPoolEvent::description() const
|
||||
{
|
||||
return "Resource Pool event";
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class ResourcePool {
|
||||
void process();
|
||||
|
||||
/** Returns the description of the resource event. */
|
||||
const char *description();
|
||||
const char *description() const;
|
||||
|
||||
/** Schedule Event */
|
||||
void scheduleEvent(int delay);
|
||||
|
||||
@@ -49,9 +49,6 @@
|
||||
#include "params/InOrderCPU.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class CacheRequest;
|
||||
typedef CacheRequest* CacheReqPtr;
|
||||
|
||||
class CacheReqPacket;
|
||||
typedef CacheReqPacket* CacheReqPktPtr;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ InOrderThreadContext::suspend(int delay)
|
||||
return;
|
||||
|
||||
thread->setStatus(ThreadContext::Suspended);
|
||||
cpu->suspendContext(thread->threadId(), delay);
|
||||
cpu->suspendContext(thread->threadId());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -135,7 +135,7 @@ InOrderThreadContext::halt(int delay)
|
||||
return;
|
||||
|
||||
thread->setStatus(ThreadContext::Halted);
|
||||
cpu->haltContext(thread->threadId(), delay);
|
||||
cpu->haltContext(thread->threadId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ class NativeTrace : public ExeTracer
|
||||
{
|
||||
size_t soFar = 0;
|
||||
while (soFar < size) {
|
||||
size_t res = ::read(fd, (uint8_t *)ptr + soFar, size - soFar);
|
||||
ssize_t res = ::read(fd, (uint8_t *)ptr + soFar, size - soFar);
|
||||
if (res < 0)
|
||||
panic("Read call failed! %s\n", strerror(errno));
|
||||
else
|
||||
|
||||
@@ -40,11 +40,15 @@ class DerivO3CPU(BaseCPU):
|
||||
activity = Param.Unsigned(0, "Initial count")
|
||||
|
||||
if buildEnv['USE_CHECKER']:
|
||||
checker = Param.BaseCPU(O3Checker(workload=Parent.workload,
|
||||
# FIXME: Shouldn't need to derefernce Parent.workload
|
||||
# Somewhere in the param parsing code
|
||||
# src/python/m5/params.py is and error that
|
||||
# has trouble converting the workload parameter properly.
|
||||
checker = Param.BaseCPU(O3Checker(workload=Parent.workload[0],
|
||||
exitOnError=False,
|
||||
updateOnError=True,
|
||||
warnOnlyOnLoadError=False),
|
||||
"checker")
|
||||
warnOnlyOnLoadError=True),
|
||||
"checker")
|
||||
checker.itb = Parent.itb
|
||||
checker.dtb = Parent.dtb
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class O3Checker(BaseCPU):
|
||||
exitOnError = Param.Bool(False, "Exit on an error")
|
||||
updateOnError = Param.Bool(False,
|
||||
"Update the checker with the main CPU's state on an error")
|
||||
warnOnlyOnLoadError = Param.Bool(False,
|
||||
warnOnlyOnLoadError = Param.Bool(True,
|
||||
"If a load result is incorrect, only print a warning and do not exit")
|
||||
function_trace = Param.Bool(False, "Enable function trace")
|
||||
function_trace_start = Param.Tick(0, "Cycle to start function trace")
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "cpu/pred/tournament.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
/**
|
||||
* Basically a wrapper class to hold both the branch predictor
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -31,8 +43,8 @@
|
||||
#include <string>
|
||||
|
||||
#include "cpu/checker/cpu_impl.hh"
|
||||
#include "cpu/o3/alpha/dyn_inst.hh"
|
||||
#include "cpu/o3/alpha/impl.hh"
|
||||
#include "cpu/o3/dyn_inst.hh"
|
||||
#include "cpu/o3/impl.hh"
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "params/O3Checker.hh"
|
||||
#include "sim/process.hh"
|
||||
@@ -41,16 +53,16 @@
|
||||
class MemObject;
|
||||
|
||||
template
|
||||
class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;
|
||||
class Checker<O3CPUImpl>;
|
||||
|
||||
/**
|
||||
* Specific non-templated derived class used for SimObject configuration.
|
||||
*/
|
||||
class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >
|
||||
class O3Checker : public Checker<O3CPUImpl>
|
||||
{
|
||||
public:
|
||||
O3Checker(Params *p)
|
||||
: Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p)
|
||||
: Checker<O3CPUImpl>(p)
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -63,7 +75,7 @@ O3CheckerParams::create()
|
||||
{
|
||||
O3Checker::Params *params = new O3Checker::Params();
|
||||
params->name = name;
|
||||
params->numberOfThreads = 1;
|
||||
params->numThreads = numThreads;
|
||||
params->max_insts_any_thread = 0;
|
||||
params->max_insts_all_threads = 0;
|
||||
params->max_loads_any_thread = 0;
|
||||
@@ -71,10 +83,8 @@ O3CheckerParams::create()
|
||||
params->exitOnError = exitOnError;
|
||||
params->updateOnError = updateOnError;
|
||||
params->warnOnlyOnLoadError = warnOnlyOnLoadError;
|
||||
params->deferRegistration = defer_registration;
|
||||
params->functionTrace = function_trace;
|
||||
params->functionTraceStart = function_trace_start;
|
||||
params->clock = clock;
|
||||
params->tracer = tracer;
|
||||
// Hack to touch all parameters. Consider not deriving Checker
|
||||
// from BaseCPU..it's not really a CPU in the end.
|
||||
Counter temp;
|
||||
@@ -91,7 +101,8 @@ O3CheckerParams::create()
|
||||
params->system = system;
|
||||
params->cpu_id = cpu_id;
|
||||
params->profile = profile;
|
||||
params->process = workload;
|
||||
params->interrupts = NULL;
|
||||
params->workload = workload;
|
||||
|
||||
O3Checker *cpu = new O3Checker(params);
|
||||
return cpu;
|
||||
|
||||
@@ -51,10 +51,10 @@
|
||||
#include "cpu/inst_seq.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
template <class>
|
||||
class O3ThreadState;
|
||||
struct O3ThreadState;
|
||||
|
||||
/**
|
||||
* DefaultCommit handles single threaded and SMT commit. Its width is
|
||||
|
||||
@@ -725,6 +725,12 @@ DefaultCommit<Impl>::handleInterrupt()
|
||||
assert(!thread[0]->inSyscall);
|
||||
thread[0]->inSyscall = true;
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->handlePendingInt();
|
||||
}
|
||||
#endif
|
||||
|
||||
// CPU will handle interrupt.
|
||||
cpu->processInterrupts(interrupt);
|
||||
|
||||
@@ -769,8 +775,8 @@ void
|
||||
DefaultCommit<Impl>::commit()
|
||||
{
|
||||
if (FullSystem) {
|
||||
// Check for any interrupt that we've already squashed for and start
|
||||
// processing it.
|
||||
// Check for any interrupt that we've already squashed for and
|
||||
// start processing it.
|
||||
if (interrupt != NoFault)
|
||||
handleInterrupt();
|
||||
|
||||
@@ -1128,7 +1134,8 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
|
||||
head_inst->setCompleted();
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker && head_inst->isStore()) {
|
||||
if (cpu->checker) {
|
||||
// Need to check the instruction before its fault is processed
|
||||
cpu->checker->verify(head_inst);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
|
||||
#if USE_CHECKER
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/checker/thread_context.hh"
|
||||
#endif
|
||||
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
@@ -72,7 +73,7 @@
|
||||
#include "debug/Activity.hh"
|
||||
#endif
|
||||
|
||||
class BaseCPUParams;
|
||||
struct BaseCPUParams;
|
||||
|
||||
using namespace TheISA;
|
||||
using namespace std;
|
||||
@@ -265,7 +266,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
|
||||
#if USE_CHECKER
|
||||
if (params->checker) {
|
||||
BaseCPU *temp_checker = params->checker;
|
||||
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
|
||||
checker = dynamic_cast<Checker<Impl> *>(temp_checker);
|
||||
checker->setIcachePort(&icachePort);
|
||||
checker->setSystem(params->system);
|
||||
} else {
|
||||
@@ -759,7 +760,8 @@ FullO3CPU<Impl>::activateContext(ThreadID tid, int delay)
|
||||
|
||||
template <class Impl>
|
||||
bool
|
||||
FullO3CPU<Impl>::deallocateContext(ThreadID tid, bool remove, int delay)
|
||||
FullO3CPU<Impl>::scheduleDeallocateContext(ThreadID tid, bool remove,
|
||||
int delay)
|
||||
{
|
||||
// Schedule removal of thread data from CPU
|
||||
if (delay){
|
||||
@@ -780,7 +782,7 @@ void
|
||||
FullO3CPU<Impl>::suspendContext(ThreadID tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
|
||||
bool deallocated = deallocateContext(tid, false, 1);
|
||||
bool deallocated = scheduleDeallocateContext(tid, false, 1);
|
||||
// If this was the last thread then unschedule the tick event.
|
||||
if ((activeThreads.size() == 1 && !deallocated) ||
|
||||
activeThreads.size() == 0)
|
||||
@@ -797,7 +799,7 @@ FullO3CPU<Impl>::haltContext(ThreadID tid)
|
||||
{
|
||||
//For now, this is the same as deallocate
|
||||
DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
|
||||
deallocateContext(tid, true, 1);
|
||||
scheduleDeallocateContext(tid, true, 1);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
@@ -1216,7 +1218,7 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
|
||||
|
||||
activityRec.reset();
|
||||
|
||||
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
|
||||
BaseCPU::takeOverFrom(oldCPU);
|
||||
|
||||
fetch.takeOverFrom();
|
||||
decode.takeOverFrom();
|
||||
|
||||
@@ -78,7 +78,7 @@ class Checkpoint;
|
||||
class MemObject;
|
||||
class Process;
|
||||
|
||||
class BaseCPUParams;
|
||||
struct BaseCPUParams;
|
||||
|
||||
class BaseO3CPU : public BaseCPU
|
||||
{
|
||||
@@ -400,7 +400,7 @@ class FullO3CPU : public BaseO3CPU
|
||||
/** Remove Thread from Active Threads List &&
|
||||
* Possibly Remove Thread Context from CPU.
|
||||
*/
|
||||
bool deallocateContext(ThreadID tid, bool remove, int delay = 1);
|
||||
bool scheduleDeallocateContext(ThreadID tid, bool remove, int delay = 1);
|
||||
|
||||
/** Remove Thread from Active Threads List &&
|
||||
* Remove Thread Context from CPU.
|
||||
@@ -725,7 +725,7 @@ class FullO3CPU : public BaseO3CPU
|
||||
* instruction results at run time. This can be set to NULL if it
|
||||
* is not being used.
|
||||
*/
|
||||
Checker<DynInstPtr> *checker;
|
||||
Checker<Impl> *checker;
|
||||
#endif
|
||||
|
||||
/** Pointer to the system. */
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "base/statistics.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
/**
|
||||
* DefaultDecode class handles both single threaded and SMT
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
#include "params/DerivO3CPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
using namespace std;
|
||||
// clang complains about std::set being overloaded with Packet::set if
|
||||
// we open up the entire namespace std
|
||||
using std::list;
|
||||
|
||||
template<class Impl>
|
||||
DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* Copyright (c) 2010-2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -41,6 +41,7 @@
|
||||
*/
|
||||
|
||||
#include "base/cp_annotate.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/o3/dyn_inst.hh"
|
||||
#include "sim/full_system.hh"
|
||||
|
||||
@@ -137,6 +138,11 @@ BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt)
|
||||
bool in_syscall = this->thread->inSyscall;
|
||||
this->thread->inSyscall = true;
|
||||
|
||||
#if USE_CHECKER
|
||||
if (this->isStoreConditional()) {
|
||||
this->reqToVerify->setExtraData(pkt->req->getExtraData());
|
||||
}
|
||||
#endif
|
||||
this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
|
||||
|
||||
this->thread->inSyscall = in_syscall;
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
#include "mem/port.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
/**
|
||||
* DefaultFetch class handles both single threaded and SMT fetch. Its
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/tlb.hh"
|
||||
@@ -52,7 +55,6 @@
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/o3/fetch.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "debug/Activity.hh"
|
||||
@@ -66,6 +68,10 @@
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#if USE_CHECKER
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#endif // USE_CHECKER
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class Impl>
|
||||
|
||||
@@ -252,7 +252,7 @@ FUPool::switchOut()
|
||||
}
|
||||
|
||||
void
|
||||
FUPool::takeOverFrom()
|
||||
FUPool::takeOver()
|
||||
{
|
||||
for (int i = 0; i < numFU; i++) {
|
||||
unitBusy[i] = false;
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/op_class.hh"
|
||||
#include "cpu/sched_list.hh"
|
||||
#include "params/FUPool.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
@@ -162,7 +161,7 @@ class FUPool : public SimObject
|
||||
void switchOut();
|
||||
|
||||
/** Takes over from another CPU's thread. */
|
||||
void takeOverFrom();
|
||||
void takeOver();
|
||||
};
|
||||
|
||||
#endif // __CPU_O3_FU_POOL_HH__
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "debug/IEW.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
class FUPool;
|
||||
|
||||
/**
|
||||
@@ -93,9 +93,6 @@ class DefaultIEW
|
||||
typedef typename CPUPol::RenameStruct RenameStruct;
|
||||
typedef typename CPUPol::IssueStruct IssueStruct;
|
||||
|
||||
friend class Impl::O3CPU;
|
||||
friend class CPUPol::IQ;
|
||||
|
||||
public:
|
||||
/** Overall IEW stage status. Used to determine if the CPU can
|
||||
* deschedule itself due to a lack of activity.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* Copyright (c) 2010-2011 ARM Limited
|
||||
* All rights reserved.
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#include "arch/utility.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/o3/fu_pool.hh"
|
||||
#include "cpu/o3/iew.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
@@ -56,6 +57,10 @@
|
||||
#include "debug/IEW.hh"
|
||||
#include "params/DerivO3CPU.hh"
|
||||
|
||||
#if USE_CHECKER
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#endif // USE_CHECKER
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class Impl>
|
||||
@@ -294,6 +299,13 @@ DefaultIEW<Impl>::initStage()
|
||||
ldstQueue.numFreeEntries(tid);
|
||||
}
|
||||
|
||||
// Initialize the checker's dcache port here
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setDcachePort(cpu->getDcachePort());
|
||||
}
|
||||
#endif
|
||||
|
||||
cpu->activateStage(O3CPU::IEWIdx);
|
||||
}
|
||||
|
||||
@@ -400,7 +412,7 @@ DefaultIEW<Impl>::takeOverFrom()
|
||||
|
||||
instQueue.takeOverFrom();
|
||||
ldstQueue.takeOverFrom();
|
||||
fuPool->takeOverFrom();
|
||||
fuPool->takeOver();
|
||||
|
||||
initStage();
|
||||
cpu->activityThisCycle();
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
#include "cpu/timebuf.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
class FUPool;
|
||||
class MemInterface;
|
||||
|
||||
@@ -93,8 +93,6 @@ class InstructionQueue
|
||||
// Typedef of iterator through the list of instructions.
|
||||
typedef typename std::list<DynInstPtr>::iterator ListIt;
|
||||
|
||||
friend class Impl::O3CPU;
|
||||
|
||||
/** FU completion event class. */
|
||||
class FUCompletion : public Event {
|
||||
private:
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
#include "params/DerivO3CPU.hh"
|
||||
#include "sim/core.hh"
|
||||
|
||||
using namespace std;
|
||||
// clang complains about std::set being overloaded with Packet::set if
|
||||
// we open up the entire namespace std
|
||||
using std::list;
|
||||
|
||||
template <class Impl>
|
||||
InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst,
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "mem/port.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
template <class Impl>
|
||||
class LSQ {
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/port.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
/**
|
||||
* Class that implements the actual LQ and SQ for each specific
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* Copyright (c) 2010-2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -45,7 +45,6 @@
|
||||
#include "arch/locked_mem.hh"
|
||||
#include "base/str.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/o3/lsq.hh"
|
||||
#include "cpu/o3/lsq_unit.hh"
|
||||
#include "debug/Activity.hh"
|
||||
@@ -246,12 +245,6 @@ void
|
||||
LSQUnit<Impl>::setDcachePort(Port *dcache_port)
|
||||
{
|
||||
dcachePort = dcache_port;
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setDcachePort(dcachePort);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class Impl>
|
||||
@@ -878,6 +871,11 @@ LSQUnit<Impl>::writebackStores()
|
||||
inst->seqNum);
|
||||
WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
|
||||
cpu->schedule(wb, curTick() + 1);
|
||||
#if USE_CHECKER
|
||||
// Make sure to set the LLSC data for verification
|
||||
inst->reqToVerify->setExtraData(0);
|
||||
inst->completeAcc(data_pkt);
|
||||
#endif
|
||||
completeStore(storeWBIdx);
|
||||
incrStIdx(storeWBIdx);
|
||||
continue;
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
#include "cpu/o3/mem_dep_unit_impl.hh"
|
||||
#include "cpu/o3/store_set.hh"
|
||||
|
||||
// Force instantation of memory dependency unit using store sets and
|
||||
// O3CPUImpl.
|
||||
template class MemDepUnit<StoreSet, O3CPUImpl>;
|
||||
|
||||
#ifdef DEBUG
|
||||
template <>
|
||||
int
|
||||
@@ -47,3 +43,7 @@ template <>
|
||||
int
|
||||
MemDepUnit<StoreSet, O3CPUImpl>::MemDepEntry::memdep_erase = 0;
|
||||
#endif
|
||||
|
||||
// Force instantation of memory dependency unit using store sets and
|
||||
// O3CPUImpl.
|
||||
template class MemDepUnit<StoreSet, O3CPUImpl>;
|
||||
|
||||
@@ -49,7 +49,7 @@ struct SNHash {
|
||||
}
|
||||
};
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
template <class Impl>
|
||||
class InstructionQueue;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/timebuf.hh"
|
||||
|
||||
class DerivO3CPUParams;
|
||||
struct DerivO3CPUParams;
|
||||
|
||||
/**
|
||||
* DefaultRename handles both single threaded and SMT rename. Its
|
||||
|
||||
@@ -65,7 +65,8 @@ class SatCounter
|
||||
* @param initial_val Starting value for each counter.
|
||||
*/
|
||||
SatCounter(unsigned bits, uint8_t initial_val)
|
||||
: initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val)
|
||||
: initialVal(initial_val), maxVal((1 << bits) - 1),
|
||||
counter(initial_val)
|
||||
{
|
||||
// Check to make sure initial value doesn't exceed the max
|
||||
// counter value.
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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) 2004-2006 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -32,6 +44,7 @@
|
||||
#define __CPU_O3_THREAD_CONTEXT_HH__
|
||||
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/o3/isa_specific.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
|
||||
@@ -71,6 +84,10 @@ class O3ThreadContext : public ThreadContext
|
||||
/** Returns a pointer to the DTB. */
|
||||
TheISA::TLB *getDTBPtr() { return cpu->dtb; }
|
||||
|
||||
#if USE_CHECKER
|
||||
BaseCPU *getCheckerCpuPtr() { return NULL; }
|
||||
#endif
|
||||
|
||||
Decoder *getDecoderPtr() { return &cpu->fetch.decoder; }
|
||||
|
||||
/** Returns a pointer to this CPU. */
|
||||
@@ -177,6 +194,10 @@ class O3ThreadContext : public ThreadContext
|
||||
/** Sets this thread's PC state. */
|
||||
virtual void pcState(const TheISA::PCState &val);
|
||||
|
||||
#if USE_CHECKER
|
||||
virtual void pcStateNoRecord(const TheISA::PCState &val);
|
||||
#endif
|
||||
|
||||
/** Reads this thread's PC. */
|
||||
virtual Addr instAddr()
|
||||
{ return cpu->instAddr(thread->threadId()); }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* Copyright (c) 2010-2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "arch/kernel_stats.hh"
|
||||
#include "arch/registers.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/o3/thread_context.hh"
|
||||
#include "cpu/quiesce_event.hh"
|
||||
#include "debug/O3CPU.hh"
|
||||
@@ -296,6 +297,20 @@ O3ThreadContext<Impl>::pcState(const TheISA::PCState &val)
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_CHECKER
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::pcStateNoRecord(const TheISA::PCState &val)
|
||||
{
|
||||
cpu->pcState(val, thread->threadId());
|
||||
|
||||
// Squash if we're not already in a state update mode.
|
||||
if (!thread->trapPending && !thread->inSyscall) {
|
||||
cpu->squashFromTC(thread->threadId());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Impl>
|
||||
int
|
||||
O3ThreadContext<Impl>::flattenIntIndex(int reg)
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
class ThreadContext;
|
||||
|
||||
/** Event for timing out quiesce instruction */
|
||||
struct EndQuiesceEvent : public Event
|
||||
class EndQuiesceEvent : public Event
|
||||
{
|
||||
public:
|
||||
/** A pointer to the thread context that is quiesced */
|
||||
ThreadContext *tc;
|
||||
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2005 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 Raasch
|
||||
*/
|
||||
|
||||
#ifndef SCHED_LIST_HH
|
||||
#define SCHED_LIST_HH
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "base/intmath.hh"
|
||||
#include "base/misc.hh"
|
||||
|
||||
// Any types you use this class for must be covered here...
|
||||
namespace {
|
||||
void ClearEntry(int &i) { i = 0; };
|
||||
void ClearEntry(unsigned &i) { i = 0; };
|
||||
void ClearEntry(double &i) { i = 0; };
|
||||
template <class T> void ClearEntry(std::list<T> &l) { l.clear(); };
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// this is a special list type that allows the user to insert elements at a
|
||||
// specified positive offset from the "current" element, but only allow them
|
||||
// be extracted from the "current" element
|
||||
//
|
||||
|
||||
|
||||
template <class T>
|
||||
class SchedList
|
||||
{
|
||||
T *data_array;
|
||||
unsigned position;
|
||||
unsigned size;
|
||||
unsigned mask;
|
||||
|
||||
public:
|
||||
SchedList(unsigned size);
|
||||
SchedList(void);
|
||||
|
||||
void init(unsigned size);
|
||||
|
||||
T &operator[](unsigned offset);
|
||||
|
||||
void advance(void);
|
||||
|
||||
void clear(void);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
template<class T>
|
||||
SchedList<T>::SchedList(unsigned _size)
|
||||
{
|
||||
size = _size;
|
||||
|
||||
// size must be a power of two
|
||||
if (!isPowerOf2(size)) {
|
||||
panic("SchedList: size must be a power of two");
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
panic("SchedList: you don't want a list that small");
|
||||
}
|
||||
|
||||
// calculate the bit mask for the modulo operation
|
||||
mask = size - 1;
|
||||
|
||||
data_array = new T[size];
|
||||
|
||||
if (!data_array) {
|
||||
panic("SchedList: could not allocate memory");
|
||||
}
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
SchedList<T>::SchedList(void)
|
||||
{
|
||||
data_array = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T> void
|
||||
SchedList<T>::init(unsigned _size)
|
||||
{
|
||||
size = _size;
|
||||
|
||||
if (!data_array) {
|
||||
// size must be a power of two
|
||||
if (size & (size-1)) {
|
||||
panic("SchedList: size must be a power of two");
|
||||
}
|
||||
|
||||
if (size < 2) {
|
||||
panic("SchedList: you don't want a list that small");
|
||||
}
|
||||
|
||||
// calculate the bit mask for the modulo operation
|
||||
mask = size - 1;
|
||||
|
||||
data_array = new T[size];
|
||||
|
||||
if (!data_array) {
|
||||
panic("SchedList: could not allocate memory");
|
||||
}
|
||||
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T> void
|
||||
SchedList<T>::advance(void)
|
||||
{
|
||||
ClearEntry(data_array[position]);
|
||||
|
||||
// position = (++position % size);
|
||||
position = ++position & mask;
|
||||
}
|
||||
|
||||
|
||||
template<class T> void
|
||||
SchedList<T>::clear(void)
|
||||
{
|
||||
for (unsigned i=0; i<size; ++i) {
|
||||
ClearEntry(data_array[i]);
|
||||
}
|
||||
|
||||
position = 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T> T&
|
||||
SchedList<T>::operator[](unsigned offset)
|
||||
{
|
||||
if (offset >= size) {
|
||||
panic("SchedList: can't access element beyond current pointer");
|
||||
}
|
||||
|
||||
// unsigned p = (position + offset) % size;
|
||||
unsigned p = (position + offset) & mask;
|
||||
|
||||
return data_array[p];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -26,9 +26,18 @@
|
||||
#
|
||||
# Authors: Gabe Black
|
||||
|
||||
from m5.defines import buildEnv
|
||||
from m5.params import *
|
||||
from BaseCPU import BaseCPU
|
||||
|
||||
if buildEnv['USE_CHECKER']:
|
||||
from DummyChecker import DummyChecker
|
||||
|
||||
class BaseSimpleCPU(BaseCPU):
|
||||
type = 'BaseSimpleCPU'
|
||||
abstract = True
|
||||
|
||||
if buildEnv['USE_CHECKER']:
|
||||
checker = Param.BaseCPU(DummyChecker(), "checker")
|
||||
checker.itb = BaseCPU.itb
|
||||
checker.dtb = BaseCPU.dtb
|
||||
|
||||
@@ -175,7 +175,7 @@ AtomicSimpleCPU::switchOut()
|
||||
void
|
||||
AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
|
||||
BaseCPU::takeOverFrom(oldCPU);
|
||||
|
||||
assert(!tickEvent.scheduled());
|
||||
|
||||
@@ -201,7 +201,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||
|
||||
|
||||
void
|
||||
AtomicSimpleCPU::activateContext(int thread_num, int delay)
|
||||
AtomicSimpleCPU::activateContext(ThreadID thread_num, int delay)
|
||||
{
|
||||
DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
|
||||
|
||||
@@ -221,7 +221,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay)
|
||||
|
||||
|
||||
void
|
||||
AtomicSimpleCPU::suspendContext(int thread_num)
|
||||
AtomicSimpleCPU::suspendContext(ThreadID thread_num)
|
||||
{
|
||||
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
|
||||
|
||||
|
||||
@@ -112,8 +112,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU
|
||||
void switchOut();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
virtual void activateContext(int thread_num, int delay);
|
||||
virtual void suspendContext(int thread_num);
|
||||
virtual void activateContext(ThreadID thread_num, int delay);
|
||||
virtual void suspendContext(ThreadID thread_num);
|
||||
|
||||
Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* Copyright (c) 2010-2011 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "base/trace.hh"
|
||||
#include "base/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/simple/base.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
@@ -79,6 +80,11 @@
|
||||
#include "sim/stats.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#if USE_CHECKER
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#include "cpu/checker/thread_context.hh"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
@@ -95,6 +101,19 @@ BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
|
||||
|
||||
tc = thread->getTC();
|
||||
|
||||
#if USE_CHECKER
|
||||
if (p->checker) {
|
||||
BaseCPU *temp_checker = p->checker;
|
||||
checker = dynamic_cast<CheckerCPU *>(temp_checker);
|
||||
checker->setSystem(p->system);
|
||||
// Manipulate thread context
|
||||
ThreadContext *cpu_tc = tc;
|
||||
tc = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker);
|
||||
} else {
|
||||
checker = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
numInst = 0;
|
||||
startNumInst = 0;
|
||||
numLoad = 0;
|
||||
@@ -114,7 +133,7 @@ BaseSimpleCPU::~BaseSimpleCPU()
|
||||
}
|
||||
|
||||
void
|
||||
BaseSimpleCPU::deallocateContext(int thread_num)
|
||||
BaseSimpleCPU::deallocateContext(ThreadID thread_num)
|
||||
{
|
||||
// for now, these are equivalent
|
||||
suspendContext(thread_num);
|
||||
@@ -122,7 +141,7 @@ BaseSimpleCPU::deallocateContext(int thread_num)
|
||||
|
||||
|
||||
void
|
||||
BaseSimpleCPU::haltContext(int thread_num)
|
||||
BaseSimpleCPU::haltContext(ThreadID thread_num)
|
||||
{
|
||||
// for now, these are equivalent
|
||||
suspendContext(thread_num);
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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) 2002-2005 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -36,6 +48,7 @@
|
||||
#include "arch/predecoder.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/decode.hh"
|
||||
#include "cpu/pc_event.hh"
|
||||
@@ -48,6 +61,10 @@
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#if USE_CHECKER
|
||||
#include "cpu/checker/cpu.hh"
|
||||
#endif
|
||||
|
||||
// forward declarations
|
||||
class Checkpoint;
|
||||
class MemObject;
|
||||
@@ -66,7 +83,7 @@ namespace Trace {
|
||||
class InstRecord;
|
||||
}
|
||||
|
||||
class BaseSimpleCPUParams;
|
||||
struct BaseSimpleCPUParams;
|
||||
|
||||
|
||||
class BaseSimpleCPU : public BaseCPU
|
||||
@@ -111,6 +128,10 @@ class BaseSimpleCPU : public BaseCPU
|
||||
* objects to modify this thread's state.
|
||||
*/
|
||||
ThreadContext *tc;
|
||||
|
||||
#if USE_CHECKER
|
||||
CheckerCPU *checker;
|
||||
#endif
|
||||
protected:
|
||||
|
||||
enum Status {
|
||||
@@ -157,8 +178,8 @@ class BaseSimpleCPU : public BaseCPU
|
||||
void postExecute();
|
||||
void advancePC(Fault fault);
|
||||
|
||||
virtual void deallocateContext(int thread_num);
|
||||
virtual void haltContext(int thread_num);
|
||||
virtual void deallocateContext(ThreadID thread_num);
|
||||
virtual void haltContext(ThreadID thread_num);
|
||||
|
||||
// statistics
|
||||
virtual void regStats();
|
||||
|
||||
@@ -176,7 +176,7 @@ TimingSimpleCPU::switchOut()
|
||||
void
|
||||
TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
|
||||
BaseCPU::takeOverFrom(oldCPU);
|
||||
|
||||
// if any of this CPU's ThreadContexts are active, mark the CPU as
|
||||
// running and schedule its tick event.
|
||||
@@ -197,7 +197,7 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||
|
||||
|
||||
void
|
||||
TimingSimpleCPU::activateContext(int thread_num, int delay)
|
||||
TimingSimpleCPU::activateContext(ThreadID thread_num, int delay)
|
||||
{
|
||||
DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
|
||||
|
||||
@@ -215,7 +215,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
|
||||
|
||||
|
||||
void
|
||||
TimingSimpleCPU::suspendContext(int thread_num)
|
||||
TimingSimpleCPU::suspendContext(ThreadID thread_num)
|
||||
{
|
||||
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
|
||||
|
||||
|
||||
@@ -244,8 +244,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||
void switchOut();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
virtual void activateContext(int thread_num, int delay);
|
||||
virtual void suspendContext(int thread_num);
|
||||
virtual void activateContext(ThreadID thread_num, int delay);
|
||||
virtual void suspendContext(ThreadID thread_num);
|
||||
|
||||
Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
|
||||
|
||||
|
||||
@@ -47,14 +47,13 @@
|
||||
#include "cpu/quiesce_event.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "params/BaseCPU.hh"
|
||||
#include "mem/fs_translating_port_proxy.hh"
|
||||
#include "mem/se_translating_port_proxy.hh"
|
||||
#include "params/BaseCPU.hh"
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/serialize.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
using namespace std;
|
||||
@@ -62,8 +61,7 @@ using namespace std;
|
||||
// constructor
|
||||
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process,
|
||||
TheISA::TLB *_itb, TheISA::TLB *_dtb)
|
||||
: ThreadState(_cpu, _thread_num, _process),
|
||||
cpu(_cpu), itb(_itb), dtb(_dtb)
|
||||
: ThreadState(_cpu, _thread_num, _process), itb(_itb), dtb(_dtb)
|
||||
{
|
||||
clearArchRegs();
|
||||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
@@ -71,9 +69,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process,
|
||||
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
|
||||
TheISA::TLB *_itb, TheISA::TLB *_dtb,
|
||||
bool use_kernel_stats)
|
||||
: ThreadState(_cpu, _thread_num, NULL),
|
||||
cpu(_cpu), system(_sys), itb(_itb), dtb(_dtb)
|
||||
|
||||
: ThreadState(_cpu, _thread_num, NULL), system(_sys), itb(_itb), dtb(_dtb)
|
||||
{
|
||||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
|
||||
@@ -81,7 +77,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
|
||||
|
||||
clearArchRegs();
|
||||
|
||||
if (cpu->params()->profile) {
|
||||
if (baseCpu->params()->profile) {
|
||||
profile = new FunctionProfile(system->kernelSymtab);
|
||||
Callback *cb =
|
||||
new MakeCallback<SimpleThread,
|
||||
@@ -183,7 +179,7 @@ SimpleThread::serialize(ostream &os)
|
||||
//
|
||||
// Now must serialize all the ISA dependent state
|
||||
//
|
||||
isa.serialize(cpu, os);
|
||||
isa.serialize(baseCpu, os);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,13 +195,14 @@ SimpleThread::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
//
|
||||
// Now must unserialize all the ISA dependent state
|
||||
//
|
||||
isa.unserialize(cpu, cp, section);
|
||||
isa.unserialize(baseCpu, cp, section);
|
||||
}
|
||||
|
||||
void
|
||||
SimpleThread::dumpFuncProfile()
|
||||
{
|
||||
std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
|
||||
std::ostream *os = simout.create(csprintf("profile.%s.dat",
|
||||
baseCpu->name()));
|
||||
profile->dump(tc, *os);
|
||||
}
|
||||
|
||||
@@ -225,7 +222,7 @@ SimpleThread::activate(int delay)
|
||||
_status = ThreadContext::Active;
|
||||
|
||||
// status() == Suspended
|
||||
cpu->activateContext(_threadId, delay);
|
||||
baseCpu->activateContext(_threadId, delay);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -237,7 +234,7 @@ SimpleThread::suspend()
|
||||
lastActivate = curTick();
|
||||
lastSuspend = curTick();
|
||||
_status = ThreadContext::Suspended;
|
||||
cpu->suspendContext(_threadId);
|
||||
baseCpu->suspendContext(_threadId);
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +245,7 @@ SimpleThread::halt()
|
||||
return;
|
||||
|
||||
_status = ThreadContext::Halted;
|
||||
cpu->haltContext(_threadId);
|
||||
baseCpu->haltContext(_threadId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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) 2001-2006 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -39,6 +51,7 @@
|
||||
#include "arch/types.hh"
|
||||
#include "base/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
#include "cpu/decode.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/thread_state.hh"
|
||||
@@ -106,12 +119,9 @@ class SimpleThread : public ThreadState
|
||||
public:
|
||||
std::string name() const
|
||||
{
|
||||
return csprintf("%s.[tid:%i]", cpu->name(), tc->threadId());
|
||||
return csprintf("%s.[tid:%i]", baseCpu->name(), tc->threadId());
|
||||
}
|
||||
|
||||
// pointer to CPU associated with this SimpleThread
|
||||
BaseCPU *cpu;
|
||||
|
||||
ProxyThreadContext<SimpleThread> *tc;
|
||||
|
||||
System *system;
|
||||
@@ -182,12 +192,16 @@ class SimpleThread : public ThreadState
|
||||
* ThreadContext interface functions.
|
||||
******************************************/
|
||||
|
||||
BaseCPU *getCpuPtr() { return cpu; }
|
||||
BaseCPU *getCpuPtr() { return baseCpu; }
|
||||
|
||||
TheISA::TLB *getITBPtr() { return itb; }
|
||||
|
||||
TheISA::TLB *getDTBPtr() { return dtb; }
|
||||
|
||||
#if USE_CHECKER
|
||||
BaseCPU *getCheckerCpuPtr() { return NULL; }
|
||||
#endif
|
||||
|
||||
Decoder *getDecoderPtr() { return &decoder; }
|
||||
|
||||
System *getSystemPtr() { return system; }
|
||||
@@ -281,7 +295,10 @@ class SimpleThread : public ThreadState
|
||||
{
|
||||
int flatIndex = isa.flattenFloatIndex(reg_idx);
|
||||
assert(flatIndex < TheISA::NumFloatRegs);
|
||||
floatRegs.i[flatIndex] = val;
|
||||
// XXX: Fix array out of bounds compiler error for gem5.fast
|
||||
// when checkercpu enabled
|
||||
if (flatIndex < TheISA::NumFloatRegs)
|
||||
floatRegs.i[flatIndex] = val;
|
||||
DPRINTF(FloatRegs, "Setting float reg %d (%d) bits to %#x, %#f.\n",
|
||||
reg_idx, flatIndex, val, floatRegs.f[flatIndex]);
|
||||
}
|
||||
@@ -298,6 +315,14 @@ class SimpleThread : public ThreadState
|
||||
_pcState = val;
|
||||
}
|
||||
|
||||
#if USE_CHECKER
|
||||
void
|
||||
pcStateNoRecord(const TheISA::PCState &val)
|
||||
{
|
||||
_pcState = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
Addr
|
||||
instAddr()
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ class ThreadContext;
|
||||
class DynInst;
|
||||
class Packet;
|
||||
|
||||
class O3CPUImpl;
|
||||
struct O3CPUImpl;
|
||||
template <class Impl> class BaseO3DynInst;
|
||||
typedef BaseO3DynInst<O3CPUImpl> O3DynInst;
|
||||
template <class Impl> class OzoneDynInst;
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -38,6 +50,7 @@
|
||||
#include "arch/types.hh"
|
||||
#include "base/types.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "config/use_checker.hh"
|
||||
|
||||
// @todo: Figure out a more architecture independent way to obtain the ITB and
|
||||
// DTB pointers.
|
||||
@@ -120,6 +133,10 @@ class ThreadContext
|
||||
|
||||
virtual TheISA::TLB *getDTBPtr() = 0;
|
||||
|
||||
#if USE_CHECKER
|
||||
virtual BaseCPU *getCheckerCpuPtr() = 0;
|
||||
#endif
|
||||
|
||||
virtual Decoder *getDecoderPtr() = 0;
|
||||
|
||||
virtual System *getSystemPtr() = 0;
|
||||
@@ -198,6 +215,10 @@ class ThreadContext
|
||||
|
||||
virtual void pcState(const TheISA::PCState &val) = 0;
|
||||
|
||||
#if USE_CHECKER
|
||||
virtual void pcStateNoRecord(const TheISA::PCState &val) = 0;
|
||||
#endif
|
||||
|
||||
virtual Addr instAddr() = 0;
|
||||
|
||||
virtual Addr nextInstAddr() = 0;
|
||||
@@ -287,6 +308,10 @@ class ProxyThreadContext : public ThreadContext
|
||||
|
||||
TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); }
|
||||
|
||||
#if USE_CHECKER
|
||||
BaseCPU *getCheckerCpuPtr() { return actualTC->getCheckerCpuPtr(); }
|
||||
#endif
|
||||
|
||||
Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
|
||||
|
||||
System *getSystemPtr() { return actualTC->getSystemPtr(); }
|
||||
@@ -367,6 +392,10 @@ class ProxyThreadContext : public ThreadContext
|
||||
|
||||
void pcState(const TheISA::PCState &val) { actualTC->pcState(val); }
|
||||
|
||||
#if USE_CHECKER
|
||||
void pcStateNoRecord(const TheISA::PCState &val) { actualTC->pcState(val); }
|
||||
#endif
|
||||
|
||||
Addr instAddr() { return actualTC->instAddr(); }
|
||||
Addr nextInstAddr() { return actualTC->nextInstAddr(); }
|
||||
MicroPC microPC() { return actualTC->microPC(); }
|
||||
|
||||
@@ -64,7 +64,7 @@ struct ThreadState {
|
||||
|
||||
ThreadState(BaseCPU *cpu, ThreadID _tid, Process *_process);
|
||||
|
||||
~ThreadState();
|
||||
virtual ~ThreadState();
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user