lsq_unit_impl.hh revision 2292
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/lsq_unit.hh"
30#include "base/str.hh"
31
32template <class Impl>
33LSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx,
34                                                          Event *wb_event,
35                                                          LSQUnit<Impl> *lsq_ptr)
36    : Event(&mainEventQueue),
37      storeIdx(store_idx),
38      wbEvent(wb_event),
39      lsqPtr(lsq_ptr)
40{
41    this->setFlags(Event::AutoDelete);
42}
43
44template <class Impl>
45void
46LSQUnit<Impl>::StoreCompletionEvent::process()
47{
48    DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx);
49    DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx);
50
51    //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
52
53    lsqPtr->cpu->wakeCPU();
54    if (wbEvent)
55        wbEvent->process();
56    lsqPtr->completeStore(storeIdx);
57}
58
59template <class Impl>
60const char *
61LSQUnit<Impl>::StoreCompletionEvent::description()
62{
63    return "LSQ store completion event";
64}
65
66template <class Impl>
67LSQUnit<Impl>::LSQUnit()
68    : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
69      loadBlockedHandled(false)
70{
71}
72
73template<class Impl>
74void
75LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
76                    unsigned maxSQEntries, unsigned id)
77
78{
79    DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
80
81    lsqID = id;
82
83    LQEntries = maxLQEntries;
84    SQEntries = maxSQEntries;
85
86    loadQueue.resize(LQEntries);
87    storeQueue.resize(SQEntries);
88
89
90    // May want to initialize these entries to NULL
91
92    loadHead = loadTail = 0;
93
94    storeHead = storeWBIdx = storeTail = 0;
95
96    usedPorts = 0;
97    cachePorts = params->cachePorts;
98
99    dcacheInterface = params->dcacheInterface;
100
101    loadFaultInst = storeFaultInst = memDepViolator = NULL;
102
103    blockedLoadSeqNum = 0;
104}
105
106template<class Impl>
107std::string
108LSQUnit<Impl>::name() const
109{
110    if (Impl::MaxThreads == 1) {
111        return iewStage->name() + ".lsq";
112    } else {
113        return iewStage->name() + ".lsq.thread." + to_string(lsqID);
114    }
115}
116
117template<class Impl>
118void
119LSQUnit<Impl>::clearLQ()
120{
121    loadQueue.clear();
122}
123
124template<class Impl>
125void
126LSQUnit<Impl>::clearSQ()
127{
128    storeQueue.clear();
129}
130
131#if 0
132template<class Impl>
133void
134LSQUnit<Impl>::setPageTable(PageTable *pt_ptr)
135{
136    DPRINTF(LSQUnit, "Setting the page table pointer.\n");
137    pTable = pt_ptr;
138}
139#endif
140
141template<class Impl>
142void
143LSQUnit<Impl>::resizeLQ(unsigned size)
144{
145    assert( size >= LQEntries);
146
147    if (size > LQEntries) {
148        while (size > loadQueue.size()) {
149            DynInstPtr dummy;
150            loadQueue.push_back(dummy);
151            LQEntries++;
152        }
153    } else {
154        LQEntries = size;
155    }
156
157}
158
159template<class Impl>
160void
161LSQUnit<Impl>::resizeSQ(unsigned size)
162{
163    if (size > SQEntries) {
164        while (size > storeQueue.size()) {
165            SQEntry dummy;
166            storeQueue.push_back(dummy);
167            SQEntries++;
168        }
169    } else {
170        SQEntries = size;
171    }
172}
173
174template <class Impl>
175void
176LSQUnit<Impl>::insert(DynInstPtr &inst)
177{
178    // Make sure we really have a memory reference.
179    assert(inst->isMemRef());
180
181    // Make sure it's one of the two classes of memory references.
182    assert(inst->isLoad() || inst->isStore());
183
184    if (inst->isLoad()) {
185        insertLoad(inst);
186    } else {
187        insertStore(inst);
188    }
189
190    inst->setInLSQ();
191}
192
193template <class Impl>
194void
195LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
196{
197    assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries);
198
199    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
200            load_inst->readPC(), loadTail, load_inst->seqNum);
201
202    load_inst->lqIdx = loadTail;
203
204    if (stores == 0) {
205        load_inst->sqIdx = -1;
206    } else {
207        load_inst->sqIdx = storeTail;
208    }
209
210    loadQueue[loadTail] = load_inst;
211
212    incrLdIdx(loadTail);
213
214    ++loads;
215}
216
217template <class Impl>
218void
219LSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
220{
221    // Make sure it is not full before inserting an instruction.
222    assert((storeTail + 1) % SQEntries != storeHead);
223    assert(stores < SQEntries);
224
225    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
226            store_inst->readPC(), storeTail, store_inst->seqNum);
227
228    store_inst->sqIdx = storeTail;
229    store_inst->lqIdx = loadTail;
230
231    storeQueue[storeTail] = SQEntry(store_inst);
232
233    incrStIdx(storeTail);
234
235    ++stores;
236
237}
238
239template <class Impl>
240typename Impl::DynInstPtr
241LSQUnit<Impl>::getMemDepViolator()
242{
243    DynInstPtr temp = memDepViolator;
244
245    memDepViolator = NULL;
246
247    return temp;
248}
249
250template <class Impl>
251unsigned
252LSQUnit<Impl>::numFreeEntries()
253{
254    unsigned free_lq_entries = LQEntries - loads;
255    unsigned free_sq_entries = SQEntries - stores;
256
257    // Both the LQ and SQ entries have an extra dummy entry to differentiate
258    // empty/full conditions.  Subtract 1 from the free entries.
259    if (free_lq_entries < free_sq_entries) {
260        return free_lq_entries - 1;
261    } else {
262        return free_sq_entries - 1;
263    }
264}
265
266template <class Impl>
267int
268LSQUnit<Impl>::numLoadsReady()
269{
270    int load_idx = loadHead;
271    int retval = 0;
272
273    while (load_idx != loadTail) {
274        assert(loadQueue[load_idx]);
275
276        if (loadQueue[load_idx]->readyToIssue()) {
277            ++retval;
278        }
279    }
280
281    return retval;
282}
283
284#if 0
285template <class Impl>
286Fault
287LSQUnit<Impl>::executeLoad()
288{
289    Fault load_fault = NoFault;
290    DynInstPtr load_inst;
291
292    assert(readyLoads.size() != 0);
293
294    // Execute a ready load.
295    LdMapIt ready_it = readyLoads.begin();
296
297    load_inst = (*ready_it).second;
298
299    // Execute the instruction, which is held in the data portion of the
300    // iterator.
301    load_fault = load_inst->execute();
302
303    // If it executed successfully, then switch it over to the executed
304    // loads list.
305    if (load_fault == NoFault) {
306        executedLoads[load_inst->seqNum] = load_inst;
307
308        readyLoads.erase(ready_it);
309    } else {
310        loadFaultInst = load_inst;
311    }
312
313    return load_fault;
314}
315#endif
316
317template <class Impl>
318Fault
319LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
320{
321    // Execute a specific load.
322    Fault load_fault = NoFault;
323
324    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
325            inst->readPC(),inst->seqNum);
326
327    // Make sure it's really in the list.
328    // Normally it should always be in the list.  However,
329    /* due to a syscall it may not be the list.
330#ifdef DEBUG
331    int i = loadHead;
332    while (1) {
333        if (i == loadTail && !find(inst)) {
334            assert(0 && "Load not in the queue!");
335        } else if (loadQueue[i] == inst) {
336            break;
337        }
338
339        i = i + 1;
340        if (i >= LQEntries) {
341            i = 0;
342        }
343    }
344#endif // DEBUG*/
345
346//    load_fault = inst->initiateAcc();
347    load_fault = inst->execute();
348
349    // If the instruction faulted, then we need to send it along to commit
350    // without the instruction completing.
351    if (load_fault != NoFault) {
352        // Maybe just set it as can commit here, although that might cause
353        // some other problems with sending traps to the ROB too quickly.
354        iewStage->instToCommit(inst);
355        iewStage->activityThisCycle();
356    }
357
358    return load_fault;
359}
360
361template <class Impl>
362Fault
363LSQUnit<Impl>::executeLoad(int lq_idx)
364{
365    // Very hackish.  Not sure the best way to check that this
366    // instruction is at the head of the ROB.  I should have some sort
367    // of extra information here so that I'm not overloading the
368    // canCommit signal for 15 different things.
369    loadQueue[lq_idx]->setCanCommit();
370    Fault ret_fault = executeLoad(loadQueue[lq_idx]);
371    loadQueue[lq_idx]->clearCanCommit();
372    return ret_fault;
373}
374
375template <class Impl>
376Fault
377LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
378{
379    using namespace TheISA;
380    // Make sure that a store exists.
381    assert(stores != 0);
382
383    int store_idx = store_inst->sqIdx;
384
385    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
386            store_inst->readPC(), store_inst->seqNum);
387
388    // Check the recently completed loads to see if any match this store's
389    // address.  If so, then we have a memory ordering violation.
390    int load_idx = store_inst->lqIdx;
391
392    Fault store_fault = store_inst->initiateAcc();
393//    Fault store_fault = store_inst->execute();
394
395    // Store size should now be available.  Use it to get proper offset for
396    // addr comparisons.
397    int size = storeQueue[store_idx].size;
398
399    if (size == 0) {
400        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
401                store_inst->readPC(),store_inst->seqNum);
402
403        return store_fault;
404    }
405
406    assert(store_fault == NoFault);
407
408    if (!storeFaultInst) {
409        if (store_fault != NoFault) {
410            panic("Fault in a store instruction!");
411            storeFaultInst = store_inst;
412        } else if (store_inst->isNonSpeculative()) {
413            // Nonspeculative accesses (namely store conditionals)
414            // need to set themselves as able to writeback if we
415            // haven't had a fault by here.
416            storeQueue[store_idx].canWB = true;
417
418            ++storesToWB;
419        }
420    }
421
422    if (!memDepViolator) {
423        while (load_idx != loadTail) {
424            // Actually should only check loads that have actually executed
425            // Might be safe because effAddr is set to InvalAddr when the
426            // dyn inst is created.
427
428            // Must actually check all addrs in the proper size range
429            // Which is more correct than needs to be.  What if for now we just
430            // assume all loads are quad-word loads, and do the addr based
431            // on that.
432            // @todo: Fix this, magic number being used here
433            if ((loadQueue[load_idx]->effAddr >> 8) ==
434                (store_inst->effAddr >> 8)) {
435                // A load incorrectly passed this store.  Squash and refetch.
436                // For now return a fault to show that it was unsuccessful.
437                memDepViolator = loadQueue[load_idx];
438
439                return genMachineCheckFault();
440            }
441
442            incrLdIdx(load_idx);
443        }
444
445        // If we've reached this point, there was no violation.
446        memDepViolator = NULL;
447    }
448
449    return store_fault;
450}
451
452template <class Impl>
453void
454LSQUnit<Impl>::commitLoad()
455{
456    assert(loadQueue[loadHead]);
457
458    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
459            loadQueue[loadHead]->readPC());
460
461
462    loadQueue[loadHead] = NULL;
463
464    incrLdIdx(loadHead);
465
466    --loads;
467}
468
469template <class Impl>
470void
471LSQUnit<Impl>::commitLoad(InstSeqNum &inst)
472{
473    // Hopefully I don't use this function too much
474    panic("Don't use this function!");
475
476    int i = loadHead;
477    while (1) {
478        if (i == loadTail) {
479            assert(0 && "Load not in the queue!");
480        } else if (loadQueue[i]->seqNum == inst) {
481            break;
482        }
483
484        ++i;
485        if (i >= LQEntries) {
486            i = 0;
487        }
488    }
489
490    loadQueue[i]->removeInLSQ();
491    loadQueue[i] = NULL;
492    --loads;
493}
494
495template <class Impl>
496void
497LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
498{
499    assert(loads == 0 || loadQueue[loadHead]);
500
501    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
502        commitLoad();
503    }
504}
505
506template <class Impl>
507void
508LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
509{
510    assert(stores == 0 || storeQueue[storeHead].inst);
511
512    int store_idx = storeHead;
513
514    while (store_idx != storeTail) {
515        assert(storeQueue[store_idx].inst);
516        if (!storeQueue[store_idx].canWB) {
517            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
518                break;
519            }
520            DPRINTF(LSQUnit, "Marking store as able to write back, PC "
521                    "%#x [sn:%lli]\n",
522                    storeQueue[store_idx].inst->readPC(),
523                    storeQueue[store_idx].inst->seqNum);
524
525            storeQueue[store_idx].canWB = true;
526
527//            --stores;
528            ++storesToWB;
529        }
530
531        incrStIdx(store_idx);
532    }
533}
534
535template <class Impl>
536void
537LSQUnit<Impl>::writebackStores()
538{
539    while (storesToWB > 0 &&
540           storeWBIdx != storeTail &&
541           storeQueue[storeWBIdx].inst &&
542           storeQueue[storeWBIdx].canWB &&
543           usedPorts < cachePorts) {
544
545        if (storeQueue[storeWBIdx].size == 0) {
546            completeStore(storeWBIdx);
547
548            incrStIdx(storeWBIdx);
549
550            continue;
551        }
552
553        if (dcacheInterface && dcacheInterface->isBlocked()) {
554            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
555                    " is blocked!\n");
556            break;
557        }
558
559        ++usedPorts;
560
561        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
562            incrStIdx(storeWBIdx);
563
564            continue;
565        }
566
567        assert(storeQueue[storeWBIdx].req);
568        assert(!storeQueue[storeWBIdx].committed);
569
570        MemReqPtr req = storeQueue[storeWBIdx].req;
571        storeQueue[storeWBIdx].committed = true;
572
573//	Fault fault = cpu->translateDataWriteReq(req);
574        req->cmd = Write;
575        req->completionEvent = NULL;
576        req->time = curTick;
577        assert(!req->data);
578        req->data = new uint8_t[64];
579        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
580
581        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
582                "to Addr:%#x, data:%#x [sn:%lli]\n",
583                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
584                req->paddr, *(req->data),
585                storeQueue[storeWBIdx].inst->seqNum);
586
587//        if (fault != NoFault) {
588            //What should we do if there is a fault???
589            //for now panic
590//            panic("Page Table Fault!!!!!\n");
591//        }
592        switch(storeQueue[storeWBIdx].size) {
593          case 1:
594            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
595            break;
596          case 2:
597            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
598            break;
599          case 4:
600            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
601            break;
602          case 8:
603            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
604            break;
605          default:
606            panic("Unexpected store size!\n");
607        }
608
609        if (dcacheInterface) {
610            MemAccessResult result = dcacheInterface->access(req);
611
612            if (isStalled() &&
613                storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
614                DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
615                        "load idx:%i\n",
616                        stallingStoreIsn, stallingLoadIdx);
617                stalled = false;
618                stallingStoreIsn = 0;
619                iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
620            }
621
622            if (result != MA_HIT && dcacheInterface->doEvents()) {
623                typename IEW::LdWritebackEvent *wb = NULL;
624                if (req->flags & LOCKED) {
625                    // Stx_C does not generate a system port transaction.
626/*
627                    if (cpu->lockFlag && cpu->lockAddr == req->paddr) {
628                        req->result=1;
629                    } else {
630                        req->result = 0;
631                    }
632*/
633                    wb = new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
634                                                            iewStage);
635                }
636
637                DPRINTF(LSQUnit,"D-Cache Write Miss!\n");
638
639                DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
640                        storeQueue[storeWBIdx].inst->seqNum);
641
642                // Will stores need their own kind of writeback events?
643                // Do stores even need writeback events?
644                assert(!req->completionEvent);
645                req->completionEvent = new
646                    StoreCompletionEvent(storeWBIdx, wb, this);
647
648                lastDcacheStall = curTick;
649
650                _status = DcacheMissStall;
651
652                //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
653
654                //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
655
656                // Increment stat here or something
657            } else {
658                DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
659                        storeWBIdx);
660
661                DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
662                        storeQueue[storeWBIdx].inst->seqNum);
663
664
665                if (req->flags & LOCKED) {
666                    // Stx_C does not generate a system port transaction.
667/*
668                    if (req->flags & UNCACHEABLE) {
669                        req->result = 2;
670                    } else {
671                        if (cpu->lockFlag && cpu->lockAddr == req->paddr) {
672                            req->result=1;
673                        } else {
674                            req->result = 0;
675                        }
676                    }
677*/
678                    typename IEW::LdWritebackEvent *wb =
679                        new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
680                                                           iewStage);
681                    wb->schedule(curTick);
682                }
683
684                completeStore(storeWBIdx);
685            }
686
687            incrStIdx(storeWBIdx);
688        } else {
689            panic("Must HAVE DCACHE!!!!!\n");
690        }
691    }
692
693    // Not sure this should set it to 0.
694    usedPorts = 0;
695
696    assert(stores >= 0 && storesToWB >= 0);
697}
698
699/*template <class Impl>
700void
701LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
702{
703    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
704                                              mshrSeqNums.end(),
705                                              seqNum);
706
707    if (mshr_it != mshrSeqNums.end()) {
708        mshrSeqNums.erase(mshr_it);
709        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
710    }
711}*/
712
713template <class Impl>
714void
715LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
716{
717    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
718            "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
719
720    int load_idx = loadTail;
721    decrLdIdx(load_idx);
722
723    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
724
725        // Clear the smart pointer to make sure it is decremented.
726        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
727                "[sn:%lli]\n",
728                loadQueue[load_idx]->readPC(),
729                loadQueue[load_idx]->seqNum);
730
731        if (isStalled() && load_idx == stallingLoadIdx) {
732            stalled = false;
733            stallingStoreIsn = 0;
734            stallingLoadIdx = 0;
735        }
736
737        loadQueue[load_idx]->squashed = true;
738        loadQueue[load_idx] = NULL;
739        --loads;
740
741        // Inefficient!
742        loadTail = load_idx;
743
744        decrLdIdx(load_idx);
745    }
746
747    if (isLoadBlocked) {
748        if (squashed_num < blockedLoadSeqNum) {
749            isLoadBlocked = false;
750            loadBlockedHandled = false;
751            blockedLoadSeqNum = 0;
752        }
753    }
754
755    int store_idx = storeTail;
756    decrStIdx(store_idx);
757
758    while (stores != 0 &&
759           storeQueue[store_idx].inst->seqNum > squashed_num) {
760
761        if (storeQueue[store_idx].canWB) {
762            break;
763        }
764
765        // Clear the smart pointer to make sure it is decremented.
766        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
767                "idx:%i [sn:%lli]\n",
768                storeQueue[store_idx].inst->readPC(),
769                store_idx, storeQueue[store_idx].inst->seqNum);
770
771        // I don't think this can happen.  It should have been cleared by the
772        // stalling load.
773        if (isStalled() &&
774            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
775            panic("Is stalled should have been cleared by stalling load!\n");
776            stalled = false;
777            stallingStoreIsn = 0;
778        }
779
780        storeQueue[store_idx].inst->squashed = true;
781        storeQueue[store_idx].inst = NULL;
782        storeQueue[store_idx].canWB = 0;
783
784        if (storeQueue[store_idx].req) {
785            assert(!storeQueue[store_idx].req->completionEvent);
786        }
787        storeQueue[store_idx].req = NULL;
788        --stores;
789
790        // Inefficient!
791        storeTail = store_idx;
792
793        decrStIdx(store_idx);
794    }
795}
796
797template <class Impl>
798void
799LSQUnit<Impl>::dumpInsts()
800{
801    cprintf("Load store queue: Dumping instructions.\n");
802    cprintf("Load queue size: %i\n", loads);
803    cprintf("Load queue: ");
804
805    int load_idx = loadHead;
806
807    while (load_idx != loadTail && loadQueue[load_idx]) {
808        cprintf("%#x ", loadQueue[load_idx]->readPC());
809
810        incrLdIdx(load_idx);
811    }
812
813    cprintf("Store queue size: %i\n", stores);
814    cprintf("Store queue: ");
815
816    int store_idx = storeHead;
817
818    while (store_idx != storeTail && storeQueue[store_idx].inst) {
819        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
820
821        incrStIdx(store_idx);
822    }
823
824    cprintf("\n");
825}
826
827template <class Impl>
828void
829LSQUnit<Impl>::completeStore(int store_idx)
830{
831    assert(storeQueue[store_idx].inst);
832    storeQueue[store_idx].completed = true;
833    --storesToWB;
834    // A bit conservative because a store completion may not free up entries,
835    // but hopefully avoids two store completions in one cycle from making
836    // the CPU tick twice.
837    cpu->activityThisCycle();
838
839    if (store_idx == storeHead) {
840        do {
841            incrStIdx(storeHead);
842
843            --stores;
844        } while (storeQueue[storeHead].completed &&
845                 storeHead != storeTail);
846
847        iewStage->updateLSQNextCycle = true;
848    }
849
850    DPRINTF(LSQUnit, "Store head idx:%i\n", storeHead);
851
852    if (isStalled() &&
853        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
854        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
855                "load idx:%i\n",
856                stallingStoreIsn, stallingLoadIdx);
857        stalled = false;
858        stallingStoreIsn = 0;
859        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
860    }
861}
862
863template <class Impl>
864inline void
865LSQUnit<Impl>::incrStIdx(int &store_idx)
866{
867    if (++store_idx >= SQEntries)
868        store_idx = 0;
869}
870
871template <class Impl>
872inline void
873LSQUnit<Impl>::decrStIdx(int &store_idx)
874{
875    if (--store_idx < 0)
876        store_idx += SQEntries;
877}
878
879template <class Impl>
880inline void
881LSQUnit<Impl>::incrLdIdx(int &load_idx)
882{
883    if (++load_idx >= LQEntries)
884        load_idx = 0;
885}
886
887template <class Impl>
888inline void
889LSQUnit<Impl>::decrLdIdx(int &load_idx)
890{
891    if (--load_idx < 0)
892        load_idx += LQEntries;
893}
894