inst_queue_impl.hh revision 1060
1#ifndef __INST_QUEUE_IMPL_HH__
2#define __INST_QUEUE_IMPL_HH__
3
4// Todo: Fix up consistency errors about back of the ready list being
5// the oldest instructions in the queue.  When woken up from the dependency
6// graph they will be the oldest, but when they are immediately executable
7// newer instructions will mistakenly get inserted onto the back.  Also
8// current ordering allows for 0 cycle added-to-scheduled.  Could maybe fake
9// it; either do in reverse order, or have added instructions put into a
10// different ready queue that, in scheduleRreadyInsts(), gets put onto the
11// normal ready queue.  This would however give only a one cycle delay,
12// but probably is more flexible to actually add in a delay parameter than
13// just running it backwards.
14
15#include <vector>
16
17#include "sim/universe.hh"
18#include "cpu/beta_cpu/inst_queue.hh"
19
20// Either compile error or max int due to sign extension.
21// Blatant hack to avoid compile warnings.
22const InstSeqNum MaxInstSeqNum = 0 - 1;
23
24template<class Impl>
25InstructionQueue<Impl>::InstructionQueue(Params &params)
26    : numEntries(params.numIQEntries),
27      intWidth(params.executeIntWidth),
28      floatWidth(params.executeFloatWidth),
29      numPhysIntRegs(params.numPhysIntRegs),
30      numPhysFloatRegs(params.numPhysFloatRegs),
31      commitToIEWDelay(params.commitToIEWDelay)
32{
33    // HACK: HARDCODED NUMBER.  REMOVE LATER AND ADD TO PARAMETER.
34    totalWidth = 1;
35    branchWidth = 1;
36    DPRINTF(IQ, "IQ: Int width is %i.\n", params.executeIntWidth);
37
38    // Initialize the number of free IQ entries.
39    freeEntries = numEntries;
40
41    // Set the number of physical registers as the number of int + float
42    numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
43
44    DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs);
45
46    //Create an entry for each physical register within the
47    //dependency graph.
48    dependGraph = new DependencyEntry[numPhysRegs];
49
50    // Resize the register scoreboard.
51    regScoreboard.resize(numPhysRegs);
52
53    // Initialize all the head pointers to point to NULL, and all the
54    // entries as unready.
55    // Note that in actuality, the registers corresponding to the logical
56    // registers start off as ready.  However this doesn't matter for the
57    // IQ as the instruction should have been correctly told if those
58    // registers are ready in rename.  Thus it can all be initialized as
59    // unready.
60    for (int i = 0; i < numPhysRegs; ++i)
61    {
62        dependGraph[i].next = NULL;
63        dependGraph[i].inst = NULL;
64        regScoreboard[i] = false;
65    }
66
67}
68
69template<class Impl>
70void
71InstructionQueue<Impl>::setCPU(FullCPU *cpu_ptr)
72{
73    cpu = cpu_ptr;
74
75    tail = cpu->instList.begin();
76}
77
78template<class Impl>
79void
80InstructionQueue<Impl>::setIssueToExecuteQueue(
81                        TimeBuffer<IssueStruct> *i2e_ptr)
82{
83    DPRINTF(IQ, "IQ: Set the issue to execute queue.\n");
84    issueToExecuteQueue = i2e_ptr;
85}
86
87template<class Impl>
88void
89InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
90{
91    DPRINTF(IQ, "IQ: Set the time buffer.\n");
92    timeBuffer = tb_ptr;
93
94    fromCommit = timeBuffer->getWire(-commitToIEWDelay);
95}
96
97// Might want to do something more complex if it knows how many instructions
98// will be issued this cycle.
99template<class Impl>
100bool
101InstructionQueue<Impl>::isFull()
102{
103    if (freeEntries == 0) {
104        return(true);
105    } else {
106        return(false);
107    }
108}
109
110template<class Impl>
111unsigned
112InstructionQueue<Impl>::numFreeEntries()
113{
114    return freeEntries;
115}
116
117template<class Impl>
118void
119InstructionQueue<Impl>::insert(DynInst *new_inst)
120{
121    // Make sure the instruction is valid
122    assert(new_inst);
123
124    DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
125            new_inst->readPC());
126
127    // Check if there are any free entries.  Panic if there are none.
128    // Might want to have this return a fault in the future instead of
129    // panicing.
130    assert(freeEntries != 0);
131
132    // If the IQ currently has nothing in it, then there's a possibility
133    // that the tail iterator is invalid (might have been pointing at an
134    // instruction that was retired).  Reset the tail iterator.
135    if (freeEntries == numEntries) {
136        tail = cpu->instList.begin();
137    }
138
139    // Move the tail iterator.  Instructions may not have been issued
140    // to the IQ, so we may have to increment the iterator more than once.
141    while ((*tail) != new_inst) {
142        tail++;
143
144        // Make sure the tail iterator points at something legal.
145        assert(tail != cpu->instList.end());
146    }
147
148
149    // Decrease the number of free entries.
150    --freeEntries;
151
152    // Look through its source registers (physical regs), and mark any
153    // dependencies.
154    addToDependents(new_inst);
155
156    // Have this instruction set itself as the producer of its destination
157    // register(s).
158    createDependency(new_inst);
159
160    // If the instruction is ready then add it to the ready list.
161    addIfReady(new_inst);
162
163    assert(freeEntries == (numEntries - countInsts()));
164}
165
166// Slightly hack function to advance the tail iterator in the case that
167// the IEW stage issues an instruction that is not added to the IQ.  This
168// is needed in case a long chain of such instructions occurs.
169template<class Impl>
170void
171InstructionQueue<Impl>::advanceTail(DynInst *inst)
172{
173    // Make sure the instruction is valid
174    assert(inst);
175
176    DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
177            inst->readPC());
178
179    // Check if there are any free entries.  Panic if there are none.
180    // Might want to have this return a fault in the future instead of
181    // panicing.
182    assert(freeEntries != 0);
183
184    // If the IQ currently has nothing in it, then there's a possibility
185    // that the tail iterator is invalid (might have been pointing at an
186    // instruction that was retired).  Reset the tail iterator.
187    if (freeEntries == numEntries) {
188        tail = cpu->instList.begin();
189    }
190
191    // Move the tail iterator.  Instructions may not have been issued
192    // to the IQ, so we may have to increment the iterator more than once.
193    while ((*tail) != inst) {
194        tail++;
195
196        // Make sure the tail iterator points at something legal.
197        assert(tail != cpu->instList.end());
198    }
199
200    assert(freeEntries <= numEntries);
201
202    // Have this instruction set itself as the producer of its destination
203    // register(s).
204    createDependency(inst);
205}
206
207// Need to make sure the number of float and integer instructions
208// issued does not exceed the total issue bandwidth.  Probably should
209// have some sort of limit of total number of branches that can be issued
210// as well.
211template<class Impl>
212void
213InstructionQueue<Impl>::scheduleReadyInsts()
214{
215    DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from "
216                "the IQ.\n");
217
218    int int_issued = 0;
219    int float_issued = 0;
220    int branch_issued = 0;
221    int squashed_issued = 0;
222    int total_issued = 0;
223
224    IssueStruct *i2e_info = issueToExecuteQueue->access(0);
225
226    bool insts_available = !readyBranchInsts.empty() ||
227        !readyIntInsts.empty() ||
228        !readyFloatInsts.empty() ||
229        !squashedInsts.empty();
230
231    // Note: Requires a globally defined constant.
232    InstSeqNum oldest_inst = MaxInstSeqNum;
233    InstList list_with_oldest = None;
234
235    // Temporary values.
236    DynInst *int_head_inst;
237    DynInst *float_head_inst;
238    DynInst *branch_head_inst;
239    DynInst *squashed_head_inst;
240
241    // Somewhat nasty code to look at all of the lists where issuable
242    // instructions are located, and choose the oldest instruction among
243    // those lists.  Consider a rewrite in the future.
244    while (insts_available && total_issued < totalWidth)
245    {
246        // Set this to false.  Each if-block is required to set it to true
247        // if there were instructions available this check.  This will cause
248        // this loop to run once more than necessary, but avoids extra calls.
249        insts_available = false;
250
251        oldest_inst = MaxInstSeqNum;
252
253        list_with_oldest = None;
254
255        if (!readyIntInsts.empty() &&
256            int_issued < intWidth) {
257
258            insts_available = true;
259
260            int_head_inst = readyIntInsts.top().inst;
261
262            if (int_head_inst->isSquashed()) {
263                readyIntInsts.pop();
264                continue;
265            }
266
267            oldest_inst = int_head_inst->seqNum;
268
269            list_with_oldest = Int;
270        }
271
272        if (!readyFloatInsts.empty() &&
273            float_issued < floatWidth) {
274
275            insts_available = true;
276
277            float_head_inst = readyFloatInsts.top().inst;
278
279            if (float_head_inst->isSquashed()) {
280                readyFloatInsts.pop();
281                continue;
282            } else if (float_head_inst->seqNum < oldest_inst) {
283                oldest_inst = float_head_inst->seqNum;
284
285                list_with_oldest = Float;
286            }
287        }
288
289        if (!readyBranchInsts.empty() &&
290            branch_issued < branchWidth) {
291
292            insts_available = true;
293
294            branch_head_inst = readyBranchInsts.top().inst;
295
296            if (branch_head_inst->isSquashed()) {
297                readyBranchInsts.pop();
298                continue;
299            } else if (branch_head_inst->seqNum < oldest_inst) {
300                oldest_inst = branch_head_inst->seqNum;
301
302                list_with_oldest = Branch;
303            }
304
305        }
306
307        if (!squashedInsts.empty()) {
308
309            insts_available = true;
310
311            squashed_head_inst = squashedInsts.top().inst;
312
313            if (squashed_head_inst->seqNum < oldest_inst) {
314                list_with_oldest = Squashed;
315            }
316
317        }
318
319        DynInst *issuing_inst = NULL;
320
321        switch (list_with_oldest) {
322          case None:
323            DPRINTF(IQ, "IQ: Not able to schedule any instructions. Issuing "
324                    "inst is %#x.\n", issuing_inst);
325            break;
326          case Int:
327            issuing_inst = int_head_inst;
328            readyIntInsts.pop();
329            ++int_issued;
330            DPRINTF(IQ, "IQ: Issuing integer instruction PC %#x.\n",
331                    issuing_inst->readPC());
332            break;
333          case Float:
334            issuing_inst = float_head_inst;
335            readyFloatInsts.pop();
336            ++float_issued;
337            DPRINTF(IQ, "IQ: Issuing float instruction PC %#x.\n",
338                    issuing_inst->readPC());
339            break;
340          case Branch:
341            issuing_inst = branch_head_inst;
342            readyBranchInsts.pop();
343            ++branch_issued;
344            DPRINTF(IQ, "IQ: Issuing branch instruction PC %#x.\n",
345                    issuing_inst->readPC());
346            break;
347          case Squashed:
348            issuing_inst = squashed_head_inst;
349            squashedInsts.pop();
350            ++squashed_issued;
351            DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n",
352                    issuing_inst->readPC());
353            break;
354        }
355
356        if (list_with_oldest != None) {
357            i2e_info->insts[total_issued] = issuing_inst;
358
359            issuing_inst->setIssued();
360
361            ++freeEntries;
362            ++total_issued;
363        }
364
365        assert(freeEntries == (numEntries - countInsts()));
366    }
367}
368
369template<class Impl>
370void
371InstructionQueue<Impl>::doSquash()
372{
373    // Make sure the squash iterator isn't pointing to nothing.
374    assert(squashIt != cpu->instList.end());
375    // Make sure the squashed sequence number is valid.
376    assert(squashedSeqNum != 0);
377
378    DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n");
379
380    // Squash any instructions younger than the squashed sequence number
381    // given.
382    while ((*squashIt)->seqNum > squashedSeqNum) {
383        DynInst *squashed_inst = (*squashIt);
384
385        // Only handle the instruction if it actually is in the IQ and
386        // hasn't already been squashed in the IQ.
387        if (!squashed_inst->isIssued() &&
388            !squashed_inst->isSquashedInIQ()) {
389            // Remove the instruction from the dependency list.
390            int8_t total_src_regs = squashed_inst->numSrcRegs();
391
392            for (int src_reg_idx = 0;
393                 src_reg_idx < total_src_regs;
394                 src_reg_idx++)
395            {
396                // Only remove it from the dependency graph if it was
397                // placed there in the first place.
398                // HACK: This assumes that instructions woken up from the
399                // dependency chain aren't informed that a specific src
400                // register has become ready.  This may not always be true
401                // in the future.
402                if (!squashed_inst->isReadySrcRegIdx(src_reg_idx)) {
403                    int8_t src_reg =
404                        squashed_inst->renamedSrcRegIdx(src_reg_idx);
405                    dependGraph[src_reg].remove(squashed_inst);
406                }
407            }
408
409            // Mark it as squashed within the IQ.
410            squashed_inst->setSquashedInIQ();
411
412            ReadyEntry temp(squashed_inst);
413
414            squashedInsts.push(temp);
415
416            DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n",
417                    squashed_inst->readPC());
418        }
419        squashIt--;
420    }
421}
422
423template<class Impl>
424void
425InstructionQueue<Impl>::squash()
426{
427    DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n");
428
429    // Read instruction sequence number of last instruction out of the
430    // time buffer.
431    squashedSeqNum = fromCommit->commitInfo.doneSeqNum;
432
433    // Setup the squash iterator to point to the tail.
434    squashIt = tail;
435
436    // Call doSquash.
437    doSquash();
438}
439
440template<class Impl>
441void
442InstructionQueue<Impl>::stopSquash()
443{
444    // Clear up the squash variables to ensure that squashing doesn't
445    // get called improperly.
446    squashedSeqNum = 0;
447
448    squashIt = cpu->instList.end();
449}
450
451template<class Impl>
452int
453InstructionQueue<Impl>::countInsts()
454{
455    ListIt count_it = cpu->instList.begin();
456    int total_insts = 0;
457
458    while (count_it != tail) {
459        if (!(*count_it)->isIssued()) {
460            ++total_insts;
461        }
462
463        count_it++;
464
465        assert(count_it != cpu->instList.end());
466    }
467
468    // Need to count the tail iterator as well.
469    if (count_it != cpu->instList.end() &&
470        (*count_it) != NULL &&
471        !(*count_it)->isIssued()) {
472        ++total_insts;
473    }
474
475    return total_insts;
476}
477
478template<class Impl>
479void
480InstructionQueue<Impl>::wakeDependents(DynInst *completed_inst)
481{
482    DPRINTF(IQ, "IQ: Waking dependents of completed instruction.\n");
483    //Look at the physical destination register of the DynInst
484    //and look it up on the dependency graph.  Then mark as ready
485    //any instructions within the instruction queue.
486    int8_t total_dest_regs = completed_inst->numDestRegs();
487
488    DependencyEntry *curr;
489
490    for (int dest_reg_idx = 0;
491         dest_reg_idx < total_dest_regs;
492         dest_reg_idx++)
493    {
494        PhysRegIndex dest_reg =
495            completed_inst->renamedDestRegIdx(dest_reg_idx);
496
497        // Special case of uniq or control registers.  They are not
498        // handled by the IQ and thus have no dependency graph entry.
499        // @todo Figure out a cleaner way to handle thie.
500        if (dest_reg >= numPhysRegs) {
501            continue;
502        }
503
504        DPRINTF(IQ, "IQ: Waking any dependents on register %i.\n",
505                (int) dest_reg);
506
507        //Maybe abstract this part into a function.
508        //Go through the dependency chain, marking the registers as ready
509        //within the waiting instructions.
510        while (dependGraph[dest_reg].next != NULL) {
511
512            curr = dependGraph[dest_reg].next;
513
514            DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n",
515                    curr->inst->readPC());
516
517            // Might want to give more information to the instruction
518            // so that it knows which of its source registers is ready.
519            // However that would mean that the dependency graph entries
520            // would need to hold the src_reg_idx.
521            curr->inst->markSrcRegReady();
522
523            addIfReady(curr->inst);
524
525            dependGraph[dest_reg].next = curr->next;
526
527            delete curr;
528        }
529
530        // Reset the head node now that all of its dependents have been woken
531        // up.
532        dependGraph[dest_reg].next = NULL;
533        dependGraph[dest_reg].inst = NULL;
534
535        // Mark the scoreboard as having that register ready.
536        regScoreboard[dest_reg] = true;
537    }
538}
539
540template<class Impl>
541bool
542InstructionQueue<Impl>::addToDependents(DynInst *new_inst)
543{
544    // Loop through the instruction's source registers, adding
545    // them to the dependency list if they are not ready.
546    int8_t total_src_regs = new_inst->numSrcRegs();
547    bool return_val = false;
548
549    for (int src_reg_idx = 0;
550         src_reg_idx < total_src_regs;
551         src_reg_idx++)
552    {
553        // Only add it to the dependency graph if it's not ready.
554        if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
555            PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
556
557            // Check the IQ's scoreboard to make sure the register
558            // hasn't become ready while the instruction was in flight
559            // between stages.  Only if it really isn't ready should
560            // it be added to the dependency graph.
561            if (regScoreboard[src_reg] == false) {
562                DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
563                        "is being added to the dependency chain.\n",
564                        new_inst->readPC(), src_reg);
565
566                dependGraph[src_reg].insert(new_inst);
567
568                // Change the return value to indicate that something
569                // was added to the dependency graph.
570                return_val = true;
571            } else {
572                DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
573                        "became ready before it reached the IQ.\n",
574                        new_inst->readPC(), src_reg);
575                // Mark a register ready within the instruction.
576                new_inst->markSrcRegReady();
577            }
578        }
579    }
580
581    return return_val;
582}
583
584template<class Impl>
585void
586InstructionQueue<Impl>::createDependency(DynInst *new_inst)
587{
588    //Actually nothing really needs to be marked when an
589    //instruction becomes the producer of a register's value,
590    //but for convenience a ptr to the producing instruction will
591    //be placed in the head node of the dependency links.
592    int8_t total_dest_regs = new_inst->numDestRegs();
593
594    for (int dest_reg_idx = 0;
595         dest_reg_idx < total_dest_regs;
596         dest_reg_idx++)
597    {
598        int8_t dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
599        dependGraph[dest_reg].inst = new_inst;
600        if (dependGraph[dest_reg].next != NULL) {
601            panic("Dependency chain is not empty.\n");
602        }
603
604        // Mark the scoreboard to say it's not yet ready.
605        regScoreboard[dest_reg] = false;
606    }
607}
608
609template<class Impl>
610void
611InstructionQueue<Impl>::DependencyEntry::insert(DynInst *new_inst)
612{
613    //Add this new, dependent instruction at the head of the dependency
614    //chain.
615
616    // First create the entry that will be added to the head of the
617    // dependency chain.
618    DependencyEntry *new_entry = new DependencyEntry;
619    new_entry->next = this->next;
620    new_entry->inst = new_inst;
621
622    // Then actually add it to the chain.
623    this->next = new_entry;
624}
625
626template<class Impl>
627void
628InstructionQueue<Impl>::DependencyEntry::remove(DynInst *inst_to_remove)
629{
630    DependencyEntry *prev = this;
631    DependencyEntry *curr = this->next;
632
633    // Make sure curr isn't NULL.  Because this instruction is being
634    // removed from a dependency list, it must have been placed there at
635    // an earlier time.  The dependency chain should not be empty,
636    // unless the instruction dependent upon it is already ready.
637    if (curr == NULL) {
638        return;
639    }
640
641    // Find the instruction to remove within the dependency linked list.
642    while(curr->inst != inst_to_remove)
643    {
644        prev = curr;
645        curr = curr->next;
646    }
647
648    // Now remove this instruction from the list.
649    prev->next = curr->next;
650
651    delete curr;
652}
653
654template<class Impl>
655void
656InstructionQueue<Impl>::addIfReady(DynInst *inst)
657{
658    //If the instruction now has all of its source registers
659    // available, then add it to the list of ready instructions.
660    if (inst->readyToIssue()) {
661        ReadyEntry to_add(inst);
662        //Add the instruction to the proper ready list.
663        if (inst->isInteger()) {
664            DPRINTF(IQ, "IQ: Integer instruction is ready to issue, "
665                    "putting it onto the ready list, PC %#x.\n",
666                    inst->readPC());
667            readyIntInsts.push(to_add);
668        } else if (inst->isFloating()) {
669            DPRINTF(IQ, "IQ: Floating instruction is ready to issue, "
670                    "putting it onto the ready list, PC %#x.\n",
671                    inst->readPC());
672            readyFloatInsts.push(to_add);
673        } else if (inst->isControl()) {
674            DPRINTF(IQ, "IQ: Branch instruction is ready to issue, "
675                    "putting it onto the ready list, PC %#x.\n",
676                    inst->readPC());
677            readyBranchInsts.push(to_add);
678        } else {
679            panic("IQ: Instruction not an expected type.\n");
680        }
681    }
682}
683
684#endif // __INST_QUEUE_IMPL_HH__
685