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