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