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 "cpu/inorder/resources/resource_list.hh"
34 #include "cpu/inorder/cpu.hh"
35 #include "cpu/inorder/first_stage.hh"
36 #include "cpu/inorder/resource_pool.hh"
37 #include "debug/InOrderStage.hh"
38 #include "params/InOrderTrace.hh"
41 using namespace ThePipeline
;
43 FirstStage::FirstStage(Params
*params
, unsigned stage_num
)
44 : PipelineStage(params
, stage_num
), numFetchingThreads(1),
45 fetchPolicy(FirstStage::RoundRobin
)
47 for(ThreadID tid
= 0; tid
< this->numThreads
; tid
++) {
48 stageStatus
[tid
] = Running
;
53 FirstStage::setCPU(InOrderCPU
*cpu_ptr
)
57 fetchPriorityList
= &cpu
->fetchPriorityList
;
59 DPRINTF(InOrderStage
, "Set CPU pointer.\n");
64 FirstStage::squash(InstSeqNum squash_seq_num
, ThreadID tid
)
66 // Set status to squashing.
67 //stageStatus[tid] = Squashing;
69 // Clear the instruction list and skid buffer in case they have any
71 DPRINTF(InOrderStage
, "Removing instructions from stage instruction "
73 while (!skidBuffer
[tid
].empty()) {
74 if (skidBuffer
[tid
].front()->seqNum
<= squash_seq_num
) {
75 DPRINTF(InOrderStage
,"[tid:%i]: Cannot remove [sn:%i] because "
76 "it's <= squashing seqNum %i.\n",
78 skidBuffer
[tid
].front()->seqNum
,
81 DPRINTF(InOrderStage
, "[tid:%i]: Cannot remove incoming "
82 "instructions before delay slot [sn:%i]. %i insts"
83 "left.\n", tid
, squash_seq_num
,
84 skidBuffer
[tid
].size());
87 DPRINTF(InOrderStage
, "[tid:%i]: Removing instruction, [sn:%i] "
88 "PC %s.\n", tid
, skidBuffer
[tid
].front()->seqNum
,
89 skidBuffer
[tid
].front()->pc
);
90 skidBuffer
[tid
].pop_front();
93 // Now that squash has propagated to the first stage,
94 // Alert CPU to remove instructions from the CPU instruction list.
95 // @todo: Move this to the CPU object.
96 cpu
->removeInstsUntil(squash_seq_num
, tid
);
100 FirstStage::squashDueToMemStall(InstSeqNum seq_num
, ThreadID tid
)
102 // Need to preserve the stalling instruction in first-stage
103 // since the squash() from first stage also removes
104 // the instruction from the CPU (removeInstsUntil). If that
105 // functionality gets changed then you can move this offset.
106 // (stalling instruction = seq_num + 1)
107 squash(seq_num
+1, tid
);
112 FirstStage::processStage(bool &status_change
)
114 list
<ThreadID
>::iterator threads
= activeThreads
->begin();
116 //Check stall and squash signals.
117 while (threads
!= activeThreads
->end()) {
118 ThreadID tid
= *threads
++;
119 status_change
= checkSignalsAndUpdate(tid
) || status_change
;
122 while (instsProcessed
< stageWidth
) {
123 ThreadID tid
= getFetchingThread(fetchPolicy
);
126 DPRINTF(InOrderStage
, "Processing [tid:%i]\n",tid
);
127 processThread(status_change
, tid
);
128 DPRINTF(InOrderStage
, "Done Processing [tid:%i]\n",tid
);
130 DPRINTF(InOrderStage
, "No more threads to fetch from.\n");
135 if (instsProcessed
> 0) {
145 //@TODO: Note in documentation, that when you make a pipeline stage change,
146 //then make sure you change the first stage too
148 FirstStage::processInsts(ThreadID tid
)
150 bool all_reqs_completed
= true;
152 for (int insts_fetched
= instsProcessed
;
153 insts_fetched
< stageWidth
;
157 bool new_inst
= false;
159 if (!skidBuffer
[tid
].empty()) {
160 inst
= skidBuffer
[tid
].front();
162 // Get new instruction.
165 inst
= new InOrderDynInst(cpu
,
167 cpu
->nextInstSeqNum(tid
),
173 tracer
->getInstRecord(ThePipeline::NumStages
,
175 cpu
->thread
[tid
]->getTC());
178 inst
->traceData
= NULL
;
181 // Add instruction to the CPU's list of instructions.
182 inst
->setInstListIt(cpu
->addInst(inst
));
184 // Create Front-End Resource Schedule For Instruction
185 inst
->setFrontSked(cpu
->frontEndSked
);
188 int reqs_processed
= 0;
189 all_reqs_completed
= processInstSchedule(inst
, reqs_processed
);
191 // If the instruction isnt squashed & we've completed one request
192 // Then we can officially count this instruction toward the stage's
194 if (reqs_processed
> 0)
197 if (!all_reqs_completed
|| !sendInstToNextStage(inst
)) {
199 DPRINTF(InOrderStage
, "[tid:%u]: [sn:%u] Did not finish all "
200 "requests for this stage. Keep in stage inst. "
201 "list.\n", tid
, inst
->seqNum
);
202 skidBuffer
[tid
].push_back(inst
);
206 } else if (!skidBuffer
[tid
].empty()){
207 DPRINTF(InOrderStage
, "[tid:%u]: [sn:%u] Finished all "
208 "requests for this stage.\n", tid
, inst
->seqNum
);
209 skidBuffer
[tid
].pop_front();
214 // Record that stage has written to the time buffer for activity
216 if (instsProcessed
) {
217 wroteToTimeBuffer
= true;
222 FirstStage::getFetchingThread(FetchPriority
&fetch_priority
)
224 ThreadID num_active_threads
= cpu
->numActiveThreads();
226 if (num_active_threads
> 1) {
227 switch (fetch_priority
) {
229 return cpu
->activeThreadId();
235 return InvalidThreadID
;
237 } else if (num_active_threads
== 1) {
238 ThreadID tid
= *activeThreads
->begin();
240 if (stageStatus
[tid
] == Running
||
241 stageStatus
[tid
] == Idle
||
242 stageStatus
[tid
] == Unblocking
) {
245 return InvalidThreadID
;
248 return InvalidThreadID
;
253 FirstStage::roundRobin()
255 list
<ThreadID
>::iterator pri_iter
= fetchPriorityList
->begin();
256 list
<ThreadID
>::iterator end
= fetchPriorityList
->end();
260 while (pri_iter
!= end
) {
261 high_pri
= *pri_iter
;
263 assert(high_pri
<= numThreads
);
265 if (stageStatus
[high_pri
] == Running
||
266 stageStatus
[high_pri
] == Idle
||
267 stageStatus
[high_pri
] == Unblocking
){
269 fetchPriorityList
->erase(pri_iter
);
270 fetchPriorityList
->push_back(high_pri
);
278 return InvalidThreadID
;