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