Changed makeExtMI to take a ThreadContext instead of a pc.
[gem5.git] / src / cpu / ozone / front_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 "arch/faults.hh"
34 #include "arch/isa_traits.hh"
35 #include "arch/utility.hh"
36 #include "base/statistics.hh"
37 #include "cpu/thread_context.hh"
38 #include "cpu/exetrace.hh"
39 #include "cpu/ozone/front_end.hh"
40 #include "mem/mem_object.hh"
41 #include "mem/packet.hh"
42 #include "mem/request.hh"
43
44 #if USE_CHECKER
45 #include "cpu/checker/cpu.hh"
46 #endif
47
48 using namespace TheISA;
49
50 template<class Impl>
51 Tick
52 FrontEnd<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
53 {
54 panic("FrontEnd doesn't expect recvAtomic callback!");
55 return curTick;
56 }
57
58 template<class Impl>
59 void
60 FrontEnd<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
61 {
62 panic("FrontEnd doesn't expect recvFunctional callback!");
63 }
64
65 template<class Impl>
66 void
67 FrontEnd<Impl>::IcachePort::recvStatusChange(Status status)
68 {
69 if (status == RangeChange)
70 return;
71
72 panic("FrontEnd doesn't expect recvStatusChange callback!");
73 }
74
75 template<class Impl>
76 bool
77 FrontEnd<Impl>::IcachePort::recvTiming(Packet *pkt)
78 {
79 fe->processCacheCompletion(pkt);
80 return true;
81 }
82
83 template<class Impl>
84 void
85 FrontEnd<Impl>::IcachePort::recvRetry()
86 {
87 fe->recvRetry();
88 }
89
90 template <class Impl>
91 FrontEnd<Impl>::FrontEnd(Params *params)
92 : branchPred(params),
93 icachePort(this),
94 mem(params->mem),
95 instBufferSize(0),
96 maxInstBufferSize(params->maxInstBufferSize),
97 width(params->frontEndWidth),
98 freeRegs(params->numPhysicalRegs),
99 numPhysRegs(params->numPhysicalRegs),
100 serializeNext(false),
101 interruptPending(false)
102 {
103 switchedOut = false;
104
105 status = Idle;
106
107 memReq = NULL;
108 // Size of cache block.
109 cacheBlkSize = 64;
110
111 assert(isPowerOf2(cacheBlkSize));
112
113 // Create mask to get rid of offset bits.
114 cacheBlkMask = (cacheBlkSize - 1);
115
116 // Create space to store a cache line.
117 cacheData = new uint8_t[cacheBlkSize];
118
119 fetchCacheLineNextCycle = true;
120
121 cacheBlkValid = cacheBlocked = false;
122
123 retryPkt = NULL;
124
125 fetchFault = NoFault;
126 }
127
128 template <class Impl>
129 std::string
130 FrontEnd<Impl>::name() const
131 {
132 return cpu->name() + ".frontend";
133 }
134
135 template <class Impl>
136 void
137 FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
138 {
139 cpu = cpu_ptr;
140
141 icachePort.setName(this->name() + "-iport");
142
143 #if USE_CHECKER
144 if (cpu->checker) {
145 cpu->checker->setIcachePort(&icachePort);
146 }
147 #endif
148 }
149
150 template <class Impl>
151 void
152 FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
153 {
154 comm = _comm;
155 // @todo: Hardcoded for now. Allow this to be set by a latency.
156 fromCommit = comm->getWire(-1);
157 }
158
159 template <class Impl>
160 void
161 FrontEnd<Impl>::setTC(ThreadContext *tc_ptr)
162 {
163 tc = tc_ptr;
164 }
165
166 template <class Impl>
167 void
168 FrontEnd<Impl>::regStats()
169 {
170 icacheStallCycles
171 .name(name() + ".icacheStallCycles")
172 .desc("Number of cycles fetch is stalled on an Icache miss")
173 .prereq(icacheStallCycles);
174
175 fetchedInsts
176 .name(name() + ".fetchedInsts")
177 .desc("Number of instructions fetch has processed")
178 .prereq(fetchedInsts);
179
180 fetchedBranches
181 .name(name() + ".fetchedBranches")
182 .desc("Number of fetched branches")
183 .prereq(fetchedBranches);
184
185 predictedBranches
186 .name(name() + ".predictedBranches")
187 .desc("Number of branches that fetch has predicted taken")
188 .prereq(predictedBranches);
189
190 fetchCycles
191 .name(name() + ".fetchCycles")
192 .desc("Number of cycles fetch has run and was not squashing or"
193 " blocked")
194 .prereq(fetchCycles);
195
196 fetchIdleCycles
197 .name(name() + ".fetchIdleCycles")
198 .desc("Number of cycles fetch was idle")
199 .prereq(fetchIdleCycles);
200
201 fetchSquashCycles
202 .name(name() + ".fetchSquashCycles")
203 .desc("Number of cycles fetch has spent squashing")
204 .prereq(fetchSquashCycles);
205
206 fetchBlockedCycles
207 .name(name() + ".fetchBlockedCycles")
208 .desc("Number of cycles fetch has spent blocked")
209 .prereq(fetchBlockedCycles);
210
211 fetchedCacheLines
212 .name(name() + ".fetchedCacheLines")
213 .desc("Number of cache lines fetched")
214 .prereq(fetchedCacheLines);
215
216 fetchIcacheSquashes
217 .name(name() + ".fetchIcacheSquashes")
218 .desc("Number of outstanding Icache misses that were squashed")
219 .prereq(fetchIcacheSquashes);
220
221 fetchNisnDist
222 .init(/* base value */ 0,
223 /* last value */ width,
224 /* bucket size */ 1)
225 .name(name() + ".rateDist")
226 .desc("Number of instructions fetched each cycle (Total)")
227 .flags(Stats::pdf);
228
229 idleRate
230 .name(name() + ".idleRate")
231 .desc("Percent of cycles fetch was idle")
232 .prereq(idleRate);
233 idleRate = fetchIdleCycles * 100 / cpu->numCycles;
234
235 branchRate
236 .name(name() + ".branchRate")
237 .desc("Number of branch fetches per cycle")
238 .flags(Stats::total);
239 branchRate = fetchedBranches / cpu->numCycles;
240
241 fetchRate
242 .name(name() + ".rate")
243 .desc("Number of inst fetches per cycle")
244 .flags(Stats::total);
245 fetchRate = fetchedInsts / cpu->numCycles;
246
247 IFQCount
248 .name(name() + ".IFQ:count")
249 .desc("cumulative IFQ occupancy")
250 ;
251
252 IFQFcount
253 .name(name() + ".IFQ:fullCount")
254 .desc("cumulative IFQ full count")
255 .flags(Stats::total)
256 ;
257
258 IFQOccupancy
259 .name(name() + ".IFQ:occupancy")
260 .desc("avg IFQ occupancy (inst's)")
261 ;
262 IFQOccupancy = IFQCount / cpu->numCycles;
263
264 IFQLatency
265 .name(name() + ".IFQ:latency")
266 .desc("avg IFQ occupant latency (cycle's)")
267 .flags(Stats::total)
268 ;
269
270 IFQFullRate
271 .name(name() + ".IFQ:fullRate")
272 .desc("fraction of time (cycles) IFQ was full")
273 .flags(Stats::total);
274 ;
275 IFQFullRate = IFQFcount * Stats::constant(100) / cpu->numCycles;
276
277 dispatchCountStat
278 .name(name() + ".DIS:count")
279 .desc("cumulative count of dispatched insts")
280 .flags(Stats::total)
281 ;
282
283 dispatchedSerializing
284 .name(name() + ".DIS:serializingInsts")
285 .desc("count of serializing insts dispatched")
286 .flags(Stats::total)
287 ;
288
289 dispatchedTempSerializing
290 .name(name() + ".DIS:tempSerializingInsts")
291 .desc("count of temporary serializing insts dispatched")
292 .flags(Stats::total)
293 ;
294
295 dispatchSerializeStallCycles
296 .name(name() + ".DIS:serializeStallCycles")
297 .desc("count of cycles dispatch stalled for serializing inst")
298 .flags(Stats::total)
299 ;
300
301 dispatchRate
302 .name(name() + ".DIS:rate")
303 .desc("dispatched insts per cycle")
304 .flags(Stats::total)
305 ;
306 dispatchRate = dispatchCountStat / cpu->numCycles;
307
308 regIntFull
309 .name(name() + ".REG:int:full")
310 .desc("number of cycles where there were no INT registers")
311 ;
312
313 regFpFull
314 .name(name() + ".REG:fp:full")
315 .desc("number of cycles where there were no FP registers")
316 ;
317 IFQLatency = IFQOccupancy / dispatchRate;
318
319 branchPred.regStats();
320 }
321
322 template <class Impl>
323 void
324 FrontEnd<Impl>::tick()
325 {
326 if (switchedOut)
327 return;
328
329 // @todo: Maybe I want to just have direct communication...
330 if (fromCommit->doneSeqNum) {
331 branchPred.update(fromCommit->doneSeqNum, 0);
332 }
333
334 IFQCount += instBufferSize;
335 IFQFcount += instBufferSize == maxInstBufferSize;
336
337 // Fetch cache line
338 if (status == IcacheAccessComplete) {
339 cacheBlkValid = true;
340
341 status = Running;
342 if (barrierInst)
343 status = SerializeBlocked;
344 if (freeRegs <= 0)
345 status = RenameBlocked;
346 checkBE();
347 } else if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
348 DPRINTF(FE, "Still in Icache wait.\n");
349 icacheStallCycles++;
350 return;
351 }
352
353 if (status == RenameBlocked || status == SerializeBlocked ||
354 status == TrapPending || status == BEBlocked) {
355 // Will cause a one cycle bubble between changing state and
356 // restarting.
357 DPRINTF(FE, "In blocked status.\n");
358
359 fetchBlockedCycles++;
360
361 if (status == SerializeBlocked) {
362 dispatchSerializeStallCycles++;
363 }
364 updateStatus();
365 return;
366 } else if (status == QuiescePending) {
367 DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n");
368 return;
369 } else if (status != IcacheAccessComplete) {
370 if (fetchCacheLineNextCycle) {
371 Fault fault = fetchCacheLine();
372 if (fault != NoFault) {
373 handleFault(fault);
374 fetchFault = fault;
375 return;
376 }
377 fetchCacheLineNextCycle = false;
378 }
379 // If miss, stall until it returns.
380 if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
381 // Tell CPU to not tick me for now.
382 return;
383 }
384 }
385
386 fetchCycles++;
387
388 int num_inst = 0;
389
390 // Otherwise loop and process instructions.
391 // One way to hack infinite width is to set width and maxInstBufferSize
392 // both really high. Inelegant, but probably will work.
393 while (num_inst < width &&
394 instBufferSize < maxInstBufferSize) {
395 // Get instruction from cache line.
396 DynInstPtr inst = getInstFromCacheline();
397
398 if (!inst) {
399 // PC is no longer in the cache line, end fetch.
400 // Might want to check this at the end of the cycle so that
401 // there's no cycle lost to checking for a new cache line.
402 DPRINTF(FE, "Need to get new cache line\n");
403 fetchCacheLineNextCycle = true;
404 break;
405 }
406
407 processInst(inst);
408
409 if (status == SerializeBlocked) {
410 break;
411 }
412
413 // Possibly push into a time buffer that estimates the front end
414 // latency
415 instBuffer.push_back(inst);
416 ++instBufferSize;
417 ++num_inst;
418
419 #if FULL_SYSTEM
420 if (inst->isQuiesce()) {
421 warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
422 status = QuiescePending;
423 break;
424 }
425 #endif
426
427 if (inst->predTaken()) {
428 // Start over with tick?
429 break;
430 } else if (freeRegs <= 0) {
431 DPRINTF(FE, "Ran out of free registers to rename to!\n");
432 status = RenameBlocked;
433 break;
434 } else if (serializeNext) {
435 break;
436 }
437 }
438
439 fetchNisnDist.sample(num_inst);
440 checkBE();
441
442 DPRINTF(FE, "Num insts processed: %i, Inst Buffer size: %i, Free "
443 "Regs %i\n", num_inst, instBufferSize, freeRegs);
444 }
445
446 template <class Impl>
447 Fault
448 FrontEnd<Impl>::fetchCacheLine()
449 {
450 // Read a cache line, based on the current PC.
451 #if FULL_SYSTEM
452 // Flag to say whether or not address is physical addr.
453 unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0;
454 #else
455 unsigned flags = 0;
456 #endif // FULL_SYSTEM
457 Fault fault = NoFault;
458
459 if (interruptPending && flags == 0) {
460 return fault;
461 }
462
463 // Align the fetch PC so it's at the start of a cache block.
464 Addr fetch_PC = icacheBlockAlignPC(PC);
465
466 DPRINTF(FE, "Fetching cache line starting at %#x.\n", fetch_PC);
467
468 // Setup the memReq to do a read of the first isntruction's address.
469 // Set the appropriate read size and flags as well.
470 memReq = new Request(0, fetch_PC, cacheBlkSize, flags,
471 fetch_PC, cpu->readCpuId(), 0);
472
473 // Translate the instruction request.
474 fault = cpu->translateInstReq(memReq, thread);
475
476 // Now do the timing access to see whether or not the instruction
477 // exists within the cache.
478 if (fault == NoFault) {
479 #if 0
480 if (cpu->system->memctrl->badaddr(memReq->paddr) ||
481 memReq->flags & UNCACHEABLE) {
482 DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a "
483 "misspeculating path!",
484 memReq->paddr);
485 return TheISA::genMachineCheckFault();
486 }
487 #endif
488
489 // Build packet here.
490 PacketPtr data_pkt = new Packet(memReq,
491 Packet::ReadReq, Packet::Broadcast);
492 data_pkt->dataStatic(cacheData);
493
494 if (!icachePort.sendTiming(data_pkt)) {
495 assert(retryPkt == NULL);
496 DPRINTF(Fetch, "Out of MSHRs!\n");
497 status = IcacheWaitRetry;
498 retryPkt = data_pkt;
499 cacheBlocked = true;
500 return NoFault;
501 }
502
503 status = IcacheWaitResponse;
504 }
505
506 // Note that this will set the cache block PC a bit earlier than it should
507 // be set.
508 cacheBlkPC = fetch_PC;
509
510 ++fetchedCacheLines;
511
512 DPRINTF(FE, "Done fetching cache line.\n");
513
514 return fault;
515 }
516
517 template <class Impl>
518 void
519 FrontEnd<Impl>::processInst(DynInstPtr &inst)
520 {
521 if (processBarriers(inst)) {
522 return;
523 }
524
525 Addr inst_PC = inst->readPC();
526
527 if (!inst->isControl()) {
528 inst->setPredTarg(inst->readNextPC());
529 } else {
530 fetchedBranches++;
531 if (branchPred.predict(inst, inst_PC, inst->threadNumber)) {
532 predictedBranches++;
533 }
534 }
535
536 Addr next_PC = inst->readPredTarg();
537
538 DPRINTF(FE, "[sn:%lli] Predicted and processed inst PC %#x, next PC "
539 "%#x\n", inst->seqNum, inst_PC, next_PC);
540
541 // inst->setNextPC(next_PC);
542
543 // Not sure where I should set this
544 PC = next_PC;
545
546 renameInst(inst);
547 }
548
549 template <class Impl>
550 bool
551 FrontEnd<Impl>::processBarriers(DynInstPtr &inst)
552 {
553 if (serializeNext) {
554 inst->setSerializeBefore();
555 serializeNext = false;
556 } else if (!inst->isSerializing() &&
557 !inst->isIprAccess() &&
558 !inst->isStoreConditional()) {
559 return false;
560 }
561
562 if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
563 !inst->isSerializeHandled()) {
564 DPRINTF(FE, "Serialize before instruction encountered.\n");
565
566 if (!inst->isTempSerializeBefore()) {
567 dispatchedSerializing++;
568 inst->setSerializeHandled();
569 } else {
570 dispatchedTempSerializing++;
571 }
572
573 // Change status over to SerializeBlocked so that other stages know
574 // what this is blocked on.
575 status = SerializeBlocked;
576
577 barrierInst = inst;
578 return true;
579 } else if ((inst->isStoreConditional() || inst->isSerializeAfter())
580 && !inst->isSerializeHandled()) {
581 DPRINTF(FE, "Serialize after instruction encountered.\n");
582
583 inst->setSerializeHandled();
584
585 dispatchedSerializing++;
586
587 serializeNext = true;
588 return false;
589 }
590 return false;
591 }
592
593 template <class Impl>
594 void
595 FrontEnd<Impl>::handleFault(Fault &fault)
596 {
597 DPRINTF(FE, "Fault at fetch, telling commit\n");
598
599 // We're blocked on the back end until it handles this fault.
600 status = TrapPending;
601
602 // Get a sequence number.
603 InstSeqNum inst_seq = getAndIncrementInstSeq();
604 // We will use a nop in order to carry the fault.
605 ExtMachInst ext_inst = TheISA::NoopMachInst;
606
607 // Create a new DynInst from the dummy nop.
608 DynInstPtr instruction = new DynInst(ext_inst, PC,
609 PC+sizeof(MachInst),
610 inst_seq, cpu);
611 instruction->setPredTarg(instruction->readNextPC());
612 // instruction->setThread(tid);
613
614 // instruction->setASID(tid);
615
616 instruction->setThreadState(thread);
617
618 instruction->traceData = NULL;
619
620 instruction->fault = fault;
621 instruction->setCanIssue();
622 instBuffer.push_back(instruction);
623 ++instBufferSize;
624 }
625
626 template <class Impl>
627 void
628 FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
629 const bool is_branch, const bool branch_taken)
630 {
631 DPRINTF(FE, "Squashing from [sn:%lli], setting PC to %#x\n",
632 squash_num, next_PC);
633
634 if (fetchFault != NoFault)
635 fetchFault = NoFault;
636
637 while (!instBuffer.empty() &&
638 instBuffer.back()->seqNum > squash_num) {
639 DynInstPtr inst = instBuffer.back();
640
641 DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n",
642 inst->seqNum, inst->readPC());
643
644 inst->clearDependents();
645
646 instBuffer.pop_back();
647 --instBufferSize;
648
649 freeRegs+= inst->numDestRegs();
650 }
651
652 // Copy over rename table from the back end.
653 renameTable.copyFrom(backEnd->renameTable);
654
655 PC = next_PC;
656
657 // Update BP with proper information.
658 if (is_branch) {
659 branchPred.squash(squash_num, next_PC, branch_taken, 0);
660 } else {
661 branchPred.squash(squash_num, 0);
662 }
663
664 // Clear the icache miss if it's outstanding.
665 if (status == IcacheWaitResponse) {
666 DPRINTF(FE, "Squashing outstanding Icache access.\n");
667 memReq = NULL;
668 }
669
670 if (status == SerializeBlocked) {
671 assert(barrierInst->seqNum > squash_num);
672 barrierInst = NULL;
673 }
674
675 // Unless this squash originated from the front end, we're probably
676 // in running mode now.
677 // Actually might want to make this latency dependent.
678 status = Running;
679 fetchCacheLineNextCycle = true;
680 }
681
682 template <class Impl>
683 typename Impl::DynInstPtr
684 FrontEnd<Impl>::getInst()
685 {
686 if (instBufferSize == 0) {
687 return NULL;
688 }
689
690 DynInstPtr inst = instBuffer.front();
691
692 instBuffer.pop_front();
693
694 --instBufferSize;
695
696 dispatchCountStat++;
697
698 return inst;
699 }
700
701 template <class Impl>
702 void
703 FrontEnd<Impl>::processCacheCompletion(PacketPtr pkt)
704 {
705 DPRINTF(FE, "Processing cache completion\n");
706
707 // Do something here.
708 if (status != IcacheWaitResponse ||
709 pkt->req != memReq ||
710 switchedOut) {
711 DPRINTF(FE, "Previous fetch was squashed.\n");
712 fetchIcacheSquashes++;
713 delete pkt->req;
714 delete pkt;
715 return;
716 }
717
718 status = IcacheAccessComplete;
719
720 /* if (checkStall(tid)) {
721 fetchStatus[tid] = Blocked;
722 } else {
723 fetchStatus[tid] = IcacheMissComplete;
724 }
725 */
726 // memcpy(cacheData, memReq->data, memReq->size);
727
728 // Reset the completion event to NULL.
729 // memReq->completionEvent = NULL;
730 delete pkt->req;
731 delete pkt;
732 memReq = NULL;
733 }
734
735 template <class Impl>
736 void
737 FrontEnd<Impl>::addFreeRegs(int num_freed)
738 {
739 if (status == RenameBlocked && freeRegs + num_freed > 0) {
740 status = Running;
741 }
742
743 DPRINTF(FE, "Adding %i freed registers\n", num_freed);
744
745 freeRegs+= num_freed;
746
747 // assert(freeRegs <= numPhysRegs);
748 if (freeRegs > numPhysRegs)
749 freeRegs = numPhysRegs;
750 }
751
752 template <class Impl>
753 void
754 FrontEnd<Impl>::recvRetry()
755 {
756 assert(cacheBlocked);
757 if (retryPkt != NULL) {
758 assert(status == IcacheWaitRetry);
759
760 if (icachePort.sendTiming(retryPkt)) {
761 status = IcacheWaitResponse;
762 retryPkt = NULL;
763 cacheBlocked = false;
764 }
765 } else {
766 // Access has been squashed since it was sent out. Just clear
767 // the cache being blocked.
768 cacheBlocked = false;
769 }
770
771 }
772
773 template <class Impl>
774 bool
775 FrontEnd<Impl>::updateStatus()
776 {
777 bool serialize_block = !backEnd->robEmpty() || instBufferSize;
778 bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
779 bool ret_val = false;
780
781 if (status == SerializeBlocked && !serialize_block) {
782 status = SerializeComplete;
783 ret_val = true;
784 }
785
786 if (status == BEBlocked && !be_block) {
787 if (barrierInst) {
788 status = SerializeBlocked;
789 } else {
790 status = Running;
791 }
792 ret_val = true;
793 }
794 return ret_val;
795 }
796
797 template <class Impl>
798 void
799 FrontEnd<Impl>::checkBE()
800 {
801 bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
802 if (be_block) {
803 if (status == Running || status == Idle) {
804 status = BEBlocked;
805 }
806 }
807 }
808
809 template <class Impl>
810 typename Impl::DynInstPtr
811 FrontEnd<Impl>::getInstFromCacheline()
812 {
813 if (status == SerializeComplete) {
814 DynInstPtr inst = barrierInst;
815 status = Running;
816 barrierInst = NULL;
817 inst->clearSerializeBefore();
818 return inst;
819 }
820
821 InstSeqNum inst_seq;
822 MachInst inst;
823 // @todo: Fix this magic number used here to handle word offset (and
824 // getting rid of PAL bit)
825 unsigned offset = (PC & cacheBlkMask) & ~3;
826
827 // PC of inst is not in this cache block
828 if (PC >= (cacheBlkPC + cacheBlkSize) || PC < cacheBlkPC || !cacheBlkValid) {
829 return NULL;
830 }
831
832 //////////////////////////
833 // Fetch one instruction
834 //////////////////////////
835
836 // Get a sequence number.
837 inst_seq = getAndIncrementInstSeq();
838
839 // Make sure this is a valid index.
840 assert(offset <= cacheBlkSize - sizeof(MachInst));
841
842 // Get the instruction from the array of the cache line.
843 inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset]));
844
845 ExtMachInst decode_inst = TheISA::makeExtMI(inst, tc);
846
847 // Create a new DynInst from the instruction fetched.
848 DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst),
849 inst_seq, cpu);
850
851 instruction->setThreadState(thread);
852
853 DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n",
854 inst_seq, instruction->readPC(),
855 instruction->staticInst->disassemble(PC));
856
857 instruction->traceData =
858 Trace::getInstRecord(curTick, tc,
859 instruction->staticInst,
860 instruction->readPC());
861
862 // Increment stat of fetched instructions.
863 ++fetchedInsts;
864
865 return instruction;
866 }
867
868 template <class Impl>
869 void
870 FrontEnd<Impl>::renameInst(DynInstPtr &inst)
871 {
872 DynInstPtr src_inst = NULL;
873 int num_src_regs = inst->numSrcRegs();
874 if (num_src_regs == 0) {
875 inst->setCanIssue();
876 } else {
877 for (int i = 0; i < num_src_regs; ++i) {
878 src_inst = renameTable[inst->srcRegIdx(i)];
879
880 inst->setSrcInst(src_inst, i);
881
882 DPRINTF(FE, "[sn:%lli]: Src reg %i is inst [sn:%lli]\n",
883 inst->seqNum, (int)inst->srcRegIdx(i), src_inst->seqNum);
884
885 if (src_inst->isResultReady()) {
886 DPRINTF(FE, "Reg ready.\n");
887 inst->markSrcRegReady(i);
888 } else {
889 DPRINTF(FE, "Adding to dependent list.\n");
890 src_inst->addDependent(inst);
891 }
892 }
893 }
894
895 for (int i = 0; i < inst->numDestRegs(); ++i) {
896 RegIndex idx = inst->destRegIdx(i);
897
898 DPRINTF(FE, "Dest reg %i is now inst [sn:%lli], was previously "
899 "[sn:%lli]\n",
900 (int)inst->destRegIdx(i), inst->seqNum,
901 renameTable[idx]->seqNum);
902
903 inst->setPrevDestInst(renameTable[idx], i);
904
905 renameTable[idx] = inst;
906 --freeRegs;
907 }
908 }
909
910 template <class Impl>
911 void
912 FrontEnd<Impl>::wakeFromQuiesce()
913 {
914 DPRINTF(FE, "Waking up from quiesce\n");
915 // Hopefully this is safe
916 status = Running;
917 }
918
919 template <class Impl>
920 void
921 FrontEnd<Impl>::switchOut()
922 {
923 switchedOut = true;
924 cpu->signalSwitched();
925 }
926
927 template <class Impl>
928 void
929 FrontEnd<Impl>::doSwitchOut()
930 {
931 memReq = NULL;
932 squash(0, 0);
933 instBuffer.clear();
934 instBufferSize = 0;
935 status = Idle;
936 }
937
938 template <class Impl>
939 void
940 FrontEnd<Impl>::takeOverFrom(ThreadContext *old_tc)
941 {
942 assert(freeRegs == numPhysRegs);
943 fetchCacheLineNextCycle = true;
944
945 cacheBlkValid = false;
946
947 #if !FULL_SYSTEM
948 // pTable = params->pTable;
949 #endif
950 fetchFault = NoFault;
951 serializeNext = false;
952 barrierInst = NULL;
953 status = Running;
954 switchedOut = false;
955 interruptPending = false;
956 }
957
958 template <class Impl>
959 void
960 FrontEnd<Impl>::dumpInsts()
961 {
962 cprintf("instBuffer size: %i\n", instBuffer.size());
963
964 InstBuffIt buff_it = instBuffer.begin();
965
966 for (int num = 0; buff_it != instBuffer.end(); num++) {
967 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
968 "Squashed:%i\n\n",
969 num, (*buff_it)->readPC(), (*buff_it)->threadNumber,
970 (*buff_it)->seqNum, (*buff_it)->isIssued(),
971 (*buff_it)->isSquashed());
972 buff_it++;
973 }
974 }