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