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"
36 #include "cpu/quiesce_event.hh"
37 #include "sim/system.hh"
39 #include "sim/process.hh"
42 #include "cpu/activity.hh"
43 #include "cpu/simple_thread.hh"
44 #include "cpu/thread_context.hh"
45 #include "cpu/o3/isa_specific.hh"
46 #include "cpu/o3/cpu.hh"
48 #include "sim/root.hh"
49 #include "sim/stat_control.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_Tick_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
)
124 template <class Impl
>
126 FullO3CPU
<Impl
>::DeallocateContextEvent::init(int thread_num
,
127 FullO3CPU
<Impl
> *thread_cpu
)
133 template <class Impl
>
135 FullO3CPU
<Impl
>::DeallocateContextEvent::process()
137 cpu
->deactivateThread(tid
);
138 cpu
->removeThread(tid
);
141 template <class Impl
>
143 FullO3CPU
<Impl
>::DeallocateContextEvent::description()
145 return "FullO3CPU \"Deallocate Context\" event";
148 template <class Impl
>
149 FullO3CPU
<Impl
>::FullO3CPU(Params
*params
)
152 removeInstsThisCycle(false),
159 regFile(params
->numPhysIntRegs
, params
->numPhysFloatRegs
),
161 freeList(params
->numberOfThreads
,
162 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
163 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
),
165 rob(params
->numROBEntries
, params
->squashWidth
,
166 params
->smtROBPolicy
, params
->smtROBThreshold
,
167 params
->numberOfThreads
),
169 scoreboard(params
->numberOfThreads
,
170 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
171 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
,
172 TheISA::NumMiscRegs
* number_of_threads
,
175 timeBuffer(params
->backComSize
, params
->forwardComSize
),
176 fetchQueue(params
->backComSize
, params
->forwardComSize
),
177 decodeQueue(params
->backComSize
, params
->forwardComSize
),
178 renameQueue(params
->backComSize
, params
->forwardComSize
),
179 iewQueue(params
->backComSize
, params
->forwardComSize
),
180 activityRec(NumStages
,
181 params
->backComSize
+ params
->forwardComSize
,
186 system(params
->system
),
187 physmem(system
->physmem
),
188 #endif // FULL_SYSTEM
191 deferRegistration(params
->deferRegistration
),
192 numThreads(number_of_threads
)
198 if (params
->checker
) {
200 BaseCPU
*temp_checker
= params
->checker
;
201 checker
= dynamic_cast<Checker
<DynInstPtr
> *>(temp_checker
);
202 checker
->setMemory(mem
);
204 checker
->setSystem(params
->system
);
207 panic("Checker enabled but not compiled in!");
208 #endif // USE_CHECKER
212 thread
.resize(number_of_threads
);
213 tids
.resize(number_of_threads
);
216 // The stages also need their CPU pointer setup. However this
217 // must be done at the upper level CPU because they have pointers
218 // to the upper level CPU, and not this FullO3CPU.
220 // Set up Pointers to the activeThreads list for each stage
221 fetch
.setActiveThreads(&activeThreads
);
222 decode
.setActiveThreads(&activeThreads
);
223 rename
.setActiveThreads(&activeThreads
);
224 iew
.setActiveThreads(&activeThreads
);
225 commit
.setActiveThreads(&activeThreads
);
227 // Give each of the stages the time buffer they will use.
228 fetch
.setTimeBuffer(&timeBuffer
);
229 decode
.setTimeBuffer(&timeBuffer
);
230 rename
.setTimeBuffer(&timeBuffer
);
231 iew
.setTimeBuffer(&timeBuffer
);
232 commit
.setTimeBuffer(&timeBuffer
);
234 // Also setup each of the stages' queues.
235 fetch
.setFetchQueue(&fetchQueue
);
236 decode
.setFetchQueue(&fetchQueue
);
237 commit
.setFetchQueue(&fetchQueue
);
238 decode
.setDecodeQueue(&decodeQueue
);
239 rename
.setDecodeQueue(&decodeQueue
);
240 rename
.setRenameQueue(&renameQueue
);
241 iew
.setRenameQueue(&renameQueue
);
242 iew
.setIEWQueue(&iewQueue
);
243 commit
.setIEWQueue(&iewQueue
);
244 commit
.setRenameQueue(&renameQueue
);
246 commit
.setIEWStage(&iew
);
247 rename
.setIEWStage(&iew
);
248 rename
.setCommitStage(&commit
);
251 int 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) or "
256 "edit your workload size.");
259 int active_threads
= 1;
262 //Make Sure That this a Valid Architeture
263 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
264 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
266 rename
.setScoreboard(&scoreboard
);
267 iew
.setScoreboard(&scoreboard
);
269 // Setup the rename map for whichever stages need it.
270 PhysRegIndex lreg_idx
= 0;
271 PhysRegIndex freg_idx
= params
->numPhysIntRegs
; //Index to 1 after int regs
273 for (int tid
=0; tid
< numThreads
; tid
++) {
274 bool bindRegs
= (tid
<= active_threads
- 1);
276 commitRenameMap
[tid
].init(TheISA::NumIntRegs
,
277 params
->numPhysIntRegs
,
278 lreg_idx
, //Index for Logical. Regs
280 TheISA::NumFloatRegs
,
281 params
->numPhysFloatRegs
,
282 freg_idx
, //Index for Float Regs
292 renameMap
[tid
].init(TheISA::NumIntRegs
,
293 params
->numPhysIntRegs
,
294 lreg_idx
, //Index for Logical. Regs
296 TheISA::NumFloatRegs
,
297 params
->numPhysFloatRegs
,
298 freg_idx
, //Index for Float Regs
309 rename
.setRenameMap(renameMap
);
310 commit
.setRenameMap(commitRenameMap
);
312 // Give renameMap & rename stage access to the freeList;
313 for (int i
=0; i
< numThreads
; i
++) {
314 renameMap
[i
].setFreeList(&freeList
);
316 rename
.setFreeList(&freeList
);
318 // Setup the ROB for whichever stages need it.
321 lastRunningCycle
= curTick
;
323 lastActivatedCycle
= -1;
325 // Give renameMap & rename stage access to the freeList;
326 //for (int i=0; i < numThreads; i++) {
327 //globalSeqNum[i] = 1;
330 contextSwitch
= false;
333 template <class Impl
>
334 FullO3CPU
<Impl
>::~FullO3CPU()
338 template <class Impl
>
340 FullO3CPU
<Impl
>::fullCPURegStats()
342 BaseO3CPU::regStats();
344 // Register any of the O3CPU's stats here.
346 .name(name() + ".timesIdled")
347 .desc("Number of times that the entire CPU went into an idle state and"
348 " unscheduled itself")
352 .name(name() + ".idleCycles")
353 .desc("Total number of cycles that the CPU has spent unscheduled due "
357 // Number of Instructions simulated
358 // --------------------------------
359 // Should probably be in Base CPU but need templated
360 // MaxThreads so put in here instead
363 .name(name() + ".committedInsts")
364 .desc("Number of Instructions Simulated");
367 .name(name() + ".committedInsts_total")
368 .desc("Number of Instructions Simulated");
371 .name(name() + ".cpi")
372 .desc("CPI: Cycles Per Instruction")
374 cpi
= simTicks
/ committedInsts
;
377 .name(name() + ".cpi_total")
378 .desc("CPI: Total CPI of All Threads")
380 totalCpi
= simTicks
/ totalCommittedInsts
;
383 .name(name() + ".ipc")
384 .desc("IPC: Instructions Per Cycle")
386 ipc
= committedInsts
/ simTicks
;
389 .name(name() + ".ipc_total")
390 .desc("IPC: Total IPC of All Threads")
392 totalIpc
= totalCommittedInsts
/ simTicks
;
396 template <class Impl
>
398 FullO3CPU
<Impl
>::getPort(const std::string
&if_name
, int idx
)
400 if (if_name
== "dcache_port")
401 return iew
.getDcachePort();
402 else if (if_name
== "icache_port")
403 return fetch
.getIcachePort();
405 panic("No Such Port\n");
408 template <class Impl
>
410 FullO3CPU
<Impl
>::tick()
412 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
418 //Tick each of the stages
433 // Now advance the time buffers
434 timeBuffer
.advance();
436 fetchQueue
.advance();
437 decodeQueue
.advance();
438 renameQueue
.advance();
441 activityRec
.advance();
443 if (removeInstsThisCycle
) {
444 cleanUpRemovedInsts();
447 if (!tickEvent
.scheduled()) {
448 if (_status
== SwitchedOut
||
449 getState() == SimObject::Drained
) {
451 lastRunningCycle
= curTick
;
452 } else if (!activityRec
.active()) {
453 lastRunningCycle
= curTick
;
456 tickEvent
.schedule(curTick
+ cycles(1));
461 updateThreadPriority();
466 template <class Impl
>
468 FullO3CPU
<Impl
>::init()
470 if (!deferRegistration
) {
471 registerThreadContexts();
474 // Set inSyscall so that the CPU doesn't squash when initially
475 // setting up registers.
476 for (int i
= 0; i
< number_of_threads
; ++i
)
477 thread
[i
]->inSyscall
= true;
479 for (int tid
=0; tid
< number_of_threads
; tid
++) {
481 ThreadContext
*src_tc
= threadContexts
[tid
];
483 ThreadContext
*src_tc
= thread
[tid
]->getTC();
485 // Threads start in the Suspended State
486 if (src_tc
->status() != ThreadContext::Suspended
) {
491 TheISA::initCPU(src_tc
, src_tc
->readCpuId());
496 for (int i
= 0; i
< number_of_threads
; ++i
)
497 thread
[i
]->inSyscall
= false;
499 // Initialize stages.
505 commit
.setThreads(thread
);
508 template <class Impl
>
510 FullO3CPU
<Impl
>::activateThread(unsigned tid
)
512 list
<unsigned>::iterator isActive
= find(
513 activeThreads
.begin(), activeThreads
.end(), tid
);
515 if (isActive
== activeThreads
.end()) {
516 DPRINTF(O3CPU
, "[tid:%i]: Adding to active threads list\n",
519 activeThreads
.push_back(tid
);
523 template <class Impl
>
525 FullO3CPU
<Impl
>::deactivateThread(unsigned tid
)
527 //Remove From Active List, if Active
528 list
<unsigned>::iterator thread_it
=
529 find(activeThreads
.begin(), activeThreads
.end(), tid
);
531 if (thread_it
!= activeThreads
.end()) {
532 DPRINTF(O3CPU
,"[tid:%i]: Removing from active threads list\n",
534 activeThreads
.erase(thread_it
);
538 template <class Impl
>
540 FullO3CPU
<Impl
>::activateContext(int tid
, int delay
)
542 // Needs to set each stage to running as well.
544 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to activate "
545 "on cycle %d\n", tid
, curTick
+ cycles(delay
));
546 scheduleActivateThreadEvent(tid
, delay
);
551 if(lastActivatedCycle
< curTick
) {
552 scheduleTickEvent(delay
);
554 // Be sure to signal that there's some activity so the CPU doesn't
555 // deschedule itself.
556 activityRec
.activity();
557 fetch
.wakeFromQuiesce();
559 lastActivatedCycle
= curTick
;
565 template <class Impl
>
567 FullO3CPU
<Impl
>::deallocateContext(int tid
, int delay
)
569 // Schedule removal of thread data from CPU
571 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to deallocate "
572 "on cycle %d\n", tid
, curTick
+ cycles(delay
));
573 scheduleDeallocateContextEvent(tid
, delay
);
575 deactivateThread(tid
);
580 template <class Impl
>
582 FullO3CPU
<Impl
>::suspendContext(int tid
)
584 DPRINTF(O3CPU
,"[tid: %i]: Suspending Thread Context.\n", tid
);
585 deactivateThread(tid
);
586 if (activeThreads
.size() == 0)
587 unscheduleTickEvent();
591 template <class Impl
>
593 FullO3CPU
<Impl
>::haltContext(int tid
)
595 //For now, this is the same as deallocate
596 DPRINTF(O3CPU
,"[tid:%i]: Halt Context called. Deallocating", tid
);
597 deallocateContext(tid
, 1);
600 template <class Impl
>
602 FullO3CPU
<Impl
>::insertThread(unsigned tid
)
604 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
605 // Will change now that the PC and thread state is internal to the CPU
606 // and not in the ThreadContext.
608 ThreadContext
*src_tc
= system
->threadContexts
[tid
];
610 ThreadContext
*src_tc
= tcBase(tid
);
613 //Bind Int Regs to Rename Map
614 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
615 PhysRegIndex phys_reg
= freeList
.getIntReg();
617 renameMap
[tid
].setEntry(ireg
,phys_reg
);
618 scoreboard
.setReg(phys_reg
);
621 //Bind Float Regs to Rename Map
622 for (int freg
= 0; freg
< TheISA::NumFloatRegs
; freg
++) {
623 PhysRegIndex phys_reg
= freeList
.getFloatReg();
625 renameMap
[tid
].setEntry(freg
,phys_reg
);
626 scoreboard
.setReg(phys_reg
);
629 //Copy Thread Data Into RegFile
630 //this->copyFromTC(tid);
633 setPC(src_tc
->readPC(), tid
);
634 setNextPC(src_tc
->readNextPC(), tid
);
635 #if ISA_HAS_DELAY_SLOT
636 setNextNPC(src_tc
->readNextNPC(), tid
);
639 src_tc
->setStatus(ThreadContext::Active
);
641 activateContext(tid
,1);
643 //Reset ROB/IQ/LSQ Entries
644 commit
.rob
->resetEntries();
648 template <class Impl
>
650 FullO3CPU
<Impl
>::removeThread(unsigned tid
)
652 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
654 // Copy Thread Data From RegFile
655 // If thread is suspended, it might be re-allocated
656 //this->copyToTC(tid);
658 // Unbind Int Regs from Rename Map
659 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
660 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(ireg
);
662 scoreboard
.unsetReg(phys_reg
);
663 freeList
.addReg(phys_reg
);
666 // Unbind Float Regs from Rename Map
667 for (int freg
= 0; freg
< TheISA::NumFloatRegs
; freg
++) {
668 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(freg
);
670 scoreboard
.unsetReg(phys_reg
);
671 freeList
.addReg(phys_reg
);
674 // Squash Throughout Pipeline
675 InstSeqNum squash_seq_num
= commit
.rob
->readHeadInst(tid
)->seqNum
;
676 fetch
.squash(0, squash_seq_num
, true, tid
);
678 rename
.squash(squash_seq_num
, tid
);
680 commit
.rob
->squash(squash_seq_num
, tid
);
682 assert(iew
.ldstQueue
.getCount(tid
) == 0);
684 // Reset ROB/IQ/LSQ Entries
685 if (activeThreads
.size() >= 1) {
686 commit
.rob
->resetEntries();
692 template <class Impl
>
694 FullO3CPU
<Impl
>::activateWhenReady(int tid
)
696 DPRINTF(O3CPU
,"[tid:%i]: Checking if resources are available for incoming"
697 "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
702 if (freeList
.numFreeIntRegs() >= TheISA::NumIntRegs
) {
703 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
704 "Phys. Int. Regs.\n",
707 } else if (freeList
.numFreeFloatRegs() >= TheISA::NumFloatRegs
) {
708 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
709 "Phys. Float. Regs.\n",
712 } else if (commit
.rob
->numFreeEntries() >=
713 commit
.rob
->entryAmount(activeThreads
.size() + 1)) {
714 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
718 } else if (iew
.instQueue
.numFreeEntries() >=
719 iew
.instQueue
.entryAmount(activeThreads
.size() + 1)) {
720 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
724 } else if (iew
.ldstQueue
.numFreeEntries() >=
725 iew
.ldstQueue
.entryAmount(activeThreads
.size() + 1)) {
726 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
735 contextSwitch
= false;
737 cpuWaitList
.remove(tid
);
742 contextSwitch
= true;
744 //@todo: dont always add to waitlist
746 cpuWaitList
.push_back(tid
);
750 template <class Impl
>
752 FullO3CPU
<Impl
>::serialize(std::ostream
&os
)
754 SimObject::State so_state
= SimObject::getState();
755 SERIALIZE_ENUM(so_state
);
756 BaseCPU::serialize(os
);
757 nameOut(os
, csprintf("%s.tickEvent", name()));
758 tickEvent
.serialize(os
);
760 // Use SimpleThread's ability to checkpoint to make it easier to
761 // write out the registers. Also make this static so it doesn't
762 // get instantiated multiple times (causes a panic in statistics).
763 static SimpleThread temp
;
765 for (int i
= 0; i
< thread
.size(); i
++) {
766 nameOut(os
, csprintf("%s.xc.%i", name(), i
));
767 temp
.copyTC(thread
[i
]->getTC());
772 template <class Impl
>
774 FullO3CPU
<Impl
>::unserialize(Checkpoint
*cp
, const std::string
§ion
)
776 SimObject::State so_state
;
777 UNSERIALIZE_ENUM(so_state
);
778 BaseCPU::unserialize(cp
, section
);
779 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
781 // Use SimpleThread's ability to checkpoint to make it easier to
782 // read in the registers. Also make this static so it doesn't
783 // get instantiated multiple times (causes a panic in statistics).
784 static SimpleThread temp
;
786 for (int i
= 0; i
< thread
.size(); i
++) {
787 temp
.copyTC(thread
[i
]->getTC());
788 temp
.unserialize(cp
, csprintf("%s.xc.%i", section
, i
));
789 thread
[i
]->getTC()->copyArchRegs(temp
.getTC());
793 template <class Impl
>
795 FullO3CPU
<Impl
>::drain(Event
*drain_event
)
797 DPRINTF(O3CPU
, "Switching out\n");
798 BaseCPU::switchOut(_sampler
);
806 // Wake the CPU and record activity so everything can drain out if
807 // the CPU was not able to immediately drain.
808 if (getState() != SimObject::Drained
) {
809 // A bit of a hack...set the drainEvent after all the drain()
810 // calls have been made, that way if all of the stages drain
811 // immediately, the signalDrained() function knows not to call
812 // process on the drain event.
813 drainEvent
= drain_event
;
816 activityRec
.activity();
824 template <class Impl
>
826 FullO3CPU
<Impl
>::resume()
828 assert(system
->getMemoryMode() == System::Timing
);
835 changeState(SimObject::Running
);
837 if (_status
== SwitchedOut
|| _status
== Idle
)
840 if (!tickEvent
.scheduled())
841 tickEvent
.schedule(curTick
);
845 template <class Impl
>
847 FullO3CPU
<Impl
>::signalDrained()
849 if (++drainCount
== NumStages
) {
850 if (tickEvent
.scheduled())
853 changeState(SimObject::Drained
);
856 drainEvent
->process();
860 assert(drainCount
<= 5);
863 template <class Impl
>
865 FullO3CPU
<Impl
>::switchOut()
872 while (!removeList
.empty()) {
876 _status
= SwitchedOut
;
879 checker
->switchOut();
883 template <class Impl
>
885 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
887 // Flush out any old data from the time buffers.
888 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
889 timeBuffer
.advance();
890 fetchQueue
.advance();
891 decodeQueue
.advance();
892 renameQueue
.advance();
898 BaseCPU::takeOverFrom(oldCPU
);
900 fetch
.takeOverFrom();
901 decode
.takeOverFrom();
902 rename
.takeOverFrom();
904 commit
.takeOverFrom();
906 assert(!tickEvent
.scheduled());
908 // @todo: Figure out how to properly select the tid to put onto
909 // the active threads list.
912 list
<unsigned>::iterator isActive
= find(
913 activeThreads
.begin(), activeThreads
.end(), tid
);
915 if (isActive
== activeThreads
.end()) {
916 //May Need to Re-code this if the delay variable is the delay
917 //needed for thread to activate
918 DPRINTF(O3CPU
, "Adding Thread %i to active threads list\n",
921 activeThreads
.push_back(tid
);
924 // Set all statuses to active, schedule the CPU's tick event.
925 // @todo: Fix up statuses so this is handled properly
926 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
927 ThreadContext
*tc
= threadContexts
[i
];
928 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
930 tickEvent
.schedule(curTick
);
933 if (!tickEvent
.scheduled())
934 tickEvent
.schedule(curTick
);
937 template <class Impl
>
939 FullO3CPU
<Impl
>::serialize(std::ostream
&os
)
941 BaseCPU::serialize(os
);
942 nameOut(os
, csprintf("%s.tickEvent", name()));
943 tickEvent
.serialize(os
);
945 // Use SimpleThread's ability to checkpoint to make it easier to
946 // write out the registers. Also make this static so it doesn't
947 // get instantiated multiple times (causes a panic in statistics).
948 static CPUExecContext temp
;
950 for (int i
= 0; i
< thread
.size(); i
++) {
951 nameOut(os
, csprintf("%s.xc.%i", name(), i
));
952 temp
.copyXC(thread
[i
]->getXCProxy());
957 template <class Impl
>
959 FullO3CPU
<Impl
>::unserialize(Checkpoint
*cp
, const std::string
§ion
)
961 BaseCPU::unserialize(cp
, section
);
962 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
964 // Use SimpleThread's ability to checkpoint to make it easier to
965 // read in the registers. Also make this static so it doesn't
966 // get instantiated multiple times (causes a panic in statistics).
967 static CPUExecContext temp
;
969 for (int i
= 0; i
< thread
.size(); i
++) {
970 temp
.copyXC(thread
[i
]->getXCProxy());
971 temp
.unserialize(cp
, csprintf("%s.xc.%i", section
, i
));
972 thread
[i
]->getXCProxy()->copyArchRegs(temp
.getProxy());
976 template <class Impl
>
978 FullO3CPU
<Impl
>::readIntReg(int reg_idx
)
980 return regFile
.readIntReg(reg_idx
);
983 template <class Impl
>
985 FullO3CPU
<Impl
>::readFloatReg(int reg_idx
, int width
)
987 return regFile
.readFloatReg(reg_idx
, width
);
990 template <class Impl
>
992 FullO3CPU
<Impl
>::readFloatReg(int reg_idx
)
994 return regFile
.readFloatReg(reg_idx
);
997 template <class Impl
>
999 FullO3CPU
<Impl
>::readFloatRegBits(int reg_idx
, int width
)
1001 return regFile
.readFloatRegBits(reg_idx
, width
);
1004 template <class Impl
>
1006 FullO3CPU
<Impl
>::readFloatRegBits(int reg_idx
)
1008 return regFile
.readFloatRegBits(reg_idx
);
1011 template <class Impl
>
1013 FullO3CPU
<Impl
>::setIntReg(int reg_idx
, uint64_t val
)
1015 regFile
.setIntReg(reg_idx
, val
);
1018 template <class Impl
>
1020 FullO3CPU
<Impl
>::setFloatReg(int reg_idx
, FloatReg val
, int width
)
1022 regFile
.setFloatReg(reg_idx
, val
, width
);
1025 template <class Impl
>
1027 FullO3CPU
<Impl
>::setFloatReg(int reg_idx
, FloatReg val
)
1029 regFile
.setFloatReg(reg_idx
, val
);
1032 template <class Impl
>
1034 FullO3CPU
<Impl
>::setFloatRegBits(int reg_idx
, FloatRegBits val
, int width
)
1036 regFile
.setFloatRegBits(reg_idx
, val
, width
);
1039 template <class Impl
>
1041 FullO3CPU
<Impl
>::setFloatRegBits(int reg_idx
, FloatRegBits val
)
1043 regFile
.setFloatRegBits(reg_idx
, val
);
1046 template <class Impl
>
1048 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, unsigned tid
)
1050 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1052 return regFile
.readIntReg(phys_reg
);
1055 template <class Impl
>
1057 FullO3CPU
<Impl
>::readArchFloatRegSingle(int reg_idx
, unsigned tid
)
1059 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1060 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1062 return regFile
.readFloatReg(phys_reg
);
1065 template <class Impl
>
1067 FullO3CPU
<Impl
>::readArchFloatRegDouble(int reg_idx
, unsigned tid
)
1069 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1070 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1072 return regFile
.readFloatReg(phys_reg
, 64);
1075 template <class Impl
>
1077 FullO3CPU
<Impl
>::readArchFloatRegInt(int reg_idx
, unsigned tid
)
1079 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1080 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1082 return regFile
.readFloatRegBits(phys_reg
);
1085 template <class Impl
>
1087 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, uint64_t val
, unsigned tid
)
1089 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1091 regFile
.setIntReg(phys_reg
, val
);
1094 template <class Impl
>
1096 FullO3CPU
<Impl
>::setArchFloatRegSingle(int reg_idx
, float val
, unsigned tid
)
1098 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1099 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1101 regFile
.setFloatReg(phys_reg
, val
);
1104 template <class Impl
>
1106 FullO3CPU
<Impl
>::setArchFloatRegDouble(int reg_idx
, double val
, unsigned tid
)
1108 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1109 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1111 regFile
.setFloatReg(phys_reg
, val
, 64);
1114 template <class Impl
>
1116 FullO3CPU
<Impl
>::setArchFloatRegInt(int reg_idx
, uint64_t val
, unsigned tid
)
1118 int idx
= reg_idx
+ TheISA::FP_Base_DepTag
;
1119 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1121 regFile
.setFloatRegBits(phys_reg
, val
);
1124 template <class Impl
>
1126 FullO3CPU
<Impl
>::readPC(unsigned tid
)
1128 return commit
.readPC(tid
);
1131 template <class Impl
>
1133 FullO3CPU
<Impl
>::setPC(Addr new_PC
,unsigned tid
)
1135 commit
.setPC(new_PC
, tid
);
1138 template <class Impl
>
1140 FullO3CPU
<Impl
>::readNextPC(unsigned tid
)
1142 return commit
.readNextPC(tid
);
1145 template <class Impl
>
1147 FullO3CPU
<Impl
>::setNextPC(uint64_t val
,unsigned tid
)
1149 commit
.setNextPC(val
, tid
);
1152 template <class Impl
>
1154 FullO3CPU
<Impl
>::readNextNPC(unsigned tid
)
1156 return commit
.readNextNPC(tid
);
1159 template <class Impl
>
1161 FullO3CPU
<Impl
>::setNextNPC(uint64_t val
,unsigned tid
)
1163 commit
.setNextNPC(val
, tid
);
1166 template <class Impl
>
1167 typename FullO3CPU
<Impl
>::ListIt
1168 FullO3CPU
<Impl
>::addInst(DynInstPtr
&inst
)
1170 instList
.push_back(inst
);
1172 return --(instList
.end());
1175 template <class Impl
>
1177 FullO3CPU
<Impl
>::instDone(unsigned tid
)
1179 // Keep an instruction count.
1180 thread
[tid
]->numInst
++;
1181 thread
[tid
]->numInsts
++;
1182 committedInsts
[tid
]++;
1183 totalCommittedInsts
++;
1185 // Check for instruction-count-based events.
1186 comInstEventQueue
[tid
]->serviceEvents(thread
[tid
]->numInst
);
1189 template <class Impl
>
1191 FullO3CPU
<Impl
>::addToRemoveList(DynInstPtr
&inst
)
1193 removeInstsThisCycle
= true;
1195 removeList
.push(inst
->getInstListIt());
1198 template <class Impl
>
1200 FullO3CPU
<Impl
>::removeFrontInst(DynInstPtr
&inst
)
1202 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %#x "
1204 inst
->threadNumber
, inst
->readPC(), inst
->seqNum
);
1206 removeInstsThisCycle
= true;
1208 // Remove the front instruction.
1209 removeList
.push(inst
->getInstListIt());
1212 template <class Impl
>
1214 FullO3CPU
<Impl
>::removeInstsNotInROB(unsigned tid
,
1215 bool squash_delay_slot
,
1216 const InstSeqNum
&delay_slot_seq_num
)
1218 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1223 bool rob_empty
= false;
1225 if (instList
.empty()) {
1227 } else if (rob
.isEmpty(/*tid*/)) {
1228 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1229 end_it
= instList
.begin();
1232 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1233 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1236 removeInstsThisCycle
= true;
1238 ListIt inst_it
= instList
.end();
1242 // Walk through the instruction list, removing any instructions
1243 // that were inserted after the given instruction iterator, end_it.
1244 while (inst_it
!= end_it
) {
1245 assert(!instList
.empty());
1247 #if ISA_HAS_DELAY_SLOT
1248 if(!squash_delay_slot
&&
1249 delay_slot_seq_num
>= (*inst_it
)->seqNum
) {
1253 squashInstIt(inst_it
, tid
);
1258 // If the ROB was empty, then we actually need to remove the first
1259 // instruction as well.
1261 squashInstIt(inst_it
, tid
);
1265 template <class Impl
>
1267 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
,
1270 assert(!instList
.empty());
1272 removeInstsThisCycle
= true;
1274 ListIt inst_iter
= instList
.end();
1278 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1279 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1280 tid
, seq_num
, (*inst_iter
)->seqNum
);
1282 while ((*inst_iter
)->seqNum
> seq_num
) {
1284 bool break_loop
= (inst_iter
== instList
.begin());
1286 squashInstIt(inst_iter
, tid
);
1295 template <class Impl
>
1297 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, const unsigned &tid
)
1299 if ((*instIt
)->threadNumber
== tid
) {
1300 DPRINTF(O3CPU
, "Squashing instruction, "
1301 "[tid:%i] [sn:%lli] PC %#x\n",
1302 (*instIt
)->threadNumber
,
1304 (*instIt
)->readPC());
1306 // Mark it as squashed.
1307 (*instIt
)->setSquashed();
1309 // @todo: Formulate a consistent method for deleting
1310 // instructions from the instruction list
1311 // Remove the instruction from the list.
1312 removeList
.push(instIt
);
1316 template <class Impl
>
1318 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1320 while (!removeList
.empty()) {
1321 DPRINTF(O3CPU
, "Removing instruction, "
1322 "[tid:%i] [sn:%lli] PC %#x\n",
1323 (*removeList
.front())->threadNumber
,
1324 (*removeList
.front())->seqNum
,
1325 (*removeList
.front())->readPC());
1327 instList
.erase(removeList
.front());
1332 removeInstsThisCycle
= false;
1335 template <class Impl>
1337 FullO3CPU<Impl>::removeAllInsts()
1342 template <class Impl
>
1344 FullO3CPU
<Impl
>::dumpInsts()
1348 ListIt inst_list_it
= instList
.begin();
1350 cprintf("Dumping Instruction List\n");
1352 while (inst_list_it
!= instList
.end()) {
1353 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1355 num
, (*inst_list_it
)->readPC(), (*inst_list_it
)->threadNumber
,
1356 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1357 (*inst_list_it
)->isSquashed());
1363 template <class Impl>
1365 FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
1367 iew.wakeDependents(inst);
1370 template <class Impl
>
1372 FullO3CPU
<Impl
>::wakeCPU()
1374 if (activityRec
.active() || tickEvent
.scheduled()) {
1375 DPRINTF(Activity
, "CPU already running.\n");
1379 DPRINTF(Activity
, "Waking up CPU\n");
1381 idleCycles
+= (curTick
- 1) - lastRunningCycle
;
1383 tickEvent
.schedule(curTick
);
1386 template <class Impl
>
1388 FullO3CPU
<Impl
>::getFreeTid()
1390 for (int i
=0; i
< numThreads
; i
++) {
1400 template <class Impl
>
1402 FullO3CPU
<Impl
>::doContextSwitch()
1404 if (contextSwitch
) {
1406 //ADD CODE TO DEACTIVE THREAD HERE (???)
1408 for (int tid
=0; tid
< cpuWaitList
.size(); tid
++) {
1409 activateWhenReady(tid
);
1412 if (cpuWaitList
.size() == 0)
1413 contextSwitch
= true;
1417 template <class Impl
>
1419 FullO3CPU
<Impl
>::updateThreadPriority()
1421 if (activeThreads
.size() > 1)
1423 //DEFAULT TO ROUND ROBIN SCHEME
1424 //e.g. Move highest priority to end of thread list
1425 list
<unsigned>::iterator list_begin
= activeThreads
.begin();
1426 list
<unsigned>::iterator list_end
= activeThreads
.end();
1428 unsigned high_thread
= *list_begin
;
1430 activeThreads
.erase(list_begin
);
1432 activeThreads
.push_back(high_thread
);
1436 // Forward declaration of FullO3CPU.
1437 template class FullO3CPU
<O3CPUImpl
>;