inorder: squash on memory stall
[gem5.git] / src / cpu / checker / cpu_impl.hh
index 5091c7c1adfbd1115bf6aef3b7d0b1a15276b153..81f49463042416075550120a66ec04555009700e 100644 (file)
 #include <string>
 
 #include "base/refcnt.hh"
-#include "cpu/base.hh"
+#include "config/the_isa.hh"
 #include "cpu/base_dyn_inst.hh"
 #include "cpu/checker/cpu.hh"
 #include "cpu/simple_thread.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/static_inst.hh"
-#include "mem/packet_impl.hh"
-#include "sim/byteswap.hh"
 #include "sim/sim_object.hh"
 #include "sim/stats.hh"
 
 #if FULL_SYSTEM
-#include "sim/system.hh"
 #include "arch/vtophys.hh"
-#include "kern/kernel_stats.hh"
 #endif // FULL_SYSTEM
 
 using namespace std;
 //The CheckerCPU does alpha only
 using namespace AlphaISA;
 
-void
-CheckerCPU::init()
-{
-}
-
-CheckerCPU::CheckerCPU(Params *p)
-    : BaseCPU(p), thread(NULL), tc(NULL)
-{
-    memReq = NULL;
-
-    numInst = 0;
-    startNumInst = 0;
-    numLoad = 0;
-    startNumLoad = 0;
-    youngestSN = 0;
-
-    changedPC = willChangePC = changedNextPC = false;
-
-    exitOnError = p->exitOnError;
-    warnOnlyOnLoadError = p->warnOnlyOnLoadError;
-#if FULL_SYSTEM
-    itb = p->itb;
-    dtb = p->dtb;
-    systemPtr = NULL;
-#else
-    process = p->process;
-#endif
-
-    result.integer = 0;
-}
-
-CheckerCPU::~CheckerCPU()
-{
-}
-
-void
-CheckerCPU::setMemory(MemObject *mem)
-{
-#if !FULL_SYSTEM
-    memPtr = mem;
-    thread = new SimpleThread(this, /* thread_num */ 0, process,
-                              /* asid */ 0, mem);
-
-    thread->setStatus(ThreadContext::Suspended);
-    tc = thread->getTC();
-    threadContexts.push_back(tc);
-#endif
-}
-
-void
-CheckerCPU::setSystem(System *system)
-{
-#if FULL_SYSTEM
-    systemPtr = system;
-
-    thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false);
-
-    thread->setStatus(ThreadContext::Suspended);
-    tc = thread->getTC();
-    threadContexts.push_back(tc);
-    delete thread->kernelStats;
-    thread->kernelStats = NULL;
-#endif
-}
-
-void
-CheckerCPU::setIcachePort(Port *icache_port)
-{
-    icachePort = icache_port;
-}
-
-void
-CheckerCPU::setDcachePort(Port *dcache_port)
-{
-    dcachePort = 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 &section)
-{
-/*
-    BaseCPU::unserialize(cp, section);
-    UNSERIALIZE_SCALAR(inst);
-    thread->unserialize(cp, csprintf("%s.xc", section));
-*/
-}
-
-Fault
-CheckerCPU::copySrcTranslate(Addr src)
-{
-    panic("Unimplemented!");
-}
-
-Fault
-CheckerCPU::copy(Addr dest)
-{
-    panic("Unimplemented!");
-}
-
-template <class T>
-Fault
-CheckerCPU::read(Addr addr, T &data, unsigned flags)
-{
-    // need to fill in CPU & thread IDs here
-    memReq = new Request();
-
-    memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
-
-    // translate to physical address
-    translateDataReadReq(memReq);
-
-    Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
-
-    pkt->dataStatic(&data);
-
-    if (!(memReq->getFlags() & UNCACHEABLE)) {
-        // 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
-    thread->translateDataWriteReq(memReq);
-
-    // 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->getFlags() & UNCACHEABLE) &&
-        (!(unverifiedReq->getFlags() & LOCKED) ||
-         ((unverifiedReq->getFlags() & LOCKED) &&
-          unverifiedReq->getScResult() == 1))) {
-        T inst_data;
-/*
-        // This code would work if the LSQ allowed for snooping.
-        Packet *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();
-        }
-    }
-
-    // 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->getScResult();
-
-    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);
-}
-
-template<>
-Fault
-CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
-{
-    return write((uint32_t)data, addr, flags, res);
-}
-
-
-#if FULL_SYSTEM
-Addr
-CheckerCPU::dbg_vtophys(Addr addr)
-{
-    return vtophys(tc, addr);
-}
-#endif // FULL_SYSTEM
-
-bool
-CheckerCPU::translateInstReq(Request *req)
-{
-#if FULL_SYSTEM
-    return (thread->translateInstReq(req) == NoFault);
-#else
-    thread->translateInstReq(req);
-    return true;
-#endif
-}
-
-void
-CheckerCPU::translateDataReadReq(Request *req)
-{
-    thread->translateDataReadReq(req);
-
-    if (req->getVaddr() != unverifiedReq->getVaddr()) {
-        warn("%lli: Request virtual addresses do not match! Inst: %#x, "
-             "checker: %#x",
-             curTick, unverifiedReq->getVaddr(), req->getVaddr());
-        handleError();
-    }
-    req->setPaddr(unverifiedReq->getPaddr());
-
-    if (checkFlags(req)) {
-        warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
-             curTick, unverifiedReq->getFlags(), req->getFlags());
-        handleError();
-    }
-}
-
-void
-CheckerCPU::translateDataWriteReq(Request *req)
-{
-    thread->translateDataWriteReq(req);
-
-    if (req->getVaddr() != unverifiedReq->getVaddr()) {
-        warn("%lli: Request virtual addresses do not match! Inst: %#x, "
-             "checker: %#x",
-             curTick, unverifiedReq->getVaddr(), req->getVaddr());
-        handleError();
-    }
-    req->setPaddr(unverifiedReq->getPaddr());
-
-    if (checkFlags(req)) {
-        warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
-             curTick, unverifiedReq->getFlags(), req->getFlags());
-        handleError();
-    }
-}
-
-bool
-CheckerCPU::checkFlags(Request *req)
-{
-    // 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 | NO_FAULT;
-    flags = flags & (mask);
-    if (flags == req->getFlags()) {
-        return false;
-    } else {
-        return true;
-    }
-}
-
-void
-CheckerCPU::dumpAndExit()
-{
-    warn("%lli: Checker PC:%#x, next PC:%#x",
-         curTick, thread->readPC(), thread->readNextPC());
-    panic("Checker found an error!");
-}
-
 template <class DynInstPtr>
 void
 Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
@@ -456,6 +93,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         }
     }
 
+    unverifiedInst = inst;
+
     // 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.
@@ -503,9 +142,9 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         // Try to fetch the instruction
 
 #if FULL_SYSTEM
-#define IFETCH_FLAGS(pc)       ((pc) & 1) ? PHYSICAL : 0
+#define IFETCH_FLAGS(pc)        ((pc) & 1) ? PHYSICAL : 0
 #else
-#define IFETCH_FLAGS(pc)       0
+#define IFETCH_FLAGS(pc)        0
 #endif
 
         uint64_t fetch_PC = thread->readPC() & ~3;
@@ -514,9 +153,10 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         memReq = new Request(inst->threadNumber, fetch_PC,
                              sizeof(uint32_t),
                              IFETCH_FLAGS(thread->readPC()),
-                             fetch_PC, thread->readCpuId(), inst->threadNumber);
+                             fetch_PC, thread->contextId(),
+                             inst->threadNumber);
 
-        bool succeeded = translateInstReq(memReq);
+        bool succeeded = itb->translateAtomic(memReq, thread);
 
         if (!succeeded) {
             if (inst->getFault() == NoFault) {
@@ -533,7 +173,7 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
                 thread->setPC(thread->readNextPC());
                 thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
 
-                return;
+                break;
             } else {
                 // The instruction is carrying an ITB fault.  Handle
                 // the fault and see if our results match the CPU on
@@ -543,7 +183,7 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
         }
 
         if (fault == NoFault) {
-            Packet *pkt = new Packet(memReq, Packet::ReadReq,
+            PacketPtr pkt = new Packet(memReq, Packet::ReadReq,
                                      Packet::Broadcast);
 
             pkt->dataStatic(&machInst);
@@ -561,8 +201,13 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
             // 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
 
 #if FULL_SYSTEM
             thread->setInst(machInst);
@@ -582,7 +227,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
 
             thread->funcExeInst++;
 
-            fault = curStaticInst->execute(this, NULL);
+            if (!inst->isUnverifiable())
+                fault = curStaticInst->execute(this, NULL);
 
             // Checks to make sure instrution results are correct.
             validateExecution(inst);
@@ -598,9 +244,7 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
             willChangePC = true;
             newPC = thread->readPC();
             DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
-#else // !FULL_SYSTEM
-            fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC());
-#endif // FULL_SYSTEM
+#endif
         } else {
 #if THE_ISA != MIPS_ISA
             // go to the next instruction
@@ -653,11 +297,12 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
             break;
         }
     }
+    unverifiedInst = NULL;
 }
 
 template <class DynInstPtr>
 void
-Checker<DynInstPtr>::switchOut(Sampler *s)
+Checker<DynInstPtr>::switchOut()
 {
     instList.clear();
 }
@@ -743,13 +388,13 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
         int misc_reg_idx = miscRegIdxs.front();
         miscRegIdxs.pop();
 
-        if (inst->tcBase()->readMiscReg(misc_reg_idx) !=
-            thread->readMiscReg(misc_reg_idx)) {
+        if (inst->tcBase()->readMiscRegNoEffect(misc_reg_idx) !=
+            thread->readMiscRegNoEffect(misc_reg_idx)) {
             warn("%lli: Misc reg idx %i (side effect) does not match! "
                  "Inst: %#x, checker: %#x",
                  curTick, misc_reg_idx,
-                 inst->tcBase()->readMiscReg(misc_reg_idx),
-                 thread->readMiscReg(misc_reg_idx));
+                 inst->tcBase()->readMiscRegNoEffect(misc_reg_idx),
+                 thread->readMiscRegNoEffect(misc_reg_idx));
             handleError(inst);
         }
     }
@@ -759,6 +404,24 @@ template <class DynInstPtr>
 void
 Checker<DynInstPtr>::validateState()
 {
+    if (updateThisCycle) {
+        warn("%lli: Instruction PC %#x results didn't match up, copying all "
+             "registers from main CPU", curTick, unverifiedInst->readPC());
+        // Heavy-weight copying of all registers
+        thread->copyArchRegs(unverifiedInst->tcBase());
+        // 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
+        updateThisCycle = false;
+    }
 }
 
 template <class DynInstPtr>
@@ -771,7 +434,7 @@ Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
     } else if (idx < TheISA::Fpcr_DepTag) {
         thread->setFloatRegBits(idx, inst->readIntResult());
     } else {
-        thread->setMiscReg(idx, inst->readIntResult());
+        thread->setMiscRegNoEffect(idx, inst->readIntResult());
     }
 }