lsq_unit_impl.hh revision 2361
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        loadQueue[i] = NULL;
203
204    assert(storesToWB == 0);
205
206    while (storesToWB > 0 &&
207           storeWBIdx != storeTail &&
208           storeQueue[storeWBIdx].inst &&
209           storeQueue[storeWBIdx].canWB) {
210
211        if (storeQueue[storeWBIdx].size == 0 ||
212            storeQueue[storeWBIdx].inst->isDataPrefetch() ||
213            storeQueue[storeWBIdx].committed ||
214            storeQueue[storeWBIdx].req->flags & LOCKED) {
215            incrStIdx(storeWBIdx);
216
217            continue;
218        }
219
220        assert(storeQueue[storeWBIdx].req);
221        assert(!storeQueue[storeWBIdx].committed);
222
223        MemReqPtr req = storeQueue[storeWBIdx].req;
224        storeQueue[storeWBIdx].committed = true;
225
226        req->cmd = Write;
227        req->completionEvent = NULL;
228        req->time = curTick;
229        assert(!req->data);
230        req->data = new uint8_t[64];
231        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
232
233        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
234                "to Addr:%#x, data:%#x [sn:%lli]\n",
235                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
236                req->paddr, *(req->data),
237                storeQueue[storeWBIdx].inst->seqNum);
238
239        switch(storeQueue[storeWBIdx].size) {
240          case 1:
241            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
242            break;
243          case 2:
244            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
245            break;
246          case 4:
247            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
248            break;
249          case 8:
250            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
251            break;
252          default:
253            panic("Unexpected store size!\n");
254        }
255        incrStIdx(storeWBIdx);
256    }
257}
258
259template<class Impl>
260void
261LSQUnit<Impl>::takeOverFrom()
262{
263    switchedOut = false;
264    loads = stores = storesToWB = 0;
265
266    loadHead = loadTail = 0;
267
268    storeHead = storeWBIdx = storeTail = 0;
269
270    usedPorts = 0;
271
272    memDepViolator = NULL;
273
274    blockedLoadSeqNum = 0;
275
276    stalled = false;
277    isLoadBlocked = false;
278    loadBlockedHandled = false;
279}
280
281template<class Impl>
282void
283LSQUnit<Impl>::resizeLQ(unsigned size)
284{
285    unsigned size_plus_sentinel = size + 1;
286    assert(size_plus_sentinel >= LQEntries);
287
288    if (size_plus_sentinel > LQEntries) {
289        while (size_plus_sentinel > loadQueue.size()) {
290            DynInstPtr dummy;
291            loadQueue.push_back(dummy);
292            LQEntries++;
293        }
294    } else {
295        LQEntries = size_plus_sentinel;
296    }
297
298}
299
300template<class Impl>
301void
302LSQUnit<Impl>::resizeSQ(unsigned size)
303{
304    unsigned size_plus_sentinel = size + 1;
305    if (size_plus_sentinel > SQEntries) {
306        while (size_plus_sentinel > storeQueue.size()) {
307            SQEntry dummy;
308            storeQueue.push_back(dummy);
309            SQEntries++;
310        }
311    } else {
312        SQEntries = size_plus_sentinel;
313    }
314}
315
316template <class Impl>
317void
318LSQUnit<Impl>::insert(DynInstPtr &inst)
319{
320    assert(inst->isMemRef());
321
322    assert(inst->isLoad() || inst->isStore());
323
324    if (inst->isLoad()) {
325        insertLoad(inst);
326    } else {
327        insertStore(inst);
328    }
329
330    inst->setInLSQ();
331}
332
333template <class Impl>
334void
335LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
336{
337    assert((loadTail + 1) % LQEntries != loadHead);
338    assert(loads < LQEntries);
339
340    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
341            load_inst->readPC(), loadTail, load_inst->seqNum);
342
343    load_inst->lqIdx = loadTail;
344
345    if (stores == 0) {
346        load_inst->sqIdx = -1;
347    } else {
348        load_inst->sqIdx = storeTail;
349    }
350
351    loadQueue[loadTail] = load_inst;
352
353    incrLdIdx(loadTail);
354
355    ++loads;
356}
357
358template <class Impl>
359void
360LSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
361{
362    // Make sure it is not full before inserting an instruction.
363    assert((storeTail + 1) % SQEntries != storeHead);
364    assert(stores < SQEntries);
365
366    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
367            store_inst->readPC(), storeTail, store_inst->seqNum);
368
369    store_inst->sqIdx = storeTail;
370    store_inst->lqIdx = loadTail;
371
372    storeQueue[storeTail] = SQEntry(store_inst);
373
374    incrStIdx(storeTail);
375
376    ++stores;
377}
378
379template <class Impl>
380typename Impl::DynInstPtr
381LSQUnit<Impl>::getMemDepViolator()
382{
383    DynInstPtr temp = memDepViolator;
384
385    memDepViolator = NULL;
386
387    return temp;
388}
389
390template <class Impl>
391unsigned
392LSQUnit<Impl>::numFreeEntries()
393{
394    unsigned free_lq_entries = LQEntries - loads;
395    unsigned free_sq_entries = SQEntries - stores;
396
397    // Both the LQ and SQ entries have an extra dummy entry to differentiate
398    // empty/full conditions.  Subtract 1 from the free entries.
399    if (free_lq_entries < free_sq_entries) {
400        return free_lq_entries - 1;
401    } else {
402        return free_sq_entries - 1;
403    }
404}
405
406template <class Impl>
407int
408LSQUnit<Impl>::numLoadsReady()
409{
410    int load_idx = loadHead;
411    int retval = 0;
412
413    while (load_idx != loadTail) {
414        assert(loadQueue[load_idx]);
415
416        if (loadQueue[load_idx]->readyToIssue()) {
417            ++retval;
418        }
419    }
420
421    return retval;
422}
423
424template <class Impl>
425Fault
426LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
427{
428    // Execute a specific load.
429    Fault load_fault = NoFault;
430
431    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
432            inst->readPC(),inst->seqNum);
433
434//    load_fault = inst->initiateAcc();
435    load_fault = inst->execute();
436
437    // If the instruction faulted, then we need to send it along to commit
438    // without the instruction completing.
439    if (load_fault != NoFault) {
440        // Send this instruction to commit, also make sure iew stage
441        // realizes there is activity.
442        iewStage->instToCommit(inst);
443        iewStage->activityThisCycle();
444    }
445
446    return load_fault;
447}
448
449template <class Impl>
450Fault
451LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
452{
453    using namespace TheISA;
454    // Make sure that a store exists.
455    assert(stores != 0);
456
457    int store_idx = store_inst->sqIdx;
458
459    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
460            store_inst->readPC(), store_inst->seqNum);
461
462    // Check the recently completed loads to see if any match this store's
463    // address.  If so, then we have a memory ordering violation.
464    int load_idx = store_inst->lqIdx;
465
466    Fault store_fault = store_inst->initiateAcc();
467//    Fault store_fault = store_inst->execute();
468
469    if (storeQueue[store_idx].size == 0) {
470        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
471                store_inst->readPC(),store_inst->seqNum);
472
473        return store_fault;
474    }
475
476    assert(store_fault == NoFault);
477
478    if (store_inst->isStoreConditional()) {
479        // Store conditionals need to set themselves as able to
480        // writeback if we haven't had a fault by here.
481        storeQueue[store_idx].canWB = true;
482
483        ++storesToWB;
484    }
485
486    if (!memDepViolator) {
487        while (load_idx != loadTail) {
488            // Really only need to check loads that have actually executed
489            // It's safe to check all loads because effAddr is set to
490            // InvalAddr when the dyn inst is created.
491
492            // @todo: For now this is extra conservative, detecting a
493            // violation if the addresses match assuming all accesses
494            // are quad word accesses.
495
496            // @todo: Fix this, magic number being used here
497            if ((loadQueue[load_idx]->effAddr >> 8) ==
498                (store_inst->effAddr >> 8)) {
499                // A load incorrectly passed this store.  Squash and refetch.
500                // For now return a fault to show that it was unsuccessful.
501                memDepViolator = loadQueue[load_idx];
502                ++lsqMemOrderViolation;
503
504                return genMachineCheckFault();
505            }
506
507            incrLdIdx(load_idx);
508        }
509
510        // If we've reached this point, there was no violation.
511        memDepViolator = NULL;
512    }
513
514    return store_fault;
515}
516
517template <class Impl>
518void
519LSQUnit<Impl>::commitLoad()
520{
521    assert(loadQueue[loadHead]);
522
523    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
524            loadQueue[loadHead]->readPC());
525
526    loadQueue[loadHead] = NULL;
527
528    incrLdIdx(loadHead);
529
530    --loads;
531}
532
533template <class Impl>
534void
535LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
536{
537    assert(loads == 0 || loadQueue[loadHead]);
538
539    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
540        commitLoad();
541    }
542}
543
544template <class Impl>
545void
546LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
547{
548    assert(stores == 0 || storeQueue[storeHead].inst);
549
550    int store_idx = storeHead;
551
552    while (store_idx != storeTail) {
553        assert(storeQueue[store_idx].inst);
554        // Mark any stores that are now committed and have not yet
555        // been marked as able to write back.
556        if (!storeQueue[store_idx].canWB) {
557            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
558                break;
559            }
560            DPRINTF(LSQUnit, "Marking store as able to write back, PC "
561                    "%#x [sn:%lli]\n",
562                    storeQueue[store_idx].inst->readPC(),
563                    storeQueue[store_idx].inst->seqNum);
564
565            storeQueue[store_idx].canWB = true;
566
567            ++storesToWB;
568        }
569
570        incrStIdx(store_idx);
571    }
572}
573
574template <class Impl>
575void
576LSQUnit<Impl>::writebackStores()
577{
578    while (storesToWB > 0 &&
579           storeWBIdx != storeTail &&
580           storeQueue[storeWBIdx].inst &&
581           storeQueue[storeWBIdx].canWB &&
582           usedPorts < cachePorts) {
583
584        // Store didn't write any data so no need to write it back to
585        // memory.
586        if (storeQueue[storeWBIdx].size == 0) {
587            completeStore(storeWBIdx);
588
589            incrStIdx(storeWBIdx);
590
591            continue;
592        }
593
594        if (dcacheInterface && dcacheInterface->isBlocked()) {
595            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
596                    " is blocked!\n");
597            ++lsqCacheBlocked;
598            break;
599        }
600
601        ++usedPorts;
602
603        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
604            incrStIdx(storeWBIdx);
605
606            continue;
607        }
608
609        assert(storeQueue[storeWBIdx].req);
610        assert(!storeQueue[storeWBIdx].committed);
611
612        MemReqPtr req = storeQueue[storeWBIdx].req;
613        storeQueue[storeWBIdx].committed = true;
614
615        req->cmd = Write;
616        req->completionEvent = NULL;
617        req->time = curTick;
618        assert(!req->data);
619        req->data = new uint8_t[64];
620        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
621
622        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
623                "to Addr:%#x, data:%#x [sn:%lli]\n",
624                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
625                req->paddr, *(req->data),
626                storeQueue[storeWBIdx].inst->seqNum);
627
628        switch(storeQueue[storeWBIdx].size) {
629          case 1:
630            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
631            break;
632          case 2:
633            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
634            break;
635          case 4:
636            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
637            break;
638          case 8:
639            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
640            break;
641          default:
642            panic("Unexpected store size!\n");
643        }
644
645        // Stores other than store conditionals are completed at this
646        // time.  Mark them as completed and, if we have a checker,
647        // tell it that the instruction is completed.
648        // @todo: Figure out what time I can say stores are complete in
649        // the timing memory.
650        if (!(req->flags & LOCKED)) {
651            storeQueue[storeWBIdx].inst->setCompleted();
652            if (cpu->checker) {
653                cpu->checker->tick(storeQueue[storeWBIdx].inst);
654            }
655        }
656
657        if (dcacheInterface) {
658            assert(!req->completionEvent);
659            StoreCompletionEvent *store_event = new
660                StoreCompletionEvent(storeWBIdx, NULL, this);
661            req->completionEvent = store_event;
662
663            MemAccessResult result = dcacheInterface->access(req);
664
665            if (isStalled() &&
666                storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
667                DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
668                        "load idx:%i\n",
669                        stallingStoreIsn, stallingLoadIdx);
670                stalled = false;
671                stallingStoreIsn = 0;
672                iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
673            }
674
675            typename IEW::LdWritebackEvent *wb = NULL;
676            if (req->flags & LOCKED) {
677                // Stx_C should not generate a system port transaction
678                // if it misses in the cache, but that might be hard
679                // to accomplish without explicit cache support.
680                wb = new typename
681                    IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
682                                              iewStage);
683                store_event->wbEvent = wb;
684            }
685
686            if (result != MA_HIT && dcacheInterface->doEvents()) {
687                DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n",
688                        storeWBIdx);
689
690                DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
691                        storeQueue[storeWBIdx].inst->seqNum);
692
693                //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
694
695                //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
696
697                // @todo: Increment stat here.
698            } else {
699                DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
700                        storeWBIdx);
701
702                DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
703                        storeQueue[storeWBIdx].inst->seqNum);
704            }
705
706            incrStIdx(storeWBIdx);
707        } else {
708            panic("Must HAVE DCACHE!!!!!\n");
709        }
710    }
711
712    // Not sure this should set it to 0.
713    usedPorts = 0;
714
715    assert(stores >= 0 && storesToWB >= 0);
716}
717
718/*template <class Impl>
719void
720LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
721{
722    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
723                                              mshrSeqNums.end(),
724                                              seqNum);
725
726    if (mshr_it != mshrSeqNums.end()) {
727        mshrSeqNums.erase(mshr_it);
728        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
729    }
730}*/
731
732template <class Impl>
733void
734LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
735{
736    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
737            "(Loads:%i Stores:%i)\n", squashed_num, loads, stores);
738
739    int load_idx = loadTail;
740    decrLdIdx(load_idx);
741
742    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
743        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
744                "[sn:%lli]\n",
745                loadQueue[load_idx]->readPC(),
746                loadQueue[load_idx]->seqNum);
747
748        if (isStalled() && load_idx == stallingLoadIdx) {
749            stalled = false;
750            stallingStoreIsn = 0;
751            stallingLoadIdx = 0;
752        }
753
754        // Clear the smart pointer to make sure it is decremented.
755        loadQueue[load_idx]->setSquashed();
756        loadQueue[load_idx] = NULL;
757        --loads;
758
759        // Inefficient!
760        loadTail = load_idx;
761
762        decrLdIdx(load_idx);
763    }
764
765    if (isLoadBlocked) {
766        if (squashed_num < blockedLoadSeqNum) {
767            isLoadBlocked = false;
768            loadBlockedHandled = false;
769            blockedLoadSeqNum = 0;
770        }
771    }
772
773    int store_idx = storeTail;
774    decrStIdx(store_idx);
775
776    while (stores != 0 &&
777           storeQueue[store_idx].inst->seqNum > squashed_num) {
778        // Instructions marked as can WB are already committed.
779        if (storeQueue[store_idx].canWB) {
780            break;
781        }
782
783        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
784                "idx:%i [sn:%lli]\n",
785                storeQueue[store_idx].inst->readPC(),
786                store_idx, storeQueue[store_idx].inst->seqNum);
787
788        // I don't think this can happen.  It should have been cleared
789        // by the stalling load.
790        if (isStalled() &&
791            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
792            panic("Is stalled should have been cleared by stalling load!\n");
793            stalled = false;
794            stallingStoreIsn = 0;
795        }
796
797        // Clear the smart pointer to make sure it is decremented.
798        storeQueue[store_idx].inst->setSquashed();
799        storeQueue[store_idx].inst = NULL;
800        storeQueue[store_idx].canWB = 0;
801
802        if (storeQueue[store_idx].req) {
803            // There should not be a completion event if the store has
804            // not yet committed.
805            assert(!storeQueue[store_idx].req->completionEvent);
806        }
807
808        storeQueue[store_idx].req = NULL;
809        --stores;
810
811        // Inefficient!
812        storeTail = store_idx;
813
814        decrStIdx(store_idx);
815        ++lsqSquashedStores;
816    }
817}
818
819template <class Impl>
820void
821LSQUnit<Impl>::completeStore(int store_idx)
822{
823    assert(storeQueue[store_idx].inst);
824    storeQueue[store_idx].completed = true;
825    --storesToWB;
826    // A bit conservative because a store completion may not free up entries,
827    // but hopefully avoids two store completions in one cycle from making
828    // the CPU tick twice.
829    cpu->activityThisCycle();
830
831    if (store_idx == storeHead) {
832        do {
833            incrStIdx(storeHead);
834
835            --stores;
836        } while (storeQueue[storeHead].completed &&
837                 storeHead != storeTail);
838
839        iewStage->updateLSQNextCycle = true;
840    }
841
842    DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head "
843            "idx:%i\n",
844            storeQueue[store_idx].inst->seqNum, store_idx, storeHead);
845
846    if (isStalled() &&
847        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
848        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
849                "load idx:%i\n",
850                stallingStoreIsn, stallingLoadIdx);
851        stalled = false;
852        stallingStoreIsn = 0;
853        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
854    }
855
856    storeQueue[store_idx].inst->setCompleted();
857
858    // Tell the checker we've completed this instruction.  Some stores
859    // may get reported twice to the checker, but the checker can
860    // handle that case.
861    if (cpu->checker) {
862        cpu->checker->tick(storeQueue[store_idx].inst);
863    }
864}
865
866template <class Impl>
867inline void
868LSQUnit<Impl>::incrStIdx(int &store_idx)
869{
870    if (++store_idx >= SQEntries)
871        store_idx = 0;
872}
873
874template <class Impl>
875inline void
876LSQUnit<Impl>::decrStIdx(int &store_idx)
877{
878    if (--store_idx < 0)
879        store_idx += SQEntries;
880}
881
882template <class Impl>
883inline void
884LSQUnit<Impl>::incrLdIdx(int &load_idx)
885{
886    if (++load_idx >= LQEntries)
887        load_idx = 0;
888}
889
890template <class Impl>
891inline void
892LSQUnit<Impl>::decrLdIdx(int &load_idx)
893{
894    if (--load_idx < 0)
895        load_idx += LQEntries;
896}
897
898template <class Impl>
899void
900LSQUnit<Impl>::dumpInsts()
901{
902    cprintf("Load store queue: Dumping instructions.\n");
903    cprintf("Load queue size: %i\n", loads);
904    cprintf("Load queue: ");
905
906    int load_idx = loadHead;
907
908    while (load_idx != loadTail && loadQueue[load_idx]) {
909        cprintf("%#x ", loadQueue[load_idx]->readPC());
910
911        incrLdIdx(load_idx);
912    }
913
914    cprintf("Store queue size: %i\n", stores);
915    cprintf("Store queue: ");
916
917    int store_idx = storeHead;
918
919    while (store_idx != storeTail && storeQueue[store_idx].inst) {
920        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
921
922        incrStIdx(store_idx);
923    }
924
925    cprintf("\n");
926}
927