cpu_impl.hh revision 2315
15643Sgblack@eecs.umich.edu/*
25643Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
35643Sgblack@eecs.umich.edu * All rights reserved.
45643Sgblack@eecs.umich.edu *
55643Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
65643Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
75643Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
85643Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
95643Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
105643Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
115643Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
125643Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
135643Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
145643Sgblack@eecs.umich.edu * this software without specific prior written permission.
155643Sgblack@eecs.umich.edu *
165643Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175643Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185643Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195643Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205643Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215643Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225643Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235643Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245643Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255643Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265643Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275643Sgblack@eecs.umich.edu */
285643Sgblack@eecs.umich.edu
295643Sgblack@eecs.umich.edu//#include <cmath>
305643Sgblack@eecs.umich.edu#include <cstdio>
3111793Sbrandon.potter@amd.com//#include <cstdlib>
3211793Sbrandon.potter@amd.com#include <iostream>
336138Sgblack@eecs.umich.edu#include <iomanip>
345651Sgblack@eecs.umich.edu#include <list>
358746Sgblack@eecs.umich.edu//#include <sstream>
368232Snate@binkert.org#include <string>
375657Sgblack@eecs.umich.edu
385643Sgblack@eecs.umich.edu//#include "base/cprintf.hh"
395643Sgblack@eecs.umich.edu//#include "base/inifile.hh"
405643Sgblack@eecs.umich.edu//#include "base/loader/symtab.hh"
415643Sgblack@eecs.umich.edu#include "base/misc.hh"
429805Sstever@gmail.com//#include "base/pollevent.hh"
439808Sstever@gmail.com//#include "base/range.hh"
449805Sstever@gmail.com#include "base/refcnt.hh"
455643Sgblack@eecs.umich.edu//#include "base/stats/events.hh"
467913SBrad.Beckmann@amd.com#include "cpu/base.hh"
477913SBrad.Beckmann@amd.com#include "cpu/base_dyn_inst.hh"
487913SBrad.Beckmann@amd.com#include "cpu/checker/cpu.hh"
497913SBrad.Beckmann@amd.com#include "cpu/cpu_exec_context.hh"
507913SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
516136Sgblack@eecs.umich.edu//#include "cpu/exetrace.hh"
525643Sgblack@eecs.umich.edu//#include "cpu/profile.hh"
535643Sgblack@eecs.umich.edu#include "cpu/sampler/sampler.hh"
545653Sgblack@eecs.umich.edu//#include "cpu/smt.hh"
555653Sgblack@eecs.umich.edu#include "cpu/static_inst.hh"
565653Sgblack@eecs.umich.edu//#include "kern/kernel_stats.hh"
575653Sgblack@eecs.umich.edu#include "mem/base_mem.hh"
585827Sgblack@eecs.umich.edu#include "mem/mem_interface.hh"
595653Sgblack@eecs.umich.edu#include "sim/byteswap.hh"
605643Sgblack@eecs.umich.edu#include "sim/builder.hh"
615643Sgblack@eecs.umich.edu//#include "sim/debug.hh"
627913SBrad.Beckmann@amd.com//#include "sim/host.hh"
637913SBrad.Beckmann@amd.com//#include "sim/sim_events.hh"
647913SBrad.Beckmann@amd.com#include "sim/sim_object.hh"
657913SBrad.Beckmann@amd.com#include "sim/stats.hh"
667913SBrad.Beckmann@amd.com
679807Sstever@gmail.com#include "cpu/o3/alpha_dyn_inst.hh"
687913SBrad.Beckmann@amd.com#include "cpu/o3/alpha_impl.hh"
699805Sstever@gmail.com
709807Sstever@gmail.com#include "cpu/ozone/dyn_inst.hh"
717913SBrad.Beckmann@amd.com#include "cpu/ozone/ozone_impl.hh"
727913SBrad.Beckmann@amd.com#include "cpu/ozone/simple_impl.hh"
739805Sstever@gmail.com
749805Sstever@gmail.com#if FULL_SYSTEM
759805Sstever@gmail.com#include "base/remote_gdb.hh"
769805Sstever@gmail.com#include "mem/functional/memory_control.hh"
779805Sstever@gmail.com#include "mem/functional/physical.hh"
789805Sstever@gmail.com#include "sim/system.hh"
799805Sstever@gmail.com#include "arch/tlb.hh"
809805Sstever@gmail.com#include "arch/stacktrace.hh"
819805Sstever@gmail.com#include "arch/vtophys.hh"
829805Sstever@gmail.com#else // !FULL_SYSTEM
839805Sstever@gmail.com#include "mem/functional/functional.hh"
849805Sstever@gmail.com#endif // FULL_SYSTEM
859805Sstever@gmail.com
869805Sstever@gmail.comusing namespace std;
879805Sstever@gmail.com//The CheckerCPU does alpha only
889805Sstever@gmail.comusing namespace AlphaISA;
899805Sstever@gmail.com
909805Sstever@gmail.comvoid
915643Sgblack@eecs.umich.eduCheckerCPU::init()
9211144Sjthestness@gmail.com{
9311144Sjthestness@gmail.com/*
9411144Sjthestness@gmail.com    BaseCPU::init();
9511144Sjthestness@gmail.com#if FULL_SYSTEM
9611144Sjthestness@gmail.com    for (int i = 0; i < execContexts.size(); ++i) {
9711144Sjthestness@gmail.com        ExecContext *xc = execContexts[i];
9811144Sjthestness@gmail.com
9911144Sjthestness@gmail.com        // initialize CPU, including PC
1005643Sgblack@eecs.umich.edu        TheISA::initCPU(xc, xc->readCpuId());
1015643Sgblack@eecs.umich.edu    }
1025643Sgblack@eecs.umich.edu#endif
1035643Sgblack@eecs.umich.edu*/
1045643Sgblack@eecs.umich.edu}
1055643Sgblack@eecs.umich.edu
10613229Sgabeblack@google.comCheckerCPU::CheckerCPU(Params *p)
1075643Sgblack@eecs.umich.edu    : BaseCPU(p), cpuXC(NULL), xcProxy(NULL)
1085643Sgblack@eecs.umich.edu{
10913229Sgabeblack@google.com    memReq = new MemReq();
1105643Sgblack@eecs.umich.edu    memReq->xc = xcProxy;
1115643Sgblack@eecs.umich.edu    memReq->asid = 0;
1125643Sgblack@eecs.umich.edu    memReq->data = new uint8_t[64];
1135643Sgblack@eecs.umich.edu
1145898Sgblack@eecs.umich.edu    numInst = 0;
1159805Sstever@gmail.com    startNumInst = 0;
1165643Sgblack@eecs.umich.edu    numLoad = 0;
1175643Sgblack@eecs.umich.edu    startNumLoad = 0;
1185643Sgblack@eecs.umich.edu    youngestSN = 0;
1195643Sgblack@eecs.umich.edu
1205643Sgblack@eecs.umich.edu    changedPC = willChangePC = changedNextPC = false;
1215643Sgblack@eecs.umich.edu
1225643Sgblack@eecs.umich.edu    exitOnError = p->exitOnError;
1235643Sgblack@eecs.umich.edu#if FULL_SYSTEM
1245643Sgblack@eecs.umich.edu    itb = p->itb;
12513229Sgabeblack@google.com    dtb = p->dtb;
1265643Sgblack@eecs.umich.edu    systemPtr = NULL;
1275643Sgblack@eecs.umich.edu    memPtr = NULL;
12813229Sgabeblack@google.com#endif
1295643Sgblack@eecs.umich.edu}
1305643Sgblack@eecs.umich.edu
1315643Sgblack@eecs.umich.eduCheckerCPU::~CheckerCPU()
1325643Sgblack@eecs.umich.edu{
1335898Sgblack@eecs.umich.edu}
1349805Sstever@gmail.com
1355643Sgblack@eecs.umich.eduvoid
1365643Sgblack@eecs.umich.eduCheckerCPU::setMemory(FunctionalMemory *mem)
1375643Sgblack@eecs.umich.edu{
1385643Sgblack@eecs.umich.edu    memPtr = mem;
1395643Sgblack@eecs.umich.edu#if !FULL_SYSTEM
1405643Sgblack@eecs.umich.edu    cpuXC = new CPUExecContext(this, /* thread_num */ 0, mem,
1417913SBrad.Beckmann@amd.com                               /* asid */ 0);
1425643Sgblack@eecs.umich.edu
1435643Sgblack@eecs.umich.edu    cpuXC->setStatus(ExecContext::Suspended);
1445643Sgblack@eecs.umich.edu    xcProxy = cpuXC->getProxy();
1457913SBrad.Beckmann@amd.com    execContexts.push_back(xcProxy);
1465643Sgblack@eecs.umich.edu#else
1475643Sgblack@eecs.umich.edu    if (systemPtr) {
1485643Sgblack@eecs.umich.edu        cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr);
1495643Sgblack@eecs.umich.edu
1505643Sgblack@eecs.umich.edu        cpuXC->setStatus(ExecContext::Suspended);
1515643Sgblack@eecs.umich.edu        xcProxy = cpuXC->getProxy();
1525643Sgblack@eecs.umich.edu        execContexts.push_back(xcProxy);
1535643Sgblack@eecs.umich.edu        memReq->xc = xcProxy;
1545643Sgblack@eecs.umich.edu    }
1555643Sgblack@eecs.umich.edu#endif
1565643Sgblack@eecs.umich.edu}
1575643Sgblack@eecs.umich.edu
1585643Sgblack@eecs.umich.edu#if FULL_SYSTEM
1595643Sgblack@eecs.umich.eduvoid
1605643Sgblack@eecs.umich.eduCheckerCPU::setSystem(System *system)
1615643Sgblack@eecs.umich.edu{
1625643Sgblack@eecs.umich.edu    systemPtr = system;
1635643Sgblack@eecs.umich.edu
1645643Sgblack@eecs.umich.edu    if (memPtr) {
1655643Sgblack@eecs.umich.edu        cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr);
1665643Sgblack@eecs.umich.edu
1675643Sgblack@eecs.umich.edu        cpuXC->setStatus(ExecContext::Suspended);
1685643Sgblack@eecs.umich.edu        xcProxy = cpuXC->getProxy();
1695643Sgblack@eecs.umich.edu        execContexts.push_back(xcProxy);
1705643Sgblack@eecs.umich.edu        memReq->xc = xcProxy;
1715643Sgblack@eecs.umich.edu    }
1725643Sgblack@eecs.umich.edu}
1735643Sgblack@eecs.umich.edu#endif
1745643Sgblack@eecs.umich.edu
1755643Sgblack@eecs.umich.eduvoid
1765643Sgblack@eecs.umich.eduCheckerCPU::serialize(ostream &os)
1775643Sgblack@eecs.umich.edu{
1785643Sgblack@eecs.umich.edu/*
1795643Sgblack@eecs.umich.edu    BaseCPU::serialize(os);
1805643Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(inst);
1815643Sgblack@eecs.umich.edu    nameOut(os, csprintf("%s.xc", name()));
1825643Sgblack@eecs.umich.edu    cpuXC->serialize(os);
1835643Sgblack@eecs.umich.edu    cacheCompletionEvent.serialize(os);
1845643Sgblack@eecs.umich.edu*/
1855643Sgblack@eecs.umich.edu}
1865643Sgblack@eecs.umich.edu
1875643Sgblack@eecs.umich.eduvoid
1885643Sgblack@eecs.umich.eduCheckerCPU::unserialize(Checkpoint *cp, const string &section)
1895643Sgblack@eecs.umich.edu{
1905643Sgblack@eecs.umich.edu/*
1915643Sgblack@eecs.umich.edu    BaseCPU::unserialize(cp, section);
1925643Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(inst);
1935643Sgblack@eecs.umich.edu    cpuXC->unserialize(cp, csprintf("%s.xc", section));
1945643Sgblack@eecs.umich.edu*/
1955643Sgblack@eecs.umich.edu}
1965643Sgblack@eecs.umich.edu
1976712Snate@binkert.orgFault
1985651Sgblack@eecs.umich.eduCheckerCPU::copySrcTranslate(Addr src)
1995657Sgblack@eecs.umich.edu{
2005657Sgblack@eecs.umich.edu    static bool no_warn = true;
2015657Sgblack@eecs.umich.edu    int blk_size = 64;
2025657Sgblack@eecs.umich.edu    // Only support block sizes of 64 atm.
2035657Sgblack@eecs.umich.edu    assert(blk_size == 64);
2045657Sgblack@eecs.umich.edu    int offset = src & (blk_size - 1);
2055651Sgblack@eecs.umich.edu
2065651Sgblack@eecs.umich.edu    // Make sure block doesn't span page
2075654Sgblack@eecs.umich.edu    if (no_warn &&
2085654Sgblack@eecs.umich.edu        (src & PageMask) != ((src + blk_size) & PageMask) &&
2096138Sgblack@eecs.umich.edu        (src >> 40) != 0xfffffc) {
2106138Sgblack@eecs.umich.edu        warn("Copied block source spans pages %x.", src);
2116138Sgblack@eecs.umich.edu        no_warn = false;
2126138Sgblack@eecs.umich.edu    }
2136138Sgblack@eecs.umich.edu
2146138Sgblack@eecs.umich.edu    memReq->reset(src & ~(blk_size - 1), blk_size);
2156138Sgblack@eecs.umich.edu
2166138Sgblack@eecs.umich.edu    // translate to physical address
2176138Sgblack@eecs.umich.edu    Fault fault = cpuXC->translateDataReadReq(memReq);
2186138Sgblack@eecs.umich.edu
2196138Sgblack@eecs.umich.edu    if (fault == NoFault) {
2206138Sgblack@eecs.umich.edu        cpuXC->copySrcAddr = src;
2216138Sgblack@eecs.umich.edu        cpuXC->copySrcPhysAddr = memReq->paddr + offset;
2226138Sgblack@eecs.umich.edu    } else {
2236138Sgblack@eecs.umich.edu        assert(!fault->isAlignmentFault());
2246138Sgblack@eecs.umich.edu
2256138Sgblack@eecs.umich.edu        cpuXC->copySrcAddr = 0;
2268746Sgblack@eecs.umich.edu        cpuXC->copySrcPhysAddr = 0;
22711150Smitch.hayenga@arm.com    }
2286138Sgblack@eecs.umich.edu    return fault;
2296138Sgblack@eecs.umich.edu}
2308746Sgblack@eecs.umich.edu
2316138Sgblack@eecs.umich.eduFault
2326138Sgblack@eecs.umich.eduCheckerCPU::copy(Addr dest)
2336139Sgblack@eecs.umich.edu{
2346139Sgblack@eecs.umich.edu    static bool no_warn = true;
2356139Sgblack@eecs.umich.edu    int blk_size = 64;
2366139Sgblack@eecs.umich.edu    // Only support block sizes of 64 atm.
2376139Sgblack@eecs.umich.edu    assert(blk_size == 64);
2386139Sgblack@eecs.umich.edu    uint8_t data[blk_size];
2396139Sgblack@eecs.umich.edu    //assert(cpuXC->copySrcAddr);
2406139Sgblack@eecs.umich.edu    int offset = dest & (blk_size - 1);
2416139Sgblack@eecs.umich.edu
2426139Sgblack@eecs.umich.edu    // Make sure block doesn't span page
2436139Sgblack@eecs.umich.edu    if (no_warn &&
2446139Sgblack@eecs.umich.edu        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
2456139Sgblack@eecs.umich.edu        (dest >> 40) != 0xfffffc) {
2466139Sgblack@eecs.umich.edu        no_warn = false;
2476139Sgblack@eecs.umich.edu        warn("Copied block destination spans pages %x. ", dest);
2486139Sgblack@eecs.umich.edu    }
2496138Sgblack@eecs.umich.edu
2506138Sgblack@eecs.umich.edu    memReq->reset(dest & ~(blk_size -1), blk_size);
2519524SAndreas.Sandberg@ARM.com    // translate to physical address
2525643Sgblack@eecs.umich.edu    Fault fault = cpuXC->translateDataWriteReq(memReq);
2535643Sgblack@eecs.umich.edu
2545643Sgblack@eecs.umich.edu    if (fault == NoFault) {
2555827Sgblack@eecs.umich.edu        Addr dest_addr = memReq->paddr + offset;
2565827Sgblack@eecs.umich.edu        // Need to read straight from memory since we have more than 8 bytes.
2575827Sgblack@eecs.umich.edu        memReq->paddr = cpuXC->copySrcPhysAddr;
2585827Sgblack@eecs.umich.edu        cpuXC->mem->read(memReq, data);
2595827Sgblack@eecs.umich.edu        memReq->paddr = dest_addr;
2605827Sgblack@eecs.umich.edu        cpuXC->mem->write(memReq, data);
2615827Sgblack@eecs.umich.edu        memReq->cmd = Copy;
2625827Sgblack@eecs.umich.edu        memReq->completionEvent = NULL;
2635827Sgblack@eecs.umich.edu        memReq->paddr = cpuXC->copySrcPhysAddr;
2645827Sgblack@eecs.umich.edu        memReq->dest = dest_addr;
2655827Sgblack@eecs.umich.edu        memReq->size = 64;
2665827Sgblack@eecs.umich.edu        memReq->time = curTick;
2675827Sgblack@eecs.umich.edu        memReq->flags &= ~INST_READ;
2685827Sgblack@eecs.umich.edu    }
2695827Sgblack@eecs.umich.edu    else
2705827Sgblack@eecs.umich.edu        assert(!fault->isAlignmentFault());
2716137Sgblack@eecs.umich.edu
27210905Sandreas.sandberg@arm.com    return fault;
2737903Shestness@cs.utexas.edu}
2747903Shestness@cs.utexas.edu
2757903Shestness@cs.utexas.edu// precise architected memory state accessor macros
2767903Shestness@cs.utexas.edutemplate <class T>
2777903Shestness@cs.utexas.eduFault
2787903Shestness@cs.utexas.eduCheckerCPU::read(Addr addr, T &data, unsigned flags)
2797903Shestness@cs.utexas.edu{
2807903Shestness@cs.utexas.edu    memReq->reset(addr, sizeof(T), flags);
2817903Shestness@cs.utexas.edu
2827903Shestness@cs.utexas.edu    // translate to physical address
2837903Shestness@cs.utexas.edu    // Should I probe the DTB?  Or should I just take the physical address
2847903Shestness@cs.utexas.edu    // and assume correct translation?
28510905Sandreas.sandberg@arm.com    translateDataReadReq(memReq);
2867903Shestness@cs.utexas.edu
2877903Shestness@cs.utexas.edu    // if we have a cache, do cache access too
2887903Shestness@cs.utexas.edu    memReq->cmd = Read;
2897903Shestness@cs.utexas.edu    memReq->completionEvent = NULL;
2907903Shestness@cs.utexas.edu    memReq->time = curTick;
2917903Shestness@cs.utexas.edu    memReq->flags &= ~INST_READ;
2927903Shestness@cs.utexas.edu
2937903Shestness@cs.utexas.edu    if (!(memReq->flags & UNCACHEABLE)) {
2947903Shestness@cs.utexas.edu        cpuXC->read(memReq, data);
2957903Shestness@cs.utexas.edu    } else {
2967903Shestness@cs.utexas.edu        // Assume the data is correct if it's an uncached access
2977903Shestness@cs.utexas.edu        memcpy(&data, &unverifiedResult.integer, sizeof(T));
2987903Shestness@cs.utexas.edu    }
2997903Shestness@cs.utexas.edu
3005643Sgblack@eecs.umich.edu    return NoFault;
3015643Sgblack@eecs.umich.edu}
3025643Sgblack@eecs.umich.edu
3035643Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
3045643Sgblack@eecs.umich.edu
305template
306Fault
307CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
308
309template
310Fault
311CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
312
313template
314Fault
315CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
316
317template
318Fault
319CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
320
321#endif //DOXYGEN_SHOULD_SKIP_THIS
322
323template<>
324Fault
325CheckerCPU::read(Addr addr, double &data, unsigned flags)
326{
327    return read(addr, *(uint64_t*)&data, flags);
328}
329
330template<>
331Fault
332CheckerCPU::read(Addr addr, float &data, unsigned flags)
333{
334    return read(addr, *(uint32_t*)&data, flags);
335}
336
337template<>
338Fault
339CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
340{
341    return read(addr, (uint32_t&)data, flags);
342}
343
344template <class T>
345Fault
346CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
347{
348    memReq->reset(addr, sizeof(T), flags);
349
350    // translate to physical address
351    cpuXC->translateDataWriteReq(memReq);
352
353    if ((!(unverifiedReq->flags & LOCKED) ||
354        ((unverifiedReq->flags & LOCKED) &&
355         unverifiedReq->result == 1)) &&
356        !(unverifiedReq->flags & UNCACHEABLE)) {
357        // do functional access
358//        cpuXC->read(memReq, data);
359
360        memReq->cmd = Write;
361//    memcpy(memReq->data,(uint8_t *)&data,memReq->size);
362        T inst_data;
363        memcpy(&inst_data, unverifiedReq->data, sizeof(T));
364        memReq->completionEvent = NULL;
365        memReq->time = curTick;
366        memReq->flags &= ~INST_READ;
367
368        // Hard to verify this as the data writes back after the
369        // instruction commits.  May only be able to check that the
370        // value produced from execute() matches the value produced
371        // from the instruction's first execution.
372        if (data != inst_data) {
373            warn("Store value does not match value in memory! "
374                 "Instruction: %#x, memory: %#x",
375                 inst_data, data);
376            handleError();
377        }
378    }
379
380    // Assume the result was the same as the one passed in.  This checker
381    // doesn't check if the SC should succeed or fail, it just checks the
382    // value.
383    if (res)
384        *res = unverifiedReq->result;
385
386    return NoFault;
387}
388
389
390#ifndef DOXYGEN_SHOULD_SKIP_THIS
391template
392Fault
393CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
394
395template
396Fault
397CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
398
399template
400Fault
401CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
402
403template
404Fault
405CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
406
407#endif //DOXYGEN_SHOULD_SKIP_THIS
408
409template<>
410Fault
411CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
412{
413    return write(*(uint64_t*)&data, addr, flags, res);
414}
415
416template<>
417Fault
418CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
419{
420    return write(*(uint32_t*)&data, addr, flags, res);
421}
422
423template<>
424Fault
425CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
426{
427    return write((uint32_t)data, addr, flags, res);
428}
429
430
431#if FULL_SYSTEM
432Addr
433CheckerCPU::dbg_vtophys(Addr addr)
434{
435    return vtophys(xcProxy, addr);
436}
437#endif // FULL_SYSTEM
438
439#if FULL_SYSTEM
440void
441CheckerCPU::post_interrupt(int int_num, int index)
442{
443    BaseCPU::post_interrupt(int_num, index);
444
445    if (cpuXC->status() == ExecContext::Suspended) {
446                DPRINTF(IPI,"Suspended Processor awoke\n");
447        cpuXC->activate();
448    }
449}
450#endif // FULL_SYSTEM
451
452bool
453CheckerCPU::translateInstReq(MemReqPtr &req)
454{
455#if FULL_SYSTEM
456    return (cpuXC->translateInstReq(req) == NoFault);
457#else
458    cpuXC->translateInstReq(req);
459    return true;
460#endif
461}
462
463void
464CheckerCPU::translateDataReadReq(MemReqPtr &req)
465{
466    cpuXC->translateDataReadReq(req);
467
468    if (req->vaddr != unverifiedReq->vaddr) {
469        warn("Request virtual addresses do not match! Inst: %#x, checker:"
470             " %#x",
471             unverifiedReq->vaddr, req->vaddr);
472    }
473    req->paddr = unverifiedReq->paddr;
474
475    if (checkFlags(req)) {
476        warn("Request flags do not match! Inst: %#x, checker: %#x",
477             unverifiedReq->flags, req->flags);
478        handleError();
479    }
480}
481
482void
483CheckerCPU::translateDataWriteReq(MemReqPtr &req)
484{
485    cpuXC->translateDataWriteReq(req);
486
487    if (req->vaddr != unverifiedReq->vaddr) {
488        warn("Request virtual addresses do not match! Inst: %#x, checker:"
489             " %#x",
490             unverifiedReq->vaddr, req->vaddr);
491    }
492    req->paddr = unverifiedReq->paddr;
493
494    if (checkFlags(req)) {
495        warn("Request flags do not match! Inst: %#x, checker: %#x",
496             unverifiedReq->flags, req->flags);
497        handleError();
498    }
499}
500
501bool
502CheckerCPU::checkFlags(MemReqPtr &req)
503{
504    // Remove any dynamic flags that don't have to do with the request itself.
505    unsigned flags = unverifiedReq->flags;
506    unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT;
507    flags = flags & (mask);
508    if (flags == req->flags) {
509        return false;
510    } else {
511        return true;
512    }
513}
514
515/* start simulation, program loaded, processor precise state initialized */
516template <class DynInstPtr>
517void
518Checker<DynInstPtr>::tick(DynInstPtr &completed_inst)
519{
520    DynInstPtr inst;
521
522    if (!instList.empty()) {
523        if (youngestSN < completed_inst->seqNum) {
524            DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
525                    completed_inst->seqNum, completed_inst->readPC());
526            instList.push_back(completed_inst);
527            youngestSN = completed_inst->seqNum;
528        }
529
530        if (!instList.front()->isCompleted()) {
531            return;
532        } else {
533            inst = instList.front();
534            instList.pop_front();
535        }
536    } else {
537        if (!completed_inst->isCompleted()) {
538            if (youngestSN < completed_inst->seqNum) {
539                DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
540                        completed_inst->seqNum, completed_inst->readPC());
541                instList.push_back(completed_inst);
542                youngestSN = completed_inst->seqNum;
543            }
544            return;
545        } else {
546            if (youngestSN < completed_inst->seqNum) {
547                inst = completed_inst;
548                youngestSN = completed_inst->seqNum;
549            } else {
550//                panic("SN already seen yet the list is empty!");
551                return;
552            }
553        }
554    }
555
556    while (1) {
557        DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
558                inst->seqNum, inst->readPC());
559//    verifyInst = completed_inst;
560        unverifiedResult.integer = inst->readIntResult();
561        unverifiedReq = inst->req;
562        numCycles++;
563
564        Fault fault = NoFault;
565
566        // maintain $r0 semantics
567        cpuXC->setIntReg(ZeroReg, 0);
568#ifdef TARGET_ALPHA
569        cpuXC->setFloatRegDouble(ZeroReg, 0.0);
570#endif // TARGET_ALPHA
571
572        // Try to fetch an instruction
573
574        // set up memory request for instruction fetch
575#if FULL_SYSTEM
576#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
577#else
578#define IFETCH_FLAGS(pc)	0
579#endif
580
581        if (changedPC) {
582            DPRINTF(Checker, "Changed PC recently to %#x\n",
583                    cpuXC->readPC());
584            if (willChangePC) {
585                if (newPC == cpuXC->readPC()) {
586                    DPRINTF(Checker, "Changed PC matches expected PC\n");
587                } else {
588                    warn("Changed PC does not match expected PC, changed: %#x, "
589                         "expected: %#x",
590                         cpuXC->readPC(), newPC);
591                    handleError();
592                }
593                willChangePC = false;
594            }
595            changedPC = false;
596        }
597        if (changedNextPC) {
598            DPRINTF(Checker, "Changed NextPC recently to %#x\n",
599                    cpuXC->readNextPC());
600            changedNextPC = false;
601        }
602
603        memReq->cmd = Read;
604        memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t),
605                      IFETCH_FLAGS(cpuXC->readPC()));
606
607        bool succeeded = translateInstReq(memReq);
608
609        if (!succeeded) {
610            warn("Instruction PC %#x was not found in the ITB!",
611                 cpuXC->readPC());
612            handleError();
613
614            // go to the next instruction
615            cpuXC->setPC(cpuXC->readNextPC());
616            cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
617
618            return;
619        }
620
621//    if (fault == NoFault)
622//        fault = cpuXC->mem->read(memReq, machInst);
623        cpuXC->mem->read(memReq, machInst);
624
625        // If we've got a valid instruction (i.e., no fault on instruction
626        // fetch), then execute it.
627
628        // keep an instruction count
629        numInst++;
630//	numInsts++;
631
632        // decode the instruction
633        machInst = gtoh(machInst);
634        // Checks that the instruction matches what we expected it to be.
635        // Checks both the machine instruction and the PC.
636        validateInst(inst);
637
638        curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC()));
639
640#if FULL_SYSTEM
641        cpuXC->setInst(machInst);
642#endif // FULL_SYSTEM
643
644        fault = inst->getFault();
645
646        // Either the instruction was a fault and we should process the fault,
647        // or we should just go ahead execute the instruction.  This assumes
648        // that the instruction is properly marked as a fault.
649        if (fault == NoFault) {
650
651            cpuXC->func_exe_inst++;
652
653            fault = curStaticInst->execute(this, NULL);
654
655            // Checks to make sure instrution results are correct.
656            validateExecution(inst);
657
658//	if (curStaticInst->isMemRef()) {
659//	    numMemRefs++;
660//	}
661
662            if (curStaticInst->isLoad()) {
663                ++numLoad;
664            }
665        }
666
667        if (fault != NoFault) {
668#if FULL_SYSTEM
669            fault->invoke(xcProxy);
670            willChangePC = true;
671            newPC = cpuXC->readPC();
672            DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
673#else // !FULL_SYSTEM
674            fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC());
675#endif // FULL_SYSTEM
676        } else {
677#if THE_ISA != MIPS_ISA
678            // go to the next instruction
679            cpuXC->setPC(cpuXC->readNextPC());
680            cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
681#else
682            // go to the next instruction
683            cpuXC->setPC(cpuXC->readNextPC());
684            cpuXC->setNextPC(cpuXC->readNextNPC());
685            cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
686#endif
687
688        }
689
690#if FULL_SYSTEM
691        Addr oldpc;
692        int count = 0;
693        do {
694            oldpc = cpuXC->readPC();
695            system->pcEventQueue.service(xcProxy);
696            count++;
697        } while (oldpc != cpuXC->readPC());
698        if (count > 1) {
699            willChangePC = true;
700            newPC = cpuXC->readPC();
701            DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
702        }
703#endif
704
705        // Checks PC, next PC.  Optionally can check all registers. (Or just those
706        // that have been modified).
707        validateState();
708
709        if (instList.empty()) {
710            break;
711        } else if (instList.front()->isCompleted()) {
712            inst = instList.front();
713            instList.pop_front();
714        } else {
715            break;
716        }
717    }
718}
719
720template <class DynInstPtr>
721void
722Checker<DynInstPtr>::switchOut(Sampler *s)
723{
724    sampler = s;
725    instList.clear();
726}
727
728template <class DynInstPtr>
729void
730Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
731{
732//    BaseCPU::takeOverFrom(oldCPU);
733
734    // if any of this CPU's ExecContexts are active, mark the CPU as
735    // running and schedule its tick event.
736/*
737    for (int i = 0; i < execContexts.size(); ++i) {
738        ExecContext *xc = execContexts[i];
739    }
740*/
741}
742
743template <class DynInstPtr>
744void
745Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
746{
747    if (inst->readPC() != cpuXC->readPC()) {
748        warn("PCs do not match! Inst: %#x, checker: %#x",
749             inst->readPC(), cpuXC->readPC());
750        if (changedPC) {
751            warn("Changed PCs recently, may not be an error");
752        } else {
753            handleError();
754        }
755    }
756
757    if (static_cast<MachInst>(inst->staticInst->machInst) !=
758        machInst) {
759        warn("Binary instructions do not match! Inst: %#x, checker: %#x",
760             static_cast<MachInst>(inst->staticInst->machInst),
761             machInst);
762        handleError();
763    }
764}
765
766template <class DynInstPtr>
767void
768Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
769{
770    if (inst->numDestRegs()) {
771        if (inst->isUnverifiable()) {
772            // @todo: Support more destination registers.
773            // Grab the result from the instruction and write it to the
774            // register.
775            RegIndex idx = inst->destRegIdx(0);
776            if (idx < TheISA::FP_Base_DepTag) {
777                cpuXC->setIntReg(idx, inst->readIntResult());
778            } else if (idx < TheISA::Fpcr_DepTag) {
779                cpuXC->setFloatRegInt(idx, inst->readIntResult());
780            } else {
781                cpuXC->setMiscReg(idx, inst->readIntResult());
782            }
783        } else if (result.integer != inst->readIntResult()) {
784            warn("Instruction results do not match! (May not be integer results) "
785                 "Inst: %#x, checker: %#x",
786                 inst->readIntResult(), result.integer);
787            handleError();
788        }
789    }
790
791    if (inst->readNextPC() != cpuXC->readNextPC()) {
792        warn("Instruction next PCs do not match! Inst: %#x, checker: %#x",
793             inst->readNextPC(), cpuXC->readNextPC());
794        handleError();
795    }
796
797    // Checking side effect registers can be difficult if they are not
798    // checked simultaneously with the execution of the instruction.
799    // This is because other valid instructions may have modified
800    // these registers in the meantime, and their values are not
801    // stored within the DynInst.
802    while (!miscRegIdxs.empty()) {
803        int misc_reg_idx = miscRegIdxs.front();
804        miscRegIdxs.pop();
805
806        if (inst->xcBase()->readMiscReg(misc_reg_idx) !=
807            cpuXC->readMiscReg(misc_reg_idx)) {
808            warn("Misc reg idx %i (side effect) does not match! Inst: %#x, "
809                 "checker: %#x",
810                 misc_reg_idx, inst->xcBase()->readMiscReg(misc_reg_idx),
811                 cpuXC->readMiscReg(misc_reg_idx));
812            handleError();
813        }
814    }
815}
816
817template <class DynInstPtr>
818void
819Checker<DynInstPtr>::validateState()
820{
821}
822
823template <class DynInstPtr>
824void
825Checker<DynInstPtr>::dumpInsts()
826{
827    int num = 0;
828
829    InstListIt inst_list_it = --(instList.end());
830
831    cprintf("Inst list size: %i\n", instList.size());
832
833    while (inst_list_it != instList.end())
834    {
835        cprintf("Instruction:%i\n",
836                num);
837
838        cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
839                "Completed:%i\n",
840                (*inst_list_it)->readPC(),
841                (*inst_list_it)->seqNum,
842                (*inst_list_it)->threadNumber,
843                (*inst_list_it)->isCompleted());
844
845        cprintf("\n");
846
847        inst_list_it--;
848        ++num;
849    }
850
851}
852
853template
854class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >;
855
856template
857class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;
858