2 * Copyright (c) 2011 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2004-2006 The Regents of The University of Michigan
15 * Copyright (c) 2011 Regents of the University of California
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 #include "config/full_system.hh"
47 #include "config/the_isa.hh"
48 #include "config/use_checker.hh"
49 #include "cpu/o3/cpu.hh"
50 #include "cpu/o3/isa_specific.hh"
51 #include "cpu/o3/thread_context.hh"
52 #include "cpu/activity.hh"
53 #include "cpu/simple_thread.hh"
54 #include "cpu/thread_context.hh"
55 #include "debug/Activity.hh"
56 #include "debug/O3CPU.hh"
57 #include "debug/Quiesce.hh"
58 #include "enums/MemoryMode.hh"
59 #include "sim/core.hh"
60 #include "sim/stat_control.hh"
61 #include "sim/system.hh"
64 #include "cpu/quiesce_event.hh"
66 #include "sim/process.hh"
70 #include "cpu/checker/cpu.hh"
71 #include "cpu/checker/thread_context.hh"
74 #if THE_ISA == ALPHA_ISA
75 #include "arch/alpha/osfpal.hh"
76 #include "debug/Activity.hh"
81 using namespace TheISA
;
84 BaseO3CPU::BaseO3CPU(BaseCPUParams
*params
)
97 FullO3CPU
<Impl
>::IcachePort::recvTiming(PacketPtr pkt
)
99 DPRINTF(O3CPU
, "Fetch unit received timing\n");
100 if (pkt
->isResponse()) {
101 // We shouldn't ever get a block in ownership state
102 assert(!(pkt
->memInhibitAsserted() && !pkt
->sharedAsserted()));
104 fetch
->processCacheCompletion(pkt
);
106 //else Snooped a coherence request, just return
112 FullO3CPU
<Impl
>::IcachePort::recvRetry()
117 template <class Impl
>
119 FullO3CPU
<Impl
>::DcachePort::recvTiming(PacketPtr pkt
)
121 return lsq
->recvTiming(pkt
);
124 template <class Impl
>
126 FullO3CPU
<Impl
>::DcachePort::recvRetry()
131 template <class Impl
>
132 FullO3CPU
<Impl
>::TickEvent::TickEvent(FullO3CPU
<Impl
> *c
)
133 : Event(CPU_Tick_Pri
), cpu(c
)
137 template <class Impl
>
139 FullO3CPU
<Impl
>::TickEvent::process()
144 template <class Impl
>
146 FullO3CPU
<Impl
>::TickEvent::description() const
148 return "FullO3CPU tick";
151 template <class Impl
>
152 FullO3CPU
<Impl
>::ActivateThreadEvent::ActivateThreadEvent()
153 : Event(CPU_Switch_Pri
)
157 template <class Impl
>
159 FullO3CPU
<Impl
>::ActivateThreadEvent::init(int thread_num
,
160 FullO3CPU
<Impl
> *thread_cpu
)
166 template <class Impl
>
168 FullO3CPU
<Impl
>::ActivateThreadEvent::process()
170 cpu
->activateThread(tid
);
173 template <class Impl
>
175 FullO3CPU
<Impl
>::ActivateThreadEvent::description() const
177 return "FullO3CPU \"Activate Thread\"";
180 template <class Impl
>
181 FullO3CPU
<Impl
>::DeallocateContextEvent::DeallocateContextEvent()
182 : Event(CPU_Tick_Pri
), tid(0), remove(false), cpu(NULL
)
186 template <class Impl
>
188 FullO3CPU
<Impl
>::DeallocateContextEvent::init(int thread_num
,
189 FullO3CPU
<Impl
> *thread_cpu
)
196 template <class Impl
>
198 FullO3CPU
<Impl
>::DeallocateContextEvent::process()
200 cpu
->deactivateThread(tid
);
202 cpu
->removeThread(tid
);
205 template <class Impl
>
207 FullO3CPU
<Impl
>::DeallocateContextEvent::description() const
209 return "FullO3CPU \"Deallocate Context\"";
212 template <class Impl
>
213 FullO3CPU
<Impl
>::FullO3CPU(DerivO3CPUParams
*params
)
221 removeInstsThisCycle(false),
223 decode(this, params
),
224 rename(this, params
),
226 commit(this, params
),
228 regFile(this, params
->numPhysIntRegs
,
229 params
->numPhysFloatRegs
),
231 freeList(params
->numThreads
,
232 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
233 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
),
236 params
->numROBEntries
, params
->squashWidth
,
237 params
->smtROBPolicy
, params
->smtROBThreshold
,
240 scoreboard(params
->numThreads
,
241 TheISA::NumIntRegs
, params
->numPhysIntRegs
,
242 TheISA::NumFloatRegs
, params
->numPhysFloatRegs
,
243 TheISA::NumMiscRegs
* numThreads
,
246 icachePort(&fetch
, this),
247 dcachePort(&iew
.ldstQueue
, this),
249 timeBuffer(params
->backComSize
, params
->forwardComSize
),
250 fetchQueue(params
->backComSize
, params
->forwardComSize
),
251 decodeQueue(params
->backComSize
, params
->forwardComSize
),
252 renameQueue(params
->backComSize
, params
->forwardComSize
),
253 iewQueue(params
->backComSize
, params
->forwardComSize
),
254 activityRec(name(), NumStages
,
255 params
->backComSize
+ params
->forwardComSize
,
259 system(params
->system
),
261 deferRegistration(params
->defer_registration
)
263 if (!deferRegistration
) {
270 if (params
->checker
) {
271 BaseCPU
*temp_checker
= params
->checker
;
272 checker
= dynamic_cast<Checker
<Impl
> *>(temp_checker
);
273 checker
->setIcachePort(&icachePort
);
275 checker
->setSystem(params
->system
);
280 #endif // USE_CHECKER
283 thread
.resize(numThreads
);
284 tids
.resize(numThreads
);
287 // The stages also need their CPU pointer setup. However this
288 // must be done at the upper level CPU because they have pointers
289 // to the upper level CPU, and not this FullO3CPU.
291 // Set up Pointers to the activeThreads list for each stage
292 fetch
.setActiveThreads(&activeThreads
);
293 decode
.setActiveThreads(&activeThreads
);
294 rename
.setActiveThreads(&activeThreads
);
295 iew
.setActiveThreads(&activeThreads
);
296 commit
.setActiveThreads(&activeThreads
);
298 // Give each of the stages the time buffer they will use.
299 fetch
.setTimeBuffer(&timeBuffer
);
300 decode
.setTimeBuffer(&timeBuffer
);
301 rename
.setTimeBuffer(&timeBuffer
);
302 iew
.setTimeBuffer(&timeBuffer
);
303 commit
.setTimeBuffer(&timeBuffer
);
305 // Also setup each of the stages' queues.
306 fetch
.setFetchQueue(&fetchQueue
);
307 decode
.setFetchQueue(&fetchQueue
);
308 commit
.setFetchQueue(&fetchQueue
);
309 decode
.setDecodeQueue(&decodeQueue
);
310 rename
.setDecodeQueue(&decodeQueue
);
311 rename
.setRenameQueue(&renameQueue
);
312 iew
.setRenameQueue(&renameQueue
);
313 iew
.setIEWQueue(&iewQueue
);
314 commit
.setIEWQueue(&iewQueue
);
315 commit
.setRenameQueue(&renameQueue
);
317 commit
.setIEWStage(&iew
);
318 rename
.setIEWStage(&iew
);
319 rename
.setCommitStage(&commit
);
322 ThreadID active_threads
= params
->workload
.size();
324 if (active_threads
> Impl::MaxThreads
) {
325 panic("Workload Size too large. Increase the 'MaxThreads'"
326 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or "
327 "edit your workload size.");
330 ThreadID active_threads
= 1;
333 //Make Sure That this a Valid Architeture
334 assert(params
->numPhysIntRegs
>= numThreads
* TheISA::NumIntRegs
);
335 assert(params
->numPhysFloatRegs
>= numThreads
* TheISA::NumFloatRegs
);
337 rename
.setScoreboard(&scoreboard
);
338 iew
.setScoreboard(&scoreboard
);
340 // Setup the rename map for whichever stages need it.
341 PhysRegIndex lreg_idx
= 0;
342 PhysRegIndex freg_idx
= params
->numPhysIntRegs
; //Index to 1 after int regs
344 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
345 bool bindRegs
= (tid
<= active_threads
- 1);
347 commitRenameMap
[tid
].init(TheISA::NumIntRegs
,
348 params
->numPhysIntRegs
,
349 lreg_idx
, //Index for Logical. Regs
351 TheISA::NumFloatRegs
,
352 params
->numPhysFloatRegs
,
353 freg_idx
, //Index for Float Regs
363 renameMap
[tid
].init(TheISA::NumIntRegs
,
364 params
->numPhysIntRegs
,
365 lreg_idx
, //Index for Logical. Regs
367 TheISA::NumFloatRegs
,
368 params
->numPhysFloatRegs
,
369 freg_idx
, //Index for Float Regs
379 activateThreadEvent
[tid
].init(tid
, this);
380 deallocateContextEvent
[tid
].init(tid
, this);
383 rename
.setRenameMap(renameMap
);
384 commit
.setRenameMap(commitRenameMap
);
386 // Give renameMap & rename stage access to the freeList;
387 for (ThreadID tid
= 0; tid
< numThreads
; tid
++)
388 renameMap
[tid
].setFreeList(&freeList
);
389 rename
.setFreeList(&freeList
);
391 // Setup the ROB for whichever stages need it.
394 lastRunningCycle
= curTick();
396 lastActivatedCycle
= -1;
398 // Give renameMap & rename stage access to the freeList;
399 for (ThreadID tid
= 0; tid
< numThreads
; tid
++)
400 globalSeqNum
[tid
] = 1;
403 contextSwitch
= false;
404 DPRINTF(O3CPU
, "Creating O3CPU object.\n");
406 // Setup any thread state.
407 this->thread
.resize(this->numThreads
);
409 for (ThreadID tid
= 0; tid
< this->numThreads
; ++tid
) {
411 // SMT is not supported in FS mode yet.
412 assert(this->numThreads
== 1);
413 this->thread
[tid
] = new Thread(this, 0);
415 if (tid
< params
->workload
.size()) {
416 DPRINTF(O3CPU
, "Workload[%i] process is %#x",
417 tid
, this->thread
[tid
]);
418 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
419 (typename
Impl::O3CPU
*)(this),
420 tid
, params
->workload
[tid
]);
422 //usedTids[tid] = true;
423 //threadMap[tid] = tid;
425 //Allocate Empty thread so M5 can use later
426 //when scheduling threads to CPU
427 Process
* dummy_proc
= NULL
;
429 this->thread
[tid
] = new typename FullO3CPU
<Impl
>::Thread(
430 (typename
Impl::O3CPU
*)(this),
432 //usedTids[tid] = false;
434 #endif // !FULL_SYSTEM
438 // Setup the TC that will serve as the interface to the threads/CPU.
439 O3ThreadContext
<Impl
> *o3_tc
= new O3ThreadContext
<Impl
>;
443 // If we're using a checker, then the TC should be the
444 // CheckerThreadContext.
446 if (params
->checker
) {
447 tc
= new CheckerThreadContext
<O3ThreadContext
<Impl
> >(
448 o3_tc
, this->checker
);
452 o3_tc
->cpu
= (typename
Impl::O3CPU
*)(this);
454 o3_tc
->thread
= this->thread
[tid
];
457 // Setup quiesce event.
458 this->thread
[tid
]->quiesceEvent
= new EndQuiesceEvent(tc
);
460 // Give the thread the TC.
461 this->thread
[tid
]->tc
= tc
;
463 // Add the TC to the CPU's list of TC's.
464 this->threadContexts
.push_back(tc
);
467 for (ThreadID tid
= 0; tid
< this->numThreads
; tid
++)
468 this->thread
[tid
]->setFuncExeInst(0);
474 template <class Impl
>
475 FullO3CPU
<Impl
>::~FullO3CPU()
479 template <class Impl
>
481 FullO3CPU
<Impl
>::regStats()
483 BaseO3CPU::regStats();
485 // Register any of the O3CPU's stats here.
487 .name(name() + ".timesIdled")
488 .desc("Number of times that the entire CPU went into an idle state and"
489 " unscheduled itself")
493 .name(name() + ".idleCycles")
494 .desc("Total number of cycles that the CPU has spent unscheduled due "
499 .name(name() + ".quiesceCycles")
500 .desc("Total number of cycles that CPU has spent quiesced or waiting "
502 .prereq(quiesceCycles
);
504 // Number of Instructions simulated
505 // --------------------------------
506 // Should probably be in Base CPU but need templated
507 // MaxThreads so put in here instead
510 .name(name() + ".committedInsts")
511 .desc("Number of Instructions Simulated");
514 .name(name() + ".committedInsts_total")
515 .desc("Number of Instructions Simulated");
518 .name(name() + ".cpi")
519 .desc("CPI: Cycles Per Instruction")
521 cpi
= numCycles
/ committedInsts
;
524 .name(name() + ".cpi_total")
525 .desc("CPI: Total CPI of All Threads")
527 totalCpi
= numCycles
/ totalCommittedInsts
;
530 .name(name() + ".ipc")
531 .desc("IPC: Instructions Per Cycle")
533 ipc
= committedInsts
/ numCycles
;
536 .name(name() + ".ipc_total")
537 .desc("IPC: Total IPC of All Threads")
539 totalIpc
= totalCommittedInsts
/ numCycles
;
541 this->fetch
.regStats();
542 this->decode
.regStats();
543 this->rename
.regStats();
544 this->iew
.regStats();
545 this->commit
.regStats();
546 this->rob
.regStats();
549 .name(name() + ".int_regfile_reads")
550 .desc("number of integer regfile reads")
551 .prereq(intRegfileReads
);
554 .name(name() + ".int_regfile_writes")
555 .desc("number of integer regfile writes")
556 .prereq(intRegfileWrites
);
559 .name(name() + ".fp_regfile_reads")
560 .desc("number of floating regfile reads")
561 .prereq(fpRegfileReads
);
564 .name(name() + ".fp_regfile_writes")
565 .desc("number of floating regfile writes")
566 .prereq(fpRegfileWrites
);
569 .name(name() + ".misc_regfile_reads")
570 .desc("number of misc regfile reads")
571 .prereq(miscRegfileReads
);
574 .name(name() + ".misc_regfile_writes")
575 .desc("number of misc regfile writes")
576 .prereq(miscRegfileWrites
);
579 template <class Impl
>
581 FullO3CPU
<Impl
>::getPort(const std::string
&if_name
, int idx
)
583 if (if_name
== "dcache_port")
585 else if (if_name
== "icache_port")
588 panic("No Such Port\n");
591 template <class Impl
>
593 FullO3CPU
<Impl
>::tick()
595 DPRINTF(O3CPU
, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
601 //Tick each of the stages
616 // Now advance the time buffers
617 timeBuffer
.advance();
619 fetchQueue
.advance();
620 decodeQueue
.advance();
621 renameQueue
.advance();
624 activityRec
.advance();
626 if (removeInstsThisCycle
) {
627 cleanUpRemovedInsts();
630 if (!tickEvent
.scheduled()) {
631 if (_status
== SwitchedOut
||
632 getState() == SimObject::Drained
) {
633 DPRINTF(O3CPU
, "Switched out!\n");
635 lastRunningCycle
= curTick();
636 } else if (!activityRec
.active() || _status
== Idle
) {
637 DPRINTF(O3CPU
, "Idle!\n");
638 lastRunningCycle
= curTick();
641 schedule(tickEvent
, nextCycle(curTick() + ticks(1)));
642 DPRINTF(O3CPU
, "Scheduling next tick!\n");
647 updateThreadPriority();
651 template <class Impl
>
653 FullO3CPU
<Impl
>::init()
657 // Set inSyscall so that the CPU doesn't squash when initially
658 // setting up registers.
659 for (ThreadID tid
= 0; tid
< numThreads
; ++tid
)
660 thread
[tid
]->inSyscall
= true;
662 // this CPU could still be unconnected if we are restoring from a
663 // checkpoint and this CPU is to be switched in, thus we can only
664 // do this here if the instruction port is actually connected, if
665 // not we have to do it as part of takeOverFrom
666 if (icachePort
.isConnected())
670 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
671 ThreadContext
*src_tc
= threadContexts
[tid
];
672 TheISA::initCPU(src_tc
, src_tc
->contextId());
673 // Initialise the ThreadContext's memory proxies
674 thread
[tid
]->initMemProxies(thread
[tid
]->getTC());
679 for (int tid
= 0; tid
< numThreads
; ++tid
)
680 thread
[tid
]->inSyscall
= false;
682 // Initialize stages.
688 commit
.setThreads(thread
);
691 template <class Impl
>
693 FullO3CPU
<Impl
>::activateThread(ThreadID tid
)
695 list
<ThreadID
>::iterator isActive
=
696 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
698 DPRINTF(O3CPU
, "[tid:%i]: Calling activate thread.\n", tid
);
700 if (isActive
== activeThreads
.end()) {
701 DPRINTF(O3CPU
, "[tid:%i]: Adding to active threads list\n",
704 activeThreads
.push_back(tid
);
708 template <class Impl
>
710 FullO3CPU
<Impl
>::deactivateThread(ThreadID tid
)
712 //Remove From Active List, if Active
713 list
<ThreadID
>::iterator thread_it
=
714 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
716 DPRINTF(O3CPU
, "[tid:%i]: Calling deactivate thread.\n", tid
);
718 if (thread_it
!= activeThreads
.end()) {
719 DPRINTF(O3CPU
,"[tid:%i]: Removing from active threads list\n",
721 activeThreads
.erase(thread_it
);
725 template <class Impl
>
727 FullO3CPU
<Impl
>::totalInstructions() const
731 ThreadID size
= thread
.size();
732 for (ThreadID i
= 0; i
< size
; i
++)
733 total
+= thread
[i
]->numInst
;
738 template <class Impl
>
740 FullO3CPU
<Impl
>::activateContext(ThreadID tid
, int delay
)
742 // Needs to set each stage to running as well.
744 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to activate "
745 "on cycle %d\n", tid
, curTick() + ticks(delay
));
746 scheduleActivateThreadEvent(tid
, delay
);
751 if (lastActivatedCycle
< curTick()) {
752 scheduleTickEvent(delay
);
754 // Be sure to signal that there's some activity so the CPU doesn't
755 // deschedule itself.
756 activityRec
.activity();
757 fetch
.wakeFromQuiesce();
759 quiesceCycles
+= tickToCycles((curTick() - 1) - lastRunningCycle
);
761 lastActivatedCycle
= curTick();
767 template <class Impl
>
769 FullO3CPU
<Impl
>::deallocateContext(ThreadID tid
, bool remove
, int delay
)
771 // Schedule removal of thread data from CPU
773 DPRINTF(O3CPU
, "[tid:%i]: Scheduling thread context to deallocate "
774 "on cycle %d\n", tid
, curTick() + ticks(delay
));
775 scheduleDeallocateContextEvent(tid
, remove
, delay
);
778 deactivateThread(tid
);
785 template <class Impl
>
787 FullO3CPU
<Impl
>::suspendContext(ThreadID tid
)
789 DPRINTF(O3CPU
,"[tid: %i]: Suspending Thread Context.\n", tid
);
790 bool deallocated
= deallocateContext(tid
, false, 1);
791 // If this was the last thread then unschedule the tick event.
792 if ((activeThreads
.size() == 1 && !deallocated
) ||
793 activeThreads
.size() == 0)
794 unscheduleTickEvent();
796 DPRINTF(Quiesce
, "Suspending Context\n");
797 lastRunningCycle
= curTick();
801 template <class Impl
>
803 FullO3CPU
<Impl
>::haltContext(ThreadID tid
)
805 //For now, this is the same as deallocate
806 DPRINTF(O3CPU
,"[tid:%i]: Halt Context called. Deallocating", tid
);
807 deallocateContext(tid
, true, 1);
810 template <class Impl
>
812 FullO3CPU
<Impl
>::insertThread(ThreadID tid
)
814 DPRINTF(O3CPU
,"[tid:%i] Initializing thread into CPU");
815 // Will change now that the PC and thread state is internal to the CPU
816 // and not in the ThreadContext.
818 ThreadContext
*src_tc
= system
->threadContexts
[tid
];
820 ThreadContext
*src_tc
= tcBase(tid
);
823 //Bind Int Regs to Rename Map
824 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
825 PhysRegIndex phys_reg
= freeList
.getIntReg();
827 renameMap
[tid
].setEntry(ireg
,phys_reg
);
828 scoreboard
.setReg(phys_reg
);
831 //Bind Float Regs to Rename Map
832 for (int freg
= 0; freg
< TheISA::NumFloatRegs
; freg
++) {
833 PhysRegIndex phys_reg
= freeList
.getFloatReg();
835 renameMap
[tid
].setEntry(freg
,phys_reg
);
836 scoreboard
.setReg(phys_reg
);
839 //Copy Thread Data Into RegFile
840 //this->copyFromTC(tid);
843 pcState(src_tc
->pcState(), tid
);
845 src_tc
->setStatus(ThreadContext::Active
);
847 activateContext(tid
,1);
849 //Reset ROB/IQ/LSQ Entries
850 commit
.rob
->resetEntries();
854 template <class Impl
>
856 FullO3CPU
<Impl
>::removeThread(ThreadID tid
)
858 DPRINTF(O3CPU
,"[tid:%i] Removing thread context from CPU.\n", tid
);
860 // Copy Thread Data From RegFile
861 // If thread is suspended, it might be re-allocated
862 // this->copyToTC(tid);
865 // @todo: 2-27-2008: Fix how we free up rename mappings
866 // here to alleviate the case for double-freeing registers
869 // Unbind Int Regs from Rename Map
870 for (int ireg
= 0; ireg
< TheISA::NumIntRegs
; ireg
++) {
871 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(ireg
);
873 scoreboard
.unsetReg(phys_reg
);
874 freeList
.addReg(phys_reg
);
877 // Unbind Float Regs from Rename Map
878 for (int freg
= TheISA::NumIntRegs
; freg
< TheISA::NumFloatRegs
; freg
++) {
879 PhysRegIndex phys_reg
= renameMap
[tid
].lookup(freg
);
881 scoreboard
.unsetReg(phys_reg
);
882 freeList
.addReg(phys_reg
);
885 // Squash Throughout Pipeline
886 DynInstPtr inst
= commit
.rob
->readHeadInst(tid
);
887 InstSeqNum squash_seq_num
= inst
->seqNum
;
888 fetch
.squash(0, squash_seq_num
, inst
, tid
);
890 rename
.squash(squash_seq_num
, tid
);
892 iew
.ldstQueue
.squash(squash_seq_num
, tid
);
893 commit
.rob
->squash(squash_seq_num
, tid
);
896 assert(iew
.instQueue
.getCount(tid
) == 0);
897 assert(iew
.ldstQueue
.getCount(tid
) == 0);
899 // Reset ROB/IQ/LSQ Entries
901 // Commented out for now. This should be possible to do by
902 // telling all the pipeline stages to drain first, and then
903 // checking until the drain completes. Once the pipeline is
904 // drained, call resetEntries(). - 10-09-06 ktlim
906 if (activeThreads.size() >= 1) {
907 commit.rob->resetEntries();
914 template <class Impl
>
916 FullO3CPU
<Impl
>::activateWhenReady(ThreadID tid
)
918 DPRINTF(O3CPU
,"[tid:%i]: Checking if resources are available for incoming"
919 "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
924 if (freeList
.numFreeIntRegs() >= TheISA::NumIntRegs
) {
925 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
926 "Phys. Int. Regs.\n",
929 } else if (freeList
.numFreeFloatRegs() >= TheISA::NumFloatRegs
) {
930 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
931 "Phys. Float. Regs.\n",
934 } else if (commit
.rob
->numFreeEntries() >=
935 commit
.rob
->entryAmount(activeThreads
.size() + 1)) {
936 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
940 } else if (iew
.instQueue
.numFreeEntries() >=
941 iew
.instQueue
.entryAmount(activeThreads
.size() + 1)) {
942 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
946 } else if (iew
.ldstQueue
.numFreeEntries() >=
947 iew
.ldstQueue
.entryAmount(activeThreads
.size() + 1)) {
948 DPRINTF(O3CPU
,"[tid:%i] Suspending thread due to not enough "
957 contextSwitch
= false;
959 cpuWaitList
.remove(tid
);
964 contextSwitch
= true;
966 //@todo: dont always add to waitlist
968 cpuWaitList
.push_back(tid
);
973 template <class Impl
>
975 FullO3CPU
<Impl
>::hwrei(ThreadID tid
)
977 #if THE_ISA == ALPHA_ISA
978 // Need to clear the lock flag upon returning from an interrupt.
979 this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG
, false, tid
);
981 this->thread
[tid
]->kernelStats
->hwrei();
983 // FIXME: XXX check for interrupts? XXX
988 template <class Impl
>
990 FullO3CPU
<Impl
>::simPalCheck(int palFunc
, ThreadID tid
)
992 #if THE_ISA == ALPHA_ISA
993 if (this->thread
[tid
]->kernelStats
)
994 this->thread
[tid
]->kernelStats
->callpal(palFunc
,
995 this->threadContexts
[tid
]);
1000 if (--System::numSystemsRunning
== 0)
1001 exitSimLoop("all cpus halted");
1006 if (this->system
->breakpoint())
1014 template <class Impl
>
1016 FullO3CPU
<Impl
>::getInterrupts()
1018 // Check if there are any outstanding interrupts
1019 return this->interrupts
->getInterrupt(this->threadContexts
[0]);
1022 template <class Impl
>
1024 FullO3CPU
<Impl
>::processInterrupts(Fault interrupt
)
1026 // Check for interrupts here. For now can copy the code that
1027 // exists within isa_fullsys_traits.hh. Also assume that thread 0
1028 // is the one that handles the interrupts.
1029 // @todo: Possibly consolidate the interrupt checking code.
1030 // @todo: Allow other threads to handle interrupts.
1032 assert(interrupt
!= NoFault
);
1033 this->interrupts
->updateIntrInfo(this->threadContexts
[0]);
1035 DPRINTF(O3CPU
, "Interrupt %s being handled\n", interrupt
->name());
1036 this->trap(interrupt
, 0, NULL
);
1041 template <class Impl
>
1043 FullO3CPU
<Impl
>::trap(Fault fault
, ThreadID tid
, StaticInstPtr inst
)
1045 // Pass the thread's TC into the invoke method.
1046 fault
->invoke(this->threadContexts
[tid
], inst
);
1051 template <class Impl
>
1053 FullO3CPU
<Impl
>::syscall(int64_t callnum
, ThreadID tid
)
1055 DPRINTF(O3CPU
, "[tid:%i] Executing syscall().\n\n", tid
);
1057 DPRINTF(Activity
,"Activity: syscall() called.\n");
1059 // Temporarily increase this by one to account for the syscall
1061 ++(this->thread
[tid
]->funcExeInst
);
1063 // Execute the actual syscall.
1064 this->thread
[tid
]->syscall(callnum
);
1066 // Decrease funcExeInst by one as the normal commit will handle
1068 --(this->thread
[tid
]->funcExeInst
);
1073 template <class Impl
>
1075 FullO3CPU
<Impl
>::serialize(std::ostream
&os
)
1077 SimObject::State so_state
= SimObject::getState();
1078 SERIALIZE_ENUM(so_state
);
1079 BaseCPU::serialize(os
);
1080 nameOut(os
, csprintf("%s.tickEvent", name()));
1081 tickEvent
.serialize(os
);
1083 // Use SimpleThread's ability to checkpoint to make it easier to
1084 // write out the registers. Also make this static so it doesn't
1085 // get instantiated multiple times (causes a panic in statistics).
1086 static SimpleThread temp
;
1088 ThreadID size
= thread
.size();
1089 for (ThreadID i
= 0; i
< size
; i
++) {
1090 nameOut(os
, csprintf("%s.xc.%i", name(), i
));
1091 temp
.copyTC(thread
[i
]->getTC());
1096 template <class Impl
>
1098 FullO3CPU
<Impl
>::unserialize(Checkpoint
*cp
, const std::string
§ion
)
1100 SimObject::State so_state
;
1101 UNSERIALIZE_ENUM(so_state
);
1102 BaseCPU::unserialize(cp
, section
);
1103 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
1105 // Use SimpleThread's ability to checkpoint to make it easier to
1106 // read in the registers. Also make this static so it doesn't
1107 // get instantiated multiple times (causes a panic in statistics).
1108 static SimpleThread temp
;
1110 ThreadID size
= thread
.size();
1111 for (ThreadID i
= 0; i
< size
; i
++) {
1112 temp
.copyTC(thread
[i
]->getTC());
1113 temp
.unserialize(cp
, csprintf("%s.xc.%i", section
, i
));
1114 thread
[i
]->getTC()->copyArchRegs(temp
.getTC());
1118 template <class Impl
>
1120 FullO3CPU
<Impl
>::drain(Event
*drain_event
)
1122 DPRINTF(O3CPU
, "Switching out\n");
1124 // If the CPU isn't doing anything, then return immediately.
1125 if (_status
== Idle
|| _status
== SwitchedOut
) {
1136 // Wake the CPU and record activity so everything can drain out if
1137 // the CPU was not able to immediately drain.
1138 if (getState() != SimObject::Drained
) {
1139 // A bit of a hack...set the drainEvent after all the drain()
1140 // calls have been made, that way if all of the stages drain
1141 // immediately, the signalDrained() function knows not to call
1142 // process on the drain event.
1143 drainEvent
= drain_event
;
1146 activityRec
.activity();
1154 template <class Impl
>
1156 FullO3CPU
<Impl
>::resume()
1164 changeState(SimObject::Running
);
1166 if (_status
== SwitchedOut
|| _status
== Idle
)
1169 assert(system
->getMemoryMode() == Enums::timing
);
1171 if (!tickEvent
.scheduled())
1172 schedule(tickEvent
, nextCycle());
1176 template <class Impl
>
1178 FullO3CPU
<Impl
>::signalDrained()
1180 if (++drainCount
== NumStages
) {
1181 if (tickEvent
.scheduled())
1184 changeState(SimObject::Drained
);
1186 BaseCPU::switchOut();
1189 drainEvent
->process();
1193 assert(drainCount
<= 5);
1196 template <class Impl
>
1198 FullO3CPU
<Impl
>::switchOut()
1205 while (!removeList
.empty()) {
1209 _status
= SwitchedOut
;
1212 checker
->switchOut();
1214 if (tickEvent
.scheduled())
1218 template <class Impl
>
1220 FullO3CPU
<Impl
>::takeOverFrom(BaseCPU
*oldCPU
)
1222 // Flush out any old data from the time buffers.
1223 for (int i
= 0; i
< timeBuffer
.getSize(); ++i
) {
1224 timeBuffer
.advance();
1225 fetchQueue
.advance();
1226 decodeQueue
.advance();
1227 renameQueue
.advance();
1231 activityRec
.reset();
1233 BaseCPU::takeOverFrom(oldCPU
, &icachePort
, &dcachePort
);
1235 fetch
.takeOverFrom();
1236 decode
.takeOverFrom();
1237 rename
.takeOverFrom();
1239 commit
.takeOverFrom();
1241 assert(!tickEvent
.scheduled() || tickEvent
.squashed());
1243 // @todo: Figure out how to properly select the tid to put onto
1244 // the active threads list.
1247 list
<ThreadID
>::iterator isActive
=
1248 std::find(activeThreads
.begin(), activeThreads
.end(), tid
);
1250 if (isActive
== activeThreads
.end()) {
1251 //May Need to Re-code this if the delay variable is the delay
1252 //needed for thread to activate
1253 DPRINTF(O3CPU
, "Adding Thread %i to active threads list\n",
1256 activeThreads
.push_back(tid
);
1259 // Set all statuses to active, schedule the CPU's tick event.
1260 // @todo: Fix up statuses so this is handled properly
1261 ThreadID size
= threadContexts
.size();
1262 for (ThreadID i
= 0; i
< size
; ++i
) {
1263 ThreadContext
*tc
= threadContexts
[i
];
1264 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
1266 reschedule(tickEvent
, nextCycle(), true);
1269 if (!tickEvent
.scheduled())
1270 schedule(tickEvent
, nextCycle());
1272 lastRunningCycle
= curTick();
1275 template <class Impl
>
1277 FullO3CPU
<Impl
>::readMiscRegNoEffect(int misc_reg
, ThreadID tid
)
1279 return this->isa
[tid
].readMiscRegNoEffect(misc_reg
);
1282 template <class Impl
>
1284 FullO3CPU
<Impl
>::readMiscReg(int misc_reg
, ThreadID tid
)
1287 return this->isa
[tid
].readMiscReg(misc_reg
, tcBase(tid
));
1290 template <class Impl
>
1292 FullO3CPU
<Impl
>::setMiscRegNoEffect(int misc_reg
,
1293 const TheISA::MiscReg
&val
, ThreadID tid
)
1295 this->isa
[tid
].setMiscRegNoEffect(misc_reg
, val
);
1298 template <class Impl
>
1300 FullO3CPU
<Impl
>::setMiscReg(int misc_reg
,
1301 const TheISA::MiscReg
&val
, ThreadID tid
)
1303 miscRegfileWrites
++;
1304 this->isa
[tid
].setMiscReg(misc_reg
, val
, tcBase(tid
));
1307 template <class Impl
>
1309 FullO3CPU
<Impl
>::readIntReg(int reg_idx
)
1312 return regFile
.readIntReg(reg_idx
);
1315 template <class Impl
>
1317 FullO3CPU
<Impl
>::readFloatReg(int reg_idx
)
1320 return regFile
.readFloatReg(reg_idx
);
1323 template <class Impl
>
1325 FullO3CPU
<Impl
>::readFloatRegBits(int reg_idx
)
1328 return regFile
.readFloatRegBits(reg_idx
);
1331 template <class Impl
>
1333 FullO3CPU
<Impl
>::setIntReg(int reg_idx
, uint64_t val
)
1336 regFile
.setIntReg(reg_idx
, val
);
1339 template <class Impl
>
1341 FullO3CPU
<Impl
>::setFloatReg(int reg_idx
, FloatReg val
)
1344 regFile
.setFloatReg(reg_idx
, val
);
1347 template <class Impl
>
1349 FullO3CPU
<Impl
>::setFloatRegBits(int reg_idx
, FloatRegBits val
)
1352 regFile
.setFloatRegBits(reg_idx
, val
);
1355 template <class Impl
>
1357 FullO3CPU
<Impl
>::readArchIntReg(int reg_idx
, ThreadID tid
)
1360 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1362 return regFile
.readIntReg(phys_reg
);
1365 template <class Impl
>
1367 FullO3CPU
<Impl
>::readArchFloatReg(int reg_idx
, ThreadID tid
)
1370 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1371 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1373 return regFile
.readFloatReg(phys_reg
);
1376 template <class Impl
>
1378 FullO3CPU
<Impl
>::readArchFloatRegInt(int reg_idx
, ThreadID tid
)
1381 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1382 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1384 return regFile
.readFloatRegBits(phys_reg
);
1387 template <class Impl
>
1389 FullO3CPU
<Impl
>::setArchIntReg(int reg_idx
, uint64_t val
, ThreadID tid
)
1392 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(reg_idx
);
1394 regFile
.setIntReg(phys_reg
, val
);
1397 template <class Impl
>
1399 FullO3CPU
<Impl
>::setArchFloatReg(int reg_idx
, float val
, ThreadID tid
)
1402 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1403 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1405 regFile
.setFloatReg(phys_reg
, val
);
1408 template <class Impl
>
1410 FullO3CPU
<Impl
>::setArchFloatRegInt(int reg_idx
, uint64_t val
, ThreadID tid
)
1413 int idx
= reg_idx
+ TheISA::NumIntRegs
;
1414 PhysRegIndex phys_reg
= commitRenameMap
[tid
].lookup(idx
);
1416 regFile
.setFloatRegBits(phys_reg
, val
);
1419 template <class Impl
>
1421 FullO3CPU
<Impl
>::pcState(ThreadID tid
)
1423 return commit
.pcState(tid
);
1426 template <class Impl
>
1428 FullO3CPU
<Impl
>::pcState(const TheISA::PCState
&val
, ThreadID tid
)
1430 commit
.pcState(val
, tid
);
1433 template <class Impl
>
1435 FullO3CPU
<Impl
>::instAddr(ThreadID tid
)
1437 return commit
.instAddr(tid
);
1440 template <class Impl
>
1442 FullO3CPU
<Impl
>::nextInstAddr(ThreadID tid
)
1444 return commit
.nextInstAddr(tid
);
1447 template <class Impl
>
1449 FullO3CPU
<Impl
>::microPC(ThreadID tid
)
1451 return commit
.microPC(tid
);
1454 template <class Impl
>
1456 FullO3CPU
<Impl
>::squashFromTC(ThreadID tid
)
1458 this->thread
[tid
]->inSyscall
= true;
1459 this->commit
.generateTCEvent(tid
);
1462 template <class Impl
>
1463 typename FullO3CPU
<Impl
>::ListIt
1464 FullO3CPU
<Impl
>::addInst(DynInstPtr
&inst
)
1466 instList
.push_back(inst
);
1468 return --(instList
.end());
1471 template <class Impl
>
1473 FullO3CPU
<Impl
>::instDone(ThreadID tid
)
1475 // Keep an instruction count.
1476 thread
[tid
]->numInst
++;
1477 thread
[tid
]->numInsts
++;
1478 committedInsts
[tid
]++;
1479 totalCommittedInsts
++;
1480 system
->totalNumInsts
++;
1481 // Check for instruction-count-based events.
1482 comInstEventQueue
[tid
]->serviceEvents(thread
[tid
]->numInst
);
1483 system
->instEventQueue
.serviceEvents(system
->totalNumInsts
);
1486 template <class Impl
>
1488 FullO3CPU
<Impl
>::removeFrontInst(DynInstPtr
&inst
)
1490 DPRINTF(O3CPU
, "Removing committed instruction [tid:%i] PC %s "
1492 inst
->threadNumber
, inst
->pcState(), inst
->seqNum
);
1494 removeInstsThisCycle
= true;
1496 // Remove the front instruction.
1497 removeList
.push(inst
->getInstListIt());
1500 template <class Impl
>
1502 FullO3CPU
<Impl
>::removeInstsNotInROB(ThreadID tid
)
1504 DPRINTF(O3CPU
, "Thread %i: Deleting instructions from instruction"
1509 bool rob_empty
= false;
1511 if (instList
.empty()) {
1513 } else if (rob
.isEmpty(/*tid*/)) {
1514 DPRINTF(O3CPU
, "ROB is empty, squashing all insts.\n");
1515 end_it
= instList
.begin();
1518 end_it
= (rob
.readTailInst(tid
))->getInstListIt();
1519 DPRINTF(O3CPU
, "ROB is not empty, squashing insts not in ROB.\n");
1522 removeInstsThisCycle
= true;
1524 ListIt inst_it
= instList
.end();
1528 // Walk through the instruction list, removing any instructions
1529 // that were inserted after the given instruction iterator, end_it.
1530 while (inst_it
!= end_it
) {
1531 assert(!instList
.empty());
1533 squashInstIt(inst_it
, tid
);
1538 // If the ROB was empty, then we actually need to remove the first
1539 // instruction as well.
1541 squashInstIt(inst_it
, tid
);
1545 template <class Impl
>
1547 FullO3CPU
<Impl
>::removeInstsUntil(const InstSeqNum
&seq_num
, ThreadID tid
)
1549 assert(!instList
.empty());
1551 removeInstsThisCycle
= true;
1553 ListIt inst_iter
= instList
.end();
1557 DPRINTF(O3CPU
, "Deleting instructions from instruction "
1558 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1559 tid
, seq_num
, (*inst_iter
)->seqNum
);
1561 while ((*inst_iter
)->seqNum
> seq_num
) {
1563 bool break_loop
= (inst_iter
== instList
.begin());
1565 squashInstIt(inst_iter
, tid
);
1574 template <class Impl
>
1576 FullO3CPU
<Impl
>::squashInstIt(const ListIt
&instIt
, ThreadID tid
)
1578 if ((*instIt
)->threadNumber
== tid
) {
1579 DPRINTF(O3CPU
, "Squashing instruction, "
1580 "[tid:%i] [sn:%lli] PC %s\n",
1581 (*instIt
)->threadNumber
,
1583 (*instIt
)->pcState());
1585 // Mark it as squashed.
1586 (*instIt
)->setSquashed();
1588 // @todo: Formulate a consistent method for deleting
1589 // instructions from the instruction list
1590 // Remove the instruction from the list.
1591 removeList
.push(instIt
);
1595 template <class Impl
>
1597 FullO3CPU
<Impl
>::cleanUpRemovedInsts()
1599 while (!removeList
.empty()) {
1600 DPRINTF(O3CPU
, "Removing instruction, "
1601 "[tid:%i] [sn:%lli] PC %s\n",
1602 (*removeList
.front())->threadNumber
,
1603 (*removeList
.front())->seqNum
,
1604 (*removeList
.front())->pcState());
1606 instList
.erase(removeList
.front());
1611 removeInstsThisCycle
= false;
1614 template <class Impl>
1616 FullO3CPU<Impl>::removeAllInsts()
1621 template <class Impl
>
1623 FullO3CPU
<Impl
>::dumpInsts()
1627 ListIt inst_list_it
= instList
.begin();
1629 cprintf("Dumping Instruction List\n");
1631 while (inst_list_it
!= instList
.end()) {
1632 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1634 num
, (*inst_list_it
)->instAddr(), (*inst_list_it
)->threadNumber
,
1635 (*inst_list_it
)->seqNum
, (*inst_list_it
)->isIssued(),
1636 (*inst_list_it
)->isSquashed());
1642 template <class Impl>
1644 FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
1646 iew.wakeDependents(inst);
1649 template <class Impl
>
1651 FullO3CPU
<Impl
>::wakeCPU()
1653 if (activityRec
.active() || tickEvent
.scheduled()) {
1654 DPRINTF(Activity
, "CPU already running.\n");
1658 DPRINTF(Activity
, "Waking up CPU\n");
1660 idleCycles
+= tickToCycles((curTick() - 1) - lastRunningCycle
);
1661 numCycles
+= tickToCycles((curTick() - 1) - lastRunningCycle
);
1663 schedule(tickEvent
, nextCycle());
1667 template <class Impl
>
1669 FullO3CPU
<Impl
>::wakeup()
1671 if (this->thread
[0]->status() != ThreadContext::Suspended
)
1676 DPRINTF(Quiesce
, "Suspended Processor woken\n");
1677 this->threadContexts
[0]->activate();
1681 template <class Impl
>
1683 FullO3CPU
<Impl
>::getFreeTid()
1685 for (ThreadID tid
= 0; tid
< numThreads
; tid
++) {
1692 return InvalidThreadID
;
1695 template <class Impl
>
1697 FullO3CPU
<Impl
>::doContextSwitch()
1699 if (contextSwitch
) {
1701 //ADD CODE TO DEACTIVE THREAD HERE (???)
1703 ThreadID size
= cpuWaitList
.size();
1704 for (ThreadID tid
= 0; tid
< size
; tid
++) {
1705 activateWhenReady(tid
);
1708 if (cpuWaitList
.size() == 0)
1709 contextSwitch
= true;
1713 template <class Impl
>
1715 FullO3CPU
<Impl
>::updateThreadPriority()
1717 if (activeThreads
.size() > 1) {
1718 //DEFAULT TO ROUND ROBIN SCHEME
1719 //e.g. Move highest priority to end of thread list
1720 list
<ThreadID
>::iterator list_begin
= activeThreads
.begin();
1722 unsigned high_thread
= *list_begin
;
1724 activeThreads
.erase(list_begin
);
1726 activeThreads
.push_back(high_thread
);
1730 // Forward declaration of FullO3CPU.
1731 template class FullO3CPU
<O3CPUImpl
>;