s/cpu_id/cpuId in o3 (to be consistent and match style), also fix some typos in
[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 #include "params/DerivO3CPU.hh"
38
39 template<class Impl>
40 void
41 LSQ<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
52 template <class Impl>
53 Tick
54 LSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
55 {
56 panic("O3CPU model does not work with atomic mode!");
57 return curTick;
58 }
59
60 template <class Impl>
61 void
62 LSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
63 {
64 DPRINTF(LSQ, "LSQ doesn't update things on a recvFunctional.");
65 }
66
67 template <class Impl>
68 void
69 LSQ<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
81 template <class Impl>
82 bool
83 LSQ<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->getThreadNum()].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
99 template <class Impl>
100 void
101 LSQ<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
115 template <class Impl>
116 LSQ<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
181 template<class Impl>
182 std::string
183 LSQ<Impl>::name() const
184 {
185 return iewStage->name() + ".lsq";
186 }
187
188 template<class Impl>
189 void
190 LSQ<Impl>::regStats()
191 {
192 //Initialize LSQs
193 for (int tid=0; tid < numThreads; tid++) {
194 thread[tid].regStats();
195 }
196 }
197
198 template<class Impl>
199 void
200 LSQ<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
201 {
202 activeThreads = at_ptr;
203 assert(activeThreads != 0);
204 }
205
206 template <class Impl>
207 void
208 LSQ<Impl>::switchOut()
209 {
210 for (int tid = 0; tid < numThreads; tid++) {
211 thread[tid].switchOut();
212 }
213 }
214
215 template <class Impl>
216 void
217 LSQ<Impl>::takeOverFrom()
218 {
219 for (int tid = 0; tid < numThreads; tid++) {
220 thread[tid].takeOverFrom();
221 }
222 }
223
224 template <class Impl>
225 int
226 LSQ<Impl>::entryAmount(int num_threads)
227 {
228 if (lsqPolicy == Partitioned) {
229 return LQEntries / num_threads;
230 } else {
231 return 0;
232 }
233 }
234
235 template <class Impl>
236 void
237 LSQ<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
263 template<class Impl>
264 void
265 LSQ<Impl>::removeEntries(unsigned tid)
266 {
267 thread[tid].clearLQ();
268 thread[tid].clearSQ();
269 }
270
271 template<class Impl>
272 void
273 LSQ<Impl>::resizeEntries(unsigned size,unsigned tid)
274 {
275 thread[tid].resizeLQ(size);
276 thread[tid].resizeSQ(size);
277 }
278
279 template<class Impl>
280 void
281 LSQ<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
293 template<class Impl>
294 void
295 LSQ<Impl>::insertLoad(DynInstPtr &load_inst)
296 {
297 unsigned tid = load_inst->threadNumber;
298
299 thread[tid].insertLoad(load_inst);
300 }
301
302 template<class Impl>
303 void
304 LSQ<Impl>::insertStore(DynInstPtr &store_inst)
305 {
306 unsigned tid = store_inst->threadNumber;
307
308 thread[tid].insertStore(store_inst);
309 }
310
311 template<class Impl>
312 Fault
313 LSQ<Impl>::executeLoad(DynInstPtr &inst)
314 {
315 unsigned tid = inst->threadNumber;
316
317 return thread[tid].executeLoad(inst);
318 }
319
320 template<class Impl>
321 Fault
322 LSQ<Impl>::executeStore(DynInstPtr &inst)
323 {
324 unsigned tid = inst->threadNumber;
325
326 return thread[tid].executeStore(inst);
327 }
328
329 template<class Impl>
330 void
331 LSQ<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
348 template<class Impl>
349 bool
350 LSQ<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
366 template<class Impl>
367 int
368 LSQ<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
384 template<class Impl>
385 int
386 LSQ<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
402 template<class Impl>
403 int
404 LSQ<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
420 template<class Impl>
421 int
422 LSQ<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
438 template<class Impl>
439 unsigned
440 LSQ<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
456 template<class Impl>
457 unsigned
458 LSQ<Impl>::numFreeEntries(unsigned tid)
459 {
460 //if (lsqPolicy == Dynamic)
461 //return numFreeEntries();
462 //else
463 return thread[tid].numFreeEntries();
464 }
465
466 template<class Impl>
467 bool
468 LSQ<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
483 template<class Impl>
484 bool
485 LSQ<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
495 template<class Impl>
496 bool
497 LSQ<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
512 template<class Impl>
513 bool
514 LSQ<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
524 template<class Impl>
525 bool
526 LSQ<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
541 template<class Impl>
542 bool
543 LSQ<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
553 template<class Impl>
554 bool
555 LSQ<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
570 template<class Impl>
571 bool
572 LSQ<Impl>::isStalled(unsigned tid)
573 {
574 if (lsqPolicy == Dynamic)
575 return isStalled();
576 else
577 return thread[tid].isStalled();
578 }
579
580 template<class Impl>
581 bool
582 LSQ<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
597 template<class Impl>
598 bool
599 LSQ<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
614 template<class Impl>
615 void
616 LSQ<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 }