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