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