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