lsq_impl.hh revision 10239
1/*
2 * Copyright (c) 2011-2012 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder.  You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2005-2006 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Korey Sewell
42 */
43
44#ifndef __CPU_O3_LSQ_IMPL_HH__
45#define __CPU_O3_LSQ_IMPL_HH__
46
47#include <algorithm>
48#include <list>
49#include <string>
50
51#include "cpu/o3/lsq.hh"
52#include "debug/Drain.hh"
53#include "debug/Fetch.hh"
54#include "debug/LSQ.hh"
55#include "debug/Writeback.hh"
56#include "params/DerivO3CPU.hh"
57
58using namespace std;
59
60template <class Impl>
61LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
62    : cpu(cpu_ptr), iewStage(iew_ptr),
63      LQEntries(params->LQEntries),
64      SQEntries(params->SQEntries),
65      numThreads(params->numThreads),
66      retryTid(-1)
67{
68    assert(numThreads > 0 && numThreads <= Impl::MaxThreads);
69
70    //**********************************************/
71    //************ Handle SMT Parameters ***********/
72    //**********************************************/
73    std::string policy = params->smtLSQPolicy;
74
75    //Convert string to lowercase
76    std::transform(policy.begin(), policy.end(), policy.begin(),
77                   (int(*)(int)) tolower);
78
79    //Figure out fetch policy
80    if (policy == "dynamic") {
81        lsqPolicy = Dynamic;
82
83        maxLQEntries = LQEntries;
84        maxSQEntries = SQEntries;
85
86        DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n");
87    } else if (policy == "partitioned") {
88        lsqPolicy = Partitioned;
89
90        //@todo:make work if part_amt doesnt divide evenly.
91        maxLQEntries = LQEntries / numThreads;
92        maxSQEntries = SQEntries / numThreads;
93
94        DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: "
95                "%i entries per LQ | %i entries per SQ\n",
96                maxLQEntries,maxSQEntries);
97    } else if (policy == "threshold") {
98        lsqPolicy = Threshold;
99
100        assert(params->smtLSQThreshold > LQEntries);
101        assert(params->smtLSQThreshold > SQEntries);
102
103        //Divide up by threshold amount
104        //@todo: Should threads check the max and the total
105        //amount of the LSQ
106        maxLQEntries  = params->smtLSQThreshold;
107        maxSQEntries  = params->smtLSQThreshold;
108
109        DPRINTF(LSQ, "LSQ sharing policy set to Threshold: "
110                "%i entries per LQ | %i entries per SQ\n",
111                maxLQEntries,maxSQEntries);
112    } else {
113        assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic,"
114                    "Partitioned, Threshold}");
115    }
116
117    //Initialize LSQs
118    thread = new LSQUnit[numThreads];
119    for (ThreadID tid = 0; tid < numThreads; tid++) {
120        thread[tid].init(cpu, iew_ptr, params, this,
121                         maxLQEntries, maxSQEntries, tid);
122        thread[tid].setDcachePort(&cpu_ptr->getDataPort());
123    }
124}
125
126
127template<class Impl>
128std::string
129LSQ<Impl>::name() const
130{
131    return iewStage->name() + ".lsq";
132}
133
134template<class Impl>
135void
136LSQ<Impl>::regStats()
137{
138    //Initialize LSQs
139    for (ThreadID tid = 0; tid < numThreads; tid++) {
140        thread[tid].regStats();
141    }
142}
143
144template<class Impl>
145void
146LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
147{
148    activeThreads = at_ptr;
149    assert(activeThreads != 0);
150}
151
152template <class Impl>
153void
154LSQ<Impl>::drainSanityCheck() const
155{
156    assert(isDrained());
157
158    for (ThreadID tid = 0; tid < numThreads; tid++)
159        thread[tid].drainSanityCheck();
160}
161
162template <class Impl>
163bool
164LSQ<Impl>::isDrained() const
165{
166    bool drained(true);
167
168    if (!lqEmpty()) {
169        DPRINTF(Drain, "Not drained, LQ not empty.\n");
170        drained = false;
171    }
172
173    if (!sqEmpty()) {
174        DPRINTF(Drain, "Not drained, SQ not empty.\n");
175        drained = false;
176    }
177
178    if (retryTid != InvalidThreadID) {
179        DPRINTF(Drain, "Not drained, the LSQ has blocked the caches.\n");
180        drained = false;
181    }
182
183    return drained;
184}
185
186template <class Impl>
187void
188LSQ<Impl>::takeOverFrom()
189{
190    for (ThreadID tid = 0; tid < numThreads; tid++) {
191        thread[tid].takeOverFrom();
192    }
193}
194
195template <class Impl>
196int
197LSQ<Impl>::entryAmount(ThreadID num_threads)
198{
199    if (lsqPolicy == Partitioned) {
200        return LQEntries / num_threads;
201    } else {
202        return 0;
203    }
204}
205
206template <class Impl>
207void
208LSQ<Impl>::resetEntries()
209{
210    if (lsqPolicy != Dynamic || numThreads > 1) {
211        int active_threads = activeThreads->size();
212
213        int maxEntries;
214
215        if (lsqPolicy == Partitioned) {
216            maxEntries = LQEntries / active_threads;
217        } else if (lsqPolicy == Threshold && active_threads == 1) {
218            maxEntries = LQEntries;
219        } else {
220            maxEntries = LQEntries;
221        }
222
223        list<ThreadID>::iterator threads  = activeThreads->begin();
224        list<ThreadID>::iterator end = activeThreads->end();
225
226        while (threads != end) {
227            ThreadID tid = *threads++;
228
229            resizeEntries(maxEntries, tid);
230        }
231    }
232}
233
234template<class Impl>
235void
236LSQ<Impl>::removeEntries(ThreadID tid)
237{
238    thread[tid].clearLQ();
239    thread[tid].clearSQ();
240}
241
242template<class Impl>
243void
244LSQ<Impl>::resizeEntries(unsigned size, ThreadID tid)
245{
246    thread[tid].resizeLQ(size);
247    thread[tid].resizeSQ(size);
248}
249
250template<class Impl>
251void
252LSQ<Impl>::tick()
253{
254    list<ThreadID>::iterator threads = activeThreads->begin();
255    list<ThreadID>::iterator end = activeThreads->end();
256
257    while (threads != end) {
258        ThreadID tid = *threads++;
259
260        thread[tid].tick();
261    }
262}
263
264template<class Impl>
265void
266LSQ<Impl>::insertLoad(DynInstPtr &load_inst)
267{
268    ThreadID tid = load_inst->threadNumber;
269
270    thread[tid].insertLoad(load_inst);
271}
272
273template<class Impl>
274void
275LSQ<Impl>::insertStore(DynInstPtr &store_inst)
276{
277    ThreadID tid = store_inst->threadNumber;
278
279    thread[tid].insertStore(store_inst);
280}
281
282template<class Impl>
283Fault
284LSQ<Impl>::executeLoad(DynInstPtr &inst)
285{
286    ThreadID tid = inst->threadNumber;
287
288    return thread[tid].executeLoad(inst);
289}
290
291template<class Impl>
292Fault
293LSQ<Impl>::executeStore(DynInstPtr &inst)
294{
295    ThreadID tid = inst->threadNumber;
296
297    return thread[tid].executeStore(inst);
298}
299
300template<class Impl>
301void
302LSQ<Impl>::writebackStores()
303{
304    list<ThreadID>::iterator threads = activeThreads->begin();
305    list<ThreadID>::iterator end = activeThreads->end();
306
307    while (threads != end) {
308        ThreadID tid = *threads++;
309
310        if (numStoresToWB(tid) > 0) {
311            DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores "
312                "available for Writeback.\n", tid, numStoresToWB(tid));
313        }
314
315        thread[tid].writebackStores();
316    }
317}
318
319template<class Impl>
320bool
321LSQ<Impl>::violation()
322{
323    /* Answers: Does Anybody Have a Violation?*/
324    list<ThreadID>::iterator threads = activeThreads->begin();
325    list<ThreadID>::iterator end = activeThreads->end();
326
327    while (threads != end) {
328        ThreadID tid = *threads++;
329
330        if (thread[tid].violation())
331            return true;
332    }
333
334    return false;
335}
336
337template <class Impl>
338void
339LSQ<Impl>::recvRetry()
340{
341    if (retryTid == InvalidThreadID)
342    {
343        //Squashed, so drop it
344        return;
345    }
346    int curr_retry_tid = retryTid;
347    // Speculatively clear the retry Tid.  This will get set again if
348    // the LSQUnit was unable to complete its access.
349    retryTid = -1;
350    thread[curr_retry_tid].recvRetry();
351}
352
353template <class Impl>
354bool
355LSQ<Impl>::recvTimingResp(PacketPtr pkt)
356{
357    if (pkt->isError())
358        DPRINTF(LSQ, "Got error packet back for address: %#X\n",
359                pkt->getAddr());
360    thread[pkt->req->threadId()].completeDataAccess(pkt);
361    return true;
362}
363
364template <class Impl>
365void
366LSQ<Impl>::recvTimingSnoopReq(PacketPtr pkt)
367{
368    DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
369            pkt->cmdString());
370
371    // must be a snoop
372    if (pkt->isInvalidate()) {
373        DPRINTF(LSQ, "received invalidation for addr:%#x\n",
374                pkt->getAddr());
375        for (ThreadID tid = 0; tid < numThreads; tid++) {
376            thread[tid].checkSnoop(pkt);
377        }
378    }
379}
380
381template<class Impl>
382int
383LSQ<Impl>::getCount()
384{
385    unsigned total = 0;
386
387    list<ThreadID>::iterator threads = activeThreads->begin();
388    list<ThreadID>::iterator end = activeThreads->end();
389
390    while (threads != end) {
391        ThreadID tid = *threads++;
392
393        total += getCount(tid);
394    }
395
396    return total;
397}
398
399template<class Impl>
400int
401LSQ<Impl>::numLoads()
402{
403    unsigned total = 0;
404
405    list<ThreadID>::iterator threads = activeThreads->begin();
406    list<ThreadID>::iterator end = activeThreads->end();
407
408    while (threads != end) {
409        ThreadID tid = *threads++;
410
411        total += numLoads(tid);
412    }
413
414    return total;
415}
416
417template<class Impl>
418int
419LSQ<Impl>::numStores()
420{
421    unsigned total = 0;
422
423    list<ThreadID>::iterator threads = activeThreads->begin();
424    list<ThreadID>::iterator end = activeThreads->end();
425
426    while (threads != end) {
427        ThreadID tid = *threads++;
428
429        total += thread[tid].numStores();
430    }
431
432    return total;
433}
434
435template<class Impl>
436unsigned
437LSQ<Impl>::numFreeLoadEntries()
438{
439    unsigned total = 0;
440
441    list<ThreadID>::iterator threads = activeThreads->begin();
442    list<ThreadID>::iterator end = activeThreads->end();
443
444    while (threads != end) {
445        ThreadID tid = *threads++;
446
447        total += thread[tid].numFreeLoadEntries();
448    }
449
450    return total;
451}
452
453template<class Impl>
454unsigned
455LSQ<Impl>::numFreeStoreEntries()
456{
457    unsigned total = 0;
458
459    list<ThreadID>::iterator threads = activeThreads->begin();
460    list<ThreadID>::iterator end = activeThreads->end();
461
462    while (threads != end) {
463        ThreadID tid = *threads++;
464
465        total += thread[tid].numFreeStoreEntries();
466    }
467
468    return total;
469}
470
471template<class Impl>
472unsigned
473LSQ<Impl>::numFreeLoadEntries(ThreadID tid)
474{
475        return thread[tid].numFreeLoadEntries();
476}
477
478template<class Impl>
479unsigned
480LSQ<Impl>::numFreeStoreEntries(ThreadID tid)
481{
482        return thread[tid].numFreeStoreEntries();
483}
484
485template<class Impl>
486bool
487LSQ<Impl>::isFull()
488{
489    list<ThreadID>::iterator threads = activeThreads->begin();
490    list<ThreadID>::iterator end = activeThreads->end();
491
492    while (threads != end) {
493        ThreadID tid = *threads++;
494
495        if (!(thread[tid].lqFull() || thread[tid].sqFull()))
496            return false;
497    }
498
499    return true;
500}
501
502template<class Impl>
503bool
504LSQ<Impl>::isFull(ThreadID tid)
505{
506    //@todo: Change to Calculate All Entries for
507    //Dynamic Policy
508    if (lsqPolicy == Dynamic)
509        return isFull();
510    else
511        return thread[tid].lqFull() || thread[tid].sqFull();
512}
513
514template<class Impl>
515bool
516LSQ<Impl>::isEmpty() const
517{
518    return lqEmpty() && sqEmpty();
519}
520
521template<class Impl>
522bool
523LSQ<Impl>::lqEmpty() const
524{
525    list<ThreadID>::const_iterator threads = activeThreads->begin();
526    list<ThreadID>::const_iterator end = activeThreads->end();
527
528    while (threads != end) {
529        ThreadID tid = *threads++;
530
531        if (!thread[tid].lqEmpty())
532            return false;
533    }
534
535    return true;
536}
537
538template<class Impl>
539bool
540LSQ<Impl>::sqEmpty() const
541{
542    list<ThreadID>::const_iterator threads = activeThreads->begin();
543    list<ThreadID>::const_iterator end = activeThreads->end();
544
545    while (threads != end) {
546        ThreadID tid = *threads++;
547
548        if (!thread[tid].sqEmpty())
549            return false;
550    }
551
552    return true;
553}
554
555template<class Impl>
556bool
557LSQ<Impl>::lqFull()
558{
559    list<ThreadID>::iterator threads = activeThreads->begin();
560    list<ThreadID>::iterator end = activeThreads->end();
561
562    while (threads != end) {
563        ThreadID tid = *threads++;
564
565        if (!thread[tid].lqFull())
566            return false;
567    }
568
569    return true;
570}
571
572template<class Impl>
573bool
574LSQ<Impl>::lqFull(ThreadID tid)
575{
576    //@todo: Change to Calculate All Entries for
577    //Dynamic Policy
578    if (lsqPolicy == Dynamic)
579        return lqFull();
580    else
581        return thread[tid].lqFull();
582}
583
584template<class Impl>
585bool
586LSQ<Impl>::sqFull()
587{
588    list<ThreadID>::iterator threads = activeThreads->begin();
589    list<ThreadID>::iterator end = activeThreads->end();
590
591    while (threads != end) {
592        ThreadID tid = *threads++;
593
594        if (!sqFull(tid))
595            return false;
596    }
597
598    return true;
599}
600
601template<class Impl>
602bool
603LSQ<Impl>::sqFull(ThreadID tid)
604{
605     //@todo: Change to Calculate All Entries for
606    //Dynamic Policy
607    if (lsqPolicy == Dynamic)
608        return sqFull();
609    else
610        return thread[tid].sqFull();
611}
612
613template<class Impl>
614bool
615LSQ<Impl>::isStalled()
616{
617    list<ThreadID>::iterator threads = activeThreads->begin();
618    list<ThreadID>::iterator end = activeThreads->end();
619
620    while (threads != end) {
621        ThreadID tid = *threads++;
622
623        if (!thread[tid].isStalled())
624            return false;
625    }
626
627    return true;
628}
629
630template<class Impl>
631bool
632LSQ<Impl>::isStalled(ThreadID tid)
633{
634    if (lsqPolicy == Dynamic)
635        return isStalled();
636    else
637        return thread[tid].isStalled();
638}
639
640template<class Impl>
641bool
642LSQ<Impl>::hasStoresToWB()
643{
644    list<ThreadID>::iterator threads = activeThreads->begin();
645    list<ThreadID>::iterator end = activeThreads->end();
646
647    while (threads != end) {
648        ThreadID tid = *threads++;
649
650        if (hasStoresToWB(tid))
651            return true;
652    }
653
654    return false;
655}
656
657template<class Impl>
658bool
659LSQ<Impl>::willWB()
660{
661    list<ThreadID>::iterator threads = activeThreads->begin();
662    list<ThreadID>::iterator end = activeThreads->end();
663
664    while (threads != end) {
665        ThreadID tid = *threads++;
666
667        if (willWB(tid))
668            return true;
669    }
670
671    return false;
672}
673
674template<class Impl>
675void
676LSQ<Impl>::dumpInsts() const
677{
678    list<ThreadID>::const_iterator threads = activeThreads->begin();
679    list<ThreadID>::const_iterator end = activeThreads->end();
680
681    while (threads != end) {
682        ThreadID tid = *threads++;
683
684        thread[tid].dumpInsts();
685    }
686}
687
688#endif//__CPU_O3_LSQ_IMPL_HH__
689