cpu.cc revision 1681
1#ifndef __SIMPLE_FULL_CPU_CC__
2#define __SIMPLE_FULL_CPU_CC__
3
4#ifdef FULL_SYSTEM
5#include "sim/system.hh"
6#else
7#include "sim/process.hh"
8#endif
9#include "sim/universe.hh"
10
11#include "cpu/exec_context.hh"
12#include "cpu/beta_cpu/full_cpu.hh"
13#include "cpu/beta_cpu/alpha_impl.hh"
14#include "cpu/beta_cpu/alpha_dyn_inst.hh"
15
16using namespace std;
17
18BaseFullCPU::BaseFullCPU(Params &params)
19    : BaseCPU(&params), cpu_id(0)
20{
21}
22
23template <class Impl>
24FullBetaCPU<Impl>::TickEvent::TickEvent(FullBetaCPU<Impl> *c)
25    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
26{
27}
28
29template <class Impl>
30void
31FullBetaCPU<Impl>::TickEvent::process()
32{
33    cpu->tick();
34}
35
36template <class Impl>
37const char *
38FullBetaCPU<Impl>::TickEvent::description()
39{
40    return "FullBetaCPU tick event";
41}
42
43//Call constructor to all the pipeline stages here
44template <class Impl>
45FullBetaCPU<Impl>::FullBetaCPU(Params &params)
46#ifdef FULL_SYSTEM
47    : BaseFullCPU(params),
48#else
49    : BaseFullCPU(params),
50#endif // FULL_SYSTEM
51      tickEvent(this),
52      fetch(params),
53      decode(params),
54      rename(params),
55      iew(params),
56      commit(params),
57
58      regFile(params.numPhysIntRegs, params.numPhysFloatRegs),
59
60      freeList(Impl::ISA::NumIntRegs, params.numPhysIntRegs,
61               Impl::ISA::NumFloatRegs, params.numPhysFloatRegs),
62
63      renameMap(Impl::ISA::NumIntRegs, params.numPhysIntRegs,
64                Impl::ISA::NumFloatRegs, params.numPhysFloatRegs,
65                Impl::ISA::NumMiscRegs,
66                Impl::ISA::ZeroReg,
67                Impl::ISA::ZeroReg + Impl::ISA::NumIntRegs),
68
69      rob(params.numROBEntries, params.squashWidth),
70
71      // What to pass to these time buffers?
72      // For now just have these time buffers be pretty big.
73      timeBuffer(5, 5),
74      fetchQueue(5, 5),
75      decodeQueue(5, 5),
76      renameQueue(5, 5),
77      iewQueue(5, 5),
78
79      xc(NULL),
80
81      globalSeqNum(1),
82
83#ifdef FULL_SYSTEM
84      system(params.system),
85      memCtrl(system->memctrl),
86      physmem(system->physmem),
87      itb(params.itb),
88      dtb(params.dtb),
89      mem(params.mem),
90#else
91      // Hardcoded for a single thread!!
92      mem(params.workload[0]->getMemory()),
93#endif // FULL_SYSTEM
94
95      icacheInterface(params.icacheInterface),
96      dcacheInterface(params.dcacheInterface),
97      deferRegistration(params.defReg),
98      numInsts(0),
99      funcExeInst(0)
100{
101    _status = Idle;
102
103#ifndef FULL_SYSTEM
104    thread.resize(this->number_of_threads);
105#endif
106
107    for (int i = 0; i < this->number_of_threads; ++i) {
108#ifdef FULL_SYSTEM
109        assert(i == 0);
110        system->execContexts[i] =
111            new ExecContext(this, i, system, itb, dtb, mem);
112
113        // initialize CPU, including PC
114        TheISA::initCPU(&system->execContexts[i]->regs);
115        execContexts.push_back(system->execContexts[i]);
116#else
117        if (i < params.workload.size()) {
118            DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, "
119                    "process is %#x",
120                    i, params.workload[i]->prog_entry, thread[i]);
121            thread[i] = new ExecContext(this, i, params.workload[i], i);
122        }
123        assert(params.workload[i]->getMemory() != NULL);
124        assert(mem != NULL);
125        execContexts.push_back(thread[i]);
126#endif // !FULL_SYSTEM
127    }
128
129    // Note that this is a hack so that my code which still uses xc-> will
130    // still work.  I should remove this eventually
131#ifdef FULL_SYSTEM
132    xc = system->execContexts[0];
133#else
134    xc = thread[0];
135#endif
136
137    // The stages also need their CPU pointer setup.  However this must be
138    // done at the upper level CPU because they have pointers to the upper
139    // level CPU, and not this FullBetaCPU.
140
141    // Give each of the stages the time buffer they will use.
142    fetch.setTimeBuffer(&timeBuffer);
143    decode.setTimeBuffer(&timeBuffer);
144    rename.setTimeBuffer(&timeBuffer);
145    iew.setTimeBuffer(&timeBuffer);
146    commit.setTimeBuffer(&timeBuffer);
147
148    // Also setup each of the stages' queues.
149    fetch.setFetchQueue(&fetchQueue);
150    decode.setFetchQueue(&fetchQueue);
151    decode.setDecodeQueue(&decodeQueue);
152    rename.setDecodeQueue(&decodeQueue);
153    rename.setRenameQueue(&renameQueue);
154    iew.setRenameQueue(&renameQueue);
155    iew.setIEWQueue(&iewQueue);
156    commit.setIEWQueue(&iewQueue);
157    commit.setRenameQueue(&renameQueue);
158
159    // Setup the rename map for whichever stages need it.
160    rename.setRenameMap(&renameMap);
161    iew.setRenameMap(&renameMap);
162
163    // Setup the free list for whichever stages need it.
164    rename.setFreeList(&freeList);
165    renameMap.setFreeList(&freeList);
166
167    // Setup the ROB for whichever stages need it.
168    commit.setROB(&rob);
169}
170
171template <class Impl>
172FullBetaCPU<Impl>::~FullBetaCPU()
173{
174}
175
176template <class Impl>
177void
178FullBetaCPU<Impl>::fullCPURegStats()
179{
180    // Register any of the FullCPU's stats here.
181}
182
183template <class Impl>
184void
185FullBetaCPU<Impl>::tick()
186{
187    DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullBetaCPU.\n");
188
189    //Tick each of the stages if they're actually running.
190    //Will want to figure out a way to unschedule itself if they're all
191    //going to be idle for a long time.
192    fetch.tick();
193
194    decode.tick();
195
196    rename.tick();
197
198    iew.tick();
199
200    commit.tick();
201
202    // Now advance the time buffers, unless the stage is stalled.
203    timeBuffer.advance();
204
205    fetchQueue.advance();
206    decodeQueue.advance();
207    renameQueue.advance();
208    iewQueue.advance();
209
210    if (_status == Running && !tickEvent.scheduled())
211        tickEvent.schedule(curTick + 1);
212}
213
214template <class Impl>
215void
216FullBetaCPU<Impl>::init()
217{
218    if(!deferRegistration)
219    {
220        this->registerExecContexts();
221
222        // Need to do a copy of the xc->regs into the CPU's regfile so
223        // that it can start properly.
224#ifdef FULL_SYSTEM
225        ExecContext *src_xc = system->execContexts[0];
226#else
227        ExecContext *src_xc = thread[0];
228#endif
229        // First loop through the integer registers.
230        for (int i = 0; i < Impl::ISA::NumIntRegs; ++i)
231        {
232            regFile.intRegFile[i] = src_xc->regs.intRegFile[i];
233        }
234
235        // Then loop through the floating point registers.
236        for (int i = 0; i < Impl::ISA::NumFloatRegs; ++i)
237        {
238            regFile.floatRegFile[i].d = src_xc->regs.floatRegFile.d[i];
239            regFile.floatRegFile[i].q = src_xc->regs.floatRegFile.q[i];
240        }
241
242        // Then loop through the misc registers.
243        regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr;
244        regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq;
245        regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag;
246        regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr;
247
248        // Then finally set the PC and the next PC.
249        regFile.pc = src_xc->regs.pc;
250        regFile.npc = src_xc->regs.npc;
251    }
252}
253
254template <class Impl>
255void
256FullBetaCPU<Impl>::activateContext(int thread_num, int delay)
257{
258    // Needs to set each stage to running as well.
259
260    scheduleTickEvent(delay);
261
262    _status = Running;
263}
264
265template <class Impl>
266void
267FullBetaCPU<Impl>::suspendContext(int thread_num)
268{
269    panic("suspendContext unimplemented!");
270}
271
272template <class Impl>
273void
274FullBetaCPU<Impl>::deallocateContext(int thread_num)
275{
276    panic("deallocateContext unimplemented!");
277}
278
279template <class Impl>
280void
281FullBetaCPU<Impl>::haltContext(int thread_num)
282{
283    panic("haltContext unimplemented!");
284}
285
286template <class Impl>
287void
288FullBetaCPU<Impl>::switchOut()
289{
290    panic("FullBetaCPU does not have a switch out function.\n");
291}
292
293template <class Impl>
294void
295FullBetaCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
296{
297    BaseCPU::takeOverFrom(oldCPU);
298
299    assert(!tickEvent.scheduled());
300
301    // Set all status's to active, schedule the
302    // CPU's tick event.
303    for (int i = 0; i < execContexts.size(); ++i) {
304        ExecContext *xc = execContexts[i];
305        if (xc->status() == ExecContext::Active && _status != Running) {
306            _status = Running;
307            tickEvent.schedule(curTick);
308        }
309    }
310}
311
312template <class Impl>
313InstSeqNum
314FullBetaCPU<Impl>::getAndIncrementInstSeq()
315{
316    // Hopefully this works right.
317    return globalSeqNum++;
318}
319
320template <class Impl>
321uint64_t
322FullBetaCPU<Impl>::readIntReg(int reg_idx)
323{
324    return regFile.readIntReg(reg_idx);
325}
326
327template <class Impl>
328float
329FullBetaCPU<Impl>::readFloatRegSingle(int reg_idx)
330{
331    return regFile.readFloatRegSingle(reg_idx);
332}
333
334template <class Impl>
335double
336FullBetaCPU<Impl>::readFloatRegDouble(int reg_idx)
337{
338    return regFile.readFloatRegDouble(reg_idx);
339}
340
341template <class Impl>
342uint64_t
343FullBetaCPU<Impl>::readFloatRegInt(int reg_idx)
344{
345    return regFile.readFloatRegInt(reg_idx);
346}
347
348template <class Impl>
349void
350FullBetaCPU<Impl>::setIntReg(int reg_idx, uint64_t val)
351{
352    regFile.setIntReg(reg_idx, val);
353}
354
355template <class Impl>
356void
357FullBetaCPU<Impl>::setFloatRegSingle(int reg_idx, float val)
358{
359    regFile.setFloatRegSingle(reg_idx, val);
360}
361
362template <class Impl>
363void
364FullBetaCPU<Impl>::setFloatRegDouble(int reg_idx, double val)
365{
366    regFile.setFloatRegDouble(reg_idx, val);
367}
368
369template <class Impl>
370void
371FullBetaCPU<Impl>::setFloatRegInt(int reg_idx, uint64_t val)
372{
373    regFile.setFloatRegInt(reg_idx, val);
374}
375
376template <class Impl>
377uint64_t
378FullBetaCPU<Impl>::readPC()
379{
380    return regFile.readPC();
381}
382
383template <class Impl>
384void
385FullBetaCPU<Impl>::setNextPC(uint64_t val)
386{
387    regFile.setNextPC(val);
388}
389
390template <class Impl>
391void
392FullBetaCPU<Impl>::setPC(Addr new_PC)
393{
394    regFile.setPC(new_PC);
395}
396
397template <class Impl>
398void
399FullBetaCPU<Impl>::addInst(DynInstPtr &inst)
400{
401    instList.push_back(inst);
402}
403
404template <class Impl>
405void
406FullBetaCPU<Impl>::instDone()
407{
408    // Keep an instruction count.
409    numInsts++;
410
411    // Check for instruction-count-based events.
412    comInstEventQueue[0]->serviceEvents(numInsts);
413}
414
415template <class Impl>
416void
417FullBetaCPU<Impl>::removeBackInst(DynInstPtr &inst)
418{
419    DynInstPtr inst_to_delete;
420
421    // Walk through the instruction list, removing any instructions
422    // that were inserted after the given instruction, inst.
423    while (instList.back() != inst)
424    {
425        assert(!instList.empty());
426
427        // Obtain the pointer to the instruction.
428        inst_to_delete = instList.back();
429
430        DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
431                inst_to_delete->seqNum, inst_to_delete->readPC());
432
433        // Remove the instruction from the list.
434        instList.pop_back();
435
436        // Mark it as squashed.
437        inst_to_delete->setSquashed();
438    }
439}
440
441template <class Impl>
442void
443FullBetaCPU<Impl>::removeFrontInst(DynInstPtr &inst)
444{
445    DynInstPtr inst_to_remove;
446
447    // The front instruction should be the same one being asked to be removed.
448    assert(instList.front() == inst);
449
450    // Remove the front instruction.
451    inst_to_remove = inst;
452    instList.pop_front();
453
454    DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n",
455            inst_to_remove, inst_to_remove->readPC());
456}
457
458template <class Impl>
459void
460FullBetaCPU<Impl>::removeInstsNotInROB()
461{
462    DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
463            "list.\n");
464
465    DynInstPtr rob_tail = rob.readTailInst();
466
467    removeBackInst(rob_tail);
468}
469
470template <class Impl>
471void
472FullBetaCPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num)
473{
474    DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
475            "list.\n");
476
477    DynInstPtr inst_to_delete;
478
479    while (instList.back()->seqNum > seq_num) {
480        assert(!instList.empty());
481
482        // Obtain the pointer to the instruction.
483        inst_to_delete = instList.back();
484
485        DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
486                inst_to_delete->seqNum, inst_to_delete->readPC());
487
488        // Remove the instruction from the list.
489        instList.back() = NULL;
490        instList.pop_back();
491
492        // Mark it as squashed.
493        inst_to_delete->setSquashed();
494    }
495
496}
497
498template <class Impl>
499void
500FullBetaCPU<Impl>::removeAllInsts()
501{
502    instList.clear();
503}
504
505template <class Impl>
506void
507FullBetaCPU<Impl>::dumpInsts()
508{
509    int num = 0;
510    typename list<DynInstPtr>::iterator inst_list_it = instList.begin();
511
512    while (inst_list_it != instList.end())
513    {
514        cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n",
515                num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum,
516                (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed());
517        inst_list_it++;
518        ++num;
519    }
520}
521
522template <class Impl>
523void
524FullBetaCPU<Impl>::wakeDependents(DynInstPtr &inst)
525{
526    iew.wakeDependents(inst);
527}
528
529// Forward declaration of FullBetaCPU.
530template class FullBetaCPU<AlphaSimpleImpl>;
531
532#endif // __SIMPLE_FULL_CPU_HH__
533