cpu.cc (7507:b1ac6773e83d) cpu.cc (7678:f19b6a3a8cec)
1/*
2 * Copyright (c) 2004-2006 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 * Authors: Kevin Lim
29 * Korey Sewell
30 */
31
32#include "config/full_system.hh"
33#include "config/the_isa.hh"
34#include "config/use_checker.hh"
35#include "cpu/activity.hh"
36#include "cpu/simple_thread.hh"
37#include "cpu/thread_context.hh"
38#include "cpu/o3/isa_specific.hh"
39#include "cpu/o3/cpu.hh"
40#include "cpu/o3/thread_context.hh"
41#include "enums/MemoryMode.hh"
42#include "sim/core.hh"
43#include "sim/stat_control.hh"
44
45#if FULL_SYSTEM
46#include "cpu/quiesce_event.hh"
47#include "sim/system.hh"
48#else
49#include "sim/process.hh"
50#endif
51
52#if USE_CHECKER
53#include "cpu/checker/cpu.hh"
54#endif
55
56#if THE_ISA == ALPHA_ISA
57#include "arch/alpha/osfpal.hh"
58#endif
59
60class BaseCPUParams;
61
62using namespace TheISA;
63using namespace std;
64
65BaseO3CPU::BaseO3CPU(BaseCPUParams *params)
66 : BaseCPU(params)
67{
68}
69
70void
71BaseO3CPU::regStats()
72{
73 BaseCPU::regStats();
74}
75
76template <class Impl>
77FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
78 : Event(CPU_Tick_Pri), cpu(c)
79{
80}
81
82template <class Impl>
83void
84FullO3CPU<Impl>::TickEvent::process()
85{
86 cpu->tick();
87}
88
89template <class Impl>
90const char *
91FullO3CPU<Impl>::TickEvent::description() const
92{
93 return "FullO3CPU tick";
94}
95
96template <class Impl>
97FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent()
98 : Event(CPU_Switch_Pri)
99{
100}
101
102template <class Impl>
103void
104FullO3CPU<Impl>::ActivateThreadEvent::init(int thread_num,
105 FullO3CPU<Impl> *thread_cpu)
106{
107 tid = thread_num;
108 cpu = thread_cpu;
109}
110
111template <class Impl>
112void
113FullO3CPU<Impl>::ActivateThreadEvent::process()
114{
115 cpu->activateThread(tid);
116}
117
118template <class Impl>
119const char *
120FullO3CPU<Impl>::ActivateThreadEvent::description() const
121{
122 return "FullO3CPU \"Activate Thread\"";
123}
124
125template <class Impl>
126FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent()
127 : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL)
128{
129}
130
131template <class Impl>
132void
133FullO3CPU<Impl>::DeallocateContextEvent::init(int thread_num,
134 FullO3CPU<Impl> *thread_cpu)
135{
136 tid = thread_num;
137 cpu = thread_cpu;
138 remove = false;
139}
140
141template <class Impl>
142void
143FullO3CPU<Impl>::DeallocateContextEvent::process()
144{
145 cpu->deactivateThread(tid);
146 if (remove)
147 cpu->removeThread(tid);
148}
149
150template <class Impl>
151const char *
152FullO3CPU<Impl>::DeallocateContextEvent::description() const
153{
154 return "FullO3CPU \"Deallocate Context\"";
155}
156
157template <class Impl>
158FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
159 : BaseO3CPU(params),
160 itb(params->itb),
161 dtb(params->dtb),
162 tickEvent(this),
163#ifndef NDEBUG
164 instcount(0),
165#endif
166 removeInstsThisCycle(false),
167 fetch(this, params),
168 decode(this, params),
169 rename(this, params),
170 iew(this, params),
171 commit(this, params),
172
173 regFile(this, params->numPhysIntRegs,
174 params->numPhysFloatRegs),
175
176 freeList(params->numThreads,
177 TheISA::NumIntRegs, params->numPhysIntRegs,
178 TheISA::NumFloatRegs, params->numPhysFloatRegs),
179
180 rob(this,
181 params->numROBEntries, params->squashWidth,
182 params->smtROBPolicy, params->smtROBThreshold,
183 params->numThreads),
184
185 scoreboard(params->numThreads,
186 TheISA::NumIntRegs, params->numPhysIntRegs,
187 TheISA::NumFloatRegs, params->numPhysFloatRegs,
188 TheISA::NumMiscRegs * numThreads,
189 TheISA::ZeroReg),
190
191 timeBuffer(params->backComSize, params->forwardComSize),
192 fetchQueue(params->backComSize, params->forwardComSize),
193 decodeQueue(params->backComSize, params->forwardComSize),
194 renameQueue(params->backComSize, params->forwardComSize),
195 iewQueue(params->backComSize, params->forwardComSize),
196 activityRec(name(), NumStages,
197 params->backComSize + params->forwardComSize,
198 params->activity),
199
200 globalSeqNum(1),
201#if FULL_SYSTEM
202 system(params->system),
203#endif // FULL_SYSTEM
204 drainCount(0),
205 deferRegistration(params->defer_registration)
206{
207 if (!deferRegistration) {
208 _status = Running;
209 } else {
210 _status = Idle;
211 }
212
213#if USE_CHECKER
214 if (params->checker) {
215 BaseCPU *temp_checker = params->checker;
216 checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
217#if FULL_SYSTEM
218 checker->setSystem(params->system);
219#endif
220 } else {
221 checker = NULL;
222 }
223#endif // USE_CHECKER
224
225#if !FULL_SYSTEM
226 thread.resize(numThreads);
227 tids.resize(numThreads);
228#endif
229
230 // The stages also need their CPU pointer setup. However this
231 // must be done at the upper level CPU because they have pointers
232 // to the upper level CPU, and not this FullO3CPU.
233
234 // Set up Pointers to the activeThreads list for each stage
235 fetch.setActiveThreads(&activeThreads);
236 decode.setActiveThreads(&activeThreads);
237 rename.setActiveThreads(&activeThreads);
238 iew.setActiveThreads(&activeThreads);
239 commit.setActiveThreads(&activeThreads);
240
241 // Give each of the stages the time buffer they will use.
242 fetch.setTimeBuffer(&timeBuffer);
243 decode.setTimeBuffer(&timeBuffer);
244 rename.setTimeBuffer(&timeBuffer);
245 iew.setTimeBuffer(&timeBuffer);
246 commit.setTimeBuffer(&timeBuffer);
247
248 // Also setup each of the stages' queues.
249 fetch.setFetchQueue(&fetchQueue);
250 decode.setFetchQueue(&fetchQueue);
251 commit.setFetchQueue(&fetchQueue);
252 decode.setDecodeQueue(&decodeQueue);
253 rename.setDecodeQueue(&decodeQueue);
254 rename.setRenameQueue(&renameQueue);
255 iew.setRenameQueue(&renameQueue);
256 iew.setIEWQueue(&iewQueue);
257 commit.setIEWQueue(&iewQueue);
258 commit.setRenameQueue(&renameQueue);
259
260 commit.setIEWStage(&iew);
261 rename.setIEWStage(&iew);
262 rename.setCommitStage(&commit);
263
264#if !FULL_SYSTEM
265 ThreadID active_threads = params->workload.size();
266
267 if (active_threads > Impl::MaxThreads) {
268 panic("Workload Size too large. Increase the 'MaxThreads'"
269 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or "
270 "edit your workload size.");
271 }
272#else
273 ThreadID active_threads = 1;
274#endif
275
276 //Make Sure That this a Valid Architeture
277 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs);
278 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs);
279
280 rename.setScoreboard(&scoreboard);
281 iew.setScoreboard(&scoreboard);
282
283 // Setup the rename map for whichever stages need it.
284 PhysRegIndex lreg_idx = 0;
285 PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs
286
287 for (ThreadID tid = 0; tid < numThreads; tid++) {
288 bool bindRegs = (tid <= active_threads - 1);
289
290 commitRenameMap[tid].init(TheISA::NumIntRegs,
291 params->numPhysIntRegs,
292 lreg_idx, //Index for Logical. Regs
293
294 TheISA::NumFloatRegs,
295 params->numPhysFloatRegs,
296 freg_idx, //Index for Float Regs
297
298 TheISA::NumMiscRegs,
299
300 TheISA::ZeroReg,
301 TheISA::ZeroReg,
302
303 tid,
304 false);
305
306 renameMap[tid].init(TheISA::NumIntRegs,
307 params->numPhysIntRegs,
308 lreg_idx, //Index for Logical. Regs
309
310 TheISA::NumFloatRegs,
311 params->numPhysFloatRegs,
312 freg_idx, //Index for Float Regs
313
314 TheISA::NumMiscRegs,
315
316 TheISA::ZeroReg,
317 TheISA::ZeroReg,
318
319 tid,
320 bindRegs);
321
322 activateThreadEvent[tid].init(tid, this);
323 deallocateContextEvent[tid].init(tid, this);
324 }
325
326 rename.setRenameMap(renameMap);
327 commit.setRenameMap(commitRenameMap);
328
329 // Give renameMap & rename stage access to the freeList;
330 for (ThreadID tid = 0; tid < numThreads; tid++)
331 renameMap[tid].setFreeList(&freeList);
332 rename.setFreeList(&freeList);
333
334 // Setup the ROB for whichever stages need it.
335 commit.setROB(&rob);
336
337 lastRunningCycle = curTick;
338
339 lastActivatedCycle = -1;
340#if 0
341 // Give renameMap & rename stage access to the freeList;
342 for (ThreadID tid = 0; tid < numThreads; tid++)
343 globalSeqNum[tid] = 1;
344#endif
345
346 contextSwitch = false;
347 DPRINTF(O3CPU, "Creating O3CPU object.\n");
348
349 // Setup any thread state.
350 this->thread.resize(this->numThreads);
351
352 for (ThreadID tid = 0; tid < this->numThreads; ++tid) {
353#if FULL_SYSTEM
354 // SMT is not supported in FS mode yet.
355 assert(this->numThreads == 1);
356 this->thread[tid] = new Thread(this, 0);
357#else
358 if (tid < params->workload.size()) {
359 DPRINTF(O3CPU, "Workload[%i] process is %#x",
360 tid, this->thread[tid]);
361 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
362 (typename Impl::O3CPU *)(this),
363 tid, params->workload[tid]);
364
365 //usedTids[tid] = true;
366 //threadMap[tid] = tid;
367 } else {
368 //Allocate Empty thread so M5 can use later
369 //when scheduling threads to CPU
370 Process* dummy_proc = NULL;
371
372 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
373 (typename Impl::O3CPU *)(this),
374 tid, dummy_proc);
375 //usedTids[tid] = false;
376 }
377#endif // !FULL_SYSTEM
378
379 ThreadContext *tc;
380
381 // Setup the TC that will serve as the interface to the threads/CPU.
382 O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
383
384 tc = o3_tc;
385
386 // If we're using a checker, then the TC should be the
387 // CheckerThreadContext.
388#if USE_CHECKER
389 if (params->checker) {
390 tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
391 o3_tc, this->checker);
392 }
393#endif
394
395 o3_tc->cpu = (typename Impl::O3CPU *)(this);
396 assert(o3_tc->cpu);
397 o3_tc->thread = this->thread[tid];
398
399#if FULL_SYSTEM
400 // Setup quiesce event.
401 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc);
402#endif
403 // Give the thread the TC.
404 this->thread[tid]->tc = tc;
405
406 // Add the TC to the CPU's list of TC's.
407 this->threadContexts.push_back(tc);
408 }
409
410 for (ThreadID tid = 0; tid < this->numThreads; tid++)
411 this->thread[tid]->setFuncExeInst(0);
412
413 lockAddr = 0;
414 lockFlag = false;
415}
416
417template <class Impl>
418FullO3CPU<Impl>::~FullO3CPU()
419{
420}
421
422template <class Impl>
423void
424FullO3CPU<Impl>::regStats()
425{
426 BaseO3CPU::regStats();
427
428 // Register any of the O3CPU's stats here.
429 timesIdled
430 .name(name() + ".timesIdled")
431 .desc("Number of times that the entire CPU went into an idle state and"
432 " unscheduled itself")
433 .prereq(timesIdled);
434
435 idleCycles
436 .name(name() + ".idleCycles")
437 .desc("Total number of cycles that the CPU has spent unscheduled due "
438 "to idling")
439 .prereq(idleCycles);
440
441 // Number of Instructions simulated
442 // --------------------------------
443 // Should probably be in Base CPU but need templated
444 // MaxThreads so put in here instead
445 committedInsts
446 .init(numThreads)
447 .name(name() + ".committedInsts")
448 .desc("Number of Instructions Simulated");
449
450 totalCommittedInsts
451 .name(name() + ".committedInsts_total")
452 .desc("Number of Instructions Simulated");
453
454 cpi
455 .name(name() + ".cpi")
456 .desc("CPI: Cycles Per Instruction")
457 .precision(6);
458 cpi = numCycles / committedInsts;
459
460 totalCpi
461 .name(name() + ".cpi_total")
462 .desc("CPI: Total CPI of All Threads")
463 .precision(6);
464 totalCpi = numCycles / totalCommittedInsts;
465
466 ipc
467 .name(name() + ".ipc")
468 .desc("IPC: Instructions Per Cycle")
469 .precision(6);
470 ipc = committedInsts / numCycles;
471
472 totalIpc
473 .name(name() + ".ipc_total")
474 .desc("IPC: Total IPC of All Threads")
475 .precision(6);
476 totalIpc = totalCommittedInsts / numCycles;
477
478 this->fetch.regStats();
479 this->decode.regStats();
480 this->rename.regStats();
481 this->iew.regStats();
482 this->commit.regStats();
483}
484
485template <class Impl>
486Port *
487FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
488{
489 if (if_name == "dcache_port")
490 return iew.getDcachePort();
491 else if (if_name == "icache_port")
492 return fetch.getIcachePort();
493 else
494 panic("No Such Port\n");
495}
496
497template <class Impl>
498void
499FullO3CPU<Impl>::tick()
500{
501 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
502
503 ++numCycles;
504
505// activity = false;
506
507 //Tick each of the stages
508 fetch.tick();
509
510 decode.tick();
511
512 rename.tick();
513
514 iew.tick();
515
516 commit.tick();
517
518#if !FULL_SYSTEM
519 doContextSwitch();
520#endif
521
522 // Now advance the time buffers
523 timeBuffer.advance();
524
525 fetchQueue.advance();
526 decodeQueue.advance();
527 renameQueue.advance();
528 iewQueue.advance();
529
530 activityRec.advance();
531
532 if (removeInstsThisCycle) {
533 cleanUpRemovedInsts();
534 }
535
536 if (!tickEvent.scheduled()) {
537 if (_status == SwitchedOut ||
538 getState() == SimObject::Drained) {
539 DPRINTF(O3CPU, "Switched out!\n");
540 // increment stat
541 lastRunningCycle = curTick;
542 } else if (!activityRec.active() || _status == Idle) {
543 DPRINTF(O3CPU, "Idle!\n");
544 lastRunningCycle = curTick;
545 timesIdled++;
546 } else {
547 schedule(tickEvent, nextCycle(curTick + ticks(1)));
548 DPRINTF(O3CPU, "Scheduling next tick!\n");
549 }
550 }
551
552#if !FULL_SYSTEM
553 updateThreadPriority();
554#endif
555}
556
557template <class Impl>
558void
559FullO3CPU<Impl>::init()
560{
561 BaseCPU::init();
562
563 // Set inSyscall so that the CPU doesn't squash when initially
564 // setting up registers.
565 for (ThreadID tid = 0; tid < numThreads; ++tid)
566 thread[tid]->inSyscall = true;
567
568#if FULL_SYSTEM
569 for (ThreadID tid = 0; tid < numThreads; tid++) {
570 ThreadContext *src_tc = threadContexts[tid];
571 TheISA::initCPU(src_tc, src_tc->contextId());
572 }
573#endif
574
575 // Clear inSyscall.
576 for (int tid = 0; tid < numThreads; ++tid)
577 thread[tid]->inSyscall = false;
578
579 // Initialize stages.
580 fetch.initStage();
581 iew.initStage();
582 rename.initStage();
583 commit.initStage();
584
585 commit.setThreads(thread);
586}
587
588template <class Impl>
589void
590FullO3CPU<Impl>::activateThread(ThreadID tid)
591{
592 list<ThreadID>::iterator isActive =
593 std::find(activeThreads.begin(), activeThreads.end(), tid);
594
595 DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);
596
597 if (isActive == activeThreads.end()) {
598 DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
599 tid);
600
601 activeThreads.push_back(tid);
602 }
603}
604
605template <class Impl>
606void
607FullO3CPU<Impl>::deactivateThread(ThreadID tid)
608{
609 //Remove From Active List, if Active
610 list<ThreadID>::iterator thread_it =
611 std::find(activeThreads.begin(), activeThreads.end(), tid);
612
613 DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);
614
615 if (thread_it != activeThreads.end()) {
616 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
617 tid);
618 activeThreads.erase(thread_it);
619 }
620}
621
622template <class Impl>
623Counter
624FullO3CPU<Impl>::totalInstructions() const
625{
626 Counter total(0);
627
628 ThreadID size = thread.size();
629 for (ThreadID i = 0; i < size; i++)
630 total += thread[i]->numInst;
631
632 return total;
633}
634
635template <class Impl>
636void
637FullO3CPU<Impl>::activateContext(ThreadID tid, int delay)
638{
639 // Needs to set each stage to running as well.
640 if (delay){
641 DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
642 "on cycle %d\n", tid, curTick + ticks(delay));
643 scheduleActivateThreadEvent(tid, delay);
644 } else {
645 activateThread(tid);
646 }
647
648 if (lastActivatedCycle < curTick) {
649 scheduleTickEvent(delay);
650
651 // Be sure to signal that there's some activity so the CPU doesn't
652 // deschedule itself.
653 activityRec.activity();
654 fetch.wakeFromQuiesce();
655
656 lastActivatedCycle = curTick;
657
658 _status = Running;
659 }
660}
661
662template <class Impl>
663bool
664FullO3CPU<Impl>::deallocateContext(ThreadID tid, bool remove, int delay)
665{
666 // Schedule removal of thread data from CPU
667 if (delay){
668 DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate "
669 "on cycle %d\n", tid, curTick + ticks(delay));
670 scheduleDeallocateContextEvent(tid, remove, delay);
671 return false;
672 } else {
673 deactivateThread(tid);
674 if (remove)
675 removeThread(tid);
676 return true;
677 }
678}
679
680template <class Impl>
681void
682FullO3CPU<Impl>::suspendContext(ThreadID tid)
683{
684 DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
685 bool deallocated = deallocateContext(tid, false, 1);
686 // If this was the last thread then unschedule the tick event.
687 if ((activeThreads.size() == 1 && !deallocated) ||
688 activeThreads.size() == 0)
689 unscheduleTickEvent();
690 _status = Idle;
691}
692
693template <class Impl>
694void
695FullO3CPU<Impl>::haltContext(ThreadID tid)
696{
697 //For now, this is the same as deallocate
698 DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
699 deallocateContext(tid, true, 1);
700}
701
702template <class Impl>
703void
704FullO3CPU<Impl>::insertThread(ThreadID tid)
705{
706 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
707 // Will change now that the PC and thread state is internal to the CPU
708 // and not in the ThreadContext.
709#if FULL_SYSTEM
710 ThreadContext *src_tc = system->threadContexts[tid];
711#else
712 ThreadContext *src_tc = tcBase(tid);
713#endif
714
715 //Bind Int Regs to Rename Map
716 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
717 PhysRegIndex phys_reg = freeList.getIntReg();
718
719 renameMap[tid].setEntry(ireg,phys_reg);
720 scoreboard.setReg(phys_reg);
721 }
722
723 //Bind Float Regs to Rename Map
724 for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {
725 PhysRegIndex phys_reg = freeList.getFloatReg();
726
727 renameMap[tid].setEntry(freg,phys_reg);
728 scoreboard.setReg(phys_reg);
729 }
730
731 //Copy Thread Data Into RegFile
732 //this->copyFromTC(tid);
733
734 //Set PC/NPC/NNPC
735 setPC(src_tc->readPC(), tid);
736 setNextPC(src_tc->readNextPC(), tid);
737 setNextNPC(src_tc->readNextNPC(), tid);
738
739 src_tc->setStatus(ThreadContext::Active);
740
741 activateContext(tid,1);
742
743 //Reset ROB/IQ/LSQ Entries
744 commit.rob->resetEntries();
745 iew.resetEntries();
746}
747
748template <class Impl>
749void
750FullO3CPU<Impl>::removeThread(ThreadID tid)
751{
752 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);
753
754 // Copy Thread Data From RegFile
755 // If thread is suspended, it might be re-allocated
756 // this->copyToTC(tid);
757
758
759 // @todo: 2-27-2008: Fix how we free up rename mappings
760 // here to alleviate the case for double-freeing registers
761 // in SMT workloads.
762
763 // Unbind Int Regs from Rename Map
764 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
765 PhysRegIndex phys_reg = renameMap[tid].lookup(ireg);
766
767 scoreboard.unsetReg(phys_reg);
768 freeList.addReg(phys_reg);
769 }
770
771 // Unbind Float Regs from Rename Map
772 for (int freg = TheISA::NumIntRegs; freg < TheISA::NumFloatRegs; freg++) {
773 PhysRegIndex phys_reg = renameMap[tid].lookup(freg);
774
775 scoreboard.unsetReg(phys_reg);
776 freeList.addReg(phys_reg);
777 }
778
779 // Squash Throughout Pipeline
780 InstSeqNum squash_seq_num = commit.rob->readHeadInst(tid)->seqNum;
781 fetch.squash(0, sizeof(TheISA::MachInst), 0, squash_seq_num, tid);
782 decode.squash(tid);
783 rename.squash(squash_seq_num, tid);
784 iew.squash(tid);
785 iew.ldstQueue.squash(squash_seq_num, tid);
786 commit.rob->squash(squash_seq_num, tid);
787
788
789 assert(iew.instQueue.getCount(tid) == 0);
790 assert(iew.ldstQueue.getCount(tid) == 0);
791
792 // Reset ROB/IQ/LSQ Entries
793
794 // Commented out for now. This should be possible to do by
795 // telling all the pipeline stages to drain first, and then
796 // checking until the drain completes. Once the pipeline is
797 // drained, call resetEntries(). - 10-09-06 ktlim
798/*
799 if (activeThreads.size() >= 1) {
800 commit.rob->resetEntries();
801 iew.resetEntries();
802 }
803*/
804}
805
806
807template <class Impl>
808void
809FullO3CPU<Impl>::activateWhenReady(ThreadID tid)
810{
811 DPRINTF(O3CPU,"[tid:%i]: Checking if resources are available for incoming"
812 "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
813 tid);
814
815 bool ready = true;
816
817 if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) {
818 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
819 "Phys. Int. Regs.\n",
820 tid);
821 ready = false;
822 } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) {
823 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
824 "Phys. Float. Regs.\n",
825 tid);
826 ready = false;
827 } else if (commit.rob->numFreeEntries() >=
828 commit.rob->entryAmount(activeThreads.size() + 1)) {
829 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
830 "ROB entries.\n",
831 tid);
832 ready = false;
833 } else if (iew.instQueue.numFreeEntries() >=
834 iew.instQueue.entryAmount(activeThreads.size() + 1)) {
835 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
836 "IQ entries.\n",
837 tid);
838 ready = false;
839 } else if (iew.ldstQueue.numFreeEntries() >=
840 iew.ldstQueue.entryAmount(activeThreads.size() + 1)) {
841 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
842 "LSQ entries.\n",
843 tid);
844 ready = false;
845 }
846
847 if (ready) {
848 insertThread(tid);
849
850 contextSwitch = false;
851
852 cpuWaitList.remove(tid);
853 } else {
854 suspendContext(tid);
855
856 //blocks fetch
857 contextSwitch = true;
858
859 //@todo: dont always add to waitlist
860 //do waitlist
861 cpuWaitList.push_back(tid);
862 }
863}
864
865#if FULL_SYSTEM
866template <class Impl>
867Fault
868FullO3CPU<Impl>::hwrei(ThreadID tid)
869{
870#if THE_ISA == ALPHA_ISA
871 // Need to clear the lock flag upon returning from an interrupt.
872 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
873
874 this->thread[tid]->kernelStats->hwrei();
875
876 // FIXME: XXX check for interrupts? XXX
877#endif
878 return NoFault;
879}
880
881template <class Impl>
882bool
883FullO3CPU<Impl>::simPalCheck(int palFunc, ThreadID tid)
884{
885#if THE_ISA == ALPHA_ISA
886 if (this->thread[tid]->kernelStats)
887 this->thread[tid]->kernelStats->callpal(palFunc,
888 this->threadContexts[tid]);
889
890 switch (palFunc) {
891 case PAL::halt:
892 halt();
893 if (--System::numSystemsRunning == 0)
894 exitSimLoop("all cpus halted");
895 break;
896
897 case PAL::bpt:
898 case PAL::bugchk:
899 if (this->system->breakpoint())
900 return false;
901 break;
902 }
903#endif
904 return true;
905}
906
907template <class Impl>
908Fault
909FullO3CPU<Impl>::getInterrupts()
910{
911 // Check if there are any outstanding interrupts
912 return this->interrupts->getInterrupt(this->threadContexts[0]);
913}
914
915template <class Impl>
916void
917FullO3CPU<Impl>::processInterrupts(Fault interrupt)
918{
919 // Check for interrupts here. For now can copy the code that
920 // exists within isa_fullsys_traits.hh. Also assume that thread 0
921 // is the one that handles the interrupts.
922 // @todo: Possibly consolidate the interrupt checking code.
923 // @todo: Allow other threads to handle interrupts.
924
925 assert(interrupt != NoFault);
926 this->interrupts->updateIntrInfo(this->threadContexts[0]);
927
928 DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
1/*
2 * Copyright (c) 2004-2006 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 * Authors: Kevin Lim
29 * Korey Sewell
30 */
31
32#include "config/full_system.hh"
33#include "config/the_isa.hh"
34#include "config/use_checker.hh"
35#include "cpu/activity.hh"
36#include "cpu/simple_thread.hh"
37#include "cpu/thread_context.hh"
38#include "cpu/o3/isa_specific.hh"
39#include "cpu/o3/cpu.hh"
40#include "cpu/o3/thread_context.hh"
41#include "enums/MemoryMode.hh"
42#include "sim/core.hh"
43#include "sim/stat_control.hh"
44
45#if FULL_SYSTEM
46#include "cpu/quiesce_event.hh"
47#include "sim/system.hh"
48#else
49#include "sim/process.hh"
50#endif
51
52#if USE_CHECKER
53#include "cpu/checker/cpu.hh"
54#endif
55
56#if THE_ISA == ALPHA_ISA
57#include "arch/alpha/osfpal.hh"
58#endif
59
60class BaseCPUParams;
61
62using namespace TheISA;
63using namespace std;
64
65BaseO3CPU::BaseO3CPU(BaseCPUParams *params)
66 : BaseCPU(params)
67{
68}
69
70void
71BaseO3CPU::regStats()
72{
73 BaseCPU::regStats();
74}
75
76template <class Impl>
77FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
78 : Event(CPU_Tick_Pri), cpu(c)
79{
80}
81
82template <class Impl>
83void
84FullO3CPU<Impl>::TickEvent::process()
85{
86 cpu->tick();
87}
88
89template <class Impl>
90const char *
91FullO3CPU<Impl>::TickEvent::description() const
92{
93 return "FullO3CPU tick";
94}
95
96template <class Impl>
97FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent()
98 : Event(CPU_Switch_Pri)
99{
100}
101
102template <class Impl>
103void
104FullO3CPU<Impl>::ActivateThreadEvent::init(int thread_num,
105 FullO3CPU<Impl> *thread_cpu)
106{
107 tid = thread_num;
108 cpu = thread_cpu;
109}
110
111template <class Impl>
112void
113FullO3CPU<Impl>::ActivateThreadEvent::process()
114{
115 cpu->activateThread(tid);
116}
117
118template <class Impl>
119const char *
120FullO3CPU<Impl>::ActivateThreadEvent::description() const
121{
122 return "FullO3CPU \"Activate Thread\"";
123}
124
125template <class Impl>
126FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent()
127 : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL)
128{
129}
130
131template <class Impl>
132void
133FullO3CPU<Impl>::DeallocateContextEvent::init(int thread_num,
134 FullO3CPU<Impl> *thread_cpu)
135{
136 tid = thread_num;
137 cpu = thread_cpu;
138 remove = false;
139}
140
141template <class Impl>
142void
143FullO3CPU<Impl>::DeallocateContextEvent::process()
144{
145 cpu->deactivateThread(tid);
146 if (remove)
147 cpu->removeThread(tid);
148}
149
150template <class Impl>
151const char *
152FullO3CPU<Impl>::DeallocateContextEvent::description() const
153{
154 return "FullO3CPU \"Deallocate Context\"";
155}
156
157template <class Impl>
158FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
159 : BaseO3CPU(params),
160 itb(params->itb),
161 dtb(params->dtb),
162 tickEvent(this),
163#ifndef NDEBUG
164 instcount(0),
165#endif
166 removeInstsThisCycle(false),
167 fetch(this, params),
168 decode(this, params),
169 rename(this, params),
170 iew(this, params),
171 commit(this, params),
172
173 regFile(this, params->numPhysIntRegs,
174 params->numPhysFloatRegs),
175
176 freeList(params->numThreads,
177 TheISA::NumIntRegs, params->numPhysIntRegs,
178 TheISA::NumFloatRegs, params->numPhysFloatRegs),
179
180 rob(this,
181 params->numROBEntries, params->squashWidth,
182 params->smtROBPolicy, params->smtROBThreshold,
183 params->numThreads),
184
185 scoreboard(params->numThreads,
186 TheISA::NumIntRegs, params->numPhysIntRegs,
187 TheISA::NumFloatRegs, params->numPhysFloatRegs,
188 TheISA::NumMiscRegs * numThreads,
189 TheISA::ZeroReg),
190
191 timeBuffer(params->backComSize, params->forwardComSize),
192 fetchQueue(params->backComSize, params->forwardComSize),
193 decodeQueue(params->backComSize, params->forwardComSize),
194 renameQueue(params->backComSize, params->forwardComSize),
195 iewQueue(params->backComSize, params->forwardComSize),
196 activityRec(name(), NumStages,
197 params->backComSize + params->forwardComSize,
198 params->activity),
199
200 globalSeqNum(1),
201#if FULL_SYSTEM
202 system(params->system),
203#endif // FULL_SYSTEM
204 drainCount(0),
205 deferRegistration(params->defer_registration)
206{
207 if (!deferRegistration) {
208 _status = Running;
209 } else {
210 _status = Idle;
211 }
212
213#if USE_CHECKER
214 if (params->checker) {
215 BaseCPU *temp_checker = params->checker;
216 checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
217#if FULL_SYSTEM
218 checker->setSystem(params->system);
219#endif
220 } else {
221 checker = NULL;
222 }
223#endif // USE_CHECKER
224
225#if !FULL_SYSTEM
226 thread.resize(numThreads);
227 tids.resize(numThreads);
228#endif
229
230 // The stages also need their CPU pointer setup. However this
231 // must be done at the upper level CPU because they have pointers
232 // to the upper level CPU, and not this FullO3CPU.
233
234 // Set up Pointers to the activeThreads list for each stage
235 fetch.setActiveThreads(&activeThreads);
236 decode.setActiveThreads(&activeThreads);
237 rename.setActiveThreads(&activeThreads);
238 iew.setActiveThreads(&activeThreads);
239 commit.setActiveThreads(&activeThreads);
240
241 // Give each of the stages the time buffer they will use.
242 fetch.setTimeBuffer(&timeBuffer);
243 decode.setTimeBuffer(&timeBuffer);
244 rename.setTimeBuffer(&timeBuffer);
245 iew.setTimeBuffer(&timeBuffer);
246 commit.setTimeBuffer(&timeBuffer);
247
248 // Also setup each of the stages' queues.
249 fetch.setFetchQueue(&fetchQueue);
250 decode.setFetchQueue(&fetchQueue);
251 commit.setFetchQueue(&fetchQueue);
252 decode.setDecodeQueue(&decodeQueue);
253 rename.setDecodeQueue(&decodeQueue);
254 rename.setRenameQueue(&renameQueue);
255 iew.setRenameQueue(&renameQueue);
256 iew.setIEWQueue(&iewQueue);
257 commit.setIEWQueue(&iewQueue);
258 commit.setRenameQueue(&renameQueue);
259
260 commit.setIEWStage(&iew);
261 rename.setIEWStage(&iew);
262 rename.setCommitStage(&commit);
263
264#if !FULL_SYSTEM
265 ThreadID active_threads = params->workload.size();
266
267 if (active_threads > Impl::MaxThreads) {
268 panic("Workload Size too large. Increase the 'MaxThreads'"
269 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or "
270 "edit your workload size.");
271 }
272#else
273 ThreadID active_threads = 1;
274#endif
275
276 //Make Sure That this a Valid Architeture
277 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs);
278 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs);
279
280 rename.setScoreboard(&scoreboard);
281 iew.setScoreboard(&scoreboard);
282
283 // Setup the rename map for whichever stages need it.
284 PhysRegIndex lreg_idx = 0;
285 PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs
286
287 for (ThreadID tid = 0; tid < numThreads; tid++) {
288 bool bindRegs = (tid <= active_threads - 1);
289
290 commitRenameMap[tid].init(TheISA::NumIntRegs,
291 params->numPhysIntRegs,
292 lreg_idx, //Index for Logical. Regs
293
294 TheISA::NumFloatRegs,
295 params->numPhysFloatRegs,
296 freg_idx, //Index for Float Regs
297
298 TheISA::NumMiscRegs,
299
300 TheISA::ZeroReg,
301 TheISA::ZeroReg,
302
303 tid,
304 false);
305
306 renameMap[tid].init(TheISA::NumIntRegs,
307 params->numPhysIntRegs,
308 lreg_idx, //Index for Logical. Regs
309
310 TheISA::NumFloatRegs,
311 params->numPhysFloatRegs,
312 freg_idx, //Index for Float Regs
313
314 TheISA::NumMiscRegs,
315
316 TheISA::ZeroReg,
317 TheISA::ZeroReg,
318
319 tid,
320 bindRegs);
321
322 activateThreadEvent[tid].init(tid, this);
323 deallocateContextEvent[tid].init(tid, this);
324 }
325
326 rename.setRenameMap(renameMap);
327 commit.setRenameMap(commitRenameMap);
328
329 // Give renameMap & rename stage access to the freeList;
330 for (ThreadID tid = 0; tid < numThreads; tid++)
331 renameMap[tid].setFreeList(&freeList);
332 rename.setFreeList(&freeList);
333
334 // Setup the ROB for whichever stages need it.
335 commit.setROB(&rob);
336
337 lastRunningCycle = curTick;
338
339 lastActivatedCycle = -1;
340#if 0
341 // Give renameMap & rename stage access to the freeList;
342 for (ThreadID tid = 0; tid < numThreads; tid++)
343 globalSeqNum[tid] = 1;
344#endif
345
346 contextSwitch = false;
347 DPRINTF(O3CPU, "Creating O3CPU object.\n");
348
349 // Setup any thread state.
350 this->thread.resize(this->numThreads);
351
352 for (ThreadID tid = 0; tid < this->numThreads; ++tid) {
353#if FULL_SYSTEM
354 // SMT is not supported in FS mode yet.
355 assert(this->numThreads == 1);
356 this->thread[tid] = new Thread(this, 0);
357#else
358 if (tid < params->workload.size()) {
359 DPRINTF(O3CPU, "Workload[%i] process is %#x",
360 tid, this->thread[tid]);
361 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
362 (typename Impl::O3CPU *)(this),
363 tid, params->workload[tid]);
364
365 //usedTids[tid] = true;
366 //threadMap[tid] = tid;
367 } else {
368 //Allocate Empty thread so M5 can use later
369 //when scheduling threads to CPU
370 Process* dummy_proc = NULL;
371
372 this->thread[tid] = new typename FullO3CPU<Impl>::Thread(
373 (typename Impl::O3CPU *)(this),
374 tid, dummy_proc);
375 //usedTids[tid] = false;
376 }
377#endif // !FULL_SYSTEM
378
379 ThreadContext *tc;
380
381 // Setup the TC that will serve as the interface to the threads/CPU.
382 O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
383
384 tc = o3_tc;
385
386 // If we're using a checker, then the TC should be the
387 // CheckerThreadContext.
388#if USE_CHECKER
389 if (params->checker) {
390 tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
391 o3_tc, this->checker);
392 }
393#endif
394
395 o3_tc->cpu = (typename Impl::O3CPU *)(this);
396 assert(o3_tc->cpu);
397 o3_tc->thread = this->thread[tid];
398
399#if FULL_SYSTEM
400 // Setup quiesce event.
401 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc);
402#endif
403 // Give the thread the TC.
404 this->thread[tid]->tc = tc;
405
406 // Add the TC to the CPU's list of TC's.
407 this->threadContexts.push_back(tc);
408 }
409
410 for (ThreadID tid = 0; tid < this->numThreads; tid++)
411 this->thread[tid]->setFuncExeInst(0);
412
413 lockAddr = 0;
414 lockFlag = false;
415}
416
417template <class Impl>
418FullO3CPU<Impl>::~FullO3CPU()
419{
420}
421
422template <class Impl>
423void
424FullO3CPU<Impl>::regStats()
425{
426 BaseO3CPU::regStats();
427
428 // Register any of the O3CPU's stats here.
429 timesIdled
430 .name(name() + ".timesIdled")
431 .desc("Number of times that the entire CPU went into an idle state and"
432 " unscheduled itself")
433 .prereq(timesIdled);
434
435 idleCycles
436 .name(name() + ".idleCycles")
437 .desc("Total number of cycles that the CPU has spent unscheduled due "
438 "to idling")
439 .prereq(idleCycles);
440
441 // Number of Instructions simulated
442 // --------------------------------
443 // Should probably be in Base CPU but need templated
444 // MaxThreads so put in here instead
445 committedInsts
446 .init(numThreads)
447 .name(name() + ".committedInsts")
448 .desc("Number of Instructions Simulated");
449
450 totalCommittedInsts
451 .name(name() + ".committedInsts_total")
452 .desc("Number of Instructions Simulated");
453
454 cpi
455 .name(name() + ".cpi")
456 .desc("CPI: Cycles Per Instruction")
457 .precision(6);
458 cpi = numCycles / committedInsts;
459
460 totalCpi
461 .name(name() + ".cpi_total")
462 .desc("CPI: Total CPI of All Threads")
463 .precision(6);
464 totalCpi = numCycles / totalCommittedInsts;
465
466 ipc
467 .name(name() + ".ipc")
468 .desc("IPC: Instructions Per Cycle")
469 .precision(6);
470 ipc = committedInsts / numCycles;
471
472 totalIpc
473 .name(name() + ".ipc_total")
474 .desc("IPC: Total IPC of All Threads")
475 .precision(6);
476 totalIpc = totalCommittedInsts / numCycles;
477
478 this->fetch.regStats();
479 this->decode.regStats();
480 this->rename.regStats();
481 this->iew.regStats();
482 this->commit.regStats();
483}
484
485template <class Impl>
486Port *
487FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
488{
489 if (if_name == "dcache_port")
490 return iew.getDcachePort();
491 else if (if_name == "icache_port")
492 return fetch.getIcachePort();
493 else
494 panic("No Such Port\n");
495}
496
497template <class Impl>
498void
499FullO3CPU<Impl>::tick()
500{
501 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
502
503 ++numCycles;
504
505// activity = false;
506
507 //Tick each of the stages
508 fetch.tick();
509
510 decode.tick();
511
512 rename.tick();
513
514 iew.tick();
515
516 commit.tick();
517
518#if !FULL_SYSTEM
519 doContextSwitch();
520#endif
521
522 // Now advance the time buffers
523 timeBuffer.advance();
524
525 fetchQueue.advance();
526 decodeQueue.advance();
527 renameQueue.advance();
528 iewQueue.advance();
529
530 activityRec.advance();
531
532 if (removeInstsThisCycle) {
533 cleanUpRemovedInsts();
534 }
535
536 if (!tickEvent.scheduled()) {
537 if (_status == SwitchedOut ||
538 getState() == SimObject::Drained) {
539 DPRINTF(O3CPU, "Switched out!\n");
540 // increment stat
541 lastRunningCycle = curTick;
542 } else if (!activityRec.active() || _status == Idle) {
543 DPRINTF(O3CPU, "Idle!\n");
544 lastRunningCycle = curTick;
545 timesIdled++;
546 } else {
547 schedule(tickEvent, nextCycle(curTick + ticks(1)));
548 DPRINTF(O3CPU, "Scheduling next tick!\n");
549 }
550 }
551
552#if !FULL_SYSTEM
553 updateThreadPriority();
554#endif
555}
556
557template <class Impl>
558void
559FullO3CPU<Impl>::init()
560{
561 BaseCPU::init();
562
563 // Set inSyscall so that the CPU doesn't squash when initially
564 // setting up registers.
565 for (ThreadID tid = 0; tid < numThreads; ++tid)
566 thread[tid]->inSyscall = true;
567
568#if FULL_SYSTEM
569 for (ThreadID tid = 0; tid < numThreads; tid++) {
570 ThreadContext *src_tc = threadContexts[tid];
571 TheISA::initCPU(src_tc, src_tc->contextId());
572 }
573#endif
574
575 // Clear inSyscall.
576 for (int tid = 0; tid < numThreads; ++tid)
577 thread[tid]->inSyscall = false;
578
579 // Initialize stages.
580 fetch.initStage();
581 iew.initStage();
582 rename.initStage();
583 commit.initStage();
584
585 commit.setThreads(thread);
586}
587
588template <class Impl>
589void
590FullO3CPU<Impl>::activateThread(ThreadID tid)
591{
592 list<ThreadID>::iterator isActive =
593 std::find(activeThreads.begin(), activeThreads.end(), tid);
594
595 DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);
596
597 if (isActive == activeThreads.end()) {
598 DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
599 tid);
600
601 activeThreads.push_back(tid);
602 }
603}
604
605template <class Impl>
606void
607FullO3CPU<Impl>::deactivateThread(ThreadID tid)
608{
609 //Remove From Active List, if Active
610 list<ThreadID>::iterator thread_it =
611 std::find(activeThreads.begin(), activeThreads.end(), tid);
612
613 DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);
614
615 if (thread_it != activeThreads.end()) {
616 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
617 tid);
618 activeThreads.erase(thread_it);
619 }
620}
621
622template <class Impl>
623Counter
624FullO3CPU<Impl>::totalInstructions() const
625{
626 Counter total(0);
627
628 ThreadID size = thread.size();
629 for (ThreadID i = 0; i < size; i++)
630 total += thread[i]->numInst;
631
632 return total;
633}
634
635template <class Impl>
636void
637FullO3CPU<Impl>::activateContext(ThreadID tid, int delay)
638{
639 // Needs to set each stage to running as well.
640 if (delay){
641 DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
642 "on cycle %d\n", tid, curTick + ticks(delay));
643 scheduleActivateThreadEvent(tid, delay);
644 } else {
645 activateThread(tid);
646 }
647
648 if (lastActivatedCycle < curTick) {
649 scheduleTickEvent(delay);
650
651 // Be sure to signal that there's some activity so the CPU doesn't
652 // deschedule itself.
653 activityRec.activity();
654 fetch.wakeFromQuiesce();
655
656 lastActivatedCycle = curTick;
657
658 _status = Running;
659 }
660}
661
662template <class Impl>
663bool
664FullO3CPU<Impl>::deallocateContext(ThreadID tid, bool remove, int delay)
665{
666 // Schedule removal of thread data from CPU
667 if (delay){
668 DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate "
669 "on cycle %d\n", tid, curTick + ticks(delay));
670 scheduleDeallocateContextEvent(tid, remove, delay);
671 return false;
672 } else {
673 deactivateThread(tid);
674 if (remove)
675 removeThread(tid);
676 return true;
677 }
678}
679
680template <class Impl>
681void
682FullO3CPU<Impl>::suspendContext(ThreadID tid)
683{
684 DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
685 bool deallocated = deallocateContext(tid, false, 1);
686 // If this was the last thread then unschedule the tick event.
687 if ((activeThreads.size() == 1 && !deallocated) ||
688 activeThreads.size() == 0)
689 unscheduleTickEvent();
690 _status = Idle;
691}
692
693template <class Impl>
694void
695FullO3CPU<Impl>::haltContext(ThreadID tid)
696{
697 //For now, this is the same as deallocate
698 DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
699 deallocateContext(tid, true, 1);
700}
701
702template <class Impl>
703void
704FullO3CPU<Impl>::insertThread(ThreadID tid)
705{
706 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
707 // Will change now that the PC and thread state is internal to the CPU
708 // and not in the ThreadContext.
709#if FULL_SYSTEM
710 ThreadContext *src_tc = system->threadContexts[tid];
711#else
712 ThreadContext *src_tc = tcBase(tid);
713#endif
714
715 //Bind Int Regs to Rename Map
716 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
717 PhysRegIndex phys_reg = freeList.getIntReg();
718
719 renameMap[tid].setEntry(ireg,phys_reg);
720 scoreboard.setReg(phys_reg);
721 }
722
723 //Bind Float Regs to Rename Map
724 for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {
725 PhysRegIndex phys_reg = freeList.getFloatReg();
726
727 renameMap[tid].setEntry(freg,phys_reg);
728 scoreboard.setReg(phys_reg);
729 }
730
731 //Copy Thread Data Into RegFile
732 //this->copyFromTC(tid);
733
734 //Set PC/NPC/NNPC
735 setPC(src_tc->readPC(), tid);
736 setNextPC(src_tc->readNextPC(), tid);
737 setNextNPC(src_tc->readNextNPC(), tid);
738
739 src_tc->setStatus(ThreadContext::Active);
740
741 activateContext(tid,1);
742
743 //Reset ROB/IQ/LSQ Entries
744 commit.rob->resetEntries();
745 iew.resetEntries();
746}
747
748template <class Impl>
749void
750FullO3CPU<Impl>::removeThread(ThreadID tid)
751{
752 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);
753
754 // Copy Thread Data From RegFile
755 // If thread is suspended, it might be re-allocated
756 // this->copyToTC(tid);
757
758
759 // @todo: 2-27-2008: Fix how we free up rename mappings
760 // here to alleviate the case for double-freeing registers
761 // in SMT workloads.
762
763 // Unbind Int Regs from Rename Map
764 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
765 PhysRegIndex phys_reg = renameMap[tid].lookup(ireg);
766
767 scoreboard.unsetReg(phys_reg);
768 freeList.addReg(phys_reg);
769 }
770
771 // Unbind Float Regs from Rename Map
772 for (int freg = TheISA::NumIntRegs; freg < TheISA::NumFloatRegs; freg++) {
773 PhysRegIndex phys_reg = renameMap[tid].lookup(freg);
774
775 scoreboard.unsetReg(phys_reg);
776 freeList.addReg(phys_reg);
777 }
778
779 // Squash Throughout Pipeline
780 InstSeqNum squash_seq_num = commit.rob->readHeadInst(tid)->seqNum;
781 fetch.squash(0, sizeof(TheISA::MachInst), 0, squash_seq_num, tid);
782 decode.squash(tid);
783 rename.squash(squash_seq_num, tid);
784 iew.squash(tid);
785 iew.ldstQueue.squash(squash_seq_num, tid);
786 commit.rob->squash(squash_seq_num, tid);
787
788
789 assert(iew.instQueue.getCount(tid) == 0);
790 assert(iew.ldstQueue.getCount(tid) == 0);
791
792 // Reset ROB/IQ/LSQ Entries
793
794 // Commented out for now. This should be possible to do by
795 // telling all the pipeline stages to drain first, and then
796 // checking until the drain completes. Once the pipeline is
797 // drained, call resetEntries(). - 10-09-06 ktlim
798/*
799 if (activeThreads.size() >= 1) {
800 commit.rob->resetEntries();
801 iew.resetEntries();
802 }
803*/
804}
805
806
807template <class Impl>
808void
809FullO3CPU<Impl>::activateWhenReady(ThreadID tid)
810{
811 DPRINTF(O3CPU,"[tid:%i]: Checking if resources are available for incoming"
812 "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
813 tid);
814
815 bool ready = true;
816
817 if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) {
818 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
819 "Phys. Int. Regs.\n",
820 tid);
821 ready = false;
822 } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) {
823 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
824 "Phys. Float. Regs.\n",
825 tid);
826 ready = false;
827 } else if (commit.rob->numFreeEntries() >=
828 commit.rob->entryAmount(activeThreads.size() + 1)) {
829 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
830 "ROB entries.\n",
831 tid);
832 ready = false;
833 } else if (iew.instQueue.numFreeEntries() >=
834 iew.instQueue.entryAmount(activeThreads.size() + 1)) {
835 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
836 "IQ entries.\n",
837 tid);
838 ready = false;
839 } else if (iew.ldstQueue.numFreeEntries() >=
840 iew.ldstQueue.entryAmount(activeThreads.size() + 1)) {
841 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
842 "LSQ entries.\n",
843 tid);
844 ready = false;
845 }
846
847 if (ready) {
848 insertThread(tid);
849
850 contextSwitch = false;
851
852 cpuWaitList.remove(tid);
853 } else {
854 suspendContext(tid);
855
856 //blocks fetch
857 contextSwitch = true;
858
859 //@todo: dont always add to waitlist
860 //do waitlist
861 cpuWaitList.push_back(tid);
862 }
863}
864
865#if FULL_SYSTEM
866template <class Impl>
867Fault
868FullO3CPU<Impl>::hwrei(ThreadID tid)
869{
870#if THE_ISA == ALPHA_ISA
871 // Need to clear the lock flag upon returning from an interrupt.
872 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
873
874 this->thread[tid]->kernelStats->hwrei();
875
876 // FIXME: XXX check for interrupts? XXX
877#endif
878 return NoFault;
879}
880
881template <class Impl>
882bool
883FullO3CPU<Impl>::simPalCheck(int palFunc, ThreadID tid)
884{
885#if THE_ISA == ALPHA_ISA
886 if (this->thread[tid]->kernelStats)
887 this->thread[tid]->kernelStats->callpal(palFunc,
888 this->threadContexts[tid]);
889
890 switch (palFunc) {
891 case PAL::halt:
892 halt();
893 if (--System::numSystemsRunning == 0)
894 exitSimLoop("all cpus halted");
895 break;
896
897 case PAL::bpt:
898 case PAL::bugchk:
899 if (this->system->breakpoint())
900 return false;
901 break;
902 }
903#endif
904 return true;
905}
906
907template <class Impl>
908Fault
909FullO3CPU<Impl>::getInterrupts()
910{
911 // Check if there are any outstanding interrupts
912 return this->interrupts->getInterrupt(this->threadContexts[0]);
913}
914
915template <class Impl>
916void
917FullO3CPU<Impl>::processInterrupts(Fault interrupt)
918{
919 // Check for interrupts here. For now can copy the code that
920 // exists within isa_fullsys_traits.hh. Also assume that thread 0
921 // is the one that handles the interrupts.
922 // @todo: Possibly consolidate the interrupt checking code.
923 // @todo: Allow other threads to handle interrupts.
924
925 assert(interrupt != NoFault);
926 this->interrupts->updateIntrInfo(this->threadContexts[0]);
927
928 DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
929 this->trap(interrupt, 0);
929 DynInstPtr dummyInst;
930 this->trap(interrupt, 0, dummyInst);
930}
931
932template <class Impl>
933void
934FullO3CPU<Impl>::updateMemPorts()
935{
936 // Update all ThreadContext's memory ports (Functional/Virtual
937 // Ports)
938 ThreadID size = thread.size();
939 for (ThreadID i = 0; i < size; ++i)
940 thread[i]->connectMemPorts(thread[i]->getTC());
941}
942#endif
943
944template <class Impl>
945void
931}
932
933template <class Impl>
934void
935FullO3CPU<Impl>::updateMemPorts()
936{
937 // Update all ThreadContext's memory ports (Functional/Virtual
938 // Ports)
939 ThreadID size = thread.size();
940 for (ThreadID i = 0; i < size; ++i)
941 thread[i]->connectMemPorts(thread[i]->getTC());
942}
943#endif
944
945template <class Impl>
946void
946FullO3CPU::trap(Fault fault, ThreadID tid)
947FullO3CPU<Impl>::trap(Fault fault, ThreadID tid, DynInstPtr inst)
947{
948 // Pass the thread's TC into the invoke method.
948{
949 // Pass the thread's TC into the invoke method.
949 fault->invoke(this->threadContexts[tid]);
950 fault->invoke(this->threadContexts[tid], inst->staticInst);
950}
951
952#if !FULL_SYSTEM
953
954template <class Impl>
955void
956FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid)
957{
958 DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);
959
960 DPRINTF(Activity,"Activity: syscall() called.\n");
961
962 // Temporarily increase this by one to account for the syscall
963 // instruction.
964 ++(this->thread[tid]->funcExeInst);
965
966 // Execute the actual syscall.
967 this->thread[tid]->syscall(callnum);
968
969 // Decrease funcExeInst by one as the normal commit will handle
970 // incrementing it.
971 --(this->thread[tid]->funcExeInst);
972}
973
974#endif
975
976template <class Impl>
977void
978FullO3CPU<Impl>::serialize(std::ostream &os)
979{
980 SimObject::State so_state = SimObject::getState();
981 SERIALIZE_ENUM(so_state);
982 BaseCPU::serialize(os);
983 nameOut(os, csprintf("%s.tickEvent", name()));
984 tickEvent.serialize(os);
985
986 // Use SimpleThread's ability to checkpoint to make it easier to
987 // write out the registers. Also make this static so it doesn't
988 // get instantiated multiple times (causes a panic in statistics).
989 static SimpleThread temp;
990
991 ThreadID size = thread.size();
992 for (ThreadID i = 0; i < size; i++) {
993 nameOut(os, csprintf("%s.xc.%i", name(), i));
994 temp.copyTC(thread[i]->getTC());
995 temp.serialize(os);
996 }
997}
998
999template <class Impl>
1000void
1001FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
1002{
1003 SimObject::State so_state;
1004 UNSERIALIZE_ENUM(so_state);
1005 BaseCPU::unserialize(cp, section);
1006 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1007
1008 // Use SimpleThread's ability to checkpoint to make it easier to
1009 // read in the registers. Also make this static so it doesn't
1010 // get instantiated multiple times (causes a panic in statistics).
1011 static SimpleThread temp;
1012
1013 ThreadID size = thread.size();
1014 for (ThreadID i = 0; i < size; i++) {
1015 temp.copyTC(thread[i]->getTC());
1016 temp.unserialize(cp, csprintf("%s.xc.%i", section, i));
1017 thread[i]->getTC()->copyArchRegs(temp.getTC());
1018 }
1019}
1020
1021template <class Impl>
1022unsigned int
1023FullO3CPU<Impl>::drain(Event *drain_event)
1024{
1025 DPRINTF(O3CPU, "Switching out\n");
1026
1027 // If the CPU isn't doing anything, then return immediately.
1028 if (_status == Idle || _status == SwitchedOut) {
1029 return 0;
1030 }
1031
1032 drainCount = 0;
1033 fetch.drain();
1034 decode.drain();
1035 rename.drain();
1036 iew.drain();
1037 commit.drain();
1038
1039 // Wake the CPU and record activity so everything can drain out if
1040 // the CPU was not able to immediately drain.
1041 if (getState() != SimObject::Drained) {
1042 // A bit of a hack...set the drainEvent after all the drain()
1043 // calls have been made, that way if all of the stages drain
1044 // immediately, the signalDrained() function knows not to call
1045 // process on the drain event.
1046 drainEvent = drain_event;
1047
1048 wakeCPU();
1049 activityRec.activity();
1050
1051 return 1;
1052 } else {
1053 return 0;
1054 }
1055}
1056
1057template <class Impl>
1058void
1059FullO3CPU<Impl>::resume()
1060{
1061 fetch.resume();
1062 decode.resume();
1063 rename.resume();
1064 iew.resume();
1065 commit.resume();
1066
1067 changeState(SimObject::Running);
1068
1069 if (_status == SwitchedOut || _status == Idle)
1070 return;
1071
1072#if FULL_SYSTEM
1073 assert(system->getMemoryMode() == Enums::timing);
1074#endif
1075
1076 if (!tickEvent.scheduled())
1077 schedule(tickEvent, nextCycle());
1078 _status = Running;
1079}
1080
1081template <class Impl>
1082void
1083FullO3CPU<Impl>::signalDrained()
1084{
1085 if (++drainCount == NumStages) {
1086 if (tickEvent.scheduled())
1087 tickEvent.squash();
1088
1089 changeState(SimObject::Drained);
1090
1091 BaseCPU::switchOut();
1092
1093 if (drainEvent) {
1094 drainEvent->process();
1095 drainEvent = NULL;
1096 }
1097 }
1098 assert(drainCount <= 5);
1099}
1100
1101template <class Impl>
1102void
1103FullO3CPU<Impl>::switchOut()
1104{
1105 fetch.switchOut();
1106 rename.switchOut();
1107 iew.switchOut();
1108 commit.switchOut();
1109 instList.clear();
1110 while (!removeList.empty()) {
1111 removeList.pop();
1112 }
1113
1114 _status = SwitchedOut;
1115#if USE_CHECKER
1116 if (checker)
1117 checker->switchOut();
1118#endif
1119 if (tickEvent.scheduled())
1120 tickEvent.squash();
1121}
1122
1123template <class Impl>
1124void
1125FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
1126{
1127 // Flush out any old data from the time buffers.
1128 for (int i = 0; i < timeBuffer.getSize(); ++i) {
1129 timeBuffer.advance();
1130 fetchQueue.advance();
1131 decodeQueue.advance();
1132 renameQueue.advance();
1133 iewQueue.advance();
1134 }
1135
1136 activityRec.reset();
1137
1138 BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort());
1139
1140 fetch.takeOverFrom();
1141 decode.takeOverFrom();
1142 rename.takeOverFrom();
1143 iew.takeOverFrom();
1144 commit.takeOverFrom();
1145
1146 assert(!tickEvent.scheduled() || tickEvent.squashed());
1147
1148 // @todo: Figure out how to properly select the tid to put onto
1149 // the active threads list.
1150 ThreadID tid = 0;
1151
1152 list<ThreadID>::iterator isActive =
1153 std::find(activeThreads.begin(), activeThreads.end(), tid);
1154
1155 if (isActive == activeThreads.end()) {
1156 //May Need to Re-code this if the delay variable is the delay
1157 //needed for thread to activate
1158 DPRINTF(O3CPU, "Adding Thread %i to active threads list\n",
1159 tid);
1160
1161 activeThreads.push_back(tid);
1162 }
1163
1164 // Set all statuses to active, schedule the CPU's tick event.
1165 // @todo: Fix up statuses so this is handled properly
1166 ThreadID size = threadContexts.size();
1167 for (ThreadID i = 0; i < size; ++i) {
1168 ThreadContext *tc = threadContexts[i];
1169 if (tc->status() == ThreadContext::Active && _status != Running) {
1170 _status = Running;
1171 reschedule(tickEvent, nextCycle(), true);
1172 }
1173 }
1174 if (!tickEvent.scheduled())
1175 schedule(tickEvent, nextCycle());
1176}
1177
1178template <class Impl>
1179TheISA::MiscReg
1180FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid)
1181{
1182 return this->isa[tid].readMiscRegNoEffect(misc_reg);
1183}
1184
1185template <class Impl>
1186TheISA::MiscReg
1187FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid)
1188{
1189 return this->isa[tid].readMiscReg(misc_reg, tcBase(tid));
1190}
1191
1192template <class Impl>
1193void
1194FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg,
1195 const TheISA::MiscReg &val, ThreadID tid)
1196{
1197 this->isa[tid].setMiscRegNoEffect(misc_reg, val);
1198}
1199
1200template <class Impl>
1201void
1202FullO3CPU<Impl>::setMiscReg(int misc_reg,
1203 const TheISA::MiscReg &val, ThreadID tid)
1204{
1205 this->isa[tid].setMiscReg(misc_reg, val, tcBase(tid));
1206}
1207
1208template <class Impl>
1209uint64_t
1210FullO3CPU<Impl>::readIntReg(int reg_idx)
1211{
1212 return regFile.readIntReg(reg_idx);
1213}
1214
1215template <class Impl>
1216FloatReg
1217FullO3CPU<Impl>::readFloatReg(int reg_idx)
1218{
1219 return regFile.readFloatReg(reg_idx);
1220}
1221
1222template <class Impl>
1223FloatRegBits
1224FullO3CPU<Impl>::readFloatRegBits(int reg_idx)
1225{
1226 return regFile.readFloatRegBits(reg_idx);
1227}
1228
1229template <class Impl>
1230void
1231FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val)
1232{
1233 regFile.setIntReg(reg_idx, val);
1234}
1235
1236template <class Impl>
1237void
1238FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val)
1239{
1240 regFile.setFloatReg(reg_idx, val);
1241}
1242
1243template <class Impl>
1244void
1245FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
1246{
1247 regFile.setFloatRegBits(reg_idx, val);
1248}
1249
1250template <class Impl>
1251uint64_t
1252FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid)
1253{
1254 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
1255
1256 return regFile.readIntReg(phys_reg);
1257}
1258
1259template <class Impl>
1260float
1261FullO3CPU<Impl>::readArchFloatReg(int reg_idx, ThreadID tid)
1262{
1263 int idx = reg_idx + TheISA::NumIntRegs;
1264 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1265
1266 return regFile.readFloatReg(phys_reg);
1267}
1268
1269template <class Impl>
1270uint64_t
1271FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, ThreadID tid)
1272{
1273 int idx = reg_idx + TheISA::NumIntRegs;
1274 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1275
1276 return regFile.readFloatRegBits(phys_reg);
1277}
1278
1279template <class Impl>
1280void
1281FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, ThreadID tid)
1282{
1283 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
1284
1285 regFile.setIntReg(phys_reg, val);
1286}
1287
1288template <class Impl>
1289void
1290FullO3CPU<Impl>::setArchFloatReg(int reg_idx, float val, ThreadID tid)
1291{
1292 int idx = reg_idx + TheISA::NumIntRegs;
1293 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1294
1295 regFile.setFloatReg(phys_reg, val);
1296}
1297
1298template <class Impl>
1299void
1300FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, ThreadID tid)
1301{
1302 int idx = reg_idx + TheISA::NumIntRegs;
1303 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1304
1305 regFile.setFloatRegBits(phys_reg, val);
1306}
1307
1308template <class Impl>
1309uint64_t
1310FullO3CPU<Impl>::readPC(ThreadID tid)
1311{
1312 return commit.readPC(tid);
1313}
1314
1315template <class Impl>
1316void
1317FullO3CPU<Impl>::setPC(Addr new_PC, ThreadID tid)
1318{
1319 commit.setPC(new_PC, tid);
1320}
1321
1322template <class Impl>
1323uint64_t
1324FullO3CPU<Impl>::readMicroPC(ThreadID tid)
1325{
1326 return commit.readMicroPC(tid);
1327}
1328
1329template <class Impl>
1330void
1331FullO3CPU<Impl>::setMicroPC(Addr new_PC, ThreadID tid)
1332{
1333 commit.setMicroPC(new_PC, tid);
1334}
1335
1336template <class Impl>
1337uint64_t
1338FullO3CPU<Impl>::readNextPC(ThreadID tid)
1339{
1340 return commit.readNextPC(tid);
1341}
1342
1343template <class Impl>
1344void
1345FullO3CPU<Impl>::setNextPC(uint64_t val, ThreadID tid)
1346{
1347 commit.setNextPC(val, tid);
1348}
1349
1350template <class Impl>
1351uint64_t
1352FullO3CPU<Impl>::readNextNPC(ThreadID tid)
1353{
1354 return commit.readNextNPC(tid);
1355}
1356
1357template <class Impl>
1358void
1359FullO3CPU<Impl>::setNextNPC(uint64_t val, ThreadID tid)
1360{
1361 commit.setNextNPC(val, tid);
1362}
1363
1364template <class Impl>
1365uint64_t
1366FullO3CPU<Impl>::readNextMicroPC(ThreadID tid)
1367{
1368 return commit.readNextMicroPC(tid);
1369}
1370
1371template <class Impl>
1372void
1373FullO3CPU<Impl>::setNextMicroPC(Addr new_PC, ThreadID tid)
1374{
1375 commit.setNextMicroPC(new_PC, tid);
1376}
1377
1378template <class Impl>
1379void
1380FullO3CPU<Impl>::squashFromTC(ThreadID tid)
1381{
1382 this->thread[tid]->inSyscall = true;
1383 this->commit.generateTCEvent(tid);
1384}
1385
1386template <class Impl>
1387typename FullO3CPU<Impl>::ListIt
1388FullO3CPU<Impl>::addInst(DynInstPtr &inst)
1389{
1390 instList.push_back(inst);
1391
1392 return --(instList.end());
1393}
1394
1395template <class Impl>
1396void
1397FullO3CPU<Impl>::instDone(ThreadID tid)
1398{
1399 // Keep an instruction count.
1400 thread[tid]->numInst++;
1401 thread[tid]->numInsts++;
1402 committedInsts[tid]++;
1403 totalCommittedInsts++;
1404
1405 // Check for instruction-count-based events.
1406 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1407}
1408
1409template <class Impl>
1410void
1411FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst)
1412{
1413 removeInstsThisCycle = true;
1414
1415 removeList.push(inst->getInstListIt());
1416}
1417
1418template <class Impl>
1419void
1420FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
1421{
1422 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %#x "
1423 "[sn:%lli]\n",
1424 inst->threadNumber, inst->readPC(), inst->seqNum);
1425
1426 removeInstsThisCycle = true;
1427
1428 // Remove the front instruction.
1429 removeList.push(inst->getInstListIt());
1430}
1431
1432template <class Impl>
1433void
1434FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid)
1435{
1436 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
1437 " list.\n", tid);
1438
1439 ListIt end_it;
1440
1441 bool rob_empty = false;
1442
1443 if (instList.empty()) {
1444 return;
1445 } else if (rob.isEmpty(/*tid*/)) {
1446 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
1447 end_it = instList.begin();
1448 rob_empty = true;
1449 } else {
1450 end_it = (rob.readTailInst(tid))->getInstListIt();
1451 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
1452 }
1453
1454 removeInstsThisCycle = true;
1455
1456 ListIt inst_it = instList.end();
1457
1458 inst_it--;
1459
1460 // Walk through the instruction list, removing any instructions
1461 // that were inserted after the given instruction iterator, end_it.
1462 while (inst_it != end_it) {
1463 assert(!instList.empty());
1464
1465 squashInstIt(inst_it, tid);
1466
1467 inst_it--;
1468 }
1469
1470 // If the ROB was empty, then we actually need to remove the first
1471 // instruction as well.
1472 if (rob_empty) {
1473 squashInstIt(inst_it, tid);
1474 }
1475}
1476
1477template <class Impl>
1478void
1479FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1480{
1481 assert(!instList.empty());
1482
1483 removeInstsThisCycle = true;
1484
1485 ListIt inst_iter = instList.end();
1486
1487 inst_iter--;
1488
1489 DPRINTF(O3CPU, "Deleting instructions from instruction "
1490 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1491 tid, seq_num, (*inst_iter)->seqNum);
1492
1493 while ((*inst_iter)->seqNum > seq_num) {
1494
1495 bool break_loop = (inst_iter == instList.begin());
1496
1497 squashInstIt(inst_iter, tid);
1498
1499 inst_iter--;
1500
1501 if (break_loop)
1502 break;
1503 }
1504}
1505
1506template <class Impl>
1507inline void
1508FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid)
1509{
1510 if ((*instIt)->threadNumber == tid) {
1511 DPRINTF(O3CPU, "Squashing instruction, "
1512 "[tid:%i] [sn:%lli] PC %#x\n",
1513 (*instIt)->threadNumber,
1514 (*instIt)->seqNum,
1515 (*instIt)->readPC());
1516
1517 // Mark it as squashed.
1518 (*instIt)->setSquashed();
1519
1520 // @todo: Formulate a consistent method for deleting
1521 // instructions from the instruction list
1522 // Remove the instruction from the list.
1523 removeList.push(instIt);
1524 }
1525}
1526
1527template <class Impl>
1528void
1529FullO3CPU<Impl>::cleanUpRemovedInsts()
1530{
1531 while (!removeList.empty()) {
1532 DPRINTF(O3CPU, "Removing instruction, "
1533 "[tid:%i] [sn:%lli] PC %#x\n",
1534 (*removeList.front())->threadNumber,
1535 (*removeList.front())->seqNum,
1536 (*removeList.front())->readPC());
1537
1538 instList.erase(removeList.front());
1539
1540 removeList.pop();
1541 }
1542
1543 removeInstsThisCycle = false;
1544}
1545/*
1546template <class Impl>
1547void
1548FullO3CPU<Impl>::removeAllInsts()
1549{
1550 instList.clear();
1551}
1552*/
1553template <class Impl>
1554void
1555FullO3CPU<Impl>::dumpInsts()
1556{
1557 int num = 0;
1558
1559 ListIt inst_list_it = instList.begin();
1560
1561 cprintf("Dumping Instruction List\n");
1562
1563 while (inst_list_it != instList.end()) {
1564 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1565 "Squashed:%i\n\n",
1566 num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
1567 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1568 (*inst_list_it)->isSquashed());
1569 inst_list_it++;
1570 ++num;
1571 }
1572}
1573/*
1574template <class Impl>
1575void
1576FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
1577{
1578 iew.wakeDependents(inst);
1579}
1580*/
1581template <class Impl>
1582void
1583FullO3CPU<Impl>::wakeCPU()
1584{
1585 if (activityRec.active() || tickEvent.scheduled()) {
1586 DPRINTF(Activity, "CPU already running.\n");
1587 return;
1588 }
1589
1590 DPRINTF(Activity, "Waking up CPU\n");
1591
1592 idleCycles += tickToCycles((curTick - 1) - lastRunningCycle);
1593 numCycles += tickToCycles((curTick - 1) - lastRunningCycle);
1594
1595 schedule(tickEvent, nextCycle());
1596}
1597
1598#if FULL_SYSTEM
1599template <class Impl>
1600void
1601FullO3CPU<Impl>::wakeup()
1602{
1603 if (this->thread[0]->status() != ThreadContext::Suspended)
1604 return;
1605
1606 this->wakeCPU();
1607
1608 DPRINTF(Quiesce, "Suspended Processor woken\n");
1609 this->threadContexts[0]->activate();
1610}
1611#endif
1612
1613template <class Impl>
1614ThreadID
1615FullO3CPU<Impl>::getFreeTid()
1616{
1617 for (ThreadID tid = 0; tid < numThreads; tid++) {
1618 if (!tids[tid]) {
1619 tids[tid] = true;
1620 return tid;
1621 }
1622 }
1623
1624 return InvalidThreadID;
1625}
1626
1627template <class Impl>
1628void
1629FullO3CPU<Impl>::doContextSwitch()
1630{
1631 if (contextSwitch) {
1632
1633 //ADD CODE TO DEACTIVE THREAD HERE (???)
1634
1635 ThreadID size = cpuWaitList.size();
1636 for (ThreadID tid = 0; tid < size; tid++) {
1637 activateWhenReady(tid);
1638 }
1639
1640 if (cpuWaitList.size() == 0)
1641 contextSwitch = true;
1642 }
1643}
1644
1645template <class Impl>
1646void
1647FullO3CPU<Impl>::updateThreadPriority()
1648{
1649 if (activeThreads.size() > 1) {
1650 //DEFAULT TO ROUND ROBIN SCHEME
1651 //e.g. Move highest priority to end of thread list
1652 list<ThreadID>::iterator list_begin = activeThreads.begin();
1653 list<ThreadID>::iterator list_end = activeThreads.end();
1654
1655 unsigned high_thread = *list_begin;
1656
1657 activeThreads.erase(list_begin);
1658
1659 activeThreads.push_back(high_thread);
1660 }
1661}
1662
1663// Forward declaration of FullO3CPU.
1664template class FullO3CPU<O3CPUImpl>;
951}
952
953#if !FULL_SYSTEM
954
955template <class Impl>
956void
957FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid)
958{
959 DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);
960
961 DPRINTF(Activity,"Activity: syscall() called.\n");
962
963 // Temporarily increase this by one to account for the syscall
964 // instruction.
965 ++(this->thread[tid]->funcExeInst);
966
967 // Execute the actual syscall.
968 this->thread[tid]->syscall(callnum);
969
970 // Decrease funcExeInst by one as the normal commit will handle
971 // incrementing it.
972 --(this->thread[tid]->funcExeInst);
973}
974
975#endif
976
977template <class Impl>
978void
979FullO3CPU<Impl>::serialize(std::ostream &os)
980{
981 SimObject::State so_state = SimObject::getState();
982 SERIALIZE_ENUM(so_state);
983 BaseCPU::serialize(os);
984 nameOut(os, csprintf("%s.tickEvent", name()));
985 tickEvent.serialize(os);
986
987 // Use SimpleThread's ability to checkpoint to make it easier to
988 // write out the registers. Also make this static so it doesn't
989 // get instantiated multiple times (causes a panic in statistics).
990 static SimpleThread temp;
991
992 ThreadID size = thread.size();
993 for (ThreadID i = 0; i < size; i++) {
994 nameOut(os, csprintf("%s.xc.%i", name(), i));
995 temp.copyTC(thread[i]->getTC());
996 temp.serialize(os);
997 }
998}
999
1000template <class Impl>
1001void
1002FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
1003{
1004 SimObject::State so_state;
1005 UNSERIALIZE_ENUM(so_state);
1006 BaseCPU::unserialize(cp, section);
1007 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1008
1009 // Use SimpleThread's ability to checkpoint to make it easier to
1010 // read in the registers. Also make this static so it doesn't
1011 // get instantiated multiple times (causes a panic in statistics).
1012 static SimpleThread temp;
1013
1014 ThreadID size = thread.size();
1015 for (ThreadID i = 0; i < size; i++) {
1016 temp.copyTC(thread[i]->getTC());
1017 temp.unserialize(cp, csprintf("%s.xc.%i", section, i));
1018 thread[i]->getTC()->copyArchRegs(temp.getTC());
1019 }
1020}
1021
1022template <class Impl>
1023unsigned int
1024FullO3CPU<Impl>::drain(Event *drain_event)
1025{
1026 DPRINTF(O3CPU, "Switching out\n");
1027
1028 // If the CPU isn't doing anything, then return immediately.
1029 if (_status == Idle || _status == SwitchedOut) {
1030 return 0;
1031 }
1032
1033 drainCount = 0;
1034 fetch.drain();
1035 decode.drain();
1036 rename.drain();
1037 iew.drain();
1038 commit.drain();
1039
1040 // Wake the CPU and record activity so everything can drain out if
1041 // the CPU was not able to immediately drain.
1042 if (getState() != SimObject::Drained) {
1043 // A bit of a hack...set the drainEvent after all the drain()
1044 // calls have been made, that way if all of the stages drain
1045 // immediately, the signalDrained() function knows not to call
1046 // process on the drain event.
1047 drainEvent = drain_event;
1048
1049 wakeCPU();
1050 activityRec.activity();
1051
1052 return 1;
1053 } else {
1054 return 0;
1055 }
1056}
1057
1058template <class Impl>
1059void
1060FullO3CPU<Impl>::resume()
1061{
1062 fetch.resume();
1063 decode.resume();
1064 rename.resume();
1065 iew.resume();
1066 commit.resume();
1067
1068 changeState(SimObject::Running);
1069
1070 if (_status == SwitchedOut || _status == Idle)
1071 return;
1072
1073#if FULL_SYSTEM
1074 assert(system->getMemoryMode() == Enums::timing);
1075#endif
1076
1077 if (!tickEvent.scheduled())
1078 schedule(tickEvent, nextCycle());
1079 _status = Running;
1080}
1081
1082template <class Impl>
1083void
1084FullO3CPU<Impl>::signalDrained()
1085{
1086 if (++drainCount == NumStages) {
1087 if (tickEvent.scheduled())
1088 tickEvent.squash();
1089
1090 changeState(SimObject::Drained);
1091
1092 BaseCPU::switchOut();
1093
1094 if (drainEvent) {
1095 drainEvent->process();
1096 drainEvent = NULL;
1097 }
1098 }
1099 assert(drainCount <= 5);
1100}
1101
1102template <class Impl>
1103void
1104FullO3CPU<Impl>::switchOut()
1105{
1106 fetch.switchOut();
1107 rename.switchOut();
1108 iew.switchOut();
1109 commit.switchOut();
1110 instList.clear();
1111 while (!removeList.empty()) {
1112 removeList.pop();
1113 }
1114
1115 _status = SwitchedOut;
1116#if USE_CHECKER
1117 if (checker)
1118 checker->switchOut();
1119#endif
1120 if (tickEvent.scheduled())
1121 tickEvent.squash();
1122}
1123
1124template <class Impl>
1125void
1126FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
1127{
1128 // Flush out any old data from the time buffers.
1129 for (int i = 0; i < timeBuffer.getSize(); ++i) {
1130 timeBuffer.advance();
1131 fetchQueue.advance();
1132 decodeQueue.advance();
1133 renameQueue.advance();
1134 iewQueue.advance();
1135 }
1136
1137 activityRec.reset();
1138
1139 BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort());
1140
1141 fetch.takeOverFrom();
1142 decode.takeOverFrom();
1143 rename.takeOverFrom();
1144 iew.takeOverFrom();
1145 commit.takeOverFrom();
1146
1147 assert(!tickEvent.scheduled() || tickEvent.squashed());
1148
1149 // @todo: Figure out how to properly select the tid to put onto
1150 // the active threads list.
1151 ThreadID tid = 0;
1152
1153 list<ThreadID>::iterator isActive =
1154 std::find(activeThreads.begin(), activeThreads.end(), tid);
1155
1156 if (isActive == activeThreads.end()) {
1157 //May Need to Re-code this if the delay variable is the delay
1158 //needed for thread to activate
1159 DPRINTF(O3CPU, "Adding Thread %i to active threads list\n",
1160 tid);
1161
1162 activeThreads.push_back(tid);
1163 }
1164
1165 // Set all statuses to active, schedule the CPU's tick event.
1166 // @todo: Fix up statuses so this is handled properly
1167 ThreadID size = threadContexts.size();
1168 for (ThreadID i = 0; i < size; ++i) {
1169 ThreadContext *tc = threadContexts[i];
1170 if (tc->status() == ThreadContext::Active && _status != Running) {
1171 _status = Running;
1172 reschedule(tickEvent, nextCycle(), true);
1173 }
1174 }
1175 if (!tickEvent.scheduled())
1176 schedule(tickEvent, nextCycle());
1177}
1178
1179template <class Impl>
1180TheISA::MiscReg
1181FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid)
1182{
1183 return this->isa[tid].readMiscRegNoEffect(misc_reg);
1184}
1185
1186template <class Impl>
1187TheISA::MiscReg
1188FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid)
1189{
1190 return this->isa[tid].readMiscReg(misc_reg, tcBase(tid));
1191}
1192
1193template <class Impl>
1194void
1195FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg,
1196 const TheISA::MiscReg &val, ThreadID tid)
1197{
1198 this->isa[tid].setMiscRegNoEffect(misc_reg, val);
1199}
1200
1201template <class Impl>
1202void
1203FullO3CPU<Impl>::setMiscReg(int misc_reg,
1204 const TheISA::MiscReg &val, ThreadID tid)
1205{
1206 this->isa[tid].setMiscReg(misc_reg, val, tcBase(tid));
1207}
1208
1209template <class Impl>
1210uint64_t
1211FullO3CPU<Impl>::readIntReg(int reg_idx)
1212{
1213 return regFile.readIntReg(reg_idx);
1214}
1215
1216template <class Impl>
1217FloatReg
1218FullO3CPU<Impl>::readFloatReg(int reg_idx)
1219{
1220 return regFile.readFloatReg(reg_idx);
1221}
1222
1223template <class Impl>
1224FloatRegBits
1225FullO3CPU<Impl>::readFloatRegBits(int reg_idx)
1226{
1227 return regFile.readFloatRegBits(reg_idx);
1228}
1229
1230template <class Impl>
1231void
1232FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val)
1233{
1234 regFile.setIntReg(reg_idx, val);
1235}
1236
1237template <class Impl>
1238void
1239FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val)
1240{
1241 regFile.setFloatReg(reg_idx, val);
1242}
1243
1244template <class Impl>
1245void
1246FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
1247{
1248 regFile.setFloatRegBits(reg_idx, val);
1249}
1250
1251template <class Impl>
1252uint64_t
1253FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid)
1254{
1255 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
1256
1257 return regFile.readIntReg(phys_reg);
1258}
1259
1260template <class Impl>
1261float
1262FullO3CPU<Impl>::readArchFloatReg(int reg_idx, ThreadID tid)
1263{
1264 int idx = reg_idx + TheISA::NumIntRegs;
1265 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1266
1267 return regFile.readFloatReg(phys_reg);
1268}
1269
1270template <class Impl>
1271uint64_t
1272FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, ThreadID tid)
1273{
1274 int idx = reg_idx + TheISA::NumIntRegs;
1275 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1276
1277 return regFile.readFloatRegBits(phys_reg);
1278}
1279
1280template <class Impl>
1281void
1282FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, ThreadID tid)
1283{
1284 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
1285
1286 regFile.setIntReg(phys_reg, val);
1287}
1288
1289template <class Impl>
1290void
1291FullO3CPU<Impl>::setArchFloatReg(int reg_idx, float val, ThreadID tid)
1292{
1293 int idx = reg_idx + TheISA::NumIntRegs;
1294 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1295
1296 regFile.setFloatReg(phys_reg, val);
1297}
1298
1299template <class Impl>
1300void
1301FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, ThreadID tid)
1302{
1303 int idx = reg_idx + TheISA::NumIntRegs;
1304 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
1305
1306 regFile.setFloatRegBits(phys_reg, val);
1307}
1308
1309template <class Impl>
1310uint64_t
1311FullO3CPU<Impl>::readPC(ThreadID tid)
1312{
1313 return commit.readPC(tid);
1314}
1315
1316template <class Impl>
1317void
1318FullO3CPU<Impl>::setPC(Addr new_PC, ThreadID tid)
1319{
1320 commit.setPC(new_PC, tid);
1321}
1322
1323template <class Impl>
1324uint64_t
1325FullO3CPU<Impl>::readMicroPC(ThreadID tid)
1326{
1327 return commit.readMicroPC(tid);
1328}
1329
1330template <class Impl>
1331void
1332FullO3CPU<Impl>::setMicroPC(Addr new_PC, ThreadID tid)
1333{
1334 commit.setMicroPC(new_PC, tid);
1335}
1336
1337template <class Impl>
1338uint64_t
1339FullO3CPU<Impl>::readNextPC(ThreadID tid)
1340{
1341 return commit.readNextPC(tid);
1342}
1343
1344template <class Impl>
1345void
1346FullO3CPU<Impl>::setNextPC(uint64_t val, ThreadID tid)
1347{
1348 commit.setNextPC(val, tid);
1349}
1350
1351template <class Impl>
1352uint64_t
1353FullO3CPU<Impl>::readNextNPC(ThreadID tid)
1354{
1355 return commit.readNextNPC(tid);
1356}
1357
1358template <class Impl>
1359void
1360FullO3CPU<Impl>::setNextNPC(uint64_t val, ThreadID tid)
1361{
1362 commit.setNextNPC(val, tid);
1363}
1364
1365template <class Impl>
1366uint64_t
1367FullO3CPU<Impl>::readNextMicroPC(ThreadID tid)
1368{
1369 return commit.readNextMicroPC(tid);
1370}
1371
1372template <class Impl>
1373void
1374FullO3CPU<Impl>::setNextMicroPC(Addr new_PC, ThreadID tid)
1375{
1376 commit.setNextMicroPC(new_PC, tid);
1377}
1378
1379template <class Impl>
1380void
1381FullO3CPU<Impl>::squashFromTC(ThreadID tid)
1382{
1383 this->thread[tid]->inSyscall = true;
1384 this->commit.generateTCEvent(tid);
1385}
1386
1387template <class Impl>
1388typename FullO3CPU<Impl>::ListIt
1389FullO3CPU<Impl>::addInst(DynInstPtr &inst)
1390{
1391 instList.push_back(inst);
1392
1393 return --(instList.end());
1394}
1395
1396template <class Impl>
1397void
1398FullO3CPU<Impl>::instDone(ThreadID tid)
1399{
1400 // Keep an instruction count.
1401 thread[tid]->numInst++;
1402 thread[tid]->numInsts++;
1403 committedInsts[tid]++;
1404 totalCommittedInsts++;
1405
1406 // Check for instruction-count-based events.
1407 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1408}
1409
1410template <class Impl>
1411void
1412FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst)
1413{
1414 removeInstsThisCycle = true;
1415
1416 removeList.push(inst->getInstListIt());
1417}
1418
1419template <class Impl>
1420void
1421FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
1422{
1423 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %#x "
1424 "[sn:%lli]\n",
1425 inst->threadNumber, inst->readPC(), inst->seqNum);
1426
1427 removeInstsThisCycle = true;
1428
1429 // Remove the front instruction.
1430 removeList.push(inst->getInstListIt());
1431}
1432
1433template <class Impl>
1434void
1435FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid)
1436{
1437 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
1438 " list.\n", tid);
1439
1440 ListIt end_it;
1441
1442 bool rob_empty = false;
1443
1444 if (instList.empty()) {
1445 return;
1446 } else if (rob.isEmpty(/*tid*/)) {
1447 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
1448 end_it = instList.begin();
1449 rob_empty = true;
1450 } else {
1451 end_it = (rob.readTailInst(tid))->getInstListIt();
1452 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
1453 }
1454
1455 removeInstsThisCycle = true;
1456
1457 ListIt inst_it = instList.end();
1458
1459 inst_it--;
1460
1461 // Walk through the instruction list, removing any instructions
1462 // that were inserted after the given instruction iterator, end_it.
1463 while (inst_it != end_it) {
1464 assert(!instList.empty());
1465
1466 squashInstIt(inst_it, tid);
1467
1468 inst_it--;
1469 }
1470
1471 // If the ROB was empty, then we actually need to remove the first
1472 // instruction as well.
1473 if (rob_empty) {
1474 squashInstIt(inst_it, tid);
1475 }
1476}
1477
1478template <class Impl>
1479void
1480FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1481{
1482 assert(!instList.empty());
1483
1484 removeInstsThisCycle = true;
1485
1486 ListIt inst_iter = instList.end();
1487
1488 inst_iter--;
1489
1490 DPRINTF(O3CPU, "Deleting instructions from instruction "
1491 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1492 tid, seq_num, (*inst_iter)->seqNum);
1493
1494 while ((*inst_iter)->seqNum > seq_num) {
1495
1496 bool break_loop = (inst_iter == instList.begin());
1497
1498 squashInstIt(inst_iter, tid);
1499
1500 inst_iter--;
1501
1502 if (break_loop)
1503 break;
1504 }
1505}
1506
1507template <class Impl>
1508inline void
1509FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid)
1510{
1511 if ((*instIt)->threadNumber == tid) {
1512 DPRINTF(O3CPU, "Squashing instruction, "
1513 "[tid:%i] [sn:%lli] PC %#x\n",
1514 (*instIt)->threadNumber,
1515 (*instIt)->seqNum,
1516 (*instIt)->readPC());
1517
1518 // Mark it as squashed.
1519 (*instIt)->setSquashed();
1520
1521 // @todo: Formulate a consistent method for deleting
1522 // instructions from the instruction list
1523 // Remove the instruction from the list.
1524 removeList.push(instIt);
1525 }
1526}
1527
1528template <class Impl>
1529void
1530FullO3CPU<Impl>::cleanUpRemovedInsts()
1531{
1532 while (!removeList.empty()) {
1533 DPRINTF(O3CPU, "Removing instruction, "
1534 "[tid:%i] [sn:%lli] PC %#x\n",
1535 (*removeList.front())->threadNumber,
1536 (*removeList.front())->seqNum,
1537 (*removeList.front())->readPC());
1538
1539 instList.erase(removeList.front());
1540
1541 removeList.pop();
1542 }
1543
1544 removeInstsThisCycle = false;
1545}
1546/*
1547template <class Impl>
1548void
1549FullO3CPU<Impl>::removeAllInsts()
1550{
1551 instList.clear();
1552}
1553*/
1554template <class Impl>
1555void
1556FullO3CPU<Impl>::dumpInsts()
1557{
1558 int num = 0;
1559
1560 ListIt inst_list_it = instList.begin();
1561
1562 cprintf("Dumping Instruction List\n");
1563
1564 while (inst_list_it != instList.end()) {
1565 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1566 "Squashed:%i\n\n",
1567 num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
1568 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1569 (*inst_list_it)->isSquashed());
1570 inst_list_it++;
1571 ++num;
1572 }
1573}
1574/*
1575template <class Impl>
1576void
1577FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
1578{
1579 iew.wakeDependents(inst);
1580}
1581*/
1582template <class Impl>
1583void
1584FullO3CPU<Impl>::wakeCPU()
1585{
1586 if (activityRec.active() || tickEvent.scheduled()) {
1587 DPRINTF(Activity, "CPU already running.\n");
1588 return;
1589 }
1590
1591 DPRINTF(Activity, "Waking up CPU\n");
1592
1593 idleCycles += tickToCycles((curTick - 1) - lastRunningCycle);
1594 numCycles += tickToCycles((curTick - 1) - lastRunningCycle);
1595
1596 schedule(tickEvent, nextCycle());
1597}
1598
1599#if FULL_SYSTEM
1600template <class Impl>
1601void
1602FullO3CPU<Impl>::wakeup()
1603{
1604 if (this->thread[0]->status() != ThreadContext::Suspended)
1605 return;
1606
1607 this->wakeCPU();
1608
1609 DPRINTF(Quiesce, "Suspended Processor woken\n");
1610 this->threadContexts[0]->activate();
1611}
1612#endif
1613
1614template <class Impl>
1615ThreadID
1616FullO3CPU<Impl>::getFreeTid()
1617{
1618 for (ThreadID tid = 0; tid < numThreads; tid++) {
1619 if (!tids[tid]) {
1620 tids[tid] = true;
1621 return tid;
1622 }
1623 }
1624
1625 return InvalidThreadID;
1626}
1627
1628template <class Impl>
1629void
1630FullO3CPU<Impl>::doContextSwitch()
1631{
1632 if (contextSwitch) {
1633
1634 //ADD CODE TO DEACTIVE THREAD HERE (???)
1635
1636 ThreadID size = cpuWaitList.size();
1637 for (ThreadID tid = 0; tid < size; tid++) {
1638 activateWhenReady(tid);
1639 }
1640
1641 if (cpuWaitList.size() == 0)
1642 contextSwitch = true;
1643 }
1644}
1645
1646template <class Impl>
1647void
1648FullO3CPU<Impl>::updateThreadPriority()
1649{
1650 if (activeThreads.size() > 1) {
1651 //DEFAULT TO ROUND ROBIN SCHEME
1652 //e.g. Move highest priority to end of thread list
1653 list<ThreadID>::iterator list_begin = activeThreads.begin();
1654 list<ThreadID>::iterator list_end = activeThreads.end();
1655
1656 unsigned high_thread = *list_begin;
1657
1658 activeThreads.erase(list_begin);
1659
1660 activeThreads.push_back(high_thread);
1661 }
1662}
1663
1664// Forward declaration of FullO3CPU.
1665template class FullO3CPU<O3CPUImpl>;