2 * Copyright (c) 2011-2012, 2014, 2016, 2017, 2019 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
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.
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.
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.
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.
43 #include "cpu/o3/cpu.hh"
45 #include "arch/generic/traits.hh"
46 #include "config/the_isa.hh"
47 #include "cpu/activity.hh"
48 #include "cpu/checker/cpu.hh"
49 #include "cpu/checker/thread_context.hh"
50 #include "cpu/o3/isa_specific.hh"
51 #include "cpu/o3/thread_context.hh"
52 #include "cpu/simple_thread.hh"
53 #include "cpu/thread_context.hh"
54 #include "debug/Activity.hh"
55 #include "debug/Drain.hh"
56 #include "debug/O3CPU.hh"
57 #include "debug/Quiesce.hh"
58 #include "enums/MemoryMode.hh"
59 #include "sim/core.hh"
60 #include "sim/full_system.hh"
61 #include "sim/process.hh"
62 #include "sim/stat_control.hh"
63 #include "sim/system.hh"
67 using namespace TheISA
;
70 BaseO3CPU::BaseO3CPU(BaseCPUParams
*params
)
82 FullO3CPU
<Impl
>::FullO3CPU(DerivO3CPUParams
*params
)
86 tickEvent([this]{ tick(); }, "FullO3CPU tick",
87 false, Event::CPU_Tick_Pri
),
88 threadExitEvent([this]{ exitThreads(); }, "FullO3CPU exit threads",
89 false, Event::CPU_Exit_Pri
),
93 removeInstsThisCycle(false),
100 /* It is mandatory that all SMT threads use the same renaming mode as
101 * they are sharing registers and rename */
102 vecMode(RenameMode
<TheISA::ISA
>::init(params
->isa
[0])),
103 regFile(params
->numPhysIntRegs
,
104 params
->numPhysFloatRegs
,
105 params
->numPhysVecRegs
,
106 params
->numPhysVecPredRegs
,
107 params
->numPhysCCRegs
,
110 freeList(name() + ".freelist", ®File
),
114 scoreboard(name() + ".scoreboard",
115 regFile
.totalNumPhysRegs()),
117 isa(numThreads
, NULL
),
119 timeBuffer(params
->backComSize
, params
->forwardComSize
),
120 fetchQueue(params
->backComSize
, params
->forwardComSize
),
121 decodeQueue(params
->backComSize
, params
->forwardComSize
),
122 renameQueue(params
->backComSize
, params
->forwardComSize
),
123 iewQueue(params
->backComSize
, params
->forwardComSize
),
124 activityRec(name(), NumStages
,
125 params
->backComSize
+ params
->forwardComSize
,
129 system(params
->system
),
130 lastRunningCycle(curCycle())
132 if (!params
->switched_out
) {
135 _status
= SwitchedOut
;
138 if (params
->checker
) {
139 BaseCPU
*temp_checker
= params
->checker
;
140 checker
= dynamic_cast<Checker
<Impl
> *>(temp_checker
);
141 checker
->setIcachePort(&this->fetch
.getInstPort());
142 checker
->setSystem(params
->system
);
148 thread
.resize(numThreads
);
149 tids
.resize(numThreads
);
152 // The stages also need their CPU pointer setup. However this
153 // must be done at the upper level CPU because they have pointers
154 // to the upper level CPU, and not this FullO3CPU.
156 // Set up Pointers to the activeThreads list for each stage
157 fetch
.setActiveThreads(&activeThreads
);
158 decode
.setActiveThreads(&activeThreads
);
159 rename
.setActiveThreads(&activeThreads
);
160 iew
.setActiveThreads(&activeThreads
);
161 commit
.setActiveThreads(&activeThreads
);
163 // Give each of the stages the time buffer they will use.
164 fetch
.setTimeBuffer(&timeBuffer
);
165 decode
.setTimeBuffer(&timeBuffer
);
166 rename
.setTimeBuffer(&timeBuffer
);
167 iew
.setTimeBuffer(&timeBuffer
);
168 commit
.setTimeBuffer(&timeBuffer
);
170 // Also setup each of the stages' queues.
171 fetch
.setFetchQueue(&fetchQueue
);
172 decode
.setFetchQueue(&fetchQueue
);
173 commit
.setFetchQueue(&fetchQueue
);
174 decode
.setDecodeQueue(&decodeQueue
);
175 rename
.setDecodeQueue(&decodeQueue
);
176 rename
.setRenameQueue(&renameQueue
);
177 iew
.setRenameQueue(&renameQueue
);
178 iew
.setIEWQueue(&iewQueue
);
179 commit
.setIEWQueue(&iewQueue
);
180 commit
.setRenameQueue(&renameQueue
);
182 commit
.setIEWStage(&iew
);
183 rename
.setIEWStage(&iew
);
184 rename
.setCommitStage(&commit
);
186 ThreadID active_threads
;
190 active_threads
= params
->workload
.size();
192 if (active_threads
> Impl::MaxThreads
) {
193 panic("Workload Size too large. Increase the 'MaxThreads' "
194 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
195 "or edit your workload size.");
199 //Make Sure That this a Valid Architeture
200 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
201 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
202 assert(params
->numPhysVecRegs
>= numThreads
* TheISA::NumVecRegs
);
203 assert(params
->numPhysVecPredRegs
>= numThreads
* TheISA::NumVecPredRegs
);
204 assert(params
->numPhysCCRegs
>= numThreads
* TheISA::NumCCRegs
);
206 rename
.setScoreboard(&scoreboard
);
207 iew
.setScoreboard(&scoreboard
);
209 // Setup the rename map for whichever stages need it.
210 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
211 isa
[tid
] = dynamic_cast<TheISA::ISA
*>(params
->isa
[tid
]);
213 assert(RenameMode
<TheISA::ISA
>::equalsInit(isa
[tid
], isa
[0]));
215 // Only Alpha has an FP zero register, so for other ISAs we
216 // use an invalid FP register index to avoid special treatment
217 // of any valid FP reg.
218 RegIndex invalidFPReg
= TheISA::NumFloatRegs
+ 1;
220 commitRenameMap
[tid
].init(®File
, TheISA::ZeroReg
, invalidFPReg
,
223 renameMap
[tid
].init(®File
, TheISA::ZeroReg
, invalidFPReg
,
227 // Initialize rename map to assign physical registers to the
228 // architectural registers for active threads only.
229 for (ThreadID tid
= 0; tid
< active_threads
; tid
++) {
230 for (RegIndex ridx
= 0; ridx
< TheISA::NumIntRegs
; ++ridx
) {
231 // Note that we can't use the rename() method because we don't
232 // want special treatment for the zero register at this point
233 PhysRegIdPtr phys_reg
= freeList
.getIntReg();
234 renameMap
[tid
].setEntry(RegId(IntRegClass
, ridx
), phys_reg
);
235 commitRenameMap
[tid
].setEntry(RegId(IntRegClass
, ridx
), phys_reg
);
238 for (RegIndex ridx
= 0; ridx
< TheISA::NumFloatRegs
; ++ridx
) {
239 PhysRegIdPtr phys_reg
= freeList
.getFloatReg();
240 renameMap
[tid
].setEntry(RegId(FloatRegClass
, ridx
), phys_reg
);
241 commitRenameMap
[tid
].setEntry(
242 RegId(FloatRegClass
, ridx
), phys_reg
);
245 /* Here we need two 'interfaces' the 'whole register' and the
246 * 'register element'. At any point only one of them will be
248 if (vecMode
== Enums::Full
) {
249 /* Initialize the full-vector interface */
250 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecRegs
; ++ridx
) {
251 RegId rid
= RegId(VecRegClass
, ridx
);
252 PhysRegIdPtr phys_reg
= freeList
.getVecReg();
253 renameMap
[tid
].setEntry(rid
, phys_reg
);
254 commitRenameMap
[tid
].setEntry(rid
, phys_reg
);
257 /* Initialize the vector-element interface */
258 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecRegs
; ++ridx
) {
259 for (ElemIndex ldx
= 0; ldx
< TheISA::NumVecElemPerVecReg
;
261 RegId lrid
= RegId(VecElemClass
, ridx
, ldx
);
262 PhysRegIdPtr phys_elem
= freeList
.getVecElem();
263 renameMap
[tid
].setEntry(lrid
, phys_elem
);
264 commitRenameMap
[tid
].setEntry(lrid
, phys_elem
);
269 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecPredRegs
; ++ridx
) {
270 PhysRegIdPtr phys_reg
= freeList
.getVecPredReg();
271 renameMap
[tid
].setEntry(RegId(VecPredRegClass
, ridx
), phys_reg
);
272 commitRenameMap
[tid
].setEntry(
273 RegId(VecPredRegClass
, ridx
), phys_reg
);
276 for (RegIndex ridx
= 0; ridx
< TheISA::NumCCRegs
; ++ridx
) {
277 PhysRegIdPtr phys_reg
= freeList
.getCCReg();
278 renameMap
[tid
].setEntry(RegId(CCRegClass
, ridx
), phys_reg
);
279 commitRenameMap
[tid
].setEntry(RegId(CCRegClass
, ridx
), phys_reg
);
283 rename
.setRenameMap(renameMap
);
284 commit
.setRenameMap(commitRenameMap
);
285 rename
.setFreeList(&freeList
);
287 // Setup the ROB for whichever stages need it.
290 lastActivatedCycle
= 0;
292 DPRINTF(O3CPU
, "Creating O3CPU object.\n");
294 // Setup any thread state.
295 this->thread
.resize(this->numThreads
);
297 for (ThreadID tid
= 0; tid
< this->numThreads
; ++tid
) {
299 // SMT is not supported in FS mode yet.
300 assert(this->numThreads
== 1);
301 this->thread
[tid
] = new Thread(this, 0, NULL
);
303 if (tid
< params
->workload
.size()) {
304 DPRINTF(O3CPU
, "Workload[%i] process is %#x",
305 tid
, this->thread
[tid
]);
306 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
307 (typename
Impl::O3CPU
*)(this),
308 tid
, params
->workload
[tid
]);
310 //usedTids[tid] = true;
311 //threadMap[tid] = tid;
313 //Allocate Empty thread so M5 can use later
314 //when scheduling threads to CPU
315 Process
* dummy_proc
= NULL
;
317 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
318 (typename
Impl::O3CPU
*)(this),
320 //usedTids[tid] = false;
326 // Setup the TC that will serve as the interface to the threads/CPU.
327 O3ThreadContext
<Impl
> *o3_tc
= new O3ThreadContext
<Impl
>;
331 // If we're using a checker, then the TC should be the
332 // CheckerThreadContext.
333 if (params
->checker
) {
334 tc
= new CheckerThreadContext
<O3ThreadContext
<Impl
> >(
335 o3_tc
, this->checker
);
338 o3_tc
->cpu
= (typename
Impl::O3CPU
*)(this);
340 o3_tc
->thread
= this->thread
[tid
];
342 // Give the thread the TC.
343 this->thread
[tid
]->tc
= tc
;
345 // Add the TC to the CPU's list of TC's.
346 this->threadContexts
.push_back(tc
);
349 // FullO3CPU always requires an interrupt controller.
350 if (!params
->switched_out
&& interrupts
.empty()) {
351 fatal("FullO3CPU %s has no interrupt controller.\n"
352 "Ensure createInterruptController() is called.\n", name());
355 for (ThreadID tid
= 0; tid
< this->numThreads
; tid
++)
356 this->thread
[tid
]->setFuncExeInst(0);
359 template <class Impl
>
360 FullO3CPU
<Impl
>::~FullO3CPU()
364 template <class Impl
>
366 FullO3CPU
<Impl
>::regProbePoints()
368 BaseCPU::regProbePoints();
370 ppInstAccessComplete
= new ProbePointArg
<PacketPtr
>(getProbeManager(), "InstAccessComplete");
371 ppDataAccessComplete
= new ProbePointArg
<std::pair
<DynInstPtr
, PacketPtr
> >(getProbeManager(), "DataAccessComplete");
373 fetch
.regProbePoints();
374 rename
.regProbePoints();
375 iew
.regProbePoints();
376 commit
.regProbePoints();
379 template <class Impl
>
381 FullO3CPU
<Impl
>::regStats()
383 BaseO3CPU::regStats();
385 // Register any of the O3CPU's stats here.
387 .name(name() + ".timesIdled")
388 .desc("Number of times that the entire CPU went into an idle state and"
389 " unscheduled itself")
393 .name(name() + ".idleCycles")
394 .desc("Total number of cycles that the CPU has spent unscheduled due "
399 .name(name() + ".quiesceCycles")
400 .desc("Total number of cycles that CPU has spent quiesced or waiting "
402 .prereq(quiesceCycles
);
404 // Number of Instructions simulated
405 // --------------------------------
406 // Should probably be in Base CPU but need templated
407 // MaxThreads so put in here instead
410 .name(name() + ".committedInsts")
411 .desc("Number of Instructions Simulated")
412 .flags(Stats::total
);
416 .name(name() + ".committedOps")
417 .desc("Number of Ops (including micro ops) Simulated")
418 .flags(Stats::total
);
421 .name(name() + ".cpi")
422 .desc("CPI: Cycles Per Instruction")
424 cpi
= numCycles
/ committedInsts
;
427 .name(name() + ".cpi_total")
428 .desc("CPI: Total CPI of All Threads")
430 totalCpi
= numCycles
/ sum(committedInsts
);
433 .name(name() + ".ipc")
434 .desc("IPC: Instructions Per Cycle")
436 ipc
= committedInsts
/ numCycles
;
439 .name(name() + ".ipc_total")
440 .desc("IPC: Total IPC of All Threads")
442 totalIpc
= sum(committedInsts
) / numCycles
;
444 this->decode
.regStats();
445 this->rename
.regStats();
446 this->iew
.regStats();
447 this->commit
.regStats();
448 this->rob
.regStats();
451 .name(name() + ".int_regfile_reads")
452 .desc("number of integer regfile reads")
453 .prereq(intRegfileReads
);
456 .name(name() + ".int_regfile_writes")
457 .desc("number of integer regfile writes")
458 .prereq(intRegfileWrites
);
461 .name(name() + ".fp_regfile_reads")
462 .desc("number of floating regfile reads")
463 .prereq(fpRegfileReads
);
466 .name(name() + ".fp_regfile_writes")
467 .desc("number of floating regfile writes")
468 .prereq(fpRegfileWrites
);
471 .name(name() + ".vec_regfile_reads")
472 .desc("number of vector regfile reads")
473 .prereq(vecRegfileReads
);
476 .name(name() + ".vec_regfile_writes")
477 .desc("number of vector regfile writes")
478 .prereq(vecRegfileWrites
);
481 .name(name() + ".pred_regfile_reads")
482 .desc("number of predicate regfile reads")
483 .prereq(vecPredRegfileReads
);
486 .name(name() + ".pred_regfile_writes")
487 .desc("number of predicate regfile writes")
488 .prereq(vecPredRegfileWrites
);
491 .name(name() + ".cc_regfile_reads")
492 .desc("number of cc regfile reads")
493 .prereq(ccRegfileReads
);
496 .name(name() + ".cc_regfile_writes")
497 .desc("number of cc regfile writes")
498 .prereq(ccRegfileWrites
);
501 .name(name() + ".misc_regfile_reads")
502 .desc("number of misc regfile reads")
503 .prereq(miscRegfileReads
);
506 .name(name() + ".misc_regfile_writes")
507 .desc("number of misc regfile writes")
508 .prereq(miscRegfileWrites
);
511 template <class Impl
>
513 FullO3CPU
<Impl
>::tick()
515 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
516 assert(!switchedOut());
517 assert(drainState() != DrainState::Drained
);
520 updateCycleCounters(BaseCPU::CPU_STATE_ON
);
524 //Tick each of the stages
535 // Now advance the time buffers
536 timeBuffer
.advance();
538 fetchQueue
.advance();
539 decodeQueue
.advance();
540 renameQueue
.advance();
543 activityRec
.advance();
545 if (removeInstsThisCycle
) {
546 cleanUpRemovedInsts();
549 if (!tickEvent
.scheduled()) {
550 if (_status
== SwitchedOut
) {
551 DPRINTF(O3CPU
, "Switched out!\n");
553 lastRunningCycle
= curCycle();
554 } else if (!activityRec
.active() || _status
== Idle
) {
555 DPRINTF(O3CPU
, "Idle!\n");
556 lastRunningCycle
= curCycle();
559 schedule(tickEvent
, clockEdge(Cycles(1)));
560 DPRINTF(O3CPU
, "Scheduling next tick!\n");
565 updateThreadPriority();
570 template <class Impl
>
572 FullO3CPU
<Impl
>::init()
576 for (ThreadID tid
= 0; tid
< numThreads
; ++tid
) {
577 // Set noSquashFromTC so that the CPU doesn't squash when initially
578 // setting up registers.
579 thread
[tid
]->noSquashFromTC
= true;
580 // Initialise the ThreadContext's memory proxies
581 thread
[tid
]->initMemProxies(thread
[tid
]->getTC());
584 // Clear noSquashFromTC.
585 for (int tid
= 0; tid
< numThreads
; ++tid
)
586 thread
[tid
]->noSquashFromTC
= false;
588 commit
.setThreads(thread
);
591 template <class Impl
>
593 FullO3CPU
<Impl
>::startup()
597 fetch
.startupStage();
598 decode
.startupStage();
600 rename
.startupStage();
601 commit
.startupStage();
604 template <class Impl
>
606 FullO3CPU
<Impl
>::activateThread(ThreadID tid
)
608 list
<ThreadID
>::iterator isActive
=
609 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
611 DPRINTF(O3CPU
, "[tid:%i] Calling activate thread.\n", tid
);
612 assert(!switchedOut());
614 if (isActive
== activeThreads
.end()) {
615 DPRINTF(O3CPU
, "[tid:%i] Adding to active threads list\n",
618 activeThreads
.push_back(tid
);
622 template <class Impl
>
624 FullO3CPU
<Impl
>::deactivateThread(ThreadID tid
)
626 //Remove From Active List, if Active
627 list
<ThreadID
>::iterator thread_it
=
628 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
630 DPRINTF(O3CPU
, "[tid:%i] Calling deactivate thread.\n", tid
);
631 assert(!switchedOut());
633 if (thread_it
!= activeThreads
.end()) {
634 DPRINTF(O3CPU
,"[tid:%i] Removing from active threads list\n",
636 activeThreads
.erase(thread_it
);
639 fetch
.deactivateThread(tid
);
640 commit
.deactivateThread(tid
);
643 template <class Impl
>
645 FullO3CPU
<Impl
>::totalInsts() const
649 ThreadID size
= thread
.size();
650 for (ThreadID i
= 0; i
< size
; i
++)
651 total
+= thread
[i
]->numInst
;
656 template <class Impl
>
658 FullO3CPU
<Impl
>::totalOps() const
662 ThreadID size
= thread
.size();
663 for (ThreadID i
= 0; i
< size
; i
++)
664 total
+= thread
[i
]->numOp
;
669 template <class Impl
>
671 FullO3CPU
<Impl
>::activateContext(ThreadID tid
)
673 assert(!switchedOut());
675 // Needs to set each stage to running as well.
678 // We don't want to wake the CPU if it is drained. In that case,
679 // we just want to flag the thread as active and schedule the tick
680 // event from drainResume() instead.
681 if (drainState() == DrainState::Drained
)
684 // If we are time 0 or if the last activation time is in the past,
685 // schedule the next tick and wake up the fetch unit
686 if (lastActivatedCycle
== 0 || lastActivatedCycle
< curTick()) {
687 scheduleTickEvent(Cycles(0));
689 // Be sure to signal that there's some activity so the CPU doesn't
690 // deschedule itself.
691 activityRec
.activity();
692 fetch
.wakeFromQuiesce();
694 Cycles
cycles(curCycle() - lastRunningCycle
);
695 // @todo: This is an oddity that is only here to match the stats
698 quiesceCycles
+= cycles
;
700 lastActivatedCycle
= curTick();
704 BaseCPU::activateContext(tid
);
708 template <class Impl
>
710 FullO3CPU
<Impl
>::suspendContext(ThreadID tid
)
712 DPRINTF(O3CPU
,"[tid:%i] Suspending Thread Context.\n", tid
);
713 assert(!switchedOut());
715 deactivateThread(tid
);
717 // If this was the last thread then unschedule the tick event.
718 if (activeThreads
.size() == 0) {
719 unscheduleTickEvent();
720 lastRunningCycle
= curCycle();
724 DPRINTF(Quiesce
, "Suspending Context\n");
726 BaseCPU::suspendContext(tid
);
729 template <class Impl
>
731 FullO3CPU
<Impl
>::haltContext(ThreadID tid
)
733 //For now, this is the same as deallocate
734 DPRINTF(O3CPU
,"[tid:%i] Halt Context called. Deallocating\n", tid
);
735 assert(!switchedOut());
737 deactivateThread(tid
);
740 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP
);
743 template <class Impl
>
745 FullO3CPU
<Impl
>::insertThread(ThreadID tid
)
747 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
748 // Will change now that the PC and thread state is internal to the CPU
749 // and not in the ThreadContext.
750 ThreadContext
*src_tc
;
752 src_tc
= system
->threads
[tid
];
754 src_tc
= tcBase(tid
);
756 //Bind Int Regs to Rename Map
758 for (RegId
reg_id(IntRegClass
, 0); reg_id
.index() < TheISA::NumIntRegs
;
760 PhysRegIdPtr phys_reg
= freeList
.getIntReg();
761 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
762 scoreboard
.setReg(phys_reg
);
765 //Bind Float Regs to Rename Map
766 for (RegId
reg_id(FloatRegClass
, 0); reg_id
.index() < TheISA::NumFloatRegs
;
768 PhysRegIdPtr phys_reg
= freeList
.getFloatReg();
769 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
770 scoreboard
.setReg(phys_reg
);
773 //Bind condition-code Regs to Rename Map
774 for (RegId
reg_id(CCRegClass
, 0); reg_id
.index() < TheISA::NumCCRegs
;
776 PhysRegIdPtr phys_reg
= freeList
.getCCReg();
777 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
778 scoreboard
.setReg(phys_reg
);
781 //Copy Thread Data Into RegFile
782 //this->copyFromTC(tid);
785 pcState(src_tc
->pcState(), tid
);
787 src_tc
->setStatus(ThreadContext::Active
);
789 activateContext(tid
);
791 //Reset ROB/IQ/LSQ Entries
792 commit
.rob
->resetEntries();
795 template <class Impl
>
797 FullO3CPU
<Impl
>::removeThread(ThreadID tid
)
799 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
801 // Copy Thread Data From RegFile
802 // If thread is suspended, it might be re-allocated
803 // this->copyToTC(tid);
806 // @todo: 2-27-2008: Fix how we free up rename mappings
807 // here to alleviate the case for double-freeing registers
810 // clear all thread-specific states in each stage of the pipeline
811 // since this thread is going to be completely removed from the CPU
812 commit
.clearStates(tid
);
813 fetch
.clearStates(tid
);
814 decode
.clearStates(tid
);
815 rename
.clearStates(tid
);
816 iew
.clearStates(tid
);
818 // at this step, all instructions in the pipeline should be already
819 // either committed successfully or squashed. All thread-specific
820 // queues in the pipeline must be empty.
821 assert(iew
.instQueue
.getCount(tid
) == 0);
822 assert(iew
.ldstQueue
.getCount(tid
) == 0);
823 assert(commit
.rob
->isEmpty(tid
));
825 // Reset ROB/IQ/LSQ Entries
827 // Commented out for now. This should be possible to do by
828 // telling all the pipeline stages to drain first, and then
829 // checking until the drain completes. Once the pipeline is
830 // drained, call resetEntries(). - 10-09-06 ktlim
832 if (activeThreads.size() >= 1) {
833 commit.rob->resetEntries();
839 template <class Impl
>
841 FullO3CPU
<Impl
>::setVectorsAsReady(ThreadID tid
)
843 if (vecMode
== Enums::Elem
) {
844 for (auto v
= 0; v
< TheISA::NumVecRegs
; v
++)
845 for (auto e
= 0; e
< TheISA::NumVecElemPerVecReg
; e
++)
847 commitRenameMap
[tid
].lookup(
848 RegId(VecElemClass
, v
, e
)
851 } else if (vecMode
== Enums::Full
) {
852 for (auto v
= 0; v
< TheISA::NumVecRegs
; v
++)
854 commitRenameMap
[tid
].lookup(
855 RegId(VecRegClass
, v
)
861 template <class Impl
>
863 FullO3CPU
<Impl
>::switchRenameMode(ThreadID tid
, UnifiedFreeList
* freelist
)
865 auto pc
= this->pcState(tid
);
867 // new_mode is the new vector renaming mode
868 auto new_mode
= RenameMode
<TheISA::ISA
>::mode(pc
);
870 // We update vecMode only if there has been a change
871 if (new_mode
!= vecMode
) {
874 renameMap
[tid
].switchMode(vecMode
);
875 commitRenameMap
[tid
].switchMode(vecMode
);
876 renameMap
[tid
].switchFreeList(freelist
);
877 setVectorsAsReady(tid
);
881 template <class Impl
>
883 FullO3CPU
<Impl
>::getInterrupts()
885 // Check if there are any outstanding interrupts
886 return this->interrupts
[0]->getInterrupt();
889 template <class Impl
>
891 FullO3CPU
<Impl
>::processInterrupts(const Fault
&interrupt
)
893 // Check for interrupts here. For now can copy the code that
894 // exists within isa_fullsys_traits.hh. Also assume that thread 0
895 // is the one that handles the interrupts.
896 // @todo: Possibly consolidate the interrupt checking code.
897 // @todo: Allow other threads to handle interrupts.
899 assert(interrupt
!= NoFault
);
900 this->interrupts
[0]->updateIntrInfo();
902 DPRINTF(O3CPU
, "Interrupt %s being handled\n", interrupt
->name());
903 this->trap(interrupt
, 0, nullptr);
906 template <class Impl
>
908 FullO3CPU
<Impl
>::trap(const Fault
&fault
, ThreadID tid
,
909 const StaticInstPtr
&inst
)
911 // Pass the thread's TC into the invoke method.
912 fault
->invoke(this->threadContexts
[tid
], inst
);
915 template <class Impl
>
917 FullO3CPU
<Impl
>::syscall(ThreadID tid
)
919 DPRINTF(O3CPU
, "[tid:%i] Executing syscall().\n\n", tid
);
921 DPRINTF(Activity
,"Activity: syscall() called.\n");
923 // Temporarily increase this by one to account for the syscall
925 ++(this->thread
[tid
]->funcExeInst
);
927 // Execute the actual syscall.
928 this->thread
[tid
]->syscall();
930 // Decrease funcExeInst by one as the normal commit will handle
932 --(this->thread
[tid
]->funcExeInst
);
935 template <class Impl
>
937 FullO3CPU
<Impl
>::serializeThread(CheckpointOut
&cp
, ThreadID tid
) const
939 thread
[tid
]->serialize(cp
);
942 template <class Impl
>
944 FullO3CPU
<Impl
>::unserializeThread(CheckpointIn
&cp
, ThreadID tid
)
946 thread
[tid
]->unserialize(cp
);
949 template <class Impl
>
951 FullO3CPU
<Impl
>::drain()
953 // Deschedule any power gating event (if any)
954 deschedulePowerGatingEvent();
956 // If the CPU isn't doing anything, then return immediately.
958 return DrainState::Drained
;
960 DPRINTF(Drain
, "Draining...\n");
962 // We only need to signal a drain to the commit stage as this
963 // initiates squashing controls the draining. Once the commit
964 // stage commits an instruction where it is safe to stop, it'll
965 // squash the rest of the instructions in the pipeline and force
966 // the fetch stage to stall. The pipeline will be drained once all
967 // in-flight instructions have retired.
970 // Wake the CPU and record activity so everything can drain out if
971 // the CPU was not able to immediately drain.
972 if (!isCpuDrained()) {
973 // If a thread is suspended, wake it up so it can be drained
974 for (auto t
: threadContexts
) {
975 if (t
->status() == ThreadContext::Suspended
){
976 DPRINTF(Drain
, "Currently suspended so activate %i \n",
979 // As the thread is now active, change the power state as well
980 activateContext(t
->threadId());
985 activityRec
.activity();
987 DPRINTF(Drain
, "CPU not drained\n");
989 return DrainState::Draining
;
991 DPRINTF(Drain
, "CPU is already drained\n");
992 if (tickEvent
.scheduled())
993 deschedule(tickEvent
);
995 // Flush out any old data from the time buffers. In
996 // particular, there might be some data in flight from the
997 // fetch stage that isn't visible in any of the CPU buffers we
998 // test in isCpuDrained().
999 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
1000 timeBuffer
.advance();
1001 fetchQueue
.advance();
1002 decodeQueue
.advance();
1003 renameQueue
.advance();
1008 return DrainState::Drained
;
1012 template <class Impl
>
1014 FullO3CPU
<Impl
>::tryDrain()
1016 if (drainState() != DrainState::Draining
|| !isCpuDrained())
1019 if (tickEvent
.scheduled())
1020 deschedule(tickEvent
);
1022 DPRINTF(Drain
, "CPU done draining, processing drain event\n");
1028 template <class Impl
>
1030 FullO3CPU
<Impl
>::drainSanityCheck() const
1032 assert(isCpuDrained());
1033 fetch
.drainSanityCheck();
1034 decode
.drainSanityCheck();
1035 rename
.drainSanityCheck();
1036 iew
.drainSanityCheck();
1037 commit
.drainSanityCheck();
1040 template <class Impl
>
1042 FullO3CPU
<Impl
>::isCpuDrained() const
1046 if (!instList
.empty() || !removeList
.empty()) {
1047 DPRINTF(Drain
, "Main CPU structures not drained.\n");
1051 if (!fetch
.isDrained()) {
1052 DPRINTF(Drain
, "Fetch not drained.\n");
1056 if (!decode
.isDrained()) {
1057 DPRINTF(Drain
, "Decode not drained.\n");
1061 if (!rename
.isDrained()) {
1062 DPRINTF(Drain
, "Rename not drained.\n");
1066 if (!iew
.isDrained()) {
1067 DPRINTF(Drain
, "IEW not drained.\n");
1071 if (!commit
.isDrained()) {
1072 DPRINTF(Drain
, "Commit not drained.\n");
1079 template <class Impl
>
1081 FullO3CPU
<Impl
>::commitDrained(ThreadID tid
)
1083 fetch
.drainStall(tid
);
1086 template <class Impl
>
1088 FullO3CPU
<Impl
>::drainResume()
1093 DPRINTF(Drain
, "Resuming...\n");
1096 fetch
.drainResume();
1097 commit
.drainResume();
1100 for (ThreadID i
= 0; i
< thread
.size(); i
++) {
1101 if (thread
[i
]->status() == ThreadContext::Active
) {
1102 DPRINTF(Drain
, "Activating thread: %i\n", i
);
1108 assert(!tickEvent
.scheduled());
1109 if (_status
== Running
)
1110 schedule(tickEvent
, nextCycle());
1112 // Reschedule any power gating event (if any)
1113 schedulePowerGatingEvent();
1116 template <class Impl
>
1118 FullO3CPU
<Impl
>::switchOut()
1120 DPRINTF(O3CPU
, "Switching out\n");
1121 BaseCPU::switchOut();
1123 activityRec
.reset();
1125 _status
= SwitchedOut
;
1128 checker
->switchOut();
1131 template <class Impl
>
1133 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
1135 BaseCPU::takeOverFrom(oldCPU
);
1137 fetch
.takeOverFrom();
1138 decode
.takeOverFrom();
1139 rename
.takeOverFrom();
1141 commit
.takeOverFrom();
1143 assert(!tickEvent
.scheduled());
1145 FullO3CPU
<Impl
> *oldO3CPU
= dynamic_cast<FullO3CPU
<Impl
>*>(oldCPU
);
1147 globalSeqNum
= oldO3CPU
->globalSeqNum
;
1149 lastRunningCycle
= curCycle();
1153 template <class Impl
>
1155 FullO3CPU
<Impl
>::verifyMemoryMode() const
1157 if (!system
->isTimingMode()) {
1158 fatal("The O3 CPU requires the memory system to be in "
1159 "'timing' mode.\n");
1163 template <class Impl
>
1165 FullO3CPU
<Impl
>::readMiscRegNoEffect(int misc_reg
, ThreadID tid
) const
1167 return this->isa
[tid
]->readMiscRegNoEffect(misc_reg
);
1170 template <class Impl
>
1172 FullO3CPU
<Impl
>::readMiscReg(int misc_reg
, ThreadID tid
)
1175 return this->isa
[tid
]->readMiscReg(misc_reg
);
1178 template <class Impl
>
1180 FullO3CPU
<Impl
>::setMiscRegNoEffect(int misc_reg
, RegVal val
, ThreadID tid
)
1182 this->isa
[tid
]->setMiscRegNoEffect(misc_reg
, val
);
1185 template <class Impl
>
1187 FullO3CPU
<Impl
>::setMiscReg(int misc_reg
, RegVal val
, ThreadID tid
)
1189 miscRegfileWrites
++;
1190 this->isa
[tid
]->setMiscReg(misc_reg
, val
);
1193 template <class Impl
>
1195 FullO3CPU
<Impl
>::readIntReg(PhysRegIdPtr phys_reg
)
1198 return regFile
.readIntReg(phys_reg
);
1201 template <class Impl
>
1203 FullO3CPU
<Impl
>::readFloatReg(PhysRegIdPtr phys_reg
)
1206 return regFile
.readFloatReg(phys_reg
);
1209 template <class Impl
>
1211 FullO3CPU
<Impl
>::readVecReg(PhysRegIdPtr phys_reg
) const
1212 -> const VecRegContainer
&
1215 return regFile
.readVecReg(phys_reg
);
1218 template <class Impl
>
1220 FullO3CPU
<Impl
>::getWritableVecReg(PhysRegIdPtr phys_reg
)
1224 return regFile
.getWritableVecReg(phys_reg
);
1227 template <class Impl
>
1229 FullO3CPU
<Impl
>::readVecElem(PhysRegIdPtr phys_reg
) const -> const VecElem
&
1232 return regFile
.readVecElem(phys_reg
);
1235 template <class Impl
>
1237 FullO3CPU
<Impl
>::readVecPredReg(PhysRegIdPtr phys_reg
) const
1238 -> const VecPredRegContainer
&
1240 vecPredRegfileReads
++;
1241 return regFile
.readVecPredReg(phys_reg
);
1244 template <class Impl
>
1246 FullO3CPU
<Impl
>::getWritableVecPredReg(PhysRegIdPtr phys_reg
)
1247 -> VecPredRegContainer
&
1249 vecPredRegfileWrites
++;
1250 return regFile
.getWritableVecPredReg(phys_reg
);
1253 template <class Impl
>
1255 FullO3CPU
<Impl
>::readCCReg(PhysRegIdPtr phys_reg
)
1258 return regFile
.readCCReg(phys_reg
);
1261 template <class Impl
>
1263 FullO3CPU
<Impl
>::setIntReg(PhysRegIdPtr phys_reg
, RegVal val
)
1266 regFile
.setIntReg(phys_reg
, val
);
1269 template <class Impl
>
1271 FullO3CPU
<Impl
>::setFloatReg(PhysRegIdPtr phys_reg
, RegVal val
)
1274 regFile
.setFloatReg(phys_reg
, val
);
1277 template <class Impl
>
1279 FullO3CPU
<Impl
>::setVecReg(PhysRegIdPtr phys_reg
, const VecRegContainer
& val
)
1282 regFile
.setVecReg(phys_reg
, val
);
1285 template <class Impl
>
1287 FullO3CPU
<Impl
>::setVecElem(PhysRegIdPtr phys_reg
, const VecElem
& val
)
1290 regFile
.setVecElem(phys_reg
, val
);
1293 template <class Impl
>
1295 FullO3CPU
<Impl
>::setVecPredReg(PhysRegIdPtr phys_reg
,
1296 const VecPredRegContainer
& val
)
1298 vecPredRegfileWrites
++;
1299 regFile
.setVecPredReg(phys_reg
, val
);
1302 template <class Impl
>
1304 FullO3CPU
<Impl
>::setCCReg(PhysRegIdPtr phys_reg
, RegVal val
)
1307 regFile
.setCCReg(phys_reg
, val
);
1310 template <class Impl
>
1312 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, ThreadID tid
)
1315 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1316 RegId(IntRegClass
, reg_idx
));
1318 return regFile
.readIntReg(phys_reg
);
1321 template <class Impl
>
1323 FullO3CPU
<Impl
>::readArchFloatReg(int reg_idx
, ThreadID tid
)
1326 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1327 RegId(FloatRegClass
, reg_idx
));
1329 return regFile
.readFloatReg(phys_reg
);
1332 template <class Impl
>
1334 FullO3CPU
<Impl
>::readArchVecReg(int reg_idx
, ThreadID tid
) const
1335 -> const VecRegContainer
&
1337 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1338 RegId(VecRegClass
, reg_idx
));
1339 return readVecReg(phys_reg
);
1342 template <class Impl
>
1344 FullO3CPU
<Impl
>::getWritableArchVecReg(int reg_idx
, ThreadID tid
)
1347 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1348 RegId(VecRegClass
, reg_idx
));
1349 return getWritableVecReg(phys_reg
);
1352 template <class Impl
>
1354 FullO3CPU
<Impl
>::readArchVecElem(const RegIndex
& reg_idx
, const ElemIndex
& ldx
,
1355 ThreadID tid
) const -> const VecElem
&
1357 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1358 RegId(VecElemClass
, reg_idx
, ldx
));
1359 return readVecElem(phys_reg
);
1362 template <class Impl
>
1364 FullO3CPU
<Impl
>::readArchVecPredReg(int reg_idx
, ThreadID tid
) const
1365 -> const VecPredRegContainer
&
1367 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1368 RegId(VecPredRegClass
, reg_idx
));
1369 return readVecPredReg(phys_reg
);
1372 template <class Impl
>
1374 FullO3CPU
<Impl
>::getWritableArchVecPredReg(int reg_idx
, ThreadID tid
)
1375 -> VecPredRegContainer
&
1377 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1378 RegId(VecPredRegClass
, reg_idx
));
1379 return getWritableVecPredReg(phys_reg
);
1382 template <class Impl
>
1384 FullO3CPU
<Impl
>::readArchCCReg(int reg_idx
, ThreadID tid
)
1387 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1388 RegId(CCRegClass
, reg_idx
));
1390 return regFile
.readCCReg(phys_reg
);
1393 template <class Impl
>
1395 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, RegVal val
, ThreadID tid
)
1398 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1399 RegId(IntRegClass
, reg_idx
));
1401 regFile
.setIntReg(phys_reg
, val
);
1404 template <class Impl
>
1406 FullO3CPU
<Impl
>::setArchFloatReg(int reg_idx
, RegVal val
, ThreadID tid
)
1409 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1410 RegId(FloatRegClass
, reg_idx
));
1412 regFile
.setFloatReg(phys_reg
, val
);
1415 template <class Impl
>
1417 FullO3CPU
<Impl
>::setArchVecReg(int reg_idx
, const VecRegContainer
& val
,
1420 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1421 RegId(VecRegClass
, reg_idx
));
1422 setVecReg(phys_reg
, val
);
1425 template <class Impl
>
1427 FullO3CPU
<Impl
>::setArchVecElem(const RegIndex
& reg_idx
, const ElemIndex
& ldx
,
1428 const VecElem
& val
, ThreadID tid
)
1430 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1431 RegId(VecElemClass
, reg_idx
, ldx
));
1432 setVecElem(phys_reg
, val
);
1435 template <class Impl
>
1437 FullO3CPU
<Impl
>::setArchVecPredReg(int reg_idx
, const VecPredRegContainer
& val
,
1440 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1441 RegId(VecPredRegClass
, reg_idx
));
1442 setVecPredReg(phys_reg
, val
);
1445 template <class Impl
>
1447 FullO3CPU
<Impl
>::setArchCCReg(int reg_idx
, RegVal val
, ThreadID tid
)
1450 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1451 RegId(CCRegClass
, reg_idx
));
1453 regFile
.setCCReg(phys_reg
, val
);
1456 template <class Impl
>
1458 FullO3CPU
<Impl
>::pcState(ThreadID tid
)
1460 return commit
.pcState(tid
);
1463 template <class Impl
>
1465 FullO3CPU
<Impl
>::pcState(const TheISA::PCState
&val
, ThreadID tid
)
1467 commit
.pcState(val
, tid
);
1470 template <class Impl
>
1472 FullO3CPU
<Impl
>::instAddr(ThreadID tid
)
1474 return commit
.instAddr(tid
);
1477 template <class Impl
>
1479 FullO3CPU
<Impl
>::nextInstAddr(ThreadID tid
)
1481 return commit
.nextInstAddr(tid
);
1484 template <class Impl
>
1486 FullO3CPU
<Impl
>::microPC(ThreadID tid
)
1488 return commit
.microPC(tid
);
1491 template <class Impl
>
1493 FullO3CPU
<Impl
>::squashFromTC(ThreadID tid
)
1495 this->thread
[tid
]->noSquashFromTC
= true;
1496 this->commit
.generateTCEvent(tid
);
1499 template <class Impl
>
1500 typename FullO3CPU
<Impl
>::ListIt
1501 FullO3CPU
<Impl
>::addInst(const DynInstPtr
&inst
)
1503 instList
.push_back(inst
);
1505 return --(instList
.end());
1508 template <class Impl
>
1510 FullO3CPU
<Impl
>::instDone(ThreadID tid
, const DynInstPtr
&inst
)
1512 // Keep an instruction count.
1513 if (!inst
->isMicroop() || inst
->isLastMicroop()) {
1514 thread
[tid
]->numInst
++;
1515 thread
[tid
]->threadStats
.numInsts
++;
1516 committedInsts
[tid
]++;
1517 system
->totalNumInsts
++;
1519 // Check for instruction-count-based events.
1520 thread
[tid
]->comInstEventQueue
.serviceEvents(thread
[tid
]->numInst
);
1522 thread
[tid
]->numOp
++;
1523 thread
[tid
]->threadStats
.numOps
++;
1524 committedOps
[tid
]++;
1526 probeInstCommit(inst
->staticInst
, inst
->instAddr());
1529 template <class Impl
>
1531 FullO3CPU
<Impl
>::removeFrontInst(const DynInstPtr
&inst
)
1533 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %s "
1535 inst
->threadNumber
, inst
->pcState(), inst
->seqNum
);
1537 removeInstsThisCycle
= true;
1539 // Remove the front instruction.
1540 removeList
.push(inst
->getInstListIt());
1543 template <class Impl
>
1545 FullO3CPU
<Impl
>::removeInstsNotInROB(ThreadID tid
)
1547 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1552 bool rob_empty
= false;
1554 if (instList
.empty()) {
1556 } else if (rob
.isEmpty(tid
)) {
1557 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1558 end_it
= instList
.begin();
1561 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1562 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1565 removeInstsThisCycle
= true;
1567 ListIt inst_it
= instList
.end();
1571 // Walk through the instruction list, removing any instructions
1572 // that were inserted after the given instruction iterator, end_it.
1573 while (inst_it
!= end_it
) {
1574 assert(!instList
.empty());
1576 squashInstIt(inst_it
, tid
);
1581 // If the ROB was empty, then we actually need to remove the first
1582 // instruction as well.
1584 squashInstIt(inst_it
, tid
);
1588 template <class Impl
>
1590 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
, ThreadID tid
)
1592 assert(!instList
.empty());
1594 removeInstsThisCycle
= true;
1596 ListIt inst_iter
= instList
.end();
1600 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1601 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1602 tid
, seq_num
, (*inst_iter
)->seqNum
);
1604 while ((*inst_iter
)->seqNum
> seq_num
) {
1606 bool break_loop
= (inst_iter
== instList
.begin());
1608 squashInstIt(inst_iter
, tid
);
1617 template <class Impl
>
1619 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, ThreadID tid
)
1621 if ((*instIt
)->threadNumber
== tid
) {
1622 DPRINTF(O3CPU
, "Squashing instruction, "
1623 "[tid:%i] [sn:%lli] PC %s\n",
1624 (*instIt
)->threadNumber
,
1626 (*instIt
)->pcState());
1628 // Mark it as squashed.
1629 (*instIt
)->setSquashed();
1631 // @todo: Formulate a consistent method for deleting
1632 // instructions from the instruction list
1633 // Remove the instruction from the list.
1634 removeList
.push(instIt
);
1638 template <class Impl
>
1640 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1642 while (!removeList
.empty()) {
1643 DPRINTF(O3CPU
, "Removing instruction, "
1644 "[tid:%i] [sn:%lli] PC %s\n",
1645 (*removeList
.front())->threadNumber
,
1646 (*removeList
.front())->seqNum
,
1647 (*removeList
.front())->pcState());
1649 instList
.erase(removeList
.front());
1654 removeInstsThisCycle
= false;
1657 template <class Impl>
1659 FullO3CPU<Impl>::removeAllInsts()
1664 template <class Impl
>
1666 FullO3CPU
<Impl
>::dumpInsts()
1670 ListIt inst_list_it
= instList
.begin();
1672 cprintf("Dumping Instruction List\n");
1674 while (inst_list_it
!= instList
.end()) {
1675 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1677 num
, (*inst_list_it
)->instAddr(), (*inst_list_it
)->threadNumber
,
1678 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1679 (*inst_list_it
)->isSquashed());
1685 template <class Impl>
1687 FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst)
1689 iew.wakeDependents(inst);
1692 template <class Impl
>
1694 FullO3CPU
<Impl
>::wakeCPU()
1696 if (activityRec
.active() || tickEvent
.scheduled()) {
1697 DPRINTF(Activity
, "CPU already running.\n");
1701 DPRINTF(Activity
, "Waking up CPU\n");
1703 Cycles
cycles(curCycle() - lastRunningCycle
);
1704 // @todo: This is an oddity that is only here to match the stats
1707 idleCycles
+= cycles
;
1708 numCycles
+= cycles
;
1711 schedule(tickEvent
, clockEdge());
1714 template <class Impl
>
1716 FullO3CPU
<Impl
>::wakeup(ThreadID tid
)
1718 if (this->thread
[tid
]->status() != ThreadContext::Suspended
)
1723 DPRINTF(Quiesce
, "Suspended Processor woken\n");
1724 this->threadContexts
[tid
]->activate();
1727 template <class Impl
>
1729 FullO3CPU
<Impl
>::getFreeTid()
1731 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
1738 return InvalidThreadID
;
1741 template <class Impl
>
1743 FullO3CPU
<Impl
>::updateThreadPriority()
1745 if (activeThreads
.size() > 1) {
1746 //DEFAULT TO ROUND ROBIN SCHEME
1747 //e.g. Move highest priority to end of thread list
1748 list
<ThreadID
>::iterator list_begin
= activeThreads
.begin();
1750 unsigned high_thread
= *list_begin
;
1752 activeThreads
.erase(list_begin
);
1754 activeThreads
.push_back(high_thread
);
1758 template <class Impl
>
1760 FullO3CPU
<Impl
>::addThreadToExitingList(ThreadID tid
)
1762 DPRINTF(O3CPU
, "Thread %d is inserted to exitingThreads list\n", tid
);
1764 // the thread trying to exit can't be already halted
1765 assert(tcBase(tid
)->status() != ThreadContext::Halted
);
1767 // make sure the thread has not been added to the list yet
1768 assert(exitingThreads
.count(tid
) == 0);
1770 // add the thread to exitingThreads list to mark that this thread is
1771 // trying to exit. The boolean value in the pair denotes if a thread is
1772 // ready to exit. The thread is not ready to exit until the corresponding
1773 // exit trap event is processed in the future. Until then, it'll be still
1774 // an active thread that is trying to exit.
1775 exitingThreads
.emplace(std::make_pair(tid
, false));
1778 template <class Impl
>
1780 FullO3CPU
<Impl
>::isThreadExiting(ThreadID tid
) const
1782 return exitingThreads
.count(tid
) == 1;
1785 template <class Impl
>
1787 FullO3CPU
<Impl
>::scheduleThreadExitEvent(ThreadID tid
)
1789 assert(exitingThreads
.count(tid
) == 1);
1791 // exit trap event has been processed. Now, the thread is ready to exit
1792 // and be removed from the CPU.
1793 exitingThreads
[tid
] = true;
1795 // we schedule a threadExitEvent in the next cycle to properly clean
1796 // up the thread's states in the pipeline. threadExitEvent has lower
1797 // priority than tickEvent, so the cleanup will happen at the very end
1798 // of the next cycle after all pipeline stages complete their operations.
1799 // We want all stages to complete squashing instructions before doing
1801 if (!threadExitEvent
.scheduled()) {
1802 schedule(threadExitEvent
, nextCycle());
1806 template <class Impl
>
1808 FullO3CPU
<Impl
>::exitThreads()
1810 // there must be at least one thread trying to exit
1811 assert(exitingThreads
.size() > 0);
1813 // terminate all threads that are ready to exit
1814 auto it
= exitingThreads
.begin();
1815 while (it
!= exitingThreads
.end()) {
1816 ThreadID thread_id
= it
->first
;
1817 bool readyToExit
= it
->second
;
1820 DPRINTF(O3CPU
, "Exiting thread %d\n", thread_id
);
1821 haltContext(thread_id
);
1822 tcBase(thread_id
)->setStatus(ThreadContext::Halted
);
1823 it
= exitingThreads
.erase(it
);
1830 // Forward declaration of FullO3CPU.
1831 template class FullO3CPU
<O3CPUImpl
>;