#include "arch/arm/utility.hh"
#include "base/trace.hh"
#include "cpu/static_inst.hh"
+ #include "sim/byteswap.hh"
+#include "sim/full_system.hh"
namespace ArmISA
{
case 0x41: return new Dumpstats(machInst);
case 0x42: return new Dumpresetstats(machInst);
case 0x43: return new M5checkpoint(machInst);
-#if FULL_SYSTEM
+ case 0x4F: return new M5writefile(machInst);
case 0x50: return new M5readfile(machInst);
-#endif
case 0x51: return new M5break(machInst);
case 0x52: return new M5switchcpu(machInst);
-#if FULL_SYSTEM
case 0x53: return new M5addsymbol(machInst);
-#endif
case 0x54: return new M5panic(machInst);
case 0x5a: return new M5workbegin(machInst);
case 0x5b: return new M5workend(machInst);
decoder_output += BasicConstructor.subst(m5readfileIop)
exec_output += PredOpExecute.subst(m5readfileIop)
-#if FULL_SYSTEM
+ m5writefileCode = '''
-#endif
+ int n = 4;
+ uint64_t offset = getArgument(xc->tcBase(), n, sizeof(uint64_t), false);
+ n = 6;
+ Addr filenameAddr = getArgument(xc->tcBase(), n, sizeof(Addr), false);
+ R0 = PseudoInst::writefile(xc->tcBase(), R0, join32to64(R3,R2), offset,
+ filenameAddr);
+ '''
+ m5writefileIop = InstObjParams("m5writefile", "M5writefile", "PredOp",
+ { "code": m5writefileCode,
+ "predicate_test": predicateTest },
+ ["IsNonSpeculative"])
+ header_output += BasicDeclare.subst(m5writefileIop)
+ decoder_output += BasicConstructor.subst(m5writefileIop)
+ exec_output += PredOpExecute.subst(m5writefileIop)
+
m5breakIop = InstObjParams("m5break", "M5break", "PredOp",
{ "code": "PseudoInst::debugbreak(xc->tcBase());",
"predicate_test": predicateTest },
return fault;
}
-#if FULL_SYSTEM
- fault = translateFs(req, tc, mode, NULL, delay, false, true);
-#else
- fault = translateSe(req, tc, mode, NULL, delay, false);
-#endif
+ Fault
+ TLB::translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode)
+ {
+ bool delay = false;
+ Fault fault;
++ if (FullSystem)
++ fault = translateFs(req, tc, mode, NULL, delay, false, true);
++ else
++ fault = translateSe(req, tc, mode, NULL, delay, false);
+ assert(!delay);
+ return fault;
+ }
+
Fault
TLB::translateTiming(RequestPtr req, ThreadContext *tc,
Translation *translation, Mode mode)
return _attr;
}
-#if FULL_SYSTEM
Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
- Translation *translation, bool &delay, bool timing);
+ Translation *translation, bool &delay,
+ bool timing, bool functional = false);
-#else
Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing);
-#endif
Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode);
Fault translateTiming(RequestPtr req, ThreadContext *tc,
Translation *translation, Mode mode);
#include "arch/arm/faults.hh"
#include "arch/arm/isa_traits.hh"
+#include "arch/arm/tlb.hh"
#include "arch/arm/utility.hh"
+#include "arch/arm/vtophys.hh"
+ #include "config/use_checker.hh"
#include "cpu/thread_context.hh"
-
-#if FULL_SYSTEM
-#include "arch/arm/vtophys.hh"
#include "mem/fs_translating_port_proxy.hh"
-#endif
-
-#include "arch/arm/tlb.hh"
+#include "sim/full_system.hh"
namespace ArmISA {
self.icache_port = ic.cpu_side
self.dcache_port = dc.cpu_side
self._cached_ports = ['icache.mem_side', 'dcache.mem_side']
- if buildEnv['FULL_SYSTEM']:
- if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
- if iwc and dwc:
- self.itb_walker_cache = iwc
- self.dtb_walker_cache = dwc
- self.itb.walker.port = iwc.cpu_side
- self.dtb.walker.port = dwc.cpu_side
- self._cached_ports += ["itb_walker_cache.mem_side", \
- "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"]
+ if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
+ if iwc and dwc:
+ self.itb_walker_cache = iwc
+ self.dtb_walker_cache = dwc
+ self.itb.walker.port = iwc.cpu_side
+ self.dtb.walker.port = dwc.cpu_side
+ self._cached_ports += ["itb_walker_cache.mem_side", \
+ "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)
Source('thread_context.cc')
Source('thread_state.cc')
-if env['FULL_SYSTEM']:
- SimObject('IntrControl.py')
-
- Source('intr_control.cc')
- Source('profile.cc')
-
- if env['TARGET_ISA'] == 'sparc':
- SimObject('LegionTrace.py')
- Source('legiontrace.cc')
+if env['TARGET_ISA'] == 'sparc':
+ SimObject('LegionTrace.py')
+ 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:
schedule(event, p->function_trace_start);
}
}
- interrupts->setCPU(this);
-#if FULL_SYSTEM
+ // Check if CPU model has interrupts connected. The CheckerCPU
+ // cannot take interrupts directly for example.
+ if (interrupts)
+ interrupts->setCPU(this);
- profileEvent = NULL;
- if (params()->profile)
- profileEvent = new ProfileEvent(this, params()->profile);
-#endif
+ if (FullSystem) {
+ profileEvent = NULL;
+ if (params()->profile)
+ profileEvent = new ProfileEvent(this, params()->profile);
+ }
tracer = params()->tracer;
}
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
+
}
-#if FULL_SYSTEM
interrupts = oldCPU->interrupts;
interrupts->setCPU(this);
#include "arch/utility.hh"
#include "base/fast_alloc.hh"
#include "base/trace.hh"
-#include "config/full_system.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"
#include "cpu/simple_thread.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
+ #include "params/CheckerCPU.hh"
+ #include "sim/tlb.hh"
-#if FULL_SYSTEM
-#include "arch/kernel_stats.hh"
-#include "arch/vtophys.hh"
-#endif // FULL_SYSTEM
-
using namespace std;
- //The CheckerCPU does alpha only
- using namespace AlphaISA;
+ using namespace TheISA;
void
CheckerCPU::init()
warnOnlyOnLoadError = p->warnOnlyOnLoadError;
itb = p->itb;
dtb = p->dtb;
-#if FULL_SYSTEM
systemPtr = NULL;
- process = p->process;
- thread = new SimpleThread(this, /* thread_num */ 0, process);
-#else
+ 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);
-#endif
- result.integer = 0;
+ updateOnError = true;
}
CheckerCPU::~CheckerCPU()
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;
+
+
+ if (secondAddr > addr)
+ size = secondAddr - addr;
+
+ // Need to account for multiple accesses like the Atomic and TimingSimple
+ while (1) {
+ memReq = new Request();
+ memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
+
+ // translate to physical address
+ fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
+
+ if (!checked_flags && fault == NoFault && unverifiedReq) {
+ flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
+ memReq->getPaddr(), memReq->getFlags());
+ pAddr = memReq->getPaddr();
+ checked_flags = true;
+ }
- memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
+ // 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;
+ }
- // translate to physical address
- dtb->translateAtomic(memReq, tc, false);
+ if (fault != NoFault) {
+ if (memReq->isPrefetch()) {
+ fault = NoFault;
+ }
+ delete memReq;
+ memReq = NULL;
+ break;
+ }
- PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
+ if (memReq != NULL) {
+ delete memReq;
+ }
- pkt->dataStatic(&data);
+ //If we don't need to access a second cache line, stop now.
+ if (secondAddr <= addr)
+ {
+ break;
+ }
- 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));
+ // Setup for accessing next cache line
+ data += size;
+ unverifiedMemData += size;
+ size = addr + fullSize - secondAddr;
+ addr = secondAddr;
}
- delete pkt;
+ 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::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)
+ CheckerCPU::writeMem(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res)
{
- return read(addr, *(uint64_t*)&data, flags);
- }
+ Fault fault = NoFault;
+ bool checked_flags = false;
+ bool flags_match = true;
+ Addr pAddr = 0x0;
- template<>
- Fault
- CheckerCPU::read(Addr addr, float &data, unsigned flags)
- {
- return read(addr, *(uint32_t*)&data, flags);
- }
+ unsigned blockSize = dcachePort->peerBlockSize();
+ int fullSize = size;
- template<>
- Fault
- CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
- {
- return read(addr, (uint32_t&)data, flags);
- }
+ Addr secondAddr = roundDown(addr + size - 1, blockSize);
- 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);
+ if (secondAddr > addr)
+ size = secondAddr - addr;
- dcachePort->sendFunctional(pkt);
+ // 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());
- delete pkt;
- */
- memcpy(&inst_data, unverifiedMemData, sizeof(T));
+ // translate to physical address
+ fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
- 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;
}
- }
-
- // 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();
-
- return NoFault;
- }
-
-
- #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)
- {
- return write(*(uint64_t*)&data, addr, flags, res);
- }
-
- template<>
- Fault
- CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
- {
- return write(*(uint32_t*)&data, addr, flags, res);
- }
+ /*
+ * 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;
+ }
- template<>
- Fault
- CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
- {
- return write((uint32_t)data, addr, flags, res);
+ //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;
}
-
-#if FULL_SYSTEM
Addr
CheckerCPU::dbg_vtophys(Addr addr)
{
return vtophys(tc, addr);
}
-#endif // FULL_SYSTEM
+ /**
+ * 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
#include <map>
#include <queue>
+ #include "arch/predecoder.hh"
#include "arch/types.hh"
#include "base/statistics.hh"
-#include "config/full_system.hh"
#include "cpu/base.hh"
#include "cpu/base_dyn_inst.hh"
#include "cpu/pc_event.hh"
{
class TLB;
}
-class Processor;
-class PhysicalMemory;
-#else
-
-class Process;
-
-#endif // FULL_SYSTEM
template <class>
class BaseDynInst;
- class CheckerCPUParams;
- class Checkpoint;
- class MemInterface;
- class PhysicalMemory;
- class Process;
- class Processor;
class ThreadContext;
-class MemInterface;
-class Checkpoint;
class Request;
/**
this->dtb->demapPage(vaddr, asn);
}
-#if FULL_SYSTEM
+ 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); }
-#else
+ 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) { }
#include <list>
#include <string>
+#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"
-#if FULL_SYSTEM
-#include "arch/vtophys.hh"
-#endif // FULL_SYSTEM
-
using namespace std;
- //The CheckerCPU does alpha only
- using namespace AlphaISA;
+ using namespace TheISA;
+
+ template <class Impl>
+ void
+ 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 DynInstPtr>
+ template <class Impl>
void
- Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
+ Checker<Impl>::verify(DynInstPtr &completed_inst)
{
DynInstPtr inst;
}
}
+ // Take any faults here
if (fault != NoFault) {
-#if FULL_SYSTEM
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;
-#endif
} 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 FULL_SYSTEM
- // @todo: Determine if these should happen only if the
- // instruction hasn't faulted. In the SimpleCPU case this may
- // not be true, but in the O3 or Ozone case this may be true.
- Addr oldpc;
- int count = 0;
- do {
- oldpc = thread->instAddr();
- system->pcEventQueue.service(tc);
- count++;
- } while (oldpc != thread->instAddr());
- if (count > 1) {
- willChangePC = true;
- newPCState = thread->pcState();
- DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
+ if (FullSystem) {
+ // @todo: Determine if these should happen only if the
+ // instruction hasn't faulted. In the SimpleCPU case this may
+ // not be true, but in the O3 or Ozone case this may be true.
+ Addr oldpc;
+ int count = 0;
+ do {
- oldpc = thread->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);
+ }
}
-#endif
// @todo: Optionally can check all registers. (Or just those
// that have been modified).
TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); }
+ BaseCPU *getCheckerCpuPtr() { return checkerTC->getCpuPtr(); }
+
+ Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); }
+
System *getSystemPtr() { return actualTC->getSystemPtr(); }
-#if FULL_SYSTEM
PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); }
TheISA::Kernel::Statistics *getKernelStats()
FSTranslatingPortProxy* getVirtProxy()
{ return actualTC->getVirtProxy(); }
-#else
- SETranslatingPortProxy* getMemProxy() { return actualTC->getMemProxy(); }
+ //XXX: How does this work now?
+ void initMemProxies(ThreadContext *tc)
+ { actualTC->initMemProxies(tc); }
+
+ void connectMemPorts(ThreadContext *tc)
+ {
+ actualTC->connectMemPorts(tc);
+ }
- Process *getProcessPtr() { return actualTC->getProcessPtr(); }
+
+ SETranslatingPortProxy* getMemProxy() { return actualTC->getMemProxy(); }
-#endif
+ /** 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)
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); }
-#if FULL_SYSTEM
void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
-#endif
void takeOverFrom(ThreadContext *oldContext)
{
void profileClear() { return actualTC->profileClear(); }
void profileSample() { return actualTC->profileSample(); }
-#endif
- int threadId() { return actualTC->threadId(); }
-
// @todo: Do I need this?
void copyArchRegs(ThreadContext *tc)
{
--- /dev/null
-#if FULL_SYSTEM
+ /*
+ * 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;
-#else
+ params->profile = profile;
+ params->interrupts = NULL;
-#endif
+ params->workload = workload;
+
+ DummyChecker *cpu = new DummyChecker(params);
+ return cpu;
+ }
activity = Param.Unsigned(0, "Initial count")
if buildEnv['USE_CHECKER']:
- checker = Param.BaseCPU(O3Checker(workload=Parent.workload,
- if not buildEnv['FULL_SYSTEM']:
- # 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=True),
- "checker")
- else:
- checker = Param.BaseCPU(O3Checker(exitOnError=False,
- updateOnError=True,
- warnOnlyOnLoadError=True),
- "checker")
++ # 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
params->dtb = dtb;
params->system = system;
params->cpu_id = cpu_id;
-#if FULL_SYSTEM
params->profile = profile;
- params->process = workload;
+ params->interrupts = NULL;
-#else
+ params->workload = workload;
-#endif
O3Checker *cpu = new O3Checker(params);
return cpu;
void
DefaultCommit<Impl>::commit()
{
-
-#if FULL_SYSTEM
- // Check for any interrupt that we've already squashed for and
- // start processing it.
- if (interrupt != NoFault)
- handleInterrupt();
-
- // Check if we have a interrupt and get read to handle it
- if (cpu->checkInterrupts(cpu->tcBase(0)))
- propagateInterrupt();
-#endif // FULL_SYSTEM
+ 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();
+
+ // Check if we have a interrupt and get read to handle it
+ if (cpu->checkInterrupts(cpu->tcBase(0)))
+ propagateInterrupt();
+ }
////////////////////////////////////
// Check for any possible squashes, handle them first
#include "sim/stat_control.hh"
#include "sim/system.hh"
-#if FULL_SYSTEM
-#include "cpu/quiesce_event.hh"
-#else
-#include "sim/process.hh"
-#endif
-
#if USE_CHECKER
#include "cpu/checker/cpu.hh"
+ #include "cpu/checker/thread_context.hh"
#endif
#if THE_ISA == ALPHA_ISA
#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);
-#if FULL_SYSTEM
checker->setSystem(params->system);
-#endif
} else {
checker = NULL;
}
#include "debug/Activity.hh"
#include "debug/Decode.hh"
#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)
*/
#include "base/cp_annotate.hh"
+ #include "config/use_checker.hh"
#include "cpu/o3/dyn_inst.hh"
+#include "sim/full_system.hh"
template <class Impl>
BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr staticInst,
#include <algorithm>
#include <cstring>
+ #include <list>
+ #include <map>
+ #include <queue>
#include "arch/isa_traits.hh"
+#include "arch/tlb.hh"
#include "arch/utility.hh"
+#include "arch/vtophys.hh"
#include "base/types.hh"
#include "config/the_isa.hh"
#include "config/use_checker.hh"
#include "sim/byteswap.hh"
#include "sim/core.hh"
#include "sim/eventq.hh"
-
-#if FULL_SYSTEM
-#include "arch/tlb.hh"
-#include "arch/vtophys.hh"
+#include "sim/full_system.hh"
#include "sim/system.hh"
-#endif // FULL_SYSTEM
+ #if USE_CHECKER
+ #include "cpu/checker/cpu.hh"
+ #endif // USE_CHECKER
+
using namespace std;
template<class Impl>
* Korey Sewell
*/
+#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"
#include "sim/stats.hh"
#include "sim/system.hh"
-#if FULL_SYSTEM
-#include "arch/kernel_stats.hh"
-#include "arch/stacktrace.hh"
-#include "arch/tlb.hh"
-#include "arch/vtophys.hh"
-#else // !FULL_SYSTEM
-#include "mem/mem_object.hh"
-#endif // FULL_SYSTEM
-
+ #if USE_CHECKER
+ #include "cpu/checker/cpu.hh"
+ #include "cpu/checker/thread_context.hh"
+ #endif
+
using namespace std;
using namespace TheISA;
tc = thread->getTC();
-#if FULL_SYSTEM
+ #if USE_CHECKER
+ if (p->checker) {
+ BaseCPU *temp_checker = p->checker;
+ checker = dynamic_cast<CheckerCPU *>(temp_checker);
-#endif
+ 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;
#include "arch/predecoder.hh"
#include "base/statistics.hh"
-#include "config/full_system.hh"
#include "config/the_isa.hh"
+ #include "config/use_checker.hh"
#include "cpu/base.hh"
#include "cpu/decode.hh"
#include "cpu/pc_event.hh"
#include "mem/port.hh"
#include "mem/request.hh"
#include "sim/eventq.hh"
+#include "sim/full_system.hh"
#include "sim/system.hh"
+ #if USE_CHECKER
+ #include "cpu/checker/cpu.hh"
+ #endif
+
// forward declarations
-#if FULL_SYSTEM
-class Processor;
-namespace TheISA
-{
- class ITB;
- class DTB;
-}
+class Checkpoint;
class MemObject;
-
-#else
-
class Process;
-
-#endif // FULL_SYSTEM
+class Processor;
+class ThreadContext;
namespace TheISA
{
#include "base/cprintf.hh"
#include "base/output.hh"
#include "base/trace.hh"
+#include "config/the_isa.hh"
+#include "cpu/base.hh"
#include "cpu/profile.hh"
#include "cpu/quiesce_event.hh"
- #include "params/BaseCPU.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
#include "mem/fs_translating_port_proxy.hh"
-#include "sim/serialize.hh"
-#include "sim/sim_exit.hh"
-#else
#include "mem/se_translating_port_proxy.hh"
++#include "params/BaseCPU.hh"
+#include "sim/full_system.hh"
#include "sim/process.hh"
- #include "sim/process.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_exit.hh"
#include "sim/system.hh"
-#endif
using namespace std;
// constructor
-#if FULL_SYSTEM
+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);
+}
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),
- system(_sys), itb(_itb), dtb(_dtb)
--
++ : ThreadState(_cpu, _thread_num, NULL), system(_sys), itb(_itb), dtb(_dtb)
{
tc = new ProxyThreadContext<SimpleThread>(this);
//
// Now must unserialize all the ISA dependent state
//
- isa.unserialize(cpu, cp, section);
+ isa.unserialize(baseCpu, cp, section);
}
-#if FULL_SYSTEM
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);
}
-#endif
void
SimpleThread::activate(int delay)
lastActivate = curTick();
lastSuspend = curTick();
-/*
-#if FULL_SYSTEM
- // Don't change the status from active if there are pending interrupts
- if (cpu->checkInterrupts()) {
- assert(status() == ThreadContext::Active);
- return;
- }
-#endif
-*/
_status = ThreadContext::Suspended;
- cpu->suspendContext(_threadId);
+ baseCpu->suspendContext(_threadId);
}
#include "arch/tlb.hh"
#include "arch/types.hh"
#include "base/types.hh"
-#include "config/full_system.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"
#include "arch/registers.hh"
#include "arch/types.hh"
#include "base/types.hh"
-#include "config/full_system.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.
struct ThreadState {
typedef ThreadContext::Status Status;
-#if FULL_SYSTEM
- ThreadState(BaseCPU *cpu, ThreadID _tid);
-#else
ThreadState(BaseCPU *cpu, ThreadID _tid, Process *_process);
-#endif
- ~ThreadState();
+ virtual ~ThreadState();
void serialize(std::ostream &os);
#include <fstream>
#include <string>
+#include "arch/kernel_stats.hh"
#include "arch/vtophys.hh"
#include "base/debug.hh"
-#include "config/full_system.hh"
+ #include "base/output.hh"
#include "config/the_isa.hh"
#include "cpu/base.hh"
#include "cpu/quiesce_event.hh"
return result;
}
-#endif
-
+ uint64_t
+ writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset,
+ Addr filename_addr)
+ {
+ ostream *os;
+
+ // copy out target filename
+ char fn[100];
+ std::string filename;
+ CopyStringOut(tc, fn, filename_addr, 100);
+ filename = std::string(fn);
+
+ if (offset == 0) {
+ // create a new file (truncate)
+ os = simout.create(filename, true);
+ } else {
+ // do not truncate file if offset is non-zero
+ // (ios::in flag is required as well to keep the existing data
+ // intact, otherwise existing data will be zeroed out.)
+ os = simout.openFile(simout.directory() + filename,
+ ios::in | ios::out | ios::binary);
+ }
+ if (!os)
+ panic("could not open file %s\n", filename);
+
+ // seek to offset
+ os->seekp(offset);
+
+ // copy out data and write to file
+ char *buf = new char[len];
+ CopyOut(tc, buf, vaddr, len);
+ os->write(buf, len);
+ if (os->fail() || os->bad())
+ panic("Error while doing writefile!\n");
+
+ simout.close(os);
+
+ delete [] buf;
+
+ return len;
+ }
+
void
debugbreak(ThreadContext *tc)
{