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