style: eliminate equality tests with true and false
[gem5.git] / src / cpu / inorder / pipeline_stage.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Korey Sewell
29 *
30 */
31
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"
42
43 using namespace std;
44 using namespace ThePipeline;
45
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)
51 {
52 init(params);
53 }
54
55 PipelineStage::~PipelineStage()
56 {
57 for(ThreadID tid = 0; tid < numThreads; tid++) {
58 skidBuffer[tid].clear();
59 stalls[tid].resources.clear();
60 }
61 }
62
63 void
64 PipelineStage::init(Params *params)
65 {
66 for(ThreadID tid = 0; tid < numThreads; tid++) {
67 stageStatus[tid] = Idle;
68
69 for (int stNum = 0; stNum < NumStages; stNum++) {
70 stalls[tid].stage[stNum] = false;
71 }
72 stalls[tid].resources.clear();
73
74 if (stageNum < BackEndStartStage)
75 lastStallingStage[tid] = BackEndStartStage - 1;
76 else
77 lastStallingStage[tid] = NumStages - 1;
78 }
79
80 if ((InOrderCPU::ThreadModel) params->threadModel ==
81 InOrderCPU::SwitchOnCacheMiss) {
82 switchedOutBuffer.resize(ThePipeline::MaxThreads);
83 switchedOutValid.resize(ThePipeline::MaxThreads);
84 }
85 }
86
87
88 std::string
89 PipelineStage::name() const
90 {
91 return cpu->name() + ".stage" + to_string(stageNum);
92 }
93
94
95 void
96 PipelineStage::regStats()
97 {
98 idleCycles
99 .name(name() + ".idleCycles")
100 .desc("Number of cycles 0 instructions are processed.");
101
102 runCycles
103 .name(name() + ".runCycles")
104 .desc("Number of cycles 1+ instructions are processed.");
105
106 utilization
107 .name(name() + ".utilization")
108 .desc("Percentage of cycles stage was utilized (processing insts).")
109 .precision(6);
110 utilization = (runCycles / cpu->numCycles) * 100;
111
112 }
113
114
115 void
116 PipelineStage::setCPU(InOrderCPU *cpu_ptr)
117 {
118 cpu = cpu_ptr;
119
120 DPRINTF(InOrderStage, "Set CPU pointer.\n");
121
122 tracer = dynamic_cast<Trace::InOrderTrace *>(cpu->getTracer());
123 }
124
125
126 void
127 PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
128 {
129 DPRINTF(InOrderStage, "Setting time buffer pointer.\n");
130 timeBuffer = tb_ptr;
131
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);
135
136 // Create wires to get information from proper places in time buffer.
137 fromNextStages = timeBuffer->getWire(-1);
138 }
139
140
141 void
142 PipelineStage::setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr)
143 {
144 DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n");
145 prevStageQueue = prev_stage_ptr;
146
147 // Setup wire to read information from fetch queue.
148 prevStage = prevStageQueue->getWire(-1);
149
150 prevStageValid = true;
151 }
152
153
154
155 void
156 PipelineStage::setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr)
157 {
158 DPRINTF(InOrderStage, "Setting next stage pointer.\n");
159 nextStageQueue = next_stage_ptr;
160
161 // Setup wire to write information to proper place in stage queue.
162 nextStage = nextStageQueue->getWire(0);
163 nextStageValid = true;
164 }
165
166
167
168 void
169 PipelineStage::setActiveThreads(list<ThreadID> *at_ptr)
170 {
171 DPRINTF(InOrderStage, "Setting active threads list pointer.\n");
172 activeThreads = at_ptr;
173 }
174
175 /*inline void
176 PipelineStage::switchToActive()
177 {
178 if (_status == Inactive) {
179 DPRINTF(Activity, "Activating stage.\n");
180
181 cpu->activateStage(stageNum);
182
183 _status = Active;
184 }
185 }*/
186
187 void
188 PipelineStage::switchOut()
189 {
190 // Stage can immediately switch out.
191 panic("Switching Out of Stages Unimplemented");
192 }
193
194
195 void
196 PipelineStage::takeOverFrom()
197 {
198 _status = Inactive;
199
200 // Be sure to reset state and clear out any old instructions.
201 for (ThreadID tid = 0; tid < numThreads; ++tid) {
202 stageStatus[tid] = Idle;
203
204 for (int stNum = 0; stNum < NumStages; stNum++) {
205 stalls[tid].stage[stNum] = false;
206 }
207
208 stalls[tid].resources.clear();
209
210 skidBuffer[tid].clear();
211 }
212 wroteToTimeBuffer = false;
213 }
214
215
216
217 bool
218 PipelineStage::checkStall(ThreadID tid) const
219 {
220 bool ret_val = false;
221
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",
225 tid, stageNum + 1);
226 ret_val = true;
227 }
228
229 if (!stalls[tid].resources.empty()) {
230 #if TRACING_ON
231 string stall_src;
232
233 for (int i=0; i < stalls[tid].resources.size(); i++) {
234 stall_src += stalls[tid].resources[i]->res->name() + ":";
235 }
236
237 DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n",
238 tid, stall_src);
239 #endif
240 ret_val = true;
241 }
242
243 return ret_val;
244 }
245
246
247 void
248 PipelineStage::removeStalls(ThreadID tid)
249 {
250 for (int st_num = 0; st_num < NumStages; st_num++) {
251 if (stalls[tid].stage[st_num]) {
252 DPRINTF(InOrderStage, "Removing stall from stage %i.\n",
253 st_num);
254 stalls[tid].stage[st_num] = false;
255 }
256
257 if (toPrevStages->stageBlock[st_num][tid]) {
258 DPRINTF(InOrderStage, "Removing pending block from stage %i.\n",
259 st_num);
260 toPrevStages->stageBlock[st_num][tid] = false;
261 }
262
263 if (fromNextStages->stageBlock[st_num][tid]) {
264 DPRINTF(InOrderStage, "Removing pending block from stage %i.\n",
265 st_num);
266 fromNextStages->stageBlock[st_num][tid] = false;
267 }
268 }
269 stalls[tid].resources.clear();
270 }
271
272 inline bool
273 PipelineStage::prevStageInstsValid()
274 {
275 return prevStage->insts.size() > 0;
276 }
277
278 bool
279 PipelineStage::isBlocked(ThreadID tid)
280 {
281 return stageStatus[tid] == Blocked;
282 }
283
284 bool
285 PipelineStage::block(ThreadID tid)
286 {
287 DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to "
288 "previous stages.\n", tid);
289
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
292 // fetch to block.
293 if (stageStatus[tid] != Blocked) {
294 if (stageStatus[tid] != Unblocking) {
295 wroteToTimeBuffer = true;
296 }
297
298 stageStatus[tid] = Blocked;
299
300 if (prevStageValid) {
301 DPRINTF(InOrderStage, "[tid:%d]: Stage %i setting block signal.\n",
302 tid, stageNum);
303 toPrevStages->stageBlock[stageNum][tid] = true;
304 }
305
306 return true;
307 }
308
309
310 return false;
311 }
312
313 void
314 PipelineStage::blockDueToBuffer(ThreadID tid)
315 {
316 DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to "
317 "next stage.\n", tid);
318
319 if (stageStatus[tid] != Blocked) {
320 if (stageStatus[tid] != Unblocking) {
321 wroteToTimeBuffer = true;
322 }
323
324 // Set the status to Blocked.
325 stageStatus[tid] = Blocked;
326 }
327 }
328
329 bool
330 PipelineStage::unblock(ThreadID tid)
331 {
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);
336
337 if (prevStageValid)
338 toPrevStages->stageUnblock[stageNum][tid] = true;
339
340 wroteToTimeBuffer = true;
341
342 stageStatus[tid] = Running;
343
344 return true;
345 }
346
347 DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid);
348 return false;
349 }
350
351 void
352 PipelineStage::setupSquash(DynInstPtr inst, ThreadID tid)
353 {
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]);
359 } else {
360 InstSeqNum squash_seq_num = inst->squashSeqNum;
361 unsigned squash_stage = (nextStageValid) ? stageNum + 1
362 : stageNum;
363
364 toPrevStages->stageInfo[squash_stage][tid].squash = true;
365 toPrevStages->stageInfo[squash_stage][tid].doneSeqNum =
366 squash_seq_num;
367
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(),
371 squash_stage);
372
373 // Save squash num for later stage use
374 cpu->lastSquashCycle[tid] = curTick();
375 cpu->squashSeqNum[tid] = squash_seq_num;
376 }
377 }
378
379 void
380 PipelineStage::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid)
381 {
382 squash(seq_num, tid);
383 }
384
385 void
386 PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid)
387 {
388 DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from "
389 "incoming stage queue.\n", tid);
390
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, "
396 "[sn:%i] PC %s.\n",
397 tid,
398 prevStage->insts[i]->seqNum,
399 prevStage->insts[i]->pcState());
400 prevStage->insts[i]->setSquashed();
401
402 prevStage->insts[i] = cpu->dummyBufferInst;
403 }
404 }
405 }
406
407 void
408 PipelineStage::squash(InstSeqNum squash_seq_num, ThreadID tid)
409 {
410 // Set status to squashing.
411 stageStatus[tid] = Squashing;
412
413 squashPrevStageInsts(squash_seq_num, tid);
414
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();
421
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());
429 cur_it++;
430 } else {
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);
435 }
436
437 }
438
439 }
440
441 int
442 PipelineStage::stageBufferAvail()
443 {
444 unsigned total = 0;
445
446 for (int i=0; i < ThePipeline::MaxThreads; i++) {
447 total += skidBuffer[i].size();
448 }
449
450 int avail = stageBufferMax - total;
451 assert(avail >= 0);
452
453 return avail;
454 }
455
456 bool
457 PipelineStage::canSendInstToStage(unsigned stage_num)
458 {
459 bool buffer_avail = false;
460
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;
464 }
465
466 if (!buffer_avail && nextStageQueueValid(stage_num)) {
467 DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n",
468 stageNum + 1);
469 }
470
471 return buffer_avail;
472 }
473
474 int
475 PipelineStage::skidSize()
476 {
477 int total = 0;
478
479 for (int i=0; i < ThePipeline::MaxThreads; i++) {
480 total += skidBuffer[i].size();
481 }
482
483 return total;
484 }
485
486 bool
487 PipelineStage::skidsEmpty()
488 {
489 list<ThreadID>::iterator threads = activeThreads->begin();
490
491 while (threads != activeThreads->end()) {
492 if (!skidBuffer[*threads++].empty())
493 return false;
494 }
495
496 return true;
497 }
498
499
500
501 void
502 PipelineStage::updateStatus()
503 {
504 bool any_unblocking = false;
505
506 list<ThreadID>::iterator threads = activeThreads->begin();
507
508 while (threads != activeThreads->end()) {
509 ThreadID tid = *threads++;
510
511 if (stageStatus[tid] == Unblocking) {
512 any_unblocking = true;
513 break;
514 }
515 }
516
517 // Stage will have activity if it's unblocking.
518 if (any_unblocking) {
519 if (_status == Inactive) {
520 _status = Active;
521
522 DPRINTF(Activity, "Activating stage.\n");
523
524 cpu->activateStage(stageNum);
525 }
526 } else {
527 // If it's not unblocking, then stage will not have any internal
528 // activity. Switch it to inactive.
529 if (_status == Active) {
530 _status = Inactive;
531 DPRINTF(Activity, "Deactivating stage.\n");
532
533 cpu->deactivateStage(stageNum);
534 }
535 }
536 }
537
538 void
539 PipelineStage::activateThread(ThreadID tid)
540 {
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);
545 } else {
546 DynInstPtr inst = switchedOutBuffer[tid];
547
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);
551
552 // Make instruction available for pipeline processing
553 skidBuffer[tid].push_back(inst);
554
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,
559 inst, Cycles(0), 0, tid);
560
561 // Clear switchout buffer
562 switchedOutBuffer[tid] = NULL;
563 switchedOutValid[tid] = false;
564
565 // Update any CPU stats based off context switches
566 cpu->updateContextSwitchStats();
567 }
568 }
569
570 }
571
572
573 void
574 PipelineStage::sortInsts()
575 {
576 if (prevStageValid) {
577 assert(prevStage->insts.size() <= stageWidth);
578
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);
585
586 int inserted_insts = 0;
587
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);
594 continue;
595 }
596
597 ThreadID tid = prevStage->insts[i]->threadNumber;
598
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]);
605
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;
610 }
611 } else {
612 DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage "
613 "buffer.\n", prevStage->insts[i]->readTid(),
614 prevStage->insts[i]->seqNum);
615
616 skidBuffer[tid].push_back(prevStage->insts[i]);
617 }
618
619 prevStage->insts[i] = cpu->dummyBufferInst;
620
621 inserted_insts++;
622 }
623 }
624 }
625
626
627
628 void
629 PipelineStage::readStallSignals(ThreadID tid)
630 {
631 for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid];
632 stage_idx++) {
633
634 DPRINTF(InOrderStage, "[tid:%i] Reading stall signals from Stage "
635 "%i. Block:%i Unblock:%i.\n",
636 tid,
637 stage_idx,
638 fromNextStages->stageBlock[stage_idx][tid],
639 fromNextStages->stageUnblock[stage_idx][tid]);
640
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,
644 stage_idx);
645 stalls[tid].stage[stage_idx] = true;
646 }
647
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,
651 stage_idx);
652 stalls[tid].stage[stage_idx] = false;
653 }
654 }
655 }
656
657
658
659 bool
660 PipelineStage::checkSignalsAndUpdate(ThreadID tid)
661 {
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.
669
670 // Update the per thread stall statuses.
671 readStallSignals(tid);
672
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;
682 }
683 }
684
685 if (checkStall(tid)) {
686 return block(tid);
687 }
688
689 if (stageStatus[tid] == Blocked) {
690 DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to "
691 "unblocking.\n", tid);
692
693 stageStatus[tid] = Unblocking;
694
695 unblock(tid);
696
697 return true;
698 }
699
700 if (stageStatus[tid] == Squashing) {
701 if (!skidBuffer[tid].empty()) {
702 DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to "
703 "unblocking.\n", tid);
704
705 stageStatus[tid] = Unblocking;
706 } else {
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 "
710 "running.\n", tid);
711
712 stageStatus[tid] = Running;
713 }
714
715 return true;
716 }
717
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.*/
720 return false;
721 }
722
723
724
725 void
726 PipelineStage::tick()
727 {
728 idle = false;
729
730 wroteToTimeBuffer = false;
731
732 bool status_change = false;
733
734 sortInsts();
735
736 instsProcessed = 0;
737
738 processStage(status_change);
739
740 if (status_change) {
741 updateStatus();
742 }
743
744 if (wroteToTimeBuffer) {
745 DPRINTF(Activity, "Activity this cycle.\n");
746 cpu->activityThisCycle();
747 }
748
749 DPRINTF(InOrderStage, "\n\n");
750 }
751
752 void
753 PipelineStage::setResStall(ResReqPtr res_req, ThreadID tid)
754 {
755 DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name());
756 stalls[tid].resources.push_back(res_req);
757 }
758
759 void
760 PipelineStage::unsetResStall(ResReqPtr res_req, ThreadID tid)
761 {
762 // Search through stalls to find stalling request and then
763 // remove it
764 vector<ResReqPtr>::iterator req_it = stalls[tid].resources.begin();
765 vector<ResReqPtr>::iterator req_end = stalls[tid].resources.end();
766
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);
774 break;
775 }
776
777 req_it++;
778 }
779
780 if (stalls[tid].resources.size() == 0) {
781 DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource"
782 "stalls.\n", tid);
783 }
784 }
785
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 &
789 // pipeline squashes
790 void
791 PipelineStage::processStage(bool &status_change)
792 {
793 list<ThreadID>::iterator threads = activeThreads->begin();
794
795 //Check stall and squash signals.
796 while (threads != activeThreads->end()) {
797 ThreadID tid = *threads++;
798
799 DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid);
800 status_change = checkSignalsAndUpdate(tid) || status_change;
801
802 processThread(status_change, tid);
803 }
804
805 if (nextStageValid) {
806 DPRINTF(InOrderStage, "%i insts now available for stage %i.\n",
807 nextStage->insts.size(), stageNum + 1);
808 }
809
810 if (instsProcessed > 0) {
811 ++runCycles;
812 idle = false;
813 } else {
814 ++idleCycles;
815 idle = true;
816 }
817
818 DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(),
819 stageNum);
820
821 DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n",
822 stageBufferAvail(), stageNum);
823 }
824
825 void
826 PipelineStage::processThread(bool &status_change, ThreadID tid)
827 {
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
834
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 "
840 "stage.\n",tid);
841
842 processInsts(tid);
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());
847
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.
851 processInsts(tid);
852
853 status_change = unblock(tid) || status_change;
854 }
855 }
856
857
858 void
859 PipelineStage::processInsts(ThreadID tid)
860 {
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();
864
865 std::list<DynInstPtr> &insts_to_stage = skidBuffer[tid];
866
867 if (insts_available == 0) {
868 DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out"
869 " early.\n",tid);
870 return;
871 }
872
873 DynInstPtr inst;
874 bool last_req_completed = true;
875
876 while (insts_available > 0 &&
877 instsProcessed < stageWidth &&
878 last_req_completed) {
879 assert(!insts_to_stage.empty());
880
881 inst = insts_to_stage.front();
882
883 DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] "
884 "%s with PC %s\n", tid, inst->seqNum,
885 inst->instName(),
886 inst->pcState());
887
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());
892
893 insts_to_stage.pop_front();
894
895 --insts_available;
896
897 continue;
898 }
899
900 int reqs_processed = 0;
901 last_req_completed = processInstSchedule(inst, reqs_processed);
902
903 // If the instruction isnt squashed & we've completed one request
904 // Then we can officially count this instruction toward the stage's
905 // bandwidth count
906 if (reqs_processed > 0)
907 instsProcessed++;
908
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)
912 continue;
913
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);
918 break;
919 }
920
921 insts_to_stage.pop_front();
922
923 --insts_available;
924 }
925
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);
930 }
931
932 // Record that stage has written to the time buffer for activity
933 // tracking.
934 if (instsProcessed) {
935 wroteToTimeBuffer = true;
936 }
937 }
938
939 bool
940 PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed)
941 {
942 bool last_req_completed = true;
943 ThreadID tid = inst->readTid();
944
945 if (inst->nextResStage() == stageNum) {
946 int res_stage_num = inst->nextResStage();
947
948 while (res_stage_num == stageNum) {
949 int res_num = inst->nextResource();
950
951
952 DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s."
953 "\n", tid, inst->seqNum, cpu->resPool->name(res_num));
954
955 ResReqPtr req = cpu->resPool->request(res_num, inst);
956 assert(req->valid);
957
958 bool req_completed = req->isCompleted();
959 bool done_in_pipeline = false;
960 if (req_completed) {
961 DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s "
962 "completed.\n", tid, inst->seqNum,
963 cpu->resPool->name(res_num));
964
965 reqs_processed++;
966
967 req->stagePasses++;
968
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);
973 }
974 } else {
975 DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed."
976 "\n", tid, inst->seqNum, cpu->resPool->name(res_num));
977
978 last_req_completed = false;
979
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);
985
986 DPRINTF(InOrderStage, "Inserting [tid:%i][sn:%i] into "
987 "switch out buffer.\n", tid, inst->seqNum);
988
989 switchedOutBuffer[tid] = inst;
990 switchedOutValid[tid] = true;
991
992 // Remove Thread From Pipeline & Resource Pool
993 inst->squashingStage = stageNum;
994 inst->squashSeqNum = inst->seqNum;
995 cpu->squashFromMemStall(inst, tid);
996
997 // Switch On Cache Miss
998 //=====================
999 // Suspend Thread at end of cycle
1000 DPRINTF(ThreadModel, "Suspending [tid:%i] due to cache "
1001 "miss.\n", tid);
1002 cpu->suspendContext(tid);
1003
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();
1008 }
1009 }
1010
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) {
1014 req->freeSlot();
1015 }
1016
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) {
1021 break;
1022 }
1023
1024 res_stage_num = inst->nextResStage();
1025 }
1026 } else {
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);
1030 }
1031
1032 return last_req_completed;
1033 }
1034
1035 bool
1036 PipelineStage::nextStageQueueValid(int stage_num)
1037 {
1038 return cpu->pipelineStage[stage_num]->nextStageValid;
1039 }
1040
1041
1042 bool
1043 PipelineStage::sendInstToNextStage(DynInstPtr inst)
1044 {
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)
1049 inst->nextStage++;
1050
1051 bool success = false;
1052 ThreadID tid = inst->readTid();
1053 int next_stage = inst->nextStage;
1054 int prev_stage = next_stage - 1;
1055
1056 assert(next_stage >= 1);
1057 assert(prev_stage >= 0);
1058
1059 DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to "
1060 "stage %u.\n", tid, stageNum+1);
1061
1062 if (!canSendInstToStage(inst->nextStage)) {
1063 DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to "
1064 "stage %u.\n", tid, stageNum+1);
1065 return false;
1066 }
1067
1068
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,
1074 inst->nextStage);
1075 } else {
1076 if (nextStageValid) {
1077 DPRINTF(InOrderStage, "[tid:%u] %i slots available in next "
1078 "stage buffer.\n", tid,
1079 cpu->pipelineStage[next_stage]->stageBufferAvail());
1080 }
1081
1082 DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into "
1083 "index %i of stage buffer %i queue.\n",
1084 tid, inst->seqNum,
1085 cpu->pipelineStage[prev_stage]->nextStage->insts.size(),
1086 cpu->pipelineStage[prev_stage]->nextStageQueue->id());
1087
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);
1091
1092 success = true;
1093
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());
1098 }
1099
1100 }
1101 }
1102
1103 return success;
1104 }
1105
1106 void
1107 PipelineStage::dumpInsts()
1108 {
1109 cprintf("Insts in Stage %i skidbuffers\n",stageNum);
1110
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();
1114
1115 while (cur_it != end_it) {
1116 DynInstPtr inst = (*cur_it);
1117
1118 cprintf("Inst. PC:%s\n[tid:%i]\n[sn:%i]\n\n",
1119 inst->pcState(), inst->threadNumber, inst->seqNum);
1120
1121 cur_it++;
1122 }
1123 }
1124
1125 }