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