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