lsq_impl.hh revision 8346
1/*
2 * Copyright (c) 2005-2006 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 * Authors: Korey Sewell
29 */
30
31#include <algorithm>
32#include <list>
33#include <string>
34
35#include "cpu/o3/lsq.hh"
36#include "debug/Fetch.hh"
37#include "debug/LSQ.hh"
38#include "debug/Writeback.hh"
39#include "params/DerivO3CPU.hh"
40
41using namespace std;
42
43template<class Impl>
44void
45LSQ<Impl>::DcachePort::setPeer(Port *port)
46{
47    Port::setPeer(port);
48
49#if FULL_SYSTEM
50    // Update the ThreadContext's memory ports (Functional/Virtual
51    // Ports)
52    lsq->updateMemPorts();
53#endif
54}
55
56template <class Impl>
57Tick
58LSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
59{
60    panic("O3CPU model does not work with atomic mode!");
61    return curTick();
62}
63
64template <class Impl>
65void
66LSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
67{
68    DPRINTF(LSQ, "LSQ doesn't update things on a recvFunctional.\n");
69}
70
71template <class Impl>
72void
73LSQ<Impl>::DcachePort::recvStatusChange(Status status)
74{
75    if (status == RangeChange) {
76        if (!snoopRangeSent) {
77            snoopRangeSent = true;
78            sendStatusChange(Port::RangeChange);
79        }
80        return;
81    }
82    panic("O3CPU doesn't expect recvStatusChange callback!");
83}
84
85template <class Impl>
86bool
87LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
88{
89    if (pkt->isError())
90        DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr());
91    if (pkt->isResponse()) {
92        lsq->thread[pkt->req->threadId()].completeDataAccess(pkt);
93    }
94    else {
95        // must be a snoop
96
97        // @TODO someday may need to process invalidations in LSQ here
98        // to provide stronger consistency model
99    }
100    return true;
101}
102
103template <class Impl>
104void
105LSQ<Impl>::DcachePort::recvRetry()
106{
107    if (lsq->retryTid == -1)
108    {
109        //Squashed, so drop it
110        return;
111    }
112    int curr_retry_tid = lsq->retryTid;
113    // Speculatively clear the retry Tid.  This will get set again if
114    // the LSQUnit was unable to complete its access.
115    lsq->retryTid = -1;
116    lsq->thread[curr_retry_tid].recvRetry();
117}
118
119template <class Impl>
120LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
121    : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this),
122      LQEntries(params->LQEntries),
123      SQEntries(params->SQEntries),
124      numThreads(params->numThreads),
125      retryTid(-1)
126{
127    dcachePort.snoopRangeSent = false;
128
129    //**********************************************/
130    //************ Handle SMT Parameters ***********/
131    //**********************************************/
132    std::string policy = params->smtLSQPolicy;
133
134    //Convert string to lowercase
135    std::transform(policy.begin(), policy.end(), policy.begin(),
136                   (int(*)(int)) tolower);
137
138    //Figure out fetch policy
139    if (policy == "dynamic") {
140        lsqPolicy = Dynamic;
141
142        maxLQEntries = LQEntries;
143        maxSQEntries = SQEntries;
144
145        DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n");
146    } else if (policy == "partitioned") {
147        lsqPolicy = Partitioned;
148
149        //@todo:make work if part_amt doesnt divide evenly.
150        maxLQEntries = LQEntries / numThreads;
151        maxSQEntries = SQEntries / numThreads;
152
153        DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: "
154                "%i entries per LQ | %i entries per SQ\n",
155                maxLQEntries,maxSQEntries);
156    } else if (policy == "threshold") {
157        lsqPolicy = Threshold;
158
159        assert(params->smtLSQThreshold > LQEntries);
160        assert(params->smtLSQThreshold > SQEntries);
161
162        //Divide up by threshold amount
163        //@todo: Should threads check the max and the total
164        //amount of the LSQ
165        maxLQEntries  = params->smtLSQThreshold;
166        maxSQEntries  = params->smtLSQThreshold;
167
168        DPRINTF(LSQ, "LSQ sharing policy set to Threshold: "
169                "%i entries per LQ | %i entries per SQ\n",
170                maxLQEntries,maxSQEntries);
171    } else {
172        assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic,"
173                    "Partitioned, Threshold}");
174    }
175
176    //Initialize LSQs
177    for (ThreadID tid = 0; tid < numThreads; tid++) {
178        thread[tid].init(cpu, iew_ptr, params, this,
179                         maxLQEntries, maxSQEntries, tid);
180        thread[tid].setDcachePort(&dcachePort);
181    }
182}
183
184
185template<class Impl>
186std::string
187LSQ<Impl>::name() const
188{
189    return iewStage->name() + ".lsq";
190}
191
192template<class Impl>
193void
194LSQ<Impl>::regStats()
195{
196    //Initialize LSQs
197    for (ThreadID tid = 0; tid < numThreads; tid++) {
198        thread[tid].regStats();
199    }
200}
201
202template<class Impl>
203void
204LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
205{
206    activeThreads = at_ptr;
207    assert(activeThreads != 0);
208}
209
210template <class Impl>
211void
212LSQ<Impl>::switchOut()
213{
214    for (ThreadID tid = 0; tid < numThreads; tid++) {
215        thread[tid].switchOut();
216    }
217}
218
219template <class Impl>
220void
221LSQ<Impl>::takeOverFrom()
222{
223    for (ThreadID tid = 0; tid < numThreads; tid++) {
224        thread[tid].takeOverFrom();
225    }
226}
227
228template <class Impl>
229int
230LSQ<Impl>::entryAmount(ThreadID num_threads)
231{
232    if (lsqPolicy == Partitioned) {
233        return LQEntries / num_threads;
234    } else {
235        return 0;
236    }
237}
238
239template <class Impl>
240void
241LSQ<Impl>::resetEntries()
242{
243    if (lsqPolicy != Dynamic || numThreads > 1) {
244        int active_threads = activeThreads->size();
245
246        int maxEntries;
247
248        if (lsqPolicy == Partitioned) {
249            maxEntries = LQEntries / active_threads;
250        } else if (lsqPolicy == Threshold && active_threads == 1) {
251            maxEntries = LQEntries;
252        } else {
253            maxEntries = LQEntries;
254        }
255
256        list<ThreadID>::iterator threads  = activeThreads->begin();
257        list<ThreadID>::iterator end = activeThreads->end();
258
259        while (threads != end) {
260            ThreadID tid = *threads++;
261
262            resizeEntries(maxEntries, tid);
263        }
264    }
265}
266
267template<class Impl>
268void
269LSQ<Impl>::removeEntries(ThreadID tid)
270{
271    thread[tid].clearLQ();
272    thread[tid].clearSQ();
273}
274
275template<class Impl>
276void
277LSQ<Impl>::resizeEntries(unsigned size, ThreadID tid)
278{
279    thread[tid].resizeLQ(size);
280    thread[tid].resizeSQ(size);
281}
282
283template<class Impl>
284void
285LSQ<Impl>::tick()
286{
287    list<ThreadID>::iterator threads = activeThreads->begin();
288    list<ThreadID>::iterator end = activeThreads->end();
289
290    while (threads != end) {
291        ThreadID tid = *threads++;
292
293        thread[tid].tick();
294    }
295}
296
297template<class Impl>
298void
299LSQ<Impl>::insertLoad(DynInstPtr &load_inst)
300{
301    ThreadID tid = load_inst->threadNumber;
302
303    thread[tid].insertLoad(load_inst);
304}
305
306template<class Impl>
307void
308LSQ<Impl>::insertStore(DynInstPtr &store_inst)
309{
310    ThreadID tid = store_inst->threadNumber;
311
312    thread[tid].insertStore(store_inst);
313}
314
315template<class Impl>
316Fault
317LSQ<Impl>::executeLoad(DynInstPtr &inst)
318{
319    ThreadID tid = inst->threadNumber;
320
321    return thread[tid].executeLoad(inst);
322}
323
324template<class Impl>
325Fault
326LSQ<Impl>::executeStore(DynInstPtr &inst)
327{
328    ThreadID tid = inst->threadNumber;
329
330    return thread[tid].executeStore(inst);
331}
332
333template<class Impl>
334void
335LSQ<Impl>::writebackStores()
336{
337    list<ThreadID>::iterator threads = activeThreads->begin();
338    list<ThreadID>::iterator end = activeThreads->end();
339
340    while (threads != end) {
341        ThreadID tid = *threads++;
342
343        if (numStoresToWB(tid) > 0) {
344            DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores "
345                "available for Writeback.\n", tid, numStoresToWB(tid));
346        }
347
348        thread[tid].writebackStores();
349    }
350}
351
352template<class Impl>
353bool
354LSQ<Impl>::violation()
355{
356    /* Answers: Does Anybody Have a Violation?*/
357    list<ThreadID>::iterator threads = activeThreads->begin();
358    list<ThreadID>::iterator end = activeThreads->end();
359
360    while (threads != end) {
361        ThreadID tid = *threads++;
362
363        if (thread[tid].violation())
364            return true;
365    }
366
367    return false;
368}
369
370template<class Impl>
371int
372LSQ<Impl>::getCount()
373{
374    unsigned total = 0;
375
376    list<ThreadID>::iterator threads = activeThreads->begin();
377    list<ThreadID>::iterator end = activeThreads->end();
378
379    while (threads != end) {
380        ThreadID tid = *threads++;
381
382        total += getCount(tid);
383    }
384
385    return total;
386}
387
388template<class Impl>
389int
390LSQ<Impl>::numLoads()
391{
392    unsigned total = 0;
393
394    list<ThreadID>::iterator threads = activeThreads->begin();
395    list<ThreadID>::iterator end = activeThreads->end();
396
397    while (threads != end) {
398        ThreadID tid = *threads++;
399
400        total += numLoads(tid);
401    }
402
403    return total;
404}
405
406template<class Impl>
407int
408LSQ<Impl>::numStores()
409{
410    unsigned total = 0;
411
412    list<ThreadID>::iterator threads = activeThreads->begin();
413    list<ThreadID>::iterator end = activeThreads->end();
414
415    while (threads != end) {
416        ThreadID tid = *threads++;
417
418        total += thread[tid].numStores();
419    }
420
421    return total;
422}
423
424template<class Impl>
425int
426LSQ<Impl>::numLoadsReady()
427{
428    unsigned total = 0;
429
430    list<ThreadID>::iterator threads = activeThreads->begin();
431    list<ThreadID>::iterator end = activeThreads->end();
432
433    while (threads != end) {
434        ThreadID tid = *threads++;
435
436        total += thread[tid].numLoadsReady();
437    }
438
439    return total;
440}
441
442template<class Impl>
443unsigned
444LSQ<Impl>::numFreeEntries()
445{
446    unsigned total = 0;
447
448    list<ThreadID>::iterator threads = activeThreads->begin();
449    list<ThreadID>::iterator end = activeThreads->end();
450
451    while (threads != end) {
452        ThreadID tid = *threads++;
453
454        total += thread[tid].numFreeEntries();
455    }
456
457    return total;
458}
459
460template<class Impl>
461unsigned
462LSQ<Impl>::numFreeEntries(ThreadID tid)
463{
464    //if (lsqPolicy == Dynamic)
465    //return numFreeEntries();
466    //else
467        return thread[tid].numFreeEntries();
468}
469
470template<class Impl>
471bool
472LSQ<Impl>::isFull()
473{
474    list<ThreadID>::iterator threads = activeThreads->begin();
475    list<ThreadID>::iterator end = activeThreads->end();
476
477    while (threads != end) {
478        ThreadID tid = *threads++;
479
480        if (!(thread[tid].lqFull() || thread[tid].sqFull()))
481            return false;
482    }
483
484    return true;
485}
486
487template<class Impl>
488bool
489LSQ<Impl>::isFull(ThreadID tid)
490{
491    //@todo: Change to Calculate All Entries for
492    //Dynamic Policy
493    if (lsqPolicy == Dynamic)
494        return isFull();
495    else
496        return thread[tid].lqFull() || thread[tid].sqFull();
497}
498
499template<class Impl>
500bool
501LSQ<Impl>::lqFull()
502{
503    list<ThreadID>::iterator threads = activeThreads->begin();
504    list<ThreadID>::iterator end = activeThreads->end();
505
506    while (threads != end) {
507        ThreadID tid = *threads++;
508
509        if (!thread[tid].lqFull())
510            return false;
511    }
512
513    return true;
514}
515
516template<class Impl>
517bool
518LSQ<Impl>::lqFull(ThreadID tid)
519{
520    //@todo: Change to Calculate All Entries for
521    //Dynamic Policy
522    if (lsqPolicy == Dynamic)
523        return lqFull();
524    else
525        return thread[tid].lqFull();
526}
527
528template<class Impl>
529bool
530LSQ<Impl>::sqFull()
531{
532    list<ThreadID>::iterator threads = activeThreads->begin();
533    list<ThreadID>::iterator end = activeThreads->end();
534
535    while (threads != end) {
536        ThreadID tid = *threads++;
537
538        if (!sqFull(tid))
539            return false;
540    }
541
542    return true;
543}
544
545template<class Impl>
546bool
547LSQ<Impl>::sqFull(ThreadID tid)
548{
549     //@todo: Change to Calculate All Entries for
550    //Dynamic Policy
551    if (lsqPolicy == Dynamic)
552        return sqFull();
553    else
554        return thread[tid].sqFull();
555}
556
557template<class Impl>
558bool
559LSQ<Impl>::isStalled()
560{
561    list<ThreadID>::iterator threads = activeThreads->begin();
562    list<ThreadID>::iterator end = activeThreads->end();
563
564    while (threads != end) {
565        ThreadID tid = *threads++;
566
567        if (!thread[tid].isStalled())
568            return false;
569    }
570
571    return true;
572}
573
574template<class Impl>
575bool
576LSQ<Impl>::isStalled(ThreadID tid)
577{
578    if (lsqPolicy == Dynamic)
579        return isStalled();
580    else
581        return thread[tid].isStalled();
582}
583
584template<class Impl>
585bool
586LSQ<Impl>::hasStoresToWB()
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 (hasStoresToWB(tid))
595            return true;
596    }
597
598    return false;
599}
600
601template<class Impl>
602bool
603LSQ<Impl>::willWB()
604{
605    list<ThreadID>::iterator threads = activeThreads->begin();
606    list<ThreadID>::iterator end = activeThreads->end();
607
608    while (threads != end) {
609        ThreadID tid = *threads++;
610
611        if (willWB(tid))
612            return true;
613    }
614
615    return false;
616}
617
618template<class Impl>
619void
620LSQ<Impl>::dumpInsts()
621{
622    list<ThreadID>::iterator threads = activeThreads->begin();
623    list<ThreadID>::iterator end = activeThreads->end();
624
625    while (threads != end) {
626        ThreadID tid = *threads++;
627
628        thread[tid].dumpInsts();
629    }
630}
631