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.
47 #include "cpu/o3/cpu.hh"
49 #include "arch/generic/traits.hh"
50 #include "arch/kernel_stats.hh"
51 #include "config/the_isa.hh"
52 #include "cpu/activity.hh"
53 #include "cpu/checker/cpu.hh"
54 #include "cpu/checker/thread_context.hh"
55 #include "cpu/o3/isa_specific.hh"
56 #include "cpu/o3/thread_context.hh"
57 #include "cpu/quiesce_event.hh"
58 #include "cpu/simple_thread.hh"
59 #include "cpu/thread_context.hh"
60 #include "debug/Activity.hh"
61 #include "debug/Drain.hh"
62 #include "debug/O3CPU.hh"
63 #include "debug/Quiesce.hh"
64 #include "enums/MemoryMode.hh"
65 #include "sim/core.hh"
66 #include "sim/full_system.hh"
67 #include "sim/process.hh"
68 #include "sim/stat_control.hh"
69 #include "sim/system.hh"
71 #if THE_ISA == ALPHA_ISA
72 #include "arch/alpha/osfpal.hh"
73 #include "debug/Activity.hh"
79 using namespace TheISA
;
82 BaseO3CPU::BaseO3CPU(BaseCPUParams
*params
)
94 FullO3CPU
<Impl
>::FullO3CPU(DerivO3CPUParams
*params
)
98 tickEvent([this]{ tick(); }, "FullO3CPU tick",
99 false, Event::CPU_Tick_Pri
),
100 threadExitEvent([this]{ exitThreads(); }, "FullO3CPU exit threads",
101 false, Event::CPU_Exit_Pri
),
105 removeInstsThisCycle(false),
107 decode(this, params
),
108 rename(this, params
),
110 commit(this, params
),
112 /* It is mandatory that all SMT threads use the same renaming mode as
113 * they are sharing registers and rename */
114 vecMode(RenameMode
<TheISA::ISA
>::init(params
->isa
[0])),
115 regFile(params
->numPhysIntRegs
,
116 params
->numPhysFloatRegs
,
117 params
->numPhysVecRegs
,
118 params
->numPhysVecPredRegs
,
119 params
->numPhysCCRegs
,
122 freeList(name() + ".freelist", ®File
),
126 scoreboard(name() + ".scoreboard",
127 regFile
.totalNumPhysRegs()),
129 isa(numThreads
, NULL
),
131 timeBuffer(params
->backComSize
, params
->forwardComSize
),
132 fetchQueue(params
->backComSize
, params
->forwardComSize
),
133 decodeQueue(params
->backComSize
, params
->forwardComSize
),
134 renameQueue(params
->backComSize
, params
->forwardComSize
),
135 iewQueue(params
->backComSize
, params
->forwardComSize
),
136 activityRec(name(), NumStages
,
137 params
->backComSize
+ params
->forwardComSize
,
141 system(params
->system
),
142 lastRunningCycle(curCycle())
144 if (!params
->switched_out
) {
147 _status
= SwitchedOut
;
150 if (params
->checker
) {
151 BaseCPU
*temp_checker
= params
->checker
;
152 checker
= dynamic_cast<Checker
<Impl
> *>(temp_checker
);
153 checker
->setIcachePort(&this->fetch
.getInstPort());
154 checker
->setSystem(params
->system
);
160 thread
.resize(numThreads
);
161 tids
.resize(numThreads
);
164 // The stages also need their CPU pointer setup. However this
165 // must be done at the upper level CPU because they have pointers
166 // to the upper level CPU, and not this FullO3CPU.
168 // Set up Pointers to the activeThreads list for each stage
169 fetch
.setActiveThreads(&activeThreads
);
170 decode
.setActiveThreads(&activeThreads
);
171 rename
.setActiveThreads(&activeThreads
);
172 iew
.setActiveThreads(&activeThreads
);
173 commit
.setActiveThreads(&activeThreads
);
175 // Give each of the stages the time buffer they will use.
176 fetch
.setTimeBuffer(&timeBuffer
);
177 decode
.setTimeBuffer(&timeBuffer
);
178 rename
.setTimeBuffer(&timeBuffer
);
179 iew
.setTimeBuffer(&timeBuffer
);
180 commit
.setTimeBuffer(&timeBuffer
);
182 // Also setup each of the stages' queues.
183 fetch
.setFetchQueue(&fetchQueue
);
184 decode
.setFetchQueue(&fetchQueue
);
185 commit
.setFetchQueue(&fetchQueue
);
186 decode
.setDecodeQueue(&decodeQueue
);
187 rename
.setDecodeQueue(&decodeQueue
);
188 rename
.setRenameQueue(&renameQueue
);
189 iew
.setRenameQueue(&renameQueue
);
190 iew
.setIEWQueue(&iewQueue
);
191 commit
.setIEWQueue(&iewQueue
);
192 commit
.setRenameQueue(&renameQueue
);
194 commit
.setIEWStage(&iew
);
195 rename
.setIEWStage(&iew
);
196 rename
.setCommitStage(&commit
);
198 ThreadID active_threads
;
202 active_threads
= params
->workload
.size();
204 if (active_threads
> Impl::MaxThreads
) {
205 panic("Workload Size too large. Increase the 'MaxThreads' "
206 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
207 "or edit your workload size.");
211 //Make Sure That this a Valid Architeture
212 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
213 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
214 assert(params
->numPhysVecRegs
>= numThreads
* TheISA::NumVecRegs
);
215 assert(params
->numPhysVecPredRegs
>= numThreads
* TheISA::NumVecPredRegs
);
216 assert(params
->numPhysCCRegs
>= numThreads
* TheISA::NumCCRegs
);
218 rename
.setScoreboard(&scoreboard
);
219 iew
.setScoreboard(&scoreboard
);
221 // Setup the rename map for whichever stages need it.
222 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
223 isa
[tid
] = params
->isa
[tid
];
224 assert(RenameMode
<TheISA::ISA
>::equalsInit(isa
[tid
], isa
[0]));
226 // Only Alpha has an FP zero register, so for other ISAs we
227 // use an invalid FP register index to avoid special treatment
228 // of any valid FP reg.
229 RegIndex invalidFPReg
= TheISA::NumFloatRegs
+ 1;
231 (THE_ISA
== ALPHA_ISA
) ? TheISA::ZeroReg
: invalidFPReg
;
233 commitRenameMap
[tid
].init(®File
, TheISA::ZeroReg
, fpZeroReg
,
237 renameMap
[tid
].init(®File
, TheISA::ZeroReg
, fpZeroReg
,
241 // Initialize rename map to assign physical registers to the
242 // architectural registers for active threads only.
243 for (ThreadID tid
= 0; tid
< active_threads
; tid
++) {
244 for (RegIndex ridx
= 0; ridx
< TheISA::NumIntRegs
; ++ridx
) {
245 // Note that we can't use the rename() method because we don't
246 // want special treatment for the zero register at this point
247 PhysRegIdPtr phys_reg
= freeList
.getIntReg();
248 renameMap
[tid
].setEntry(RegId(IntRegClass
, ridx
), phys_reg
);
249 commitRenameMap
[tid
].setEntry(RegId(IntRegClass
, ridx
), phys_reg
);
252 for (RegIndex ridx
= 0; ridx
< TheISA::NumFloatRegs
; ++ridx
) {
253 PhysRegIdPtr phys_reg
= freeList
.getFloatReg();
254 renameMap
[tid
].setEntry(RegId(FloatRegClass
, ridx
), phys_reg
);
255 commitRenameMap
[tid
].setEntry(
256 RegId(FloatRegClass
, ridx
), phys_reg
);
259 /* Here we need two 'interfaces' the 'whole register' and the
260 * 'register element'. At any point only one of them will be
262 if (vecMode
== Enums::Full
) {
263 /* Initialize the full-vector interface */
264 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecRegs
; ++ridx
) {
265 RegId rid
= RegId(VecRegClass
, ridx
);
266 PhysRegIdPtr phys_reg
= freeList
.getVecReg();
267 renameMap
[tid
].setEntry(rid
, phys_reg
);
268 commitRenameMap
[tid
].setEntry(rid
, phys_reg
);
271 /* Initialize the vector-element interface */
272 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecRegs
; ++ridx
) {
273 for (ElemIndex ldx
= 0; ldx
< TheISA::NumVecElemPerVecReg
;
275 RegId lrid
= RegId(VecElemClass
, ridx
, ldx
);
276 PhysRegIdPtr phys_elem
= freeList
.getVecElem();
277 renameMap
[tid
].setEntry(lrid
, phys_elem
);
278 commitRenameMap
[tid
].setEntry(lrid
, phys_elem
);
283 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecPredRegs
; ++ridx
) {
284 PhysRegIdPtr phys_reg
= freeList
.getVecPredReg();
285 renameMap
[tid
].setEntry(RegId(VecPredRegClass
, ridx
), phys_reg
);
286 commitRenameMap
[tid
].setEntry(
287 RegId(VecPredRegClass
, ridx
), phys_reg
);
290 for (RegIndex ridx
= 0; ridx
< TheISA::NumCCRegs
; ++ridx
) {
291 PhysRegIdPtr phys_reg
= freeList
.getCCReg();
292 renameMap
[tid
].setEntry(RegId(CCRegClass
, ridx
), phys_reg
);
293 commitRenameMap
[tid
].setEntry(RegId(CCRegClass
, ridx
), phys_reg
);
297 rename
.setRenameMap(renameMap
);
298 commit
.setRenameMap(commitRenameMap
);
299 rename
.setFreeList(&freeList
);
301 // Setup the ROB for whichever stages need it.
304 lastActivatedCycle
= 0;
306 DPRINTF(O3CPU
, "Creating O3CPU object.\n");
308 // Setup any thread state.
309 this->thread
.resize(this->numThreads
);
311 for (ThreadID tid
= 0; tid
< this->numThreads
; ++tid
) {
313 // SMT is not supported in FS mode yet.
314 assert(this->numThreads
== 1);
315 this->thread
[tid
] = new Thread(this, 0, NULL
);
317 if (tid
< params
->workload
.size()) {
318 DPRINTF(O3CPU
, "Workload[%i] process is %#x",
319 tid
, this->thread
[tid
]);
320 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
321 (typename
Impl::O3CPU
*)(this),
322 tid
, params
->workload
[tid
]);
324 //usedTids[tid] = true;
325 //threadMap[tid] = tid;
327 //Allocate Empty thread so M5 can use later
328 //when scheduling threads to CPU
329 Process
* dummy_proc
= NULL
;
331 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
332 (typename
Impl::O3CPU
*)(this),
334 //usedTids[tid] = false;
340 // Setup the TC that will serve as the interface to the threads/CPU.
341 O3ThreadContext
<Impl
> *o3_tc
= new O3ThreadContext
<Impl
>;
345 // If we're using a checker, then the TC should be the
346 // CheckerThreadContext.
347 if (params
->checker
) {
348 tc
= new CheckerThreadContext
<O3ThreadContext
<Impl
> >(
349 o3_tc
, this->checker
);
352 o3_tc
->cpu
= (typename
Impl::O3CPU
*)(this);
354 o3_tc
->thread
= this->thread
[tid
];
356 // Setup quiesce event.
357 this->thread
[tid
]->quiesceEvent
= new EndQuiesceEvent(tc
);
359 // Give the thread the TC.
360 this->thread
[tid
]->tc
= tc
;
362 // Add the TC to the CPU's list of TC's.
363 this->threadContexts
.push_back(tc
);
366 // FullO3CPU always requires an interrupt controller.
367 if (!params
->switched_out
&& interrupts
.empty()) {
368 fatal("FullO3CPU %s has no interrupt controller.\n"
369 "Ensure createInterruptController() is called.\n", name());
372 for (ThreadID tid
= 0; tid
< this->numThreads
; tid
++)
373 this->thread
[tid
]->setFuncExeInst(0);
376 template <class Impl
>
377 FullO3CPU
<Impl
>::~FullO3CPU()
381 template <class Impl
>
383 FullO3CPU
<Impl
>::regProbePoints()
385 BaseCPU::regProbePoints();
387 ppInstAccessComplete
= new ProbePointArg
<PacketPtr
>(getProbeManager(), "InstAccessComplete");
388 ppDataAccessComplete
= new ProbePointArg
<std::pair
<DynInstPtr
, PacketPtr
> >(getProbeManager(), "DataAccessComplete");
390 fetch
.regProbePoints();
391 rename
.regProbePoints();
392 iew
.regProbePoints();
393 commit
.regProbePoints();
396 template <class Impl
>
398 FullO3CPU
<Impl
>::regStats()
400 BaseO3CPU::regStats();
402 // Register any of the O3CPU's stats here.
404 .name(name() + ".timesIdled")
405 .desc("Number of times that the entire CPU went into an idle state and"
406 " unscheduled itself")
410 .name(name() + ".idleCycles")
411 .desc("Total number of cycles that the CPU has spent unscheduled due "
416 .name(name() + ".quiesceCycles")
417 .desc("Total number of cycles that CPU has spent quiesced or waiting "
419 .prereq(quiesceCycles
);
421 // Number of Instructions simulated
422 // --------------------------------
423 // Should probably be in Base CPU but need templated
424 // MaxThreads so put in here instead
427 .name(name() + ".committedInsts")
428 .desc("Number of Instructions Simulated")
429 .flags(Stats::total
);
433 .name(name() + ".committedOps")
434 .desc("Number of Ops (including micro ops) Simulated")
435 .flags(Stats::total
);
438 .name(name() + ".cpi")
439 .desc("CPI: Cycles Per Instruction")
441 cpi
= numCycles
/ committedInsts
;
444 .name(name() + ".cpi_total")
445 .desc("CPI: Total CPI of All Threads")
447 totalCpi
= numCycles
/ sum(committedInsts
);
450 .name(name() + ".ipc")
451 .desc("IPC: Instructions Per Cycle")
453 ipc
= committedInsts
/ numCycles
;
456 .name(name() + ".ipc_total")
457 .desc("IPC: Total IPC of All Threads")
459 totalIpc
= sum(committedInsts
) / numCycles
;
461 this->fetch
.regStats();
462 this->decode
.regStats();
463 this->rename
.regStats();
464 this->iew
.regStats();
465 this->commit
.regStats();
466 this->rob
.regStats();
469 .name(name() + ".int_regfile_reads")
470 .desc("number of integer regfile reads")
471 .prereq(intRegfileReads
);
474 .name(name() + ".int_regfile_writes")
475 .desc("number of integer regfile writes")
476 .prereq(intRegfileWrites
);
479 .name(name() + ".fp_regfile_reads")
480 .desc("number of floating regfile reads")
481 .prereq(fpRegfileReads
);
484 .name(name() + ".fp_regfile_writes")
485 .desc("number of floating regfile writes")
486 .prereq(fpRegfileWrites
);
489 .name(name() + ".vec_regfile_reads")
490 .desc("number of vector regfile reads")
491 .prereq(vecRegfileReads
);
494 .name(name() + ".vec_regfile_writes")
495 .desc("number of vector regfile writes")
496 .prereq(vecRegfileWrites
);
499 .name(name() + ".pred_regfile_reads")
500 .desc("number of predicate regfile reads")
501 .prereq(vecPredRegfileReads
);
504 .name(name() + ".pred_regfile_writes")
505 .desc("number of predicate regfile writes")
506 .prereq(vecPredRegfileWrites
);
509 .name(name() + ".cc_regfile_reads")
510 .desc("number of cc regfile reads")
511 .prereq(ccRegfileReads
);
514 .name(name() + ".cc_regfile_writes")
515 .desc("number of cc regfile writes")
516 .prereq(ccRegfileWrites
);
519 .name(name() + ".misc_regfile_reads")
520 .desc("number of misc regfile reads")
521 .prereq(miscRegfileReads
);
524 .name(name() + ".misc_regfile_writes")
525 .desc("number of misc regfile writes")
526 .prereq(miscRegfileWrites
);
529 template <class Impl
>
531 FullO3CPU
<Impl
>::tick()
533 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
534 assert(!switchedOut());
535 assert(drainState() != DrainState::Drained
);
538 updateCycleCounters(BaseCPU::CPU_STATE_ON
);
542 //Tick each of the stages
553 // Now advance the time buffers
554 timeBuffer
.advance();
556 fetchQueue
.advance();
557 decodeQueue
.advance();
558 renameQueue
.advance();
561 activityRec
.advance();
563 if (removeInstsThisCycle
) {
564 cleanUpRemovedInsts();
567 if (!tickEvent
.scheduled()) {
568 if (_status
== SwitchedOut
) {
569 DPRINTF(O3CPU
, "Switched out!\n");
571 lastRunningCycle
= curCycle();
572 } else if (!activityRec
.active() || _status
== Idle
) {
573 DPRINTF(O3CPU
, "Idle!\n");
574 lastRunningCycle
= curCycle();
577 schedule(tickEvent
, clockEdge(Cycles(1)));
578 DPRINTF(O3CPU
, "Scheduling next tick!\n");
583 updateThreadPriority();
588 template <class Impl
>
590 FullO3CPU
<Impl
>::init()
594 for (ThreadID tid
= 0; tid
< numThreads
; ++tid
) {
595 // Set noSquashFromTC so that the CPU doesn't squash when initially
596 // setting up registers.
597 thread
[tid
]->noSquashFromTC
= true;
598 // Initialise the ThreadContext's memory proxies
599 thread
[tid
]->initMemProxies(thread
[tid
]->getTC());
602 if (FullSystem
&& !params()->switched_out
) {
603 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
604 ThreadContext
*src_tc
= threadContexts
[tid
];
605 TheISA::initCPU(src_tc
, src_tc
->contextId());
609 // Clear noSquashFromTC.
610 for (int tid
= 0; tid
< numThreads
; ++tid
)
611 thread
[tid
]->noSquashFromTC
= false;
613 commit
.setThreads(thread
);
616 template <class Impl
>
618 FullO3CPU
<Impl
>::startup()
621 for (int tid
= 0; tid
< numThreads
; ++tid
)
622 isa
[tid
]->startup(threadContexts
[tid
]);
624 fetch
.startupStage();
625 decode
.startupStage();
627 rename
.startupStage();
628 commit
.startupStage();
631 template <class Impl
>
633 FullO3CPU
<Impl
>::activateThread(ThreadID tid
)
635 list
<ThreadID
>::iterator isActive
=
636 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
638 DPRINTF(O3CPU
, "[tid:%i] Calling activate thread.\n", tid
);
639 assert(!switchedOut());
641 if (isActive
== activeThreads
.end()) {
642 DPRINTF(O3CPU
, "[tid:%i] Adding to active threads list\n",
645 activeThreads
.push_back(tid
);
649 template <class Impl
>
651 FullO3CPU
<Impl
>::deactivateThread(ThreadID tid
)
653 //Remove From Active List, if Active
654 list
<ThreadID
>::iterator thread_it
=
655 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
657 DPRINTF(O3CPU
, "[tid:%i] Calling deactivate thread.\n", tid
);
658 assert(!switchedOut());
660 if (thread_it
!= activeThreads
.end()) {
661 DPRINTF(O3CPU
,"[tid:%i] Removing from active threads list\n",
663 activeThreads
.erase(thread_it
);
666 fetch
.deactivateThread(tid
);
667 commit
.deactivateThread(tid
);
670 template <class Impl
>
672 FullO3CPU
<Impl
>::totalInsts() const
676 ThreadID size
= thread
.size();
677 for (ThreadID i
= 0; i
< size
; i
++)
678 total
+= thread
[i
]->numInst
;
683 template <class Impl
>
685 FullO3CPU
<Impl
>::totalOps() const
689 ThreadID size
= thread
.size();
690 for (ThreadID i
= 0; i
< size
; i
++)
691 total
+= thread
[i
]->numOp
;
696 template <class Impl
>
698 FullO3CPU
<Impl
>::activateContext(ThreadID tid
)
700 assert(!switchedOut());
702 // Needs to set each stage to running as well.
705 // We don't want to wake the CPU if it is drained. In that case,
706 // we just want to flag the thread as active and schedule the tick
707 // event from drainResume() instead.
708 if (drainState() == DrainState::Drained
)
711 // If we are time 0 or if the last activation time is in the past,
712 // schedule the next tick and wake up the fetch unit
713 if (lastActivatedCycle
== 0 || lastActivatedCycle
< curTick()) {
714 scheduleTickEvent(Cycles(0));
716 // Be sure to signal that there's some activity so the CPU doesn't
717 // deschedule itself.
718 activityRec
.activity();
719 fetch
.wakeFromQuiesce();
721 Cycles
cycles(curCycle() - lastRunningCycle
);
722 // @todo: This is an oddity that is only here to match the stats
725 quiesceCycles
+= cycles
;
727 lastActivatedCycle
= curTick();
731 BaseCPU::activateContext(tid
);
735 template <class Impl
>
737 FullO3CPU
<Impl
>::suspendContext(ThreadID tid
)
739 DPRINTF(O3CPU
,"[tid:%i] Suspending Thread Context.\n", tid
);
740 assert(!switchedOut());
742 deactivateThread(tid
);
744 // If this was the last thread then unschedule the tick event.
745 if (activeThreads
.size() == 0) {
746 unscheduleTickEvent();
747 lastRunningCycle
= curCycle();
751 DPRINTF(Quiesce
, "Suspending Context\n");
753 BaseCPU::suspendContext(tid
);
756 template <class Impl
>
758 FullO3CPU
<Impl
>::haltContext(ThreadID tid
)
760 //For now, this is the same as deallocate
761 DPRINTF(O3CPU
,"[tid:%i] Halt Context called. Deallocating\n", tid
);
762 assert(!switchedOut());
764 deactivateThread(tid
);
767 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP
);
770 template <class Impl
>
772 FullO3CPU
<Impl
>::insertThread(ThreadID tid
)
774 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
775 // Will change now that the PC and thread state is internal to the CPU
776 // and not in the ThreadContext.
777 ThreadContext
*src_tc
;
779 src_tc
= system
->threadContexts
[tid
];
781 src_tc
= tcBase(tid
);
783 //Bind Int Regs to Rename Map
785 for (RegId
reg_id(IntRegClass
, 0); reg_id
.index() < TheISA::NumIntRegs
;
787 PhysRegIdPtr phys_reg
= freeList
.getIntReg();
788 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
789 scoreboard
.setReg(phys_reg
);
792 //Bind Float Regs to Rename Map
793 for (RegId
reg_id(FloatRegClass
, 0); reg_id
.index() < TheISA::NumFloatRegs
;
795 PhysRegIdPtr phys_reg
= freeList
.getFloatReg();
796 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
797 scoreboard
.setReg(phys_reg
);
800 //Bind condition-code Regs to Rename Map
801 for (RegId
reg_id(CCRegClass
, 0); reg_id
.index() < TheISA::NumCCRegs
;
803 PhysRegIdPtr phys_reg
= freeList
.getCCReg();
804 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
805 scoreboard
.setReg(phys_reg
);
808 //Copy Thread Data Into RegFile
809 //this->copyFromTC(tid);
812 pcState(src_tc
->pcState(), tid
);
814 src_tc
->setStatus(ThreadContext::Active
);
816 activateContext(tid
);
818 //Reset ROB/IQ/LSQ Entries
819 commit
.rob
->resetEntries();
822 template <class Impl
>
824 FullO3CPU
<Impl
>::removeThread(ThreadID tid
)
826 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
828 // Copy Thread Data From RegFile
829 // If thread is suspended, it might be re-allocated
830 // this->copyToTC(tid);
833 // @todo: 2-27-2008: Fix how we free up rename mappings
834 // here to alleviate the case for double-freeing registers
837 // clear all thread-specific states in each stage of the pipeline
838 // since this thread is going to be completely removed from the CPU
839 commit
.clearStates(tid
);
840 fetch
.clearStates(tid
);
841 decode
.clearStates(tid
);
842 rename
.clearStates(tid
);
843 iew
.clearStates(tid
);
845 // at this step, all instructions in the pipeline should be already
846 // either committed successfully or squashed. All thread-specific
847 // queues in the pipeline must be empty.
848 assert(iew
.instQueue
.getCount(tid
) == 0);
849 assert(iew
.ldstQueue
.getCount(tid
) == 0);
850 assert(commit
.rob
->isEmpty(tid
));
852 // Reset ROB/IQ/LSQ Entries
854 // Commented out for now. This should be possible to do by
855 // telling all the pipeline stages to drain first, and then
856 // checking until the drain completes. Once the pipeline is
857 // drained, call resetEntries(). - 10-09-06 ktlim
859 if (activeThreads.size() >= 1) {
860 commit.rob->resetEntries();
866 template <class Impl
>
868 FullO3CPU
<Impl
>::switchRenameMode(ThreadID tid
, UnifiedFreeList
* freelist
)
870 auto pc
= this->pcState(tid
);
872 // new_mode is the new vector renaming mode
873 auto new_mode
= RenameMode
<TheISA::ISA
>::mode(pc
);
875 // We update vecMode only if there has been a change
876 if (new_mode
!= vecMode
) {
879 renameMap
[tid
].switchMode(vecMode
);
880 commitRenameMap
[tid
].switchMode(vecMode
);
881 renameMap
[tid
].switchFreeList(freelist
);
885 template <class Impl
>
887 FullO3CPU
<Impl
>::getInterrupts()
889 // Check if there are any outstanding interrupts
890 return this->interrupts
[0]->getInterrupt(this->threadContexts
[0]);
893 template <class Impl
>
895 FullO3CPU
<Impl
>::processInterrupts(const Fault
&interrupt
)
897 // Check for interrupts here. For now can copy the code that
898 // exists within isa_fullsys_traits.hh. Also assume that thread 0
899 // is the one that handles the interrupts.
900 // @todo: Possibly consolidate the interrupt checking code.
901 // @todo: Allow other threads to handle interrupts.
903 assert(interrupt
!= NoFault
);
904 this->interrupts
[0]->updateIntrInfo(this->threadContexts
[0]);
906 DPRINTF(O3CPU
, "Interrupt %s being handled\n", interrupt
->name());
907 this->trap(interrupt
, 0, nullptr);
910 template <class Impl
>
912 FullO3CPU
<Impl
>::trap(const Fault
&fault
, ThreadID tid
,
913 const StaticInstPtr
&inst
)
915 // Pass the thread's TC into the invoke method.
916 fault
->invoke(this->threadContexts
[tid
], inst
);
919 template <class Impl
>
921 FullO3CPU
<Impl
>::syscall(int64_t callnum
, ThreadID tid
, Fault
*fault
)
923 DPRINTF(O3CPU
, "[tid:%i] Executing syscall().\n\n", tid
);
925 DPRINTF(Activity
,"Activity: syscall() called.\n");
927 // Temporarily increase this by one to account for the syscall
929 ++(this->thread
[tid
]->funcExeInst
);
931 // Execute the actual syscall.
932 this->thread
[tid
]->syscall(callnum
, fault
);
934 // Decrease funcExeInst by one as the normal commit will handle
936 --(this->thread
[tid
]->funcExeInst
);
939 template <class Impl
>
941 FullO3CPU
<Impl
>::serializeThread(CheckpointOut
&cp
, ThreadID tid
) const
943 thread
[tid
]->serialize(cp
);
946 template <class Impl
>
948 FullO3CPU
<Impl
>::unserializeThread(CheckpointIn
&cp
, ThreadID tid
)
950 thread
[tid
]->unserialize(cp
);
953 template <class Impl
>
955 FullO3CPU
<Impl
>::drain()
957 // Deschedule any power gating event (if any)
958 deschedulePowerGatingEvent();
960 // If the CPU isn't doing anything, then return immediately.
962 return DrainState::Drained
;
964 DPRINTF(Drain
, "Draining...\n");
966 // We only need to signal a drain to the commit stage as this
967 // initiates squashing controls the draining. Once the commit
968 // stage commits an instruction where it is safe to stop, it'll
969 // squash the rest of the instructions in the pipeline and force
970 // the fetch stage to stall. The pipeline will be drained once all
971 // in-flight instructions have retired.
974 // Wake the CPU and record activity so everything can drain out if
975 // the CPU was not able to immediately drain.
976 if (!isCpuDrained()) {
977 // If a thread is suspended, wake it up so it can be drained
978 for (auto t
: threadContexts
) {
979 if (t
->status() == ThreadContext::Suspended
){
980 DPRINTF(Drain
, "Currently suspended so activate %i \n",
983 // As the thread is now active, change the power state as well
984 activateContext(t
->threadId());
989 activityRec
.activity();
991 DPRINTF(Drain
, "CPU not drained\n");
993 return DrainState::Draining
;
995 DPRINTF(Drain
, "CPU is already drained\n");
996 if (tickEvent
.scheduled())
997 deschedule(tickEvent
);
999 // Flush out any old data from the time buffers. In
1000 // particular, there might be some data in flight from the
1001 // fetch stage that isn't visible in any of the CPU buffers we
1002 // test in isCpuDrained().
1003 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
1004 timeBuffer
.advance();
1005 fetchQueue
.advance();
1006 decodeQueue
.advance();
1007 renameQueue
.advance();
1012 return DrainState::Drained
;
1016 template <class Impl
>
1018 FullO3CPU
<Impl
>::tryDrain()
1020 if (drainState() != DrainState::Draining
|| !isCpuDrained())
1023 if (tickEvent
.scheduled())
1024 deschedule(tickEvent
);
1026 DPRINTF(Drain
, "CPU done draining, processing drain event\n");
1032 template <class Impl
>
1034 FullO3CPU
<Impl
>::drainSanityCheck() const
1036 assert(isCpuDrained());
1037 fetch
.drainSanityCheck();
1038 decode
.drainSanityCheck();
1039 rename
.drainSanityCheck();
1040 iew
.drainSanityCheck();
1041 commit
.drainSanityCheck();
1044 template <class Impl
>
1046 FullO3CPU
<Impl
>::isCpuDrained() const
1050 if (!instList
.empty() || !removeList
.empty()) {
1051 DPRINTF(Drain
, "Main CPU structures not drained.\n");
1055 if (!fetch
.isDrained()) {
1056 DPRINTF(Drain
, "Fetch not drained.\n");
1060 if (!decode
.isDrained()) {
1061 DPRINTF(Drain
, "Decode not drained.\n");
1065 if (!rename
.isDrained()) {
1066 DPRINTF(Drain
, "Rename not drained.\n");
1070 if (!iew
.isDrained()) {
1071 DPRINTF(Drain
, "IEW not drained.\n");
1075 if (!commit
.isDrained()) {
1076 DPRINTF(Drain
, "Commit not drained.\n");
1083 template <class Impl
>
1085 FullO3CPU
<Impl
>::commitDrained(ThreadID tid
)
1087 fetch
.drainStall(tid
);
1090 template <class Impl
>
1092 FullO3CPU
<Impl
>::drainResume()
1097 DPRINTF(Drain
, "Resuming...\n");
1100 fetch
.drainResume();
1101 commit
.drainResume();
1104 for (ThreadID i
= 0; i
< thread
.size(); i
++) {
1105 if (thread
[i
]->status() == ThreadContext::Active
) {
1106 DPRINTF(Drain
, "Activating thread: %i\n", i
);
1112 assert(!tickEvent
.scheduled());
1113 if (_status
== Running
)
1114 schedule(tickEvent
, nextCycle());
1116 // Reschedule any power gating event (if any)
1117 schedulePowerGatingEvent();
1120 template <class Impl
>
1122 FullO3CPU
<Impl
>::switchOut()
1124 DPRINTF(O3CPU
, "Switching out\n");
1125 BaseCPU::switchOut();
1127 activityRec
.reset();
1129 _status
= SwitchedOut
;
1132 checker
->switchOut();
1135 template <class Impl
>
1137 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
1139 BaseCPU::takeOverFrom(oldCPU
);
1141 fetch
.takeOverFrom();
1142 decode
.takeOverFrom();
1143 rename
.takeOverFrom();
1145 commit
.takeOverFrom();
1147 assert(!tickEvent
.scheduled());
1149 FullO3CPU
<Impl
> *oldO3CPU
= dynamic_cast<FullO3CPU
<Impl
>*>(oldCPU
);
1151 globalSeqNum
= oldO3CPU
->globalSeqNum
;
1153 lastRunningCycle
= curCycle();
1157 template <class Impl
>
1159 FullO3CPU
<Impl
>::verifyMemoryMode() const
1161 if (!system
->isTimingMode()) {
1162 fatal("The O3 CPU requires the memory system to be in "
1163 "'timing' mode.\n");
1167 template <class Impl
>
1169 FullO3CPU
<Impl
>::readMiscRegNoEffect(int misc_reg
, ThreadID tid
) const
1171 return this->isa
[tid
]->readMiscRegNoEffect(misc_reg
);
1174 template <class Impl
>
1176 FullO3CPU
<Impl
>::readMiscReg(int misc_reg
, ThreadID tid
)
1179 return this->isa
[tid
]->readMiscReg(misc_reg
, tcBase(tid
));
1182 template <class Impl
>
1184 FullO3CPU
<Impl
>::setMiscRegNoEffect(int misc_reg
, RegVal val
, ThreadID tid
)
1186 this->isa
[tid
]->setMiscRegNoEffect(misc_reg
, val
);
1189 template <class Impl
>
1191 FullO3CPU
<Impl
>::setMiscReg(int misc_reg
, RegVal val
, ThreadID tid
)
1193 miscRegfileWrites
++;
1194 this->isa
[tid
]->setMiscReg(misc_reg
, val
, tcBase(tid
));
1197 template <class Impl
>
1199 FullO3CPU
<Impl
>::readIntReg(PhysRegIdPtr phys_reg
)
1202 return regFile
.readIntReg(phys_reg
);
1205 template <class Impl
>
1207 FullO3CPU
<Impl
>::readFloatReg(PhysRegIdPtr phys_reg
)
1210 return regFile
.readFloatReg(phys_reg
);
1213 template <class Impl
>
1215 FullO3CPU
<Impl
>::readVecReg(PhysRegIdPtr phys_reg
) const
1216 -> const VecRegContainer
&
1219 return regFile
.readVecReg(phys_reg
);
1222 template <class Impl
>
1224 FullO3CPU
<Impl
>::getWritableVecReg(PhysRegIdPtr phys_reg
)
1228 return regFile
.getWritableVecReg(phys_reg
);
1231 template <class Impl
>
1233 FullO3CPU
<Impl
>::readVecElem(PhysRegIdPtr phys_reg
) const -> const VecElem
&
1236 return regFile
.readVecElem(phys_reg
);
1239 template <class Impl
>
1241 FullO3CPU
<Impl
>::readVecPredReg(PhysRegIdPtr phys_reg
) const
1242 -> const VecPredRegContainer
&
1244 vecPredRegfileReads
++;
1245 return regFile
.readVecPredReg(phys_reg
);
1248 template <class Impl
>
1250 FullO3CPU
<Impl
>::getWritableVecPredReg(PhysRegIdPtr phys_reg
)
1251 -> VecPredRegContainer
&
1253 vecPredRegfileWrites
++;
1254 return regFile
.getWritableVecPredReg(phys_reg
);
1257 template <class Impl
>
1259 FullO3CPU
<Impl
>::readCCReg(PhysRegIdPtr phys_reg
)
1262 return regFile
.readCCReg(phys_reg
);
1265 template <class Impl
>
1267 FullO3CPU
<Impl
>::setIntReg(PhysRegIdPtr phys_reg
, RegVal val
)
1270 regFile
.setIntReg(phys_reg
, val
);
1273 template <class Impl
>
1275 FullO3CPU
<Impl
>::setFloatReg(PhysRegIdPtr phys_reg
, RegVal val
)
1278 regFile
.setFloatReg(phys_reg
, val
);
1281 template <class Impl
>
1283 FullO3CPU
<Impl
>::setVecReg(PhysRegIdPtr phys_reg
, const VecRegContainer
& val
)
1286 regFile
.setVecReg(phys_reg
, val
);
1289 template <class Impl
>
1291 FullO3CPU
<Impl
>::setVecElem(PhysRegIdPtr phys_reg
, const VecElem
& val
)
1294 regFile
.setVecElem(phys_reg
, val
);
1297 template <class Impl
>
1299 FullO3CPU
<Impl
>::setVecPredReg(PhysRegIdPtr phys_reg
,
1300 const VecPredRegContainer
& val
)
1302 vecPredRegfileWrites
++;
1303 regFile
.setVecPredReg(phys_reg
, val
);
1306 template <class Impl
>
1308 FullO3CPU
<Impl
>::setCCReg(PhysRegIdPtr phys_reg
, RegVal val
)
1311 regFile
.setCCReg(phys_reg
, val
);
1314 template <class Impl
>
1316 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, ThreadID tid
)
1319 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1320 RegId(IntRegClass
, reg_idx
));
1322 return regFile
.readIntReg(phys_reg
);
1325 template <class Impl
>
1327 FullO3CPU
<Impl
>::readArchFloatReg(int reg_idx
, ThreadID tid
)
1330 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1331 RegId(FloatRegClass
, reg_idx
));
1333 return regFile
.readFloatReg(phys_reg
);
1336 template <class Impl
>
1338 FullO3CPU
<Impl
>::readArchVecReg(int reg_idx
, ThreadID tid
) const
1339 -> const VecRegContainer
&
1341 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1342 RegId(VecRegClass
, reg_idx
));
1343 return readVecReg(phys_reg
);
1346 template <class Impl
>
1348 FullO3CPU
<Impl
>::getWritableArchVecReg(int reg_idx
, ThreadID tid
)
1351 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1352 RegId(VecRegClass
, reg_idx
));
1353 return getWritableVecReg(phys_reg
);
1356 template <class Impl
>
1358 FullO3CPU
<Impl
>::readArchVecElem(const RegIndex
& reg_idx
, const ElemIndex
& ldx
,
1359 ThreadID tid
) const -> const VecElem
&
1361 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1362 RegId(VecElemClass
, reg_idx
, ldx
));
1363 return readVecElem(phys_reg
);
1366 template <class Impl
>
1368 FullO3CPU
<Impl
>::readArchVecPredReg(int reg_idx
, ThreadID tid
) const
1369 -> const VecPredRegContainer
&
1371 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1372 RegId(VecPredRegClass
, reg_idx
));
1373 return readVecPredReg(phys_reg
);
1376 template <class Impl
>
1378 FullO3CPU
<Impl
>::getWritableArchVecPredReg(int reg_idx
, ThreadID tid
)
1379 -> VecPredRegContainer
&
1381 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1382 RegId(VecPredRegClass
, reg_idx
));
1383 return getWritableVecPredReg(phys_reg
);
1386 template <class Impl
>
1388 FullO3CPU
<Impl
>::readArchCCReg(int reg_idx
, ThreadID tid
)
1391 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1392 RegId(CCRegClass
, reg_idx
));
1394 return regFile
.readCCReg(phys_reg
);
1397 template <class Impl
>
1399 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, RegVal val
, ThreadID tid
)
1402 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1403 RegId(IntRegClass
, reg_idx
));
1405 regFile
.setIntReg(phys_reg
, val
);
1408 template <class Impl
>
1410 FullO3CPU
<Impl
>::setArchFloatReg(int reg_idx
, RegVal val
, ThreadID tid
)
1413 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1414 RegId(FloatRegClass
, reg_idx
));
1416 regFile
.setFloatReg(phys_reg
, val
);
1419 template <class Impl
>
1421 FullO3CPU
<Impl
>::setArchVecReg(int reg_idx
, const VecRegContainer
& val
,
1424 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1425 RegId(VecRegClass
, reg_idx
));
1426 setVecReg(phys_reg
, val
);
1429 template <class Impl
>
1431 FullO3CPU
<Impl
>::setArchVecElem(const RegIndex
& reg_idx
, const ElemIndex
& ldx
,
1432 const VecElem
& val
, ThreadID tid
)
1434 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1435 RegId(VecElemClass
, reg_idx
, ldx
));
1436 setVecElem(phys_reg
, val
);
1439 template <class Impl
>
1441 FullO3CPU
<Impl
>::setArchVecPredReg(int reg_idx
, const VecPredRegContainer
& val
,
1444 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1445 RegId(VecPredRegClass
, reg_idx
));
1446 setVecPredReg(phys_reg
, val
);
1449 template <class Impl
>
1451 FullO3CPU
<Impl
>::setArchCCReg(int reg_idx
, RegVal val
, ThreadID tid
)
1454 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1455 RegId(CCRegClass
, reg_idx
));
1457 regFile
.setCCReg(phys_reg
, val
);
1460 template <class Impl
>
1462 FullO3CPU
<Impl
>::pcState(ThreadID tid
)
1464 return commit
.pcState(tid
);
1467 template <class Impl
>
1469 FullO3CPU
<Impl
>::pcState(const TheISA::PCState
&val
, ThreadID tid
)
1471 commit
.pcState(val
, tid
);
1474 template <class Impl
>
1476 FullO3CPU
<Impl
>::instAddr(ThreadID tid
)
1478 return commit
.instAddr(tid
);
1481 template <class Impl
>
1483 FullO3CPU
<Impl
>::nextInstAddr(ThreadID tid
)
1485 return commit
.nextInstAddr(tid
);
1488 template <class Impl
>
1490 FullO3CPU
<Impl
>::microPC(ThreadID tid
)
1492 return commit
.microPC(tid
);
1495 template <class Impl
>
1497 FullO3CPU
<Impl
>::squashFromTC(ThreadID tid
)
1499 this->thread
[tid
]->noSquashFromTC
= true;
1500 this->commit
.generateTCEvent(tid
);
1503 template <class Impl
>
1504 typename FullO3CPU
<Impl
>::ListIt
1505 FullO3CPU
<Impl
>::addInst(const DynInstPtr
&inst
)
1507 instList
.push_back(inst
);
1509 return --(instList
.end());
1512 template <class Impl
>
1514 FullO3CPU
<Impl
>::instDone(ThreadID tid
, const DynInstPtr
&inst
)
1516 // Keep an instruction count.
1517 if (!inst
->isMicroop() || inst
->isLastMicroop()) {
1518 thread
[tid
]->numInst
++;
1519 thread
[tid
]->numInsts
++;
1520 committedInsts
[tid
]++;
1521 system
->totalNumInsts
++;
1523 // Check for instruction-count-based events.
1524 comInstEventQueue
[tid
]->serviceEvents(thread
[tid
]->numInst
);
1526 thread
[tid
]->numOp
++;
1527 thread
[tid
]->numOps
++;
1528 committedOps
[tid
]++;
1530 probeInstCommit(inst
->staticInst
, inst
->instAddr());
1533 template <class Impl
>
1535 FullO3CPU
<Impl
>::removeFrontInst(const DynInstPtr
&inst
)
1537 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %s "
1539 inst
->threadNumber
, inst
->pcState(), inst
->seqNum
);
1541 removeInstsThisCycle
= true;
1543 // Remove the front instruction.
1544 removeList
.push(inst
->getInstListIt());
1547 template <class Impl
>
1549 FullO3CPU
<Impl
>::removeInstsNotInROB(ThreadID tid
)
1551 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1556 bool rob_empty
= false;
1558 if (instList
.empty()) {
1560 } else if (rob
.isEmpty(tid
)) {
1561 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1562 end_it
= instList
.begin();
1565 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1566 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1569 removeInstsThisCycle
= true;
1571 ListIt inst_it
= instList
.end();
1575 // Walk through the instruction list, removing any instructions
1576 // that were inserted after the given instruction iterator, end_it.
1577 while (inst_it
!= end_it
) {
1578 assert(!instList
.empty());
1580 squashInstIt(inst_it
, tid
);
1585 // If the ROB was empty, then we actually need to remove the first
1586 // instruction as well.
1588 squashInstIt(inst_it
, tid
);
1592 template <class Impl
>
1594 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
, ThreadID tid
)
1596 assert(!instList
.empty());
1598 removeInstsThisCycle
= true;
1600 ListIt inst_iter
= instList
.end();
1604 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1605 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1606 tid
, seq_num
, (*inst_iter
)->seqNum
);
1608 while ((*inst_iter
)->seqNum
> seq_num
) {
1610 bool break_loop
= (inst_iter
== instList
.begin());
1612 squashInstIt(inst_iter
, tid
);
1621 template <class Impl
>
1623 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, ThreadID tid
)
1625 if ((*instIt
)->threadNumber
== tid
) {
1626 DPRINTF(O3CPU
, "Squashing instruction, "
1627 "[tid:%i] [sn:%lli] PC %s\n",
1628 (*instIt
)->threadNumber
,
1630 (*instIt
)->pcState());
1632 // Mark it as squashed.
1633 (*instIt
)->setSquashed();
1635 // @todo: Formulate a consistent method for deleting
1636 // instructions from the instruction list
1637 // Remove the instruction from the list.
1638 removeList
.push(instIt
);
1642 template <class Impl
>
1644 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1646 while (!removeList
.empty()) {
1647 DPRINTF(O3CPU
, "Removing instruction, "
1648 "[tid:%i] [sn:%lli] PC %s\n",
1649 (*removeList
.front())->threadNumber
,
1650 (*removeList
.front())->seqNum
,
1651 (*removeList
.front())->pcState());
1653 instList
.erase(removeList
.front());
1658 removeInstsThisCycle
= false;
1661 template <class Impl>
1663 FullO3CPU<Impl>::removeAllInsts()
1668 template <class Impl
>
1670 FullO3CPU
<Impl
>::dumpInsts()
1674 ListIt inst_list_it
= instList
.begin();
1676 cprintf("Dumping Instruction List\n");
1678 while (inst_list_it
!= instList
.end()) {
1679 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1681 num
, (*inst_list_it
)->instAddr(), (*inst_list_it
)->threadNumber
,
1682 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1683 (*inst_list_it
)->isSquashed());
1689 template <class Impl>
1691 FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst)
1693 iew.wakeDependents(inst);
1696 template <class Impl
>
1698 FullO3CPU
<Impl
>::wakeCPU()
1700 if (activityRec
.active() || tickEvent
.scheduled()) {
1701 DPRINTF(Activity
, "CPU already running.\n");
1705 DPRINTF(Activity
, "Waking up CPU\n");
1707 Cycles
cycles(curCycle() - lastRunningCycle
);
1708 // @todo: This is an oddity that is only here to match the stats
1711 idleCycles
+= cycles
;
1712 numCycles
+= cycles
;
1715 schedule(tickEvent
, clockEdge());
1718 template <class Impl
>
1720 FullO3CPU
<Impl
>::wakeup(ThreadID tid
)
1722 if (this->thread
[tid
]->status() != ThreadContext::Suspended
)
1727 DPRINTF(Quiesce
, "Suspended Processor woken\n");
1728 this->threadContexts
[tid
]->activate();
1731 template <class Impl
>
1733 FullO3CPU
<Impl
>::getFreeTid()
1735 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
1742 return InvalidThreadID
;
1745 template <class Impl
>
1747 FullO3CPU
<Impl
>::updateThreadPriority()
1749 if (activeThreads
.size() > 1) {
1750 //DEFAULT TO ROUND ROBIN SCHEME
1751 //e.g. Move highest priority to end of thread list
1752 list
<ThreadID
>::iterator list_begin
= activeThreads
.begin();
1754 unsigned high_thread
= *list_begin
;
1756 activeThreads
.erase(list_begin
);
1758 activeThreads
.push_back(high_thread
);
1762 template <class Impl
>
1764 FullO3CPU
<Impl
>::addThreadToExitingList(ThreadID tid
)
1766 DPRINTF(O3CPU
, "Thread %d is inserted to exitingThreads list\n", tid
);
1768 // the thread trying to exit can't be already halted
1769 assert(tcBase(tid
)->status() != ThreadContext::Halted
);
1771 // make sure the thread has not been added to the list yet
1772 assert(exitingThreads
.count(tid
) == 0);
1774 // add the thread to exitingThreads list to mark that this thread is
1775 // trying to exit. The boolean value in the pair denotes if a thread is
1776 // ready to exit. The thread is not ready to exit until the corresponding
1777 // exit trap event is processed in the future. Until then, it'll be still
1778 // an active thread that is trying to exit.
1779 exitingThreads
.emplace(std::make_pair(tid
, false));
1782 template <class Impl
>
1784 FullO3CPU
<Impl
>::isThreadExiting(ThreadID tid
) const
1786 return exitingThreads
.count(tid
) == 1;
1789 template <class Impl
>
1791 FullO3CPU
<Impl
>::scheduleThreadExitEvent(ThreadID tid
)
1793 assert(exitingThreads
.count(tid
) == 1);
1795 // exit trap event has been processed. Now, the thread is ready to exit
1796 // and be removed from the CPU.
1797 exitingThreads
[tid
] = true;
1799 // we schedule a threadExitEvent in the next cycle to properly clean
1800 // up the thread's states in the pipeline. threadExitEvent has lower
1801 // priority than tickEvent, so the cleanup will happen at the very end
1802 // of the next cycle after all pipeline stages complete their operations.
1803 // We want all stages to complete squashing instructions before doing
1805 if (!threadExitEvent
.scheduled()) {
1806 schedule(threadExitEvent
, nextCycle());
1810 template <class Impl
>
1812 FullO3CPU
<Impl
>::exitThreads()
1814 // there must be at least one thread trying to exit
1815 assert(exitingThreads
.size() > 0);
1817 // terminate all threads that are ready to exit
1818 auto it
= exitingThreads
.begin();
1819 while (it
!= exitingThreads
.end()) {
1820 ThreadID thread_id
= it
->first
;
1821 bool readyToExit
= it
->second
;
1824 DPRINTF(O3CPU
, "Exiting thread %d\n", thread_id
);
1825 haltContext(thread_id
);
1826 tcBase(thread_id
)->setStatus(ThreadContext::Halted
);
1827 it
= exitingThreads
.erase(it
);
1834 // Forward declaration of FullO3CPU.
1835 template class FullO3CPU
<O3CPUImpl
>;