cpu.cc revision 2632:1bb2f91485ea
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.setRegBits(i, src_xc->readRegBits(i))
262        }
263/*
264        // Then loop through the misc registers.
265        regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr;
266        regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq;
267        regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag;
268        regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr;
269*/
270        // Then finally set the PC and the next PC.
271        regFile.pc = src_xc->readPC();
272        regFile.npc = src_xc->readNextPC();
273    }
274}
275
276template <class Impl>
277void
278FullO3CPU<Impl>::activateContext(int thread_num, int delay)
279{
280    // Needs to set each stage to running as well.
281
282    scheduleTickEvent(delay);
283
284    _status = Running;
285}
286
287template <class Impl>
288void
289FullO3CPU<Impl>::suspendContext(int thread_num)
290{
291    panic("suspendContext unimplemented!");
292}
293
294template <class Impl>
295void
296FullO3CPU<Impl>::deallocateContext(int thread_num)
297{
298    panic("deallocateContext unimplemented!");
299}
300
301template <class Impl>
302void
303FullO3CPU<Impl>::haltContext(int thread_num)
304{
305    panic("haltContext unimplemented!");
306}
307
308template <class Impl>
309void
310FullO3CPU<Impl>::switchOut()
311{
312    panic("FullO3CPU does not have a switch out function.\n");
313}
314
315template <class Impl>
316void
317FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
318{
319    BaseCPU::takeOverFrom(oldCPU);
320
321    assert(!tickEvent.scheduled());
322
323    // Set all status's to active, schedule the
324    // CPU's tick event.
325    for (int i = 0; i < execContexts.size(); ++i) {
326        ExecContext *xc = execContexts[i];
327        if (xc->status() == ExecContext::Active && _status != Running) {
328            _status = Running;
329            tickEvent.schedule(curTick);
330        }
331    }
332}
333
334template <class Impl>
335InstSeqNum
336FullO3CPU<Impl>::getAndIncrementInstSeq()
337{
338    // Hopefully this works right.
339    return globalSeqNum++;
340}
341
342template <class Impl>
343uint64_t
344FullO3CPU<Impl>::readIntReg(int reg_idx)
345{
346    return regFile.readIntReg(reg_idx);
347}
348
349template <class Impl>
350FloatReg
351FullO3CPU<Impl>::readFloatReg(int reg_idx, int width)
352{
353    return regFile.readFloatReg(reg_idx, width);
354}
355
356template <class Impl>
357FloatReg
358FullO3CPU<Impl>::readFloatReg(int reg_idx)
359{
360    return regFile.readFloatReg(reg_idx);
361}
362
363template <class Impl>
364FloatRegBits
365FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width)
366{
367    return regFile.readFloatRegBits(reg_idx, width);
368}
369
370template <class Impl>
371FloatRegBits
372FullO3CPU<Impl>::readFloatRegBits(int reg_idx)
373{
374    return regFile.readFloatRegBits(reg_idx);
375}
376
377template <class Impl>
378void
379FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val)
380{
381    regFile.setIntReg(reg_idx, val);
382}
383
384template <class Impl>
385void
386FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width)
387{
388    regFile.setFloatReg(reg_idx, val, width);
389}
390
391template <class Impl>
392void
393FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val)
394{
395    regFile.setFloatReg(reg_idx, val);
396}
397
398template <class Impl>
399void
400FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width)
401{
402    regFile.setFloatRegBits(reg_idx, val, width);
403}
404
405template <class Impl>
406void
407FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
408{
409    regFile.setFloatRegBits(reg_idx, val);
410}
411
412template <class Impl>
413uint64_t
414FullO3CPU<Impl>::readPC()
415{
416    return regFile.readPC();
417}
418
419template <class Impl>
420void
421FullO3CPU<Impl>::setNextPC(uint64_t val)
422{
423    regFile.setNextPC(val);
424}
425
426template <class Impl>
427void
428FullO3CPU<Impl>::setPC(Addr new_PC)
429{
430    regFile.setPC(new_PC);
431}
432
433template <class Impl>
434void
435FullO3CPU<Impl>::addInst(DynInstPtr &inst)
436{
437    instList.push_back(inst);
438}
439
440template <class Impl>
441void
442FullO3CPU<Impl>::instDone()
443{
444    // Keep an instruction count.
445    numInsts++;
446
447    // Check for instruction-count-based events.
448    comInstEventQueue[0]->serviceEvents(numInsts);
449}
450
451template <class Impl>
452void
453FullO3CPU<Impl>::removeBackInst(DynInstPtr &inst)
454{
455    DynInstPtr inst_to_delete;
456
457    // Walk through the instruction list, removing any instructions
458    // that were inserted after the given instruction, inst.
459    while (instList.back() != inst)
460    {
461        assert(!instList.empty());
462
463        // Obtain the pointer to the instruction.
464        inst_to_delete = instList.back();
465
466        DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
467                inst_to_delete->seqNum, inst_to_delete->readPC());
468
469        // Remove the instruction from the list.
470        instList.pop_back();
471
472        // Mark it as squashed.
473        inst_to_delete->setSquashed();
474    }
475}
476
477template <class Impl>
478void
479FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
480{
481    DynInstPtr inst_to_remove;
482
483    // The front instruction should be the same one being asked to be removed.
484    assert(instList.front() == inst);
485
486    // Remove the front instruction.
487    inst_to_remove = inst;
488    instList.pop_front();
489
490    DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n",
491            inst_to_remove, inst_to_remove->readPC());
492}
493
494template <class Impl>
495void
496FullO3CPU<Impl>::removeInstsNotInROB()
497{
498    DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
499            "list.\n");
500
501    DynInstPtr rob_tail = rob.readTailInst();
502
503    removeBackInst(rob_tail);
504}
505
506template <class Impl>
507void
508FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num)
509{
510    DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
511            "list.\n");
512
513    DynInstPtr inst_to_delete;
514
515    while (instList.back()->seqNum > seq_num) {
516        assert(!instList.empty());
517
518        // Obtain the pointer to the instruction.
519        inst_to_delete = instList.back();
520
521        DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
522                inst_to_delete->seqNum, inst_to_delete->readPC());
523
524        // Remove the instruction from the list.
525        instList.back() = NULL;
526        instList.pop_back();
527
528        // Mark it as squashed.
529        inst_to_delete->setSquashed();
530    }
531
532}
533
534template <class Impl>
535void
536FullO3CPU<Impl>::removeAllInsts()
537{
538    instList.clear();
539}
540
541template <class Impl>
542void
543FullO3CPU<Impl>::dumpInsts()
544{
545    int num = 0;
546    typename list<DynInstPtr>::iterator inst_list_it = instList.begin();
547
548    while (inst_list_it != instList.end())
549    {
550        cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n",
551                num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum,
552                (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed());
553        inst_list_it++;
554        ++num;
555    }
556}
557
558template <class Impl>
559void
560FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
561{
562    iew.wakeDependents(inst);
563}
564
565// Forward declaration of FullO3CPU.
566template class FullO3CPU<AlphaSimpleImpl>;
567