base.hh revision 2462
1/*
2 * Copyright (c) 2002-2005 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
29#ifndef __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__
30#define __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__
31
32#include "base/statistics.hh"
33#include "config/full_system.hh"
34#include "cpu/base.hh"
35#include "cpu/cpu_exec_context.hh"
36#include "cpu/pc_event.hh"
37#include "cpu/sampler/sampler.hh"
38#include "cpu/static_inst.hh"
39#include "mem/packet.hh"
40#include "mem/port.hh"
41#include "mem/request.hh"
42#include "sim/eventq.hh"
43
44// forward declarations
45#if FULL_SYSTEM
46class Processor;
47class AlphaITB;
48class AlphaDTB;
49class MemObject;
50
51class RemoteGDB;
52class GDBListener;
53
54#else
55
56class Process;
57
58#endif // FULL_SYSTEM
59
60class ExecContext;
61class Checkpoint;
62
63namespace Trace {
64    class InstRecord;
65}
66
67
68// Set exactly one of these symbols to 1 to set the memory access
69// model.  Probably should make these template parameters, or even
70// just fork the CPU models.
71//
72#define SIMPLE_CPU_MEM_TIMING    0
73#define SIMPLE_CPU_MEM_ATOMIC    0
74#define SIMPLE_CPU_MEM_IMMEDIATE 1
75
76
77class SimpleCPU : public BaseCPU
78{
79  protected:
80    typedef TheISA::MachInst MachInst;
81    typedef TheISA::MiscReg MiscReg;
82    class CpuPort : public Port
83    {
84
85        SimpleCPU *cpu;
86
87      public:
88
89        CpuPort(SimpleCPU *_cpu)
90            : cpu(_cpu)
91        { }
92
93      protected:
94
95        virtual bool recvTiming(Packet &pkt);
96
97        virtual Tick recvAtomic(Packet &pkt);
98
99        virtual void recvFunctional(Packet &pkt);
100
101        virtual void recvStatusChange(Status status);
102
103        virtual Packet *recvRetry();
104    };
105
106    CpuPort icachePort;
107    CpuPort dcachePort;
108
109  public:
110    // main simulation loop (one cycle)
111    void tick();
112    virtual void init();
113
114  private:
115    struct TickEvent : public Event
116    {
117        SimpleCPU *cpu;
118        int width;
119
120        TickEvent(SimpleCPU *c, int w);
121        void process();
122        const char *description();
123    };
124
125    TickEvent tickEvent;
126
127    /// Schedule tick event, regardless of its current state.
128    void scheduleTickEvent(int numCycles)
129    {
130        if (tickEvent.squashed())
131            tickEvent.reschedule(curTick + cycles(numCycles));
132        else if (!tickEvent.scheduled())
133            tickEvent.schedule(curTick + cycles(numCycles));
134    }
135
136    /// Unschedule tick event, regardless of its current state.
137    void unscheduleTickEvent()
138    {
139        if (tickEvent.scheduled())
140            tickEvent.squash();
141    }
142
143  private:
144    Trace::InstRecord *traceData;
145
146  public:
147    //
148    enum Status {
149        Running,
150        Idle,
151        IcacheRetry,
152        IcacheWaitResponse,
153        IcacheAccessComplete,
154        DcacheRetry,
155        DcacheWaitResponse,
156        DcacheWaitSwitch,
157        SwitchedOut
158    };
159
160  private:
161    Status _status;
162
163  public:
164    void post_interrupt(int int_num, int index);
165
166    void zero_fill_64(Addr addr) {
167      static int warned = 0;
168      if (!warned) {
169        warn ("WH64 is not implemented");
170        warned = 1;
171      }
172    };
173
174  public:
175    struct Params : public BaseCPU::Params
176    {
177        int width;
178#if FULL_SYSTEM
179        AlphaITB *itb;
180        AlphaDTB *dtb;
181#else
182        MemObject *mem;
183        Process *process;
184#endif
185    };
186    SimpleCPU(Params *params);
187    virtual ~SimpleCPU();
188
189  public:
190    // execution context
191    CPUExecContext *cpuXC;
192
193    ExecContext *xcProxy;
194
195    void switchOut(Sampler *s);
196    void takeOverFrom(BaseCPU *oldCPU);
197
198#if FULL_SYSTEM
199    Addr dbg_vtophys(Addr addr);
200
201    bool interval_stats;
202#endif
203
204    // current instruction
205    MachInst inst;
206
207#if SIMPLE_CPU_MEM_TIMING
208    Packet *retry_pkt;
209#elif SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
210    CpuRequest *ifetch_req;
211    Packet     *ifetch_pkt;
212    CpuRequest *data_read_req;
213    Packet     *data_read_pkt;
214    CpuRequest *data_write_req;
215    Packet     *data_write_pkt;
216#endif
217
218    // Pointer to the sampler that is telling us to switchover.
219    // Used to signal the completion of the pipe drain and schedule
220    // the next switchover
221    Sampler *sampler;
222
223    StaticInstPtr curStaticInst;
224
225    Status status() const { return _status; }
226
227    virtual void activateContext(int thread_num, int delay);
228    virtual void suspendContext(int thread_num);
229    virtual void deallocateContext(int thread_num);
230    virtual void haltContext(int thread_num);
231
232    // statistics
233    virtual void regStats();
234    virtual void resetStats();
235
236    // number of simulated instructions
237    Counter numInst;
238    Counter startNumInst;
239    Stats::Scalar<> numInsts;
240
241    virtual Counter totalInstructions() const
242    {
243        return numInst - startNumInst;
244    }
245
246    // number of simulated memory references
247    Stats::Scalar<> numMemRefs;
248
249    // number of simulated loads
250    Counter numLoad;
251    Counter startNumLoad;
252
253    // number of idle cycles
254    Stats::Average<> notIdleFraction;
255    Stats::Formula idleFraction;
256
257    // number of cycles stalled for I-cache responses
258    Stats::Scalar<> icacheStallCycles;
259    Counter lastIcacheStall;
260
261    // number of cycles stalled for I-cache retries
262    Stats::Scalar<> icacheRetryCycles;
263    Counter lastIcacheRetry;
264
265    // number of cycles stalled for D-cache responses
266    Stats::Scalar<> dcacheStallCycles;
267    Counter lastDcacheStall;
268
269    // number of cycles stalled for D-cache retries
270    Stats::Scalar<> dcacheRetryCycles;
271    Counter lastDcacheRetry;
272
273    void sendIcacheRequest(Packet *pkt);
274    void sendDcacheRequest(Packet *pkt);
275    void processResponse(Packet &response);
276
277    Packet * processRetry();
278    void recvStatusChange(Port::Status status) {}
279
280    virtual void serialize(std::ostream &os);
281    virtual void unserialize(Checkpoint *cp, const std::string &section);
282
283    template <class T>
284    Fault read(Addr addr, T &data, unsigned flags);
285
286    template <class T>
287    Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
288
289    // These functions are only used in CPU models that split
290    // effective address computation from the actual memory access.
291    void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
292    Addr getEA() 	{ panic("SimpleCPU::getEA() not implemented\n"); }
293
294    void prefetch(Addr addr, unsigned flags)
295    {
296        // need to do this...
297    }
298
299    void writeHint(Addr addr, int size, unsigned flags)
300    {
301        // need to do this...
302    }
303
304    Fault copySrcTranslate(Addr src);
305
306    Fault copy(Addr dest);
307
308    // The register accessor methods provide the index of the
309    // instruction's operand (e.g., 0 or 1), not the architectural
310    // register index, to simplify the implementation of register
311    // renaming.  We find the architectural register index by indexing
312    // into the instruction's own operand index table.  Note that a
313    // raw pointer to the StaticInst is provided instead of a
314    // ref-counted StaticInstPtr to redice overhead.  This is fine as
315    // long as these methods don't copy the pointer into any long-term
316    // storage (which is pretty hard to imagine they would have reason
317    // to do).
318
319    uint64_t readIntReg(const StaticInst *si, int idx)
320    {
321        return cpuXC->readIntReg(si->srcRegIdx(idx));
322    }
323
324    float readFloatRegSingle(const StaticInst *si, int idx)
325    {
326        int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
327        return cpuXC->readFloatRegSingle(reg_idx);
328    }
329
330    double readFloatRegDouble(const StaticInst *si, int idx)
331    {
332        int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
333        return cpuXC->readFloatRegDouble(reg_idx);
334    }
335
336    uint64_t readFloatRegInt(const StaticInst *si, int idx)
337    {
338        int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
339        return cpuXC->readFloatRegInt(reg_idx);
340    }
341
342    void setIntReg(const StaticInst *si, int idx, uint64_t val)
343    {
344        cpuXC->setIntReg(si->destRegIdx(idx), val);
345    }
346
347    void setFloatRegSingle(const StaticInst *si, int idx, float val)
348    {
349        int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
350        cpuXC->setFloatRegSingle(reg_idx, val);
351    }
352
353    void setFloatRegDouble(const StaticInst *si, int idx, double val)
354    {
355        int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
356        cpuXC->setFloatRegDouble(reg_idx, val);
357    }
358
359    void setFloatRegInt(const StaticInst *si, int idx, uint64_t val)
360    {
361        int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
362        cpuXC->setFloatRegInt(reg_idx, val);
363    }
364
365    uint64_t readPC() { return cpuXC->readPC(); }
366    uint64_t readNextPC() { return cpuXC->readNextPC(); }
367    uint64_t readNextNPC() { return cpuXC->readNextNPC(); }
368
369    void setPC(uint64_t val) { cpuXC->setPC(val); }
370    void setNextPC(uint64_t val) { cpuXC->setNextPC(val); }
371    void setNextNPC(uint64_t val) { cpuXC->setNextNPC(val); }
372
373    MiscReg readMiscReg(int misc_reg)
374    {
375        return cpuXC->readMiscReg(misc_reg);
376    }
377
378    MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
379    {
380        return cpuXC->readMiscRegWithEffect(misc_reg, fault);
381    }
382
383    Fault setMiscReg(int misc_reg, const MiscReg &val)
384    {
385        return cpuXC->setMiscReg(misc_reg, val);
386    }
387
388    Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
389    {
390        return cpuXC->setMiscRegWithEffect(misc_reg, val);
391    }
392
393#if FULL_SYSTEM
394    Fault hwrei() { return cpuXC->hwrei(); }
395    int readIntrFlag() { return cpuXC->readIntrFlag(); }
396    void setIntrFlag(int val) { cpuXC->setIntrFlag(val); }
397    bool inPalMode() { return cpuXC->inPalMode(); }
398    void ev5_trap(Fault fault) { fault->invoke(xcProxy); }
399    bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); }
400#else
401    void syscall() { cpuXC->syscall(); }
402#endif
403
404    bool misspeculating() { return cpuXC->misspeculating(); }
405    ExecContext *xcBase() { return xcProxy; }
406};
407
408#endif // __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__
409