simple_thread.hh revision 2188
1/*
2 * Copyright (c) 2001-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
29#ifndef __CPU_EXEC_CONTEXT_HH__
30#define __CPU_EXEC_CONTEXT_HH__
31
32#include "config/full_system.hh"
33#include "mem/functional/functional.hh"
34#include "mem/mem_req.hh"
35#include "sim/eventq.hh"
36#include "sim/host.hh"
37#include "sim/serialize.hh"
38#include "arch/isa_traits.hh"
39//#include "arch/isa_registers.hh"
40#include "sim/byteswap.hh"
41
42// forward declaration: see functional_memory.hh
43class FunctionalMemory;
44class PhysicalMemory;
45class BaseCPU;
46
47#if FULL_SYSTEM
48
49#include "sim/system.hh"
50#include "targetarch/alpha_memory.hh"
51
52class FunctionProfile;
53class ProfileNode;
54class MemoryController;
55namespace Kernel { class Binning; class Statistics; }
56
57#else // !FULL_SYSTEM
58
59#include "sim/process.hh"
60
61#endif // FULL_SYSTEM
62
63//
64// The ExecContext object represents a functional context for
65// instruction execution.  It incorporates everything required for
66// architecture-level functional simulation of a single thread.
67//
68
69class ExecContext
70{
71  protected:
72    typedef TheISA::RegFile RegFile;
73    typedef TheISA::MachInst MachInst;
74    typedef TheISA::MiscRegFile MiscRegFile;
75  public:
76    enum Status
77    {
78        /// Initialized but not running yet.  All CPUs start in
79        /// this state, but most transition to Active on cycle 1.
80        /// In MP or SMT systems, non-primary contexts will stay
81        /// in this state until a thread is assigned to them.
82        Unallocated,
83
84        /// Running.  Instructions should be executed only when
85        /// the context is in this state.
86        Active,
87
88        /// Temporarily inactive.  Entered while waiting for
89        /// initialization,synchronization, etc.
90        Suspended,
91
92        /// Permanently shut down.  Entered when target executes
93        /// m5exit pseudo-instruction.  When all contexts enter
94        /// this state, the simulation will terminate.
95        Halted
96    };
97
98  private:
99    Status _status;
100
101  public:
102    Status status() const { return _status; }
103
104    void setStatus(Status newStatus) { _status = newStatus; }
105
106    /// Set the status to Active.  Optional delay indicates number of
107    /// cycles to wait before beginning execution.
108    void activate(int delay = 1);
109
110    /// Set the status to Suspended.
111    void suspend();
112
113    /// Set the status to Unallocated.
114    void deallocate();
115
116    /// Set the status to Halted.
117    void halt();
118
119  public:
120    RegFile regs;	// correct-path register context
121
122    // pointer to CPU associated with this context
123    BaseCPU *cpu;
124
125    // Current instruction
126    MachInst inst;
127
128    // Index of hardware thread context on the CPU that this represents.
129    int thread_num;
130
131    // ID of this context w.r.t. the System or Process object to which
132    // it belongs.  For full-system mode, this is the system CPU ID.
133    int cpu_id;
134
135    Tick lastActivate;
136    Tick lastSuspend;
137
138#if FULL_SYSTEM
139    FunctionalMemory *mem;
140    AlphaITB *itb;
141    AlphaDTB *dtb;
142    System *system;
143
144    // the following two fields are redundant, since we can always
145    // look them up through the system pointer, but we'll leave them
146    // here for now for convenience
147    MemoryController *memctrl;
148    PhysicalMemory *physmem;
149
150    Kernel::Binning *kernelBinning;
151    Kernel::Statistics *kernelStats;
152    bool bin;
153    bool fnbin;
154
155    FunctionProfile *profile;
156    ProfileNode *profileNode;
157    Addr profilePC;
158    void dumpFuncProfile();
159
160    /** Event for timing out quiesce instruction */
161    struct EndQuiesceEvent : public Event
162    {
163        /** A pointer to the execution context that is quiesced */
164        ExecContext *xc;
165
166        EndQuiesceEvent(ExecContext *_xc);
167
168        /** Event process to occur at interrupt*/
169        virtual void process();
170
171        /** Event description */
172        virtual const char *description();
173    };
174    EndQuiesceEvent quiesceEvent;
175
176#else
177    Process *process;
178
179    FunctionalMemory *mem;	// functional storage for process address space
180
181    // Address space ID.  Note that this is used for TIMING cache
182    // simulation only; all functional memory accesses should use
183    // one of the FunctionalMemory pointers above.
184    short asid;
185
186#endif
187
188    /**
189     * Temporary storage to pass the source address from copy_load to
190     * copy_store.
191     * @todo Remove this temporary when we have a better way to do it.
192     */
193    Addr copySrcAddr;
194    /**
195     * Temp storage for the physical source address of a copy.
196     * @todo Remove this temporary when we have a better way to do it.
197     */
198    Addr copySrcPhysAddr;
199
200
201    /*
202     * number of executed instructions, for matching with syscall trace
203     * points in EIO files.
204     */
205    Counter func_exe_inst;
206
207    //
208    // Count failed store conditionals so we can warn of apparent
209    // application deadlock situations.
210    unsigned storeCondFailures;
211
212    // constructor: initialize context from given process structure
213#if FULL_SYSTEM
214    ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
215                AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem);
216#else
217    ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
218    ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
219                int _asid);
220#endif
221    virtual ~ExecContext();
222
223    virtual void takeOverFrom(ExecContext *oldContext);
224
225    void regStats(const std::string &name);
226
227    void serialize(std::ostream &os);
228    void unserialize(Checkpoint *cp, const std::string &section);
229
230#if FULL_SYSTEM
231    bool validInstAddr(Addr addr) { return true; }
232    bool validDataAddr(Addr addr) { return true; }
233    int getInstAsid() { return regs.instAsid(); }
234    int getDataAsid() { return regs.dataAsid(); }
235
236    Fault translateInstReq(MemReqPtr &req)
237    {
238        return itb->translate(req);
239    }
240
241    Fault translateDataReadReq(MemReqPtr &req)
242    {
243        return dtb->translate(req, false);
244    }
245
246    Fault translateDataWriteReq(MemReqPtr &req)
247    {
248        return dtb->translate(req, true);
249    }
250
251#else
252    bool validInstAddr(Addr addr)
253    { return process->validInstAddr(addr); }
254
255    bool validDataAddr(Addr addr)
256    { return process->validDataAddr(addr); }
257
258    int getInstAsid() { return asid; }
259    int getDataAsid() { return asid; }
260
261    Fault dummyTranslation(MemReqPtr &req)
262    {
263#if 0
264        assert((req->vaddr >> 48 & 0xffff) == 0);
265#endif
266
267        // put the asid in the upper 16 bits of the paddr
268        req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
269        req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
270        return NoFault;
271    }
272    Fault translateInstReq(MemReqPtr &req)
273    {
274        return dummyTranslation(req);
275    }
276    Fault translateDataReadReq(MemReqPtr &req)
277    {
278        return dummyTranslation(req);
279    }
280    Fault translateDataWriteReq(MemReqPtr &req)
281    {
282        return dummyTranslation(req);
283    }
284
285#endif
286
287    template <class T>
288    Fault read(MemReqPtr &req, T &data)
289    {
290#if FULL_SYSTEM && defined(TARGET_ALPHA)
291        if (req->flags & LOCKED) {
292            MiscRegFile *cregs = &req->xc->regs.miscRegs;
293            cregs->lock_addr = req->paddr;
294            cregs->lock_flag = true;
295        }
296#endif
297
298        Fault error;
299        error = mem->read(req, data);
300        data = LittleEndianGuest::gtoh(data);
301        return error;
302    }
303
304    template <class T>
305    Fault write(MemReqPtr &req, T &data)
306    {
307#if FULL_SYSTEM && defined(TARGET_ALPHA)
308
309        MiscRegFile *cregs;
310
311        // If this is a store conditional, act appropriately
312        if (req->flags & LOCKED) {
313            cregs = &req->xc->regs.miscRegs;
314
315            if (req->flags & UNCACHEABLE) {
316                // Don't update result register (see stq_c in isa_desc)
317                req->result = 2;
318                req->xc->storeCondFailures = 0;//Needed? [RGD]
319            } else {
320                req->result = cregs->lock_flag;
321                if (!cregs->lock_flag ||
322                    ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
323                    cregs->lock_flag = false;
324                    if (((++req->xc->storeCondFailures) % 100000) == 0) {
325                        std::cerr << "Warning: "
326                                  << req->xc->storeCondFailures
327                                  << " consecutive store conditional failures "
328                                  << "on cpu " << req->xc->cpu_id
329                                  << std::endl;
330                    }
331                    return NoFault;
332                }
333                else req->xc->storeCondFailures = 0;
334            }
335        }
336
337        // Need to clear any locked flags on other proccessors for
338        // this address.  Only do this for succsful Store Conditionals
339        // and all other stores (WH64?).  Unsuccessful Store
340        // Conditionals would have returned above, and wouldn't fall
341        // through.
342        for (int i = 0; i < system->execContexts.size(); i++){
343            cregs = &system->execContexts[i]->regs.miscRegs;
344            if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
345                cregs->lock_flag = false;
346            }
347        }
348
349#endif
350        return mem->write(req, (T)LittleEndianGuest::htog(data));
351    }
352
353    virtual bool misspeculating();
354
355
356    MachInst getInst() { return inst; }
357
358    void setInst(MachInst new_inst)
359    {
360        inst = new_inst;
361    }
362
363    Fault instRead(MemReqPtr &req)
364    {
365        return mem->read(req, inst);
366    }
367
368    //
369    // New accessors for new decoder.
370    //
371    uint64_t readIntReg(int reg_idx)
372    {
373        return regs.intRegFile[reg_idx];
374    }
375
376    float readFloatRegSingle(int reg_idx)
377    {
378        return (float)regs.floatRegFile.d[reg_idx];
379    }
380
381    double readFloatRegDouble(int reg_idx)
382    {
383        return regs.floatRegFile.d[reg_idx];
384    }
385
386    uint64_t readFloatRegInt(int reg_idx)
387    {
388        return regs.floatRegFile.q[reg_idx];
389    }
390
391    void setIntReg(int reg_idx, uint64_t val)
392    {
393        regs.intRegFile[reg_idx] = val;
394    }
395
396    void setFloatRegSingle(int reg_idx, float val)
397    {
398        regs.floatRegFile.d[reg_idx] = (double)val;
399    }
400
401    void setFloatRegDouble(int reg_idx, double val)
402    {
403        regs.floatRegFile.d[reg_idx] = val;
404    }
405
406    void setFloatRegInt(int reg_idx, uint64_t val)
407    {
408        regs.floatRegFile.q[reg_idx] = val;
409    }
410
411    uint64_t readPC()
412    {
413        return regs.pc;
414    }
415
416    void setNextPC(uint64_t val)
417    {
418        regs.npc = val;
419    }
420
421    uint64_t readUniq()
422    {
423        return regs.miscRegs.uniq;
424    }
425
426    void setUniq(uint64_t val)
427    {
428        regs.miscRegs.uniq = val;
429    }
430
431    uint64_t readFpcr()
432    {
433        return regs.miscRegs.fpcr;
434    }
435
436    void setFpcr(uint64_t val)
437    {
438        regs.miscRegs.fpcr = val;
439    }
440
441#if FULL_SYSTEM
442    uint64_t readIpr(int idx, Fault &fault);
443    Fault setIpr(int idx, uint64_t val);
444    int readIntrFlag() { return regs.intrflag; }
445    void setIntrFlag(int val) { regs.intrflag = val; }
446    Fault hwrei();
447    bool inPalMode() { return AlphaISA::PcPAL(regs.pc); }
448    void ev5_trap(Fault fault);
449    bool simPalCheck(int palFunc);
450#endif
451
452    /** Meant to be more generic trap function to be
453     *  called when an instruction faults.
454     *  @param fault The fault generated by executing the instruction.
455     *  @todo How to do this properly so it's dependent upon ISA only?
456     */
457
458    void trap(Fault fault);
459
460#if !FULL_SYSTEM
461    TheISA::IntReg getSyscallArg(int i)
462    {
463        return regs.intRegFile[TheISA::ArgumentReg0 + i];
464    }
465
466    // used to shift args for indirect syscall
467    void setSyscallArg(int i, TheISA::IntReg val)
468    {
469        regs.intRegFile[TheISA::ArgumentReg0 + i] = val;
470    }
471
472    void setSyscallReturn(SyscallReturn return_value)
473    {
474        // check for error condition.  Alpha syscall convention is to
475        // indicate success/failure in reg a3 (r19) and put the
476        // return value itself in the standard return value reg (v0).
477        const int RegA3 = 19;	// only place this is used
478        if (return_value.successful()) {
479            // no error
480            regs.intRegFile[RegA3] = 0;
481            regs.intRegFile[TheISA::ReturnValueReg] = return_value.value();
482        } else {
483            // got an error, return details
484            regs.intRegFile[RegA3] = (TheISA::IntReg) -1;
485            regs.intRegFile[TheISA::ReturnValueReg] = -return_value.value();
486        }
487    }
488
489    void syscall()
490    {
491        process->syscall(this);
492    }
493#endif
494};
495
496
497// for non-speculative execution context, spec_mode is always false
498inline bool
499ExecContext::misspeculating()
500{
501    return false;
502}
503
504#endif // __CPU_EXEC_CONTEXT_HH__
505