2 * Copyright (c) 2007 MIPS Technologies, Inc.
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.
28 * Authors: Korey Sewell
32 #include "base/str.hh"
33 #include "config/the_isa.hh"
34 #include "cpu/inorder/cpu.hh"
35 #include "cpu/inorder/pipeline_stage.hh"
36 #include "cpu/inorder/resource_pool.hh"
37 #include "debug/Activity.hh"
38 #include "debug/InOrderStage.hh"
39 #include "debug/InOrderStall.hh"
40 #include "debug/Resource.hh"
41 #include "debug/ThreadModel.hh"
44 using namespace ThePipeline
;
46 PipelineStage::PipelineStage(Params
*params
, unsigned stage_num
)
47 : stageNum(stage_num
), stageWidth(params
->stageWidth
),
48 numThreads(ThePipeline::MaxThreads
), _status(Inactive
),
49 stageBufferMax(params
->stageWidth
),
50 prevStageValid(false), nextStageValid(false), idle(false)
55 PipelineStage::~PipelineStage()
57 for(ThreadID tid
= 0; tid
< numThreads
; tid
++) {
58 skidBuffer
[tid
].clear();
59 stalls
[tid
].resources
.clear();
64 PipelineStage::init(Params
*params
)
66 for(ThreadID tid
= 0; tid
< numThreads
; tid
++) {
67 stageStatus
[tid
] = Idle
;
69 for (int stNum
= 0; stNum
< NumStages
; stNum
++) {
70 stalls
[tid
].stage
[stNum
] = false;
72 stalls
[tid
].resources
.clear();
74 if (stageNum
< BackEndStartStage
)
75 lastStallingStage
[tid
] = BackEndStartStage
- 1;
77 lastStallingStage
[tid
] = NumStages
- 1;
80 if ((InOrderCPU::ThreadModel
) params
->threadModel
==
81 InOrderCPU::SwitchOnCacheMiss
) {
82 switchedOutBuffer
.resize(ThePipeline::MaxThreads
);
83 switchedOutValid
.resize(ThePipeline::MaxThreads
);
89 PipelineStage::name() const
91 return cpu
->name() + ".stage" + to_string(stageNum
);
96 PipelineStage::regStats()
99 .name(name() + ".idleCycles")
100 .desc("Number of cycles 0 instructions are processed.");
103 .name(name() + ".runCycles")
104 .desc("Number of cycles 1+ instructions are processed.");
107 .name(name() + ".utilization")
108 .desc("Percentage of cycles stage was utilized (processing insts).")
110 utilization
= (runCycles
/ cpu
->numCycles
) * 100;
116 PipelineStage::setCPU(InOrderCPU
*cpu_ptr
)
120 DPRINTF(InOrderStage
, "Set CPU pointer.\n");
122 tracer
= dynamic_cast<Trace::InOrderTrace
*>(cpu
->getTracer());
127 PipelineStage::setTimeBuffer(TimeBuffer
<TimeStruct
> *tb_ptr
)
129 DPRINTF(InOrderStage
, "Setting time buffer pointer.\n");
132 // Setup wire to write information back to fetch.
133 // @todo: should this be writing to the next stage => -1 and reading from is (0)???
134 toPrevStages
= timeBuffer
->getWire(0);
136 // Create wires to get information from proper places in time buffer.
137 fromNextStages
= timeBuffer
->getWire(-1);
142 PipelineStage::setPrevStageQueue(TimeBuffer
<InterStageStruct
> *prev_stage_ptr
)
144 DPRINTF(InOrderStage
, "Setting previous stage queue pointer.\n");
145 prevStageQueue
= prev_stage_ptr
;
147 // Setup wire to read information from fetch queue.
148 prevStage
= prevStageQueue
->getWire(-1);
150 prevStageValid
= true;
156 PipelineStage::setNextStageQueue(TimeBuffer
<InterStageStruct
> *next_stage_ptr
)
158 DPRINTF(InOrderStage
, "Setting next stage pointer.\n");
159 nextStageQueue
= next_stage_ptr
;
161 // Setup wire to write information to proper place in stage queue.
162 nextStage
= nextStageQueue
->getWire(0);
163 nextStageValid
= true;
169 PipelineStage::setActiveThreads(list
<ThreadID
> *at_ptr
)
171 DPRINTF(InOrderStage
, "Setting active threads list pointer.\n");
172 activeThreads
= at_ptr
;
176 PipelineStage::switchToActive()
178 if (_status == Inactive) {
179 DPRINTF(Activity, "Activating stage.\n");
181 cpu->activateStage(stageNum);
188 PipelineStage::switchOut()
190 // Stage can immediately switch out.
191 panic("Switching Out of Stages Unimplemented");
196 PipelineStage::takeOverFrom()
200 // Be sure to reset state and clear out any old instructions.
201 for (ThreadID tid
= 0; tid
< numThreads
; ++tid
) {
202 stageStatus
[tid
] = Idle
;
204 for (int stNum
= 0; stNum
< NumStages
; stNum
++) {
205 stalls
[tid
].stage
[stNum
] = false;
208 stalls
[tid
].resources
.clear();
210 skidBuffer
[tid
].clear();
212 wroteToTimeBuffer
= false;
218 PipelineStage::checkStall(ThreadID tid
) const
220 bool ret_val
= false;
222 // Only check pipeline stall from stage directly following this stage
223 if (nextStageValid
&& stalls
[tid
].stage
[stageNum
+ 1]) {
224 DPRINTF(InOrderStage
,"[tid:%i]: Stall fom Stage %i detected.\n",
229 if (!stalls
[tid
].resources
.empty()) {
233 for (int i
=0; i
< stalls
[tid
].resources
.size(); i
++) {
234 stall_src
+= stalls
[tid
].resources
[i
]->res
->name() + ":";
237 DPRINTF(InOrderStage
,"[tid:%i]: Stall fom resources (%s) detected.\n",
248 PipelineStage::removeStalls(ThreadID tid
)
250 for (int st_num
= 0; st_num
< NumStages
; st_num
++) {
251 if (stalls
[tid
].stage
[st_num
] == true) {
252 DPRINTF(InOrderStage
, "Removing stall from stage %i.\n",
254 stalls
[tid
].stage
[st_num
] = false;
257 if (toPrevStages
->stageBlock
[st_num
][tid
] == true) {
258 DPRINTF(InOrderStage
, "Removing pending block from stage %i.\n",
260 toPrevStages
->stageBlock
[st_num
][tid
] = false;
263 if (fromNextStages
->stageBlock
[st_num
][tid
] == true) {
264 DPRINTF(InOrderStage
, "Removing pending block from stage %i.\n",
266 fromNextStages
->stageBlock
[st_num
][tid
] = false;
269 stalls
[tid
].resources
.clear();
273 PipelineStage::prevStageInstsValid()
275 return prevStage
->insts
.size() > 0;
279 PipelineStage::isBlocked(ThreadID tid
)
281 return stageStatus
[tid
] == Blocked
;
285 PipelineStage::block(ThreadID tid
)
287 DPRINTF(InOrderStage
, "[tid:%d]: Blocking, sending block signal back to "
288 "previous stages.\n", tid
);
290 // If the stage status is blocked or unblocking then stage has not yet
291 // signalled fetch to unblock. In that case, there is no need to tell
293 if (stageStatus
[tid
] != Blocked
) {
294 if (stageStatus
[tid
] != Unblocking
) {
295 wroteToTimeBuffer
= true;
298 stageStatus
[tid
] = Blocked
;
300 if (prevStageValid
) {
301 DPRINTF(InOrderStage
, "[tid:%d]: Stage %i setting block signal.\n",
303 toPrevStages
->stageBlock
[stageNum
][tid
] = true;
314 PipelineStage::blockDueToBuffer(ThreadID tid
)
316 DPRINTF(InOrderStage
, "[tid:%d]: Blocking instructions from passing to "
317 "next stage.\n", tid
);
319 if (stageStatus
[tid
] != Blocked
) {
320 if (stageStatus
[tid
] != Unblocking
) {
321 wroteToTimeBuffer
= true;
324 // Set the status to Blocked.
325 stageStatus
[tid
] = Blocked
;
330 PipelineStage::unblock(ThreadID tid
)
332 // @todo: Shouldnt this be if any available slots are open???
333 // Stage is done unblocking only if the skid buffer is empty.
334 if (skidBuffer
[tid
].empty()) {
335 DPRINTF(InOrderStage
, "[tid:%u]: Done unblocking.\n", tid
);
338 toPrevStages
->stageUnblock
[stageNum
][tid
] = true;
340 wroteToTimeBuffer
= true;
342 stageStatus
[tid
] = Running
;
347 DPRINTF(InOrderStage
, "[tid:%u]: Currently unblocking.\n", tid
);
352 PipelineStage::setupSquash(DynInstPtr inst
, ThreadID tid
)
354 if (cpu
->lastSquashCycle
[tid
] == curTick() &&
355 cpu
->squashSeqNum
[tid
] < inst
->seqNum
){
356 DPRINTF(Resource
, "Ignoring [sn:%i] branch squash signal due to "
357 "another stage's squash signal for after [sn:%i].\n",
358 inst
->seqNum
, cpu
->squashSeqNum
[tid
]);
360 InstSeqNum squash_seq_num
= inst
->squashSeqNum
;
361 unsigned squash_stage
= (nextStageValid
) ? stageNum
+ 1
364 toPrevStages
->stageInfo
[squash_stage
][tid
].squash
= true;
365 toPrevStages
->stageInfo
[squash_stage
][tid
].doneSeqNum
=
368 DPRINTF(InOrderStage
, "[tid:%i]: Setting up squashing after "
369 "[sn:%i], due to [sn:%i] %s. Squash-Start-Stage:%i\n",
370 tid
, squash_seq_num
, inst
->seqNum
, inst
->instName(),
373 // Save squash num for later stage use
374 cpu
->lastSquashCycle
[tid
] = curTick();
375 cpu
->squashSeqNum
[tid
] = squash_seq_num
;
380 PipelineStage::squashDueToMemStall(InstSeqNum seq_num
, ThreadID tid
)
382 squash(seq_num
, tid
);
386 PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num
, ThreadID tid
)
388 DPRINTF(InOrderStage
, "[tid:%i]: Removing instructions from "
389 "incoming stage queue.\n", tid
);
391 int insts_from_prev_stage
= prevStage
->insts
.size();
392 for (int i
=0; i
< insts_from_prev_stage
; i
++) {
393 if (prevStage
->insts
[i
]->threadNumber
== tid
&&
394 prevStage
->insts
[i
]->seqNum
> squash_seq_num
) {
395 DPRINTF(InOrderStage
, "[tid:%i]: Squashing instruction, "
398 prevStage
->insts
[i
]->seqNum
,
399 prevStage
->insts
[i
]->pcState());
400 prevStage
->insts
[i
]->setSquashed();
402 prevStage
->insts
[i
] = cpu
->dummyBufferInst
;
408 PipelineStage::squash(InstSeqNum squash_seq_num
, ThreadID tid
)
410 // Set status to squashing.
411 stageStatus
[tid
] = Squashing
;
413 squashPrevStageInsts(squash_seq_num
, tid
);
415 DPRINTF(InOrderStage
, "[tid:%i]: Removing instructions from incoming stage"
416 " skidbuffer.\n", tid
);
417 //@TODO: Walk Through List Using iterator and remove
418 // all instructions over the value
419 std::list
<DynInstPtr
>::iterator cur_it
= skidBuffer
[tid
].begin();
420 std::list
<DynInstPtr
>::iterator end_it
= skidBuffer
[tid
].end();
422 while (cur_it
!= end_it
) {
423 if ((*cur_it
)->seqNum
<= squash_seq_num
) {
424 DPRINTF(InOrderStage
, "[tid:%i]: Cannot remove skidBuffer "
425 "instructions (starting w/[sn:%i]) before "
426 "[sn:%i]. %i insts left.\n", tid
,
427 (*cur_it
)->seqNum
, squash_seq_num
,
428 skidBuffer
[tid
].size());
431 DPRINTF(InOrderStage
, "[tid:%i]: Removing instruction, [sn:%i] "
432 " PC %s.\n", tid
, (*cur_it
)->seqNum
, (*cur_it
)->pc
);
433 (*cur_it
)->setSquashed();
434 cur_it
= skidBuffer
[tid
].erase(cur_it
);
442 PipelineStage::stageBufferAvail()
446 for (int i
=0; i
< ThePipeline::MaxThreads
; i
++) {
447 total
+= skidBuffer
[i
].size();
450 int avail
= stageBufferMax
- total
;
457 PipelineStage::canSendInstToStage(unsigned stage_num
)
459 bool buffer_avail
= false;
461 if (cpu
->pipelineStage
[stage_num
]->prevStageValid
) {
462 buffer_avail
= cpu
->pipelineStage
[stage_num
]->stageBufferAvail() -
463 cpu
->pipelineStage
[stage_num
-1]->nextStage
->insts
.size() >= 1;
466 if (!buffer_avail
&& nextStageQueueValid(stage_num
)) {
467 DPRINTF(InOrderStall
, "STALL: No room in stage %i buffer.\n",
475 PipelineStage::skidSize()
479 for (int i
=0; i
< ThePipeline::MaxThreads
; i
++) {
480 total
+= skidBuffer
[i
].size();
487 PipelineStage::skidsEmpty()
489 list
<ThreadID
>::iterator threads
= activeThreads
->begin();
491 while (threads
!= activeThreads
->end()) {
492 if (!skidBuffer
[*threads
++].empty())
502 PipelineStage::updateStatus()
504 bool any_unblocking
= false;
506 list
<ThreadID
>::iterator threads
= activeThreads
->begin();
508 while (threads
!= activeThreads
->end()) {
509 ThreadID tid
= *threads
++;
511 if (stageStatus
[tid
] == Unblocking
) {
512 any_unblocking
= true;
517 // Stage will have activity if it's unblocking.
518 if (any_unblocking
) {
519 if (_status
== Inactive
) {
522 DPRINTF(Activity
, "Activating stage.\n");
524 cpu
->activateStage(stageNum
);
527 // If it's not unblocking, then stage will not have any internal
528 // activity. Switch it to inactive.
529 if (_status
== Active
) {
531 DPRINTF(Activity
, "Deactivating stage.\n");
533 cpu
->deactivateStage(stageNum
);
539 PipelineStage::activateThread(ThreadID tid
)
541 if (cpu
->threadModel
== InOrderCPU::SwitchOnCacheMiss
) {
542 if (!switchedOutValid
[tid
]) {
543 DPRINTF(InOrderStage
, "[tid:%i] No instruction available in "
544 "switch out buffer.\n", tid
);
546 DynInstPtr inst
= switchedOutBuffer
[tid
];
548 DPRINTF(InOrderStage
,"[tid:%i]: Re-Inserting [sn:%lli] PC:%s into"
549 " stage skidBuffer %i\n", tid
, inst
->seqNum
,
550 inst
->pcState(), inst
->threadNumber
);
552 // Make instruction available for pipeline processing
553 skidBuffer
[tid
].push_back(inst
);
555 // Update PC so that we start fetching after this instruction to
556 // prevent "double"-execution of instructions
557 cpu
->resPool
->scheduleEvent((InOrderCPU::CPUEventType
)
558 ResourcePool::UpdateAfterContextSwitch
,
561 // Clear switchout buffer
562 switchedOutBuffer
[tid
] = NULL
;
563 switchedOutValid
[tid
] = false;
565 // Update any CPU stats based off context switches
566 cpu
->updateContextSwitchStats();
574 PipelineStage::sortInsts()
576 if (prevStageValid
) {
577 assert(prevStage
->insts
.size() <= stageWidth
);
579 int insts_from_prev_stage
= prevStage
->insts
.size();
580 int insts_from_cur_stage
= skidSize();
581 DPRINTF(InOrderStage
, "%i insts available from stage buffer %i. Stage "
582 "currently has %i insts from last cycle.\n",
583 insts_from_prev_stage
, prevStageQueue
->id(),
584 insts_from_cur_stage
);
586 int inserted_insts
= 0;
588 for (int i
= 0; i
< insts_from_prev_stage
; i
++) {
589 if (prevStage
->insts
[i
]->isSquashed()) {
590 DPRINTF(InOrderStage
, "[tid:%i]: Ignoring squashed [sn:%i], "
591 "not inserting into stage buffer.\n",
592 prevStage
->insts
[i
]->readTid(),
593 prevStage
->insts
[i
]->seqNum
);
597 ThreadID tid
= prevStage
->insts
[i
]->threadNumber
;
599 if (inserted_insts
+ insts_from_cur_stage
== stageWidth
) {
600 DPRINTF(InOrderStage
, "Stage %i has accepted all insts "
601 "possible for this tick. Placing [sn:%i] in stage %i skidBuffer\n",
602 stageNum
, prevStage
->insts
[i
]->seqNum
, stageNum
- 1);
603 cpu
->pipelineStage
[stageNum
- 1]->
604 skidBuffer
[tid
].push_front(prevStage
->insts
[i
]);
606 int prev_stage
= stageNum
- 1;
607 if (cpu
->pipelineStage
[prev_stage
]->stageStatus
[tid
] == Running
||
608 cpu
->pipelineStage
[prev_stage
]->stageStatus
[tid
] == Idle
) {
609 cpu
->pipelineStage
[prev_stage
]->stageStatus
[tid
] = Unblocking
;
612 DPRINTF(InOrderStage
, "[tid:%i]: Inserting [sn:%i] into stage "
613 "buffer.\n", prevStage
->insts
[i
]->readTid(),
614 prevStage
->insts
[i
]->seqNum
);
616 skidBuffer
[tid
].push_back(prevStage
->insts
[i
]);
619 prevStage
->insts
[i
] = cpu
->dummyBufferInst
;
629 PipelineStage::readStallSignals(ThreadID tid
)
631 for (int stage_idx
= stageNum
+1; stage_idx
<= lastStallingStage
[tid
];
634 DPRINTF(InOrderStage
, "[tid:%i] Reading stall signals from Stage "
635 "%i. Block:%i Unblock:%i.\n",
638 fromNextStages
->stageBlock
[stage_idx
][tid
],
639 fromNextStages
->stageUnblock
[stage_idx
][tid
]);
641 // Check for Stage Blocking Signal
642 if (fromNextStages
->stageBlock
[stage_idx
][tid
]) {
643 DPRINTF(InOrderStage
, "[tid:%i] Stall from stage %i set.\n", tid
,
645 stalls
[tid
].stage
[stage_idx
] = true;
648 // Check for Stage Unblocking Signal
649 if (fromNextStages
->stageUnblock
[stage_idx
][tid
]) {
650 DPRINTF(InOrderStage
, "[tid:%i] Stall from stage %i unset.\n", tid
,
652 stalls
[tid
].stage
[stage_idx
] = false;
660 PipelineStage::checkSignalsAndUpdate(ThreadID tid
)
662 // Check if there's a squash signal, squash if there is.
663 // Check stall signals, block if necessary.
664 // If status was blocked
665 // Check if stall conditions have passed
666 // if so then go to unblocking
667 // If status was Squashing
668 // check if squashing is not high. Switch to running this cycle.
670 // Update the per thread stall statuses.
671 readStallSignals(tid
);
673 // Check for squash from later pipeline stages
674 for (int stage_idx
=stageNum
; stage_idx
< NumStages
; stage_idx
++) {
675 if (fromNextStages
->stageInfo
[stage_idx
][tid
].squash
) {
676 DPRINTF(InOrderStage
, "[tid:%u]: Squashing instructions due to "
677 "squash from stage %u.\n", tid
, stage_idx
);
678 InstSeqNum squash_seq_num
= fromNextStages
->
679 stageInfo
[stage_idx
][tid
].doneSeqNum
;
680 squash(squash_seq_num
, tid
);
681 break; //return true;
685 if (checkStall(tid
)) {
689 if (stageStatus
[tid
] == Blocked
) {
690 DPRINTF(InOrderStage
, "[tid:%u]: Done blocking, switching to "
691 "unblocking.\n", tid
);
693 stageStatus
[tid
] = Unblocking
;
700 if (stageStatus
[tid
] == Squashing
) {
701 if (!skidBuffer
[tid
].empty()) {
702 DPRINTF(InOrderStage
, "[tid:%u]: Done squashing, switching to "
703 "unblocking.\n", tid
);
705 stageStatus
[tid
] = Unblocking
;
707 // Switch status to running if stage isn't being told to block or
708 // squash this cycle.
709 DPRINTF(InOrderStage
, "[tid:%u]: Done squashing, switching to "
712 stageStatus
[tid
] = Running
;
718 // If we've reached this point, we have not gotten any signals that
719 // cause stage to change its status. Stage remains the same as before.*/
726 PipelineStage::tick()
730 wroteToTimeBuffer
= false;
732 bool status_change
= false;
738 processStage(status_change
);
744 if (wroteToTimeBuffer
) {
745 DPRINTF(Activity
, "Activity this cycle.\n");
746 cpu
->activityThisCycle();
749 DPRINTF(InOrderStage
, "\n\n");
753 PipelineStage::setResStall(ResReqPtr res_req
, ThreadID tid
)
755 DPRINTF(InOrderStage
, "Inserting stall from %s.\n", res_req
->res
->name());
756 stalls
[tid
].resources
.push_back(res_req
);
760 PipelineStage::unsetResStall(ResReqPtr res_req
, ThreadID tid
)
762 // Search through stalls to find stalling request and then
764 vector
<ResReqPtr
>::iterator req_it
= stalls
[tid
].resources
.begin();
765 vector
<ResReqPtr
>::iterator req_end
= stalls
[tid
].resources
.end();
767 while (req_it
!= req_end
) {
768 if( (*req_it
)->res
== res_req
->res
&& // Same Resource
769 (*req_it
)->inst
== res_req
->inst
&& // Same Instruction
770 (*req_it
)->getSlot() == res_req
->getSlot()) {
771 DPRINTF(InOrderStage
, "[tid:%u]: Clearing stall by %s.\n",
772 tid
, res_req
->res
->name());
773 stalls
[tid
].resources
.erase(req_it
);
780 if (stalls
[tid
].resources
.size() == 0) {
781 DPRINTF(InOrderStage
, "[tid:%u]: There are no remaining resource"
786 // @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be
787 // handled one at a time, but instead first come first serve by instruction?
788 // Questions are how should a pipeline stage handle thread-specific stalls &
791 PipelineStage::processStage(bool &status_change
)
793 list
<ThreadID
>::iterator threads
= activeThreads
->begin();
795 //Check stall and squash signals.
796 while (threads
!= activeThreads
->end()) {
797 ThreadID tid
= *threads
++;
799 DPRINTF(InOrderStage
,"Processing [tid:%i]\n",tid
);
800 status_change
= checkSignalsAndUpdate(tid
) || status_change
;
802 processThread(status_change
, tid
);
805 if (nextStageValid
) {
806 DPRINTF(InOrderStage
, "%i insts now available for stage %i.\n",
807 nextStage
->insts
.size(), stageNum
+ 1);
810 if (instsProcessed
> 0) {
818 DPRINTF(InOrderStage
, "%i left in stage %i incoming buffer.\n", skidSize(),
821 DPRINTF(InOrderStage
, "%i available in stage %i incoming buffer.\n",
822 stageBufferAvail(), stageNum
);
826 PipelineStage::processThread(bool &status_change
, ThreadID tid
)
828 // If status is Running or idle,
829 // call processInsts()
830 // If status is Unblocking,
831 // buffer any instructions coming from fetch
832 // continue trying to empty skid buffer
833 // check if stall conditions have passed
835 // Stage should try to process as many instructions as its bandwidth
836 // will allow, as long as it is not currently blocked.
837 if (stageStatus
[tid
] == Running
||
838 stageStatus
[tid
] == Idle
) {
839 DPRINTF(InOrderStage
, "[tid:%u]: Not blocked, so attempting to run "
843 } else if (stageStatus
[tid
] == Unblocking
) {
844 // Make sure that the skid buffer has something in it if the
845 // status is unblocking.
846 assert(!skidsEmpty());
848 // If the status was unblocking, then instructions from the skid
849 // buffer were used. Remove those instructions and handle
850 // the rest of unblocking.
853 status_change
= unblock(tid
) || status_change
;
859 PipelineStage::processInsts(ThreadID tid
)
861 // Instructions can come either from the skid buffer or the list of
862 // instructions coming from fetch, depending on stage's status.
863 int insts_available
= skidBuffer
[tid
].size();
865 std::list
<DynInstPtr
> &insts_to_stage
= skidBuffer
[tid
];
867 if (insts_available
== 0) {
868 DPRINTF(InOrderStage
, "[tid:%u]: Nothing to do, breaking out"
874 bool last_req_completed
= true;
876 while (insts_available
> 0 &&
877 instsProcessed
< stageWidth
&&
878 last_req_completed
) {
879 assert(!insts_to_stage
.empty());
881 inst
= insts_to_stage
.front();
883 DPRINTF(InOrderStage
, "[tid:%u]: Processing instruction [sn:%lli] "
884 "%s with PC %s\n", tid
, inst
->seqNum
,
888 if (inst
->isSquashed()) {
889 DPRINTF(InOrderStage
, "[tid:%u]: Instruction %i with PC %s is "
890 "squashed, skipping.\n",
891 tid
, inst
->seqNum
, inst
->pcState());
893 insts_to_stage
.pop_front();
900 int reqs_processed
= 0;
901 last_req_completed
= processInstSchedule(inst
, reqs_processed
);
903 // If the instruction isnt squashed & we've completed one request
904 // Then we can officially count this instruction toward the stage's
906 if (reqs_processed
> 0)
909 // Don't let instruction pass to next stage if it hasnt completed
910 // all of it's requests for this stage.
911 if (!last_req_completed
)
914 // Send to Next Stage or Break Loop
915 if (nextStageValid
&& !sendInstToNextStage(inst
)) {
916 DPRINTF(InOrderStage
, "[tid:%i] [sn:%i] unable to proceed to stage"
917 " %i.\n", tid
, inst
->seqNum
,inst
->nextStage
);
921 insts_to_stage
.pop_front();
926 // If we didn't process all instructions, then we will need to block
927 // and put all those instructions into the skid buffer.
928 if (!insts_to_stage
.empty()) {
929 blockDueToBuffer(tid
);
932 // Record that stage has written to the time buffer for activity
934 if (instsProcessed
) {
935 wroteToTimeBuffer
= true;
940 PipelineStage::processInstSchedule(DynInstPtr inst
,int &reqs_processed
)
942 bool last_req_completed
= true;
943 ThreadID tid
= inst
->readTid();
945 if (inst
->nextResStage() == stageNum
) {
946 int res_stage_num
= inst
->nextResStage();
948 while (res_stage_num
== stageNum
) {
949 int res_num
= inst
->nextResource();
952 DPRINTF(InOrderStage
, "[tid:%i]: [sn:%i]: sending request to %s."
953 "\n", tid
, inst
->seqNum
, cpu
->resPool
->name(res_num
));
955 ResReqPtr req
= cpu
->resPool
->request(res_num
, inst
);
958 bool req_completed
= req
->isCompleted();
959 bool done_in_pipeline
= false;
961 DPRINTF(InOrderStage
, "[tid:%i]: [sn:%i] request to %s "
962 "completed.\n", tid
, inst
->seqNum
,
963 cpu
->resPool
->name(res_num
));
969 done_in_pipeline
= inst
->finishSkedEntry();
970 if (done_in_pipeline
) {
971 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] finished "
972 "in pipeline.\n", tid
, inst
->seqNum
);
975 DPRINTF(InOrderStage
, "[tid:%i]: [sn:%i] request to %s failed."
976 "\n", tid
, inst
->seqNum
, cpu
->resPool
->name(res_num
));
978 last_req_completed
= false;
980 if (req
->isMemStall() &&
981 cpu
->threadModel
== InOrderCPU::SwitchOnCacheMiss
) {
982 // Save Stalling Instruction
983 DPRINTF(ThreadModel
, "[tid:%i] [sn:%i] Detected cache "
984 "miss.\n", tid
, inst
->seqNum
);
986 DPRINTF(InOrderStage
, "Inserting [tid:%i][sn:%i] into "
987 "switch out buffer.\n", tid
, inst
->seqNum
);
989 switchedOutBuffer
[tid
] = inst
;
990 switchedOutValid
[tid
] = true;
992 // Remove Thread From Pipeline & Resource Pool
993 inst
->squashingStage
= stageNum
;
994 inst
->squashSeqNum
= inst
->seqNum
;
995 cpu
->squashFromMemStall(inst
, tid
);
997 // Switch On Cache Miss
998 //=====================
999 // Suspend Thread at end of cycle
1000 DPRINTF(ThreadModel
, "Suspending [tid:%i] due to cache "
1002 cpu
->suspendContext(tid
);
1004 // Activate Next Ready Thread at end of cycle
1005 DPRINTF(ThreadModel
, "Attempting to activate next ready "
1006 "thread due to cache miss.\n");
1007 cpu
->activateNextReadyContext();
1011 // If this request is no longer needs to take up bandwidth in the
1012 // resource, go ahead and free that bandwidth up
1013 if (req
->doneInResource
) {
1017 // No longer need to process this instruction if the last
1018 // request it had wasn't completed or if there is nothing
1019 // else for it to do in the pipeline
1020 if (done_in_pipeline
|| !req_completed
) {
1024 res_stage_num
= inst
->nextResStage();
1027 DPRINTF(InOrderStage
, "[tid:%u]: Instruction [sn:%i] with PC %s "
1028 " needed no resources in stage %i.\n",
1029 tid
, inst
->seqNum
, inst
->pcState(), stageNum
);
1032 return last_req_completed
;
1036 PipelineStage::nextStageQueueValid(int stage_num
)
1038 return cpu
->pipelineStage
[stage_num
]->nextStageValid
;
1043 PipelineStage::sendInstToNextStage(DynInstPtr inst
)
1045 // Update Next Stage Variable in Instruction
1046 // NOTE: Some Resources will update this nextStage var. to
1047 // for bypassing, so can't always assume nextStage=stageNum+1
1048 if (inst
->nextStage
== stageNum
)
1051 bool success
= false;
1052 ThreadID tid
= inst
->readTid();
1053 int next_stage
= inst
->nextStage
;
1054 int prev_stage
= next_stage
- 1;
1056 assert(next_stage
>= 1);
1057 assert(prev_stage
>= 0);
1059 DPRINTF(InOrderStage
, "[tid:%u]: Attempting to send instructions to "
1060 "stage %u.\n", tid
, stageNum
+1);
1062 if (!canSendInstToStage(inst
->nextStage
)) {
1063 DPRINTF(InOrderStage
, "[tid:%u]: Could not send instruction to "
1064 "stage %u.\n", tid
, stageNum
+1);
1069 if (nextStageQueueValid(inst
->nextStage
- 1)) {
1070 if (inst
->seqNum
> cpu
->squashSeqNum
[tid
] &&
1071 curTick() == cpu
->lastSquashCycle
[tid
]) {
1072 DPRINTF(InOrderStage
, "[tid:%u]: [sn:%i]: squashed, skipping "
1073 "insertion into stage %i queue.\n", tid
, inst
->seqNum
,
1076 if (nextStageValid
) {
1077 DPRINTF(InOrderStage
, "[tid:%u] %i slots available in next "
1078 "stage buffer.\n", tid
,
1079 cpu
->pipelineStage
[next_stage
]->stageBufferAvail());
1082 DPRINTF(InOrderStage
, "[tid:%u]: [sn:%i]: being placed into "
1083 "index %i of stage buffer %i queue.\n",
1085 cpu
->pipelineStage
[prev_stage
]->nextStage
->insts
.size(),
1086 cpu
->pipelineStage
[prev_stage
]->nextStageQueue
->id());
1088 // Place instructions in inter-stage communication struct for next
1089 // pipeline stage to read next cycle
1090 cpu
->pipelineStage
[prev_stage
]->nextStage
->insts
.push_back(inst
);
1094 // Take note of trace data for this inst & stage
1095 if (inst
->traceData
) {
1096 //@todo: exec traces are broke. fix them
1097 inst
->traceData
->setStageCycle(stageNum
, curTick());
1107 PipelineStage::dumpInsts()
1109 cprintf("Insts in Stage %i skidbuffers\n",stageNum
);
1111 for (ThreadID tid
= 0; tid
< ThePipeline::MaxThreads
; tid
++) {
1112 std::list
<DynInstPtr
>::iterator cur_it
= skidBuffer
[tid
].begin();
1113 std::list
<DynInstPtr
>::iterator end_it
= skidBuffer
[tid
].end();
1115 while (cur_it
!= end_it
) {
1116 DynInstPtr inst
= (*cur_it
);
1118 cprintf("Inst. PC:%s\n[tid:%i]\n[sn:%i]\n\n",
1119 inst
->pcState(), inst
->threadNumber
, inst
->seqNum
);