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