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