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