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