cpu_impl.hh revision 2354
11049Sbinkertn@umich.edu/*
21049Sbinkertn@umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
31049Sbinkertn@umich.edu * All rights reserved.
41049Sbinkertn@umich.edu *
51049Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
61049Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
71049Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
81049Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
91049Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
101049Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
111049Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
121049Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
131049Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
141049Sbinkertn@umich.edu * this software without specific prior written permission.
151049Sbinkertn@umich.edu *
161049Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171049Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181049Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191049Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201049Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211049Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221049Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231049Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241049Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251049Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261049Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271049Sbinkertn@umich.edu */
281049Sbinkertn@umich.edu
291049Sbinkertn@umich.edu#include <list>
301049Sbinkertn@umich.edu#include <string>
311049Sbinkertn@umich.edu
321049Sbinkertn@umich.edu#include "base/refcnt.hh"
331049Sbinkertn@umich.edu#include "cpu/base.hh"
341049Sbinkertn@umich.edu#include "cpu/base_dyn_inst.hh"
351049Sbinkertn@umich.edu#include "cpu/checker/cpu.hh"
361049Sbinkertn@umich.edu#include "cpu/cpu_exec_context.hh"
371049Sbinkertn@umich.edu#include "cpu/exec_context.hh"
381049Sbinkertn@umich.edu#include "cpu/static_inst.hh"
391049Sbinkertn@umich.edu#include "sim/byteswap.hh"
401049Sbinkertn@umich.edu#include "sim/sim_object.hh"
411049Sbinkertn@umich.edu#include "sim/stats.hh"
421049Sbinkertn@umich.edu
431049Sbinkertn@umich.edu#include "cpu/o3/alpha_dyn_inst.hh"
441049Sbinkertn@umich.edu#include "cpu/o3/alpha_impl.hh"
451049Sbinkertn@umich.edu
461049Sbinkertn@umich.edu#include "cpu/ozone/dyn_inst.hh"
471049Sbinkertn@umich.edu#include "cpu/ozone/ozone_impl.hh"
481049Sbinkertn@umich.edu#include "cpu/ozone/simple_impl.hh"
491049Sbinkertn@umich.edu
501049Sbinkertn@umich.edu#if FULL_SYSTEM
511049Sbinkertn@umich.edu#include "sim/system.hh"
521049Sbinkertn@umich.edu#include "arch/vtophys.hh"
531049Sbinkertn@umich.edu#endif // FULL_SYSTEM
541049Sbinkertn@umich.edu
551049Sbinkertn@umich.eduusing namespace std;
561049Sbinkertn@umich.edu//The CheckerCPU does alpha only
571049Sbinkertn@umich.eduusing namespace AlphaISA;
581049Sbinkertn@umich.edu
591049Sbinkertn@umich.eduvoid
601049Sbinkertn@umich.eduCheckerCPU::init()
611049Sbinkertn@umich.edu{
621049Sbinkertn@umich.edu}
631049Sbinkertn@umich.edu
641049Sbinkertn@umich.eduCheckerCPU::CheckerCPU(Params *p)
651049Sbinkertn@umich.edu    : BaseCPU(p), cpuXC(NULL), xcProxy(NULL)
661049Sbinkertn@umich.edu{
671049Sbinkertn@umich.edu    memReq = new MemReq();
681049Sbinkertn@umich.edu    memReq->xc = xcProxy;
691049Sbinkertn@umich.edu    memReq->asid = 0;
701049Sbinkertn@umich.edu    memReq->data = new uint8_t[64];
711049Sbinkertn@umich.edu
721049Sbinkertn@umich.edu    numInst = 0;
731049Sbinkertn@umich.edu    startNumInst = 0;
741049Sbinkertn@umich.edu    numLoad = 0;
751049Sbinkertn@umich.edu    startNumLoad = 0;
761049Sbinkertn@umich.edu    youngestSN = 0;
771049Sbinkertn@umich.edu
781049Sbinkertn@umich.edu    changedPC = willChangePC = changedNextPC = false;
791049Sbinkertn@umich.edu
801049Sbinkertn@umich.edu    exitOnError = p->exitOnError;
811049Sbinkertn@umich.edu    updateOnError = p->updateOnError;
821049Sbinkertn@umich.edu#if FULL_SYSTEM
831049Sbinkertn@umich.edu    itb = p->itb;
841049Sbinkertn@umich.edu    dtb = p->dtb;
851049Sbinkertn@umich.edu    systemPtr = NULL;
861049Sbinkertn@umich.edu    memPtr = NULL;
871049Sbinkertn@umich.edu#endif
881049Sbinkertn@umich.edu}
891049Sbinkertn@umich.edu
901049Sbinkertn@umich.eduCheckerCPU::~CheckerCPU()
911049Sbinkertn@umich.edu{
921049Sbinkertn@umich.edu}
931049Sbinkertn@umich.edu
941049Sbinkertn@umich.eduvoid
951049Sbinkertn@umich.eduCheckerCPU::setMemory(FunctionalMemory *mem)
961049Sbinkertn@umich.edu{
971049Sbinkertn@umich.edu    memPtr = mem;
981049Sbinkertn@umich.edu#if !FULL_SYSTEM
991049Sbinkertn@umich.edu    cpuXC = new CPUExecContext(this, /* thread_num */ 0, mem,
1001049Sbinkertn@umich.edu                               /* asid */ 0);
1011049Sbinkertn@umich.edu
1021049Sbinkertn@umich.edu    cpuXC->setStatus(ExecContext::Suspended);
1031049Sbinkertn@umich.edu    xcProxy = cpuXC->getProxy();
1041049Sbinkertn@umich.edu    execContexts.push_back(xcProxy);
1051049Sbinkertn@umich.edu#else
1061049Sbinkertn@umich.edu    if (systemPtr) {
1071049Sbinkertn@umich.edu        cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false);
1081049Sbinkertn@umich.edu
1091049Sbinkertn@umich.edu        cpuXC->setStatus(ExecContext::Suspended);
1101049Sbinkertn@umich.edu        xcProxy = cpuXC->getProxy();
1111049Sbinkertn@umich.edu        execContexts.push_back(xcProxy);
1121049Sbinkertn@umich.edu        memReq->xc = xcProxy;
1131049Sbinkertn@umich.edu        delete cpuXC->kernelStats;
1141049Sbinkertn@umich.edu        cpuXC->kernelStats = NULL;
1151049Sbinkertn@umich.edu    }
1161049Sbinkertn@umich.edu#endif
1171049Sbinkertn@umich.edu}
1181049Sbinkertn@umich.edu
1191049Sbinkertn@umich.edu#if FULL_SYSTEM
1201049Sbinkertn@umich.eduvoid
1211049Sbinkertn@umich.eduCheckerCPU::setSystem(System *system)
1221049Sbinkertn@umich.edu{
1231049Sbinkertn@umich.edu    systemPtr = system;
1241049Sbinkertn@umich.edu
1251049Sbinkertn@umich.edu    if (memPtr) {
1261049Sbinkertn@umich.edu        cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false);
1271049Sbinkertn@umich.edu
1281049Sbinkertn@umich.edu        cpuXC->setStatus(ExecContext::Suspended);
1291049Sbinkertn@umich.edu        xcProxy = cpuXC->getProxy();
1301049Sbinkertn@umich.edu        execContexts.push_back(xcProxy);
1311049Sbinkertn@umich.edu        memReq->xc = xcProxy;
1321049Sbinkertn@umich.edu        delete cpuXC->kernelStats;
1331049Sbinkertn@umich.edu        cpuXC->kernelStats = NULL;
1341049Sbinkertn@umich.edu    }
1351049Sbinkertn@umich.edu}
1361049Sbinkertn@umich.edu#endif
1371049Sbinkertn@umich.edu
1381049Sbinkertn@umich.eduvoid
1391049Sbinkertn@umich.eduCheckerCPU::serialize(ostream &os)
1401049Sbinkertn@umich.edu{
1411049Sbinkertn@umich.edu/*
1421049Sbinkertn@umich.edu    BaseCPU::serialize(os);
1431049Sbinkertn@umich.edu    SERIALIZE_SCALAR(inst);
1441049Sbinkertn@umich.edu    nameOut(os, csprintf("%s.xc", name()));
1451049Sbinkertn@umich.edu    cpuXC->serialize(os);
1461049Sbinkertn@umich.edu    cacheCompletionEvent.serialize(os);
1471049Sbinkertn@umich.edu*/
1481049Sbinkertn@umich.edu}
1491049Sbinkertn@umich.edu
1501049Sbinkertn@umich.eduvoid
1511049Sbinkertn@umich.eduCheckerCPU::unserialize(Checkpoint *cp, const string &section)
1521049Sbinkertn@umich.edu{
1531049Sbinkertn@umich.edu/*
1541049Sbinkertn@umich.edu    BaseCPU::unserialize(cp, section);
1551049Sbinkertn@umich.edu    UNSERIALIZE_SCALAR(inst);
1561049Sbinkertn@umich.edu    cpuXC->unserialize(cp, csprintf("%s.xc", section));
1571049Sbinkertn@umich.edu*/
1581049Sbinkertn@umich.edu}
1591049Sbinkertn@umich.edu
1601049Sbinkertn@umich.eduFault
1611049Sbinkertn@umich.eduCheckerCPU::copySrcTranslate(Addr src)
1621049Sbinkertn@umich.edu{
1631049Sbinkertn@umich.edu    panic("Unimplemented!");
1641049Sbinkertn@umich.edu}
1651049Sbinkertn@umich.edu
1661049Sbinkertn@umich.eduFault
1671049Sbinkertn@umich.eduCheckerCPU::copy(Addr dest)
1681049Sbinkertn@umich.edu{
1691049Sbinkertn@umich.edu    panic("Unimplemented!");
1701049Sbinkertn@umich.edu}
1711049Sbinkertn@umich.edu
1721049Sbinkertn@umich.edutemplate <class T>
1731049Sbinkertn@umich.eduFault
1741306Sbinkertn@umich.eduCheckerCPU::read(Addr addr, T &data, unsigned flags)
1751049Sbinkertn@umich.edu{
1761049Sbinkertn@umich.edu    memReq->reset(addr, sizeof(T), flags);
1771049Sbinkertn@umich.edu
1781049Sbinkertn@umich.edu    // translate to physical address
1791049Sbinkertn@umich.edu    translateDataReadReq(memReq);
1801049Sbinkertn@umich.edu
1811049Sbinkertn@umich.edu    memReq->cmd = Read;
1821049Sbinkertn@umich.edu    memReq->completionEvent = NULL;
1831049Sbinkertn@umich.edu    memReq->time = curTick;
1841049Sbinkertn@umich.edu    memReq->flags &= ~INST_READ;
1851049Sbinkertn@umich.edu
1861049Sbinkertn@umich.edu    if (!(memReq->flags & UNCACHEABLE)) {
1871049Sbinkertn@umich.edu        // Access memory to see if we have the same data
1881049Sbinkertn@umich.edu        cpuXC->read(memReq, data);
1891049Sbinkertn@umich.edu    } else {
1901049Sbinkertn@umich.edu        // Assume the data is correct if it's an uncached access
1911049Sbinkertn@umich.edu        memcpy(&data, &unverifiedResult.integer, sizeof(T));
1921049Sbinkertn@umich.edu    }
1931049Sbinkertn@umich.edu
1941049Sbinkertn@umich.edu    return NoFault;
1951049Sbinkertn@umich.edu}
1961049Sbinkertn@umich.edu
1971049Sbinkertn@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
1981049Sbinkertn@umich.edu
1991049Sbinkertn@umich.edutemplate
2001049Sbinkertn@umich.eduFault
2011049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
2021049Sbinkertn@umich.edu
2031049Sbinkertn@umich.edutemplate
2041049Sbinkertn@umich.eduFault
2051049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
2061049Sbinkertn@umich.edu
2071049Sbinkertn@umich.edutemplate
2081049Sbinkertn@umich.eduFault
2091049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
2101049Sbinkertn@umich.edu
2111049Sbinkertn@umich.edutemplate
2121049Sbinkertn@umich.eduFault
2131049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
2141049Sbinkertn@umich.edu
2151049Sbinkertn@umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
2161049Sbinkertn@umich.edu
2171049Sbinkertn@umich.edutemplate<>
2181049Sbinkertn@umich.eduFault
2191049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, double &data, unsigned flags)
2201049Sbinkertn@umich.edu{
2211049Sbinkertn@umich.edu    return read(addr, *(uint64_t*)&data, flags);
2221049Sbinkertn@umich.edu}
2231049Sbinkertn@umich.edu
2241049Sbinkertn@umich.edutemplate<>
2251049Sbinkertn@umich.eduFault
2261049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, float &data, unsigned flags)
2271049Sbinkertn@umich.edu{
2281049Sbinkertn@umich.edu    return read(addr, *(uint32_t*)&data, flags);
2291049Sbinkertn@umich.edu}
2301049Sbinkertn@umich.edu
2311049Sbinkertn@umich.edutemplate<>
2321049Sbinkertn@umich.eduFault
2331049Sbinkertn@umich.eduCheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
2341049Sbinkertn@umich.edu{
2351049Sbinkertn@umich.edu    return read(addr, (uint32_t&)data, flags);
2361049Sbinkertn@umich.edu}
2371049Sbinkertn@umich.edu
2381049Sbinkertn@umich.edutemplate <class T>
2391049Sbinkertn@umich.eduFault
2401049Sbinkertn@umich.eduCheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
2411049Sbinkertn@umich.edu{
2421049Sbinkertn@umich.edu    memReq->reset(addr, sizeof(T), flags);
2431049Sbinkertn@umich.edu
2441049Sbinkertn@umich.edu    // translate to physical address
2451049Sbinkertn@umich.edu    cpuXC->translateDataWriteReq(memReq);
2461049Sbinkertn@umich.edu
2471049Sbinkertn@umich.edu    // Can compare the write data and result only if it's cacheable,
2481049Sbinkertn@umich.edu    // not a store conditional, or is a store conditional that
2491049Sbinkertn@umich.edu    // succeeded.
2501049Sbinkertn@umich.edu    // @todo: Verify that actual memory matches up with these values.
2511049Sbinkertn@umich.edu    // Right now it only verifies that the instruction data is the
2521049Sbinkertn@umich.edu    // same as what was in the request that got sent to memory; there
2531049Sbinkertn@umich.edu    // is no verification that it is the same as what is in memory.
2541049Sbinkertn@umich.edu    // This is because the LSQ would have to be snooped in the CPU to
2551049Sbinkertn@umich.edu    // verify this data.
2561049Sbinkertn@umich.edu    if (unverifiedReq &&
2571049Sbinkertn@umich.edu        !(unverifiedReq->flags & UNCACHEABLE) &&
2581049Sbinkertn@umich.edu        (!(unverifiedReq->flags & LOCKED) ||
2591049Sbinkertn@umich.edu         ((unverifiedReq->flags & LOCKED) &&
2601049Sbinkertn@umich.edu          unverifiedReq->result == 1))) {
2611049Sbinkertn@umich.edu#if 0
2621049Sbinkertn@umich.edu        memReq->cmd = Read;
2631049Sbinkertn@umich.edu        memReq->completionEvent = NULL;
2641049Sbinkertn@umich.edu        memReq->time = curTick;
2651049Sbinkertn@umich.edu        memReq->flags &= ~INST_READ;
2661049Sbinkertn@umich.edu        cpuXC->read(memReq, inst_data);
2671049Sbinkertn@umich.edu#endif
2681049Sbinkertn@umich.edu        T inst_data;
2691049Sbinkertn@umich.edu        memcpy(&inst_data, unverifiedReq->data, sizeof(T));
2701049Sbinkertn@umich.edu
2711049Sbinkertn@umich.edu        if (data != inst_data) {
2721049Sbinkertn@umich.edu            warn("%lli: Store value does not match value in memory! "
2731049Sbinkertn@umich.edu                 "Instruction: %#x, memory: %#x",
2741049Sbinkertn@umich.edu                 curTick, inst_data, data);
2751049Sbinkertn@umich.edu            handleError();
2761049Sbinkertn@umich.edu        }
2771049Sbinkertn@umich.edu    }
2781049Sbinkertn@umich.edu
2791049Sbinkertn@umich.edu    // Assume the result was the same as the one passed in.  This checker
2801049Sbinkertn@umich.edu    // doesn't check if the SC should succeed or fail, it just checks the
2811049Sbinkertn@umich.edu    // value.
2821049Sbinkertn@umich.edu    if (res)
2831049Sbinkertn@umich.edu        *res = unverifiedReq->result;
2841049Sbinkertn@umich.edu
2851049Sbinkertn@umich.edu    return NoFault;
2861049Sbinkertn@umich.edu}
2871049Sbinkertn@umich.edu
2881049Sbinkertn@umich.edu
2891049Sbinkertn@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
2901049Sbinkertn@umich.edutemplate
2911049Sbinkertn@umich.eduFault
2921049Sbinkertn@umich.eduCheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
2931049Sbinkertn@umich.edu
2941049Sbinkertn@umich.edutemplate
2951049Sbinkertn@umich.eduFault
2961049Sbinkertn@umich.eduCheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
2971049Sbinkertn@umich.edu
2981049Sbinkertn@umich.edutemplate
2991049Sbinkertn@umich.eduFault
3001049Sbinkertn@umich.eduCheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
3011049Sbinkertn@umich.edu
3021049Sbinkertn@umich.edutemplate
3031049Sbinkertn@umich.eduFault
3041049Sbinkertn@umich.eduCheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
3051049Sbinkertn@umich.edu
3061049Sbinkertn@umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
3071049Sbinkertn@umich.edu
3081049Sbinkertn@umich.edutemplate<>
3091049Sbinkertn@umich.eduFault
3101049Sbinkertn@umich.eduCheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
3111049Sbinkertn@umich.edu{
3121049Sbinkertn@umich.edu    return write(*(uint64_t*)&data, addr, flags, res);
3131049Sbinkertn@umich.edu}
3141049Sbinkertn@umich.edu
3151049Sbinkertn@umich.edutemplate<>
3161049Sbinkertn@umich.eduFault
3171049Sbinkertn@umich.eduCheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
3181049Sbinkertn@umich.edu{
3191049Sbinkertn@umich.edu    return write(*(uint32_t*)&data, addr, flags, res);
3201049Sbinkertn@umich.edu}
3211049Sbinkertn@umich.edu
3221049Sbinkertn@umich.edutemplate<>
3231049Sbinkertn@umich.eduFault
3241049Sbinkertn@umich.eduCheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
3251049Sbinkertn@umich.edu{
3261049Sbinkertn@umich.edu    return write((uint32_t)data, addr, flags, res);
3271049Sbinkertn@umich.edu}
3281049Sbinkertn@umich.edu
3291049Sbinkertn@umich.edu
3301049Sbinkertn@umich.edu#if FULL_SYSTEM
3311049Sbinkertn@umich.eduAddr
3321049Sbinkertn@umich.eduCheckerCPU::dbg_vtophys(Addr addr)
3331049Sbinkertn@umich.edu{
3341049Sbinkertn@umich.edu    return vtophys(xcProxy, addr);
3351049Sbinkertn@umich.edu}
3361049Sbinkertn@umich.edu#endif // FULL_SYSTEM
3371049Sbinkertn@umich.edu
3381049Sbinkertn@umich.edubool
3391049Sbinkertn@umich.eduCheckerCPU::translateInstReq(MemReqPtr &req)
3401049Sbinkertn@umich.edu{
3411049Sbinkertn@umich.edu#if FULL_SYSTEM
3421049Sbinkertn@umich.edu    return (cpuXC->translateInstReq(req) == NoFault);
3431049Sbinkertn@umich.edu#else
3441049Sbinkertn@umich.edu    cpuXC->translateInstReq(req);
3451049Sbinkertn@umich.edu    return true;
3461049Sbinkertn@umich.edu#endif
3471049Sbinkertn@umich.edu}
3481049Sbinkertn@umich.edu
3491049Sbinkertn@umich.eduvoid
3501049Sbinkertn@umich.eduCheckerCPU::translateDataReadReq(MemReqPtr &req)
3511049Sbinkertn@umich.edu{
3521049Sbinkertn@umich.edu    cpuXC->translateDataReadReq(req);
3531049Sbinkertn@umich.edu
3541049Sbinkertn@umich.edu    if (!unverifiedReq) {
3551049Sbinkertn@umich.edu        warn("%lli: Request virtual addresses do not match! Inst: N/A, "
3561049Sbinkertn@umich.edu             "checker: %#x",
3571049Sbinkertn@umich.edu             curTick, req->vaddr);
3581049Sbinkertn@umich.edu        return;
3591049Sbinkertn@umich.edu    } else if (req->vaddr != unverifiedReq->vaddr) {
3601049Sbinkertn@umich.edu        warn("%lli: Request virtual addresses do not match! Inst: %#x, "
3611049Sbinkertn@umich.edu             "checker: %#x",
3621049Sbinkertn@umich.edu             curTick, unverifiedReq->vaddr, req->vaddr);
3631049Sbinkertn@umich.edu        handleError();
3641049Sbinkertn@umich.edu    }
3651049Sbinkertn@umich.edu    req->paddr = unverifiedReq->paddr;
3661049Sbinkertn@umich.edu
3671049Sbinkertn@umich.edu    if (checkFlags(req)) {
3681049Sbinkertn@umich.edu        warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
3691049Sbinkertn@umich.edu             curTick, unverifiedReq->flags, req->flags);
3701049Sbinkertn@umich.edu        handleError();
3711049Sbinkertn@umich.edu    }
3721049Sbinkertn@umich.edu}
3731049Sbinkertn@umich.edu
3741049Sbinkertn@umich.eduvoid
3751049Sbinkertn@umich.eduCheckerCPU::translateDataWriteReq(MemReqPtr &req)
3761049Sbinkertn@umich.edu{
3771049Sbinkertn@umich.edu    cpuXC->translateDataWriteReq(req);
3781049Sbinkertn@umich.edu
3791049Sbinkertn@umich.edu    if (!unverifiedReq) {
3801049Sbinkertn@umich.edu        warn("%lli: Request virtual addresses do not match! Inst: N/A, "
3811049Sbinkertn@umich.edu             "checker: %#x",
3821049Sbinkertn@umich.edu             curTick, req->vaddr);
3831049Sbinkertn@umich.edu        return;
3841049Sbinkertn@umich.edu    } else if (req->vaddr != unverifiedReq->vaddr) {
3851049Sbinkertn@umich.edu        warn("%lli: Request virtual addresses do not match! Inst: %#x, "
3861049Sbinkertn@umich.edu             "checker: %#x",
3871049Sbinkertn@umich.edu             curTick, unverifiedReq->vaddr, req->vaddr);
3881049Sbinkertn@umich.edu        handleError();
3891049Sbinkertn@umich.edu    }
3901049Sbinkertn@umich.edu    req->paddr = unverifiedReq->paddr;
3911049Sbinkertn@umich.edu
3921049Sbinkertn@umich.edu    if (checkFlags(req)) {
3931049Sbinkertn@umich.edu        warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
3941049Sbinkertn@umich.edu             curTick, unverifiedReq->flags, req->flags);
3951049Sbinkertn@umich.edu        handleError();
3961049Sbinkertn@umich.edu    }
3971049Sbinkertn@umich.edu}
3981049Sbinkertn@umich.edu
3991049Sbinkertn@umich.edubool
4001049Sbinkertn@umich.eduCheckerCPU::checkFlags(MemReqPtr &req)
4011049Sbinkertn@umich.edu{
4021049Sbinkertn@umich.edu    // Remove any dynamic flags that don't have to do with the request itself.
4031049Sbinkertn@umich.edu    unsigned flags = unverifiedReq->flags;
4041049Sbinkertn@umich.edu    unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT;
4051049Sbinkertn@umich.edu    flags = flags & (mask);
4061049Sbinkertn@umich.edu    if (flags == req->flags) {
4071049Sbinkertn@umich.edu        return false;
4081049Sbinkertn@umich.edu    } else {
4091049Sbinkertn@umich.edu        return true;
4101049Sbinkertn@umich.edu    }
4111049Sbinkertn@umich.edu}
4121049Sbinkertn@umich.edu
4131049Sbinkertn@umich.edutemplate <class DynInstPtr>
4141049Sbinkertn@umich.eduvoid
4151049Sbinkertn@umich.eduChecker<DynInstPtr>::tick(DynInstPtr &completed_inst)
416{
417    DynInstPtr inst;
418
419    // Either check this instruction, or add it to a list of
420    // instructions waiting to be checked.  Instructions must be
421    // checked in program order, so if a store has committed yet not
422    // completed, there may be some instructions that are waiting
423    // behind it that have completed and must be checked.
424    if (!instList.empty()) {
425        if (youngestSN < completed_inst->seqNum) {
426            DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
427                    completed_inst->seqNum, completed_inst->readPC());
428            instList.push_back(completed_inst);
429            youngestSN = completed_inst->seqNum;
430        }
431
432        if (!instList.front()->isCompleted()) {
433            return;
434        } else {
435            inst = instList.front();
436            instList.pop_front();
437        }
438    } else {
439        if (!completed_inst->isCompleted()) {
440            if (youngestSN < completed_inst->seqNum) {
441                DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
442                        completed_inst->seqNum, completed_inst->readPC());
443                instList.push_back(completed_inst);
444                youngestSN = completed_inst->seqNum;
445            }
446            return;
447        } else {
448            if (youngestSN < completed_inst->seqNum) {
449                inst = completed_inst;
450                youngestSN = completed_inst->seqNum;
451            } else {
452                return;
453            }
454        }
455    }
456
457    unverifiedInst = inst;
458
459    // Try to check all instructions that are completed, ending if we
460    // run out of instructions to check or if an instruction is not
461    // yet completed.
462    while (1) {
463        DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
464                inst->seqNum, inst->readPC());
465        unverifiedResult.integer = inst->readIntResult();
466        unverifiedReq = inst->req;
467        numCycles++;
468
469        Fault fault = NoFault;
470
471        // maintain $r0 semantics
472        cpuXC->setIntReg(ZeroReg, 0);
473#ifdef TARGET_ALPHA
474        cpuXC->setFloatRegDouble(ZeroReg, 0.0);
475#endif // TARGET_ALPHA
476
477        // Check if any recent PC changes match up with anything we
478        // expect to happen.  This is mostly to check if traps or
479        // PC-based events have occurred in both the checker and CPU.
480        if (changedPC) {
481            DPRINTF(Checker, "Changed PC recently to %#x\n",
482                    cpuXC->readPC());
483            if (willChangePC) {
484                if (newPC == cpuXC->readPC()) {
485                    DPRINTF(Checker, "Changed PC matches expected PC\n");
486                } else {
487                    warn("%lli: Changed PC does not match expected PC, "
488                         "changed: %#x, expected: %#x",
489                         curTick, cpuXC->readPC(), newPC);
490                    handleError();
491                }
492                willChangePC = false;
493            }
494            changedPC = false;
495        }
496        if (changedNextPC) {
497            DPRINTF(Checker, "Changed NextPC recently to %#x\n",
498                    cpuXC->readNextPC());
499            changedNextPC = false;
500        }
501
502        // Try to fetch the instruction
503
504#if FULL_SYSTEM
505#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
506#else
507#define IFETCH_FLAGS(pc)	0
508#endif
509
510        // set up memory request for instruction fetch
511        memReq->cmd = Read;
512        memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t),
513                      IFETCH_FLAGS(cpuXC->readPC()));
514
515        bool succeeded = translateInstReq(memReq);
516
517        if (!succeeded) {
518            if (inst->getFault() == NoFault) {
519                // In this case the instruction was not a dummy
520                // instruction carrying an ITB fault.  In the single
521                // threaded case the ITB should still be able to
522                // translate this instruction; in the SMT case it's
523                // possible that its ITB entry was kicked out.
524                warn("%lli: Instruction PC %#x was not found in the ITB!",
525                     curTick, cpuXC->readPC());
526                handleError();
527
528                // go to the next instruction
529                cpuXC->setPC(cpuXC->readNextPC());
530                cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
531
532                break;
533            } else {
534                // The instruction is carrying an ITB fault.  Handle
535                // the fault and see if our results match the CPU on
536                // the next tick().
537                fault = inst->getFault();
538            }
539        }
540
541        if (fault == NoFault) {
542            cpuXC->mem->read(memReq, machInst);
543
544            // keep an instruction count
545            numInst++;
546
547            // decode the instruction
548            machInst = gtoh(machInst);
549            // Checks that the instruction matches what we expected it to be.
550            // Checks both the machine instruction and the PC.
551            validateInst(inst);
552
553            curStaticInst = StaticInst::decode(makeExtMI(machInst,
554                                                         cpuXC->readPC()));
555
556#if FULL_SYSTEM
557            cpuXC->setInst(machInst);
558#endif // FULL_SYSTEM
559
560            fault = inst->getFault();
561        }
562
563        // Either the instruction was a fault and we should process the fault,
564        // or we should just go ahead execute the instruction.  This assumes
565        // that the instruction is properly marked as a fault.
566        if (fault == NoFault) {
567
568            cpuXC->func_exe_inst++;
569
570            if (!inst->isUnverifiable())
571                fault = curStaticInst->execute(this, NULL);
572
573            // Checks to make sure instrution results are correct.
574            validateExecution(inst);
575
576            if (curStaticInst->isLoad()) {
577                ++numLoad;
578            }
579        }
580
581        if (fault != NoFault) {
582#if FULL_SYSTEM
583            fault->invoke(xcProxy);
584            willChangePC = true;
585            newPC = cpuXC->readPC();
586            DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
587#else // !FULL_SYSTEM
588            fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC());
589#endif // FULL_SYSTEM
590        } else {
591#if THE_ISA != MIPS_ISA
592            // go to the next instruction
593            cpuXC->setPC(cpuXC->readNextPC());
594            cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
595#else
596            // go to the next instruction
597            cpuXC->setPC(cpuXC->readNextPC());
598            cpuXC->setNextPC(cpuXC->readNextNPC());
599            cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
600#endif
601
602        }
603
604#if FULL_SYSTEM
605        // @todo: Determine if these should happen only if the
606        // instruction hasn't faulted.  In the SimpleCPU case this may
607        // not be true, but in the O3 or Ozone case this may be true.
608        Addr oldpc;
609        int count = 0;
610        do {
611            oldpc = cpuXC->readPC();
612            system->pcEventQueue.service(xcProxy);
613            count++;
614        } while (oldpc != cpuXC->readPC());
615        if (count > 1) {
616            willChangePC = true;
617            newPC = cpuXC->readPC();
618            DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
619        }
620#endif
621
622        // @todo:  Optionally can check all registers. (Or just those
623        // that have been modified).
624        validateState();
625
626        // Continue verifying instructions if there's another completed
627        // instruction waiting to be verified.
628        if (instList.empty()) {
629            break;
630        } else if (instList.front()->isCompleted()) {
631            inst = instList.front();
632            instList.pop_front();
633        } else {
634            break;
635        }
636    }
637    unverifiedInst = NULL;
638}
639
640template <class DynInstPtr>
641void
642Checker<DynInstPtr>::switchOut(Sampler *s)
643{
644    instList.clear();
645}
646
647template <class DynInstPtr>
648void
649Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
650{
651}
652
653template <class DynInstPtr>
654void
655Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
656{
657    if (inst->readPC() != cpuXC->readPC()) {
658        warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
659             curTick, inst->readPC(), cpuXC->readPC());
660        if (changedPC) {
661            warn("%lli: Changed PCs recently, may not be an error",
662                 curTick);
663        } else {
664            handleError();
665        }
666    }
667
668    MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
669
670    if (mi != machInst) {
671        warn("%lli: Binary instructions do not match! Inst: %#x, "
672             "checker: %#x",
673             curTick, mi, machInst);
674        handleError();
675    }
676}
677
678template <class DynInstPtr>
679void
680Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
681{
682    if (inst->numDestRegs()) {
683        // @todo: Support more destination registers.
684        if (inst->isUnverifiable()) {
685            // Unverifiable instructions assume they were executed
686            // properly by the CPU. Grab the result from the
687            // instruction and write it to the register.
688            RegIndex idx = inst->destRegIdx(0);
689            if (idx < TheISA::FP_Base_DepTag) {
690                cpuXC->setIntReg(idx, inst->readIntResult());
691            } else if (idx < TheISA::Fpcr_DepTag) {
692                cpuXC->setFloatRegInt(idx, inst->readIntResult());
693            } else {
694                cpuXC->setMiscReg(idx, inst->readIntResult());
695            }
696        } else if (result.integer != inst->readIntResult()) {
697            warn("%lli: Instruction results do not match! (Results may not "
698                 "actually be integers) Inst: %#x, checker: %#x",
699                 curTick, inst->readIntResult(), result.integer);
700            handleError();
701        }
702    }
703
704    if (inst->readNextPC() != cpuXC->readNextPC()) {
705        warn("%lli: Instruction next PCs do not match! Inst: %#x, "
706             "checker: %#x",
707             curTick, inst->readNextPC(), cpuXC->readNextPC());
708        handleError();
709    }
710
711    // Checking side effect registers can be difficult if they are not
712    // checked simultaneously with the execution of the instruction.
713    // This is because other valid instructions may have modified
714    // these registers in the meantime, and their values are not
715    // stored within the DynInst.
716    while (!miscRegIdxs.empty()) {
717        int misc_reg_idx = miscRegIdxs.front();
718        miscRegIdxs.pop();
719
720        if (inst->xcBase()->readMiscReg(misc_reg_idx) !=
721            cpuXC->readMiscReg(misc_reg_idx)) {
722            warn("%lli: Misc reg idx %i (side effect) does not match! "
723                 "Inst: %#x, checker: %#x",
724                 curTick, misc_reg_idx,
725                 inst->xcBase()->readMiscReg(misc_reg_idx),
726                 cpuXC->readMiscReg(misc_reg_idx));
727            handleError();
728        }
729    }
730}
731
732template <class DynInstPtr>
733void
734Checker<DynInstPtr>::validateState()
735{
736    if (updateThisCycle) {
737        warn("%lli: Instruction PC %#x results didn't match up, copying all "
738             "registers from main CPU", unverifiedInst->readPC());
739        // Heavy-weight copying of all registers
740        cpuXC->copyArchRegs(unverifiedInst->xcBase());
741        updateThisCycle = false;
742    }
743}
744
745template <class DynInstPtr>
746void
747Checker<DynInstPtr>::dumpInsts()
748{
749    int num = 0;
750
751    InstListIt inst_list_it = --(instList.end());
752
753    cprintf("Inst list size: %i\n", instList.size());
754
755    while (inst_list_it != instList.end())
756    {
757        cprintf("Instruction:%i\n",
758                num);
759
760        cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
761                "Completed:%i\n",
762                (*inst_list_it)->readPC(),
763                (*inst_list_it)->seqNum,
764                (*inst_list_it)->threadNumber,
765                (*inst_list_it)->isCompleted());
766
767        cprintf("\n");
768
769        inst_list_it--;
770        ++num;
771    }
772
773}
774
775template
776class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >;
777
778template
779class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;
780