Revert power patch sets with unexpected interactions
[gem5.git] / src / cpu / o3 / lsq_impl.hh
1 /*
2 * Copyright (c) 2011-2012, 2014 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2005-2006 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Korey Sewell
42 */
43
44 #ifndef __CPU_O3_LSQ_IMPL_HH__
45 #define __CPU_O3_LSQ_IMPL_HH__
46
47 #include <algorithm>
48 #include <list>
49 #include <string>
50
51 #include "cpu/o3/lsq.hh"
52 #include "debug/Drain.hh"
53 #include "debug/Fetch.hh"
54 #include "debug/LSQ.hh"
55 #include "debug/Writeback.hh"
56 #include "params/DerivO3CPU.hh"
57
58 using namespace std;
59
60 template <class Impl>
61 LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
62 : cpu(cpu_ptr), iewStage(iew_ptr),
63 LQEntries(params->LQEntries),
64 SQEntries(params->SQEntries),
65 numThreads(params->numThreads)
66 {
67 assert(numThreads > 0 && numThreads <= Impl::MaxThreads);
68
69 //**********************************************/
70 //************ Handle SMT Parameters ***********/
71 //**********************************************/
72 std::string policy = params->smtLSQPolicy;
73
74 //Convert string to lowercase
75 std::transform(policy.begin(), policy.end(), policy.begin(),
76 (int(*)(int)) tolower);
77
78 //Figure out fetch policy
79 if (policy == "dynamic") {
80 lsqPolicy = Dynamic;
81
82 maxLQEntries = LQEntries;
83 maxSQEntries = SQEntries;
84
85 DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n");
86 } else if (policy == "partitioned") {
87 lsqPolicy = Partitioned;
88
89 //@todo:make work if part_amt doesnt divide evenly.
90 maxLQEntries = LQEntries / numThreads;
91 maxSQEntries = SQEntries / numThreads;
92
93 DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: "
94 "%i entries per LQ | %i entries per SQ\n",
95 maxLQEntries,maxSQEntries);
96 } else if (policy == "threshold") {
97 lsqPolicy = Threshold;
98
99 assert(params->smtLSQThreshold > LQEntries);
100 assert(params->smtLSQThreshold > SQEntries);
101
102 //Divide up by threshold amount
103 //@todo: Should threads check the max and the total
104 //amount of the LSQ
105 maxLQEntries = params->smtLSQThreshold;
106 maxSQEntries = params->smtLSQThreshold;
107
108 DPRINTF(LSQ, "LSQ sharing policy set to Threshold: "
109 "%i entries per LQ | %i entries per SQ\n",
110 maxLQEntries,maxSQEntries);
111 } else {
112 assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic,"
113 "Partitioned, Threshold}");
114 }
115
116 //Initialize LSQs
117 thread = new LSQUnit[numThreads];
118 for (ThreadID tid = 0; tid < numThreads; tid++) {
119 thread[tid].init(cpu, iew_ptr, params, this,
120 maxLQEntries, maxSQEntries, tid);
121 thread[tid].setDcachePort(&cpu_ptr->getDataPort());
122 }
123 }
124
125
126 template<class Impl>
127 std::string
128 LSQ<Impl>::name() const
129 {
130 return iewStage->name() + ".lsq";
131 }
132
133 template<class Impl>
134 void
135 LSQ<Impl>::regStats()
136 {
137 //Initialize LSQs
138 for (ThreadID tid = 0; tid < numThreads; tid++) {
139 thread[tid].regStats();
140 }
141 }
142
143 template<class Impl>
144 void
145 LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
146 {
147 activeThreads = at_ptr;
148 assert(activeThreads != 0);
149 }
150
151 template <class Impl>
152 void
153 LSQ<Impl>::drainSanityCheck() const
154 {
155 assert(isDrained());
156
157 for (ThreadID tid = 0; tid < numThreads; tid++)
158 thread[tid].drainSanityCheck();
159 }
160
161 template <class Impl>
162 bool
163 LSQ<Impl>::isDrained() const
164 {
165 bool drained(true);
166
167 if (!lqEmpty()) {
168 DPRINTF(Drain, "Not drained, LQ not empty.\n");
169 drained = false;
170 }
171
172 if (!sqEmpty()) {
173 DPRINTF(Drain, "Not drained, SQ not empty.\n");
174 drained = false;
175 }
176
177 return drained;
178 }
179
180 template <class Impl>
181 void
182 LSQ<Impl>::takeOverFrom()
183 {
184 for (ThreadID tid = 0; tid < numThreads; tid++) {
185 thread[tid].takeOverFrom();
186 }
187 }
188
189 template <class Impl>
190 int
191 LSQ<Impl>::entryAmount(ThreadID num_threads)
192 {
193 if (lsqPolicy == Partitioned) {
194 return LQEntries / num_threads;
195 } else {
196 return 0;
197 }
198 }
199
200 template <class Impl>
201 void
202 LSQ<Impl>::resetEntries()
203 {
204 if (lsqPolicy != Dynamic || numThreads > 1) {
205 int active_threads = activeThreads->size();
206
207 int maxEntries;
208
209 if (lsqPolicy == Partitioned) {
210 maxEntries = LQEntries / active_threads;
211 } else if (lsqPolicy == Threshold && active_threads == 1) {
212 maxEntries = LQEntries;
213 } else {
214 maxEntries = LQEntries;
215 }
216
217 list<ThreadID>::iterator threads = activeThreads->begin();
218 list<ThreadID>::iterator end = activeThreads->end();
219
220 while (threads != end) {
221 ThreadID tid = *threads++;
222
223 resizeEntries(maxEntries, tid);
224 }
225 }
226 }
227
228 template<class Impl>
229 void
230 LSQ<Impl>::removeEntries(ThreadID tid)
231 {
232 thread[tid].clearLQ();
233 thread[tid].clearSQ();
234 }
235
236 template<class Impl>
237 void
238 LSQ<Impl>::resizeEntries(unsigned size, ThreadID tid)
239 {
240 thread[tid].resizeLQ(size);
241 thread[tid].resizeSQ(size);
242 }
243
244 template<class Impl>
245 void
246 LSQ<Impl>::tick()
247 {
248 list<ThreadID>::iterator threads = activeThreads->begin();
249 list<ThreadID>::iterator end = activeThreads->end();
250
251 while (threads != end) {
252 ThreadID tid = *threads++;
253
254 thread[tid].tick();
255 }
256 }
257
258 template<class Impl>
259 void
260 LSQ<Impl>::insertLoad(DynInstPtr &load_inst)
261 {
262 ThreadID tid = load_inst->threadNumber;
263
264 thread[tid].insertLoad(load_inst);
265 }
266
267 template<class Impl>
268 void
269 LSQ<Impl>::insertStore(DynInstPtr &store_inst)
270 {
271 ThreadID tid = store_inst->threadNumber;
272
273 thread[tid].insertStore(store_inst);
274 }
275
276 template<class Impl>
277 Fault
278 LSQ<Impl>::executeLoad(DynInstPtr &inst)
279 {
280 ThreadID tid = inst->threadNumber;
281
282 return thread[tid].executeLoad(inst);
283 }
284
285 template<class Impl>
286 Fault
287 LSQ<Impl>::executeStore(DynInstPtr &inst)
288 {
289 ThreadID tid = inst->threadNumber;
290
291 return thread[tid].executeStore(inst);
292 }
293
294 template<class Impl>
295 void
296 LSQ<Impl>::writebackStores()
297 {
298 list<ThreadID>::iterator threads = activeThreads->begin();
299 list<ThreadID>::iterator end = activeThreads->end();
300
301 while (threads != end) {
302 ThreadID tid = *threads++;
303
304 if (numStoresToWB(tid) > 0) {
305 DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores "
306 "available for Writeback.\n", tid, numStoresToWB(tid));
307 }
308
309 thread[tid].writebackStores();
310 }
311 }
312
313 template<class Impl>
314 bool
315 LSQ<Impl>::violation()
316 {
317 /* Answers: Does Anybody Have a Violation?*/
318 list<ThreadID>::iterator threads = activeThreads->begin();
319 list<ThreadID>::iterator end = activeThreads->end();
320
321 while (threads != end) {
322 ThreadID tid = *threads++;
323
324 if (thread[tid].violation())
325 return true;
326 }
327
328 return false;
329 }
330
331 template <class Impl>
332 void
333 LSQ<Impl>::recvReqRetry()
334 {
335 iewStage->cacheUnblocked();
336
337 for (ThreadID tid : *activeThreads) {
338 thread[tid].recvRetry();
339 }
340 }
341
342 template <class Impl>
343 bool
344 LSQ<Impl>::recvTimingResp(PacketPtr pkt)
345 {
346 if (pkt->isError())
347 DPRINTF(LSQ, "Got error packet back for address: %#X\n",
348 pkt->getAddr());
349
350 thread[pkt->req->threadId()].completeDataAccess(pkt);
351
352 if (pkt->isInvalidate()) {
353 // This response also contains an invalidate; e.g. this can be the case
354 // if cmd is ReadRespWithInvalidate.
355 //
356 // The calling order between completeDataAccess and checkSnoop matters.
357 // By calling checkSnoop after completeDataAccess, we ensure that the
358 // fault set by checkSnoop is not lost. Calling writeback (more
359 // specifically inst->completeAcc) in completeDataAccess overwrites
360 // fault, and in case this instruction requires squashing (as
361 // determined by checkSnoop), the ReExec fault set by checkSnoop would
362 // be lost otherwise.
363
364 DPRINTF(LSQ, "received invalidation with response for addr:%#x\n",
365 pkt->getAddr());
366
367 for (ThreadID tid = 0; tid < numThreads; tid++) {
368 thread[tid].checkSnoop(pkt);
369 }
370 }
371
372 delete pkt->req;
373 delete pkt;
374 return true;
375 }
376
377 template <class Impl>
378 void
379 LSQ<Impl>::recvTimingSnoopReq(PacketPtr pkt)
380 {
381 DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
382 pkt->cmdString());
383
384 // must be a snoop
385 if (pkt->isInvalidate()) {
386 DPRINTF(LSQ, "received invalidation for addr:%#x\n",
387 pkt->getAddr());
388 for (ThreadID tid = 0; tid < numThreads; tid++) {
389 thread[tid].checkSnoop(pkt);
390 }
391 }
392 }
393
394 template<class Impl>
395 int
396 LSQ<Impl>::getCount()
397 {
398 unsigned total = 0;
399
400 list<ThreadID>::iterator threads = activeThreads->begin();
401 list<ThreadID>::iterator end = activeThreads->end();
402
403 while (threads != end) {
404 ThreadID tid = *threads++;
405
406 total += getCount(tid);
407 }
408
409 return total;
410 }
411
412 template<class Impl>
413 int
414 LSQ<Impl>::numLoads()
415 {
416 unsigned total = 0;
417
418 list<ThreadID>::iterator threads = activeThreads->begin();
419 list<ThreadID>::iterator end = activeThreads->end();
420
421 while (threads != end) {
422 ThreadID tid = *threads++;
423
424 total += numLoads(tid);
425 }
426
427 return total;
428 }
429
430 template<class Impl>
431 int
432 LSQ<Impl>::numStores()
433 {
434 unsigned total = 0;
435
436 list<ThreadID>::iterator threads = activeThreads->begin();
437 list<ThreadID>::iterator end = activeThreads->end();
438
439 while (threads != end) {
440 ThreadID tid = *threads++;
441
442 total += thread[tid].numStores();
443 }
444
445 return total;
446 }
447
448 template<class Impl>
449 unsigned
450 LSQ<Impl>::numFreeLoadEntries()
451 {
452 unsigned total = 0;
453
454 list<ThreadID>::iterator threads = activeThreads->begin();
455 list<ThreadID>::iterator end = activeThreads->end();
456
457 while (threads != end) {
458 ThreadID tid = *threads++;
459
460 total += thread[tid].numFreeLoadEntries();
461 }
462
463 return total;
464 }
465
466 template<class Impl>
467 unsigned
468 LSQ<Impl>::numFreeStoreEntries()
469 {
470 unsigned total = 0;
471
472 list<ThreadID>::iterator threads = activeThreads->begin();
473 list<ThreadID>::iterator end = activeThreads->end();
474
475 while (threads != end) {
476 ThreadID tid = *threads++;
477
478 total += thread[tid].numFreeStoreEntries();
479 }
480
481 return total;
482 }
483
484 template<class Impl>
485 unsigned
486 LSQ<Impl>::numFreeLoadEntries(ThreadID tid)
487 {
488 return thread[tid].numFreeLoadEntries();
489 }
490
491 template<class Impl>
492 unsigned
493 LSQ<Impl>::numFreeStoreEntries(ThreadID tid)
494 {
495 return thread[tid].numFreeStoreEntries();
496 }
497
498 template<class Impl>
499 bool
500 LSQ<Impl>::isFull()
501 {
502 list<ThreadID>::iterator threads = activeThreads->begin();
503 list<ThreadID>::iterator end = activeThreads->end();
504
505 while (threads != end) {
506 ThreadID tid = *threads++;
507
508 if (!(thread[tid].lqFull() || thread[tid].sqFull()))
509 return false;
510 }
511
512 return true;
513 }
514
515 template<class Impl>
516 bool
517 LSQ<Impl>::isFull(ThreadID tid)
518 {
519 //@todo: Change to Calculate All Entries for
520 //Dynamic Policy
521 if (lsqPolicy == Dynamic)
522 return isFull();
523 else
524 return thread[tid].lqFull() || thread[tid].sqFull();
525 }
526
527 template<class Impl>
528 bool
529 LSQ<Impl>::isEmpty() const
530 {
531 return lqEmpty() && sqEmpty();
532 }
533
534 template<class Impl>
535 bool
536 LSQ<Impl>::lqEmpty() const
537 {
538 list<ThreadID>::const_iterator threads = activeThreads->begin();
539 list<ThreadID>::const_iterator end = activeThreads->end();
540
541 while (threads != end) {
542 ThreadID tid = *threads++;
543
544 if (!thread[tid].lqEmpty())
545 return false;
546 }
547
548 return true;
549 }
550
551 template<class Impl>
552 bool
553 LSQ<Impl>::sqEmpty() const
554 {
555 list<ThreadID>::const_iterator threads = activeThreads->begin();
556 list<ThreadID>::const_iterator end = activeThreads->end();
557
558 while (threads != end) {
559 ThreadID tid = *threads++;
560
561 if (!thread[tid].sqEmpty())
562 return false;
563 }
564
565 return true;
566 }
567
568 template<class Impl>
569 bool
570 LSQ<Impl>::lqFull()
571 {
572 list<ThreadID>::iterator threads = activeThreads->begin();
573 list<ThreadID>::iterator end = activeThreads->end();
574
575 while (threads != end) {
576 ThreadID tid = *threads++;
577
578 if (!thread[tid].lqFull())
579 return false;
580 }
581
582 return true;
583 }
584
585 template<class Impl>
586 bool
587 LSQ<Impl>::lqFull(ThreadID tid)
588 {
589 //@todo: Change to Calculate All Entries for
590 //Dynamic Policy
591 if (lsqPolicy == Dynamic)
592 return lqFull();
593 else
594 return thread[tid].lqFull();
595 }
596
597 template<class Impl>
598 bool
599 LSQ<Impl>::sqFull()
600 {
601 list<ThreadID>::iterator threads = activeThreads->begin();
602 list<ThreadID>::iterator end = activeThreads->end();
603
604 while (threads != end) {
605 ThreadID tid = *threads++;
606
607 if (!sqFull(tid))
608 return false;
609 }
610
611 return true;
612 }
613
614 template<class Impl>
615 bool
616 LSQ<Impl>::sqFull(ThreadID tid)
617 {
618 //@todo: Change to Calculate All Entries for
619 //Dynamic Policy
620 if (lsqPolicy == Dynamic)
621 return sqFull();
622 else
623 return thread[tid].sqFull();
624 }
625
626 template<class Impl>
627 bool
628 LSQ<Impl>::isStalled()
629 {
630 list<ThreadID>::iterator threads = activeThreads->begin();
631 list<ThreadID>::iterator end = activeThreads->end();
632
633 while (threads != end) {
634 ThreadID tid = *threads++;
635
636 if (!thread[tid].isStalled())
637 return false;
638 }
639
640 return true;
641 }
642
643 template<class Impl>
644 bool
645 LSQ<Impl>::isStalled(ThreadID tid)
646 {
647 if (lsqPolicy == Dynamic)
648 return isStalled();
649 else
650 return thread[tid].isStalled();
651 }
652
653 template<class Impl>
654 bool
655 LSQ<Impl>::hasStoresToWB()
656 {
657 list<ThreadID>::iterator threads = activeThreads->begin();
658 list<ThreadID>::iterator end = activeThreads->end();
659
660 while (threads != end) {
661 ThreadID tid = *threads++;
662
663 if (hasStoresToWB(tid))
664 return true;
665 }
666
667 return false;
668 }
669
670 template<class Impl>
671 bool
672 LSQ<Impl>::willWB()
673 {
674 list<ThreadID>::iterator threads = activeThreads->begin();
675 list<ThreadID>::iterator end = activeThreads->end();
676
677 while (threads != end) {
678 ThreadID tid = *threads++;
679
680 if (willWB(tid))
681 return true;
682 }
683
684 return false;
685 }
686
687 template<class Impl>
688 void
689 LSQ<Impl>::dumpInsts() const
690 {
691 list<ThreadID>::const_iterator threads = activeThreads->begin();
692 list<ThreadID>::const_iterator end = activeThreads->end();
693
694 while (threads != end) {
695 ThreadID tid = *threads++;
696
697 thread[tid].dumpInsts();
698 }
699 }
700
701 #endif//__CPU_O3_LSQ_IMPL_HH__