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