lsq_unit_impl.hh revision 2310
11689SN/A/*
27783SGiacomo.Gabrielli@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37783SGiacomo.Gabrielli@arm.com * All rights reserved.
47783SGiacomo.Gabrielli@arm.com *
57783SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without
67783SGiacomo.Gabrielli@arm.com * modification, are permitted provided that the following conditions are
77783SGiacomo.Gabrielli@arm.com * met: redistributions of source code must retain the above copyright
87783SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer;
97783SGiacomo.Gabrielli@arm.com * redistributions in binary form must reproduce the above copyright
107783SGiacomo.Gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the
117783SGiacomo.Gabrielli@arm.com * documentation and/or other materials provided with the distribution;
127783SGiacomo.Gabrielli@arm.com * neither the name of the copyright holders nor the names of its
137783SGiacomo.Gabrielli@arm.com * contributors may be used to endorse or promote products derived from
142316SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271689SN/A */
281689SN/A
291689SN/A#include "cpu/o3/lsq_unit.hh"
301689SN/A#include "base/str.hh"
311689SN/A
321689SN/Atemplate <class Impl>
331689SN/ALSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx,
341689SN/A                                                          Event *wb_event,
351689SN/A                                                          LSQUnit<Impl> *lsq_ptr)
361689SN/A    : Event(&mainEventQueue),
371689SN/A      storeIdx(store_idx),
381689SN/A      wbEvent(wb_event),
392665SN/A      lsqPtr(lsq_ptr)
402665SN/A{
411689SN/A    this->setFlags(Event::AutoDelete);
421061SN/A}
435953Ssaidi@eecs.umich.edu
445596Sgblack@eecs.umich.edutemplate <class Impl>
451061SN/Avoid
461061SN/ALSQUnit<Impl>::StoreCompletionEvent::process()
475596Sgblack@eecs.umich.edu{
488502Sgblack@eecs.umich.edu    DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx);
497720Sgblack@eecs.umich.edu    DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx);
505596Sgblack@eecs.umich.edu
518502Sgblack@eecs.umich.edu    //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
524637SN/A
534637SN/A    if (lsqPtr->isSwitchedOut())
544637SN/A        return;
554637SN/A
564637SN/A    lsqPtr->cpu->wakeCPU();
578502Sgblack@eecs.umich.edu    if (wbEvent)
588502Sgblack@eecs.umich.edu        wbEvent->process();
598502Sgblack@eecs.umich.edu    lsqPtr->completeStore(storeIdx);
601061SN/A}
612292SN/A
622292SN/Atemplate <class Impl>
632292SN/Aconst char *
642292SN/ALSQUnit<Impl>::StoreCompletionEvent::description()
652292SN/A{
665596Sgblack@eecs.umich.edu    return "LSQ store completion event";
672292SN/A}
681464SN/A
691464SN/Atemplate <class Impl>
701464SN/ALSQUnit<Impl>::LSQUnit()
712292SN/A    : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
723782SN/A      loadBlockedHandled(false)
731464SN/A{
741464SN/A}
752292SN/A
763782SN/Atemplate<class Impl>
772292SN/Avoid
781464SN/ALSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
797783SGiacomo.Gabrielli@arm.com                    unsigned maxSQEntries, unsigned id)
807783SGiacomo.Gabrielli@arm.com
818471SGiacomo.Gabrielli@arm.com{
828471SGiacomo.Gabrielli@arm.com    DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
838471SGiacomo.Gabrielli@arm.com
848471SGiacomo.Gabrielli@arm.com    switchedOut = false;
858471SGiacomo.Gabrielli@arm.com
868471SGiacomo.Gabrielli@arm.com    lsqID = id;
878471SGiacomo.Gabrielli@arm.com
888471SGiacomo.Gabrielli@arm.com    LQEntries = maxLQEntries;
898471SGiacomo.Gabrielli@arm.com    SQEntries = maxSQEntries;
901061SN/A
911061SN/A    loadQueue.resize(LQEntries);
922292SN/A    storeQueue.resize(SQEntries);
932292SN/A
945596Sgblack@eecs.umich.edu
952292SN/A    // May want to initialize these entries to NULL
962348SN/A
972680SN/A    loadHead = loadTail = 0;
982348SN/A
992680SN/A    storeHead = storeWBIdx = storeTail = 0;
1002292SN/A
1012292SN/A    usedPorts = 0;
1022292SN/A    cachePorts = params->cachePorts;
1032292SN/A
1042292SN/A    dcacheInterface = params->dcacheInterface;
1052292SN/A
1062292SN/A    loadFaultInst = storeFaultInst = memDepViolator = NULL;
1072292SN/A
1082292SN/A    blockedLoadSeqNum = 0;
1092292SN/A}
1102292SN/A
1112292SN/Atemplate<class Impl>
1125596Sgblack@eecs.umich.edustd::string
1132292SN/ALSQUnit<Impl>::name() const
1142348SN/A{
1152680SN/A    if (Impl::MaxThreads == 1) {
1162348SN/A        return iewStage->name() + ".lsq";
1172680SN/A    } else {
1182292SN/A        return iewStage->name() + ".lsq.thread." + to_string(lsqID);
1192292SN/A    }
1202292SN/A}
1212292SN/A
1222292SN/Atemplate<class Impl>
1232292SN/Avoid
1242292SN/ALSQUnit<Impl>::clearLQ()
1252292SN/A{
1262292SN/A    loadQueue.clear();
1272292SN/A}
1282292SN/A
1292292SN/Atemplate<class Impl>
1305596Sgblack@eecs.umich.eduvoid
1312292SN/ALSQUnit<Impl>::clearSQ()
1327758Sminkyu.jeong@arm.com{
1337758Sminkyu.jeong@arm.com    storeQueue.clear();
1347758Sminkyu.jeong@arm.com}
1357758Sminkyu.jeong@arm.com
1367758Sminkyu.jeong@arm.com#if 0
1377758Sminkyu.jeong@arm.comtemplate<class Impl>
1387758Sminkyu.jeong@arm.comvoid
1392790SN/ALSQUnit<Impl>::setPageTable(PageTable *pt_ptr)
1402292SN/A{
1417758Sminkyu.jeong@arm.com    DPRINTF(LSQUnit, "Setting the page table pointer.\n");
1427758Sminkyu.jeong@arm.com    pTable = pt_ptr;
1432292SN/A}
1442292SN/A#endif
1452292SN/A
1461858SN/Atemplate<class Impl>
1471061SN/Avoid
1485702Ssaidi@eecs.umich.eduLSQUnit<Impl>::switchOut()
1495702Ssaidi@eecs.umich.edu{
1505702Ssaidi@eecs.umich.edu    switchedOut = true;
1515702Ssaidi@eecs.umich.edu    for (int i = 0; i < loadQueue.size(); ++i)
1525702Ssaidi@eecs.umich.edu        loadQueue[i] = NULL;
1537720Sgblack@eecs.umich.edu
1545702Ssaidi@eecs.umich.edu    while (storesToWB > 0 &&
1555702Ssaidi@eecs.umich.edu           storeWBIdx != storeTail &&
1565702Ssaidi@eecs.umich.edu           storeQueue[storeWBIdx].inst &&
1577720Sgblack@eecs.umich.edu           storeQueue[storeWBIdx].canWB) {
1587720Sgblack@eecs.umich.edu
1597720Sgblack@eecs.umich.edu        if (storeQueue[storeWBIdx].size == 0 ||
1607720Sgblack@eecs.umich.edu            storeQueue[storeWBIdx].inst->isDataPrefetch() ||
1615953Ssaidi@eecs.umich.edu            storeQueue[storeWBIdx].committed ||
1625953Ssaidi@eecs.umich.edu            storeQueue[storeWBIdx].req->flags & LOCKED) {
1637720Sgblack@eecs.umich.edu            incrStIdx(storeWBIdx);
1645953Ssaidi@eecs.umich.edu
1655702Ssaidi@eecs.umich.edu            continue;
1665702Ssaidi@eecs.umich.edu        }
1675702Ssaidi@eecs.umich.edu
1685702Ssaidi@eecs.umich.edu        assert(storeQueue[storeWBIdx].req);
1695702Ssaidi@eecs.umich.edu        assert(!storeQueue[storeWBIdx].committed);
1705702Ssaidi@eecs.umich.edu
1715702Ssaidi@eecs.umich.edu        MemReqPtr req = storeQueue[storeWBIdx].req;
1725702Ssaidi@eecs.umich.edu        storeQueue[storeWBIdx].committed = true;
1735702Ssaidi@eecs.umich.edu
1745702Ssaidi@eecs.umich.edu        req->cmd = Write;
1755702Ssaidi@eecs.umich.edu        req->completionEvent = NULL;
1761061SN/A        req->time = curTick;
1775596Sgblack@eecs.umich.edu        assert(!req->data);
1781061SN/A        req->data = new uint8_t[64];
1797684Sgblack@eecs.umich.edu        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
1801061SN/A
1815702Ssaidi@eecs.umich.edu        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
1825702Ssaidi@eecs.umich.edu                "to Addr:%#x, data:%#x [sn:%lli]\n",
1835702Ssaidi@eecs.umich.edu                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
1845702Ssaidi@eecs.umich.edu                req->paddr, *(req->data),
1855702Ssaidi@eecs.umich.edu                storeQueue[storeWBIdx].inst->seqNum);
1865702Ssaidi@eecs.umich.edu
1875702Ssaidi@eecs.umich.edu        switch(storeQueue[storeWBIdx].size) {
1885702Ssaidi@eecs.umich.edu          case 1:
1895702Ssaidi@eecs.umich.edu            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
1905702Ssaidi@eecs.umich.edu            break;
1918557Sgblack@eecs.umich.edu          case 2:
1928557Sgblack@eecs.umich.edu            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
1931061SN/A            break;
1941061SN/A          case 4:
1955596Sgblack@eecs.umich.edu            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
1961061SN/A            break;
1978557Sgblack@eecs.umich.edu          case 8:
1988557Sgblack@eecs.umich.edu            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
1998557Sgblack@eecs.umich.edu            break;
2005556SN/A          default:
2015556SN/A            panic("Unexpected store size!\n");
2025556SN/A        }
2037720Sgblack@eecs.umich.edu        incrStIdx(storeWBIdx);
2042669SN/A    }
2057720Sgblack@eecs.umich.edu}
2067720Sgblack@eecs.umich.edu
2077720Sgblack@eecs.umich.edutemplate<class Impl>
2085556SN/Avoid
2098557Sgblack@eecs.umich.eduLSQUnit<Impl>::takeOverFrom()
2101061SN/A{
2111061SN/A    switchedOut = false;
212    loads = stores = storesToWB = 0;
213
214    loadHead = loadTail = 0;
215
216    storeHead = storeWBIdx = storeTail = 0;
217
218    usedPorts = 0;
219
220    loadFaultInst = storeFaultInst = memDepViolator = NULL;
221
222    blockedLoadSeqNum = 0;
223
224    stalled = false;
225    isLoadBlocked = false;
226    loadBlockedHandled = false;
227}
228
229template<class Impl>
230void
231LSQUnit<Impl>::resizeLQ(unsigned size)
232{
233    assert( size >= LQEntries);
234
235    if (size > LQEntries) {
236        while (size > loadQueue.size()) {
237            DynInstPtr dummy;
238            loadQueue.push_back(dummy);
239            LQEntries++;
240        }
241    } else {
242        LQEntries = size;
243    }
244
245}
246
247template<class Impl>
248void
249LSQUnit<Impl>::resizeSQ(unsigned size)
250{
251    if (size > SQEntries) {
252        while (size > storeQueue.size()) {
253            SQEntry dummy;
254            storeQueue.push_back(dummy);
255            SQEntries++;
256        }
257    } else {
258        SQEntries = size;
259    }
260}
261
262template <class Impl>
263void
264LSQUnit<Impl>::insert(DynInstPtr &inst)
265{
266    // Make sure we really have a memory reference.
267    assert(inst->isMemRef());
268
269    // Make sure it's one of the two classes of memory references.
270    assert(inst->isLoad() || inst->isStore());
271
272    if (inst->isLoad()) {
273        insertLoad(inst);
274    } else {
275        insertStore(inst);
276    }
277
278    inst->setInLSQ();
279}
280
281template <class Impl>
282void
283LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
284{
285    assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries);
286
287    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
288            load_inst->readPC(), loadTail, load_inst->seqNum);
289
290    load_inst->lqIdx = loadTail;
291
292    if (stores == 0) {
293        load_inst->sqIdx = -1;
294    } else {
295        load_inst->sqIdx = storeTail;
296    }
297
298    loadQueue[loadTail] = load_inst;
299
300    incrLdIdx(loadTail);
301
302    ++loads;
303}
304
305template <class Impl>
306void
307LSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
308{
309    // Make sure it is not full before inserting an instruction.
310    assert((storeTail + 1) % SQEntries != storeHead);
311    assert(stores < SQEntries);
312
313    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
314            store_inst->readPC(), storeTail, store_inst->seqNum);
315
316    store_inst->sqIdx = storeTail;
317    store_inst->lqIdx = loadTail;
318
319    storeQueue[storeTail] = SQEntry(store_inst);
320
321    incrStIdx(storeTail);
322
323    ++stores;
324
325}
326
327template <class Impl>
328typename Impl::DynInstPtr
329LSQUnit<Impl>::getMemDepViolator()
330{
331    DynInstPtr temp = memDepViolator;
332
333    memDepViolator = NULL;
334
335    return temp;
336}
337
338template <class Impl>
339unsigned
340LSQUnit<Impl>::numFreeEntries()
341{
342    unsigned free_lq_entries = LQEntries - loads;
343    unsigned free_sq_entries = SQEntries - stores;
344
345    // Both the LQ and SQ entries have an extra dummy entry to differentiate
346    // empty/full conditions.  Subtract 1 from the free entries.
347    if (free_lq_entries < free_sq_entries) {
348        return free_lq_entries - 1;
349    } else {
350        return free_sq_entries - 1;
351    }
352}
353
354template <class Impl>
355int
356LSQUnit<Impl>::numLoadsReady()
357{
358    int load_idx = loadHead;
359    int retval = 0;
360
361    while (load_idx != loadTail) {
362        assert(loadQueue[load_idx]);
363
364        if (loadQueue[load_idx]->readyToIssue()) {
365            ++retval;
366        }
367    }
368
369    return retval;
370}
371
372#if 0
373template <class Impl>
374Fault
375LSQUnit<Impl>::executeLoad()
376{
377    Fault load_fault = NoFault;
378    DynInstPtr load_inst;
379
380    assert(readyLoads.size() != 0);
381
382    // Execute a ready load.
383    LdMapIt ready_it = readyLoads.begin();
384
385    load_inst = (*ready_it).second;
386
387    // Execute the instruction, which is held in the data portion of the
388    // iterator.
389    load_fault = load_inst->execute();
390
391    // If it executed successfully, then switch it over to the executed
392    // loads list.
393    if (load_fault == NoFault) {
394        executedLoads[load_inst->seqNum] = load_inst;
395
396        readyLoads.erase(ready_it);
397    } else {
398        loadFaultInst = load_inst;
399    }
400
401    return load_fault;
402}
403#endif
404
405template <class Impl>
406Fault
407LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
408{
409    // Execute a specific load.
410    Fault load_fault = NoFault;
411
412    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
413            inst->readPC(),inst->seqNum);
414
415    // Make sure it's really in the list.
416    // Normally it should always be in the list.  However,
417    /* due to a syscall it may not be the list.
418#ifdef DEBUG
419    int i = loadHead;
420    while (1) {
421        if (i == loadTail && !find(inst)) {
422            assert(0 && "Load not in the queue!");
423        } else if (loadQueue[i] == inst) {
424            break;
425        }
426
427        i = i + 1;
428        if (i >= LQEntries) {
429            i = 0;
430        }
431    }
432#endif // DEBUG*/
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        // Maybe just set it as can commit here, although that might cause
441        // some other problems with sending traps to the ROB too quickly.
442        iewStage->instToCommit(inst);
443        iewStage->activityThisCycle();
444    }
445
446    return load_fault;
447}
448
449template <class Impl>
450Fault
451LSQUnit<Impl>::executeLoad(int lq_idx)
452{
453    // Very hackish.  Not sure the best way to check that this
454    // instruction is at the head of the ROB.  I should have some sort
455    // of extra information here so that I'm not overloading the
456    // canCommit signal for 15 different things.
457    loadQueue[lq_idx]->setCanCommit();
458    Fault ret_fault = executeLoad(loadQueue[lq_idx]);
459    loadQueue[lq_idx]->clearCanCommit();
460    return ret_fault;
461}
462
463template <class Impl>
464Fault
465LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
466{
467    using namespace TheISA;
468    // Make sure that a store exists.
469    assert(stores != 0);
470
471    int store_idx = store_inst->sqIdx;
472
473    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
474            store_inst->readPC(), store_inst->seqNum);
475
476    // Check the recently completed loads to see if any match this store's
477    // address.  If so, then we have a memory ordering violation.
478    int load_idx = store_inst->lqIdx;
479
480    Fault store_fault = store_inst->initiateAcc();
481//    Fault store_fault = store_inst->execute();
482
483    // Store size should now be available.  Use it to get proper offset for
484    // addr comparisons.
485    int size = storeQueue[store_idx].size;
486
487    if (size == 0) {
488        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
489                store_inst->readPC(),store_inst->seqNum);
490
491        return store_fault;
492    }
493
494    assert(store_fault == NoFault);
495
496    if (!storeFaultInst) {
497        if (store_fault != NoFault) {
498            panic("Fault in a store instruction!");
499            storeFaultInst = store_inst;
500        } else if (store_inst->isNonSpeculative()) {
501            // Nonspeculative accesses (namely store conditionals)
502            // need to set themselves as able to writeback if we
503            // haven't had a fault by here.
504            storeQueue[store_idx].canWB = true;
505
506            ++storesToWB;
507        }
508    }
509
510    if (!memDepViolator) {
511        while (load_idx != loadTail) {
512            // Actually should only check loads that have actually executed
513            // Might be safe because effAddr is set to InvalAddr when the
514            // dyn inst is created.
515
516            // Must actually check all addrs in the proper size range
517            // Which is more correct than needs to be.  What if for now we just
518            // assume all loads are quad-word loads, and do the addr based
519            // on that.
520            // @todo: Fix this, magic number being used here
521            if ((loadQueue[load_idx]->effAddr >> 8) ==
522                (store_inst->effAddr >> 8)) {
523                // A load incorrectly passed this store.  Squash and refetch.
524                // For now return a fault to show that it was unsuccessful.
525                memDepViolator = loadQueue[load_idx];
526
527                return genMachineCheckFault();
528            }
529
530            incrLdIdx(load_idx);
531        }
532
533        // If we've reached this point, there was no violation.
534        memDepViolator = NULL;
535    }
536
537    return store_fault;
538}
539
540template <class Impl>
541void
542LSQUnit<Impl>::commitLoad()
543{
544    assert(loadQueue[loadHead]);
545
546    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
547            loadQueue[loadHead]->readPC());
548
549
550    loadQueue[loadHead] = NULL;
551
552    incrLdIdx(loadHead);
553
554    --loads;
555}
556
557template <class Impl>
558void
559LSQUnit<Impl>::commitLoad(InstSeqNum &inst)
560{
561    // Hopefully I don't use this function too much
562    panic("Don't use this function!");
563
564    int i = loadHead;
565    while (1) {
566        if (i == loadTail) {
567            assert(0 && "Load not in the queue!");
568        } else if (loadQueue[i]->seqNum == inst) {
569            break;
570        }
571
572        ++i;
573        if (i >= LQEntries) {
574            i = 0;
575        }
576    }
577
578    loadQueue[i]->removeInLSQ();
579    loadQueue[i] = NULL;
580    --loads;
581}
582
583template <class Impl>
584void
585LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
586{
587    assert(loads == 0 || loadQueue[loadHead]);
588
589    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
590        commitLoad();
591    }
592}
593
594template <class Impl>
595void
596LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
597{
598    assert(stores == 0 || storeQueue[storeHead].inst);
599
600    int store_idx = storeHead;
601
602    while (store_idx != storeTail) {
603        assert(storeQueue[store_idx].inst);
604        if (!storeQueue[store_idx].canWB) {
605            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
606                break;
607            }
608            DPRINTF(LSQUnit, "Marking store as able to write back, PC "
609                    "%#x [sn:%lli]\n",
610                    storeQueue[store_idx].inst->readPC(),
611                    storeQueue[store_idx].inst->seqNum);
612
613            storeQueue[store_idx].canWB = true;
614
615//            --stores;
616            ++storesToWB;
617        }
618
619        incrStIdx(store_idx);
620    }
621}
622
623template <class Impl>
624void
625LSQUnit<Impl>::writebackStores()
626{
627    while (storesToWB > 0 &&
628           storeWBIdx != storeTail &&
629           storeQueue[storeWBIdx].inst &&
630           storeQueue[storeWBIdx].canWB &&
631           usedPorts < cachePorts) {
632
633        if (storeQueue[storeWBIdx].size == 0) {
634            completeStore(storeWBIdx);
635
636            incrStIdx(storeWBIdx);
637
638            continue;
639        }
640
641        if (dcacheInterface && dcacheInterface->isBlocked()) {
642            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
643                    " is blocked!\n");
644            break;
645        }
646
647        ++usedPorts;
648
649        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
650            incrStIdx(storeWBIdx);
651
652            continue;
653        }
654
655        assert(storeQueue[storeWBIdx].req);
656        assert(!storeQueue[storeWBIdx].committed);
657
658        MemReqPtr req = storeQueue[storeWBIdx].req;
659        storeQueue[storeWBIdx].committed = true;
660
661//	Fault fault = cpu->translateDataWriteReq(req);
662        req->cmd = Write;
663        req->completionEvent = NULL;
664        req->time = curTick;
665        assert(!req->data);
666        req->data = new uint8_t[64];
667        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
668
669        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
670                "to Addr:%#x, data:%#x [sn:%lli]\n",
671                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
672                req->paddr, *(req->data),
673                storeQueue[storeWBIdx].inst->seqNum);
674
675        switch(storeQueue[storeWBIdx].size) {
676          case 1:
677            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
678            break;
679          case 2:
680            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
681            break;
682          case 4:
683            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
684            break;
685          case 8:
686            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
687            break;
688          default:
689            panic("Unexpected store size!\n");
690        }
691        if (!(req->flags & LOCKED)) {
692            storeQueue[storeWBIdx].inst->setCompleted();
693        }
694
695        if (dcacheInterface) {
696            assert(!req->completionEvent);
697            StoreCompletionEvent *store_event = new
698                StoreCompletionEvent(storeWBIdx, NULL, this);
699            req->completionEvent = store_event;
700
701            MemAccessResult result = dcacheInterface->access(req);
702
703            if (isStalled() &&
704                storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
705                DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
706                        "load idx:%i\n",
707                        stallingStoreIsn, stallingLoadIdx);
708                stalled = false;
709                stallingStoreIsn = 0;
710                iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
711            }
712
713            if (result != MA_HIT && dcacheInterface->doEvents()) {
714                typename IEW::LdWritebackEvent *wb = NULL;
715                if (req->flags & LOCKED) {
716                    // Stx_C should not generate a system port transaction,
717                    // but that might be hard to accomplish.
718                    wb = new typename
719                        IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
720                                              iewStage);
721                    store_event->wbEvent = wb;
722                }
723
724                DPRINTF(LSQUnit,"D-Cache Write Miss!\n");
725
726                DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
727                        storeQueue[storeWBIdx].inst->seqNum);
728
729                lastDcacheStall = curTick;
730
731//                _status = DcacheMissStall;
732
733                //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
734
735                //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
736
737                // Increment stat here or something
738            } else {
739                DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
740                        storeWBIdx);
741
742                DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
743                        storeQueue[storeWBIdx].inst->seqNum);
744
745
746                if (req->flags & LOCKED) {
747                    // Stx_C does not generate a system port transaction.
748/*
749                    if (req->flags & UNCACHEABLE) {
750                        req->result = 2;
751                    } else {
752                        if (cpu->lockFlag && cpu->lockAddr == req->paddr) {
753                            req->result=1;
754                        } else {
755                            req->result = 0;
756                        }
757                    }
758*/
759                    typename IEW::LdWritebackEvent *wb =
760                        new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
761                                                           iewStage);
762                    store_event->wbEvent = wb;
763                }
764            }
765
766            incrStIdx(storeWBIdx);
767        } else {
768            panic("Must HAVE DCACHE!!!!!\n");
769        }
770    }
771
772    // Not sure this should set it to 0.
773    usedPorts = 0;
774
775    assert(stores >= 0 && storesToWB >= 0);
776}
777
778/*template <class Impl>
779void
780LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
781{
782    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
783                                              mshrSeqNums.end(),
784                                              seqNum);
785
786    if (mshr_it != mshrSeqNums.end()) {
787        mshrSeqNums.erase(mshr_it);
788        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
789    }
790}*/
791
792template <class Impl>
793void
794LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
795{
796    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
797            "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
798
799    int load_idx = loadTail;
800    decrLdIdx(load_idx);
801
802    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
803
804        // Clear the smart pointer to make sure it is decremented.
805        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
806                "[sn:%lli]\n",
807                loadQueue[load_idx]->readPC(),
808                loadQueue[load_idx]->seqNum);
809
810        if (isStalled() && load_idx == stallingLoadIdx) {
811            stalled = false;
812            stallingStoreIsn = 0;
813            stallingLoadIdx = 0;
814        }
815
816        loadQueue[load_idx]->squashed = true;
817        loadQueue[load_idx] = NULL;
818        --loads;
819
820        // Inefficient!
821        loadTail = load_idx;
822
823        decrLdIdx(load_idx);
824    }
825
826    if (isLoadBlocked) {
827        if (squashed_num < blockedLoadSeqNum) {
828            isLoadBlocked = false;
829            loadBlockedHandled = false;
830            blockedLoadSeqNum = 0;
831        }
832    }
833
834    int store_idx = storeTail;
835    decrStIdx(store_idx);
836
837    while (stores != 0 &&
838           storeQueue[store_idx].inst->seqNum > squashed_num) {
839
840        if (storeQueue[store_idx].canWB) {
841            break;
842        }
843
844        // Clear the smart pointer to make sure it is decremented.
845        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
846                "idx:%i [sn:%lli]\n",
847                storeQueue[store_idx].inst->readPC(),
848                store_idx, storeQueue[store_idx].inst->seqNum);
849
850        // I don't think this can happen.  It should have been cleared by the
851        // stalling load.
852        if (isStalled() &&
853            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
854            panic("Is stalled should have been cleared by stalling load!\n");
855            stalled = false;
856            stallingStoreIsn = 0;
857        }
858
859        storeQueue[store_idx].inst->squashed = true;
860        storeQueue[store_idx].inst = NULL;
861        storeQueue[store_idx].canWB = 0;
862
863        if (storeQueue[store_idx].req) {
864            assert(!storeQueue[store_idx].req->completionEvent);
865        }
866        storeQueue[store_idx].req = NULL;
867        --stores;
868
869        // Inefficient!
870        storeTail = store_idx;
871
872        decrStIdx(store_idx);
873    }
874}
875
876template <class Impl>
877void
878LSQUnit<Impl>::dumpInsts()
879{
880    cprintf("Load store queue: Dumping instructions.\n");
881    cprintf("Load queue size: %i\n", loads);
882    cprintf("Load queue: ");
883
884    int load_idx = loadHead;
885
886    while (load_idx != loadTail && loadQueue[load_idx]) {
887        cprintf("%#x ", loadQueue[load_idx]->readPC());
888
889        incrLdIdx(load_idx);
890    }
891
892    cprintf("Store queue size: %i\n", stores);
893    cprintf("Store queue: ");
894
895    int store_idx = storeHead;
896
897    while (store_idx != storeTail && storeQueue[store_idx].inst) {
898        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
899
900        incrStIdx(store_idx);
901    }
902
903    cprintf("\n");
904}
905
906template <class Impl>
907void
908LSQUnit<Impl>::completeStore(int store_idx)
909{
910    assert(storeQueue[store_idx].inst);
911    storeQueue[store_idx].completed = true;
912    --storesToWB;
913    // A bit conservative because a store completion may not free up entries,
914    // but hopefully avoids two store completions in one cycle from making
915    // the CPU tick twice.
916    cpu->activityThisCycle();
917
918    if (store_idx == storeHead) {
919        do {
920            incrStIdx(storeHead);
921
922            --stores;
923        } while (storeQueue[storeHead].completed &&
924                 storeHead != storeTail);
925
926        iewStage->updateLSQNextCycle = true;
927    }
928
929    DPRINTF(LSQUnit, "Store head idx:%i\n", storeHead);
930
931    if (isStalled() &&
932        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
933        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
934                "load idx:%i\n",
935                stallingStoreIsn, stallingLoadIdx);
936        stalled = false;
937        stallingStoreIsn = 0;
938        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
939    }
940}
941
942template <class Impl>
943inline void
944LSQUnit<Impl>::incrStIdx(int &store_idx)
945{
946    if (++store_idx >= SQEntries)
947        store_idx = 0;
948}
949
950template <class Impl>
951inline void
952LSQUnit<Impl>::decrStIdx(int &store_idx)
953{
954    if (--store_idx < 0)
955        store_idx += SQEntries;
956}
957
958template <class Impl>
959inline void
960LSQUnit<Impl>::incrLdIdx(int &load_idx)
961{
962    if (++load_idx >= LQEntries)
963        load_idx = 0;
964}
965
966template <class Impl>
967inline void
968LSQUnit<Impl>::decrLdIdx(int &load_idx)
969{
970    if (--load_idx < 0)
971        load_idx += LQEntries;
972}
973