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