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