rename_impl.hh revision 1061
1#include <list>
2
3#include "cpu/beta_cpu/rename.hh"
4
5template <class Impl>
6SimpleRename<Impl>::SimpleRename(Params &params)
7    : iewToRenameDelay(params.iewToRenameDelay),
8      decodeToRenameDelay(params.decodeToRenameDelay),
9      commitToRenameDelay(params.commitToRenameDelay),
10      renameWidth(params.renameWidth),
11      commitWidth(params.commitWidth),
12      numInst(0)
13{
14    _status = Idle;
15}
16
17template <class Impl>
18void
19SimpleRename<Impl>::setCPU(FullCPU *cpu_ptr)
20{
21    DPRINTF(Rename, "Rename: Setting CPU pointer.\n");
22    cpu = cpu_ptr;
23}
24
25template <class Impl>
26void
27SimpleRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
28{
29    DPRINTF(Rename, "Rename: Setting time buffer pointer.\n");
30    timeBuffer = tb_ptr;
31
32    // Setup wire to read information from time buffer, from IEW stage.
33    fromIEW = timeBuffer->getWire(-iewToRenameDelay);
34
35    // Setup wire to read infromation from time buffer, from commit stage.
36    fromCommit = timeBuffer->getWire(-commitToRenameDelay);
37
38    // Setup wire to write information to previous stages.
39    toDecode = timeBuffer->getWire(0);
40}
41
42template <class Impl>
43void
44SimpleRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
45{
46    DPRINTF(Rename, "Rename: Setting rename queue pointer.\n");
47    renameQueue = rq_ptr;
48
49    // Setup wire to write information to future stages.
50    toIEW = renameQueue->getWire(0);
51}
52
53template <class Impl>
54void
55SimpleRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
56{
57    DPRINTF(Rename, "Rename: Setting decode queue pointer.\n");
58    decodeQueue = dq_ptr;
59
60    // Setup wire to get information from decode.
61    fromDecode = decodeQueue->getWire(-decodeToRenameDelay);
62
63}
64
65template <class Impl>
66void
67SimpleRename<Impl>::setRenameMap(RenameMap *rm_ptr)
68{
69    DPRINTF(Rename, "Rename: Setting rename map pointer.\n");
70    renameMap = rm_ptr;
71}
72
73template <class Impl>
74void
75SimpleRename<Impl>::setFreeList(FreeList *fl_ptr)
76{
77    DPRINTF(Rename, "Rename: Setting free list pointer.\n");
78    freeList = fl_ptr;
79}
80
81template <class Impl>
82void
83SimpleRename<Impl>::dumpHistory()
84{
85    typename list<RenameHistory>::iterator buf_it = historyBuffer.begin();
86
87    while (buf_it != historyBuffer.end())
88    {
89        cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys "
90                "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg,
91                (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg);
92
93        buf_it++;
94    }
95}
96
97template <class Impl>
98void
99SimpleRename<Impl>::block()
100{
101    DPRINTF(Rename, "Rename: Blocking.\n");
102    // Set status to Blocked.
103    _status = Blocked;
104
105    // Add the current inputs onto the skid buffer, so they can be
106    // reprocessed when this stage unblocks.
107    skidBuffer.push(*fromDecode);
108
109    // Note that this stage only signals previous stages to stall when
110    // it is the cause of the stall originates at this stage.  Otherwise
111    // the previous stages are expected to check all possible stall signals.
112}
113
114template <class Impl>
115inline void
116SimpleRename<Impl>::unblock()
117{
118    DPRINTF(Rename, "Rename: Read instructions out of skid buffer this "
119            "cycle.\n");
120    // Remove the now processed instructions from the skid buffer.
121    skidBuffer.pop();
122
123    // If there's still information in the skid buffer, then
124    // continue to tell previous stages to stall.  They will be
125    // able to restart once the skid buffer is empty.
126    if (!skidBuffer.empty()) {
127                toDecode->renameInfo.stall = true;
128    } else {
129        DPRINTF(Rename, "Rename: Done unblocking.\n");
130        _status = Running;
131    }
132}
133
134template <class Impl>
135void
136SimpleRename<Impl>::doSquash()
137{
138    typename list<RenameHistory>::iterator hb_it = historyBuffer.begin();
139//    typename list<RenameHistory>::iterator delete_it;
140
141    InstSeqNum squashed_seq_num = fromCommit->commitInfo.doneSeqNum;
142
143#ifdef FULL_SYSTEM
144    assert(!historyBuffer.empty());
145#else
146    // After a syscall squashes everything, the history buffer may be empty
147    // but the ROB may still be squashing instructions.
148    if (historyBuffer.empty()) {
149        return;
150    }
151#endif // FULL_SYSTEM
152
153    // Go through the most recent instructions, undoing the mappings
154    // they did and freeing up the registers.
155    while ((*hb_it).instSeqNum > squashed_seq_num)
156    {
157        DPRINTF(Rename, "Rename: Removing history entry with sequence "
158                "number %i.\n", (*hb_it).instSeqNum);
159
160        // If it's not simply a place holder, then add the registers.
161        if (!(*hb_it).placeHolder) {
162            // Tell the rename map to set the architected register to the
163            // previous physical register that it was renamed to.
164            renameMap->setEntry(hb_it->archReg, hb_it->prevPhysReg);
165
166            // Put the renamed physical register back on the free list.
167            freeList->addReg(hb_it->newPhysReg);
168        }
169
170//        delete_it = hb_it;
171
172//        hb_it++;
173
174        historyBuffer.erase(hb_it++);
175
176        assert(hb_it != historyBuffer.end());
177    }
178}
179
180template <class Impl>
181void
182SimpleRename<Impl>::squash()
183{
184    DPRINTF(Rename, "Rename: Squashing instructions.\n");
185    // Set the status to Squashing.
186    _status = Squashing;
187
188    numInst = 0;
189
190    // Clear the skid buffer in case it has any data in it.
191    while (!skidBuffer.empty())
192    {
193        skidBuffer.pop();
194    }
195
196    doSquash();
197}
198
199// In the future, when a SmartPtr is used for DynInst, then this function
200// itself can handle returning the instruction's physical registers to
201// the free list.
202template<class Impl>
203void
204SimpleRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num)
205{
206    DPRINTF(Rename, "Rename: Removing a committed instruction from the "
207            "history buffer, until sequence number %lli.\n", inst_seq_num);
208    typename list<RenameHistory>::iterator hb_it = historyBuffer.end();
209
210    --hb_it;
211
212    if (hb_it->instSeqNum > inst_seq_num) {
213        DPRINTF(Rename, "Rename: Old sequence number encountered.  Ensure "
214                "that a syscall happened recently.\n");
215        return;
216    }
217
218    while ((*hb_it).instSeqNum != inst_seq_num)
219    {
220        // Make sure we haven't gone off the end of the list.
221        assert(hb_it != historyBuffer.end());
222
223        // In theory instructions at the end of the history buffer
224        // should be older than the instruction being removed, which
225        // means they will have a lower sequence number.  Also the
226        // instruction being removed from the history really should
227        // be the last instruction in the list, as it is the instruction
228        // that was just committed that is being removed.
229        assert(hb_it->instSeqNum < inst_seq_num);
230        DPRINTF(Rename, "Rename: Freeing up older rename of reg %i, sequence"
231                " number %i.\n",
232                (*hb_it).prevPhysReg, (*hb_it).instSeqNum);
233
234        if (!(*hb_it).placeHolder) {
235            freeList->addReg((*hb_it).prevPhysReg);
236        }
237
238        historyBuffer.erase(hb_it--);
239    }
240
241    // Finally free up the previous register of the squashed instruction
242    // itself.
243    if (!(*hb_it).placeHolder) {
244        freeList->addReg(hb_it->prevPhysReg);
245    }
246
247    historyBuffer.erase(hb_it);
248
249}
250
251template <class Impl>
252inline void
253SimpleRename<Impl>::renameSrcRegs(DynInstPtr &inst)
254{
255    unsigned num_src_regs = inst->numSrcRegs();
256
257    // Get the architectual register numbers from the source and
258    // destination operands, and redirect them to the right register.
259    // Will need to mark dependencies though.
260    for (int src_idx = 0; src_idx < num_src_regs; src_idx++)
261    {
262        RegIndex src_reg = inst->srcRegIdx(src_idx);
263
264        // Look up the source registers to get the phys. register they've
265        // been renamed to, and set the sources to those registers.
266        RegIndex renamed_reg = renameMap->lookup(src_reg);
267
268        DPRINTF(Rename, "Rename: Looking up arch reg %i, got "
269                "physical reg %i.\n", (int)src_reg, (int)renamed_reg);
270
271        inst->renameSrcReg(src_idx, renamed_reg);
272
273        // Either incorporate it into the info passed back,
274        // or make another function call to see if that register is
275        // ready or not.
276        if (renameMap->isReady(renamed_reg)) {
277            DPRINTF(Rename, "Rename: Register is ready.\n");
278
279            inst->markSrcRegReady(src_idx);
280        }
281    }
282}
283
284template <class Impl>
285inline void
286SimpleRename<Impl>::renameDestRegs(DynInstPtr &inst)
287{
288    typename SimpleRenameMap::RenameInfo rename_result;
289
290    unsigned num_dest_regs = inst->numDestRegs();
291
292    // Rename the destination registers.
293    for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++)
294    {
295        RegIndex dest_reg = inst->destRegIdx(dest_idx);
296
297        // Get the physical register that the destination will be
298        // renamed to.
299        rename_result = renameMap->rename(dest_reg);
300
301        DPRINTF(Rename, "Rename: Renaming arch reg %i to physical "
302                "reg %i.\n", (int)dest_reg,
303                (int)rename_result.first);
304
305        // Record the rename information so that a history can be kept.
306        RenameHistory hb_entry(inst->seqNum, dest_reg,
307                               rename_result.first,
308                               rename_result.second);
309
310        historyBuffer.push_front(hb_entry);
311
312        DPRINTF(Rename, "Rename: Adding instruction to history buffer, "
313                "sequence number %lli.\n",
314                (*historyBuffer.begin()).instSeqNum);
315
316        // Tell the instruction to rename the appropriate destination
317        // register (dest_idx) to the new physical register
318        // (rename_result.first), and record the previous physical
319        // register that the same logical register was renamed to
320        // (rename_result.second).
321        inst->renameDestReg(dest_idx,
322                            rename_result.first,
323                            rename_result.second);
324    }
325
326    // If it's an instruction with no destination registers, then put
327    // a placeholder within the history buffer.  It might be better
328    // to not put it in the history buffer at all (other than branches,
329    // which always need at least a place holder), and differentiate
330    // between instructions with and without destination registers
331    // when getting from commit the instructions that committed.
332    if (num_dest_regs == 0) {
333        RenameHistory hb_entry(inst->seqNum);
334
335        historyBuffer.push_front(hb_entry);
336
337        DPRINTF(Rename, "Rename: Adding placeholder instruction to "
338                "history buffer, sequence number %lli.\n",
339                inst->seqNum);
340    }
341}
342
343template <class Impl>
344inline int
345SimpleRename<Impl>::calcFreeROBEntries()
346{
347    return fromCommit->commitInfo.freeROBEntries -
348        renameWidth * iewToRenameDelay;
349}
350
351template <class Impl>
352inline int
353SimpleRename<Impl>::calcFreeIQEntries()
354{
355    return fromIEW->iewInfo.freeIQEntries - renameWidth * iewToRenameDelay;
356}
357
358template<class Impl>
359void
360SimpleRename<Impl>::tick()
361{
362    // Rename will need to try to rename as many instructions as it
363    // has bandwidth, unless it is blocked.
364
365    // Check if _status is BarrierStall.  If so, then check if the number
366    // of free ROB entries is equal to the number of total ROB entries.
367    // Once equal then wake this stage up.  Set status to unblocking maybe.
368
369    if (_status != Blocked && _status != Squashing) {
370        DPRINTF(Rename, "Rename: Status is not blocked, will attempt to "
371                        "run stage.\n");
372        // Make sure that the skid buffer has something in it if the
373        // status is unblocking.
374        assert(_status == Unblocking ? !skidBuffer.empty() : 1);
375
376        rename();
377
378        // If the status was unblocking, then instructions from the skid
379        // buffer were used.  Remove those instructions and handle
380        // the rest of unblocking.
381        if (_status == Unblocking) {
382            if (fromDecode->size > 0) {
383                // Add the current inputs onto the skid buffer, so they can be
384                // reprocessed when this stage unblocks.
385                skidBuffer.push(*fromDecode);
386            }
387
388            unblock();
389        }
390    } else if (_status == Blocked) {
391        // If stage is blocked and still receiving valid instructions,
392        // make sure to store them in the skid buffer.
393        if (fromDecode->size > 0) {
394
395            block();
396
397            // Continue to tell previous stage to stall.
398            toDecode->renameInfo.stall = true;
399        }
400
401        if (!fromIEW->iewInfo.stall &&
402            !fromCommit->commitInfo.stall &&
403            calcFreeROBEntries() > 0 &&
404            calcFreeIQEntries() > 0 &&
405            renameMap->numFreeEntries() > 0) {
406
407            // Need to be sure to check all blocking conditions above.
408            // If they have cleared, then start unblocking.
409            DPRINTF(Rename, "Rename: Stall signals cleared, going to "
410                    "unblock.\n");
411            _status = Unblocking;
412
413            // Continue to tell previous stage to block until this stage
414            // is done unblocking.
415            toDecode->renameInfo.stall = true;
416        } else {
417            // Otherwise no conditions have changed.  Tell previous
418            // stage to continue blocking.
419            toDecode->renameInfo.stall = true;
420        }
421
422        if (fromCommit->commitInfo.squash ||
423            fromCommit->commitInfo.robSquashing) {
424            squash();
425            return;
426        }
427    } else if (_status == Squashing) {
428        if (fromCommit->commitInfo.squash) {
429            squash();
430        } else if (!fromCommit->commitInfo.squash &&
431                   !fromCommit->commitInfo.robSquashing) {
432
433            DPRINTF(Rename, "Rename: Done squashing, going to running.\n");
434            _status = Running;
435        } else {
436            doSquash();
437        }
438    }
439
440    // Ugly code, revamp all of the tick() functions eventually.
441    if (fromCommit->commitInfo.doneSeqNum != 0 && _status != Squashing) {
442        removeFromHistory(fromCommit->commitInfo.doneSeqNum);
443    }
444
445    // Perhaps put this outside of this function, since this will
446    // happen regardless of whether or not the stage is blocked or
447    // squashing.
448    // Read from the time buffer any necessary data.
449    // Read registers that are freed, and add them to the freelist.
450    // This is unnecessary due to the history buffer (assuming the history
451    // buffer works properly).
452/*
453    while(!fromCommit->commitInfo.freeRegs.empty())
454    {
455        PhysRegIndex freed_reg = fromCommit->commitInfo.freeRegs.back();
456        DPRINTF(Rename, "Rename: Adding freed register %i to freelist.\n",
457                (int)freed_reg);
458        freeList->addReg(freed_reg);
459
460        fromCommit->commitInfo.freeRegs.pop_back();
461    }
462*/
463
464}
465
466template<class Impl>
467void
468SimpleRename<Impl>::rename()
469{
470    // Check if any of the stages ahead of rename are telling rename
471    // to squash.  The squash() function will also take care of fixing up
472    // the rename map and the free list.
473    if (fromCommit->commitInfo.squash ||
474        fromCommit->commitInfo.robSquashing) {
475        DPRINTF(Rename, "Rename: Receiving signal from Commit to squash.\n");
476        squash();
477        return;
478    }
479
480    // Check if time buffer is telling this stage to stall.
481    if (fromIEW->iewInfo.stall ||
482        fromCommit->commitInfo.stall) {
483        DPRINTF(Rename, "Rename: Receiving signal from IEW/Commit to "
484                        "stall.\n");
485        block();
486        return;
487    }
488
489    // Check if the current status is squashing.  If so, set its status
490    // to running and resume execution the next cycle.
491    if (_status == Squashing) {
492        DPRINTF(Rename, "Rename: Done squashing.\n");
493        _status = Running;
494        return;
495    }
496
497    // Check the decode queue to see if instructions are available.
498    // If there are no available instructions to rename, then do nothing.
499    // Or, if the stage is currently unblocking, then go ahead and run it.
500    if (fromDecode->size == 0 && _status != Unblocking) {
501        DPRINTF(Rename, "Rename: Nothing to do, breaking out early.\n");
502        // Should I change status to idle?
503        return;
504    }
505
506    ////////////////////////////////////
507    // Actual rename part.
508    ////////////////////////////////////
509
510    DynInstPtr inst;
511
512    // If we're unblocking, then we may be in the middle of an instruction
513    // group.  Subtract off numInst to get the proper number of instructions
514    // left.
515    int insts_available = _status == Unblocking ?
516        skidBuffer.front().size - numInst :
517        fromDecode->size;
518
519    bool block_this_cycle = false;
520
521    // Will have to do a different calculation for the number of free
522    // entries.  Number of free entries recorded on this cycle -
523    // renameWidth * renameToDecodeDelay
524    int free_rob_entries = calcFreeROBEntries();
525    int free_iq_entries = calcFreeIQEntries();
526    int min_iq_rob = min(free_rob_entries, free_iq_entries);
527
528    unsigned to_iew_index = 0;
529
530    // Check if there's any space left.
531    if (min_iq_rob <= 0) {
532        DPRINTF(Rename, "Rename: Blocking due to no free ROB or IQ "
533                "entries.\n"
534                "Rename: ROB has %d free entries.\n"
535                "Rename: IQ has %d free entries.\n",
536                free_rob_entries,
537                free_iq_entries);
538        block();
539        // Tell previous stage to stall.
540        toDecode->renameInfo.stall = true;
541
542        return;
543    } else if (min_iq_rob < insts_available) {
544        DPRINTF(Rename, "Rename: Will have to block this cycle.  Only "
545                "%i insts can be renamed due to IQ/ROB limits.\n",
546                min_iq_rob);
547
548        insts_available = min_iq_rob;
549
550        block_this_cycle = true;
551    }
552
553    while (insts_available > 0) {
554        DPRINTF(Rename, "Rename: Sending instructions to iew.\n");
555
556        // Get the next instruction either from the skid buffer or the
557        // decode queue.
558        inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
559               fromDecode->insts[numInst];
560
561        if (inst->isSquashed()) {
562            DPRINTF(Rename, "Rename: instruction %i with PC %#x is "
563                    "squashed, skipping.\n",
564                    inst->seqNum, inst->readPC());
565
566            // Go to the next instruction.
567            ++numInst;
568
569            // Decrement how many instructions are available.
570            --insts_available;
571
572            continue;
573        }
574
575        DPRINTF(Rename, "Rename: Processing instruction %i with PC %#x.\n",
576                inst->seqNum, inst->readPC());
577
578        // If it's a trap instruction, then it needs to wait here within
579        // rename until the ROB is empty.  Needs a way to detect that the
580        // ROB is empty.  Maybe an event?
581        // Would be nice if it could be avoided putting this into a
582        // specific stage and instead just put it into the AlphaFullCPU.
583        // Might not really be feasible though...
584        // (EXCB, TRAPB)
585        if (inst->isSerializing()) {
586            panic("Rename: Serializing instruction encountered.\n");
587            DPRINTF(Rename, "Rename: Serializing instruction "
588                            "encountered.\n");
589
590            // Change status over to BarrierStall so that other stages know
591            // what this is blocked on.
592            _status = BarrierStall;
593
594            block_this_cycle = true;
595
596            break;
597        }
598
599        // Check here to make sure there are enough destination registers
600        // to rename to.  Otherwise block.
601        if (renameMap->numFreeEntries() < inst->numDestRegs())
602        {
603            DPRINTF(Rename, "Rename: Blocking due to lack of free "
604                            "physical registers to rename to.\n");
605            // Need some sort of event based on a register being freed.
606
607            block_this_cycle = true;
608
609            break;
610        }
611
612        renameSrcRegs(inst);
613
614        renameDestRegs(inst);
615
616        // Put instruction in rename queue.
617        toIEW->insts[to_iew_index] = inst;
618        ++(toIEW->size);
619
620        // Decrease the number of free ROB and IQ entries.
621        --free_rob_entries;
622        --free_iq_entries;
623
624        // Increment which instruction we're on.
625        ++to_iew_index;
626        ++numInst;
627
628        // Decrement how many instructions are available.
629        --insts_available;
630    }
631
632    // Check if there's any instructions left that haven't yet been renamed.
633    // If so then block.
634    if (block_this_cycle) {
635        block();
636
637        toDecode->renameInfo.stall = true;
638    } else {
639        // If we had a successful rename and didn't have to exit early, then
640        // reset numInst so it will refer to the correct instruction on next
641        // run.
642        numInst = 0;
643    }
644}
645