2 * Copyright (c) 2011-2012 ARM Limited
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.
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.
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.
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.
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"
68 #if THE_ISA == ALPHA_ISA
69 #include "arch/alpha/osfpal.hh"
70 #include "debug/Activity.hh"
75 using namespace TheISA
;
78 BaseO3CPU::BaseO3CPU(BaseCPUParams
*params
)
91 FullO3CPU
<Impl
>::IcachePort::recvTimingResp(PacketPtr pkt
)
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
);
103 FullO3CPU
<Impl
>::IcachePort::recvRetry()
108 template <class Impl
>
110 FullO3CPU
<Impl
>::DcachePort::recvTimingResp(PacketPtr pkt
)
112 return lsq
->recvTimingResp(pkt
);
115 template <class Impl
>
117 FullO3CPU
<Impl
>::DcachePort::recvTimingSnoopReq(PacketPtr pkt
)
119 lsq
->recvTimingSnoopReq(pkt
);
122 template <class Impl
>
124 FullO3CPU
<Impl
>::DcachePort::recvRetry()
129 template <class Impl
>
130 FullO3CPU
<Impl
>::TickEvent::TickEvent(FullO3CPU
<Impl
> *c
)
131 : Event(CPU_Tick_Pri
), cpu(c
)
135 template <class Impl
>
137 FullO3CPU
<Impl
>::TickEvent::process()
142 template <class Impl
>
144 FullO3CPU
<Impl
>::TickEvent::description() const
146 return "FullO3CPU tick";
149 template <class Impl
>
150 FullO3CPU
<Impl
>::ActivateThreadEvent::ActivateThreadEvent()
151 : Event(CPU_Switch_Pri
)
155 template <class Impl
>
157 FullO3CPU
<Impl
>::ActivateThreadEvent::init(int thread_num
,
158 FullO3CPU
<Impl
> *thread_cpu
)
164 template <class Impl
>
166 FullO3CPU
<Impl
>::ActivateThreadEvent::process()
168 cpu
->activateThread(tid
);
171 template <class Impl
>
173 FullO3CPU
<Impl
>::ActivateThreadEvent::description() const
175 return "FullO3CPU \"Activate Thread\"";
178 template <class Impl
>
179 FullO3CPU
<Impl
>::DeallocateContextEvent::DeallocateContextEvent()
180 : Event(CPU_Tick_Pri
), tid(0), remove(false), cpu(NULL
)
184 template <class Impl
>
186 FullO3CPU
<Impl
>::DeallocateContextEvent::init(int thread_num
,
187 FullO3CPU
<Impl
> *thread_cpu
)
194 template <class Impl
>
196 FullO3CPU
<Impl
>::DeallocateContextEvent::process()
198 cpu
->deactivateThread(tid
);
200 cpu
->removeThread(tid
);
203 template <class Impl
>
205 FullO3CPU
<Impl
>::DeallocateContextEvent::description() const
207 return "FullO3CPU \"Deallocate Context\"";
210 template <class Impl
>
211 FullO3CPU
<Impl
>::FullO3CPU(DerivO3CPUParams
*params
)
219 removeInstsThisCycle(false),
221 decode(this, params
),
222 rename(this, params
),
224 commit(this, params
),
226 regFile(this, params
->numPhysIntRegs
,
227 params
->numPhysFloatRegs
),
229 freeList(params
->numThreads
,
230 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
231 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
),
234 params
->numROBEntries
, params
->squashWidth
,
235 params
->smtROBPolicy
, params
->smtROBThreshold
,
238 scoreboard(params
->numThreads
,
239 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
240 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
,
241 TheISA::NumMiscRegs
* numThreads
,
244 icachePort(&fetch
, this),
245 dcachePort(&iew
.ldstQueue
, this),
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
,
257 system(params
->system
),
259 deferRegistration(params
->defer_registration
),
260 lastRunningCycle(curCycle())
262 if (!deferRegistration
) {
265 _status
= SwitchedOut
;
268 if (params
->checker
) {
269 BaseCPU
*temp_checker
= params
->checker
;
270 checker
= dynamic_cast<Checker
<Impl
> *>(temp_checker
);
271 checker
->setIcachePort(&icachePort
);
272 checker
->setSystem(params
->system
);
278 thread
.resize(numThreads
);
279 tids
.resize(numThreads
);
282 // The stages also need their CPU pointer setup. However this
283 // must be done at the upper level CPU because they have pointers
284 // to the upper level CPU, and not this FullO3CPU.
286 // Set up Pointers to the activeThreads list for each stage
287 fetch
.setActiveThreads(&activeThreads
);
288 decode
.setActiveThreads(&activeThreads
);
289 rename
.setActiveThreads(&activeThreads
);
290 iew
.setActiveThreads(&activeThreads
);
291 commit
.setActiveThreads(&activeThreads
);
293 // Give each of the stages the time buffer they will use.
294 fetch
.setTimeBuffer(&timeBuffer
);
295 decode
.setTimeBuffer(&timeBuffer
);
296 rename
.setTimeBuffer(&timeBuffer
);
297 iew
.setTimeBuffer(&timeBuffer
);
298 commit
.setTimeBuffer(&timeBuffer
);
300 // Also setup each of the stages' queues.
301 fetch
.setFetchQueue(&fetchQueue
);
302 decode
.setFetchQueue(&fetchQueue
);
303 commit
.setFetchQueue(&fetchQueue
);
304 decode
.setDecodeQueue(&decodeQueue
);
305 rename
.setDecodeQueue(&decodeQueue
);
306 rename
.setRenameQueue(&renameQueue
);
307 iew
.setRenameQueue(&renameQueue
);
308 iew
.setIEWQueue(&iewQueue
);
309 commit
.setIEWQueue(&iewQueue
);
310 commit
.setRenameQueue(&renameQueue
);
312 commit
.setIEWStage(&iew
);
313 rename
.setIEWStage(&iew
);
314 rename
.setCommitStage(&commit
);
316 ThreadID active_threads
;
320 active_threads
= params
->workload
.size();
322 if (active_threads
> Impl::MaxThreads
) {
323 panic("Workload Size too large. Increase the 'MaxThreads' "
324 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
325 "or edit your workload size.");
329 //Make Sure That this a Valid Architeture
330 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
331 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
333 rename
.setScoreboard(&scoreboard
);
334 iew
.setScoreboard(&scoreboard
);
336 // Setup the rename map for whichever stages need it.
337 PhysRegIndex lreg_idx
= 0;
338 PhysRegIndex freg_idx
= params
->numPhysIntRegs
; //Index to 1 after int regs
340 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
341 bool bindRegs
= (tid
<= active_threads
- 1);
343 commitRenameMap
[tid
].init(TheISA::NumIntRegs
,
344 params
->numPhysIntRegs
,
345 lreg_idx
, //Index for Logical. Regs
347 TheISA::NumFloatRegs
,
348 params
->numPhysFloatRegs
,
349 freg_idx
, //Index for Float Regs
359 renameMap
[tid
].init(TheISA::NumIntRegs
,
360 params
->numPhysIntRegs
,
361 lreg_idx
, //Index for Logical. Regs
363 TheISA::NumFloatRegs
,
364 params
->numPhysFloatRegs
,
365 freg_idx
, //Index for Float Regs
375 activateThreadEvent
[tid
].init(tid
, this);
376 deallocateContextEvent
[tid
].init(tid
, this);
379 rename
.setRenameMap(renameMap
);
380 commit
.setRenameMap(commitRenameMap
);
382 // Give renameMap & rename stage access to the freeList;
383 for (ThreadID tid
= 0; tid
< numThreads
; tid
++)
384 renameMap
[tid
].setFreeList(&freeList
);
385 rename
.setFreeList(&freeList
);
387 // Setup the ROB for whichever stages need it.
390 lastActivatedCycle
= 0;
392 // Give renameMap & rename stage access to the freeList;
393 for (ThreadID tid
= 0; tid
< numThreads
; tid
++)
394 globalSeqNum
[tid
] = 1;
397 contextSwitch
= false;
398 DPRINTF(O3CPU
, "Creating O3CPU object.\n");
400 // Setup any thread state.
401 this->thread
.resize(this->numThreads
);
403 for (ThreadID tid
= 0; tid
< this->numThreads
; ++tid
) {
405 // SMT is not supported in FS mode yet.
406 assert(this->numThreads
== 1);
407 this->thread
[tid
] = new Thread(this, 0, NULL
);
409 if (tid
< params
->workload
.size()) {
410 DPRINTF(O3CPU
, "Workload[%i] process is %#x",
411 tid
, this->thread
[tid
]);
412 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
413 (typename
Impl::O3CPU
*)(this),
414 tid
, params
->workload
[tid
]);
416 //usedTids[tid] = true;
417 //threadMap[tid] = tid;
419 //Allocate Empty thread so M5 can use later
420 //when scheduling threads to CPU
421 Process
* dummy_proc
= NULL
;
423 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
424 (typename
Impl::O3CPU
*)(this),
426 //usedTids[tid] = false;
432 // Setup the TC that will serve as the interface to the threads/CPU.
433 O3ThreadContext
<Impl
> *o3_tc
= new O3ThreadContext
<Impl
>;
437 // If we're using a checker, then the TC should be the
438 // CheckerThreadContext.
439 if (params
->checker
) {
440 tc
= new CheckerThreadContext
<O3ThreadContext
<Impl
> >(
441 o3_tc
, this->checker
);
444 o3_tc
->cpu
= (typename
Impl::O3CPU
*)(this);
446 o3_tc
->thread
= this->thread
[tid
];
449 // Setup quiesce event.
450 this->thread
[tid
]->quiesceEvent
= new EndQuiesceEvent(tc
);
452 // Give the thread the TC.
453 this->thread
[tid
]->tc
= tc
;
455 // Add the TC to the CPU's list of TC's.
456 this->threadContexts
.push_back(tc
);
459 // FullO3CPU always requires an interrupt controller.
460 if (!params
->defer_registration
&& !interrupts
) {
461 fatal("FullO3CPU %s has no interrupt controller.\n"
462 "Ensure createInterruptController() is called.\n", name());
465 for (ThreadID tid
= 0; tid
< this->numThreads
; tid
++)
466 this->thread
[tid
]->setFuncExeInst(0);
472 template <class Impl
>
473 FullO3CPU
<Impl
>::~FullO3CPU()
477 template <class Impl
>
479 FullO3CPU
<Impl
>::regStats()
481 BaseO3CPU::regStats();
483 // Register any of the O3CPU's stats here.
485 .name(name() + ".timesIdled")
486 .desc("Number of times that the entire CPU went into an idle state and"
487 " unscheduled itself")
491 .name(name() + ".idleCycles")
492 .desc("Total number of cycles that the CPU has spent unscheduled due "
497 .name(name() + ".quiesceCycles")
498 .desc("Total number of cycles that CPU has spent quiesced or waiting "
500 .prereq(quiesceCycles
);
502 // Number of Instructions simulated
503 // --------------------------------
504 // Should probably be in Base CPU but need templated
505 // MaxThreads so put in here instead
508 .name(name() + ".committedInsts")
509 .desc("Number of Instructions Simulated");
513 .name(name() + ".committedOps")
514 .desc("Number of Ops (including micro ops) Simulated");
517 .name(name() + ".committedInsts_total")
518 .desc("Number of Instructions Simulated");
521 .name(name() + ".cpi")
522 .desc("CPI: Cycles Per Instruction")
524 cpi
= numCycles
/ committedInsts
;
527 .name(name() + ".cpi_total")
528 .desc("CPI: Total CPI of All Threads")
530 totalCpi
= numCycles
/ totalCommittedInsts
;
533 .name(name() + ".ipc")
534 .desc("IPC: Instructions Per Cycle")
536 ipc
= committedInsts
/ numCycles
;
539 .name(name() + ".ipc_total")
540 .desc("IPC: Total IPC of All Threads")
542 totalIpc
= totalCommittedInsts
/ numCycles
;
544 this->fetch
.regStats();
545 this->decode
.regStats();
546 this->rename
.regStats();
547 this->iew
.regStats();
548 this->commit
.regStats();
549 this->rob
.regStats();
552 .name(name() + ".int_regfile_reads")
553 .desc("number of integer regfile reads")
554 .prereq(intRegfileReads
);
557 .name(name() + ".int_regfile_writes")
558 .desc("number of integer regfile writes")
559 .prereq(intRegfileWrites
);
562 .name(name() + ".fp_regfile_reads")
563 .desc("number of floating regfile reads")
564 .prereq(fpRegfileReads
);
567 .name(name() + ".fp_regfile_writes")
568 .desc("number of floating regfile writes")
569 .prereq(fpRegfileWrites
);
572 .name(name() + ".misc_regfile_reads")
573 .desc("number of misc regfile reads")
574 .prereq(miscRegfileReads
);
577 .name(name() + ".misc_regfile_writes")
578 .desc("number of misc regfile writes")
579 .prereq(miscRegfileWrites
);
582 template <class Impl
>
584 FullO3CPU
<Impl
>::tick()
586 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
592 //Tick each of the stages
606 // Now advance the time buffers
607 timeBuffer
.advance();
609 fetchQueue
.advance();
610 decodeQueue
.advance();
611 renameQueue
.advance();
614 activityRec
.advance();
616 if (removeInstsThisCycle
) {
617 cleanUpRemovedInsts();
620 if (!tickEvent
.scheduled()) {
621 if (_status
== SwitchedOut
||
622 getDrainState() == Drainable::Drained
) {
623 DPRINTF(O3CPU
, "Switched out!\n");
625 lastRunningCycle
= curCycle();
626 } else if (!activityRec
.active() || _status
== Idle
) {
627 DPRINTF(O3CPU
, "Idle!\n");
628 lastRunningCycle
= curCycle();
631 schedule(tickEvent
, clockEdge(Cycles(1)));
632 DPRINTF(O3CPU
, "Scheduling next tick!\n");
637 updateThreadPriority();
640 template <class Impl
>
642 FullO3CPU
<Impl
>::init()
646 for (ThreadID tid
= 0; tid
< numThreads
; ++tid
) {
647 // Set inSyscall so that the CPU doesn't squash when initially
648 // setting up registers.
649 thread
[tid
]->inSyscall
= true;
650 // Initialise the ThreadContext's memory proxies
651 thread
[tid
]->initMemProxies(thread
[tid
]->getTC());
654 // this CPU could still be unconnected if we are restoring from a
655 // checkpoint and this CPU is to be switched in, thus we can only
656 // do this here if the instruction port is actually connected, if
657 // not we have to do it as part of takeOverFrom
658 if (icachePort
.isConnected())
661 if (FullSystem
&& !params()->defer_registration
) {
662 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
663 ThreadContext
*src_tc
= threadContexts
[tid
];
664 TheISA::initCPU(src_tc
, src_tc
->contextId());
669 for (int tid
= 0; tid
< numThreads
; ++tid
)
670 thread
[tid
]->inSyscall
= false;
672 // Initialize stages.
678 commit
.setThreads(thread
);
681 template <class Impl
>
683 FullO3CPU
<Impl
>::activateThread(ThreadID tid
)
685 list
<ThreadID
>::iterator isActive
=
686 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
688 DPRINTF(O3CPU
, "[tid:%i]: Calling activate thread.\n", tid
);
690 if (isActive
== activeThreads
.end()) {
691 DPRINTF(O3CPU
, "[tid:%i]: Adding to active threads list\n",
694 activeThreads
.push_back(tid
);
698 template <class Impl
>
700 FullO3CPU
<Impl
>::deactivateThread(ThreadID tid
)
702 //Remove From Active List, if Active
703 list
<ThreadID
>::iterator thread_it
=
704 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
706 DPRINTF(O3CPU
, "[tid:%i]: Calling deactivate thread.\n", tid
);
708 if (thread_it
!= activeThreads
.end()) {
709 DPRINTF(O3CPU
,"[tid:%i]: Removing from active threads list\n",
711 activeThreads
.erase(thread_it
);
715 template <class Impl
>
717 FullO3CPU
<Impl
>::totalInsts() const
721 ThreadID size
= thread
.size();
722 for (ThreadID i
= 0; i
< size
; i
++)
723 total
+= thread
[i
]->numInst
;
728 template <class Impl
>
730 FullO3CPU
<Impl
>::totalOps() const
734 ThreadID size
= thread
.size();
735 for (ThreadID i
= 0; i
< size
; i
++)
736 total
+= thread
[i
]->numOp
;
741 template <class Impl
>
743 FullO3CPU
<Impl
>::activateContext(ThreadID tid
, Cycles delay
)
745 // Needs to set each stage to running as well.
747 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to activate "
748 "on cycle %d\n", tid
, clockEdge(delay
));
749 scheduleActivateThreadEvent(tid
, delay
);
754 // If we are time 0 or if the last activation time is in the past,
755 // schedule the next tick and wake up the fetch unit
756 if (lastActivatedCycle
== 0 || lastActivatedCycle
< curTick()) {
757 scheduleTickEvent(delay
);
759 // Be sure to signal that there's some activity so the CPU doesn't
760 // deschedule itself.
761 activityRec
.activity();
762 fetch
.wakeFromQuiesce();
764 Cycles
cycles(curCycle() - lastRunningCycle
);
765 // @todo: This is an oddity that is only here to match the stats
768 quiesceCycles
+= cycles
;
770 lastActivatedCycle
= curTick();
776 template <class Impl
>
778 FullO3CPU
<Impl
>::scheduleDeallocateContext(ThreadID tid
, bool remove
,
781 // Schedule removal of thread data from CPU
783 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to deallocate "
784 "on tick %d\n", tid
, clockEdge(delay
));
785 scheduleDeallocateContextEvent(tid
, remove
, delay
);
788 deactivateThread(tid
);
795 template <class Impl
>
797 FullO3CPU
<Impl
>::suspendContext(ThreadID tid
)
799 DPRINTF(O3CPU
,"[tid: %i]: Suspending Thread Context.\n", tid
);
800 bool deallocated
= scheduleDeallocateContext(tid
, false, Cycles(1));
801 // If this was the last thread then unschedule the tick event.
802 if ((activeThreads
.size() == 1 && !deallocated
) ||
803 activeThreads
.size() == 0)
804 unscheduleTickEvent();
806 DPRINTF(Quiesce
, "Suspending Context\n");
807 lastRunningCycle
= curCycle();
811 template <class Impl
>
813 FullO3CPU
<Impl
>::haltContext(ThreadID tid
)
815 //For now, this is the same as deallocate
816 DPRINTF(O3CPU
,"[tid:%i]: Halt Context called. Deallocating", tid
);
817 scheduleDeallocateContext(tid
, true, Cycles(1));
820 template <class Impl
>
822 FullO3CPU
<Impl
>::insertThread(ThreadID tid
)
824 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
825 // Will change now that the PC and thread state is internal to the CPU
826 // and not in the ThreadContext.
827 ThreadContext
*src_tc
;
829 src_tc
= system
->threadContexts
[tid
];
831 src_tc
= tcBase(tid
);
833 //Bind Int Regs to Rename Map
834 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
835 PhysRegIndex phys_reg
= freeList
.getIntReg();
837 renameMap
[tid
].setEntry(ireg
,phys_reg
);
838 scoreboard
.setReg(phys_reg
);
841 //Bind Float Regs to Rename Map
842 for (int freg
= 0; freg
< TheISA::NumFloatRegs
; freg
++) {
843 PhysRegIndex phys_reg
= freeList
.getFloatReg();
845 renameMap
[tid
].setEntry(freg
,phys_reg
);
846 scoreboard
.setReg(phys_reg
);
849 //Copy Thread Data Into RegFile
850 //this->copyFromTC(tid);
853 pcState(src_tc
->pcState(), tid
);
855 src_tc
->setStatus(ThreadContext::Active
);
857 activateContext(tid
, Cycles(1));
859 //Reset ROB/IQ/LSQ Entries
860 commit
.rob
->resetEntries();
864 template <class Impl
>
866 FullO3CPU
<Impl
>::removeThread(ThreadID tid
)
868 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
870 // Copy Thread Data From RegFile
871 // If thread is suspended, it might be re-allocated
872 // this->copyToTC(tid);
875 // @todo: 2-27-2008: Fix how we free up rename mappings
876 // here to alleviate the case for double-freeing registers
879 // Unbind Int Regs from Rename Map
880 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
881 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(ireg
);
883 scoreboard
.unsetReg(phys_reg
);
884 freeList
.addReg(phys_reg
);
887 // Unbind Float Regs from Rename Map
888 for (int freg
= TheISA::NumIntRegs
; freg
< TheISA::NumFloatRegs
; freg
++) {
889 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(freg
);
891 scoreboard
.unsetReg(phys_reg
);
892 freeList
.addReg(phys_reg
);
895 // Squash Throughout Pipeline
896 DynInstPtr inst
= commit
.rob
->readHeadInst(tid
);
897 InstSeqNum squash_seq_num
= inst
->seqNum
;
898 fetch
.squash(0, squash_seq_num
, inst
, tid
);
900 rename
.squash(squash_seq_num
, tid
);
902 iew
.ldstQueue
.squash(squash_seq_num
, tid
);
903 commit
.rob
->squash(squash_seq_num
, tid
);
906 assert(iew
.instQueue
.getCount(tid
) == 0);
907 assert(iew
.ldstQueue
.getCount(tid
) == 0);
909 // Reset ROB/IQ/LSQ Entries
911 // Commented out for now. This should be possible to do by
912 // telling all the pipeline stages to drain first, and then
913 // checking until the drain completes. Once the pipeline is
914 // drained, call resetEntries(). - 10-09-06 ktlim
916 if (activeThreads.size() >= 1) {
917 commit.rob->resetEntries();
924 template <class Impl
>
926 FullO3CPU
<Impl
>::activateWhenReady(ThreadID tid
)
928 DPRINTF(O3CPU
,"[tid:%i]: Checking if resources are available for incoming"
929 "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
934 if (freeList
.numFreeIntRegs() >= TheISA::NumIntRegs
) {
935 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
936 "Phys. Int. Regs.\n",
939 } else if (freeList
.numFreeFloatRegs() >= TheISA::NumFloatRegs
) {
940 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
941 "Phys. Float. Regs.\n",
944 } else if (commit
.rob
->numFreeEntries() >=
945 commit
.rob
->entryAmount(activeThreads
.size() + 1)) {
946 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
950 } else if (iew
.instQueue
.numFreeEntries() >=
951 iew
.instQueue
.entryAmount(activeThreads
.size() + 1)) {
952 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
956 } else if (iew
.ldstQueue
.numFreeEntries() >=
957 iew
.ldstQueue
.entryAmount(activeThreads
.size() + 1)) {
958 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
967 contextSwitch
= false;
969 cpuWaitList
.remove(tid
);
974 contextSwitch
= true;
976 //@todo: dont always add to waitlist
978 cpuWaitList
.push_back(tid
);
982 template <class Impl
>
984 FullO3CPU
<Impl
>::hwrei(ThreadID tid
)
986 #if THE_ISA == ALPHA_ISA
987 // Need to clear the lock flag upon returning from an interrupt.
988 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG
, false, tid
);
990 this->thread
[tid
]->kernelStats
->hwrei();
992 // FIXME: XXX check for interrupts? XXX
997 template <class Impl
>
999 FullO3CPU
<Impl
>::simPalCheck(int palFunc
, ThreadID tid
)
1001 #if THE_ISA == ALPHA_ISA
1002 if (this->thread
[tid
]->kernelStats
)
1003 this->thread
[tid
]->kernelStats
->callpal(palFunc
,
1004 this->threadContexts
[tid
]);
1009 if (--System::numSystemsRunning
== 0)
1010 exitSimLoop("all cpus halted");
1015 if (this->system
->breakpoint())
1023 template <class Impl
>
1025 FullO3CPU
<Impl
>::getInterrupts()
1027 // Check if there are any outstanding interrupts
1028 return this->interrupts
->getInterrupt(this->threadContexts
[0]);
1031 template <class Impl
>
1033 FullO3CPU
<Impl
>::processInterrupts(Fault interrupt
)
1035 // Check for interrupts here. For now can copy the code that
1036 // exists within isa_fullsys_traits.hh. Also assume that thread 0
1037 // is the one that handles the interrupts.
1038 // @todo: Possibly consolidate the interrupt checking code.
1039 // @todo: Allow other threads to handle interrupts.
1041 assert(interrupt
!= NoFault
);
1042 this->interrupts
->updateIntrInfo(this->threadContexts
[0]);
1044 DPRINTF(O3CPU
, "Interrupt %s being handled\n", interrupt
->name());
1045 this->trap(interrupt
, 0, NULL
);
1048 template <class Impl
>
1050 FullO3CPU
<Impl
>::trap(Fault fault
, ThreadID tid
, StaticInstPtr inst
)
1052 // Pass the thread's TC into the invoke method.
1053 fault
->invoke(this->threadContexts
[tid
], inst
);
1056 template <class Impl
>
1058 FullO3CPU
<Impl
>::syscall(int64_t callnum
, ThreadID tid
)
1060 DPRINTF(O3CPU
, "[tid:%i] Executing syscall().\n\n", tid
);
1062 DPRINTF(Activity
,"Activity: syscall() called.\n");
1064 // Temporarily increase this by one to account for the syscall
1066 ++(this->thread
[tid
]->funcExeInst
);
1068 // Execute the actual syscall.
1069 this->thread
[tid
]->syscall(callnum
);
1071 // Decrease funcExeInst by one as the normal commit will handle
1073 --(this->thread
[tid
]->funcExeInst
);
1076 template <class Impl
>
1078 FullO3CPU
<Impl
>::serialize(std::ostream
&os
)
1080 Drainable::State
so_state(getDrainState());
1081 SERIALIZE_ENUM(so_state
);
1082 BaseCPU::serialize(os
);
1083 nameOut(os
, csprintf("%s.tickEvent", name()));
1084 tickEvent
.serialize(os
);
1086 // Use SimpleThread's ability to checkpoint to make it easier to
1087 // write out the registers. Also make this static so it doesn't
1088 // get instantiated multiple times (causes a panic in statistics).
1089 static SimpleThread temp
;
1091 ThreadID size
= thread
.size();
1092 for (ThreadID i
= 0; i
< size
; i
++) {
1093 nameOut(os
, csprintf("%s.xc.%i", name(), i
));
1094 temp
.copyTC(thread
[i
]->getTC());
1099 template <class Impl
>
1101 FullO3CPU
<Impl
>::unserialize(Checkpoint
*cp
, const std::string
§ion
)
1103 Drainable::State so_state
;
1104 UNSERIALIZE_ENUM(so_state
);
1105 BaseCPU::unserialize(cp
, section
);
1106 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
1108 // Use SimpleThread's ability to checkpoint to make it easier to
1109 // read in the registers. Also make this static so it doesn't
1110 // get instantiated multiple times (causes a panic in statistics).
1111 static SimpleThread temp
;
1113 ThreadID size
= thread
.size();
1114 for (ThreadID i
= 0; i
< size
; i
++) {
1115 temp
.copyTC(thread
[i
]->getTC());
1116 temp
.unserialize(cp
, csprintf("%s.xc.%i", section
, i
));
1117 thread
[i
]->getTC()->copyArchRegs(temp
.getTC());
1121 template <class Impl
>
1123 FullO3CPU
<Impl
>::drain(DrainManager
*drain_manager
)
1125 DPRINTF(O3CPU
, "Switching out\n");
1127 // If the CPU isn't doing anything, then return immediately.
1128 if (_status
== SwitchedOut
)
1138 // Wake the CPU and record activity so everything can drain out if
1139 // the CPU was not able to immediately drain.
1140 if (getDrainState() != Drainable::Drained
) {
1141 // A bit of a hack...set the drainManager after all the drain()
1142 // calls have been made, that way if all of the stages drain
1143 // immediately, the signalDrained() function knows not to call
1144 // process on the drain event.
1145 drainManager
= drain_manager
;
1148 activityRec
.activity();
1150 DPRINTF(Drain
, "CPU not drained\n");
1158 template <class Impl
>
1160 FullO3CPU
<Impl
>::drainResume()
1168 setDrainState(Drainable::Running
);
1170 if (_status
== SwitchedOut
)
1173 assert(system
->getMemoryMode() == Enums::timing
);
1175 if (!tickEvent
.scheduled())
1176 schedule(tickEvent
, nextCycle());
1180 template <class Impl
>
1182 FullO3CPU
<Impl
>::signalDrained()
1184 if (++drainCount
== NumStages
) {
1185 if (tickEvent
.scheduled())
1188 setDrainState(Drainable::Drained
);
1190 BaseCPU::switchOut();
1193 DPRINTF(Drain
, "CPU done draining, processing drain event\n");
1194 drainManager
->signalDrainDone();
1195 drainManager
= NULL
;
1198 assert(drainCount
<= 5);
1201 template <class Impl
>
1203 FullO3CPU
<Impl
>::switchOut()
1210 while (!removeList
.empty()) {
1214 _status
= SwitchedOut
;
1217 checker
->switchOut();
1219 if (tickEvent
.scheduled())
1223 template <class Impl
>
1225 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
1227 // Flush out any old data from the time buffers.
1228 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
1229 timeBuffer
.advance();
1230 fetchQueue
.advance();
1231 decodeQueue
.advance();
1232 renameQueue
.advance();
1236 activityRec
.reset();
1238 BaseCPU::takeOverFrom(oldCPU
);
1240 fetch
.takeOverFrom();
1241 decode
.takeOverFrom();
1242 rename
.takeOverFrom();
1244 commit
.takeOverFrom();
1246 assert(!tickEvent
.scheduled() || tickEvent
.squashed());
1248 FullO3CPU
<Impl
> *oldO3CPU
= dynamic_cast<FullO3CPU
<Impl
>*>(oldCPU
);
1250 globalSeqNum
= oldO3CPU
->globalSeqNum
;
1252 // @todo: Figure out how to properly select the tid to put onto
1253 // the active threads list.
1256 list
<ThreadID
>::iterator isActive
=
1257 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
1259 if (isActive
== activeThreads
.end()) {
1260 //May Need to Re-code this if the delay variable is the delay
1261 //needed for thread to activate
1262 DPRINTF(O3CPU
, "Adding Thread %i to active threads list\n",
1265 activeThreads
.push_back(tid
);
1268 // Set all statuses to active, schedule the CPU's tick event.
1269 // @todo: Fix up statuses so this is handled properly
1270 ThreadID size
= threadContexts
.size();
1271 for (ThreadID i
= 0; i
< size
; ++i
) {
1272 ThreadContext
*tc
= threadContexts
[i
];
1273 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
1275 reschedule(tickEvent
, nextCycle(), true);
1278 if (!tickEvent
.scheduled())
1279 schedule(tickEvent
, nextCycle());
1281 lastRunningCycle
= curCycle();
1284 template <class Impl
>
1286 FullO3CPU
<Impl
>::readMiscRegNoEffect(int misc_reg
, ThreadID tid
)
1288 return this->isa
[tid
].readMiscRegNoEffect(misc_reg
);
1291 template <class Impl
>
1293 FullO3CPU
<Impl
>::readMiscReg(int misc_reg
, ThreadID tid
)
1296 return this->isa
[tid
].readMiscReg(misc_reg
, tcBase(tid
));
1299 template <class Impl
>
1301 FullO3CPU
<Impl
>::setMiscRegNoEffect(int misc_reg
,
1302 const TheISA::MiscReg
&val
, ThreadID tid
)
1304 this->isa
[tid
].setMiscRegNoEffect(misc_reg
, val
);
1307 template <class Impl
>
1309 FullO3CPU
<Impl
>::setMiscReg(int misc_reg
,
1310 const TheISA::MiscReg
&val
, ThreadID tid
)
1312 miscRegfileWrites
++;
1313 this->isa
[tid
].setMiscReg(misc_reg
, val
, tcBase(tid
));
1316 template <class Impl
>
1318 FullO3CPU
<Impl
>::readIntReg(int reg_idx
)
1321 return regFile
.readIntReg(reg_idx
);
1324 template <class Impl
>
1326 FullO3CPU
<Impl
>::readFloatReg(int reg_idx
)
1329 return regFile
.readFloatReg(reg_idx
);
1332 template <class Impl
>
1334 FullO3CPU
<Impl
>::readFloatRegBits(int reg_idx
)
1337 return regFile
.readFloatRegBits(reg_idx
);
1340 template <class Impl
>
1342 FullO3CPU
<Impl
>::setIntReg(int reg_idx
, uint64_t val
)
1345 regFile
.setIntReg(reg_idx
, val
);
1348 template <class Impl
>
1350 FullO3CPU
<Impl
>::setFloatReg(int reg_idx
, FloatReg val
)
1353 regFile
.setFloatReg(reg_idx
, val
);
1356 template <class Impl
>
1358 FullO3CPU
<Impl
>::setFloatRegBits(int reg_idx
, FloatRegBits val
)
1361 regFile
.setFloatRegBits(reg_idx
, val
);
1364 template <class Impl
>
1366 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, ThreadID tid
)
1369 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1371 return regFile
.readIntReg(phys_reg
);
1374 template <class Impl
>
1376 FullO3CPU
<Impl
>::readArchFloatReg(int reg_idx
, ThreadID tid
)
1379 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1380 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1382 return regFile
.readFloatReg(phys_reg
);
1385 template <class Impl
>
1387 FullO3CPU
<Impl
>::readArchFloatRegInt(int reg_idx
, ThreadID tid
)
1390 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1391 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1393 return regFile
.readFloatRegBits(phys_reg
);
1396 template <class Impl
>
1398 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, uint64_t val
, ThreadID tid
)
1401 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1403 regFile
.setIntReg(phys_reg
, val
);
1406 template <class Impl
>
1408 FullO3CPU
<Impl
>::setArchFloatReg(int reg_idx
, float val
, ThreadID tid
)
1411 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1412 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1414 regFile
.setFloatReg(phys_reg
, val
);
1417 template <class Impl
>
1419 FullO3CPU
<Impl
>::setArchFloatRegInt(int reg_idx
, uint64_t val
, ThreadID tid
)
1422 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1423 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1425 regFile
.setFloatRegBits(phys_reg
, val
);
1428 template <class Impl
>
1430 FullO3CPU
<Impl
>::pcState(ThreadID tid
)
1432 return commit
.pcState(tid
);
1435 template <class Impl
>
1437 FullO3CPU
<Impl
>::pcState(const TheISA::PCState
&val
, ThreadID tid
)
1439 commit
.pcState(val
, tid
);
1442 template <class Impl
>
1444 FullO3CPU
<Impl
>::instAddr(ThreadID tid
)
1446 return commit
.instAddr(tid
);
1449 template <class Impl
>
1451 FullO3CPU
<Impl
>::nextInstAddr(ThreadID tid
)
1453 return commit
.nextInstAddr(tid
);
1456 template <class Impl
>
1458 FullO3CPU
<Impl
>::microPC(ThreadID tid
)
1460 return commit
.microPC(tid
);
1463 template <class Impl
>
1465 FullO3CPU
<Impl
>::squashFromTC(ThreadID tid
)
1467 this->thread
[tid
]->inSyscall
= true;
1468 this->commit
.generateTCEvent(tid
);
1471 template <class Impl
>
1472 typename FullO3CPU
<Impl
>::ListIt
1473 FullO3CPU
<Impl
>::addInst(DynInstPtr
&inst
)
1475 instList
.push_back(inst
);
1477 return --(instList
.end());
1480 template <class Impl
>
1482 FullO3CPU
<Impl
>::instDone(ThreadID tid
, DynInstPtr
&inst
)
1484 // Keep an instruction count.
1485 if (!inst
->isMicroop() || inst
->isLastMicroop()) {
1486 thread
[tid
]->numInst
++;
1487 thread
[tid
]->numInsts
++;
1488 committedInsts
[tid
]++;
1489 totalCommittedInsts
++;
1491 thread
[tid
]->numOp
++;
1492 thread
[tid
]->numOps
++;
1493 committedOps
[tid
]++;
1495 system
->totalNumInsts
++;
1496 // Check for instruction-count-based events.
1497 comInstEventQueue
[tid
]->serviceEvents(thread
[tid
]->numInst
);
1498 system
->instEventQueue
.serviceEvents(system
->totalNumInsts
);
1501 template <class Impl
>
1503 FullO3CPU
<Impl
>::removeFrontInst(DynInstPtr
&inst
)
1505 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %s "
1507 inst
->threadNumber
, inst
->pcState(), inst
->seqNum
);
1509 removeInstsThisCycle
= true;
1511 // Remove the front instruction.
1512 removeList
.push(inst
->getInstListIt());
1515 template <class Impl
>
1517 FullO3CPU
<Impl
>::removeInstsNotInROB(ThreadID tid
)
1519 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1524 bool rob_empty
= false;
1526 if (instList
.empty()) {
1528 } else if (rob
.isEmpty(/*tid*/)) {
1529 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1530 end_it
= instList
.begin();
1533 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1534 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1537 removeInstsThisCycle
= true;
1539 ListIt inst_it
= instList
.end();
1543 // Walk through the instruction list, removing any instructions
1544 // that were inserted after the given instruction iterator, end_it.
1545 while (inst_it
!= end_it
) {
1546 assert(!instList
.empty());
1548 squashInstIt(inst_it
, tid
);
1553 // If the ROB was empty, then we actually need to remove the first
1554 // instruction as well.
1556 squashInstIt(inst_it
, tid
);
1560 template <class Impl
>
1562 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
, ThreadID tid
)
1564 assert(!instList
.empty());
1566 removeInstsThisCycle
= true;
1568 ListIt inst_iter
= instList
.end();
1572 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1573 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1574 tid
, seq_num
, (*inst_iter
)->seqNum
);
1576 while ((*inst_iter
)->seqNum
> seq_num
) {
1578 bool break_loop
= (inst_iter
== instList
.begin());
1580 squashInstIt(inst_iter
, tid
);
1589 template <class Impl
>
1591 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, ThreadID tid
)
1593 if ((*instIt
)->threadNumber
== tid
) {
1594 DPRINTF(O3CPU
, "Squashing instruction, "
1595 "[tid:%i] [sn:%lli] PC %s\n",
1596 (*instIt
)->threadNumber
,
1598 (*instIt
)->pcState());
1600 // Mark it as squashed.
1601 (*instIt
)->setSquashed();
1603 // @todo: Formulate a consistent method for deleting
1604 // instructions from the instruction list
1605 // Remove the instruction from the list.
1606 removeList
.push(instIt
);
1610 template <class Impl
>
1612 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1614 while (!removeList
.empty()) {
1615 DPRINTF(O3CPU
, "Removing instruction, "
1616 "[tid:%i] [sn:%lli] PC %s\n",
1617 (*removeList
.front())->threadNumber
,
1618 (*removeList
.front())->seqNum
,
1619 (*removeList
.front())->pcState());
1621 instList
.erase(removeList
.front());
1626 removeInstsThisCycle
= false;
1629 template <class Impl>
1631 FullO3CPU<Impl>::removeAllInsts()
1636 template <class Impl
>
1638 FullO3CPU
<Impl
>::dumpInsts()
1642 ListIt inst_list_it
= instList
.begin();
1644 cprintf("Dumping Instruction List\n");
1646 while (inst_list_it
!= instList
.end()) {
1647 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1649 num
, (*inst_list_it
)->instAddr(), (*inst_list_it
)->threadNumber
,
1650 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1651 (*inst_list_it
)->isSquashed());
1657 template <class Impl>
1659 FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
1661 iew.wakeDependents(inst);
1664 template <class Impl
>
1666 FullO3CPU
<Impl
>::wakeCPU()
1668 if (activityRec
.active() || tickEvent
.scheduled()) {
1669 DPRINTF(Activity
, "CPU already running.\n");
1673 DPRINTF(Activity
, "Waking up CPU\n");
1675 Cycles
cycles(curCycle() - lastRunningCycle
);
1676 // @todo: This is an oddity that is only here to match the stats
1679 idleCycles
+= cycles
;
1680 numCycles
+= cycles
;
1682 schedule(tickEvent
, nextCycle());
1685 template <class Impl
>
1687 FullO3CPU
<Impl
>::wakeup()
1689 if (this->thread
[0]->status() != ThreadContext::Suspended
)
1694 DPRINTF(Quiesce
, "Suspended Processor woken\n");
1695 this->threadContexts
[0]->activate();
1698 template <class Impl
>
1700 FullO3CPU
<Impl
>::getFreeTid()
1702 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
1709 return InvalidThreadID
;
1712 template <class Impl
>
1714 FullO3CPU
<Impl
>::doContextSwitch()
1716 if (contextSwitch
) {
1718 //ADD CODE TO DEACTIVE THREAD HERE (???)
1720 ThreadID size
= cpuWaitList
.size();
1721 for (ThreadID tid
= 0; tid
< size
; tid
++) {
1722 activateWhenReady(tid
);
1725 if (cpuWaitList
.size() == 0)
1726 contextSwitch
= true;
1730 template <class Impl
>
1732 FullO3CPU
<Impl
>::updateThreadPriority()
1734 if (activeThreads
.size() > 1) {
1735 //DEFAULT TO ROUND ROBIN SCHEME
1736 //e.g. Move highest priority to end of thread list
1737 list
<ThreadID
>::iterator list_begin
= activeThreads
.begin();
1739 unsigned high_thread
= *list_begin
;
1741 activeThreads
.erase(list_begin
);
1743 activeThreads
.push_back(high_thread
);
1747 // Forward declaration of FullO3CPU.
1748 template class FullO3CPU
<O3CPUImpl
>;