Merge zizzer:/bk/newmem
[gem5.git] / src / cpu / ozone / lsq_unit_impl.hh
1 /*
2 * Copyright (c) 2004-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: Kevin Lim
29 */
30
31 #include "arch/isa_traits.hh"
32 #include "base/str.hh"
33 #include "cpu/ozone/lsq_unit.hh"
34
35 template <class Impl>
36 OzoneLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx,
37 Event *wb_event,
38 OzoneLSQ<Impl> *lsq_ptr)
39 : Event(&mainEventQueue),
40 storeIdx(store_idx),
41 wbEvent(wb_event),
42 lsqPtr(lsq_ptr)
43 {
44 this->setFlags(Event::AutoDelete);
45 }
46
47 template <class Impl>
48 void
49 OzoneLSQ<Impl>::StoreCompletionEvent::process()
50 {
51 DPRINTF(OzoneLSQ, "Cache miss complete for store idx:%i\n", storeIdx);
52
53 //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
54
55 // lsqPtr->cpu->wakeCPU();
56 if (wbEvent)
57 wbEvent->process();
58 lsqPtr->completeStore(storeIdx);
59 }
60
61 template <class Impl>
62 const char *
63 OzoneLSQ<Impl>::StoreCompletionEvent::description()
64 {
65 return "LSQ store completion event";
66 }
67
68 template <class Impl>
69 OzoneLSQ<Impl>::OzoneLSQ()
70 : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false)
71 {
72 }
73
74 template<class Impl>
75 void
76 OzoneLSQ<Impl>::init(Params *params, unsigned maxLQEntries,
77 unsigned maxSQEntries, unsigned id)
78
79 {
80 DPRINTF(OzoneLSQ, "Creating OzoneLSQ%i object.\n",id);
81
82 lsqID = id;
83
84 LQEntries = maxLQEntries;
85 SQEntries = maxSQEntries;
86
87 loadQueue.resize(LQEntries);
88 storeQueue.resize(SQEntries);
89
90
91 // May want to initialize these entries to NULL
92
93 loadHead = loadTail = 0;
94
95 storeHead = storeWBIdx = storeTail = 0;
96
97 usedPorts = 0;
98 cachePorts = params->cachePorts;
99
100 dcacheInterface = params->dcacheInterface;
101
102 loadFaultInst = storeFaultInst = memDepViolator = NULL;
103 }
104
105 template<class Impl>
106 std::string
107 OzoneLSQ<Impl>::name() const
108 {
109 return "lsqunit";
110 }
111
112 template<class Impl>
113 void
114 OzoneLSQ<Impl>::clearLQ()
115 {
116 loadQueue.clear();
117 }
118
119 template<class Impl>
120 void
121 OzoneLSQ<Impl>::clearSQ()
122 {
123 storeQueue.clear();
124 }
125
126 template<class Impl>
127 void
128 OzoneLSQ<Impl>::resizeLQ(unsigned size)
129 {
130 assert( size >= LQEntries);
131
132 if (size > LQEntries) {
133 while (size > loadQueue.size()) {
134 DynInstPtr dummy;
135 loadQueue.push_back(dummy);
136 LQEntries++;
137 }
138 } else {
139 LQEntries = size;
140 }
141
142 }
143
144 template<class Impl>
145 void
146 OzoneLSQ<Impl>::resizeSQ(unsigned size)
147 {
148 if (size > SQEntries) {
149 while (size > storeQueue.size()) {
150 SQEntry dummy;
151 storeQueue.push_back(dummy);
152 SQEntries++;
153 }
154 } else {
155 SQEntries = size;
156 }
157 }
158
159 template <class Impl>
160 void
161 OzoneLSQ<Impl>::insert(DynInstPtr &inst)
162 {
163 // Make sure we really have a memory reference.
164 assert(inst->isMemRef());
165
166 // Make sure it's one of the two classes of memory references.
167 assert(inst->isLoad() || inst->isStore());
168
169 if (inst->isLoad()) {
170 insertLoad(inst);
171 } else {
172 insertStore(inst);
173 }
174
175 // inst->setInLSQ();
176 }
177
178 template <class Impl>
179 void
180 OzoneLSQ<Impl>::insertLoad(DynInstPtr &load_inst)
181 {
182 assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries);
183
184 DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
185 load_inst->readPC(), loadTail, load_inst->seqNum);
186
187 load_inst->lqIdx = loadTail;
188
189 if (stores == 0) {
190 load_inst->sqIdx = -1;
191 } else {
192 load_inst->sqIdx = storeTail;
193 }
194
195 loadQueue[loadTail] = load_inst;
196
197 incrLdIdx(loadTail);
198
199 ++loads;
200 }
201
202 template <class Impl>
203 void
204 OzoneLSQ<Impl>::insertStore(DynInstPtr &store_inst)
205 {
206 // Make sure it is not full before inserting an instruction.
207 assert((storeTail + 1) % SQEntries != storeHead);
208 assert(stores < SQEntries);
209
210 DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
211 store_inst->readPC(), storeTail, store_inst->seqNum);
212
213 store_inst->sqIdx = storeTail;
214 store_inst->lqIdx = loadTail;
215
216 storeQueue[storeTail] = SQEntry(store_inst);
217
218 incrStIdx(storeTail);
219
220 ++stores;
221
222 }
223
224 template <class Impl>
225 typename Impl::DynInstPtr
226 OzoneLSQ<Impl>::getMemDepViolator()
227 {
228 DynInstPtr temp = memDepViolator;
229
230 memDepViolator = NULL;
231
232 return temp;
233 }
234
235 template <class Impl>
236 unsigned
237 OzoneLSQ<Impl>::numFreeEntries()
238 {
239 unsigned free_lq_entries = LQEntries - loads;
240 unsigned free_sq_entries = SQEntries - stores;
241
242 // Both the LQ and SQ entries have an extra dummy entry to differentiate
243 // empty/full conditions. Subtract 1 from the free entries.
244 if (free_lq_entries < free_sq_entries) {
245 return free_lq_entries - 1;
246 } else {
247 return free_sq_entries - 1;
248 }
249 }
250
251 template <class Impl>
252 int
253 OzoneLSQ<Impl>::numLoadsReady()
254 {
255 int load_idx = loadHead;
256 int retval = 0;
257
258 while (load_idx != loadTail) {
259 assert(loadQueue[load_idx]);
260
261 if (loadQueue[load_idx]->readyToIssue()) {
262 ++retval;
263 }
264 }
265
266 return retval;
267 }
268
269 #if 0
270 template <class Impl>
271 Fault
272 OzoneLSQ<Impl>::executeLoad()
273 {
274 Fault load_fault = NoFault;
275 DynInstPtr load_inst;
276
277 assert(readyLoads.size() != 0);
278
279 // Execute a ready load.
280 LdMapIt ready_it = readyLoads.begin();
281
282 load_inst = (*ready_it).second;
283
284 // Execute the instruction, which is held in the data portion of the
285 // iterator.
286 load_fault = load_inst->execute();
287
288 // If it executed successfully, then switch it over to the executed
289 // loads list.
290 if (load_fault == NoFault) {
291 executedLoads[load_inst->seqNum] = load_inst;
292
293 readyLoads.erase(ready_it);
294 } else {
295 loadFaultInst = load_inst;
296 }
297
298 return load_fault;
299 }
300 #endif
301
302 template <class Impl>
303 Fault
304 OzoneLSQ<Impl>::executeLoad(DynInstPtr &inst)
305 {
306 // Execute a specific load.
307 Fault load_fault = NoFault;
308
309 DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n",
310 inst->readPC(),inst->seqNum);
311
312 // Make sure it's really in the list.
313 // Normally it should always be in the list. However,
314 /* due to a syscall it may not be the list.
315 #ifdef DEBUG
316 int i = loadHead;
317 while (1) {
318 if (i == loadTail && !find(inst)) {
319 assert(0 && "Load not in the queue!");
320 } else if (loadQueue[i] == inst) {
321 break;
322 }
323
324 i = i + 1;
325 if (i >= LQEntries) {
326 i = 0;
327 }
328 }
329 #endif // DEBUG*/
330
331 load_fault = inst->initiateAcc();
332
333 // Might want to make sure that I'm not overwriting a previously faulting
334 // instruction that hasn't been checked yet.
335 // Actually probably want the oldest faulting load
336 if (load_fault != NoFault) {
337 // Maybe just set it as can commit here, although that might cause
338 // some other problems with sending traps to the ROB too quickly.
339 // iewStage->instToCommit(inst);
340 // iewStage->activityThisCycle();
341 }
342
343 return load_fault;
344 }
345
346 template <class Impl>
347 Fault
348 OzoneLSQ<Impl>::executeLoad(int lq_idx)
349 {
350 // Very hackish. Not sure the best way to check that this
351 // instruction is at the head of the ROB. I should have some sort
352 // of extra information here so that I'm not overloading the
353 // canCommit signal for 15 different things.
354 loadQueue[lq_idx]->setCanCommit();
355 Fault ret_fault = executeLoad(loadQueue[lq_idx]);
356 loadQueue[lq_idx]->clearCanCommit();
357 return ret_fault;
358 }
359
360 template <class Impl>
361 Fault
362 OzoneLSQ<Impl>::executeStore(DynInstPtr &store_inst)
363 {
364 // Make sure that a store exists.
365 assert(stores != 0);
366
367 int store_idx = store_inst->sqIdx;
368
369 DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n",
370 store_inst->readPC(), store_inst->seqNum);
371
372 // Check the recently completed loads to see if any match this store's
373 // address. If so, then we have a memory ordering violation.
374 int load_idx = store_inst->lqIdx;
375
376 Fault store_fault = store_inst->initiateAcc();
377
378 // Store size should now be available. Use it to get proper offset for
379 // addr comparisons.
380 int size = storeQueue[store_idx].size;
381
382 if (size == 0) {
383 DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
384 store_inst->readPC(),store_inst->seqNum);
385
386 return store_fault;
387 }
388
389 assert(store_fault == NoFault);
390
391 if (!storeFaultInst) {
392 if (store_fault != NoFault) {
393 panic("Fault in a store instruction!");
394 storeFaultInst = store_inst;
395 } else if (store_inst->isNonSpeculative()) {
396 // Nonspeculative accesses (namely store conditionals)
397 // need to set themselves as able to writeback if we
398 // haven't had a fault by here.
399 storeQueue[store_idx].canWB = true;
400
401 ++storesToWB;
402 }
403 }
404
405 if (!memDepViolator) {
406 while (load_idx != loadTail) {
407 // Actually should only check loads that have actually executed
408 // Might be safe because effAddr is set to InvalAddr when the
409 // dyn inst is created.
410
411 // Must actually check all addrs in the proper size range
412 // Which is more correct than needs to be. What if for now we just
413 // assume all loads are quad-word loads, and do the addr based
414 // on that.
415 // @todo: Fix this, magic number being used here
416 if ((loadQueue[load_idx]->effAddr >> 8) ==
417 (store_inst->effAddr >> 8)) {
418 // A load incorrectly passed this store. Squash and refetch.
419 // For now return a fault to show that it was unsuccessful.
420 memDepViolator = loadQueue[load_idx];
421
422 return TheISA::genMachineCheckFault();
423 }
424
425 incrLdIdx(load_idx);
426 }
427
428 // If we've reached this point, there was no violation.
429 memDepViolator = NULL;
430 }
431
432 return store_fault;
433 }
434
435 template <class Impl>
436 void
437 OzoneLSQ<Impl>::commitLoad()
438 {
439 assert(loadQueue[loadHead]);
440
441 DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n",
442 loadQueue[loadHead]->seqNum, loadQueue[loadHead]->readPC());
443
444
445 loadQueue[loadHead] = NULL;
446
447 incrLdIdx(loadHead);
448
449 --loads;
450 }
451
452 template <class Impl>
453 void
454 OzoneLSQ<Impl>::commitLoad(InstSeqNum &inst)
455 {
456 // Hopefully I don't use this function too much
457 panic("Don't use this function!");
458
459 int i = loadHead;
460 while (1) {
461 if (i == loadTail) {
462 assert(0 && "Load not in the queue!");
463 } else if (loadQueue[i]->seqNum == inst) {
464 break;
465 }
466
467 ++i;
468 if (i >= LQEntries) {
469 i = 0;
470 }
471 }
472
473 // loadQueue[i]->removeInLSQ();
474 loadQueue[i] = NULL;
475 --loads;
476 }
477
478 template <class Impl>
479 void
480 OzoneLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst)
481 {
482 assert(loads == 0 || loadQueue[loadHead]);
483
484 while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
485 commitLoad();
486 }
487 }
488
489 template <class Impl>
490 void
491 OzoneLSQ<Impl>::commitStores(InstSeqNum &youngest_inst)
492 {
493 assert(stores == 0 || storeQueue[storeHead].inst);
494
495 int store_idx = storeHead;
496
497 while (store_idx != storeTail) {
498 assert(storeQueue[store_idx].inst);
499 if (!storeQueue[store_idx].canWB) {
500 if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
501 break;
502 }
503 DPRINTF(OzoneLSQ, "Marking store as able to write back, PC "
504 "%#x [sn:%lli]\n",
505 storeQueue[store_idx].inst->readPC(),
506 storeQueue[store_idx].inst->seqNum);
507
508 storeQueue[store_idx].canWB = true;
509
510 // --stores;
511 ++storesToWB;
512 }
513
514 incrStIdx(store_idx);
515 }
516 }
517
518 template <class Impl>
519 void
520 OzoneLSQ<Impl>::writebackStores()
521 {
522 while (storesToWB > 0 &&
523 storeWBIdx != storeTail &&
524 storeQueue[storeWBIdx].inst &&
525 storeQueue[storeWBIdx].canWB &&
526 usedPorts < cachePorts) {
527
528 if (storeQueue[storeWBIdx].size == 0) {
529 completeStore(storeWBIdx);
530
531 incrStIdx(storeWBIdx);
532
533 continue;
534 }
535
536 if (dcacheInterface && dcacheInterface->isBlocked()) {
537 DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
538 " is blocked!\n");
539 break;
540 }
541
542 ++usedPorts;
543
544 if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
545 incrStIdx(storeWBIdx);
546
547 continue;
548 }
549
550 assert(storeQueue[storeWBIdx].req);
551 assert(!storeQueue[storeWBIdx].committed);
552
553 MemReqPtr req = storeQueue[storeWBIdx].req;
554 storeQueue[storeWBIdx].committed = true;
555
556 // Fault fault = cpu->translateDataReadReq(req);
557 req->cmd = Write;
558 req->completionEvent = NULL;
559 req->time = curTick;
560 assert(!req->data);
561 req->data = new uint8_t[64];
562 memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
563
564 DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x "
565 "to Addr:%#x, data:%#x [sn:%lli]\n",
566 storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
567 req->paddr, *(req->data),
568 storeQueue[storeWBIdx].inst->seqNum);
569
570 // if (fault != NoFault) {
571 //What should we do if there is a fault???
572 //for now panic
573 // panic("Page Table Fault!!!!!\n");
574 // }
575
576 if (dcacheInterface) {
577 MemAccessResult result = dcacheInterface->access(req);
578
579 //@todo temp fix for LL/SC (works fine for 1 CPU)
580 if (req->flags & LOCKED) {
581 req->result=1;
582 panic("LL/SC! oh no no support!!!");
583 }
584
585 if (isStalled() &&
586 storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
587 DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
588 "load idx:%i\n",
589 stallingStoreIsn, stallingLoadIdx);
590 stalled = false;
591 stallingStoreIsn = 0;
592 be->replayMemInst(loadQueue[stallingLoadIdx]);
593 }
594
595 if (result != MA_HIT && dcacheInterface->doEvents()) {
596 Event *wb = NULL;
597 /*
598 typename IEW::LdWritebackEvent *wb = NULL;
599 if (req->flags & LOCKED) {
600 // Stx_C does not generate a system port transaction.
601 req->result=0;
602 wb = new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
603 iewStage);
604 }
605 */
606 DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n");
607
608 // DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
609 // storeQueue[storeWBIdx].inst->seqNum);
610
611 // Will stores need their own kind of writeback events?
612 // Do stores even need writeback events?
613 assert(!req->completionEvent);
614 req->completionEvent = new
615 StoreCompletionEvent(storeWBIdx, wb, this);
616
617 lastDcacheStall = curTick;
618
619 _status = DcacheMissStall;
620
621 //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
622
623 //DPRINTF(OzoneLSQ, "Added MSHR. count = %i\n",mshrSeqNums.size());
624
625 // Increment stat here or something
626 } else {
627 DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n",
628 storeWBIdx);
629
630 // DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
631 // storeQueue[storeWBIdx].inst->seqNum);
632
633 if (req->flags & LOCKED) {
634 // Stx_C does not generate a system port transaction.
635 req->result=1;
636 typename BackEnd::LdWritebackEvent *wb =
637 new typename BackEnd::LdWritebackEvent(storeQueue[storeWBIdx].inst,
638 be);
639 wb->schedule(curTick);
640 }
641
642 completeStore(storeWBIdx);
643 }
644
645 incrStIdx(storeWBIdx);
646 } else {
647 panic("Must HAVE DCACHE!!!!!\n");
648 }
649 }
650
651 // Not sure this should set it to 0.
652 usedPorts = 0;
653
654 assert(stores >= 0 && storesToWB >= 0);
655 }
656
657 /*template <class Impl>
658 void
659 OzoneLSQ<Impl>::removeMSHR(InstSeqNum seqNum)
660 {
661 list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
662 mshrSeqNums.end(),
663 seqNum);
664
665 if (mshr_it != mshrSeqNums.end()) {
666 mshrSeqNums.erase(mshr_it);
667 DPRINTF(OzoneLSQ, "Removing MSHR. count = %i\n",mshrSeqNums.size());
668 }
669 }*/
670
671 template <class Impl>
672 void
673 OzoneLSQ<Impl>::squash(const InstSeqNum &squashed_num)
674 {
675 DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!"
676 "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
677
678 int load_idx = loadTail;
679 decrLdIdx(load_idx);
680
681 while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
682
683 // Clear the smart pointer to make sure it is decremented.
684 DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, "
685 "[sn:%lli]\n",
686 loadQueue[load_idx]->readPC(),
687 loadQueue[load_idx]->seqNum);
688
689 if (isStalled() && load_idx == stallingLoadIdx) {
690 stalled = false;
691 stallingStoreIsn = 0;
692 stallingLoadIdx = 0;
693 }
694
695 // loadQueue[load_idx]->squashed = true;
696 loadQueue[load_idx] = NULL;
697 --loads;
698
699 // Inefficient!
700 loadTail = load_idx;
701
702 decrLdIdx(load_idx);
703 }
704
705 int store_idx = storeTail;
706 decrStIdx(store_idx);
707
708 while (stores != 0 && storeQueue[store_idx].inst->seqNum > squashed_num) {
709
710 // Clear the smart pointer to make sure it is decremented.
711 DPRINTF(OzoneLSQ,"Store Instruction PC %#x squashed, "
712 "idx:%i [sn:%lli]\n",
713 storeQueue[store_idx].inst->readPC(),
714 store_idx, storeQueue[store_idx].inst->seqNum);
715
716 // I don't think this can happen. It should have been cleared by the
717 // stalling load.
718 if (isStalled() &&
719 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
720 panic("Is stalled should have been cleared by stalling load!\n");
721 stalled = false;
722 stallingStoreIsn = 0;
723 }
724
725 // storeQueue[store_idx].inst->squashed = true;
726 storeQueue[store_idx].inst = NULL;
727 storeQueue[store_idx].canWB = 0;
728
729 if (storeQueue[store_idx].req) {
730 assert(!storeQueue[store_idx].req->completionEvent);
731 }
732 storeQueue[store_idx].req = NULL;
733 --stores;
734
735 // Inefficient!
736 storeTail = store_idx;
737
738 decrStIdx(store_idx);
739 }
740 }
741
742 template <class Impl>
743 void
744 OzoneLSQ<Impl>::dumpInsts()
745 {
746 cprintf("Load store queue: Dumping instructions.\n");
747 cprintf("Load queue size: %i\n", loads);
748 cprintf("Load queue: ");
749
750 int load_idx = loadHead;
751
752 while (load_idx != loadTail && loadQueue[load_idx]) {
753 cprintf("[sn:%lli] %#x ", loadQueue[load_idx]->seqNum,
754 loadQueue[load_idx]->readPC());
755
756 incrLdIdx(load_idx);
757 }
758
759 cprintf("\nStore queue size: %i\n", stores);
760 cprintf("Store queue: ");
761
762 int store_idx = storeHead;
763
764 while (store_idx != storeTail && storeQueue[store_idx].inst) {
765 cprintf("[sn:%lli] %#x ", storeQueue[store_idx].inst->seqNum,
766 storeQueue[store_idx].inst->readPC());
767
768 incrStIdx(store_idx);
769 }
770
771 cprintf("\n");
772 }
773
774 template <class Impl>
775 void
776 OzoneLSQ<Impl>::completeStore(int store_idx)
777 {
778 assert(storeQueue[store_idx].inst);
779 storeQueue[store_idx].completed = true;
780 --storesToWB;
781 // A bit conservative because a store completion may not free up entries,
782 // but hopefully avoids two store completions in one cycle from making
783 // the CPU tick twice.
784 // cpu->activityThisCycle();
785
786 if (store_idx == storeHead) {
787 do {
788 incrStIdx(storeHead);
789
790 --stores;
791 } while (storeQueue[storeHead].completed &&
792 storeHead != storeTail);
793
794 // be->updateLSQNextCycle = true;
795 }
796
797 DPRINTF(OzoneLSQ, "Store head idx:%i\n", storeHead);
798
799 if (isStalled() &&
800 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
801 DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
802 "load idx:%i\n",
803 stallingStoreIsn, stallingLoadIdx);
804 stalled = false;
805 stallingStoreIsn = 0;
806 be->replayMemInst(loadQueue[stallingLoadIdx]);
807 }
808 }
809
810 template <class Impl>
811 inline void
812 OzoneLSQ<Impl>::incrStIdx(int &store_idx)
813 {
814 if (++store_idx >= SQEntries)
815 store_idx = 0;
816 }
817
818 template <class Impl>
819 inline void
820 OzoneLSQ<Impl>::decrStIdx(int &store_idx)
821 {
822 if (--store_idx < 0)
823 store_idx += SQEntries;
824 }
825
826 template <class Impl>
827 inline void
828 OzoneLSQ<Impl>::incrLdIdx(int &load_idx)
829 {
830 if (++load_idx >= LQEntries)
831 load_idx = 0;
832 }
833
834 template <class Impl>
835 inline void
836 OzoneLSQ<Impl>::decrLdIdx(int &load_idx)
837 {
838 if (--load_idx < 0)
839 load_idx += LQEntries;
840 }