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