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