cpu.hh revision 2315
1/*
2 * Copyright (c) 2004-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_O3_FULL_CPU_HH__
30#define __CPU_O3_FULL_CPU_HH__
31
32#include <iostream>
33#include <list>
34#include <queue>
35#include <set>
36#include <vector>
37
38#include "base/statistics.hh"
39#include "base/timebuf.hh"
40#include "config/full_system.hh"
41#include "cpu/base.hh"
42#include "cpu/cpu_exec_context.hh"
43#include "cpu/o3/comm.hh"
44#include "cpu/o3/cpu_policy.hh"
45#include "cpu/o3/scoreboard.hh"
46#include "cpu/o3/thread_state.hh"
47#include "sim/process.hh"
48
49class ExecContext;
50class MemInterface;
51class Process;
52
53class BaseFullCPU : public BaseCPU
54{
55    //Stuff that's pretty ISA independent will go here.
56  public:
57    typedef BaseCPU::Params Params;
58
59    BaseFullCPU(Params *params);
60
61    void regStats();
62
63  protected:
64    int cpu_id;
65};
66
67template <class Impl>
68class FullO3CPU : public BaseFullCPU
69{
70  public:
71    //Put typedefs from the Impl here.
72    typedef typename Impl::CPUPol CPUPolicy;
73    typedef typename Impl::Params Params;
74    typedef typename Impl::DynInstPtr DynInstPtr;
75
76    typedef O3ThreadState<Impl> Thread;
77
78    typedef typename std::list<DynInstPtr>::iterator ListIt;
79
80  public:
81    enum Status {
82        Running,
83        Idle,
84        Halted,
85        Blocked,
86        SwitchedOut
87    };
88
89    /** Overall CPU status. */
90    Status _status;
91
92  private:
93    class TickEvent : public Event
94    {
95      private:
96        /** Pointer to the CPU. */
97        FullO3CPU<Impl> *cpu;
98
99      public:
100        /** Constructs a tick event. */
101        TickEvent(FullO3CPU<Impl> *c);
102
103        /** Processes a tick event, calling tick() on the CPU. */
104        void process();
105        /** Returns the description of the tick event. */
106        const char *description();
107    };
108
109    /** The tick event used for scheduling CPU ticks. */
110    TickEvent tickEvent;
111
112    /** Schedule tick event, regardless of its current state. */
113    void scheduleTickEvent(int delay)
114    {
115        if (tickEvent.squashed())
116            tickEvent.reschedule(curTick + cycles(delay));
117        else if (!tickEvent.scheduled())
118            tickEvent.schedule(curTick + cycles(delay));
119    }
120
121    /** Unschedule tick event, regardless of its current state. */
122    void unscheduleTickEvent()
123    {
124        if (tickEvent.scheduled())
125            tickEvent.squash();
126    }
127
128  public:
129    /** Constructs a CPU with the given parameters. */
130    FullO3CPU(Params *params);
131    /** Destructor. */
132    ~FullO3CPU();
133
134    /** Registers statistics. */
135    void fullCPURegStats();
136
137    /** Ticks CPU, calling tick() on each stage, and checking the overall
138     *  activity to see if the CPU should deschedule itself.
139     */
140    void tick();
141
142    /** Initialize the CPU */
143    void init();
144
145    /** Setup CPU to insert a thread's context */
146    void insertThread(unsigned tid);
147
148    /** Remove all of a thread's context from CPU */
149    void removeThread(unsigned tid);
150
151    /** Count the Total Instructions Committed in the CPU. */
152    virtual Counter totalInstructions() const
153    {
154        Counter total(0);
155
156        for (int i=0; i < thread.size(); i++)
157            total += thread[i]->numInst;
158
159        return total;
160    }
161
162    /** Add Thread to Active Threads List. */
163    void activateContext(int tid, int delay);
164
165    /** Remove Thread from Active Threads List */
166    void suspendContext(int tid);
167
168    /** Remove Thread from Active Threads List &&
169     *  Remove Thread Context from CPU.
170     */
171    void deallocateContext(int tid);
172
173    /** Remove Thread from Active Threads List &&
174     *  Remove Thread Context from CPU.
175     */
176    void haltContext(int tid);
177
178    /** Activate a Thread When CPU Resources are Available. */
179    void activateWhenReady(int tid);
180
181    /** Add or Remove a Thread Context in the CPU. */
182    void doContextSwitch();
183
184    /** Update The Order In Which We Process Threads. */
185    void updateThreadPriority();
186
187    /** Executes a syscall on this cycle.
188     *  ---------------------------------------
189     *  Note: this is a virtual function. CPU-Specific
190     *  functionality defined in derived classes
191     */
192    virtual void syscall(int tid) {}
193
194    /** Check if there are any system calls pending. */
195    void checkSyscalls();
196
197    /** Switches out this CPU.
198     *  @todo: Implement this.
199     */
200    void switchOut(Sampler *sampler);
201
202    /** Takes over from another CPU.
203     *  @todo: Implement this.
204     */
205    void takeOverFrom(BaseCPU *oldCPU);
206
207    /** Get the current instruction sequence number, and increment it. */
208    InstSeqNum getAndIncrementInstSeq();
209
210#if FULL_SYSTEM
211    /** Check if this address is a valid instruction address. */
212    bool validInstAddr(Addr addr) { return true; }
213
214    /** Check if this address is a valid data address. */
215    bool validDataAddr(Addr addr) { return true; }
216
217    /** Get instruction asid. */
218    int getInstAsid(unsigned tid)
219    { return regFile.miscRegs[tid].getInstAsid(); }
220
221    /** Get data asid. */
222    int getDataAsid(unsigned tid)
223    { return regFile.miscRegs[tid].getDataAsid(); }
224#else
225    /** Check if this address is a valid instruction address. */
226    bool validInstAddr(Addr addr,unsigned tid)
227    { return thread[tid]->validInstAddr(addr); }
228
229    /** Check if this address is a valid data address. */
230    bool validDataAddr(Addr addr,unsigned tid)
231    { return thread[tid]->validDataAddr(addr); }
232
233    /** Get instruction asid. */
234    int getInstAsid(unsigned tid)
235    { return thread[tid]->asid; }
236
237    /** Get data asid. */
238    int getDataAsid(unsigned tid)
239    { return thread[tid]->asid; }
240
241#endif
242
243    //
244    // New accessors for new decoder.
245    //
246    uint64_t readIntReg(int reg_idx);
247
248    float readFloatRegSingle(int reg_idx);
249
250    double readFloatRegDouble(int reg_idx);
251
252    uint64_t readFloatRegInt(int reg_idx);
253
254    void setIntReg(int reg_idx, uint64_t val);
255
256    void setFloatRegSingle(int reg_idx, float val);
257
258    void setFloatRegDouble(int reg_idx, double val);
259
260    void setFloatRegInt(int reg_idx, uint64_t val);
261
262    uint64_t readArchIntReg(int reg_idx, unsigned tid);
263
264    float readArchFloatRegSingle(int reg_idx, unsigned tid);
265
266    double readArchFloatRegDouble(int reg_idx, unsigned tid);
267
268    uint64_t readArchFloatRegInt(int reg_idx, unsigned tid);
269
270    void setArchIntReg(int reg_idx, uint64_t val, unsigned tid);
271
272    void setArchFloatRegSingle(int reg_idx, float val, unsigned tid);
273
274    void setArchFloatRegDouble(int reg_idx, double val, unsigned tid);
275
276    void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid);
277
278    uint64_t readPC(unsigned tid);
279
280    void setPC(Addr new_PC,unsigned tid);
281
282    uint64_t readNextPC(unsigned tid);
283
284    void setNextPC(uint64_t val,unsigned tid);
285
286    /** Function to add instruction onto the head of the list of the
287     *  instructions.  Used when new instructions are fetched.
288     */
289    ListIt addInst(DynInstPtr &inst);
290
291    /** Function to tell the CPU that an instruction has completed. */
292    void instDone(unsigned tid);
293
294    /** Add Instructions to the CPU Remove List*/
295    void addToRemoveList(DynInstPtr &inst);
296
297    /** Remove an instruction from the front of the list.  It is expected
298     *  that there are no instructions in front of it (that is, none are older
299     *  than the instruction being removed).  Used when retiring instructions.
300     *  @todo: Remove the argument to this function, and just have it remove
301     *  last instruction once it's verified that commit has the same ordering
302     *  as the instruction list.
303     */
304    void removeFrontInst(DynInstPtr &inst);
305
306    /** Remove all instructions that are not currently in the ROB. */
307    void removeInstsNotInROB(unsigned tid);
308
309    /** Remove all instructions younger than the given sequence number. */
310    void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid);
311
312    inline void squashInstIt(const ListIt &instIt, const unsigned &tid);
313
314    void cleanUpRemovedInsts();
315
316    /** Remove all instructions from the list. */
317    void removeAllInsts();
318
319    void dumpInsts();
320
321    /** Basically a wrapper function so that instructions executed at
322     *  commit can tell the instruction queue that they have completed.
323     *  Eventually this hack should be removed.
324     */
325    void wakeDependents(DynInstPtr &inst);
326
327  public:
328    /** List of all the instructions in flight. */
329    std::list<DynInstPtr> instList;
330
331    /** List of all the instructions that will be removed at the end of this
332     *  cycle.
333     */
334    std::queue<ListIt> removeList;
335
336#ifdef DEBUG
337    std::set<InstSeqNum> snList;
338#endif
339
340    /** Records if instructions need to be removed this cycle due to being
341     *  retired or squashed.
342     */
343    bool removeInstsThisCycle;
344
345  protected:
346    /** The fetch stage. */
347    typename CPUPolicy::Fetch fetch;
348
349    /** The decode stage. */
350    typename CPUPolicy::Decode decode;
351
352    /** The dispatch stage. */
353    typename CPUPolicy::Rename rename;
354
355    /** The issue/execute/writeback stages. */
356    typename CPUPolicy::IEW iew;
357
358    /** The commit stage. */
359    typename CPUPolicy::Commit commit;
360
361    /** The register file. */
362    typename CPUPolicy::RegFile regFile;
363
364    /** The free list. */
365    typename CPUPolicy::FreeList freeList;
366
367    /** The rename map. */
368    typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads];
369
370    /** The commit rename map. */
371    typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads];
372
373    /** The re-order buffer. */
374    typename CPUPolicy::ROB rob;
375
376    /** Active Threads List */
377    std::list<unsigned> activeThreads;
378
379    /** Integer Register Scoreboard */
380    Scoreboard scoreboard;
381
382  public:
383    /** Enum to give each stage a specific index, so when calling
384     *  activateStage() or deactivateStage(), they can specify which stage
385     *  is being activated/deactivated.
386     */
387    enum StageIdx {
388        FetchIdx,
389        DecodeIdx,
390        RenameIdx,
391        IEWIdx,
392        CommitIdx,
393        NumStages };
394
395    /** Typedefs from the Impl to get the structs that each of the
396     *  time buffers should use.
397     */
398    typedef typename CPUPolicy::TimeStruct TimeStruct;
399
400    typedef typename CPUPolicy::FetchStruct FetchStruct;
401
402    typedef typename CPUPolicy::DecodeStruct DecodeStruct;
403
404    typedef typename CPUPolicy::RenameStruct RenameStruct;
405
406    typedef typename CPUPolicy::IEWStruct IEWStruct;
407
408    /** The main time buffer to do backwards communication. */
409    TimeBuffer<TimeStruct> timeBuffer;
410
411    /** The fetch stage's instruction queue. */
412    TimeBuffer<FetchStruct> fetchQueue;
413
414    /** The decode stage's instruction queue. */
415    TimeBuffer<DecodeStruct> decodeQueue;
416
417    /** The rename stage's instruction queue. */
418    TimeBuffer<RenameStruct> renameQueue;
419
420    /** The IEW stage's instruction queue. */
421    TimeBuffer<IEWStruct> iewQueue;
422
423  private:
424    /** Time buffer that tracks if any cycles has active communication in them.
425     *  It should be as long as the longest communication latency in the system.
426     *  Each time any time buffer is written, the activity buffer should also
427     *  be written to. The activityBuffer is advanced along with all the other
428     *  time buffers, so it should always have a 1 somewhere in it only if there
429     *  is active communication in a time buffer.
430     */
431    TimeBuffer<bool> activityBuffer;
432
433    /** Tracks how many stages and cycles of time buffer have activity. Stages
434     *  increment this count when they switch to active, and decrement it when
435     *  they switch to inactive. Whenever a cycle that previously had no
436     *  information is written in the time buffer, this is incremented. When
437     *  a cycle that had information exits the time buffer due to age, this
438     *  count is decremented. When the count is 0, there is no activity in the
439     *  CPU, and it can be descheduled.
440     */
441    int activityCount;
442
443    /** Records if there has been activity this cycle. */
444    bool activity;
445
446    /** Records which stages are active/inactive. */
447    bool stageActive[NumStages];
448
449  public:
450    /** Wakes the CPU, rescheduling the CPU if it's not already active. */
451    void wakeCPU();
452    /** Records that there is activity this cycle. */
453    void activityThisCycle();
454    /** Advances the activity buffer, decrementing the activityCount if active
455     *  communication just left the time buffer, and descheduling the CPU if
456     *  there is no activity.
457     */
458    void advanceActivityBuffer();
459    /** Marks a stage as active. */
460    void activateStage(const StageIdx idx);
461    /** Deactivates a stage. */
462    void deactivateStage(const StageIdx idx);
463
464    /** Gets a free thread id. Use if thread ids change across system. */
465    int getFreeTid();
466
467  public:
468    /** Temporary function to get pointer to exec context. */
469    ExecContext *xcBase(unsigned tid)
470    {
471        return thread[tid]->getXCProxy();
472    }
473
474    /** The global sequence number counter. */
475    InstSeqNum globalSeqNum;
476
477#if FULL_SYSTEM
478    /** Pointer to the system. */
479    System *system;
480
481    /** Pointer to the memory controller. */
482    MemoryController *memCtrl;
483    /** Pointer to physical memory. */
484    PhysicalMemory *physmem;
485#endif
486
487    // List of all ExecContexts.
488    std::vector<Thread *> thread;
489
490    /** Pointer to memory. */
491    FunctionalMemory *mem;
492
493#if 0
494    /** Page table pointer. */
495    PageTable *pTable;
496#endif
497
498    /** Pointer to the icache interface. */
499    MemInterface *icacheInterface;
500    /** Pointer to the dcache interface. */
501    MemInterface *dcacheInterface;
502
503    /** Whether or not the CPU should defer its registration. */
504    bool deferRegistration;
505
506    /** Is there a context switch pending? */
507    bool contextSwitch;
508
509    /** Threads Scheduled to Enter CPU */
510    std::list<int> cpuWaitList;
511
512    /** The cycle that the CPU was last running, used for statistics. */
513    Tick lastRunningCycle;
514
515    /** Number of Threads CPU can process */
516    unsigned numThreads;
517
518    /** Mapping for system thread id to cpu id */
519    std::map<unsigned,unsigned> threadMap;
520
521    /** Available thread ids in the cpu*/
522    std::vector<unsigned> tids;
523
524    /** Stat for total number of times the CPU is descheduled. */
525    Stats::Scalar<> timesIdled;
526    /** Stat for total number of cycles the CPU spends descheduled. */
527    Stats::Scalar<> idleCycles;
528    /** Stat for the number of committed instructions per thread. */
529    Stats::Vector<> committedInsts;
530    /** Stat for the total number of committed instructions. */
531    Stats::Scalar<> totalCommittedInsts;
532    /** Stat for the CPI per thread. */
533    Stats::Formula cpi;
534    /** Stat for the total CPI. */
535    Stats::Formula totalCpi;
536    /** Stat for the IPC per thread. */
537    Stats::Formula ipc;
538    /** Stat for the total IPC. */
539    Stats::Formula totalIpc;
540};
541
542#endif
543