O3: Track if the RAS has been pushed or not to pop the RAS if neccessary.
[gem5.git] / src / cpu / ozone / lw_back_end_impl.hh
1 /*
2 * Copyright (c) 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 "config/the_isa.hh"
32 #include "cpu/checker/cpu.hh"
33 #include "cpu/ozone/lw_back_end.hh"
34 #include "cpu/op_class.hh"
35
36 template <class Impl>
37 void
38 LWBackEnd<Impl>::generateTrapEvent(Tick latency)
39 {
40 DPRINTF(BE, "Generating trap event\n");
41
42 TrapEvent *trap = new TrapEvent(this);
43
44 trap->schedule(curTick() + cpu->ticks(latency));
45
46 thread->trapPending = true;
47 }
48
49 template <class Impl>
50 int
51 LWBackEnd<Impl>::wakeDependents(DynInstPtr &inst, bool memory_deps)
52 {
53 assert(!inst->isSquashed());
54 std::vector<DynInstPtr> &dependents = memory_deps ? inst->getMemDeps() :
55 inst->getDependents();
56 int num_outputs = dependents.size();
57
58 DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum);
59
60 for (int i = 0; i < num_outputs; i++) {
61 DynInstPtr dep_inst = dependents[i];
62 if (!memory_deps) {
63 dep_inst->markSrcRegReady();
64 } else {
65 if (!dep_inst->isSquashed())
66 dep_inst->markMemInstReady(inst.get());
67 }
68
69 DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum);
70
71 if (dep_inst->readyToIssue() && dep_inst->isInROB() &&
72 !dep_inst->isNonSpeculative() && !dep_inst->isStoreConditional() &&
73 dep_inst->memDepReady() && !dep_inst->isMemBarrier() &&
74 !dep_inst->isWriteBarrier()) {
75 DPRINTF(BE, "Adding instruction to exeList [sn:%lli]\n",
76 dep_inst->seqNum);
77 exeList.push(dep_inst);
78 if (dep_inst->iqItValid) {
79 DPRINTF(BE, "Removing instruction from waiting list\n");
80 waitingList.erase(dep_inst->iqIt);
81 waitingInsts--;
82 dep_inst->iqItValid = false;
83 assert(waitingInsts >= 0);
84 }
85 if (dep_inst->isMemRef()) {
86 removeWaitingMemOp(dep_inst);
87 DPRINTF(BE, "Issued a waiting mem op [sn:%lli]\n",
88 dep_inst->seqNum);
89 }
90 }
91 }
92 return num_outputs;
93 }
94
95 template <class Impl>
96 void
97 LWBackEnd<Impl>::rescheduleMemInst(DynInstPtr &inst)
98 {
99 replayList.push_front(inst);
100 }
101
102 template <class Impl>
103 LWBackEnd<Impl>::TrapEvent::TrapEvent(LWBackEnd<Impl> *_be)
104 : Event(&mainEventQueue, CPU_Tick_Pri), be(_be)
105 {
106 this->setFlags(Event::AutoDelete);
107 }
108
109 template <class Impl>
110 void
111 LWBackEnd<Impl>::TrapEvent::process()
112 {
113 be->trapSquash = true;
114 }
115
116 template <class Impl>
117 const char *
118 LWBackEnd<Impl>::TrapEvent::description() const
119 {
120 return "Trap";
121 }
122
123 template <class Impl>
124 void
125 LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst)
126 {
127 bool found_inst = false;
128 while (!replayList.empty()) {
129 exeList.push(replayList.front());
130 if (replayList.front() == inst) {
131 found_inst = true;
132 }
133 replayList.pop_front();
134 }
135 assert(found_inst);
136 }
137
138 template <class Impl>
139 LWBackEnd<Impl>::LWBackEnd(Params *params)
140 : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(params->backEndLatency, 0),
141 trapSquash(false), tcSquash(false),
142 latency(params->backEndLatency),
143 width(params->backEndWidth), lsqLimits(params->lsqLimits),
144 exactFullStall(true)
145 {
146 numROBEntries = params->numROBEntries;
147 numInsts = 0;
148 maxOutstandingMemOps = params->maxOutstandingMemOps;
149 numWaitingMemOps = 0;
150 waitingInsts = 0;
151 switchedOut = false;
152 switchPending = false;
153
154 LSQ.setBE(this);
155
156 // Setup IQ and LSQ with their parameters here.
157 instsToDispatch = d2i.getWire(-1);
158
159 instsToExecute = i2e.getWire(-1);
160
161 dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width;
162 issueWidth = params->issueWidth ? params->issueWidth : width;
163 wbWidth = params->wbWidth ? params->wbWidth : width;
164 commitWidth = params->commitWidth ? params->commitWidth : width;
165
166 LSQ.init(params, params->LQEntries, params->SQEntries, 0);
167
168 dispatchStatus = Running;
169 commitStatus = Running;
170 }
171
172 template <class Impl>
173 std::string
174 LWBackEnd<Impl>::name() const
175 {
176 return cpu->name() + ".backend";
177 }
178
179 template <class Impl>
180 void
181 LWBackEnd<Impl>::regStats()
182 {
183 using namespace Stats;
184 LSQ.regStats();
185
186 robCapEvents
187 .init(cpu->numThreads)
188 .name(name() + ".ROB:cap_events")
189 .desc("number of cycles where ROB cap was active")
190 .flags(total)
191 ;
192
193 robCapInstCount
194 .init(cpu->numThreads)
195 .name(name() + ".ROB:cap_inst")
196 .desc("number of instructions held up by ROB cap")
197 .flags(total)
198 ;
199
200 iqCapEvents
201 .init(cpu->numThreads)
202 .name(name() +".IQ:cap_events" )
203 .desc("number of cycles where IQ cap was active")
204 .flags(total)
205 ;
206
207 iqCapInstCount
208 .init(cpu->numThreads)
209 .name(name() + ".IQ:cap_inst")
210 .desc("number of instructions held up by IQ cap")
211 .flags(total)
212 ;
213
214 exeInst
215 .init(cpu->numThreads)
216 .name(name() + ".ISSUE:count")
217 .desc("number of insts issued")
218 .flags(total)
219 ;
220
221 exeSwp
222 .init(cpu->numThreads)
223 .name(name() + ".ISSUE:swp")
224 .desc("number of swp insts issued")
225 .flags(total)
226 ;
227
228 exeNop
229 .init(cpu->numThreads)
230 .name(name() + ".ISSUE:nop")
231 .desc("number of nop insts issued")
232 .flags(total)
233 ;
234
235 exeRefs
236 .init(cpu->numThreads)
237 .name(name() + ".ISSUE:refs")
238 .desc("number of memory reference insts issued")
239 .flags(total)
240 ;
241
242 exeLoads
243 .init(cpu->numThreads)
244 .name(name() + ".ISSUE:loads")
245 .desc("number of load insts issued")
246 .flags(total)
247 ;
248
249 exeBranches
250 .init(cpu->numThreads)
251 .name(name() + ".ISSUE:branches")
252 .desc("Number of branches issued")
253 .flags(total)
254 ;
255
256 issuedOps
257 .init(cpu->numThreads)
258 .name(name() + ".ISSUE:op_count")
259 .desc("number of insts issued")
260 .flags(total)
261 ;
262
263 /*
264 for (int i=0; i<Num_OpClasses; ++i) {
265 stringstream subname;
266 subname << opClassStrings[i] << "_delay";
267 issue_delay_dist.subname(i, subname.str());
268 }
269 */
270 //
271 // Other stats
272 //
273 lsqForwLoads
274 .init(cpu->numThreads)
275 .name(name() + ".LSQ:forw_loads")
276 .desc("number of loads forwarded via LSQ")
277 .flags(total)
278 ;
279
280 invAddrLoads
281 .init(cpu->numThreads)
282 .name(name() + ".ISSUE:addr_loads")
283 .desc("number of invalid-address loads")
284 .flags(total)
285 ;
286
287 invAddrSwpfs
288 .init(cpu->numThreads)
289 .name(name() + ".ISSUE:addr_swpfs")
290 .desc("number of invalid-address SW prefetches")
291 .flags(total)
292 ;
293
294 lsqBlockedLoads
295 .init(cpu->numThreads)
296 .name(name() + ".LSQ:blocked_loads")
297 .desc("number of ready loads not issued due to memory disambiguation")
298 .flags(total)
299 ;
300
301 lsqInversion
302 .name(name() + ".ISSUE:lsq_invert")
303 .desc("Number of times LSQ instruction issued early")
304 ;
305
306 nIssuedDist
307 .init(issueWidth + 1)
308 .name(name() + ".ISSUE:issued_per_cycle")
309 .desc("Number of insts issued each cycle")
310 .flags(total | pdf | dist)
311 ;
312 /*
313 issueDelayDist
314 .init(Num_OpClasses,0,99,2)
315 .name(name() + ".ISSUE:")
316 .desc("cycles from operands ready to issue")
317 .flags(pdf | cdf)
318 ;
319
320 queueResDist
321 .init(Num_OpClasses, 0, 99, 2)
322 .name(name() + ".IQ:residence:")
323 .desc("cycles from dispatch to issue")
324 .flags(total | pdf | cdf )
325 ;
326 for (int i = 0; i < Num_OpClasses; ++i) {
327 queueResDist.subname(i, opClassStrings[i]);
328 }
329 */
330 writebackCount
331 .init(cpu->numThreads)
332 .name(name() + ".WB:count")
333 .desc("cumulative count of insts written-back")
334 .flags(total)
335 ;
336
337 producerInst
338 .init(cpu->numThreads)
339 .name(name() + ".WB:producers")
340 .desc("num instructions producing a value")
341 .flags(total)
342 ;
343
344 consumerInst
345 .init(cpu->numThreads)
346 .name(name() + ".WB:consumers")
347 .desc("num instructions consuming a value")
348 .flags(total)
349 ;
350
351 wbPenalized
352 .init(cpu->numThreads)
353 .name(name() + ".WB:penalized")
354 .desc("number of instrctions required to write to 'other' IQ")
355 .flags(total)
356 ;
357
358
359 wbPenalizedRate
360 .name(name() + ".WB:penalized_rate")
361 .desc ("fraction of instructions written-back that wrote to 'other' IQ")
362 .flags(total)
363 ;
364
365 wbPenalizedRate = wbPenalized / writebackCount;
366
367 wbFanout
368 .name(name() + ".WB:fanout")
369 .desc("average fanout of values written-back")
370 .flags(total)
371 ;
372
373 wbFanout = producerInst / consumerInst;
374
375 wbRate
376 .name(name() + ".WB:rate")
377 .desc("insts written-back per cycle")
378 .flags(total)
379 ;
380 wbRate = writebackCount / cpu->numCycles;
381
382 statComInst
383 .init(cpu->numThreads)
384 .name(name() + ".COM:count")
385 .desc("Number of instructions committed")
386 .flags(total)
387 ;
388
389 statComSwp
390 .init(cpu->numThreads)
391 .name(name() + ".COM:swp_count")
392 .desc("Number of s/w prefetches committed")
393 .flags(total)
394 ;
395
396 statComRefs
397 .init(cpu->numThreads)
398 .name(name() + ".COM:refs")
399 .desc("Number of memory references committed")
400 .flags(total)
401 ;
402
403 statComLoads
404 .init(cpu->numThreads)
405 .name(name() + ".COM:loads")
406 .desc("Number of loads committed")
407 .flags(total)
408 ;
409
410 statComMembars
411 .init(cpu->numThreads)
412 .name(name() + ".COM:membars")
413 .desc("Number of memory barriers committed")
414 .flags(total)
415 ;
416
417 statComBranches
418 .init(cpu->numThreads)
419 .name(name() + ".COM:branches")
420 .desc("Number of branches committed")
421 .flags(total)
422 ;
423 nCommittedDist
424 .init(0,commitWidth,1)
425 .name(name() + ".COM:committed_per_cycle")
426 .desc("Number of insts commited each cycle")
427 .flags(pdf)
428 ;
429
430 //
431 // Commit-Eligible instructions...
432 //
433 // -> The number of instructions eligible to commit in those
434 // cycles where we reached our commit BW limit (less the number
435 // actually committed)
436 //
437 // -> The average value is computed over ALL CYCLES... not just
438 // the BW limited cycles
439 //
440 // -> The standard deviation is computed only over cycles where
441 // we reached the BW limit
442 //
443 commitEligible
444 .init(cpu->numThreads)
445 .name(name() + ".COM:bw_limited")
446 .desc("number of insts not committed due to BW limits")
447 .flags(total)
448 ;
449
450 commitEligibleSamples
451 .name(name() + ".COM:bw_lim_events")
452 .desc("number cycles where commit BW limit reached")
453 ;
454
455 squashedInsts
456 .init(cpu->numThreads)
457 .name(name() + ".COM:squashed_insts")
458 .desc("Number of instructions removed from inst list")
459 ;
460
461 ROBSquashedInsts
462 .init(cpu->numThreads)
463 .name(name() + ".COM:rob_squashed_insts")
464 .desc("Number of instructions removed from inst list when they reached the head of the ROB")
465 ;
466
467 ROBFcount
468 .name(name() + ".ROB:full_count")
469 .desc("number of cycles where ROB was full")
470 ;
471
472 ROBCount
473 .init(cpu->numThreads)
474 .name(name() + ".ROB:occupancy")
475 .desc(name() + ".ROB occupancy (cumulative)")
476 .flags(total)
477 ;
478
479 ROBFullRate
480 .name(name() + ".ROB:full_rate")
481 .desc("ROB full per cycle")
482 ;
483 ROBFullRate = ROBFcount / cpu->numCycles;
484
485 ROBOccRate
486 .name(name() + ".ROB:occ_rate")
487 .desc("ROB occupancy rate")
488 .flags(total)
489 ;
490 ROBOccRate = ROBCount / cpu->numCycles;
491 /*
492 ROBOccDist
493 .init(cpu->numThreads, 0, numROBEntries, 2)
494 .name(name() + ".ROB:occ_dist")
495 .desc("ROB Occupancy per cycle")
496 .flags(total | cdf)
497 ;
498 */
499 }
500
501 template <class Impl>
502 void
503 LWBackEnd<Impl>::setCPU(OzoneCPU *cpu_ptr)
504 {
505 cpu = cpu_ptr;
506 LSQ.setCPU(cpu_ptr);
507 checker = cpu->checker;
508 }
509
510 template <class Impl>
511 void
512 LWBackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
513 {
514 comm = _comm;
515 toIEW = comm->getWire(0);
516 fromCommit = comm->getWire(-1);
517 }
518
519 template <class Impl>
520 void
521 LWBackEnd<Impl>::checkInterrupts()
522 {
523 if (cpu->checkInterrupts(tc) && !trapSquash && !tcSquash) {
524 frontEnd->interruptPending = true;
525 if (robEmpty() && !LSQ.hasStoresToWB()) {
526 // Will need to squash all instructions currently in flight and have
527 // the interrupt handler restart at the last non-committed inst.
528 // Most of that can be handled through the trap() function. The
529 // processInterrupts() function really just checks for interrupts
530 // and then calls trap() if there is an interrupt present.
531
532 // Not sure which thread should be the one to interrupt. For now
533 // always do thread 0.
534 assert(!thread->inSyscall);
535 thread->inSyscall = true;
536
537 // CPU will handle implementation of the interrupt.
538 cpu->processInterrupts();
539
540 // Now squash or record that I need to squash this cycle.
541 commitStatus = TrapPending;
542
543 // Exit state update mode to avoid accidental updating.
544 thread->inSyscall = false;
545
546 // Generate trap squash event.
547 generateTrapEvent();
548
549 DPRINTF(BE, "Interrupt detected.\n");
550 } else {
551 DPRINTF(BE, "Interrupt must wait for ROB to drain.\n");
552 }
553 }
554 }
555
556 template <class Impl>
557 void
558 LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency)
559 {
560 DPRINTF(BE, "Handling fault!\n");
561
562 assert(!thread->inSyscall);
563
564 thread->inSyscall = true;
565
566 // Consider holding onto the trap and waiting until the trap event
567 // happens for this to be executed.
568 fault->invoke(thread->getTC());
569
570 // Exit state update mode to avoid accidental updating.
571 thread->inSyscall = false;
572
573 commitStatus = TrapPending;
574
575 // Generate trap squash event.
576 generateTrapEvent(latency);
577 }
578
579 template <class Impl>
580 void
581 LWBackEnd<Impl>::tick()
582 {
583 DPRINTF(BE, "Ticking back end\n");
584
585 // Read in any done instruction information and update the IQ or LSQ.
586 updateStructures();
587
588 if (switchPending && robEmpty() && !LSQ.hasStoresToWB()) {
589 cpu->signalSwitched();
590 return;
591 }
592
593 readyInstsForCommit();
594
595 numInstsToWB.advance();
596
597 ROBCount[0]+= numInsts;
598
599 wbCycle = 0;
600
601 checkInterrupts();
602
603 if (trapSquash) {
604 assert(!tcSquash);
605 squashFromTrap();
606 } else if (tcSquash) {
607 squashFromTC();
608 }
609
610 if (dispatchStatus != Blocked) {
611 dispatchInsts();
612 } else {
613 checkDispatchStatus();
614 }
615
616 if (commitStatus != TrapPending) {
617 executeInsts();
618
619 commitInsts();
620 }
621
622 LSQ.writebackStores();
623
624 DPRINTF(BE, "Waiting insts: %i, mem ops: %i, ROB entries in use: %i, "
625 "LSQ loads: %i, LSQ stores: %i\n",
626 waitingInsts, numWaitingMemOps, numInsts,
627 LSQ.numLoads(), LSQ.numStores());
628
629 #ifdef DEBUG
630 assert(numInsts == instList.size());
631 assert(waitingInsts == waitingList.size());
632 assert(numWaitingMemOps == waitingMemOps.size());
633 assert(!switchedOut);
634 #endif
635 }
636
637 template <class Impl>
638 void
639 LWBackEnd<Impl>::updateStructures()
640 {
641 if (fromCommit->doneSeqNum) {
642 LSQ.commitLoads(fromCommit->doneSeqNum);
643 LSQ.commitStores(fromCommit->doneSeqNum);
644 }
645
646 if (fromCommit->nonSpecSeqNum) {
647 if (fromCommit->uncached) {
648 // LSQ.executeLoad(fromCommit->lqIdx);
649 } else {
650 // IQ.scheduleNonSpec(
651 // fromCommit->nonSpecSeqNum);
652 }
653 }
654 }
655
656 template <class Impl>
657 void
658 LWBackEnd<Impl>::addToLSQ(DynInstPtr &inst)
659 {
660 // Do anything LSQ specific here?
661 LSQ.insert(inst);
662 }
663
664 template <class Impl>
665 void
666 LWBackEnd<Impl>::dispatchInsts()
667 {
668 DPRINTF(BE, "Trying to dispatch instructions.\n");
669
670 while (numInsts < numROBEntries &&
671 numWaitingMemOps < maxOutstandingMemOps) {
672 // Get instruction from front of time buffer
673 if (lsqLimits && LSQ.isFull()) {
674 break;
675 }
676
677 DynInstPtr inst = frontEnd->getInst();
678 if (!inst) {
679 break;
680 } else if (inst->isSquashed()) {
681 continue;
682 }
683
684 ++numInsts;
685 instList.push_front(inst);
686
687 inst->setInROB();
688
689 DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n",
690 inst->seqNum, inst->readPC());
691
692 for (int i = 0; i < inst->numDestRegs(); ++i)
693 renameTable[inst->destRegIdx(i)] = inst;
694
695 if (inst->isMemBarrier() || inst->isWriteBarrier()) {
696 if (memBarrier) {
697 DPRINTF(BE, "Instruction [sn:%lli] is waiting on "
698 "barrier [sn:%lli].\n",
699 inst->seqNum, memBarrier->seqNum);
700 memBarrier->addMemDependent(inst);
701 inst->addSrcMemInst(memBarrier);
702 }
703 memBarrier = inst;
704 inst->setCanCommit();
705 } else if (inst->readyToIssue() &&
706 !inst->isNonSpeculative() &&
707 !inst->isStoreConditional()) {
708 if (inst->isMemRef()) {
709
710 LSQ.insert(inst);
711 if (memBarrier) {
712 DPRINTF(BE, "Instruction [sn:%lli] is waiting on "
713 "barrier [sn:%lli].\n",
714 inst->seqNum, memBarrier->seqNum);
715 memBarrier->addMemDependent(inst);
716 inst->addSrcMemInst(memBarrier);
717 addWaitingMemOp(inst);
718
719 waitingList.push_front(inst);
720 inst->iqIt = waitingList.begin();
721 inst->iqItValid = true;
722 waitingInsts++;
723 } else {
724 DPRINTF(BE, "Instruction [sn:%lli] ready, addding to "
725 "exeList.\n",
726 inst->seqNum);
727 exeList.push(inst);
728 }
729 } else if (inst->isNop()) {
730 DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n",
731 inst->seqNum);
732 inst->setIssued();
733 inst->setExecuted();
734 inst->setCanCommit();
735 numInstsToWB[0]++;
736 } else {
737 DPRINTF(BE, "Instruction [sn:%lli] ready, addding to "
738 "exeList.\n",
739 inst->seqNum);
740 exeList.push(inst);
741 }
742 } else {
743 if (inst->isNonSpeculative() || inst->isStoreConditional()) {
744 inst->setCanCommit();
745 DPRINTF(BE, "Adding non speculative instruction\n");
746 }
747
748 if (inst->isMemRef()) {
749 addWaitingMemOp(inst);
750 LSQ.insert(inst);
751 if (memBarrier) {
752 memBarrier->addMemDependent(inst);
753 inst->addSrcMemInst(memBarrier);
754
755 DPRINTF(BE, "Instruction [sn:%lli] is waiting on "
756 "barrier [sn:%lli].\n",
757 inst->seqNum, memBarrier->seqNum);
758 }
759 }
760
761 DPRINTF(BE, "Instruction [sn:%lli] not ready, addding to "
762 "waitingList.\n",
763 inst->seqNum);
764 waitingList.push_front(inst);
765 inst->iqIt = waitingList.begin();
766 inst->iqItValid = true;
767 waitingInsts++;
768 }
769 }
770
771 // Check if IQ or LSQ is full. If so we'll need to break and stop
772 // removing instructions. Also update the number of insts to remove
773 // from the queue. Check here if we don't care about exact stall
774 // conditions.
775 /*
776 bool stall = false;
777 if (IQ.isFull()) {
778 DPRINTF(BE, "IQ is full!\n");
779 stall = true;
780 } else if (LSQ.isFull()) {
781 DPRINTF(BE, "LSQ is full!\n");
782 stall = true;
783 } else if (isFull()) {
784 DPRINTF(BE, "ROB is full!\n");
785 stall = true;
786 ROB_fcount++;
787 }
788 if (stall) {
789 d2i.advance();
790 dispatchStall();
791 return;
792 }
793 */
794 }
795
796 template <class Impl>
797 void
798 LWBackEnd<Impl>::dispatchStall()
799 {
800 dispatchStatus = Blocked;
801 if (!cpu->decoupledFrontEnd) {
802 // Tell front end to stall here through a timebuffer, or just tell
803 // it directly.
804 }
805 }
806
807 template <class Impl>
808 void
809 LWBackEnd<Impl>::checkDispatchStatus()
810 {
811 DPRINTF(BE, "Checking dispatch status\n");
812 assert(dispatchStatus == Blocked);
813 if (!LSQ.isFull() && !isFull()) {
814 DPRINTF(BE, "Dispatch no longer blocked\n");
815 dispatchStatus = Running;
816 dispatchInsts();
817 }
818 }
819
820 template <class Impl>
821 void
822 LWBackEnd<Impl>::executeInsts()
823 {
824 DPRINTF(BE, "Trying to execute instructions\n");
825
826 int num_executed = 0;
827 while (!exeList.empty() && num_executed < issueWidth) {
828 DynInstPtr inst = exeList.top();
829
830 DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n",
831 inst->seqNum, inst->readPC());
832
833 // Check if the instruction is squashed; if so then skip it
834 // and don't count it towards the FU usage.
835 if (inst->isSquashed()) {
836 DPRINTF(BE, "Execute: Instruction was squashed.\n");
837
838 // Not sure how to handle this plus the method of sending # of
839 // instructions to use. Probably will just have to count it
840 // towards the bandwidth usage, but not the FU usage.
841 ++num_executed;
842
843 // Consider this instruction executed so that commit can go
844 // ahead and retire the instruction.
845 inst->setExecuted();
846
847 // Not sure if I should set this here or just let commit try to
848 // commit any squashed instructions. I like the latter a bit more.
849 inst->setCanCommit();
850
851 // ++iewExecSquashedInsts;
852 exeList.pop();
853
854 continue;
855 }
856
857 Fault fault = NoFault;
858
859 // Execute instruction.
860 // Note that if the instruction faults, it will be handled
861 // at the commit stage.
862 if (inst->isMemRef() &&
863 (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
864 DPRINTF(BE, "Execute: Initiating access for memory "
865 "reference.\n");
866
867 if (inst->isLoad()) {
868 LSQ.executeLoad(inst);
869 } else if (inst->isStore()) {
870 Fault fault = LSQ.executeStore(inst);
871
872 if (!inst->isStoreConditional() && fault == NoFault) {
873 inst->setExecuted();
874
875 instToCommit(inst);
876 } else if (fault != NoFault) {
877 // If the instruction faulted, then we need to send it along to commit
878 // without the instruction completing.
879 // Send this instruction to commit, also make sure iew stage
880 // realizes there is activity.
881 inst->setExecuted();
882
883 instToCommit(inst);
884 }
885 } else {
886 panic("Unknown mem type!");
887 }
888 } else {
889 inst->execute();
890
891 inst->setExecuted();
892
893 instToCommit(inst);
894 }
895
896 updateExeInstStats(inst);
897
898 ++funcExeInst;
899 ++num_executed;
900
901 exeList.pop();
902
903 if (inst->mispredicted()) {
904 squashDueToBranch(inst);
905 break;
906 } else if (LSQ.violation()) {
907 // Get the DynInst that caused the violation. Note that this
908 // clears the violation signal.
909 DynInstPtr violator;
910 violator = LSQ.getMemDepViolator();
911
912 DPRINTF(BE, "LDSTQ detected a violation. Violator PC: "
913 "%#x, inst PC: %#x. Addr is: %#x.\n",
914 violator->readPC(), inst->readPC(), inst->physEffAddr);
915
916 // Squash.
917 squashDueToMemViolation(inst);
918 }
919 }
920
921 issuedOps[0]+= num_executed;
922 nIssuedDist[num_executed]++;
923 }
924
925 template<class Impl>
926 void
927 LWBackEnd<Impl>::instToCommit(DynInstPtr &inst)
928 {
929 DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n",
930 inst->seqNum, inst->readPC());
931
932 if (!inst->isSquashed()) {
933 if (inst->isExecuted()) {
934 inst->setResultReady();
935 int dependents = wakeDependents(inst);
936 if (dependents) {
937 producerInst[0]++;
938 consumerInst[0]+= dependents;
939 }
940 }
941 }
942
943 writeback.push_back(inst);
944
945 numInstsToWB[0]++;
946
947 writebackCount[0]++;
948 }
949
950 template <class Impl>
951 void
952 LWBackEnd<Impl>::readyInstsForCommit()
953 {
954 for (int i = numInstsToWB[-latency];
955 !writeback.empty() && i;
956 --i)
957 {
958 DynInstPtr inst = writeback.front();
959 writeback.pop_front();
960 if (!inst->isSquashed()) {
961 DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n",
962 inst->seqNum, inst->readPC());
963
964 inst->setCanCommit();
965 }
966 }
967 }
968
969 #if 0
970 template <class Impl>
971 void
972 LWBackEnd<Impl>::writebackInsts()
973 {
974 int wb_width = wbWidth;
975 // Using this method I'm not quite sure how to prevent an
976 // instruction from waking its own dependents multiple times,
977 // without the guarantee that commit always has enough bandwidth
978 // to accept all instructions being written back. This guarantee
979 // might not be too unrealistic.
980 InstListIt wb_inst_it = writeback.begin();
981 InstListIt wb_end_it = writeback.end();
982 int inst_num = 0;
983 int consumer_insts = 0;
984
985 for (; inst_num < wb_width &&
986 wb_inst_it != wb_end_it; inst_num++) {
987 DynInstPtr inst = (*wb_inst_it);
988
989 // Some instructions will be sent to commit without having
990 // executed because they need commit to handle them.
991 // E.g. Uncached loads have not actually executed when they
992 // are first sent to commit. Instead commit must tell the LSQ
993 // when it's ready to execute the uncached load.
994 if (!inst->isSquashed()) {
995 DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n",
996 inst->seqNum, inst->readPC());
997
998 inst->setCanCommit();
999 inst->setResultReady();
1000
1001 if (inst->isExecuted()) {
1002 int dependents = wakeDependents(inst);
1003 if (dependents) {
1004 producer_inst[0]++;
1005 consumer_insts+= dependents;
1006 }
1007 }
1008 }
1009
1010 writeback.erase(wb_inst_it++);
1011 }
1012 LSQ.writebackStores();
1013 consumer_inst[0]+= consumer_insts;
1014 writeback_count[0]+= inst_num;
1015 }
1016 #endif
1017 template <class Impl>
1018 bool
1019 LWBackEnd<Impl>::commitInst(int inst_num)
1020 {
1021 // Read instruction from the head of the ROB
1022 DynInstPtr inst = instList.back();
1023
1024 // Make sure instruction is valid
1025 assert(inst);
1026
1027 if (!inst->readyToCommit())
1028 return false;
1029
1030 DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n",
1031 inst->seqNum, inst->readPC());
1032
1033 thread->setPC(inst->readPC());
1034 thread->setNextPC(inst->readNextPC());
1035 inst->setAtCommit();
1036
1037 // If the instruction is not executed yet, then it is a non-speculative
1038 // or store inst. Signal backwards that it should be executed.
1039 if (!inst->isExecuted()) {
1040 if (inst->isNonSpeculative() ||
1041 (inst->isStoreConditional() && inst->getFault() == NoFault) ||
1042 inst->isMemBarrier() ||
1043 inst->isWriteBarrier()) {
1044 if ((inst->isMemBarrier() || inst->isWriteBarrier() ||
1045 inst->isQuiesce()) && LSQ.hasStoresToWB())
1046 {
1047 DPRINTF(BE, "Waiting for all stores to writeback.\n");
1048 return false;
1049 }
1050
1051 DPRINTF(BE, "Encountered a store or non-speculative "
1052 "instruction at the head of the ROB, PC %#x.\n",
1053 inst->readPC());
1054
1055 if (inst->isMemBarrier() || inst->isWriteBarrier()) {
1056 DPRINTF(BE, "Waking dependents on barrier [sn:%lli]\n",
1057 inst->seqNum);
1058 assert(memBarrier);
1059 wakeDependents(inst, true);
1060 if (memBarrier == inst)
1061 memBarrier = NULL;
1062 inst->clearMemDependents();
1063 }
1064
1065 // Send back the non-speculative instruction's sequence number.
1066 if (inst->iqItValid) {
1067 DPRINTF(BE, "Removing instruction from waiting list\n");
1068 waitingList.erase(inst->iqIt);
1069 inst->iqItValid = false;
1070 waitingInsts--;
1071 assert(waitingInsts >= 0);
1072 if (inst->isStore())
1073 removeWaitingMemOp(inst);
1074 }
1075
1076 exeList.push(inst);
1077
1078 // Change the instruction so it won't try to commit again until
1079 // it is executed.
1080 inst->clearCanCommit();
1081
1082 // ++commitNonSpecStalls;
1083
1084 return false;
1085 } else if (inst->isLoad()) {
1086 DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n",
1087 inst->seqNum, inst->readPC());
1088
1089 // Send back the non-speculative instruction's sequence
1090 // number. Maybe just tell the lsq to re-execute the load.
1091
1092 // Send back the non-speculative instruction's sequence number.
1093 if (inst->iqItValid) {
1094 DPRINTF(BE, "Removing instruction from waiting list\n");
1095 waitingList.erase(inst->iqIt);
1096 inst->iqItValid = false;
1097 waitingInsts--;
1098 assert(waitingInsts >= 0);
1099 removeWaitingMemOp(inst);
1100 }
1101 replayMemInst(inst);
1102
1103 inst->clearCanCommit();
1104
1105 return false;
1106 } else {
1107 panic("Trying to commit un-executed instruction "
1108 "of unknown type!\n");
1109 }
1110 }
1111
1112 // Not handled for now.
1113 assert(!inst->isThreadSync());
1114 assert(inst->memDepReady());
1115 // Stores will mark themselves as totally completed as they need
1116 // to wait to writeback to memory. @todo: Hack...attempt to fix
1117 // having the checker be forced to wait until a store completes in
1118 // order to check all of the instructions. If the store at the
1119 // head of the check list misses, but a later store hits, then
1120 // loads in the checker may see the younger store values instead
1121 // of the store they should see. Either the checker needs its own
1122 // memory (annoying to update), its own store buffer (how to tell
1123 // which value is correct?), or something else...
1124 if (!inst->isStore()) {
1125 inst->setCompleted();
1126 }
1127 // Check if the instruction caused a fault. If so, trap.
1128 Fault inst_fault = inst->getFault();
1129
1130 // Use checker prior to updating anything due to traps or PC
1131 // based events.
1132 if (checker) {
1133 checker->verify(inst);
1134 }
1135
1136 if (inst_fault != NoFault) {
1137 DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n",
1138 inst->seqNum, inst->readPC());
1139
1140 // Instruction is completed as it has a fault.
1141 inst->setCompleted();
1142
1143 if (LSQ.hasStoresToWB()) {
1144 DPRINTF(BE, "Stores still in flight, will wait until drained.\n");
1145 return false;
1146 } else if (inst_num != 0) {
1147 DPRINTF(BE, "Will wait until instruction is head of commit group.\n");
1148 return false;
1149 }
1150 else if (checker && inst->isStore()) {
1151 checker->verify(inst);
1152 }
1153
1154 handleFault(inst_fault);
1155 return false;
1156 }
1157
1158 int freed_regs = 0;
1159
1160 for (int i = 0; i < inst->numDestRegs(); ++i) {
1161 DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n",
1162 (int)inst->destRegIdx(i), inst->seqNum);
1163 thread->renameTable[inst->destRegIdx(i)] = inst;
1164 ++freed_regs;
1165 }
1166
1167 if (FullSystem && thread->profile) {
1168 thread->profilePC = inst->readPC();
1169 ProfileNode *node = thread->profile->consume(thread->getTC(),
1170 inst->staticInst);
1171
1172 if (node)
1173 thread->profileNode = node;
1174 }
1175
1176 if (inst->traceData) {
1177 inst->traceData->setFetchSeq(inst->seqNum);
1178 inst->traceData->setCPSeq(thread->numInst);
1179 inst->traceData->finalize();
1180 inst->traceData = NULL;
1181 }
1182
1183 inst->clearDependents();
1184
1185 frontEnd->addFreeRegs(freed_regs);
1186
1187 instList.pop_back();
1188
1189 --numInsts;
1190 ++thread->funcExeInst;
1191 // Maybe move this to where the fault is handled; if the fault is
1192 // handled, don't try to set this myself as the fault will set it.
1193 // If not, then I set thread->PC = thread->nextPC and
1194 // thread->nextPC = thread->nextPC + 4.
1195 thread->setPC(thread->readNextPC());
1196 thread->setNextPC(thread->readNextPC() + sizeof(TheISA::MachInst));
1197 updateComInstStats(inst);
1198
1199 // Write the done sequence number here.
1200 toIEW->doneSeqNum = inst->seqNum;
1201 lastCommitCycle = curTick();
1202
1203 if (FullSystem) {
1204 int count = 0;
1205 Addr oldpc;
1206 do {
1207 if (count == 0)
1208 assert(!thread->inSyscall && !thread->trapPending);
1209 oldpc = thread->readPC();
1210 cpu->system->pcEventQueue.service(
1211 thread->getTC());
1212 count++;
1213 } while (oldpc != thread->readPC());
1214 if (count > 1) {
1215 DPRINTF(BE, "PC skip function event, stopping commit\n");
1216 tcSquash = true;
1217 return false;
1218 }
1219 }
1220 return true;
1221 }
1222
1223 template <class Impl>
1224 void
1225 LWBackEnd<Impl>::commitInsts()
1226 {
1227 // Not sure this should be a loop or not.
1228 int inst_num = 0;
1229 while (!instList.empty() && inst_num < commitWidth) {
1230 if (instList.back()->isSquashed()) {
1231 instList.back()->clearDependents();
1232 ROBSquashedInsts[instList.back()->threadNumber]++;
1233 instList.pop_back();
1234 --numInsts;
1235 continue;
1236 }
1237
1238 if (!commitInst(inst_num++)) {
1239 DPRINTF(BE, "Can't commit, Instruction [sn:%lli] PC "
1240 "%#x is head of ROB and not ready\n",
1241 instList.back()->seqNum, instList.back()->readPC());
1242 --inst_num;
1243 break;
1244 }
1245 }
1246 nCommittedDist.sample(inst_num);
1247 }
1248
1249 template <class Impl>
1250 void
1251 LWBackEnd<Impl>::squash(const InstSeqNum &sn)
1252 {
1253 LSQ.squash(sn);
1254
1255 int freed_regs = 0;
1256 InstListIt insts_end_it = waitingList.end();
1257 InstListIt insts_it = waitingList.begin();
1258
1259 while (insts_it != insts_end_it && (*insts_it)->seqNum > sn)
1260 {
1261 if ((*insts_it)->isSquashed()) {
1262 ++insts_it;
1263 continue;
1264 }
1265 DPRINTF(BE, "Squashing instruction on waitingList PC %#x, [sn:%lli].\n",
1266 (*insts_it)->readPC(),
1267 (*insts_it)->seqNum);
1268
1269 if ((*insts_it)->isMemRef()) {
1270 DPRINTF(BE, "Squashing a waiting mem op [sn:%lli]\n",
1271 (*insts_it)->seqNum);
1272 removeWaitingMemOp((*insts_it));
1273 }
1274
1275 waitingList.erase(insts_it++);
1276 waitingInsts--;
1277 }
1278 assert(waitingInsts >= 0);
1279
1280 insts_it = instList.begin();
1281
1282 while (!instList.empty() && (*insts_it)->seqNum > sn)
1283 {
1284 if ((*insts_it)->isSquashed()) {
1285 panic("Instruction should not be already squashed and on list!");
1286 ++insts_it;
1287 continue;
1288 }
1289 DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n",
1290 (*insts_it)->readPC(),
1291 (*insts_it)->seqNum);
1292
1293 // Mark the instruction as squashed, and ready to commit so that
1294 // it can drain out of the pipeline.
1295 (*insts_it)->setSquashed();
1296
1297 (*insts_it)->setCanCommit();
1298
1299 (*insts_it)->clearInROB();
1300
1301 for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) {
1302 DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i);
1303 DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n",
1304 (int)(*insts_it)->destRegIdx(i), prev_dest->seqNum);
1305 renameTable[(*insts_it)->destRegIdx(i)] = prev_dest;
1306 ++freed_regs;
1307 }
1308
1309 (*insts_it)->clearDependents();
1310
1311 squashedInsts[(*insts_it)->threadNumber]++;
1312
1313 instList.erase(insts_it++);
1314 --numInsts;
1315 }
1316
1317 while (memBarrier && memBarrier->seqNum > sn) {
1318 DPRINTF(BE, "[sn:%lli] Memory barrier squashed (or previously "
1319 "squashed)\n", memBarrier->seqNum);
1320 memBarrier->clearMemDependents();
1321 if (memBarrier->memDepReady()) {
1322 DPRINTF(BE, "No previous barrier\n");
1323 memBarrier = NULL;
1324 } else {
1325 std::list<DynInstPtr> &srcs = memBarrier->getMemSrcs();
1326 memBarrier = srcs.front();
1327 srcs.pop_front();
1328 assert(srcs.empty());
1329 DPRINTF(BE, "Previous barrier: [sn:%lli]\n",
1330 memBarrier->seqNum);
1331 }
1332 }
1333
1334 insts_it = replayList.begin();
1335 insts_end_it = replayList.end();
1336 while (!replayList.empty() && insts_it != insts_end_it) {
1337 if ((*insts_it)->seqNum < sn) {
1338 ++insts_it;
1339 continue;
1340 }
1341 assert((*insts_it)->isSquashed());
1342
1343 replayList.erase(insts_it++);
1344 }
1345
1346 frontEnd->addFreeRegs(freed_regs);
1347 }
1348
1349 template <class Impl>
1350 void
1351 LWBackEnd<Impl>::squashFromTC()
1352 {
1353 InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1;
1354 squash(squashed_inst);
1355 frontEnd->squash(squashed_inst, thread->readPC(),
1356 false, false);
1357 frontEnd->interruptPending = false;
1358
1359 thread->trapPending = false;
1360 thread->inSyscall = false;
1361 tcSquash = false;
1362 commitStatus = Running;
1363 }
1364
1365 template <class Impl>
1366 void
1367 LWBackEnd<Impl>::squashFromTrap()
1368 {
1369 InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1;
1370 squash(squashed_inst);
1371 frontEnd->squash(squashed_inst, thread->readPC(),
1372 false, false);
1373 frontEnd->interruptPending = false;
1374
1375 thread->trapPending = false;
1376 thread->inSyscall = false;
1377 trapSquash = false;
1378 commitStatus = Running;
1379 }
1380
1381 template <class Impl>
1382 void
1383 LWBackEnd<Impl>::squashDueToBranch(DynInstPtr &inst)
1384 {
1385 // Update the branch predictor state I guess
1386 DPRINTF(BE, "Squashing due to branch [sn:%lli], will restart at PC %#x\n",
1387 inst->seqNum, inst->readNextPC());
1388 squash(inst->seqNum);
1389 frontEnd->squash(inst->seqNum, inst->readNextPC(),
1390 true, inst->mispredicted());
1391 }
1392
1393 template <class Impl>
1394 void
1395 LWBackEnd<Impl>::squashDueToMemViolation(DynInstPtr &inst)
1396 {
1397 // Update the branch predictor state I guess
1398 DPRINTF(BE, "Squashing due to violation [sn:%lli], will restart at PC %#x\n",
1399 inst->seqNum, inst->readNextPC());
1400 squash(inst->seqNum);
1401 frontEnd->squash(inst->seqNum, inst->readNextPC(),
1402 false, inst->mispredicted());
1403 }
1404
1405 template <class Impl>
1406 void
1407 LWBackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst)
1408 {
1409 DPRINTF(IEW, "Memory blocked, squashing load and younger insts, "
1410 "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum);
1411
1412 squash(inst->seqNum - 1);
1413 frontEnd->squash(inst->seqNum - 1, inst->readPC());
1414 }
1415
1416 template <class Impl>
1417 void
1418 LWBackEnd<Impl>::switchOut()
1419 {
1420 switchPending = true;
1421 }
1422
1423 template <class Impl>
1424 void
1425 LWBackEnd<Impl>::doSwitchOut()
1426 {
1427 switchedOut = true;
1428 switchPending = false;
1429 // Need to get rid of all committed, non-speculative state and write it
1430 // to memory/TC. In this case this is stores that have committed and not
1431 // yet written back.
1432 assert(robEmpty());
1433 assert(!LSQ.hasStoresToWB());
1434 writeback.clear();
1435 for (int i = 0; i < numInstsToWB.getSize() + 1; ++i)
1436 numInstsToWB.advance();
1437
1438 // squash(0);
1439 assert(waitingList.empty());
1440 assert(instList.empty());
1441 assert(replayList.empty());
1442 assert(writeback.empty());
1443 LSQ.switchOut();
1444 }
1445
1446 template <class Impl>
1447 void
1448 LWBackEnd<Impl>::takeOverFrom(ThreadContext *old_tc)
1449 {
1450 assert(!squashPending);
1451 squashSeqNum = 0;
1452 squashNextPC = 0;
1453 tcSquash = false;
1454 trapSquash = false;
1455
1456 numInsts = 0;
1457 numWaitingMemOps = 0;
1458 waitingMemOps.clear();
1459 waitingInsts = 0;
1460 switchedOut = false;
1461 dispatchStatus = Running;
1462 commitStatus = Running;
1463 LSQ.takeOverFrom(old_tc);
1464 }
1465
1466 template <class Impl>
1467 void
1468 LWBackEnd<Impl>::updateExeInstStats(DynInstPtr &inst)
1469 {
1470 ThreadID tid = inst->threadNumber;
1471
1472 exeInst[tid]++;
1473
1474 //
1475 // Control operations
1476 //
1477 if (inst->isControl())
1478 exeBranches[tid]++;
1479
1480 //
1481 // Memory operations
1482 //
1483 if (inst->isMemRef()) {
1484 exeRefs[tid]++;
1485
1486 if (inst->isLoad())
1487 exeLoads[tid]++;
1488 }
1489 }
1490
1491 template <class Impl>
1492 void
1493 LWBackEnd<Impl>::updateComInstStats(DynInstPtr &inst)
1494 {
1495 ThreadID tid = inst->threadNumber;
1496
1497 // keep an instruction count
1498 thread->numInst++;
1499 thread->numInsts++;
1500
1501 cpu->numInst++;
1502 //
1503 // Pick off the software prefetches
1504 //
1505 #ifdef TARGET_ALPHA
1506 if (inst->isDataPrefetch()) {
1507 statComSwp[tid]++;
1508 } else {
1509 statComInst[tid]++;
1510 }
1511 #else
1512 statComInst[tid]++;
1513 #endif
1514
1515 //
1516 // Control Instructions
1517 //
1518 if (inst->isControl())
1519 statComBranches[tid]++;
1520
1521 //
1522 // Memory references
1523 //
1524 if (inst->isMemRef()) {
1525 statComRefs[tid]++;
1526
1527 if (inst->isLoad()) {
1528 statComLoads[tid]++;
1529 }
1530 }
1531
1532 if (inst->isMemBarrier()) {
1533 statComMembars[tid]++;
1534 }
1535 }
1536
1537 template <class Impl>
1538 void
1539 LWBackEnd<Impl>::dumpInsts()
1540 {
1541 int num = 0;
1542 int valid_num = 0;
1543
1544 InstListIt inst_list_it = --(instList.end());
1545
1546 cprintf("ExeList size: %i\n", exeList.size());
1547
1548 cprintf("Inst list size: %i\n", instList.size());
1549
1550 while (inst_list_it != instList.end())
1551 {
1552 cprintf("Instruction:%i\n",
1553 num);
1554 if (!(*inst_list_it)->isSquashed()) {
1555 if (!(*inst_list_it)->isIssued()) {
1556 ++valid_num;
1557 cprintf("Count:%i\n", valid_num);
1558 } else if ((*inst_list_it)->isMemRef() &&
1559 !(*inst_list_it)->memOpDone) {
1560 // Loads that have not been marked as executed still count
1561 // towards the total instructions.
1562 ++valid_num;
1563 cprintf("Count:%i\n", valid_num);
1564 }
1565 }
1566
1567 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
1568 "Issued:%i\nSquashed:%i\n",
1569 (*inst_list_it)->readPC(),
1570 (*inst_list_it)->seqNum,
1571 (*inst_list_it)->threadNumber,
1572 (*inst_list_it)->isIssued(),
1573 (*inst_list_it)->isSquashed());
1574
1575 if ((*inst_list_it)->isMemRef()) {
1576 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
1577 }
1578
1579 cprintf("\n");
1580
1581 inst_list_it--;
1582 ++num;
1583 }
1584
1585 inst_list_it = --(writeback.end());
1586
1587 cprintf("Writeback list size: %i\n", writeback.size());
1588
1589 while (inst_list_it != writeback.end())
1590 {
1591 cprintf("Instruction:%i\n",
1592 num);
1593 if (!(*inst_list_it)->isSquashed()) {
1594 if (!(*inst_list_it)->isIssued()) {
1595 ++valid_num;
1596 cprintf("Count:%i\n", valid_num);
1597 } else if ((*inst_list_it)->isMemRef() &&
1598 !(*inst_list_it)->memOpDone) {
1599 // Loads that have not been marked as executed still count
1600 // towards the total instructions.
1601 ++valid_num;
1602 cprintf("Count:%i\n", valid_num);
1603 }
1604 }
1605
1606 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
1607 "Issued:%i\nSquashed:%i\n",
1608 (*inst_list_it)->readPC(),
1609 (*inst_list_it)->seqNum,
1610 (*inst_list_it)->threadNumber,
1611 (*inst_list_it)->isIssued(),
1612 (*inst_list_it)->isSquashed());
1613
1614 if ((*inst_list_it)->isMemRef()) {
1615 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
1616 }
1617
1618 cprintf("\n");
1619
1620 inst_list_it--;
1621 ++num;
1622 }
1623
1624 cprintf("Waiting list size: %i\n", waitingList.size());
1625
1626 inst_list_it = --(waitingList.end());
1627
1628 while (inst_list_it != waitingList.end())
1629 {
1630 cprintf("Instruction:%i\n",
1631 num);
1632 if (!(*inst_list_it)->isSquashed()) {
1633 if (!(*inst_list_it)->isIssued()) {
1634 ++valid_num;
1635 cprintf("Count:%i\n", valid_num);
1636 } else if ((*inst_list_it)->isMemRef() &&
1637 !(*inst_list_it)->memOpDone) {
1638 // Loads that have not been marked as executed still count
1639 // towards the total instructions.
1640 ++valid_num;
1641 cprintf("Count:%i\n", valid_num);
1642 }
1643 }
1644
1645 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
1646 "Issued:%i\nSquashed:%i\n",
1647 (*inst_list_it)->readPC(),
1648 (*inst_list_it)->seqNum,
1649 (*inst_list_it)->threadNumber,
1650 (*inst_list_it)->isIssued(),
1651 (*inst_list_it)->isSquashed());
1652
1653 if ((*inst_list_it)->isMemRef()) {
1654 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
1655 }
1656
1657 cprintf("\n");
1658
1659 inst_list_it--;
1660 ++num;
1661 }
1662
1663 cprintf("waitingMemOps list size: %i\n", waitingMemOps.size());
1664
1665 MemIt waiting_it = waitingMemOps.begin();
1666
1667 while (waiting_it != waitingMemOps.end())
1668 {
1669 cprintf("[sn:%lli] ", (*waiting_it));
1670 waiting_it++;
1671 ++num;
1672 }
1673 cprintf("\n");
1674 }