iew_impl.hh revision 1060
1// @todo: Fix the instantaneous communication among all the stages within
2// iew.  There's a clear delay between issue and execute, yet backwards
3// communication happens simultaneously.  Might not be that bad really...
4// it might skew stats a bit though.  Issue would otherwise try to issue
5// instructions that would never be executed if there were a delay; without
6// it issue will simply squash.  Make this stage block properly.  Make this
7// stage delay after a squash properly.  Update the statuses for each stage.
8// Actually read instructions out of the skid buffer.
9
10#include <queue>
11
12#include "base/timebuf.hh"
13#include "cpu/beta_cpu/iew.hh"
14
15template<class Impl, class IQ>
16SimpleIEW<Impl, IQ>::SimpleIEW(Params &params)
17    : // Just make this time buffer really big for now
18      issueToExecQueue(20, 20),
19      instQueue(params),
20      commitToIEWDelay(params.commitToIEWDelay),
21      renameToIEWDelay(params.renameToIEWDelay),
22      issueToExecuteDelay(params.issueToExecuteDelay),
23      issueReadWidth(params.issueWidth),
24      issueWidth(params.issueWidth),
25      executeWidth(params.executeWidth)
26{
27    DPRINTF(IEW, "IEW: executeIntWidth: %i.\n", params.executeIntWidth);
28    _status = Idle;
29    _issueStatus = Idle;
30    _exeStatus = Idle;
31    _wbStatus = Idle;
32
33    // Setup wire to read instructions coming from issue.
34    fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay);
35
36    // Instruction queue needs the queue between issue and execute.
37    instQueue.setIssueToExecuteQueue(&issueToExecQueue);
38}
39
40template<class Impl, class IQ>
41void
42SimpleIEW<Impl, IQ>::setCPU(FullCPU *cpu_ptr)
43{
44    DPRINTF(IEW, "IEW: Setting CPU pointer.\n");
45    cpu = cpu_ptr;
46
47    instQueue.setCPU(cpu_ptr);
48}
49
50template<class Impl, class IQ>
51void
52SimpleIEW<Impl, IQ>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
53{
54    DPRINTF(IEW, "IEW: Setting time buffer pointer.\n");
55    timeBuffer = tb_ptr;
56
57    // Setup wire to read information from time buffer, from commit.
58    fromCommit = timeBuffer->getWire(-commitToIEWDelay);
59
60    // Setup wire to write information back to previous stages.
61    toRename = timeBuffer->getWire(0);
62
63    // Instruction queue also needs main time buffer.
64    instQueue.setTimeBuffer(tb_ptr);
65}
66
67template<class Impl, class IQ>
68void
69SimpleIEW<Impl, IQ>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
70{
71    DPRINTF(IEW, "IEW: Setting rename queue pointer.\n");
72    renameQueue = rq_ptr;
73
74    // Setup wire to read information from rename queue.
75    fromRename = renameQueue->getWire(-renameToIEWDelay);
76}
77
78template<class Impl, class IQ>
79void
80SimpleIEW<Impl, IQ>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
81{
82    DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n");
83    iewQueue = iq_ptr;
84
85    // Setup wire to write instructions to commit.
86    toCommit = iewQueue->getWire(0);
87}
88
89template<class Impl, class IQ>
90void
91SimpleIEW<Impl, IQ>::setRenameMap(RenameMap *rm_ptr)
92{
93    DPRINTF(IEW, "IEW: Setting rename map pointer.\n");
94    renameMap = rm_ptr;
95}
96
97template<class Impl, class IQ>
98void
99SimpleIEW<Impl, IQ>::wakeDependents(DynInst *inst)
100{
101    instQueue.wakeDependents(inst);
102}
103
104template<class Impl, class IQ>
105void
106SimpleIEW<Impl, IQ>::block()
107{
108    DPRINTF(IEW, "IEW: Blocking.\n");
109    // Set the status to Blocked.
110    _status = Blocked;
111
112    // Add the current inputs to the skid buffer so they can be
113    // reprocessed when this stage unblocks.
114    skidBuffer.push(*fromRename);
115
116    // Note that this stage only signals previous stages to stall when
117    // it is the cause of the stall originates at this stage.  Otherwise
118    // the previous stages are expected to check all possible stall signals.
119}
120
121template<class Impl, class IQ>
122inline void
123SimpleIEW<Impl, IQ>::unblock()
124{
125    // Check if there's information in the skid buffer.  If there is, then
126    // set status to unblocking, otherwise set it directly to running.
127    DPRINTF(IEW, "IEW: Reading instructions out of the skid "
128            "buffer.\n");
129    // Remove the now processed instructions from the skid buffer.
130    skidBuffer.pop();
131
132    // If there's still information in the skid buffer, then
133    // continue to tell previous stages to stall.  They will be
134    // able to restart once the skid buffer is empty.
135    if (!skidBuffer.empty()) {
136        toRename->iewInfo.stall = true;
137    } else {
138        DPRINTF(IEW, "IEW: Stage is done unblocking.\n");
139        _status = Running;
140    }
141}
142
143template<class Impl, class IQ>
144void
145SimpleIEW<Impl, IQ>::squash()
146{
147    DPRINTF(IEW, "IEW: Squashing all instructions.\n");
148    _status = Squashing;
149
150    // Tell the IQ to start squashing.
151    instQueue.squash();
152
153    // Tell rename to squash through the time buffer.
154    // This communication may be redundant depending upon where squash()
155    // is called.
156//    toRename->iewInfo.squash = true;
157}
158
159template<class Impl, class IQ>
160void
161SimpleIEW<Impl, IQ>::squash(DynInst *inst)
162{
163    DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC:%#x.\n",
164            inst->PC);
165    // Perhaps leave the squashing up to the ROB stage to tell it when to
166    // squash?
167    _status = Squashing;
168
169    // Tell rename to squash through the time buffer.
170    toRename->iewInfo.squash = true;
171    // Also send PC update information back to prior stages.
172    toRename->iewInfo.squashedSeqNum = inst->seqNum;
173    toRename->iewInfo.nextPC = inst->readCalcTarg();
174    toRename->iewInfo.predIncorrect = true;
175}
176
177template<class Impl, class IQ>
178void
179SimpleIEW<Impl, IQ>::tick()
180{
181    // Considering putting all the state-determining stuff in this section.
182
183    // Try to fill up issue queue with as many instructions as bandwidth
184    // allows.
185    // Decode should try to execute as many instructions as its bandwidth
186    // will allow, as long as it is not currently blocked.
187
188    // Check if the stage is in a running status.
189    if (_status != Blocked && _status != Squashing) {
190        DPRINTF(IEW, "IEW: Status is not blocked, attempting to run "
191                     "stage.\n");
192        iew();
193
194        // If it's currently unblocking, check to see if it should switch
195        // to running.
196        if (_status == Unblocking) {
197            unblock();
198        }
199    } else if (_status == Squashing) {
200
201        DPRINTF(IEW, "IEW: Still squashing.\n");
202
203        // Check if stage should remain squashing.  Stop squashing if the
204        // squash signal clears.
205        if (!fromCommit->commitInfo.squash &&
206            !fromCommit->commitInfo.robSquashing) {
207            DPRINTF(IEW, "IEW: Done squashing, changing status to "
208                    "running.\n");
209
210            _status = Running;
211            instQueue.stopSquash();
212        } else {
213            instQueue.doSquash();
214        }
215
216        // Also should advance its own time buffers if the stage ran.
217        // Not sure about this...
218//        issueToExecQueue.advance();
219    } else if (_status == Blocked) {
220        // Continue to tell previous stage to stall.
221        toRename->iewInfo.stall = true;
222
223        // Check if possible stall conditions have cleared.
224        if (!fromCommit->commitInfo.stall &&
225            !instQueue.isFull()) {
226            DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n");
227            _status = Unblocking;
228        }
229
230        // If there's still instructions coming from rename, continue to
231        // put them on the skid buffer.
232        if (fromRename->insts[0] != NULL) {
233            block();
234        }
235
236        if (fromCommit->commitInfo.squash ||
237            fromCommit->commitInfo.robSquashing) {
238            squash();
239        }
240    }
241
242    // @todo: Maybe put these at the beginning, so if it's idle it can
243    // return early.
244    // Write back number of free IQ entries here.
245    toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries();
246
247    DPRINTF(IEW, "IEW: IQ has %i free entries.\n",
248            instQueue.numFreeEntries());
249}
250
251template<class Impl, class IQ>
252void
253SimpleIEW<Impl, IQ>::iew()
254{
255    // Might want to put all state checks in the tick() function.
256    // Check if being told to stall from commit.
257    if (fromCommit->commitInfo.stall) {
258        block();
259        return;
260    } else if (fromCommit->commitInfo.squash ||
261               fromCommit->commitInfo.robSquashing) {
262        // Also check if commit is telling this stage to squash.
263        squash();
264        return;
265    }
266
267    ////////////////////////////////////////
268    //ISSUE stage
269    ////////////////////////////////////////
270
271    //Put into its own function?
272    //Add instructions to IQ if there are any instructions there
273
274    // Check if there are any instructions coming from rename, and we're.
275    // not squashing.
276    if (fromRename->insts[0] != NULL && _status != Squashing) {
277
278        // Loop through the instructions, putting them in the instruction
279        // queue.
280        for (int inst_num = 0; inst_num < issueReadWidth; ++inst_num)
281        {
282            DynInst *inst = fromRename->insts[inst_num];
283
284            // Make sure there's a valid instruction there.
285            if (inst == NULL)
286                break;
287
288            DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n",
289                    inst->readPC());
290
291            // If it's a memory reference, don't put it in the
292            // instruction queue.  These will only be executed at commit.
293            // Do the same for nonspeculative instructions and nops.
294            // Be sure to mark these instructions as ready so that the
295            // commit stage can go ahead and execute them, and mark
296            // them as issued so the IQ doesn't reprocess them.
297            if (inst->isMemRef()) {
298                DPRINTF(IEW, "IEW: Issue: Memory instruction "
299                             "encountered, skipping.\n");
300
301                inst->setIssued();
302                inst->setExecuted();
303                inst->setCanCommit();
304
305                instQueue.advanceTail(inst);
306                continue;
307            } else if (inst->isNonSpeculative()) {
308                DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction "
309                        "encountered, skipping.\n");
310
311                inst->setIssued();
312                inst->setExecuted();
313                inst->setCanCommit();
314
315                instQueue.advanceTail(inst);
316                continue;
317            } else if (inst->isNop()) {
318                DPRINTF(IEW, "IEW: Issue: Nop instruction encountered "
319                        ", skipping.\n");
320
321                inst->setIssued();
322                inst->setExecuted();
323                inst->setCanCommit();
324
325                instQueue.advanceTail(inst);
326                continue;
327            } else if (instQueue.isFull()) {
328                DPRINTF(IEW, "IEW: Issue: IQ has become full.\n");
329                // Call function to start blocking.
330                block();
331                // Tell previous stage to stall.
332                toRename->iewInfo.stall = true;
333                break;
334            }
335
336            // If the instruction queue is not full, then add the
337            // instruction.
338            instQueue.insert(fromRename->insts[inst_num]);
339        }
340    }
341
342    // Have the instruction queue try to schedule any ready instructions.
343    instQueue.scheduleReadyInsts();
344
345    ////////////////////////////////////////
346    //EXECUTE/WRITEBACK stage
347    ////////////////////////////////////////
348
349    //Put into its own function?
350    //Similarly should probably have separate execution for int vs FP.
351    // Above comment is handled by the issue queue only issuing a valid
352    // mix of int/fp instructions.
353    //Actually okay to just have one execution, buuuuuut will need
354    //somewhere that defines the execution latency of all instructions.
355    // @todo: Move to the FU pool used in the current full cpu.
356
357    int fu_usage = 0;
358
359    // Execute/writeback any instructions that are available.
360    for (int inst_num = 0;
361         fu_usage < executeWidth && /* Haven't exceeded available FU's. */
362         inst_num < issueWidth && /* Haven't exceeded issue width. */
363         fromIssue->insts[inst_num]; /* There are available instructions. */
364         ++inst_num) {
365        DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n");
366
367        // Get instruction from issue's queue.
368        DynInst *inst = fromIssue->insts[inst_num];
369
370        DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC());
371
372        inst->setExecuted();
373
374        // Check if the instruction is squashed; if so then skip it
375        // and don't count it towards the FU usage.
376        if (inst->isSquashed()) {
377            DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n");
378            continue;
379        }
380
381        // If an instruction is executed, then count it towards FU usage.
382        ++fu_usage;
383
384        // Execute instruction.
385        // Note that if the instruction faults, it will be handled
386        // at the commit stage.
387        inst->execute();
388
389        // First check the time slot that this instruction will write
390        // to.  If there are free write ports at the time, then go ahead
391        // and write the instruction to that time.  If there are not,
392        // keep looking back to see where's the first time there's a
393        // free slot.  What happens if you run out of free spaces?
394        // For now naively assume that all instructions take one cycle.
395        // Otherwise would have to look into the time buffer based on the
396        // latency of the instruction.
397
398        // Add finished instruction to queue to commit.
399        toCommit->insts[inst_num] = inst;
400
401        // Check if branch was correct.  This check happens after the
402        // instruction is added to the queue because even if the branch
403        // is mispredicted, the branch instruction itself is still valid.
404        if (inst->mispredicted()) {
405            DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n");
406            DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n",
407                    inst->nextPC);
408
409            // If incorrect, then signal the ROB that it must be squashed.
410            squash(inst);
411
412            // Not sure it really needs to break.
413//            break;
414        }
415    }
416
417    // Loop through the head of the time buffer and wake any dependents.
418    // These instructions are about to write back.  In the simple model
419    // this loop can really happen within the previous loop, but when
420    // instructions have actual latencies, this loop must be separate.
421    // Also mark scoreboard that this instruction is finally complete.
422    // Either have IEW have direct access to rename map, or have this as
423    // part of backwards communication.
424    for (int inst_num = 0; inst_num < executeWidth &&
425             toCommit->insts[inst_num] != NULL; inst_num++)
426    {
427        DynInst *inst = toCommit->insts[inst_num];
428
429        DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n",
430                inst->readPC());
431
432        instQueue.wakeDependents(inst);
433
434        for (int i = 0; i < inst->numDestRegs(); i++)
435        {
436            renameMap->markAsReady(inst->renamedDestRegIdx(i));
437        }
438    }
439
440    // Also should advance its own time buffers if the stage ran.
441    // Not the best place for it, but this works (hopefully).
442    issueToExecQueue.advance();
443}
444