2 * Copyright (c) 2004-2006 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "config/full_system.hh"
33 #include "config/use_checker.hh"
35 #include "cpu/activity.hh"
36 #include "cpu/simple_thread.hh"
37 #include "cpu/thread_context.hh"
38 #include "cpu/o3/isa_specific.hh"
39 #include "cpu/o3/cpu.hh"
40 #include "enums/MemoryMode.hh"
41 #include "sim/core.hh"
42 #include "sim/stat_control.hh"
45 #include "cpu/quiesce_event.hh"
46 #include "sim/system.hh"
48 #include "sim/process.hh"
52 #include "cpu/checker/cpu.hh"
56 using namespace TheISA
;
58 BaseO3CPU::BaseO3CPU(Params
*params
)
59 : BaseCPU(params
), cpu_id(0)
70 FullO3CPU
<Impl
>::TickEvent::TickEvent(FullO3CPU
<Impl
> *c
)
71 : Event(&mainEventQueue
, CPU_Tick_Pri
), cpu(c
)
77 FullO3CPU
<Impl
>::TickEvent::process()
84 FullO3CPU
<Impl
>::TickEvent::description()
86 return "FullO3CPU tick event";
90 FullO3CPU
<Impl
>::ActivateThreadEvent::ActivateThreadEvent()
91 : Event(&mainEventQueue
, CPU_Switch_Pri
)
97 FullO3CPU
<Impl
>::ActivateThreadEvent::init(int thread_num
,
98 FullO3CPU
<Impl
> *thread_cpu
)
104 template <class Impl
>
106 FullO3CPU
<Impl
>::ActivateThreadEvent::process()
108 cpu
->activateThread(tid
);
111 template <class Impl
>
113 FullO3CPU
<Impl
>::ActivateThreadEvent::description()
115 return "FullO3CPU \"Activate Thread\" event";
118 template <class Impl
>
119 FullO3CPU
<Impl
>::DeallocateContextEvent::DeallocateContextEvent()
120 : Event(&mainEventQueue
, CPU_Tick_Pri
), tid(0), remove(false), cpu(NULL
)
124 template <class Impl
>
126 FullO3CPU
<Impl
>::DeallocateContextEvent::init(int thread_num
,
127 FullO3CPU
<Impl
> *thread_cpu
)
134 template <class Impl
>
136 FullO3CPU
<Impl
>::DeallocateContextEvent::process()
138 cpu
->deactivateThread(tid
);
140 cpu
->removeThread(tid
);
143 template <class Impl
>
145 FullO3CPU
<Impl
>::DeallocateContextEvent::description()
147 return "FullO3CPU \"Deallocate Context\" event";
150 template <class Impl
>
151 FullO3CPU
<Impl
>::FullO3CPU(O3CPU
*o3_cpu
, Params
*params
)
158 removeInstsThisCycle(false),
159 fetch(o3_cpu
, params
),
160 decode(o3_cpu
, params
),
161 rename(o3_cpu
, params
),
163 commit(o3_cpu
, params
),
165 regFile(o3_cpu
, params
->numPhysIntRegs
,
166 params
->numPhysFloatRegs
),
168 freeList(params
->numberOfThreads
,
169 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
170 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
),
173 params
->numROBEntries
, params
->squashWidth
,
174 params
->smtROBPolicy
, params
->smtROBThreshold
,
175 params
->numberOfThreads
),
177 scoreboard(params
->numberOfThreads
,
178 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
179 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
,
180 TheISA::NumMiscRegs
* number_of_threads
,
183 timeBuffer(params
->backComSize
, params
->forwardComSize
),
184 fetchQueue(params
->backComSize
, params
->forwardComSize
),
185 decodeQueue(params
->backComSize
, params
->forwardComSize
),
186 renameQueue(params
->backComSize
, params
->forwardComSize
),
187 iewQueue(params
->backComSize
, params
->forwardComSize
),
188 activityRec(NumStages
,
189 params
->backComSize
+ params
->forwardComSize
,
194 system(params
->system
),
195 physmem(system
->physmem
),
196 #endif // FULL_SYSTEM
198 deferRegistration(params
->deferRegistration
),
199 numThreads(number_of_threads
)
201 if (!deferRegistration
) {
208 if (params
->checker
) {
209 BaseCPU
*temp_checker
= params
->checker
;
210 checker
= dynamic_cast<Checker
<DynInstPtr
> *>(temp_checker
);
212 checker
->setSystem(params
->system
);
217 #endif // USE_CHECKER
220 thread
.resize(number_of_threads
);
221 tids
.resize(number_of_threads
);
224 // The stages also need their CPU pointer setup. However this
225 // must be done at the upper level CPU because they have pointers
226 // to the upper level CPU, and not this FullO3CPU.
228 // Set up Pointers to the activeThreads list for each stage
229 fetch
.setActiveThreads(&activeThreads
);
230 decode
.setActiveThreads(&activeThreads
);
231 rename
.setActiveThreads(&activeThreads
);
232 iew
.setActiveThreads(&activeThreads
);
233 commit
.setActiveThreads(&activeThreads
);
235 // Give each of the stages the time buffer they will use.
236 fetch
.setTimeBuffer(&timeBuffer
);
237 decode
.setTimeBuffer(&timeBuffer
);
238 rename
.setTimeBuffer(&timeBuffer
);
239 iew
.setTimeBuffer(&timeBuffer
);
240 commit
.setTimeBuffer(&timeBuffer
);
242 // Also setup each of the stages' queues.
243 fetch
.setFetchQueue(&fetchQueue
);
244 decode
.setFetchQueue(&fetchQueue
);
245 commit
.setFetchQueue(&fetchQueue
);
246 decode
.setDecodeQueue(&decodeQueue
);
247 rename
.setDecodeQueue(&decodeQueue
);
248 rename
.setRenameQueue(&renameQueue
);
249 iew
.setRenameQueue(&renameQueue
);
250 iew
.setIEWQueue(&iewQueue
);
251 commit
.setIEWQueue(&iewQueue
);
252 commit
.setRenameQueue(&renameQueue
);
254 commit
.setIEWStage(&iew
);
255 rename
.setIEWStage(&iew
);
256 rename
.setCommitStage(&commit
);
259 int active_threads
= params
->workload
.size();
261 if (active_threads
> Impl::MaxThreads
) {
262 panic("Workload Size too large. Increase the 'MaxThreads'"
263 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or "
264 "edit your workload size.");
267 int active_threads
= 1;
270 //Make Sure That this a Valid Architeture
271 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
272 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
274 rename
.setScoreboard(&scoreboard
);
275 iew
.setScoreboard(&scoreboard
);
277 // Setup the rename map for whichever stages need it.
278 PhysRegIndex lreg_idx
= 0;
279 PhysRegIndex freg_idx
= params
->numPhysIntRegs
; //Index to 1 after int regs
281 for (int tid
=0; tid
< numThreads
; tid
++) {
282 bool bindRegs
= (tid
<= active_threads
- 1);
284 commitRenameMap
[tid
].init(TheISA::NumIntRegs
,
285 params
->numPhysIntRegs
,
286 lreg_idx
, //Index for Logical. Regs
288 TheISA::NumFloatRegs
,
289 params
->numPhysFloatRegs
,
290 freg_idx
, //Index for Float Regs
300 renameMap
[tid
].init(TheISA::NumIntRegs
,
301 params
->numPhysIntRegs
,
302 lreg_idx
, //Index for Logical. Regs
304 TheISA::NumFloatRegs
,
305 params
->numPhysFloatRegs
,
306 freg_idx
, //Index for Float Regs
316 activateThreadEvent
[tid
].init(tid
, this);
317 deallocateContextEvent
[tid
].init(tid
, this);
320 rename
.setRenameMap(renameMap
);
321 commit
.setRenameMap(commitRenameMap
);
323 // Give renameMap & rename stage access to the freeList;
324 for (int i
=0; i
< numThreads
; i
++) {
325 renameMap
[i
].setFreeList(&freeList
);
327 rename
.setFreeList(&freeList
);
329 // Setup the ROB for whichever stages need it.
332 lastRunningCycle
= curTick
;
334 lastActivatedCycle
= -1;
336 // Give renameMap & rename stage access to the freeList;
337 //for (int i=0; i < numThreads; i++) {
338 //globalSeqNum[i] = 1;
341 contextSwitch
= false;
344 template <class Impl
>
345 FullO3CPU
<Impl
>::~FullO3CPU()
349 template <class Impl
>
351 FullO3CPU
<Impl
>::fullCPURegStats()
353 BaseO3CPU::regStats();
355 // Register any of the O3CPU's stats here.
357 .name(name() + ".timesIdled")
358 .desc("Number of times that the entire CPU went into an idle state and"
359 " unscheduled itself")
363 .name(name() + ".idleCycles")
364 .desc("Total number of cycles that the CPU has spent unscheduled due "
368 // Number of Instructions simulated
369 // --------------------------------
370 // Should probably be in Base CPU but need templated
371 // MaxThreads so put in here instead
374 .name(name() + ".committedInsts")
375 .desc("Number of Instructions Simulated");
378 .name(name() + ".committedInsts_total")
379 .desc("Number of Instructions Simulated");
382 .name(name() + ".cpi")
383 .desc("CPI: Cycles Per Instruction")
385 cpi
= numCycles
/ committedInsts
;
388 .name(name() + ".cpi_total")
389 .desc("CPI: Total CPI of All Threads")
391 totalCpi
= numCycles
/ totalCommittedInsts
;
394 .name(name() + ".ipc")
395 .desc("IPC: Instructions Per Cycle")
397 ipc
= committedInsts
/ numCycles
;
400 .name(name() + ".ipc_total")
401 .desc("IPC: Total IPC of All Threads")
403 totalIpc
= totalCommittedInsts
/ numCycles
;
407 template <class Impl
>
409 FullO3CPU
<Impl
>::getPort(const std::string
&if_name
, int idx
)
411 if (if_name
== "dcache_port")
412 return iew
.getDcachePort();
413 else if (if_name
== "icache_port")
414 return fetch
.getIcachePort();
416 panic("No Such Port\n");
419 template <class Impl
>
421 FullO3CPU
<Impl
>::tick()
423 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
429 //Tick each of the stages
444 // Now advance the time buffers
445 timeBuffer
.advance();
447 fetchQueue
.advance();
448 decodeQueue
.advance();
449 renameQueue
.advance();
452 activityRec
.advance();
454 if (removeInstsThisCycle
) {
455 cleanUpRemovedInsts();
458 if (!tickEvent
.scheduled()) {
459 if (_status
== SwitchedOut
||
460 getState() == SimObject::Drained
) {
461 DPRINTF(O3CPU
, "Switched out!\n");
463 lastRunningCycle
= curTick
;
464 } else if (!activityRec
.active() || _status
== Idle
) {
465 DPRINTF(O3CPU
, "Idle!\n");
466 lastRunningCycle
= curTick
;
469 tickEvent
.schedule(nextCycle(curTick
+ cycles(1)));
470 DPRINTF(O3CPU
, "Scheduling next tick!\n");
475 updateThreadPriority();
480 template <class Impl
>
482 FullO3CPU
<Impl
>::init()
484 if (!deferRegistration
) {
485 registerThreadContexts();
488 // Set inSyscall so that the CPU doesn't squash when initially
489 // setting up registers.
490 for (int i
= 0; i
< number_of_threads
; ++i
)
491 thread
[i
]->inSyscall
= true;
493 for (int tid
=0; tid
< number_of_threads
; tid
++) {
495 ThreadContext
*src_tc
= threadContexts
[tid
];
497 ThreadContext
*src_tc
= thread
[tid
]->getTC();
499 // Threads start in the Suspended State
500 if (src_tc
->status() != ThreadContext::Suspended
) {
505 TheISA::initCPU(src_tc
, src_tc
->readCpuId());
510 for (int i
= 0; i
< number_of_threads
; ++i
)
511 thread
[i
]->inSyscall
= false;
513 // Initialize stages.
519 commit
.setThreads(thread
);
522 template <class Impl
>
524 FullO3CPU
<Impl
>::activateThread(unsigned tid
)
526 list
<unsigned>::iterator isActive
= find(
527 activeThreads
.begin(), activeThreads
.end(), tid
);
529 DPRINTF(O3CPU
, "[tid:%i]: Calling activate thread.\n", tid
);
531 if (isActive
== activeThreads
.end()) {
532 DPRINTF(O3CPU
, "[tid:%i]: Adding to active threads list\n",
535 activeThreads
.push_back(tid
);
539 template <class Impl
>
541 FullO3CPU
<Impl
>::deactivateThread(unsigned tid
)
543 //Remove From Active List, if Active
544 list
<unsigned>::iterator thread_it
=
545 find(activeThreads
.begin(), activeThreads
.end(), tid
);
547 DPRINTF(O3CPU
, "[tid:%i]: Calling deactivate thread.\n", tid
);
549 if (thread_it
!= activeThreads
.end()) {
550 DPRINTF(O3CPU
,"[tid:%i]: Removing from active threads list\n",
552 activeThreads
.erase(thread_it
);
556 template <class Impl
>
558 FullO3CPU
<Impl
>::activateContext(int tid
, int delay
)
560 // Needs to set each stage to running as well.
562 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to activate "
563 "on cycle %d\n", tid
, curTick
+ cycles(delay
));
564 scheduleActivateThreadEvent(tid
, delay
);
569 if (lastActivatedCycle
< curTick
) {
570 scheduleTickEvent(delay
);
572 // Be sure to signal that there's some activity so the CPU doesn't
573 // deschedule itself.
574 activityRec
.activity();
575 fetch
.wakeFromQuiesce();
577 lastActivatedCycle
= curTick
;
583 template <class Impl
>
585 FullO3CPU
<Impl
>::deallocateContext(int tid
, bool remove
, int delay
)
587 // Schedule removal of thread data from CPU
589 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to deallocate "
590 "on cycle %d\n", tid
, curTick
+ cycles(delay
));
591 scheduleDeallocateContextEvent(tid
, remove
, delay
);
594 deactivateThread(tid
);
601 template <class Impl
>
603 FullO3CPU
<Impl
>::suspendContext(int tid
)
605 DPRINTF(O3CPU
,"[tid: %i]: Suspending Thread Context.\n", tid
);
606 bool deallocated
= deallocateContext(tid
, false, 1);
607 // If this was the last thread then unschedule the tick event.
608 if (activeThreads
.size() == 1 && !deallocated
||
609 activeThreads
.size() == 0)
610 unscheduleTickEvent();
614 template <class Impl
>
616 FullO3CPU
<Impl
>::haltContext(int tid
)
618 //For now, this is the same as deallocate
619 DPRINTF(O3CPU
,"[tid:%i]: Halt Context called. Deallocating", tid
);
620 deallocateContext(tid
, true, 1);
623 template <class Impl
>
625 FullO3CPU
<Impl
>::insertThread(unsigned tid
)
627 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
628 // Will change now that the PC and thread state is internal to the CPU
629 // and not in the ThreadContext.
631 ThreadContext
*src_tc
= system
->threadContexts
[tid
];
633 ThreadContext
*src_tc
= tcBase(tid
);
636 //Bind Int Regs to Rename Map
637 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
638 PhysRegIndex phys_reg
= freeList
.getIntReg();
640 renameMap
[tid
].setEntry(ireg
,phys_reg
);
641 scoreboard
.setReg(phys_reg
);
644 //Bind Float Regs to Rename Map
645 for (int freg
= 0; freg
< TheISA::NumFloatRegs
; freg
++) {
646 PhysRegIndex phys_reg
= freeList
.getFloatReg();
648 renameMap
[tid
].setEntry(freg
,phys_reg
);
649 scoreboard
.setReg(phys_reg
);
652 //Copy Thread Data Into RegFile
653 //this->copyFromTC(tid);
656 setPC(src_tc
->readPC(), tid
);
657 setNextPC(src_tc
->readNextPC(), tid
);
658 setNextNPC(src_tc
->readNextNPC(), tid
);
660 src_tc
->setStatus(ThreadContext::Active
);
662 activateContext(tid
,1);
664 //Reset ROB/IQ/LSQ Entries
665 commit
.rob
->resetEntries();
669 template <class Impl
>
671 FullO3CPU
<Impl
>::removeThread(unsigned tid
)
673 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
675 // Copy Thread Data From RegFile
676 // If thread is suspended, it might be re-allocated
677 //this->copyToTC(tid);
679 // Unbind Int Regs from Rename Map
680 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
681 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(ireg
);
683 scoreboard
.unsetReg(phys_reg
);
684 freeList
.addReg(phys_reg
);
687 // Unbind Float Regs from Rename Map
688 for (int freg
= 0; freg
< TheISA::NumFloatRegs
; freg
++) {
689 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(freg
);
691 scoreboard
.unsetReg(phys_reg
);
692 freeList
.addReg(phys_reg
);
695 // Squash Throughout Pipeline
696 InstSeqNum squash_seq_num
= commit
.rob
->readHeadInst(tid
)->seqNum
;
697 fetch
.squash(0, sizeof(TheISA::MachInst
), 0, squash_seq_num
, tid
);
699 rename
.squash(squash_seq_num
, tid
);
701 commit
.rob
->squash(squash_seq_num
, tid
);
703 assert(iew
.ldstQueue
.getCount(tid
) == 0);
705 // Reset ROB/IQ/LSQ Entries
707 // Commented out for now. This should be possible to do by
708 // telling all the pipeline stages to drain first, and then
709 // checking until the drain completes. Once the pipeline is
710 // drained, call resetEntries(). - 10-09-06 ktlim
712 if (activeThreads.size() >= 1) {
713 commit.rob->resetEntries();
720 template <class Impl
>
722 FullO3CPU
<Impl
>::activateWhenReady(int tid
)
724 DPRINTF(O3CPU
,"[tid:%i]: Checking if resources are available for incoming"
725 "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
730 if (freeList
.numFreeIntRegs() >= TheISA::NumIntRegs
) {
731 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
732 "Phys. Int. Regs.\n",
735 } else if (freeList
.numFreeFloatRegs() >= TheISA::NumFloatRegs
) {
736 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
737 "Phys. Float. Regs.\n",
740 } else if (commit
.rob
->numFreeEntries() >=
741 commit
.rob
->entryAmount(activeThreads
.size() + 1)) {
742 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
746 } else if (iew
.instQueue
.numFreeEntries() >=
747 iew
.instQueue
.entryAmount(activeThreads
.size() + 1)) {
748 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
752 } else if (iew
.ldstQueue
.numFreeEntries() >=
753 iew
.ldstQueue
.entryAmount(activeThreads
.size() + 1)) {
754 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
763 contextSwitch
= false;
765 cpuWaitList
.remove(tid
);
770 contextSwitch
= true;
772 //@todo: dont always add to waitlist
774 cpuWaitList
.push_back(tid
);
779 template <class Impl
>
781 FullO3CPU
<Impl
>::updateMemPorts()
783 // Update all ThreadContext's memory ports (Functional/Virtual
785 for (int i
= 0; i
< thread
.size(); ++i
)
786 thread
[i
]->connectMemPorts();
790 template <class Impl
>
792 FullO3CPU
<Impl
>::serialize(std::ostream
&os
)
794 SimObject::State so_state
= SimObject::getState();
795 SERIALIZE_ENUM(so_state
);
796 BaseCPU::serialize(os
);
797 nameOut(os
, csprintf("%s.tickEvent", name()));
798 tickEvent
.serialize(os
);
800 // Use SimpleThread's ability to checkpoint to make it easier to
801 // write out the registers. Also make this static so it doesn't
802 // get instantiated multiple times (causes a panic in statistics).
803 static SimpleThread temp
;
805 for (int i
= 0; i
< thread
.size(); i
++) {
806 nameOut(os
, csprintf("%s.xc.%i", name(), i
));
807 temp
.copyTC(thread
[i
]->getTC());
812 template <class Impl
>
814 FullO3CPU
<Impl
>::unserialize(Checkpoint
*cp
, const std::string
§ion
)
816 SimObject::State so_state
;
817 UNSERIALIZE_ENUM(so_state
);
818 BaseCPU::unserialize(cp
, section
);
819 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
821 // Use SimpleThread's ability to checkpoint to make it easier to
822 // read in the registers. Also make this static so it doesn't
823 // get instantiated multiple times (causes a panic in statistics).
824 static SimpleThread temp
;
826 for (int i
= 0; i
< thread
.size(); i
++) {
827 temp
.copyTC(thread
[i
]->getTC());
828 temp
.unserialize(cp
, csprintf("%s.xc.%i", section
, i
));
829 thread
[i
]->getTC()->copyArchRegs(temp
.getTC());
833 template <class Impl
>
835 FullO3CPU
<Impl
>::drain(Event
*drain_event
)
837 DPRINTF(O3CPU
, "Switching out\n");
839 // If the CPU isn't doing anything, then return immediately.
840 if (_status
== Idle
|| _status
== SwitchedOut
) {
851 // Wake the CPU and record activity so everything can drain out if
852 // the CPU was not able to immediately drain.
853 if (getState() != SimObject::Drained
) {
854 // A bit of a hack...set the drainEvent after all the drain()
855 // calls have been made, that way if all of the stages drain
856 // immediately, the signalDrained() function knows not to call
857 // process on the drain event.
858 drainEvent
= drain_event
;
861 activityRec
.activity();
869 template <class Impl
>
871 FullO3CPU
<Impl
>::resume()
879 changeState(SimObject::Running
);
881 if (_status
== SwitchedOut
|| _status
== Idle
)
885 assert(system
->getMemoryMode() == Enums::timing
);
888 if (!tickEvent
.scheduled())
889 tickEvent
.schedule(nextCycle());
893 template <class Impl
>
895 FullO3CPU
<Impl
>::signalDrained()
897 if (++drainCount
== NumStages
) {
898 if (tickEvent
.scheduled())
901 changeState(SimObject::Drained
);
903 BaseCPU::switchOut();
906 drainEvent
->process();
910 assert(drainCount
<= 5);
913 template <class Impl
>
915 FullO3CPU
<Impl
>::switchOut()
922 while (!removeList
.empty()) {
926 _status
= SwitchedOut
;
929 checker
->switchOut();
931 if (tickEvent
.scheduled())
935 template <class Impl
>
937 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
939 // Flush out any old data from the time buffers.
940 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
941 timeBuffer
.advance();
942 fetchQueue
.advance();
943 decodeQueue
.advance();
944 renameQueue
.advance();
950 BaseCPU::takeOverFrom(oldCPU
, fetch
.getIcachePort(), iew
.getDcachePort());
952 fetch
.takeOverFrom();
953 decode
.takeOverFrom();
954 rename
.takeOverFrom();
956 commit
.takeOverFrom();
958 assert(!tickEvent
.scheduled());
960 // @todo: Figure out how to properly select the tid to put onto
961 // the active threads list.
964 list
<unsigned>::iterator isActive
= find(
965 activeThreads
.begin(), activeThreads
.end(), tid
);
967 if (isActive
== activeThreads
.end()) {
968 //May Need to Re-code this if the delay variable is the delay
969 //needed for thread to activate
970 DPRINTF(O3CPU
, "Adding Thread %i to active threads list\n",
973 activeThreads
.push_back(tid
);
976 // Set all statuses to active, schedule the CPU's tick event.
977 // @todo: Fix up statuses so this is handled properly
978 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
979 ThreadContext
*tc
= threadContexts
[i
];
980 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
982 tickEvent
.schedule(nextCycle());
985 if (!tickEvent
.scheduled())
986 tickEvent
.schedule(nextCycle());
989 template <class Impl
>
991 FullO3CPU
<Impl
>::readIntReg(int reg_idx
)
993 return regFile
.readIntReg(reg_idx
);
996 template <class Impl
>
998 FullO3CPU
<Impl
>::readFloatReg(int reg_idx
, int width
)
1000 return regFile
.readFloatReg(reg_idx
, width
);
1003 template <class Impl
>
1005 FullO3CPU
<Impl
>::readFloatReg(int reg_idx
)
1007 return regFile
.readFloatReg(reg_idx
);
1010 template <class Impl
>
1012 FullO3CPU
<Impl
>::readFloatRegBits(int reg_idx
, int width
)
1014 return regFile
.readFloatRegBits(reg_idx
, width
);
1017 template <class Impl
>
1019 FullO3CPU
<Impl
>::readFloatRegBits(int reg_idx
)
1021 return regFile
.readFloatRegBits(reg_idx
);
1024 template <class Impl
>
1026 FullO3CPU
<Impl
>::setIntReg(int reg_idx
, uint64_t val
)
1028 regFile
.setIntReg(reg_idx
, val
);
1031 template <class Impl
>
1033 FullO3CPU
<Impl
>::setFloatReg(int reg_idx
, FloatReg val
, int width
)
1035 regFile
.setFloatReg(reg_idx
, val
, width
);
1038 template <class Impl
>
1040 FullO3CPU
<Impl
>::setFloatReg(int reg_idx
, FloatReg val
)
1042 regFile
.setFloatReg(reg_idx
, val
);
1045 template <class Impl
>
1047 FullO3CPU
<Impl
>::setFloatRegBits(int reg_idx
, FloatRegBits val
, int width
)
1049 regFile
.setFloatRegBits(reg_idx
, val
, width
);
1052 template <class Impl
>
1054 FullO3CPU
<Impl
>::setFloatRegBits(int reg_idx
, FloatRegBits val
)
1056 regFile
.setFloatRegBits(reg_idx
, val
);
1059 template <class Impl
>
1061 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, unsigned tid
)
1063 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1065 return regFile
.readIntReg(phys_reg
);
1068 template <class Impl
>
1070 FullO3CPU
<Impl
>::readArchFloatRegSingle(int reg_idx
, unsigned tid
)
1072 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1073 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1075 return regFile
.readFloatReg(phys_reg
);
1078 template <class Impl
>
1080 FullO3CPU
<Impl
>::readArchFloatRegDouble(int reg_idx
, unsigned tid
)
1082 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1083 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1085 return regFile
.readFloatReg(phys_reg
, 64);
1088 template <class Impl
>
1090 FullO3CPU
<Impl
>::readArchFloatRegInt(int reg_idx
, unsigned tid
)
1092 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1093 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1095 return regFile
.readFloatRegBits(phys_reg
);
1098 template <class Impl
>
1100 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, uint64_t val
, unsigned tid
)
1102 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1104 regFile
.setIntReg(phys_reg
, val
);
1107 template <class Impl
>
1109 FullO3CPU
<Impl
>::setArchFloatRegSingle(int reg_idx
, float val
, unsigned tid
)
1111 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1112 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1114 regFile
.setFloatReg(phys_reg
, val
);
1117 template <class Impl
>
1119 FullO3CPU
<Impl
>::setArchFloatRegDouble(int reg_idx
, double val
, unsigned tid
)
1121 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1122 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1124 regFile
.setFloatReg(phys_reg
, val
, 64);
1127 template <class Impl
>
1129 FullO3CPU
<Impl
>::setArchFloatRegInt(int reg_idx
, uint64_t val
, unsigned tid
)
1131 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1132 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1134 regFile
.setFloatRegBits(phys_reg
, val
);
1137 template <class Impl
>
1139 FullO3CPU
<Impl
>::readPC(unsigned tid
)
1141 return commit
.readPC(tid
);
1144 template <class Impl
>
1146 FullO3CPU
<Impl
>::setPC(Addr new_PC
,unsigned tid
)
1148 commit
.setPC(new_PC
, tid
);
1151 template <class Impl
>
1153 FullO3CPU
<Impl
>::readMicroPC(unsigned tid
)
1155 return commit
.readMicroPC(tid
);
1158 template <class Impl
>
1160 FullO3CPU
<Impl
>::setMicroPC(Addr new_PC
,unsigned tid
)
1162 commit
.setMicroPC(new_PC
, tid
);
1165 template <class Impl
>
1167 FullO3CPU
<Impl
>::readNextPC(unsigned tid
)
1169 return commit
.readNextPC(tid
);
1172 template <class Impl
>
1174 FullO3CPU
<Impl
>::setNextPC(uint64_t val
,unsigned tid
)
1176 commit
.setNextPC(val
, tid
);
1179 template <class Impl
>
1181 FullO3CPU
<Impl
>::readNextNPC(unsigned tid
)
1183 return commit
.readNextNPC(tid
);
1186 template <class Impl
>
1188 FullO3CPU
<Impl
>::setNextNPC(uint64_t val
,unsigned tid
)
1190 commit
.setNextNPC(val
, tid
);
1193 template <class Impl
>
1195 FullO3CPU
<Impl
>::readNextMicroPC(unsigned tid
)
1197 return commit
.readNextMicroPC(tid
);
1200 template <class Impl
>
1202 FullO3CPU
<Impl
>::setNextMicroPC(Addr new_PC
,unsigned tid
)
1204 commit
.setNextMicroPC(new_PC
, tid
);
1207 template <class Impl
>
1208 typename FullO3CPU
<Impl
>::ListIt
1209 FullO3CPU
<Impl
>::addInst(DynInstPtr
&inst
)
1211 instList
.push_back(inst
);
1213 return --(instList
.end());
1216 template <class Impl
>
1218 FullO3CPU
<Impl
>::instDone(unsigned tid
)
1220 // Keep an instruction count.
1221 thread
[tid
]->numInst
++;
1222 thread
[tid
]->numInsts
++;
1223 committedInsts
[tid
]++;
1224 totalCommittedInsts
++;
1226 // Check for instruction-count-based events.
1227 comInstEventQueue
[tid
]->serviceEvents(thread
[tid
]->numInst
);
1230 template <class Impl
>
1232 FullO3CPU
<Impl
>::addToRemoveList(DynInstPtr
&inst
)
1234 removeInstsThisCycle
= true;
1236 removeList
.push(inst
->getInstListIt());
1239 template <class Impl
>
1241 FullO3CPU
<Impl
>::removeFrontInst(DynInstPtr
&inst
)
1243 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %#x "
1245 inst
->threadNumber
, inst
->readPC(), inst
->seqNum
);
1247 removeInstsThisCycle
= true;
1249 // Remove the front instruction.
1250 removeList
.push(inst
->getInstListIt());
1253 template <class Impl
>
1255 FullO3CPU
<Impl
>::removeInstsNotInROB(unsigned tid
)
1257 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1262 bool rob_empty
= false;
1264 if (instList
.empty()) {
1266 } else if (rob
.isEmpty(/*tid*/)) {
1267 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1268 end_it
= instList
.begin();
1271 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1272 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1275 removeInstsThisCycle
= true;
1277 ListIt inst_it
= instList
.end();
1281 // Walk through the instruction list, removing any instructions
1282 // that were inserted after the given instruction iterator, end_it.
1283 while (inst_it
!= end_it
) {
1284 assert(!instList
.empty());
1286 squashInstIt(inst_it
, tid
);
1291 // If the ROB was empty, then we actually need to remove the first
1292 // instruction as well.
1294 squashInstIt(inst_it
, tid
);
1298 template <class Impl
>
1300 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
,
1303 assert(!instList
.empty());
1305 removeInstsThisCycle
= true;
1307 ListIt inst_iter
= instList
.end();
1311 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1312 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1313 tid
, seq_num
, (*inst_iter
)->seqNum
);
1315 while ((*inst_iter
)->seqNum
> seq_num
) {
1317 bool break_loop
= (inst_iter
== instList
.begin());
1319 squashInstIt(inst_iter
, tid
);
1328 template <class Impl
>
1330 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, const unsigned &tid
)
1332 if ((*instIt
)->threadNumber
== tid
) {
1333 DPRINTF(O3CPU
, "Squashing instruction, "
1334 "[tid:%i] [sn:%lli] PC %#x\n",
1335 (*instIt
)->threadNumber
,
1337 (*instIt
)->readPC());
1339 // Mark it as squashed.
1340 (*instIt
)->setSquashed();
1342 // @todo: Formulate a consistent method for deleting
1343 // instructions from the instruction list
1344 // Remove the instruction from the list.
1345 removeList
.push(instIt
);
1349 template <class Impl
>
1351 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1353 while (!removeList
.empty()) {
1354 DPRINTF(O3CPU
, "Removing instruction, "
1355 "[tid:%i] [sn:%lli] PC %#x\n",
1356 (*removeList
.front())->threadNumber
,
1357 (*removeList
.front())->seqNum
,
1358 (*removeList
.front())->readPC());
1360 instList
.erase(removeList
.front());
1365 removeInstsThisCycle
= false;
1368 template <class Impl>
1370 FullO3CPU<Impl>::removeAllInsts()
1375 template <class Impl
>
1377 FullO3CPU
<Impl
>::dumpInsts()
1381 ListIt inst_list_it
= instList
.begin();
1383 cprintf("Dumping Instruction List\n");
1385 while (inst_list_it
!= instList
.end()) {
1386 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1388 num
, (*inst_list_it
)->readPC(), (*inst_list_it
)->threadNumber
,
1389 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1390 (*inst_list_it
)->isSquashed());
1396 template <class Impl>
1398 FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
1400 iew.wakeDependents(inst);
1403 template <class Impl
>
1405 FullO3CPU
<Impl
>::wakeCPU()
1407 if (activityRec
.active() || tickEvent
.scheduled()) {
1408 DPRINTF(Activity
, "CPU already running.\n");
1412 DPRINTF(Activity
, "Waking up CPU\n");
1414 idleCycles
+= (curTick
- 1) - lastRunningCycle
;
1416 tickEvent
.schedule(nextCycle());
1419 template <class Impl
>
1421 FullO3CPU
<Impl
>::getFreeTid()
1423 for (int i
=0; i
< numThreads
; i
++) {
1433 template <class Impl
>
1435 FullO3CPU
<Impl
>::doContextSwitch()
1437 if (contextSwitch
) {
1439 //ADD CODE TO DEACTIVE THREAD HERE (???)
1441 for (int tid
=0; tid
< cpuWaitList
.size(); tid
++) {
1442 activateWhenReady(tid
);
1445 if (cpuWaitList
.size() == 0)
1446 contextSwitch
= true;
1450 template <class Impl
>
1452 FullO3CPU
<Impl
>::updateThreadPriority()
1454 if (activeThreads
.size() > 1)
1456 //DEFAULT TO ROUND ROBIN SCHEME
1457 //e.g. Move highest priority to end of thread list
1458 list
<unsigned>::iterator list_begin
= activeThreads
.begin();
1459 list
<unsigned>::iterator list_end
= activeThreads
.end();
1461 unsigned high_thread
= *list_begin
;
1463 activeThreads
.erase(list_begin
);
1465 activeThreads
.push_back(high_thread
);
1469 // Forward declaration of FullO3CPU.
1470 template class FullO3CPU
<O3CPUImpl
>;