CPU: Make physPort and getPhysPort available in SE mode.
[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/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"
39
40 using namespace std;
41 using namespace ThePipeline;
42
43 FirstStage::FirstStage(Params *params, unsigned stage_num)
44 : PipelineStage(params, stage_num), numFetchingThreads(1),
45 fetchPolicy(FirstStage::RoundRobin)
46 {
47 for(ThreadID tid = 0; tid < this->numThreads; tid++) {
48 stageStatus[tid] = Running;
49 }
50 }
51
52 void
53 FirstStage::setCPU(InOrderCPU *cpu_ptr)
54 {
55 cpu = cpu_ptr;
56
57 fetchPriorityList = &cpu->fetchPriorityList;
58
59 DPRINTF(InOrderStage, "Set CPU pointer.\n");
60 }
61
62
63 void
64 FirstStage::squash(InstSeqNum squash_seq_num, ThreadID tid)
65 {
66 // Set status to squashing.
67 //stageStatus[tid] = Squashing;
68
69 // Clear the instruction list and skid buffer in case they have any
70 // insts in them.
71 DPRINTF(InOrderStage, "Removing instructions from stage instruction "
72 "list.\n");
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",
77 tid,
78 skidBuffer[tid].front()->seqNum,
79 squash_seq_num);
80
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());
85 break;
86 }
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();
91 }
92
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);
97 }
98
99 void
100 FirstStage::squashDueToMemStall(InstSeqNum seq_num, ThreadID tid)
101 {
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);
108 }
109
110
111 void
112 FirstStage::processStage(bool &status_change)
113 {
114 list<ThreadID>::iterator threads = activeThreads->begin();
115
116 //Check stall and squash signals.
117 while (threads != activeThreads->end()) {
118 ThreadID tid = *threads++;
119 status_change = checkSignalsAndUpdate(tid) || status_change;
120 }
121
122 while (instsProcessed < stageWidth) {
123 ThreadID tid = getFetchingThread(fetchPolicy);
124
125 if (tid >= 0) {
126 DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
127 processThread(status_change, tid);
128 DPRINTF(InOrderStage, "Done Processing [tid:%i]\n",tid);
129 } else {
130 DPRINTF(InOrderStage, "No more threads to fetch from.\n");
131 break;
132 }
133 }
134
135 if (instsProcessed > 0) {
136 ++runCycles;
137 idle = false;
138 } else {
139 ++idleCycles;
140 idle = true;
141 }
142
143 }
144
145 //@TODO: Note in documentation, that when you make a pipeline stage change,
146 //then make sure you change the first stage too
147 void
148 FirstStage::processInsts(ThreadID tid)
149 {
150 bool all_reqs_completed = true;
151
152 for (int insts_fetched = instsProcessed;
153 insts_fetched < stageWidth;
154 insts_fetched++) {
155
156 DynInstPtr inst;
157 bool new_inst = false;
158
159 if (!skidBuffer[tid].empty()) {
160 inst = skidBuffer[tid].front();
161 } else {
162 // Get new instruction.
163 new_inst = true;
164
165 inst = new InOrderDynInst(cpu,
166 cpu->thread[tid],
167 cpu->nextInstSeqNum(tid),
168 tid,
169 tid);
170
171 #if TRACING_ON
172 inst->traceData =
173 tracer->getInstRecord(ThePipeline::NumStages,
174 cpu->stageTracing,
175 cpu->thread[tid]->getTC());
176
177 #else
178 inst->traceData = NULL;
179 #endif // TRACING_ON
180
181 // Add instruction to the CPU's list of instructions.
182 inst->setInstListIt(cpu->addInst(inst));
183
184 // Create Front-End Resource Schedule For Instruction
185 inst->setFrontSked(cpu->frontEndSked);
186 }
187
188 int reqs_processed = 0;
189 all_reqs_completed = processInstSchedule(inst, reqs_processed);
190
191 // If the instruction isnt squashed & we've completed one request
192 // Then we can officially count this instruction toward the stage's
193 // bandwidth count
194 if (reqs_processed > 0)
195 instsProcessed++;
196
197 if (!all_reqs_completed || !sendInstToNextStage(inst)) {
198 if (new_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);
203 }
204 block(tid);
205 break;
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();
210 }
211
212 }
213
214 // Record that stage has written to the time buffer for activity
215 // tracking.
216 if (instsProcessed) {
217 wroteToTimeBuffer = true;
218 }
219 }
220
221 ThreadID
222 FirstStage::getFetchingThread(FetchPriority &fetch_priority)
223 {
224 ThreadID num_active_threads = cpu->numActiveThreads();
225
226 if (num_active_threads > 1) {
227 switch (fetch_priority) {
228 case SingleThread:
229 return cpu->activeThreadId();
230
231 case RoundRobin:
232 return roundRobin();
233
234 default:
235 return InvalidThreadID;
236 }
237 } else if (num_active_threads == 1) {
238 ThreadID tid = *activeThreads->begin();
239
240 if (stageStatus[tid] == Running ||
241 stageStatus[tid] == Idle ||
242 stageStatus[tid] == Unblocking) {
243 return tid;
244 } else {
245 return InvalidThreadID;
246 }
247 } else {
248 return InvalidThreadID;
249 }
250 }
251
252 ThreadID
253 FirstStage::roundRobin()
254 {
255 list<ThreadID>::iterator pri_iter = fetchPriorityList->begin();
256 list<ThreadID>::iterator end = fetchPriorityList->end();
257
258 ThreadID high_pri;
259
260 while (pri_iter != end) {
261 high_pri = *pri_iter;
262
263 assert(high_pri <= numThreads);
264
265 if (stageStatus[high_pri] == Running ||
266 stageStatus[high_pri] == Idle ||
267 stageStatus[high_pri] == Unblocking){
268
269 fetchPriorityList->erase(pri_iter);
270 fetchPriorityList->push_back(high_pri);
271
272 return high_pri;
273 }
274
275 pri_iter++;
276 }
277
278 return InvalidThreadID;
279 }