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