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