merge
[gem5.git] / src / cpu / inorder / first_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 "cpu/inorder/first_stage.hh"
34 #include "cpu/inorder/resources/resource_list.hh"
35 #include "cpu/inorder/resource_pool.hh"
36 #include "cpu/inorder/cpu.hh"
37 #include "params/InOrderTrace.hh"
38
39 using namespace std;
40 using namespace ThePipeline;
41
42 FirstStage::FirstStage(Params *params, unsigned stage_num)
43 : PipelineStage(params, stage_num), numFetchingThreads(1),
44 fetchPolicy(FirstStage::RoundRobin)
45 {
46 for(ThreadID tid = 0; tid < this->numThreads; tid++) {
47 stageStatus[tid] = Running;
48 }
49 }
50
51 void
52 FirstStage::setCPU(InOrderCPU *cpu_ptr)
53 {
54 cpu = cpu_ptr;
55
56 fetchPriorityList = &cpu->fetchPriorityList;
57
58 DPRINTF(InOrderStage, "Set CPU pointer.\n");
59 }
60
61
62 void
63 FirstStage::squash(InstSeqNum squash_seq_num, ThreadID tid)
64 {
65 // Set status to squashing.
66 //stageStatus[tid] = Squashing;
67
68 // Clear the instruction list and skid buffer in case they have any
69 // insts in them.
70 DPRINTF(InOrderStage, "Removing instructions from stage instruction "
71 "list.\n");
72 while (!insts[tid].empty()) {
73 if (insts[tid].front()->seqNum <= squash_seq_num) {
74 DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because "
75 "it's <= squashing seqNum %i.\n",
76 tid,
77 insts[tid].front()->seqNum,
78 squash_seq_num);
79
80 DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming "
81 "instructions before delay slot [sn:%i]. %i insts"
82 "left.\n", tid, squash_seq_num,
83 insts[tid].size());
84 break;
85 }
86 DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] "
87 "PC %08p.\n", tid, insts[tid].front()->seqNum,
88 insts[tid].front()->PC);
89 insts[tid].pop();
90 }
91
92 // Now that squash has propagated to the first stage,
93 // Alert CPU to remove instructions from the CPU instruction list.
94 // @todo: Move this to the CPU object.
95 cpu->removeInstsUntil(squash_seq_num, tid);
96 }
97
98 void
99 FirstStage::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid)
100 {
101 // Need to preserve the stalling instruction in first-stage
102 // since the squash() from first stage also removes
103 // the instruction from the CPU (removeInstsUntil). If that
104 // functionality gets changed then you can move this offset.
105 // (stalling instruction = seq_num + 1)
106 squash(seq_num+1, tid);
107 }
108
109
110 void
111 FirstStage::processStage(bool &status_change)
112 {
113 list<ThreadID>::iterator threads = activeThreads->begin();
114
115 //Check stall and squash signals.
116 while (threads != activeThreads->end()) {
117 ThreadID tid = *threads++;
118 status_change = checkSignalsAndUpdate(tid) || status_change;
119 }
120
121 for (int insts_fetched = 0;
122 insts_fetched < stageWidth && canSendInstToStage(1);
123 insts_fetched++) {
124 ThreadID tid = getFetchingThread(fetchPolicy);
125
126 if (tid >= 0) {
127 DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
128 processThread(status_change, tid);
129 } else {
130 DPRINTF(InOrderStage, "No more threads to fetch from.\n");
131 }
132 }
133
134 if (instsProcessed > 0) {
135 ++runCycles;
136 idle = false;
137 } else {
138 ++idleCycles;
139 idle = true;
140 }
141
142 }
143
144 //@TODO: Note in documentation, that when you make a pipeline stage change,
145 //then make sure you change the first stage too
146 void
147 FirstStage::processInsts(ThreadID tid)
148 {
149 bool all_reqs_completed = true;
150
151 for (int insts_fetched = 0;
152 insts_fetched < stageWidth && canSendInstToStage(1);
153 insts_fetched++) {
154
155 DynInstPtr inst;
156 bool new_inst = false;
157
158 if (!insts[tid].empty()) {
159 inst = insts[tid].front();
160 } else {
161 // Get new instruction.
162 new_inst = true;
163
164 inst = new InOrderDynInst(cpu,
165 cpu->thread[tid],
166 cpu->nextInstSeqNum(tid),
167 tid,
168 tid);
169
170 #if TRACING_ON
171 inst->traceData =
172 tracer->getInstRecord(ThePipeline::NumStages,
173 cpu->stageTracing,
174 cpu->thread[tid]->getTC());
175
176 #else
177 inst->traceData = NULL;
178 #endif // TRACING_ON
179
180 // Add instruction to the CPU's list of instructions.
181 inst->setInstListIt(cpu->addInst(inst));
182
183 // Create Front-End Resource Schedule For Instruction
184 ThePipeline::createFrontEndSchedule(inst);
185 }
186
187 int reqs_processed = 0;
188 all_reqs_completed = processInstSchedule(inst, reqs_processed);
189
190 // If the instruction isnt squashed & we've completed one request
191 // Then we can officially count this instruction toward the stage's
192 // bandwidth count
193 if (reqs_processed > 0)
194 instsProcessed++;
195
196 if (!all_reqs_completed) {
197 if (new_inst) {
198 DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all "
199 "requests for this stage. Keep in stage inst. "
200 "list.\n", tid, inst->seqNum);
201 insts[tid].push(inst);
202 }
203 break;
204 } else if (!insts[tid].empty()){
205 insts[tid].pop();
206 }
207
208 sendInstToNextStage(inst);
209 }
210
211 // Record that stage has written to the time buffer for activity
212 // tracking.
213 if (toNextStageIndex) {
214 wroteToTimeBuffer = true;
215 }
216 }
217
218 ThreadID
219 FirstStage::getFetchingThread(FetchPriority &fetch_priority)
220 {
221 ThreadID num_active_threads = cpu->numActiveThreads();
222
223 if (num_active_threads > 1) {
224 switch (fetch_priority) {
225 case SingleThread:
226 return cpu->activeThreadId();
227
228 case RoundRobin:
229 return roundRobin();
230
231 default:
232 return InvalidThreadID;
233 }
234 } else if (num_active_threads == 1) {
235 ThreadID tid = *activeThreads->begin();
236
237 if (stageStatus[tid] == Running ||
238 stageStatus[tid] == Idle) {
239 return tid;
240 } else {
241 return InvalidThreadID;
242 }
243 } else {
244 return InvalidThreadID;
245 }
246 }
247
248 ThreadID
249 FirstStage::roundRobin()
250 {
251 list<ThreadID>::iterator pri_iter = fetchPriorityList->begin();
252 list<ThreadID>::iterator end = fetchPriorityList->end();
253
254 ThreadID high_pri;
255
256 while (pri_iter != end) {
257 high_pri = *pri_iter;
258
259 assert(high_pri <= numThreads);
260
261 if (stageStatus[high_pri] == Running ||
262 stageStatus[high_pri] == Idle) {
263
264 fetchPriorityList->erase(pri_iter);
265 fetchPriorityList->push_back(high_pri);
266
267 return high_pri;
268 }
269
270 pri_iter++;
271 }
272
273 return InvalidThreadID;
274 }