cpu.hh revision 8794:e2ac2b7164dd
1/*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Kevin Lim
29 */
30
31#ifndef __CPU_CHECKER_CPU_HH__
32#define __CPU_CHECKER_CPU_HH__
33
34#include <list>
35#include <map>
36#include <queue>
37
38#include "arch/types.hh"
39#include "base/statistics.hh"
40#include "cpu/base.hh"
41#include "cpu/base_dyn_inst.hh"
42#include "cpu/pc_event.hh"
43#include "cpu/simple_thread.hh"
44#include "cpu/static_inst.hh"
45#include "sim/eventq.hh"
46
47// forward declarations
48namespace TheISA
49{
50    class TLB;
51}
52
53template <class>
54class BaseDynInst;
55class CheckerCPUParams;
56class Checkpoint;
57class MemInterface;
58class PhysicalMemory;
59class Process;
60class Processor;
61class ThreadContext;
62class Request;
63
64/**
65 * CheckerCPU class.  Dynamically verifies instructions as they are
66 * completed by making sure that the instruction and its results match
67 * the independent execution of the benchmark inside the checker.  The
68 * checker verifies instructions in order, regardless of the order in
69 * which instructions complete.  There are certain results that can
70 * not be verified, specifically the result of a store conditional or
71 * the values of uncached accesses.  In these cases, and with
72 * instructions marked as "IsUnverifiable", the checker assumes that
73 * the value from the main CPU's execution is correct and simply
74 * copies that value.  It provides a CheckerThreadContext (see
75 * checker/thread_context.hh) that provides hooks for updating the
76 * Checker's state through any ThreadContext accesses.  This allows the
77 * checker to be able to correctly verify instructions, even with
78 * external accesses to the ThreadContext that change state.
79 */
80class CheckerCPU : public BaseCPU
81{
82  protected:
83    typedef TheISA::MachInst MachInst;
84    typedef TheISA::FloatReg FloatReg;
85    typedef TheISA::FloatRegBits FloatRegBits;
86    typedef TheISA::MiscReg MiscReg;
87  public:
88    virtual void init();
89
90  public:
91    typedef CheckerCPUParams Params;
92    const Params *params() const
93    { return reinterpret_cast<const Params *>(_params); }
94    CheckerCPU(Params *p);
95    virtual ~CheckerCPU();
96
97    Process *process;
98
99    void setSystem(System *system);
100
101    System *systemPtr;
102
103    void setIcachePort(Port *icache_port);
104
105    Port *icachePort;
106
107    void setDcachePort(Port *dcache_port);
108
109    Port *dcachePort;
110
111    virtual Port *getPort(const std::string &name, int idx)
112    {
113        panic("Not supported on checker!");
114        return NULL;
115    }
116
117  public:
118    // Primary thread being run.
119    SimpleThread *thread;
120
121    ThreadContext *tc;
122
123    TheISA::TLB *itb;
124    TheISA::TLB *dtb;
125
126    Addr dbg_vtophys(Addr addr);
127
128    union Result {
129        uint64_t integer;
130//        float fp;
131        double dbl;
132    };
133
134    Result result;
135
136    // current instruction
137    MachInst machInst;
138
139    // Pointer to the one memory request.
140    RequestPtr memReq;
141
142    StaticInstPtr curStaticInst;
143
144    // number of simulated instructions
145    Counter numInst;
146    Counter startNumInst;
147
148    std::queue<int> miscRegIdxs;
149
150    virtual Counter totalInstructions() const
151    {
152        return 0;
153    }
154
155    // number of simulated loads
156    Counter numLoad;
157    Counter startNumLoad;
158
159    virtual void serialize(std::ostream &os);
160    virtual void unserialize(Checkpoint *cp, const std::string &section);
161
162    template <class T>
163    Fault read(Addr addr, T &data, unsigned flags);
164
165    template <class T>
166    Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
167
168    // These functions are only used in CPU models that split
169    // effective address computation from the actual memory access.
170    void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
171    Addr getEA()        { panic("SimpleCPU::getEA() not implemented\n"); }
172
173    // The register accessor methods provide the index of the
174    // instruction's operand (e.g., 0 or 1), not the architectural
175    // register index, to simplify the implementation of register
176    // renaming.  We find the architectural register index by indexing
177    // into the instruction's own operand index table.  Note that a
178    // raw pointer to the StaticInst is provided instead of a
179    // ref-counted StaticInstPtr to redice overhead.  This is fine as
180    // long as these methods don't copy the pointer into any long-term
181    // storage (which is pretty hard to imagine they would have reason
182    // to do).
183
184    uint64_t readIntRegOperand(const StaticInst *si, int idx)
185    {
186        return thread->readIntReg(si->srcRegIdx(idx));
187    }
188
189    FloatReg readFloatRegOperand(const StaticInst *si, int idx)
190    {
191        int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
192        return thread->readFloatReg(reg_idx);
193    }
194
195    FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
196    {
197        int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
198        return thread->readFloatRegBits(reg_idx);
199    }
200
201    void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
202    {
203        thread->setIntReg(si->destRegIdx(idx), val);
204        result.integer = val;
205    }
206
207    void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
208    {
209        int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
210        thread->setFloatReg(reg_idx, val);
211        result.dbl = (double)val;
212    }
213
214    void setFloatRegOperandBits(const StaticInst *si, int idx,
215                                FloatRegBits val)
216    {
217        int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
218        thread->setFloatRegBits(reg_idx, val);
219        result.integer = val;
220    }
221
222    uint64_t instAddr() { return thread->instAddr(); }
223
224    uint64_t nextInstAddr() { return thread->nextInstAddr(); }
225
226    MiscReg readMiscRegNoEffect(int misc_reg)
227    {
228        return thread->readMiscRegNoEffect(misc_reg);
229    }
230
231    MiscReg readMiscReg(int misc_reg)
232    {
233        return thread->readMiscReg(misc_reg);
234    }
235
236    void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
237    {
238        result.integer = val;
239        miscRegIdxs.push(misc_reg);
240        return thread->setMiscRegNoEffect(misc_reg, val);
241    }
242
243    void setMiscReg(int misc_reg, const MiscReg &val)
244    {
245        miscRegIdxs.push(misc_reg);
246        return thread->setMiscReg(misc_reg, val);
247    }
248
249    void recordPCChange(uint64_t val) { changedPC = true; newPC = val; }
250    void recordNextPCChange(uint64_t val) { changedNextPC = true; }
251
252    void demapPage(Addr vaddr, uint64_t asn)
253    {
254        this->itb->demapPage(vaddr, asn);
255        this->dtb->demapPage(vaddr, asn);
256    }
257
258    void demapInstPage(Addr vaddr, uint64_t asn)
259    {
260        this->itb->demapPage(vaddr, asn);
261    }
262
263    void demapDataPage(Addr vaddr, uint64_t asn)
264    {
265        this->dtb->demapPage(vaddr, asn);
266    }
267
268    Fault hwrei() { return thread->hwrei(); }
269    bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
270    // Assume that the normal CPU's call to syscall was successful.
271    // The checker's state would have already been updated by the syscall.
272    void syscall(uint64_t callnum) { }
273
274    void handleError()
275    {
276        if (exitOnError)
277            dumpAndExit();
278    }
279
280    bool checkFlags(Request *req);
281
282    void dumpAndExit();
283
284    ThreadContext *tcBase() { return tc; }
285    SimpleThread *threadBase() { return thread; }
286
287    Result unverifiedResult;
288    Request *unverifiedReq;
289    uint8_t *unverifiedMemData;
290
291    bool changedPC;
292    bool willChangePC;
293    uint64_t newPC;
294    bool changedNextPC;
295    bool exitOnError;
296    bool updateOnError;
297    bool warnOnlyOnLoadError;
298
299    InstSeqNum youngestSN;
300};
301
302/**
303 * Templated Checker class.  This Checker class is templated on the
304 * DynInstPtr of the instruction type that will be verified.  Proper
305 * template instantiations of the Checker must be placed at the bottom
306 * of checker/cpu.cc.
307 */
308template <class DynInstPtr>
309class Checker : public CheckerCPU
310{
311  public:
312    Checker(Params *p)
313        : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
314    { }
315
316    void switchOut();
317    void takeOverFrom(BaseCPU *oldCPU);
318
319    void verify(DynInstPtr &inst);
320
321    void validateInst(DynInstPtr &inst);
322    void validateExecution(DynInstPtr &inst);
323    void validateState();
324
325    void copyResult(DynInstPtr &inst);
326
327  private:
328    void handleError(DynInstPtr &inst)
329    {
330        if (exitOnError) {
331            dumpAndExit(inst);
332        } else if (updateOnError) {
333            updateThisCycle = true;
334        }
335    }
336
337    void dumpAndExit(DynInstPtr &inst);
338
339    bool updateThisCycle;
340
341    DynInstPtr unverifiedInst;
342
343    std::list<DynInstPtr> instList;
344    typedef typename std::list<DynInstPtr>::iterator InstListIt;
345    void dumpInsts();
346};
347
348#endif // __CPU_CHECKER_CPU_HH__
349