lsq_unit_impl.hh revision 2336
111524Sdavid.guillen@arm.com/*
211524Sdavid.guillen@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
311524Sdavid.guillen@arm.com * All rights reserved.
411524Sdavid.guillen@arm.com *
511524Sdavid.guillen@arm.com * Redistribution and use in source and binary forms, with or without
611524Sdavid.guillen@arm.com * modification, are permitted provided that the following conditions are
711524Sdavid.guillen@arm.com * met: redistributions of source code must retain the above copyright
811524Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer;
911524Sdavid.guillen@arm.com * redistributions in binary form must reproduce the above copyright
1011524Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer in the
1111524Sdavid.guillen@arm.com * documentation and/or other materials provided with the distribution;
1211524Sdavid.guillen@arm.com * neither the name of the copyright holders nor the names of its
1311524Sdavid.guillen@arm.com * contributors may be used to endorse or promote products derived from
1411524Sdavid.guillen@arm.com * this software without specific prior written permission.
1511524Sdavid.guillen@arm.com *
1611524Sdavid.guillen@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711524Sdavid.guillen@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811524Sdavid.guillen@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911524Sdavid.guillen@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011524Sdavid.guillen@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111524Sdavid.guillen@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211524Sdavid.guillen@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311524Sdavid.guillen@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411524Sdavid.guillen@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511524Sdavid.guillen@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611524Sdavid.guillen@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711524Sdavid.guillen@arm.com */
2811524Sdavid.guillen@arm.com
2911524Sdavid.guillen@arm.com#include "cpu/checker/cpu.hh"
3011524Sdavid.guillen@arm.com#include "cpu/o3/lsq_unit.hh"
3111524Sdavid.guillen@arm.com#include "base/str.hh"
3211524Sdavid.guillen@arm.com
3311524Sdavid.guillen@arm.comtemplate <class Impl>
3411524Sdavid.guillen@arm.comLSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx,
3511524Sdavid.guillen@arm.com                                                          Event *wb_event,
3611524Sdavid.guillen@arm.com                                                          LSQUnit<Impl> *lsq_ptr)
3711524Sdavid.guillen@arm.com    : Event(&mainEventQueue),
3811524Sdavid.guillen@arm.com      wbEvent(wb_event),
3911524Sdavid.guillen@arm.com      storeIdx(store_idx),
4011524Sdavid.guillen@arm.com      lsqPtr(lsq_ptr)
4111524Sdavid.guillen@arm.com{
4211524Sdavid.guillen@arm.com    this->setFlags(Event::AutoDelete);
4311524Sdavid.guillen@arm.com}
4411524Sdavid.guillen@arm.com
4511524Sdavid.guillen@arm.comtemplate <class Impl>
4611524Sdavid.guillen@arm.comvoid
4711524Sdavid.guillen@arm.comLSQUnit<Impl>::StoreCompletionEvent::process()
4811524Sdavid.guillen@arm.com{
4911524Sdavid.guillen@arm.com    DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx);
5011524Sdavid.guillen@arm.com    DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx);
5111524Sdavid.guillen@arm.com
5211524Sdavid.guillen@arm.com    //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
5311524Sdavid.guillen@arm.com
5411524Sdavid.guillen@arm.com    if (lsqPtr->isSwitchedOut())
5511524Sdavid.guillen@arm.com        return;
5611524Sdavid.guillen@arm.com
5711524Sdavid.guillen@arm.com    lsqPtr->cpu->wakeCPU();
5811524Sdavid.guillen@arm.com    if (wbEvent)
5911524Sdavid.guillen@arm.com        wbEvent->process();
6011524Sdavid.guillen@arm.com    lsqPtr->completeStore(storeIdx);
6111524Sdavid.guillen@arm.com}
6211524Sdavid.guillen@arm.com
6311524Sdavid.guillen@arm.comtemplate <class Impl>
6411524Sdavid.guillen@arm.comconst char *
6511524Sdavid.guillen@arm.comLSQUnit<Impl>::StoreCompletionEvent::description()
6611524Sdavid.guillen@arm.com{
6711524Sdavid.guillen@arm.com    return "LSQ store completion event";
6811524Sdavid.guillen@arm.com}
6911524Sdavid.guillen@arm.com
7011524Sdavid.guillen@arm.comtemplate <class Impl>
7111524Sdavid.guillen@arm.comLSQUnit<Impl>::LSQUnit()
7211524Sdavid.guillen@arm.com    : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
7311524Sdavid.guillen@arm.com      loadBlockedHandled(false)
7411524Sdavid.guillen@arm.com{
7511524Sdavid.guillen@arm.com}
7611524Sdavid.guillen@arm.com
7711524Sdavid.guillen@arm.comtemplate<class Impl>
7811524Sdavid.guillen@arm.comvoid
7911524Sdavid.guillen@arm.comLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
8011524Sdavid.guillen@arm.com                    unsigned maxSQEntries, unsigned id)
8111524Sdavid.guillen@arm.com
8211524Sdavid.guillen@arm.com{
8311524Sdavid.guillen@arm.com    DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
8411524Sdavid.guillen@arm.com
8511524Sdavid.guillen@arm.com    switchedOut = false;
8611524Sdavid.guillen@arm.com
8711524Sdavid.guillen@arm.com    lsqID = id;
8811524Sdavid.guillen@arm.com
8911524Sdavid.guillen@arm.com    // Add 1 for the sentinel entry (they are circular queues).
9011524Sdavid.guillen@arm.com    LQEntries = maxLQEntries + 1;
9111524Sdavid.guillen@arm.com    SQEntries = maxSQEntries + 1;
9211524Sdavid.guillen@arm.com
9311524Sdavid.guillen@arm.com    loadQueue.resize(LQEntries);
9411524Sdavid.guillen@arm.com    storeQueue.resize(SQEntries);
9511524Sdavid.guillen@arm.com
9611524Sdavid.guillen@arm.com    loadHead = loadTail = 0;
9711524Sdavid.guillen@arm.com
9811524Sdavid.guillen@arm.com    storeHead = storeWBIdx = storeTail = 0;
9911524Sdavid.guillen@arm.com
10011524Sdavid.guillen@arm.com    usedPorts = 0;
10111524Sdavid.guillen@arm.com    cachePorts = params->cachePorts;
10211524Sdavid.guillen@arm.com
10311524Sdavid.guillen@arm.com    dcacheInterface = params->dcacheInterface;
10411524Sdavid.guillen@arm.com
10511524Sdavid.guillen@arm.com    memDepViolator = NULL;
10611524Sdavid.guillen@arm.com
10711524Sdavid.guillen@arm.com    blockedLoadSeqNum = 0;
10811524Sdavid.guillen@arm.com}
10911524Sdavid.guillen@arm.com
11011524Sdavid.guillen@arm.comtemplate<class Impl>
11111524Sdavid.guillen@arm.comstd::string
11211524Sdavid.guillen@arm.comLSQUnit<Impl>::name() const
11311524Sdavid.guillen@arm.com{
11411524Sdavid.guillen@arm.com    if (Impl::MaxThreads == 1) {
11511524Sdavid.guillen@arm.com        return iewStage->name() + ".lsq";
11611524Sdavid.guillen@arm.com    } else {
11711524Sdavid.guillen@arm.com        return iewStage->name() + ".lsq.thread." + to_string(lsqID);
11811524Sdavid.guillen@arm.com    }
11911524Sdavid.guillen@arm.com}
12011524Sdavid.guillen@arm.com
12111524Sdavid.guillen@arm.comtemplate<class Impl>
12211524Sdavid.guillen@arm.comvoid
12311524Sdavid.guillen@arm.comLSQUnit<Impl>::clearLQ()
12411524Sdavid.guillen@arm.com{
12511524Sdavid.guillen@arm.com    loadQueue.clear();
12611524Sdavid.guillen@arm.com}
12711524Sdavid.guillen@arm.com
12811524Sdavid.guillen@arm.comtemplate<class Impl>
12911524Sdavid.guillen@arm.comvoid
13011524Sdavid.guillen@arm.comLSQUnit<Impl>::clearSQ()
13111524Sdavid.guillen@arm.com{
13211524Sdavid.guillen@arm.com    storeQueue.clear();
13311524Sdavid.guillen@arm.com}
13411524Sdavid.guillen@arm.com
13511524Sdavid.guillen@arm.com#if 0
13611524Sdavid.guillen@arm.comtemplate<class Impl>
13711524Sdavid.guillen@arm.comvoid
13811524Sdavid.guillen@arm.comLSQUnit<Impl>::setPageTable(PageTable *pt_ptr)
13911524Sdavid.guillen@arm.com{
14011524Sdavid.guillen@arm.com    DPRINTF(LSQUnit, "Setting the page table pointer.\n");
14111524Sdavid.guillen@arm.com    pTable = pt_ptr;
14211524Sdavid.guillen@arm.com}
14311524Sdavid.guillen@arm.com#endif
14411524Sdavid.guillen@arm.com
14511525Sandreas.sandberg@arm.comtemplate<class Impl>
14611524Sdavid.guillen@arm.comvoid
14711524Sdavid.guillen@arm.comLSQUnit<Impl>::switchOut()
14811524Sdavid.guillen@arm.com{
14911524Sdavid.guillen@arm.com    switchedOut = true;
15011524Sdavid.guillen@arm.com    for (int i = 0; i < loadQueue.size(); ++i)
15111524Sdavid.guillen@arm.com        loadQueue[i] = NULL;
15211524Sdavid.guillen@arm.com
15311524Sdavid.guillen@arm.com    assert(storesToWB == 0);
15411524Sdavid.guillen@arm.com
15511525Sandreas.sandberg@arm.com    while (storesToWB > 0 &&
15611524Sdavid.guillen@arm.com           storeWBIdx != storeTail &&
15711524Sdavid.guillen@arm.com           storeQueue[storeWBIdx].inst &&
15811524Sdavid.guillen@arm.com           storeQueue[storeWBIdx].canWB) {
15911524Sdavid.guillen@arm.com
16011524Sdavid.guillen@arm.com        if (storeQueue[storeWBIdx].size == 0 ||
16111524Sdavid.guillen@arm.com            storeQueue[storeWBIdx].inst->isDataPrefetch() ||
16211525Sandreas.sandberg@arm.com            storeQueue[storeWBIdx].committed ||
16311524Sdavid.guillen@arm.com            storeQueue[storeWBIdx].req->flags & LOCKED) {
16411524Sdavid.guillen@arm.com            incrStIdx(storeWBIdx);
16511524Sdavid.guillen@arm.com
16611524Sdavid.guillen@arm.com            continue;
16711524Sdavid.guillen@arm.com        }
16811524Sdavid.guillen@arm.com
16911524Sdavid.guillen@arm.com        assert(storeQueue[storeWBIdx].req);
17011524Sdavid.guillen@arm.com        assert(!storeQueue[storeWBIdx].committed);
17111524Sdavid.guillen@arm.com
17211524Sdavid.guillen@arm.com        MemReqPtr req = storeQueue[storeWBIdx].req;
17311524Sdavid.guillen@arm.com        storeQueue[storeWBIdx].committed = true;
17411524Sdavid.guillen@arm.com
17511524Sdavid.guillen@arm.com        req->cmd = Write;
17611524Sdavid.guillen@arm.com        req->completionEvent = NULL;
17711524Sdavid.guillen@arm.com        req->time = curTick;
17811524Sdavid.guillen@arm.com        assert(!req->data);
17911524Sdavid.guillen@arm.com        req->data = new uint8_t[64];
180        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
181
182        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
183                "to Addr:%#x, data:%#x [sn:%lli]\n",
184                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
185                req->paddr, *(req->data),
186                storeQueue[storeWBIdx].inst->seqNum);
187
188        switch(storeQueue[storeWBIdx].size) {
189          case 1:
190            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
191            break;
192          case 2:
193            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
194            break;
195          case 4:
196            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
197            break;
198          case 8:
199            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
200            break;
201          default:
202            panic("Unexpected store size!\n");
203        }
204        incrStIdx(storeWBIdx);
205    }
206}
207
208template<class Impl>
209void
210LSQUnit<Impl>::takeOverFrom()
211{
212    switchedOut = false;
213    loads = stores = storesToWB = 0;
214
215    loadHead = loadTail = 0;
216
217    storeHead = storeWBIdx = storeTail = 0;
218
219    usedPorts = 0;
220
221    memDepViolator = NULL;
222
223    blockedLoadSeqNum = 0;
224
225    stalled = false;
226    isLoadBlocked = false;
227    loadBlockedHandled = false;
228}
229
230template<class Impl>
231void
232LSQUnit<Impl>::resizeLQ(unsigned size)
233{
234    unsigned size_plus_sentinel = size + 1;
235    assert(size_plus_sentinel >= LQEntries);
236
237    if (size_plus_sentinel > LQEntries) {
238        while (size_plus_sentinel > loadQueue.size()) {
239            DynInstPtr dummy;
240            loadQueue.push_back(dummy);
241            LQEntries++;
242        }
243    } else {
244        LQEntries = size_plus_sentinel;
245    }
246
247}
248
249template<class Impl>
250void
251LSQUnit<Impl>::resizeSQ(unsigned size)
252{
253    unsigned size_plus_sentinel = size + 1;
254    if (size_plus_sentinel > SQEntries) {
255        while (size_plus_sentinel > storeQueue.size()) {
256            SQEntry dummy;
257            storeQueue.push_back(dummy);
258            SQEntries++;
259        }
260    } else {
261        SQEntries = size_plus_sentinel;
262    }
263}
264
265template <class Impl>
266void
267LSQUnit<Impl>::insert(DynInstPtr &inst)
268{
269    assert(inst->isMemRef());
270
271    assert(inst->isLoad() || inst->isStore());
272
273    if (inst->isLoad()) {
274        insertLoad(inst);
275    } else {
276        insertStore(inst);
277    }
278
279    inst->setInLSQ();
280}
281
282template <class Impl>
283void
284LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
285{
286    assert((loadTail + 1) % LQEntries != loadHead);
287    assert(loads < LQEntries);
288
289    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
290            load_inst->readPC(), loadTail, load_inst->seqNum);
291
292    load_inst->lqIdx = loadTail;
293
294    if (stores == 0) {
295        load_inst->sqIdx = -1;
296    } else {
297        load_inst->sqIdx = storeTail;
298    }
299
300    loadQueue[loadTail] = load_inst;
301
302    incrLdIdx(loadTail);
303
304    ++loads;
305}
306
307template <class Impl>
308void
309LSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
310{
311    // Make sure it is not full before inserting an instruction.
312    assert((storeTail + 1) % SQEntries != storeHead);
313    assert(stores < SQEntries);
314
315    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
316            store_inst->readPC(), storeTail, store_inst->seqNum);
317
318    store_inst->sqIdx = storeTail;
319    store_inst->lqIdx = loadTail;
320
321    storeQueue[storeTail] = SQEntry(store_inst);
322
323    incrStIdx(storeTail);
324
325    ++stores;
326}
327
328template <class Impl>
329typename Impl::DynInstPtr
330LSQUnit<Impl>::getMemDepViolator()
331{
332    DynInstPtr temp = memDepViolator;
333
334    memDepViolator = NULL;
335
336    return temp;
337}
338
339template <class Impl>
340unsigned
341LSQUnit<Impl>::numFreeEntries()
342{
343    unsigned free_lq_entries = LQEntries - loads;
344    unsigned free_sq_entries = SQEntries - stores;
345
346    // Both the LQ and SQ entries have an extra dummy entry to differentiate
347    // empty/full conditions.  Subtract 1 from the free entries.
348    if (free_lq_entries < free_sq_entries) {
349        return free_lq_entries - 1;
350    } else {
351        return free_sq_entries - 1;
352    }
353}
354
355template <class Impl>
356int
357LSQUnit<Impl>::numLoadsReady()
358{
359    int load_idx = loadHead;
360    int retval = 0;
361
362    while (load_idx != loadTail) {
363        assert(loadQueue[load_idx]);
364
365        if (loadQueue[load_idx]->readyToIssue()) {
366            ++retval;
367        }
368    }
369
370    return retval;
371}
372
373template <class Impl>
374Fault
375LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
376{
377    // Execute a specific load.
378    Fault load_fault = NoFault;
379
380    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
381            inst->readPC(),inst->seqNum);
382
383//    load_fault = inst->initiateAcc();
384    load_fault = inst->execute();
385
386    // If the instruction faulted, then we need to send it along to commit
387    // without the instruction completing.
388    if (load_fault != NoFault) {
389        // Send this instruction to commit, also make sure iew stage
390        // realizes there is activity.
391        iewStage->instToCommit(inst);
392        iewStage->activityThisCycle();
393    }
394
395    return load_fault;
396}
397
398template <class Impl>
399Fault
400LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
401{
402    using namespace TheISA;
403    // Make sure that a store exists.
404    assert(stores != 0);
405
406    int store_idx = store_inst->sqIdx;
407
408    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
409            store_inst->readPC(), store_inst->seqNum);
410
411    // Check the recently completed loads to see if any match this store's
412    // address.  If so, then we have a memory ordering violation.
413    int load_idx = store_inst->lqIdx;
414
415    Fault store_fault = store_inst->initiateAcc();
416//    Fault store_fault = store_inst->execute();
417
418    if (storeQueue[store_idx].size == 0) {
419        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
420                store_inst->readPC(),store_inst->seqNum);
421
422        return store_fault;
423    }
424
425    assert(store_fault == NoFault);
426
427    if (store_inst->isStoreConditional()) {
428        // Store conditionals need to set themselves as able to
429        // writeback if we haven't had a fault by here.
430        storeQueue[store_idx].canWB = true;
431
432        ++storesToWB;
433    }
434
435    if (!memDepViolator) {
436        while (load_idx != loadTail) {
437            // Really only need to check loads that have actually executed
438            // It's safe to check all loads because effAddr is set to
439            // InvalAddr when the dyn inst is created.
440
441            // @todo: For now this is extra conservative, detecting a
442            // violation if the addresses match assuming all accesses
443            // are quad word accesses.
444
445            // @todo: Fix this, magic number being used here
446            if ((loadQueue[load_idx]->effAddr >> 8) ==
447                (store_inst->effAddr >> 8)) {
448                // A load incorrectly passed this store.  Squash and refetch.
449                // For now return a fault to show that it was unsuccessful.
450                memDepViolator = loadQueue[load_idx];
451
452                return genMachineCheckFault();
453            }
454
455            incrLdIdx(load_idx);
456        }
457
458        // If we've reached this point, there was no violation.
459        memDepViolator = NULL;
460    }
461
462    return store_fault;
463}
464
465template <class Impl>
466void
467LSQUnit<Impl>::commitLoad()
468{
469    assert(loadQueue[loadHead]);
470
471    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
472            loadQueue[loadHead]->readPC());
473
474
475    loadQueue[loadHead] = NULL;
476
477    incrLdIdx(loadHead);
478
479    --loads;
480}
481
482template <class Impl>
483void
484LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
485{
486    assert(loads == 0 || loadQueue[loadHead]);
487
488    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
489        commitLoad();
490    }
491}
492
493template <class Impl>
494void
495LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
496{
497    assert(stores == 0 || storeQueue[storeHead].inst);
498
499    int store_idx = storeHead;
500
501    while (store_idx != storeTail) {
502        assert(storeQueue[store_idx].inst);
503        // Mark any stores that are now committed and have not yet
504        // been marked as able to write back.
505        if (!storeQueue[store_idx].canWB) {
506            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
507                break;
508            }
509            DPRINTF(LSQUnit, "Marking store as able to write back, PC "
510                    "%#x [sn:%lli]\n",
511                    storeQueue[store_idx].inst->readPC(),
512                    storeQueue[store_idx].inst->seqNum);
513
514            storeQueue[store_idx].canWB = true;
515
516            ++storesToWB;
517        }
518
519        incrStIdx(store_idx);
520    }
521}
522
523template <class Impl>
524void
525LSQUnit<Impl>::writebackStores()
526{
527    while (storesToWB > 0 &&
528           storeWBIdx != storeTail &&
529           storeQueue[storeWBIdx].inst &&
530           storeQueue[storeWBIdx].canWB &&
531           usedPorts < cachePorts) {
532
533        // Store didn't write any data so no need to write it back to
534        // memory.
535        if (storeQueue[storeWBIdx].size == 0) {
536            completeStore(storeWBIdx);
537
538            incrStIdx(storeWBIdx);
539
540            continue;
541        }
542
543        if (dcacheInterface && dcacheInterface->isBlocked()) {
544            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
545                    " is blocked!\n");
546            break;
547        }
548
549        ++usedPorts;
550
551        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
552            incrStIdx(storeWBIdx);
553
554            continue;
555        }
556
557        assert(storeQueue[storeWBIdx].req);
558        assert(!storeQueue[storeWBIdx].committed);
559
560        MemReqPtr req = storeQueue[storeWBIdx].req;
561        storeQueue[storeWBIdx].committed = true;
562
563        req->cmd = Write;
564        req->completionEvent = NULL;
565        req->time = curTick;
566        assert(!req->data);
567        req->data = new uint8_t[64];
568        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
569
570        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
571                "to Addr:%#x, data:%#x [sn:%lli]\n",
572                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
573                req->paddr, *(req->data),
574                storeQueue[storeWBIdx].inst->seqNum);
575
576        switch(storeQueue[storeWBIdx].size) {
577          case 1:
578            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
579            break;
580          case 2:
581            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
582            break;
583          case 4:
584            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
585            break;
586          case 8:
587            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
588            break;
589          default:
590            panic("Unexpected store size!\n");
591        }
592
593        // Stores other than store conditionals are completed at this
594        // time.  Mark them as completed and, if we have a checker,
595        // tell it that the instruction is completed.
596        // @todo: Figure out what time I can say stores are complete in
597        // the timing memory.
598        if (!(req->flags & LOCKED)) {
599            storeQueue[storeWBIdx].inst->setCompleted();
600            if (cpu->checker) {
601                cpu->checker->tick(storeQueue[storeWBIdx].inst);
602            }
603        }
604
605        if (dcacheInterface) {
606            assert(!req->completionEvent);
607            StoreCompletionEvent *store_event = new
608                StoreCompletionEvent(storeWBIdx, NULL, this);
609            req->completionEvent = store_event;
610
611            MemAccessResult result = dcacheInterface->access(req);
612
613            if (isStalled() &&
614                storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
615                DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
616                        "load idx:%i\n",
617                        stallingStoreIsn, stallingLoadIdx);
618                stalled = false;
619                stallingStoreIsn = 0;
620                iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
621            }
622
623            typename IEW::LdWritebackEvent *wb = NULL;
624            if (req->flags & LOCKED) {
625                // Stx_C should not generate a system port transaction
626                // if it misses in the cache, but that might be hard
627                // to accomplish without explicit cache support.
628                wb = new typename
629                    IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
630                                              iewStage);
631                store_event->wbEvent = wb;
632            }
633
634            if (result != MA_HIT && dcacheInterface->doEvents()) {
635                DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n",
636                        storeWBIdx);
637
638                DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
639                        storeQueue[storeWBIdx].inst->seqNum);
640
641                //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
642
643                //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
644
645                // @todo: Increment stat here.
646            } else {
647                DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
648                        storeWBIdx);
649
650                DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
651                        storeQueue[storeWBIdx].inst->seqNum);
652            }
653
654            incrStIdx(storeWBIdx);
655        } else {
656            panic("Must HAVE DCACHE!!!!!\n");
657        }
658    }
659
660    // Not sure this should set it to 0.
661    usedPorts = 0;
662
663    assert(stores >= 0 && storesToWB >= 0);
664}
665
666/*template <class Impl>
667void
668LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
669{
670    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
671                                              mshrSeqNums.end(),
672                                              seqNum);
673
674    if (mshr_it != mshrSeqNums.end()) {
675        mshrSeqNums.erase(mshr_it);
676        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
677    }
678}*/
679
680template <class Impl>
681void
682LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
683{
684    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
685            "(Loads:%i Stores:%i)\n", squashed_num, loads, stores);
686
687    int load_idx = loadTail;
688    decrLdIdx(load_idx);
689
690    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
691        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
692                "[sn:%lli]\n",
693                loadQueue[load_idx]->readPC(),
694                loadQueue[load_idx]->seqNum);
695
696        if (isStalled() && load_idx == stallingLoadIdx) {
697            stalled = false;
698            stallingStoreIsn = 0;
699            stallingLoadIdx = 0;
700        }
701
702        // Clear the smart pointer to make sure it is decremented.
703        loadQueue[load_idx]->squashed = true;
704        loadQueue[load_idx] = NULL;
705        --loads;
706
707        // Inefficient!
708        loadTail = load_idx;
709
710        decrLdIdx(load_idx);
711    }
712
713    if (isLoadBlocked) {
714        if (squashed_num < blockedLoadSeqNum) {
715            isLoadBlocked = false;
716            loadBlockedHandled = false;
717            blockedLoadSeqNum = 0;
718        }
719    }
720
721    int store_idx = storeTail;
722    decrStIdx(store_idx);
723
724    while (stores != 0 &&
725           storeQueue[store_idx].inst->seqNum > squashed_num) {
726        // Instructions marked as can WB are already committed.
727        if (storeQueue[store_idx].canWB) {
728            break;
729        }
730
731        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
732                "idx:%i [sn:%lli]\n",
733                storeQueue[store_idx].inst->readPC(),
734                store_idx, storeQueue[store_idx].inst->seqNum);
735
736        // I don't think this can happen.  It should have been cleared
737        // by the stalling load.
738        if (isStalled() &&
739            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
740            panic("Is stalled should have been cleared by stalling load!\n");
741            stalled = false;
742            stallingStoreIsn = 0;
743        }
744
745        // Clear the smart pointer to make sure it is decremented.
746        storeQueue[store_idx].inst->squashed = true;
747        storeQueue[store_idx].inst = NULL;
748        storeQueue[store_idx].canWB = 0;
749
750        if (storeQueue[store_idx].req) {
751            // There should not be a completion event if the store has
752            // not yet committed.
753            assert(!storeQueue[store_idx].req->completionEvent);
754        }
755
756        storeQueue[store_idx].req = NULL;
757        --stores;
758
759        // Inefficient!
760        storeTail = store_idx;
761
762        decrStIdx(store_idx);
763    }
764}
765
766template <class Impl>
767void
768LSQUnit<Impl>::completeStore(int store_idx)
769{
770    assert(storeQueue[store_idx].inst);
771    storeQueue[store_idx].completed = true;
772    --storesToWB;
773    // A bit conservative because a store completion may not free up entries,
774    // but hopefully avoids two store completions in one cycle from making
775    // the CPU tick twice.
776    cpu->activityThisCycle();
777
778    if (store_idx == storeHead) {
779        do {
780            incrStIdx(storeHead);
781
782            --stores;
783        } while (storeQueue[storeHead].completed &&
784                 storeHead != storeTail);
785
786        iewStage->updateLSQNextCycle = true;
787    }
788
789    DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head "
790            "idx:%i\n",
791            storeQueue[store_idx].inst->seqNum, store_idx, storeHead);
792
793    if (isStalled() &&
794        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
795        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
796                "load idx:%i\n",
797                stallingStoreIsn, stallingLoadIdx);
798        stalled = false;
799        stallingStoreIsn = 0;
800        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
801    }
802
803    storeQueue[store_idx].inst->setCompleted();
804
805    // Tell the checker we've completed this instruction.  Some stores
806    // may get reported twice to the checker, but the checker can
807    // handle that case.
808    if (cpu->checker) {
809        cpu->checker->tick(storeQueue[store_idx].inst);
810    }
811}
812
813template <class Impl>
814inline void
815LSQUnit<Impl>::incrStIdx(int &store_idx)
816{
817    if (++store_idx >= SQEntries)
818        store_idx = 0;
819}
820
821template <class Impl>
822inline void
823LSQUnit<Impl>::decrStIdx(int &store_idx)
824{
825    if (--store_idx < 0)
826        store_idx += SQEntries;
827}
828
829template <class Impl>
830inline void
831LSQUnit<Impl>::incrLdIdx(int &load_idx)
832{
833    if (++load_idx >= LQEntries)
834        load_idx = 0;
835}
836
837template <class Impl>
838inline void
839LSQUnit<Impl>::decrLdIdx(int &load_idx)
840{
841    if (--load_idx < 0)
842        load_idx += LQEntries;
843}
844
845template <class Impl>
846void
847LSQUnit<Impl>::dumpInsts()
848{
849    cprintf("Load store queue: Dumping instructions.\n");
850    cprintf("Load queue size: %i\n", loads);
851    cprintf("Load queue: ");
852
853    int load_idx = loadHead;
854
855    while (load_idx != loadTail && loadQueue[load_idx]) {
856        cprintf("%#x ", loadQueue[load_idx]->readPC());
857
858        incrLdIdx(load_idx);
859    }
860
861    cprintf("Store queue size: %i\n", stores);
862    cprintf("Store queue: ");
863
864    int store_idx = storeHead;
865
866    while (store_idx != storeTail && storeQueue[store_idx].inst) {
867        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
868
869        incrStIdx(store_idx);
870    }
871
872    cprintf("\n");
873}
874