Merge ktlim@zizzer.eecs.umich.edu:/bk/m5
[gem5.git] / cpu / beta_cpu / decode_impl.hh
1 #include "cpu/beta_cpu/decode.hh"
2
3 template<class Impl>
4 SimpleDecode<Impl>::SimpleDecode(Params &params)
5 : renameToDecodeDelay(params.renameToDecodeDelay),
6 iewToDecodeDelay(params.iewToDecodeDelay),
7 commitToDecodeDelay(params.commitToDecodeDelay),
8 fetchToDecodeDelay(params.fetchToDecodeDelay),
9 decodeWidth(params.decodeWidth),
10 numInst(0)
11 {
12 DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
13 _status = Idle;
14 }
15
16 template <class Impl>
17 void
18 SimpleDecode<Impl>::regStats()
19 {
20 decodeIdleCycles
21 .name(name() + ".decodeIdleCycles")
22 .desc("Number of cycles decode is idle")
23 .prereq(decodeIdleCycles);
24 decodeBlockedCycles
25 .name(name() + ".decodeBlockedCycles")
26 .desc("Number of cycles decode is blocked")
27 .prereq(decodeBlockedCycles);
28 decodeUnblockCycles
29 .name(name() + ".decodeUnblockCycles")
30 .desc("Number of cycles decode is unblocking")
31 .prereq(decodeUnblockCycles);
32 decodeSquashCycles
33 .name(name() + ".decodeSquashCycles")
34 .desc("Number of cycles decode is squashing")
35 .prereq(decodeSquashCycles);
36 decodeBranchMispred
37 .name(name() + ".decodeBranchMispred")
38 .desc("Number of times decode detected a branch misprediction")
39 .prereq(decodeBranchMispred);
40 decodeControlMispred
41 .name(name() + ".decodeControlMispred")
42 .desc("Number of times decode detected an instruction incorrectly"
43 " predicted as a control")
44 .prereq(decodeControlMispred);
45 decodeDecodedInsts
46 .name(name() + ".decodeDecodedInsts")
47 .desc("Number of instructions handled by decode")
48 .prereq(decodeDecodedInsts);
49 decodeSquashedInsts
50 .name(name() + ".decodeSquashedInsts")
51 .desc("Number of squashed instructions handled by decode")
52 .prereq(decodeSquashedInsts);
53 }
54
55 template<class Impl>
56 void
57 SimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
58 {
59 DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
60 cpu = cpu_ptr;
61 }
62
63 template<class Impl>
64 void
65 SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
66 {
67 DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
68 timeBuffer = tb_ptr;
69
70 // Setup wire to write information back to fetch.
71 toFetch = timeBuffer->getWire(0);
72
73 // Create wires to get information from proper places in time buffer.
74 fromRename = timeBuffer->getWire(-renameToDecodeDelay);
75 fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
76 fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
77 }
78
79 template<class Impl>
80 void
81 SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
82 {
83 DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
84 decodeQueue = dq_ptr;
85
86 // Setup wire to write information to proper place in decode queue.
87 toRename = decodeQueue->getWire(0);
88 }
89
90 template<class Impl>
91 void
92 SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
93 {
94 DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
95 fetchQueue = fq_ptr;
96
97 // Setup wire to read information from fetch queue.
98 fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
99 }
100
101 template<class Impl>
102 void
103 SimpleDecode<Impl>::block()
104 {
105 DPRINTF(Decode, "Decode: Blocking.\n");
106
107 // Set the status to Blocked.
108 _status = Blocked;
109
110 // Add the current inputs to the skid buffer so they can be
111 // reprocessed when this stage unblocks.
112 skidBuffer.push(*fromFetch);
113
114 // Note that this stage only signals previous stages to stall when
115 // it is the cause of the stall originates at this stage. Otherwise
116 // the previous stages are expected to check all possible stall signals.
117 }
118
119 template<class Impl>
120 inline void
121 SimpleDecode<Impl>::unblock()
122 {
123 DPRINTF(Decode, "Decode: Unblocking, going to remove "
124 "instructions from skid buffer.\n");
125 // Remove the now processed instructions from the skid buffer.
126 skidBuffer.pop();
127
128 // If there's still information in the skid buffer, then
129 // continue to tell previous stages to stall. They will be
130 // able to restart once the skid buffer is empty.
131 if (!skidBuffer.empty()) {
132 toFetch->decodeInfo.stall = true;
133 } else {
134 DPRINTF(Decode, "Decode: Finished unblocking.\n");
135 _status = Running;
136 }
137 }
138
139 // This squash is specifically for when Decode detects a PC-relative branch
140 // was predicted incorrectly.
141 template<class Impl>
142 void
143 SimpleDecode<Impl>::squash(DynInstPtr &inst)
144 {
145 DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
146 "detected at decode.\n");
147 Addr new_PC = inst->readNextPC();
148
149 toFetch->decodeInfo.branchMispredict = true;
150 toFetch->decodeInfo.doneSeqNum = inst->seqNum;
151 toFetch->decodeInfo.predIncorrect = true;
152 toFetch->decodeInfo.squash = true;
153 toFetch->decodeInfo.nextPC = new_PC;
154 toFetch->decodeInfo.branchTaken = true;
155
156 // Set status to squashing.
157 _status = Squashing;
158
159 // Maybe advance the time buffer? Not sure what to do in the normal
160 // case.
161
162 // Clear the skid buffer in case it has any data in it.
163 while (!skidBuffer.empty())
164 {
165 skidBuffer.pop();
166 }
167 }
168
169 template<class Impl>
170 void
171 SimpleDecode<Impl>::squash()
172 {
173 DPRINTF(Decode, "Decode: Squashing.\n");
174 // Set status to squashing.
175 _status = Squashing;
176
177 // Maybe advance the time buffer? Not sure what to do in the normal
178 // case.
179
180 // Clear the skid buffer in case it has any data in it.
181 while (!skidBuffer.empty())
182 {
183 skidBuffer.pop();
184 }
185 }
186
187 template<class Impl>
188 void
189 SimpleDecode<Impl>::tick()
190 {
191 // Decode should try to execute as many instructions as its bandwidth
192 // will allow, as long as it is not currently blocked.
193 if (_status != Blocked && _status != Squashing) {
194 DPRINTF(Decode, "Decode: Not blocked, so attempting to run "
195 "stage.\n");
196 // Make sure that the skid buffer has something in it if the
197 // status is unblocking.
198 assert(_status == Unblocking ? !skidBuffer.empty() : 1);
199
200 decode();
201
202 // If the status was unblocking, then instructions from the skid
203 // buffer were used. Remove those instructions and handle
204 // the rest of unblocking.
205 if (_status == Unblocking) {
206 ++decodeUnblockCycles;
207
208 if (fromFetch->size > 0) {
209 // Add the current inputs to the skid buffer so they can be
210 // reprocessed when this stage unblocks.
211 skidBuffer.push(*fromFetch);
212 }
213
214 unblock();
215 }
216 } else if (_status == Blocked) {
217 ++decodeBlockedCycles;
218
219 if (fromFetch->size > 0) {
220 block();
221 }
222
223 if (!fromRename->renameInfo.stall &&
224 !fromIEW->iewInfo.stall &&
225 !fromCommit->commitInfo.stall) {
226 DPRINTF(Decode, "Decode: Stall signals cleared, going to "
227 "unblock.\n");
228 _status = Unblocking;
229
230 // Continue to tell previous stage to block until this
231 // stage is done unblocking.
232 toFetch->decodeInfo.stall = true;
233 } else {
234 DPRINTF(Decode, "Decode: Still blocked.\n");
235 toFetch->decodeInfo.stall = true;
236 }
237
238 if (fromCommit->commitInfo.squash ||
239 fromCommit->commitInfo.robSquashing) {
240 squash();
241 }
242 } else if (_status == Squashing) {
243 ++decodeSquashCycles;
244
245 if (!fromCommit->commitInfo.squash &&
246 !fromCommit->commitInfo.robSquashing) {
247 _status = Running;
248 } else if (fromCommit->commitInfo.squash) {
249 squash();
250 }
251 }
252 }
253
254 template<class Impl>
255 void
256 SimpleDecode<Impl>::decode()
257 {
258 // Check time buffer if being told to squash.
259 if (fromCommit->commitInfo.squash) {
260 squash();
261 return;
262 }
263
264 // Check time buffer if being told to stall.
265 if (fromRename->renameInfo.stall ||
266 fromIEW->iewInfo.stall ||
267 fromCommit->commitInfo.stall)
268 {
269 block();
270 return;
271 }
272
273 // Check fetch queue to see if instructions are available.
274 // If no available instructions, do nothing, unless this stage is
275 // currently unblocking.
276 if (fromFetch->size == 0 && _status != Unblocking) {
277 DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
278 // Should I change the status to idle?
279 ++decodeIdleCycles;
280 return;
281 }
282
283 // Might be better to use a base DynInst * instead?
284 DynInstPtr inst;
285
286 unsigned to_rename_index = 0;
287
288 int insts_available = _status == Unblocking ?
289 skidBuffer.front().size :
290 fromFetch->size;
291
292 // Debug block...
293 #if 0
294 if (insts_available) {
295 DPRINTF(Decode, "Decode: Instructions available.\n");
296 } else {
297 if (_status == Unblocking && skidBuffer.empty()) {
298 DPRINTF(Decode, "Decode: No instructions available, skid buffer "
299 "empty.\n");
300 } else if (_status != Unblocking &&
301 !fromFetch->insts[0]) {
302 DPRINTF(Decode, "Decode: No instructions available, fetch queue "
303 "empty.\n");
304 } else {
305 panic("Decode: No instructions available, unexpected condition!"
306 "\n");
307 }
308 }
309 #endif
310
311 while (insts_available > 0)
312 {
313 DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
314
315 inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
316 fromFetch->insts[numInst];
317
318 DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n",
319 inst->seqNum, inst->readPC());
320
321 if (inst->isSquashed()) {
322 DPRINTF(Decode, "Decode: Instruction %i with PC %#x is "
323 "squashed, skipping.\n",
324 inst->seqNum, inst->readPC());
325
326 ++decodeSquashedInsts;
327
328 ++numInst;
329 --insts_available;
330
331 continue;
332 }
333
334 // This current instruction is valid, so add it into the decode
335 // queue. The next instruction may not be valid, so check to
336 // see if branches were predicted correctly.
337 toRename->insts[to_rename_index] = inst;
338
339 ++(toRename->size);
340
341 // Ensure that if it was predicted as a branch, it really is a
342 // branch.
343 if (inst->predTaken() && !inst->isControl()) {
344 panic("Instruction predicted as a branch!");
345
346 ++decodeControlMispred;
347 // Might want to set some sort of boolean and just do
348 // a check at the end
349 squash(inst);
350 break;
351 }
352
353 // Go ahead and compute any PC-relative branches.
354
355 if (inst->isDirectCtrl() && inst->isUncondCtrl()) {
356
357 inst->setNextPC(inst->branchTarget());
358
359 if (inst->mispredicted()) {
360 ++decodeBranchMispred;
361 // Might want to set some sort of boolean and just do
362 // a check at the end
363 squash(inst);
364 break;
365 }
366 }
367
368 // Normally can check if a direct branch has the right target
369 // addr (either the immediate, or the branch PC + 4) and redirect
370 // fetch if it's incorrect.
371
372
373 // Also check if instructions have no source registers. Mark
374 // them as ready to issue at any time. Not sure if this check
375 // should exist here or at a later stage; however it doesn't matter
376 // too much for function correctness.
377 // Isn't this handled by the inst queue?
378 if (inst->numSrcRegs() == 0) {
379 inst->setCanIssue();
380 }
381
382 // Increment which instruction we're looking at.
383 ++numInst;
384 ++to_rename_index;
385 ++decodeDecodedInsts;
386
387 --insts_available;
388 }
389
390 numInst = 0;
391 }