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