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