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