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