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
)
95 FullO3CPU
<Impl
>::IcachePort::recvTimingResp(PacketPtr pkt
)
97 DPRINTF(O3CPU
, "Fetch unit received timing\n");
98 // We shouldn't ever get a cacheable block in Modified state
99 assert(pkt
->req
->isUncacheable() ||
100 !(pkt
->cacheResponding() && !pkt
->hasSharers()));
101 fetch
->processCacheCompletion(pkt
);
108 FullO3CPU
<Impl
>::IcachePort::recvReqRetry()
110 fetch
->recvReqRetry();
113 template <class Impl
>
115 FullO3CPU
<Impl
>::DcachePort::recvTimingResp(PacketPtr pkt
)
117 return lsq
->recvTimingResp(pkt
);
120 template <class Impl
>
122 FullO3CPU
<Impl
>::DcachePort::recvTimingSnoopReq(PacketPtr pkt
)
124 for (ThreadID tid
= 0; tid
< cpu
->numThreads
; tid
++) {
125 if (cpu
->getCpuAddrMonitor(tid
)->doMonitor(pkt
)) {
129 lsq
->recvTimingSnoopReq(pkt
);
132 template <class Impl
>
134 FullO3CPU
<Impl
>::DcachePort::recvReqRetry()
139 template <class Impl
>
140 FullO3CPU
<Impl
>::FullO3CPU(DerivO3CPUParams
*params
)
144 tickEvent([this]{ tick(); }, "FullO3CPU tick",
145 false, Event::CPU_Tick_Pri
),
146 threadExitEvent([this]{ exitThreads(); }, "FullO3CPU exit threads",
147 false, Event::CPU_Exit_Pri
),
151 removeInstsThisCycle(false),
153 decode(this, params
),
154 rename(this, params
),
156 commit(this, params
),
158 /* It is mandatory that all SMT threads use the same renaming mode as
159 * they are sharing registers and rename */
160 vecMode(RenameMode
<TheISA::ISA
>::init(params
->isa
[0])),
161 regFile(params
->numPhysIntRegs
,
162 params
->numPhysFloatRegs
,
163 params
->numPhysVecRegs
,
164 params
->numPhysVecPredRegs
,
165 params
->numPhysCCRegs
,
168 freeList(name() + ".freelist", ®File
),
172 scoreboard(name() + ".scoreboard",
173 regFile
.totalNumPhysRegs()),
175 isa(numThreads
, NULL
),
177 icachePort(&fetch
, this),
178 dcachePort(&iew
.ldstQueue
, this),
180 timeBuffer(params
->backComSize
, params
->forwardComSize
),
181 fetchQueue(params
->backComSize
, params
->forwardComSize
),
182 decodeQueue(params
->backComSize
, params
->forwardComSize
),
183 renameQueue(params
->backComSize
, params
->forwardComSize
),
184 iewQueue(params
->backComSize
, params
->forwardComSize
),
185 activityRec(name(), NumStages
,
186 params
->backComSize
+ params
->forwardComSize
,
190 system(params
->system
),
191 lastRunningCycle(curCycle())
193 if (!params
->switched_out
) {
196 _status
= SwitchedOut
;
199 if (params
->checker
) {
200 BaseCPU
*temp_checker
= params
->checker
;
201 checker
= dynamic_cast<Checker
<Impl
> *>(temp_checker
);
202 checker
->setIcachePort(&icachePort
);
203 checker
->setSystem(params
->system
);
209 thread
.resize(numThreads
);
210 tids
.resize(numThreads
);
213 // The stages also need their CPU pointer setup. However this
214 // must be done at the upper level CPU because they have pointers
215 // to the upper level CPU, and not this FullO3CPU.
217 // Set up Pointers to the activeThreads list for each stage
218 fetch
.setActiveThreads(&activeThreads
);
219 decode
.setActiveThreads(&activeThreads
);
220 rename
.setActiveThreads(&activeThreads
);
221 iew
.setActiveThreads(&activeThreads
);
222 commit
.setActiveThreads(&activeThreads
);
224 // Give each of the stages the time buffer they will use.
225 fetch
.setTimeBuffer(&timeBuffer
);
226 decode
.setTimeBuffer(&timeBuffer
);
227 rename
.setTimeBuffer(&timeBuffer
);
228 iew
.setTimeBuffer(&timeBuffer
);
229 commit
.setTimeBuffer(&timeBuffer
);
231 // Also setup each of the stages' queues.
232 fetch
.setFetchQueue(&fetchQueue
);
233 decode
.setFetchQueue(&fetchQueue
);
234 commit
.setFetchQueue(&fetchQueue
);
235 decode
.setDecodeQueue(&decodeQueue
);
236 rename
.setDecodeQueue(&decodeQueue
);
237 rename
.setRenameQueue(&renameQueue
);
238 iew
.setRenameQueue(&renameQueue
);
239 iew
.setIEWQueue(&iewQueue
);
240 commit
.setIEWQueue(&iewQueue
);
241 commit
.setRenameQueue(&renameQueue
);
243 commit
.setIEWStage(&iew
);
244 rename
.setIEWStage(&iew
);
245 rename
.setCommitStage(&commit
);
247 ThreadID active_threads
;
251 active_threads
= params
->workload
.size();
253 if (active_threads
> Impl::MaxThreads
) {
254 panic("Workload Size too large. Increase the 'MaxThreads' "
255 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) "
256 "or edit your workload size.");
260 //Make Sure That this a Valid Architeture
261 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
262 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
263 assert(params
->numPhysVecRegs
>= numThreads
* TheISA::NumVecRegs
);
264 assert(params
->numPhysVecPredRegs
>= numThreads
* TheISA::NumVecPredRegs
);
265 assert(params
->numPhysCCRegs
>= numThreads
* TheISA::NumCCRegs
);
267 rename
.setScoreboard(&scoreboard
);
268 iew
.setScoreboard(&scoreboard
);
270 // Setup the rename map for whichever stages need it.
271 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
272 isa
[tid
] = params
->isa
[tid
];
273 assert(RenameMode
<TheISA::ISA
>::equalsInit(isa
[tid
], isa
[0]));
275 // Only Alpha has an FP zero register, so for other ISAs we
276 // use an invalid FP register index to avoid special treatment
277 // of any valid FP reg.
278 RegIndex invalidFPReg
= TheISA::NumFloatRegs
+ 1;
280 (THE_ISA
== ALPHA_ISA
) ? TheISA::ZeroReg
: invalidFPReg
;
282 commitRenameMap
[tid
].init(®File
, TheISA::ZeroReg
, fpZeroReg
,
286 renameMap
[tid
].init(®File
, TheISA::ZeroReg
, fpZeroReg
,
290 // Initialize rename map to assign physical registers to the
291 // architectural registers for active threads only.
292 for (ThreadID tid
= 0; tid
< active_threads
; tid
++) {
293 for (RegIndex ridx
= 0; ridx
< TheISA::NumIntRegs
; ++ridx
) {
294 // Note that we can't use the rename() method because we don't
295 // want special treatment for the zero register at this point
296 PhysRegIdPtr phys_reg
= freeList
.getIntReg();
297 renameMap
[tid
].setEntry(RegId(IntRegClass
, ridx
), phys_reg
);
298 commitRenameMap
[tid
].setEntry(RegId(IntRegClass
, ridx
), phys_reg
);
301 for (RegIndex ridx
= 0; ridx
< TheISA::NumFloatRegs
; ++ridx
) {
302 PhysRegIdPtr phys_reg
= freeList
.getFloatReg();
303 renameMap
[tid
].setEntry(RegId(FloatRegClass
, ridx
), phys_reg
);
304 commitRenameMap
[tid
].setEntry(
305 RegId(FloatRegClass
, ridx
), phys_reg
);
308 /* Here we need two 'interfaces' the 'whole register' and the
309 * 'register element'. At any point only one of them will be
311 if (vecMode
== Enums::Full
) {
312 /* Initialize the full-vector interface */
313 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecRegs
; ++ridx
) {
314 RegId rid
= RegId(VecRegClass
, ridx
);
315 PhysRegIdPtr phys_reg
= freeList
.getVecReg();
316 renameMap
[tid
].setEntry(rid
, phys_reg
);
317 commitRenameMap
[tid
].setEntry(rid
, phys_reg
);
320 /* Initialize the vector-element interface */
321 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecRegs
; ++ridx
) {
322 for (ElemIndex ldx
= 0; ldx
< TheISA::NumVecElemPerVecReg
;
324 RegId lrid
= RegId(VecElemClass
, ridx
, ldx
);
325 PhysRegIdPtr phys_elem
= freeList
.getVecElem();
326 renameMap
[tid
].setEntry(lrid
, phys_elem
);
327 commitRenameMap
[tid
].setEntry(lrid
, phys_elem
);
332 for (RegIndex ridx
= 0; ridx
< TheISA::NumVecPredRegs
; ++ridx
) {
333 PhysRegIdPtr phys_reg
= freeList
.getVecPredReg();
334 renameMap
[tid
].setEntry(RegId(VecPredRegClass
, ridx
), phys_reg
);
335 commitRenameMap
[tid
].setEntry(
336 RegId(VecPredRegClass
, ridx
), phys_reg
);
339 for (RegIndex ridx
= 0; ridx
< TheISA::NumCCRegs
; ++ridx
) {
340 PhysRegIdPtr phys_reg
= freeList
.getCCReg();
341 renameMap
[tid
].setEntry(RegId(CCRegClass
, ridx
), phys_reg
);
342 commitRenameMap
[tid
].setEntry(RegId(CCRegClass
, ridx
), phys_reg
);
346 rename
.setRenameMap(renameMap
);
347 commit
.setRenameMap(commitRenameMap
);
348 rename
.setFreeList(&freeList
);
350 // Setup the ROB for whichever stages need it.
353 lastActivatedCycle
= 0;
355 // Give renameMap & rename stage access to the freeList;
356 for (ThreadID tid
= 0; tid
< numThreads
; tid
++)
357 globalSeqNum
[tid
] = 1;
360 DPRINTF(O3CPU
, "Creating O3CPU object.\n");
362 // Setup any thread state.
363 this->thread
.resize(this->numThreads
);
365 for (ThreadID tid
= 0; tid
< this->numThreads
; ++tid
) {
367 // SMT is not supported in FS mode yet.
368 assert(this->numThreads
== 1);
369 this->thread
[tid
] = new Thread(this, 0, NULL
);
371 if (tid
< params
->workload
.size()) {
372 DPRINTF(O3CPU
, "Workload[%i] process is %#x",
373 tid
, this->thread
[tid
]);
374 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
375 (typename
Impl::O3CPU
*)(this),
376 tid
, params
->workload
[tid
]);
378 //usedTids[tid] = true;
379 //threadMap[tid] = tid;
381 //Allocate Empty thread so M5 can use later
382 //when scheduling threads to CPU
383 Process
* dummy_proc
= NULL
;
385 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
386 (typename
Impl::O3CPU
*)(this),
388 //usedTids[tid] = false;
394 // Setup the TC that will serve as the interface to the threads/CPU.
395 O3ThreadContext
<Impl
> *o3_tc
= new O3ThreadContext
<Impl
>;
399 // If we're using a checker, then the TC should be the
400 // CheckerThreadContext.
401 if (params
->checker
) {
402 tc
= new CheckerThreadContext
<O3ThreadContext
<Impl
> >(
403 o3_tc
, this->checker
);
406 o3_tc
->cpu
= (typename
Impl::O3CPU
*)(this);
408 o3_tc
->thread
= this->thread
[tid
];
410 // Setup quiesce event.
411 this->thread
[tid
]->quiesceEvent
= new EndQuiesceEvent(tc
);
413 // Give the thread the TC.
414 this->thread
[tid
]->tc
= tc
;
416 // Add the TC to the CPU's list of TC's.
417 this->threadContexts
.push_back(tc
);
420 // FullO3CPU always requires an interrupt controller.
421 if (!params
->switched_out
&& interrupts
.empty()) {
422 fatal("FullO3CPU %s has no interrupt controller.\n"
423 "Ensure createInterruptController() is called.\n", name());
426 for (ThreadID tid
= 0; tid
< this->numThreads
; tid
++)
427 this->thread
[tid
]->setFuncExeInst(0);
430 template <class Impl
>
431 FullO3CPU
<Impl
>::~FullO3CPU()
435 template <class Impl
>
437 FullO3CPU
<Impl
>::regProbePoints()
439 BaseCPU::regProbePoints();
441 ppInstAccessComplete
= new ProbePointArg
<PacketPtr
>(getProbeManager(), "InstAccessComplete");
442 ppDataAccessComplete
= new ProbePointArg
<std::pair
<DynInstPtr
, PacketPtr
> >(getProbeManager(), "DataAccessComplete");
444 fetch
.regProbePoints();
445 rename
.regProbePoints();
446 iew
.regProbePoints();
447 commit
.regProbePoints();
450 template <class Impl
>
452 FullO3CPU
<Impl
>::regStats()
454 BaseO3CPU::regStats();
456 // Register any of the O3CPU's stats here.
458 .name(name() + ".timesIdled")
459 .desc("Number of times that the entire CPU went into an idle state and"
460 " unscheduled itself")
464 .name(name() + ".idleCycles")
465 .desc("Total number of cycles that the CPU has spent unscheduled due "
470 .name(name() + ".quiesceCycles")
471 .desc("Total number of cycles that CPU has spent quiesced or waiting "
473 .prereq(quiesceCycles
);
475 // Number of Instructions simulated
476 // --------------------------------
477 // Should probably be in Base CPU but need templated
478 // MaxThreads so put in here instead
481 .name(name() + ".committedInsts")
482 .desc("Number of Instructions Simulated")
483 .flags(Stats::total
);
487 .name(name() + ".committedOps")
488 .desc("Number of Ops (including micro ops) Simulated")
489 .flags(Stats::total
);
492 .name(name() + ".cpi")
493 .desc("CPI: Cycles Per Instruction")
495 cpi
= numCycles
/ committedInsts
;
498 .name(name() + ".cpi_total")
499 .desc("CPI: Total CPI of All Threads")
501 totalCpi
= numCycles
/ sum(committedInsts
);
504 .name(name() + ".ipc")
505 .desc("IPC: Instructions Per Cycle")
507 ipc
= committedInsts
/ numCycles
;
510 .name(name() + ".ipc_total")
511 .desc("IPC: Total IPC of All Threads")
513 totalIpc
= sum(committedInsts
) / numCycles
;
515 this->fetch
.regStats();
516 this->decode
.regStats();
517 this->rename
.regStats();
518 this->iew
.regStats();
519 this->commit
.regStats();
520 this->rob
.regStats();
523 .name(name() + ".int_regfile_reads")
524 .desc("number of integer regfile reads")
525 .prereq(intRegfileReads
);
528 .name(name() + ".int_regfile_writes")
529 .desc("number of integer regfile writes")
530 .prereq(intRegfileWrites
);
533 .name(name() + ".fp_regfile_reads")
534 .desc("number of floating regfile reads")
535 .prereq(fpRegfileReads
);
538 .name(name() + ".fp_regfile_writes")
539 .desc("number of floating regfile writes")
540 .prereq(fpRegfileWrites
);
543 .name(name() + ".vec_regfile_reads")
544 .desc("number of vector regfile reads")
545 .prereq(vecRegfileReads
);
548 .name(name() + ".vec_regfile_writes")
549 .desc("number of vector regfile writes")
550 .prereq(vecRegfileWrites
);
553 .name(name() + ".pred_regfile_reads")
554 .desc("number of predicate regfile reads")
555 .prereq(vecPredRegfileReads
);
558 .name(name() + ".pred_regfile_writes")
559 .desc("number of predicate regfile writes")
560 .prereq(vecPredRegfileWrites
);
563 .name(name() + ".cc_regfile_reads")
564 .desc("number of cc regfile reads")
565 .prereq(ccRegfileReads
);
568 .name(name() + ".cc_regfile_writes")
569 .desc("number of cc regfile writes")
570 .prereq(ccRegfileWrites
);
573 .name(name() + ".misc_regfile_reads")
574 .desc("number of misc regfile reads")
575 .prereq(miscRegfileReads
);
578 .name(name() + ".misc_regfile_writes")
579 .desc("number of misc regfile writes")
580 .prereq(miscRegfileWrites
);
583 template <class Impl
>
585 FullO3CPU
<Impl
>::tick()
587 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
588 assert(!switchedOut());
589 assert(drainState() != DrainState::Drained
);
592 updateCycleCounters(BaseCPU::CPU_STATE_ON
);
596 //Tick each of the stages
607 // Now advance the time buffers
608 timeBuffer
.advance();
610 fetchQueue
.advance();
611 decodeQueue
.advance();
612 renameQueue
.advance();
615 activityRec
.advance();
617 if (removeInstsThisCycle
) {
618 cleanUpRemovedInsts();
621 if (!tickEvent
.scheduled()) {
622 if (_status
== SwitchedOut
) {
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();
642 template <class Impl
>
644 FullO3CPU
<Impl
>::init()
648 for (ThreadID tid
= 0; tid
< numThreads
; ++tid
) {
649 // Set noSquashFromTC so that the CPU doesn't squash when initially
650 // setting up registers.
651 thread
[tid
]->noSquashFromTC
= true;
652 // Initialise the ThreadContext's memory proxies
653 thread
[tid
]->initMemProxies(thread
[tid
]->getTC());
656 if (FullSystem
&& !params()->switched_out
) {
657 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
658 ThreadContext
*src_tc
= threadContexts
[tid
];
659 TheISA::initCPU(src_tc
, src_tc
->contextId());
663 // Clear noSquashFromTC.
664 for (int tid
= 0; tid
< numThreads
; ++tid
)
665 thread
[tid
]->noSquashFromTC
= false;
667 commit
.setThreads(thread
);
670 template <class Impl
>
672 FullO3CPU
<Impl
>::startup()
675 for (int tid
= 0; tid
< numThreads
; ++tid
)
676 isa
[tid
]->startup(threadContexts
[tid
]);
678 fetch
.startupStage();
679 decode
.startupStage();
681 rename
.startupStage();
682 commit
.startupStage();
685 template <class Impl
>
687 FullO3CPU
<Impl
>::activateThread(ThreadID tid
)
689 list
<ThreadID
>::iterator isActive
=
690 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
692 DPRINTF(O3CPU
, "[tid:%i]: Calling activate thread.\n", tid
);
693 assert(!switchedOut());
695 if (isActive
== activeThreads
.end()) {
696 DPRINTF(O3CPU
, "[tid:%i]: Adding to active threads list\n",
699 activeThreads
.push_back(tid
);
703 template <class Impl
>
705 FullO3CPU
<Impl
>::deactivateThread(ThreadID tid
)
707 //Remove From Active List, if Active
708 list
<ThreadID
>::iterator thread_it
=
709 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
711 DPRINTF(O3CPU
, "[tid:%i]: Calling deactivate thread.\n", tid
);
712 assert(!switchedOut());
714 if (thread_it
!= activeThreads
.end()) {
715 DPRINTF(O3CPU
,"[tid:%i]: Removing from active threads list\n",
717 activeThreads
.erase(thread_it
);
720 fetch
.deactivateThread(tid
);
721 commit
.deactivateThread(tid
);
724 template <class Impl
>
726 FullO3CPU
<Impl
>::totalInsts() const
730 ThreadID size
= thread
.size();
731 for (ThreadID i
= 0; i
< size
; i
++)
732 total
+= thread
[i
]->numInst
;
737 template <class Impl
>
739 FullO3CPU
<Impl
>::totalOps() const
743 ThreadID size
= thread
.size();
744 for (ThreadID i
= 0; i
< size
; i
++)
745 total
+= thread
[i
]->numOp
;
750 template <class Impl
>
752 FullO3CPU
<Impl
>::activateContext(ThreadID tid
)
754 assert(!switchedOut());
756 // Needs to set each stage to running as well.
759 // We don't want to wake the CPU if it is drained. In that case,
760 // we just want to flag the thread as active and schedule the tick
761 // event from drainResume() instead.
762 if (drainState() == DrainState::Drained
)
765 // If we are time 0 or if the last activation time is in the past,
766 // schedule the next tick and wake up the fetch unit
767 if (lastActivatedCycle
== 0 || lastActivatedCycle
< curTick()) {
768 scheduleTickEvent(Cycles(0));
770 // Be sure to signal that there's some activity so the CPU doesn't
771 // deschedule itself.
772 activityRec
.activity();
773 fetch
.wakeFromQuiesce();
775 Cycles
cycles(curCycle() - lastRunningCycle
);
776 // @todo: This is an oddity that is only here to match the stats
779 quiesceCycles
+= cycles
;
781 lastActivatedCycle
= curTick();
785 BaseCPU::activateContext(tid
);
789 template <class Impl
>
791 FullO3CPU
<Impl
>::suspendContext(ThreadID tid
)
793 DPRINTF(O3CPU
,"[tid: %i]: Suspending Thread Context.\n", tid
);
794 assert(!switchedOut());
796 deactivateThread(tid
);
798 // If this was the last thread then unschedule the tick event.
799 if (activeThreads
.size() == 0) {
800 unscheduleTickEvent();
801 lastRunningCycle
= curCycle();
805 DPRINTF(Quiesce
, "Suspending Context\n");
807 BaseCPU::suspendContext(tid
);
810 template <class Impl
>
812 FullO3CPU
<Impl
>::haltContext(ThreadID tid
)
814 //For now, this is the same as deallocate
815 DPRINTF(O3CPU
,"[tid:%i]: Halt Context called. Deallocating\n", tid
);
816 assert(!switchedOut());
818 deactivateThread(tid
);
821 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP
);
824 template <class Impl
>
826 FullO3CPU
<Impl
>::insertThread(ThreadID tid
)
828 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
829 // Will change now that the PC and thread state is internal to the CPU
830 // and not in the ThreadContext.
831 ThreadContext
*src_tc
;
833 src_tc
= system
->threadContexts
[tid
];
835 src_tc
= tcBase(tid
);
837 //Bind Int Regs to Rename Map
839 for (RegId
reg_id(IntRegClass
, 0); reg_id
.index() < TheISA::NumIntRegs
;
841 PhysRegIdPtr phys_reg
= freeList
.getIntReg();
842 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
843 scoreboard
.setReg(phys_reg
);
846 //Bind Float Regs to Rename Map
847 for (RegId
reg_id(FloatRegClass
, 0); reg_id
.index() < TheISA::NumFloatRegs
;
849 PhysRegIdPtr phys_reg
= freeList
.getFloatReg();
850 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
851 scoreboard
.setReg(phys_reg
);
854 //Bind condition-code Regs to Rename Map
855 for (RegId
reg_id(CCRegClass
, 0); reg_id
.index() < TheISA::NumCCRegs
;
857 PhysRegIdPtr phys_reg
= freeList
.getCCReg();
858 renameMap
[tid
].setEntry(reg_id
, phys_reg
);
859 scoreboard
.setReg(phys_reg
);
862 //Copy Thread Data Into RegFile
863 //this->copyFromTC(tid);
866 pcState(src_tc
->pcState(), tid
);
868 src_tc
->setStatus(ThreadContext::Active
);
870 activateContext(tid
);
872 //Reset ROB/IQ/LSQ Entries
873 commit
.rob
->resetEntries();
876 template <class Impl
>
878 FullO3CPU
<Impl
>::removeThread(ThreadID tid
)
880 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
882 // Copy Thread Data From RegFile
883 // If thread is suspended, it might be re-allocated
884 // this->copyToTC(tid);
887 // @todo: 2-27-2008: Fix how we free up rename mappings
888 // here to alleviate the case for double-freeing registers
891 // clear all thread-specific states in each stage of the pipeline
892 // since this thread is going to be completely removed from the CPU
893 commit
.clearStates(tid
);
894 fetch
.clearStates(tid
);
895 decode
.clearStates(tid
);
896 rename
.clearStates(tid
);
897 iew
.clearStates(tid
);
899 // at this step, all instructions in the pipeline should be already
900 // either committed successfully or squashed. All thread-specific
901 // queues in the pipeline must be empty.
902 assert(iew
.instQueue
.getCount(tid
) == 0);
903 assert(iew
.ldstQueue
.getCount(tid
) == 0);
904 assert(commit
.rob
->isEmpty(tid
));
906 // Reset ROB/IQ/LSQ Entries
908 // Commented out for now. This should be possible to do by
909 // telling all the pipeline stages to drain first, and then
910 // checking until the drain completes. Once the pipeline is
911 // drained, call resetEntries(). - 10-09-06 ktlim
913 if (activeThreads.size() >= 1) {
914 commit.rob->resetEntries();
920 template <class Impl
>
922 FullO3CPU
<Impl
>::hwrei(ThreadID tid
)
924 #if THE_ISA == ALPHA_ISA
925 // Need to clear the lock flag upon returning from an interrupt.
926 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG
, false, tid
);
928 this->thread
[tid
]->kernelStats
->hwrei();
930 // FIXME: XXX check for interrupts? XXX
935 template <class Impl
>
937 FullO3CPU
<Impl
>::simPalCheck(int palFunc
, ThreadID tid
)
939 #if THE_ISA == ALPHA_ISA
940 if (this->thread
[tid
]->kernelStats
)
941 this->thread
[tid
]->kernelStats
->callpal(palFunc
,
942 this->threadContexts
[tid
]);
947 if (--System::numSystemsRunning
== 0)
948 exitSimLoop("all cpus halted");
953 if (this->system
->breakpoint())
961 template <class Impl
>
963 FullO3CPU
<Impl
>::switchRenameMode(ThreadID tid
, UnifiedFreeList
* freelist
)
965 auto pc
= this->pcState(tid
);
967 // new_mode is the new vector renaming mode
968 auto new_mode
= RenameMode
<TheISA::ISA
>::mode(pc
);
970 // We update vecMode only if there has been a change
971 if (new_mode
!= vecMode
) {
974 renameMap
[tid
].switchMode(vecMode
);
975 commitRenameMap
[tid
].switchMode(vecMode
);
976 renameMap
[tid
].switchFreeList(freelist
);
980 template <class Impl
>
982 FullO3CPU
<Impl
>::getInterrupts()
984 // Check if there are any outstanding interrupts
985 return this->interrupts
[0]->getInterrupt(this->threadContexts
[0]);
988 template <class Impl
>
990 FullO3CPU
<Impl
>::processInterrupts(const Fault
&interrupt
)
992 // Check for interrupts here. For now can copy the code that
993 // exists within isa_fullsys_traits.hh. Also assume that thread 0
994 // is the one that handles the interrupts.
995 // @todo: Possibly consolidate the interrupt checking code.
996 // @todo: Allow other threads to handle interrupts.
998 assert(interrupt
!= NoFault
);
999 this->interrupts
[0]->updateIntrInfo(this->threadContexts
[0]);
1001 DPRINTF(O3CPU
, "Interrupt %s being handled\n", interrupt
->name());
1002 this->trap(interrupt
, 0, nullptr);
1005 template <class Impl
>
1007 FullO3CPU
<Impl
>::trap(const Fault
&fault
, ThreadID tid
,
1008 const StaticInstPtr
&inst
)
1010 // Pass the thread's TC into the invoke method.
1011 fault
->invoke(this->threadContexts
[tid
], inst
);
1014 template <class Impl
>
1016 FullO3CPU
<Impl
>::syscall(int64_t callnum
, ThreadID tid
, Fault
*fault
)
1018 DPRINTF(O3CPU
, "[tid:%i] Executing syscall().\n\n", tid
);
1020 DPRINTF(Activity
,"Activity: syscall() called.\n");
1022 // Temporarily increase this by one to account for the syscall
1024 ++(this->thread
[tid
]->funcExeInst
);
1026 // Execute the actual syscall.
1027 this->thread
[tid
]->syscall(callnum
, fault
);
1029 // Decrease funcExeInst by one as the normal commit will handle
1031 --(this->thread
[tid
]->funcExeInst
);
1034 template <class Impl
>
1036 FullO3CPU
<Impl
>::serializeThread(CheckpointOut
&cp
, ThreadID tid
) const
1038 thread
[tid
]->serialize(cp
);
1041 template <class Impl
>
1043 FullO3CPU
<Impl
>::unserializeThread(CheckpointIn
&cp
, ThreadID tid
)
1045 thread
[tid
]->unserialize(cp
);
1048 template <class Impl
>
1050 FullO3CPU
<Impl
>::drain()
1052 // Deschedule any power gating event (if any)
1053 deschedulePowerGatingEvent();
1055 // If the CPU isn't doing anything, then return immediately.
1057 return DrainState::Drained
;
1059 DPRINTF(Drain
, "Draining...\n");
1061 // We only need to signal a drain to the commit stage as this
1062 // initiates squashing controls the draining. Once the commit
1063 // stage commits an instruction where it is safe to stop, it'll
1064 // squash the rest of the instructions in the pipeline and force
1065 // the fetch stage to stall. The pipeline will be drained once all
1066 // in-flight instructions have retired.
1069 // Wake the CPU and record activity so everything can drain out if
1070 // the CPU was not able to immediately drain.
1072 // If a thread is suspended, wake it up so it can be drained
1073 for (auto t
: threadContexts
) {
1074 if (t
->status() == ThreadContext::Suspended
){
1075 DPRINTF(Drain
, "Currently suspended so activate %i \n",
1078 // As the thread is now active, change the power state as well
1079 activateContext(t
->threadId());
1084 activityRec
.activity();
1086 DPRINTF(Drain
, "CPU not drained\n");
1088 return DrainState::Draining
;
1090 DPRINTF(Drain
, "CPU is already drained\n");
1091 if (tickEvent
.scheduled())
1092 deschedule(tickEvent
);
1094 // Flush out any old data from the time buffers. In
1095 // particular, there might be some data in flight from the
1096 // fetch stage that isn't visible in any of the CPU buffers we
1097 // test in isDrained().
1098 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
1099 timeBuffer
.advance();
1100 fetchQueue
.advance();
1101 decodeQueue
.advance();
1102 renameQueue
.advance();
1107 return DrainState::Drained
;
1111 template <class Impl
>
1113 FullO3CPU
<Impl
>::tryDrain()
1115 if (drainState() != DrainState::Draining
|| !isDrained())
1118 if (tickEvent
.scheduled())
1119 deschedule(tickEvent
);
1121 DPRINTF(Drain
, "CPU done draining, processing drain event\n");
1127 template <class Impl
>
1129 FullO3CPU
<Impl
>::drainSanityCheck() const
1131 assert(isDrained());
1132 fetch
.drainSanityCheck();
1133 decode
.drainSanityCheck();
1134 rename
.drainSanityCheck();
1135 iew
.drainSanityCheck();
1136 commit
.drainSanityCheck();
1139 template <class Impl
>
1141 FullO3CPU
<Impl
>::isDrained() const
1145 if (!instList
.empty() || !removeList
.empty()) {
1146 DPRINTF(Drain
, "Main CPU structures not drained.\n");
1150 if (!fetch
.isDrained()) {
1151 DPRINTF(Drain
, "Fetch not drained.\n");
1155 if (!decode
.isDrained()) {
1156 DPRINTF(Drain
, "Decode not drained.\n");
1160 if (!rename
.isDrained()) {
1161 DPRINTF(Drain
, "Rename not drained.\n");
1165 if (!iew
.isDrained()) {
1166 DPRINTF(Drain
, "IEW not drained.\n");
1170 if (!commit
.isDrained()) {
1171 DPRINTF(Drain
, "Commit not drained.\n");
1178 template <class Impl
>
1180 FullO3CPU
<Impl
>::commitDrained(ThreadID tid
)
1182 fetch
.drainStall(tid
);
1185 template <class Impl
>
1187 FullO3CPU
<Impl
>::drainResume()
1192 DPRINTF(Drain
, "Resuming...\n");
1195 fetch
.drainResume();
1196 commit
.drainResume();
1199 for (ThreadID i
= 0; i
< thread
.size(); i
++) {
1200 if (thread
[i
]->status() == ThreadContext::Active
) {
1201 DPRINTF(Drain
, "Activating thread: %i\n", i
);
1207 assert(!tickEvent
.scheduled());
1208 if (_status
== Running
)
1209 schedule(tickEvent
, nextCycle());
1211 // Reschedule any power gating event (if any)
1212 schedulePowerGatingEvent();
1215 template <class Impl
>
1217 FullO3CPU
<Impl
>::switchOut()
1219 DPRINTF(O3CPU
, "Switching out\n");
1220 BaseCPU::switchOut();
1222 activityRec
.reset();
1224 _status
= SwitchedOut
;
1227 checker
->switchOut();
1230 template <class Impl
>
1232 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
1234 BaseCPU::takeOverFrom(oldCPU
);
1236 fetch
.takeOverFrom();
1237 decode
.takeOverFrom();
1238 rename
.takeOverFrom();
1240 commit
.takeOverFrom();
1242 assert(!tickEvent
.scheduled());
1244 FullO3CPU
<Impl
> *oldO3CPU
= dynamic_cast<FullO3CPU
<Impl
>*>(oldCPU
);
1246 globalSeqNum
= oldO3CPU
->globalSeqNum
;
1248 lastRunningCycle
= curCycle();
1252 template <class Impl
>
1254 FullO3CPU
<Impl
>::verifyMemoryMode() const
1256 if (!system
->isTimingMode()) {
1257 fatal("The O3 CPU requires the memory system to be in "
1258 "'timing' mode.\n");
1262 template <class Impl
>
1264 FullO3CPU
<Impl
>::readMiscRegNoEffect(int misc_reg
, ThreadID tid
) const
1266 return this->isa
[tid
]->readMiscRegNoEffect(misc_reg
);
1269 template <class Impl
>
1271 FullO3CPU
<Impl
>::readMiscReg(int misc_reg
, ThreadID tid
)
1274 return this->isa
[tid
]->readMiscReg(misc_reg
, tcBase(tid
));
1277 template <class Impl
>
1279 FullO3CPU
<Impl
>::setMiscRegNoEffect(int misc_reg
, RegVal val
, ThreadID tid
)
1281 this->isa
[tid
]->setMiscRegNoEffect(misc_reg
, val
);
1284 template <class Impl
>
1286 FullO3CPU
<Impl
>::setMiscReg(int misc_reg
, RegVal val
, ThreadID tid
)
1288 miscRegfileWrites
++;
1289 this->isa
[tid
]->setMiscReg(misc_reg
, val
, tcBase(tid
));
1292 template <class Impl
>
1294 FullO3CPU
<Impl
>::readIntReg(PhysRegIdPtr phys_reg
)
1297 return regFile
.readIntReg(phys_reg
);
1300 template <class Impl
>
1302 FullO3CPU
<Impl
>::readFloatReg(PhysRegIdPtr phys_reg
)
1305 return regFile
.readFloatReg(phys_reg
);
1308 template <class Impl
>
1310 FullO3CPU
<Impl
>::readVecReg(PhysRegIdPtr phys_reg
) const
1311 -> const VecRegContainer
&
1314 return regFile
.readVecReg(phys_reg
);
1317 template <class Impl
>
1319 FullO3CPU
<Impl
>::getWritableVecReg(PhysRegIdPtr phys_reg
)
1323 return regFile
.getWritableVecReg(phys_reg
);
1326 template <class Impl
>
1328 FullO3CPU
<Impl
>::readVecElem(PhysRegIdPtr phys_reg
) const -> const VecElem
&
1331 return regFile
.readVecElem(phys_reg
);
1334 template <class Impl
>
1336 FullO3CPU
<Impl
>::readVecPredReg(PhysRegIdPtr phys_reg
) const
1337 -> const VecPredRegContainer
&
1339 vecPredRegfileReads
++;
1340 return regFile
.readVecPredReg(phys_reg
);
1343 template <class Impl
>
1345 FullO3CPU
<Impl
>::getWritableVecPredReg(PhysRegIdPtr phys_reg
)
1346 -> VecPredRegContainer
&
1348 vecPredRegfileWrites
++;
1349 return regFile
.getWritableVecPredReg(phys_reg
);
1352 template <class Impl
>
1354 FullO3CPU
<Impl
>::readCCReg(PhysRegIdPtr phys_reg
)
1357 return regFile
.readCCReg(phys_reg
);
1360 template <class Impl
>
1362 FullO3CPU
<Impl
>::setIntReg(PhysRegIdPtr phys_reg
, RegVal val
)
1365 regFile
.setIntReg(phys_reg
, val
);
1368 template <class Impl
>
1370 FullO3CPU
<Impl
>::setFloatReg(PhysRegIdPtr phys_reg
, RegVal val
)
1373 regFile
.setFloatReg(phys_reg
, val
);
1376 template <class Impl
>
1378 FullO3CPU
<Impl
>::setVecReg(PhysRegIdPtr phys_reg
, const VecRegContainer
& val
)
1381 regFile
.setVecReg(phys_reg
, val
);
1384 template <class Impl
>
1386 FullO3CPU
<Impl
>::setVecElem(PhysRegIdPtr phys_reg
, const VecElem
& val
)
1389 regFile
.setVecElem(phys_reg
, val
);
1392 template <class Impl
>
1394 FullO3CPU
<Impl
>::setVecPredReg(PhysRegIdPtr phys_reg
,
1395 const VecPredRegContainer
& val
)
1397 vecPredRegfileWrites
++;
1398 regFile
.setVecPredReg(phys_reg
, val
);
1401 template <class Impl
>
1403 FullO3CPU
<Impl
>::setCCReg(PhysRegIdPtr phys_reg
, RegVal val
)
1406 regFile
.setCCReg(phys_reg
, val
);
1409 template <class Impl
>
1411 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, ThreadID tid
)
1414 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1415 RegId(IntRegClass
, reg_idx
));
1417 return regFile
.readIntReg(phys_reg
);
1420 template <class Impl
>
1422 FullO3CPU
<Impl
>::readArchFloatReg(int reg_idx
, ThreadID tid
)
1425 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1426 RegId(FloatRegClass
, reg_idx
));
1428 return regFile
.readFloatReg(phys_reg
);
1431 template <class Impl
>
1433 FullO3CPU
<Impl
>::readArchVecReg(int reg_idx
, ThreadID tid
) const
1434 -> const VecRegContainer
&
1436 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1437 RegId(VecRegClass
, reg_idx
));
1438 return readVecReg(phys_reg
);
1441 template <class Impl
>
1443 FullO3CPU
<Impl
>::getWritableArchVecReg(int reg_idx
, ThreadID tid
)
1446 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1447 RegId(VecRegClass
, reg_idx
));
1448 return getWritableVecReg(phys_reg
);
1451 template <class Impl
>
1453 FullO3CPU
<Impl
>::readArchVecElem(const RegIndex
& reg_idx
, const ElemIndex
& ldx
,
1454 ThreadID tid
) const -> const VecElem
&
1456 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1457 RegId(VecElemClass
, reg_idx
, ldx
));
1458 return readVecElem(phys_reg
);
1461 template <class Impl
>
1463 FullO3CPU
<Impl
>::readArchVecPredReg(int reg_idx
, ThreadID tid
) const
1464 -> const VecPredRegContainer
&
1466 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1467 RegId(VecPredRegClass
, reg_idx
));
1468 return readVecPredReg(phys_reg
);
1471 template <class Impl
>
1473 FullO3CPU
<Impl
>::getWritableArchVecPredReg(int reg_idx
, ThreadID tid
)
1474 -> VecPredRegContainer
&
1476 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1477 RegId(VecPredRegClass
, reg_idx
));
1478 return getWritableVecPredReg(phys_reg
);
1481 template <class Impl
>
1483 FullO3CPU
<Impl
>::readArchCCReg(int reg_idx
, ThreadID tid
)
1486 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1487 RegId(CCRegClass
, reg_idx
));
1489 return regFile
.readCCReg(phys_reg
);
1492 template <class Impl
>
1494 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, RegVal val
, ThreadID tid
)
1497 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1498 RegId(IntRegClass
, reg_idx
));
1500 regFile
.setIntReg(phys_reg
, val
);
1503 template <class Impl
>
1505 FullO3CPU
<Impl
>::setArchFloatReg(int reg_idx
, RegVal val
, ThreadID tid
)
1508 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1509 RegId(FloatRegClass
, reg_idx
));
1511 regFile
.setFloatReg(phys_reg
, val
);
1514 template <class Impl
>
1516 FullO3CPU
<Impl
>::setArchVecReg(int reg_idx
, const VecRegContainer
& val
,
1519 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1520 RegId(VecRegClass
, reg_idx
));
1521 setVecReg(phys_reg
, val
);
1524 template <class Impl
>
1526 FullO3CPU
<Impl
>::setArchVecElem(const RegIndex
& reg_idx
, const ElemIndex
& ldx
,
1527 const VecElem
& val
, ThreadID tid
)
1529 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1530 RegId(VecElemClass
, reg_idx
, ldx
));
1531 setVecElem(phys_reg
, val
);
1534 template <class Impl
>
1536 FullO3CPU
<Impl
>::setArchVecPredReg(int reg_idx
, const VecPredRegContainer
& val
,
1539 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1540 RegId(VecPredRegClass
, reg_idx
));
1541 setVecPredReg(phys_reg
, val
);
1544 template <class Impl
>
1546 FullO3CPU
<Impl
>::setArchCCReg(int reg_idx
, RegVal val
, ThreadID tid
)
1549 PhysRegIdPtr phys_reg
= commitRenameMap
[tid
].lookup(
1550 RegId(CCRegClass
, reg_idx
));
1552 regFile
.setCCReg(phys_reg
, val
);
1555 template <class Impl
>
1557 FullO3CPU
<Impl
>::pcState(ThreadID tid
)
1559 return commit
.pcState(tid
);
1562 template <class Impl
>
1564 FullO3CPU
<Impl
>::pcState(const TheISA::PCState
&val
, ThreadID tid
)
1566 commit
.pcState(val
, tid
);
1569 template <class Impl
>
1571 FullO3CPU
<Impl
>::instAddr(ThreadID tid
)
1573 return commit
.instAddr(tid
);
1576 template <class Impl
>
1578 FullO3CPU
<Impl
>::nextInstAddr(ThreadID tid
)
1580 return commit
.nextInstAddr(tid
);
1583 template <class Impl
>
1585 FullO3CPU
<Impl
>::microPC(ThreadID tid
)
1587 return commit
.microPC(tid
);
1590 template <class Impl
>
1592 FullO3CPU
<Impl
>::squashFromTC(ThreadID tid
)
1594 this->thread
[tid
]->noSquashFromTC
= true;
1595 this->commit
.generateTCEvent(tid
);
1598 template <class Impl
>
1599 typename FullO3CPU
<Impl
>::ListIt
1600 FullO3CPU
<Impl
>::addInst(const DynInstPtr
&inst
)
1602 instList
.push_back(inst
);
1604 return --(instList
.end());
1607 template <class Impl
>
1609 FullO3CPU
<Impl
>::instDone(ThreadID tid
, const DynInstPtr
&inst
)
1611 // Keep an instruction count.
1612 if (!inst
->isMicroop() || inst
->isLastMicroop()) {
1613 thread
[tid
]->numInst
++;
1614 thread
[tid
]->numInsts
++;
1615 committedInsts
[tid
]++;
1616 system
->totalNumInsts
++;
1618 // Check for instruction-count-based events.
1619 comInstEventQueue
[tid
]->serviceEvents(thread
[tid
]->numInst
);
1620 system
->instEventQueue
.serviceEvents(system
->totalNumInsts
);
1622 thread
[tid
]->numOp
++;
1623 thread
[tid
]->numOps
++;
1624 committedOps
[tid
]++;
1626 probeInstCommit(inst
->staticInst
);
1629 template <class Impl
>
1631 FullO3CPU
<Impl
>::removeFrontInst(const DynInstPtr
&inst
)
1633 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %s "
1635 inst
->threadNumber
, inst
->pcState(), inst
->seqNum
);
1637 removeInstsThisCycle
= true;
1639 // Remove the front instruction.
1640 removeList
.push(inst
->getInstListIt());
1643 template <class Impl
>
1645 FullO3CPU
<Impl
>::removeInstsNotInROB(ThreadID tid
)
1647 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1652 bool rob_empty
= false;
1654 if (instList
.empty()) {
1656 } else if (rob
.isEmpty(tid
)) {
1657 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1658 end_it
= instList
.begin();
1661 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1662 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1665 removeInstsThisCycle
= true;
1667 ListIt inst_it
= instList
.end();
1671 // Walk through the instruction list, removing any instructions
1672 // that were inserted after the given instruction iterator, end_it.
1673 while (inst_it
!= end_it
) {
1674 assert(!instList
.empty());
1676 squashInstIt(inst_it
, tid
);
1681 // If the ROB was empty, then we actually need to remove the first
1682 // instruction as well.
1684 squashInstIt(inst_it
, tid
);
1688 template <class Impl
>
1690 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
, ThreadID tid
)
1692 assert(!instList
.empty());
1694 removeInstsThisCycle
= true;
1696 ListIt inst_iter
= instList
.end();
1700 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1701 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1702 tid
, seq_num
, (*inst_iter
)->seqNum
);
1704 while ((*inst_iter
)->seqNum
> seq_num
) {
1706 bool break_loop
= (inst_iter
== instList
.begin());
1708 squashInstIt(inst_iter
, tid
);
1717 template <class Impl
>
1719 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, ThreadID tid
)
1721 if ((*instIt
)->threadNumber
== tid
) {
1722 DPRINTF(O3CPU
, "Squashing instruction, "
1723 "[tid:%i] [sn:%lli] PC %s\n",
1724 (*instIt
)->threadNumber
,
1726 (*instIt
)->pcState());
1728 // Mark it as squashed.
1729 (*instIt
)->setSquashed();
1731 // @todo: Formulate a consistent method for deleting
1732 // instructions from the instruction list
1733 // Remove the instruction from the list.
1734 removeList
.push(instIt
);
1738 template <class Impl
>
1740 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1742 while (!removeList
.empty()) {
1743 DPRINTF(O3CPU
, "Removing instruction, "
1744 "[tid:%i] [sn:%lli] PC %s\n",
1745 (*removeList
.front())->threadNumber
,
1746 (*removeList
.front())->seqNum
,
1747 (*removeList
.front())->pcState());
1749 instList
.erase(removeList
.front());
1754 removeInstsThisCycle
= false;
1757 template <class Impl>
1759 FullO3CPU<Impl>::removeAllInsts()
1764 template <class Impl
>
1766 FullO3CPU
<Impl
>::dumpInsts()
1770 ListIt inst_list_it
= instList
.begin();
1772 cprintf("Dumping Instruction List\n");
1774 while (inst_list_it
!= instList
.end()) {
1775 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1777 num
, (*inst_list_it
)->instAddr(), (*inst_list_it
)->threadNumber
,
1778 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1779 (*inst_list_it
)->isSquashed());
1785 template <class Impl>
1787 FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst)
1789 iew.wakeDependents(inst);
1792 template <class Impl
>
1794 FullO3CPU
<Impl
>::wakeCPU()
1796 if (activityRec
.active() || tickEvent
.scheduled()) {
1797 DPRINTF(Activity
, "CPU already running.\n");
1801 DPRINTF(Activity
, "Waking up CPU\n");
1803 Cycles
cycles(curCycle() - lastRunningCycle
);
1804 // @todo: This is an oddity that is only here to match the stats
1807 idleCycles
+= cycles
;
1808 numCycles
+= cycles
;
1811 schedule(tickEvent
, clockEdge());
1814 template <class Impl
>
1816 FullO3CPU
<Impl
>::wakeup(ThreadID tid
)
1818 if (this->thread
[tid
]->status() != ThreadContext::Suspended
)
1823 DPRINTF(Quiesce
, "Suspended Processor woken\n");
1824 this->threadContexts
[tid
]->activate();
1827 template <class Impl
>
1829 FullO3CPU
<Impl
>::getFreeTid()
1831 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
1838 return InvalidThreadID
;
1841 template <class Impl
>
1843 FullO3CPU
<Impl
>::updateThreadPriority()
1845 if (activeThreads
.size() > 1) {
1846 //DEFAULT TO ROUND ROBIN SCHEME
1847 //e.g. Move highest priority to end of thread list
1848 list
<ThreadID
>::iterator list_begin
= activeThreads
.begin();
1850 unsigned high_thread
= *list_begin
;
1852 activeThreads
.erase(list_begin
);
1854 activeThreads
.push_back(high_thread
);
1858 template <class Impl
>
1860 FullO3CPU
<Impl
>::addThreadToExitingList(ThreadID tid
)
1862 DPRINTF(O3CPU
, "Thread %d is inserted to exitingThreads list\n", tid
);
1864 // make sure the thread is Active
1865 assert(std::find(activeThreads
.begin(), activeThreads
.end(), tid
)
1866 != activeThreads
.end());
1868 // make sure the thread has not been added to the list yet
1869 assert(exitingThreads
.count(tid
) == 0);
1871 // add the thread to exitingThreads list to mark that this thread is
1872 // trying to exit. The boolean value in the pair denotes if a thread is
1873 // ready to exit. The thread is not ready to exit until the corresponding
1874 // exit trap event is processed in the future. Until then, it'll be still
1875 // an active thread that is trying to exit.
1876 exitingThreads
.emplace(std::make_pair(tid
, false));
1879 template <class Impl
>
1881 FullO3CPU
<Impl
>::isThreadExiting(ThreadID tid
) const
1883 return exitingThreads
.count(tid
) == 1;
1886 template <class Impl
>
1888 FullO3CPU
<Impl
>::scheduleThreadExitEvent(ThreadID tid
)
1890 assert(exitingThreads
.count(tid
) == 1);
1892 // exit trap event has been processed. Now, the thread is ready to exit
1893 // and be removed from the CPU.
1894 exitingThreads
[tid
] = true;
1896 // we schedule a threadExitEvent in the next cycle to properly clean
1897 // up the thread's states in the pipeline. threadExitEvent has lower
1898 // priority than tickEvent, so the cleanup will happen at the very end
1899 // of the next cycle after all pipeline stages complete their operations.
1900 // We want all stages to complete squashing instructions before doing
1902 if (!threadExitEvent
.scheduled()) {
1903 schedule(threadExitEvent
, nextCycle());
1907 template <class Impl
>
1909 FullO3CPU
<Impl
>::exitThreads()
1911 // there must be at least one thread trying to exit
1912 assert(exitingThreads
.size() > 0);
1914 // terminate all threads that are ready to exit
1915 auto it
= exitingThreads
.begin();
1916 while (it
!= exitingThreads
.end()) {
1917 ThreadID thread_id
= it
->first
;
1918 bool readyToExit
= it
->second
;
1921 DPRINTF(O3CPU
, "Exiting thread %d\n", thread_id
);
1922 haltContext(thread_id
);
1923 tcBase(thread_id
)->setStatus(ThreadContext::Halted
);
1924 it
= exitingThreads
.erase(it
);
1931 // Forward declaration of FullO3CPU.
1932 template class FullO3CPU
<O3CPUImpl
>;