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