cpu.cc revision 1696
12SN/A/*
21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292SN/A#ifdef FULL_SYSTEM
302SN/A#include "sim/system.hh"
3111793Sbrandon.potter@amd.com#else
3211793Sbrandon.potter@amd.com#include "sim/process.hh"
332SN/A#endif
342SN/A#include "sim/root.hh"
352SN/A
362SN/A#include "cpu/beta_cpu/alpha_dyn_inst.hh"
372SN/A#include "cpu/beta_cpu/alpha_impl.hh"
381380SN/A#include "cpu/beta_cpu/full_cpu.hh"
391380SN/A#include "cpu/exec_context.hh"
401380SN/A
411380SN/Ausing namespace std;
421380SN/A
431380SN/ABaseFullCPU::BaseFullCPU(Params &params)
441380SN/A    : BaseCPU(&params), cpu_id(0)
451380SN/A{
461380SN/A}
471380SN/A
481380SN/Atemplate <class Impl>
491380SN/AFullBetaCPU<Impl>::TickEvent::TickEvent(FullBetaCPU<Impl> *c)
501380SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
511380SN/A{
521380SN/A}
531380SN/A
541380SN/Atemplate <class Impl>
551380SN/Avoid
561380SN/AFullBetaCPU<Impl>::TickEvent::process()
571380SN/A{
581380SN/A    cpu->tick();
591380SN/A}
601380SN/A
611380SN/Atemplate <class Impl>
621380SN/Aconst char *
631380SN/AFullBetaCPU<Impl>::TickEvent::description()
641380SN/A{
651380SN/A    return "FullBetaCPU tick event";
661380SN/A}
671380SN/A
682SN/A//Call constructor to all the pipeline stages here
692SN/Atemplate <class Impl>
702SN/AFullBetaCPU<Impl>::FullBetaCPU(Params &params)
712SN/A#ifdef FULL_SYSTEM
722SN/A    : BaseFullCPU(params),
732SN/A#else
741793SN/A    : BaseFullCPU(params),
751793SN/A#endif // FULL_SYSTEM
762SN/A      tickEvent(this),
771793SN/A      fetch(params),
781793SN/A      decode(params),
791793SN/A      rename(params),
801793SN/A      iew(params),
811793SN/A      commit(params),
821793SN/A
831793SN/A      regFile(params.numPhysIntRegs, params.numPhysFloatRegs),
841793SN/A
852SN/A      freeList(Impl::ISA::NumIntRegs, params.numPhysIntRegs,
862SN/A               Impl::ISA::NumFloatRegs, params.numPhysFloatRegs),
872SN/A
882SN/A      renameMap(Impl::ISA::NumIntRegs, params.numPhysIntRegs,
892SN/A                Impl::ISA::NumFloatRegs, params.numPhysFloatRegs,
902SN/A                Impl::ISA::NumMiscRegs,
912SN/A                Impl::ISA::ZeroReg,
922SN/A                Impl::ISA::ZeroReg + Impl::ISA::NumIntRegs),
932SN/A
942SN/A      rob(params.numROBEntries, params.squashWidth),
952SN/A
962SN/A      // What to pass to these time buffers?
972SN/A      // For now just have these time buffers be pretty big.
982SN/A      timeBuffer(5, 5),
992SN/A      fetchQueue(5, 5),
1002SN/A      decodeQueue(5, 5),
1012SN/A      renameQueue(5, 5),
1022SN/A      iewQueue(5, 5),
1032SN/A
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