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