Replace tests of LOCKED/UNCACHEABLE flags with isLocked()/isUncacheable().
[gem5.git] / src / cpu / ozone / front_end_impl.hh
1 /*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Kevin Lim
29 */
30
31 #include "config/use_checker.hh"
32
33 #include "arch/faults.hh"
34 #include "arch/isa_traits.hh"
35 #include "arch/utility.hh"
36 #include "base/statistics.hh"
37 #include "cpu/thread_context.hh"
38 #include "cpu/exetrace.hh"
39 #include "cpu/ozone/front_end.hh"
40 #include "mem/mem_object.hh"
41 #include "mem/packet.hh"
42 #include "mem/request.hh"
43
44 #if USE_CHECKER
45 #include "cpu/checker/cpu.hh"
46 #endif
47
48 using namespace TheISA;
49
50 template<class Impl>
51 Tick
52 FrontEnd<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
53 {
54 panic("FrontEnd doesn't expect recvAtomic callback!");
55 return curTick;
56 }
57
58 template<class Impl>
59 void
60 FrontEnd<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
61 {
62 panic("FrontEnd doesn't expect recvFunctional callback!");
63 }
64
65 template<class Impl>
66 void
67 FrontEnd<Impl>::IcachePort::recvStatusChange(Status status)
68 {
69 if (status == RangeChange)
70 return;
71
72 panic("FrontEnd doesn't expect recvStatusChange callback!");
73 }
74
75 template<class Impl>
76 bool
77 FrontEnd<Impl>::IcachePort::recvTiming(Packet *pkt)
78 {
79 fe->processCacheCompletion(pkt);
80 return true;
81 }
82
83 template<class Impl>
84 void
85 FrontEnd<Impl>::IcachePort::recvRetry()
86 {
87 fe->recvRetry();
88 }
89
90 template <class Impl>
91 FrontEnd<Impl>::FrontEnd(Params *params)
92 : branchPred(params),
93 icachePort(this),
94 mem(params->mem),
95 numInstsReady(params->frontEndLatency, 0),
96 instBufferSize(0),
97 maxInstBufferSize(params->maxInstBufferSize),
98 latency(params->frontEndLatency),
99 width(params->frontEndWidth),
100 freeRegs(params->numPhysicalRegs),
101 numPhysRegs(params->numPhysicalRegs),
102 serializeNext(false),
103 interruptPending(false)
104 {
105 switchedOut = false;
106
107 status = Idle;
108
109 memReq = NULL;
110 // Size of cache block.
111 cacheBlkSize = 64;
112
113 assert(isPowerOf2(cacheBlkSize));
114
115 // Create mask to get rid of offset bits.
116 cacheBlkMask = (cacheBlkSize - 1);
117
118 // Create space to store a cache line.
119 cacheData = new uint8_t[cacheBlkSize];
120
121 fetchCacheLineNextCycle = true;
122
123 cacheBlkValid = cacheBlocked = false;
124
125 retryPkt = NULL;
126
127 fetchFault = NoFault;
128 }
129
130 template <class Impl>
131 std::string
132 FrontEnd<Impl>::name() const
133 {
134 return cpu->name() + ".frontend";
135 }
136
137 template <class Impl>
138 void
139 FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
140 {
141 cpu = cpu_ptr;
142
143 icachePort.setName(this->name() + "-iport");
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 for (int insts_to_queue = numInstsReady[-latency];
332 !instBuffer.empty() && insts_to_queue;
333 --insts_to_queue)
334 {
335 DPRINTF(FE, "Transferring instruction [sn:%lli] to the feBuffer\n",
336 instBuffer.front()->seqNum);
337 feBuffer.push_back(instBuffer.front());
338 instBuffer.pop_front();
339 }
340
341 numInstsReady.advance();
342
343 // @todo: Maybe I want to just have direct communication...
344 if (fromCommit->doneSeqNum) {
345 branchPred.update(fromCommit->doneSeqNum, 0);
346 }
347
348 IFQCount += instBufferSize;
349 IFQFcount += instBufferSize == maxInstBufferSize;
350
351 // Fetch cache line
352 if (status == IcacheAccessComplete) {
353 cacheBlkValid = true;
354
355 status = Running;
356 // if (barrierInst)
357 // status = SerializeBlocked;
358 if (freeRegs <= 0)
359 status = RenameBlocked;
360 checkBE();
361 } else if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
362 DPRINTF(FE, "Still in Icache wait.\n");
363 icacheStallCycles++;
364 return;
365 }
366
367 if (status == RenameBlocked || status == SerializeBlocked ||
368 status == TrapPending || status == BEBlocked) {
369 // Will cause a one cycle bubble between changing state and
370 // restarting.
371 DPRINTF(FE, "In blocked status.\n");
372
373 fetchBlockedCycles++;
374
375 if (status == SerializeBlocked) {
376 dispatchSerializeStallCycles++;
377 }
378 updateStatus();
379 return;
380 } else if (status == QuiescePending) {
381 DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n");
382 return;
383 } else if (status != IcacheAccessComplete) {
384 if (fetchCacheLineNextCycle) {
385 Fault fault = fetchCacheLine();
386 if (fault != NoFault) {
387 handleFault(fault);
388 fetchFault = fault;
389 return;
390 }
391 fetchCacheLineNextCycle = false;
392 }
393 // If miss, stall until it returns.
394 if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
395 // Tell CPU to not tick me for now.
396 return;
397 }
398 }
399
400 fetchCycles++;
401
402 int num_inst = 0;
403
404 // Otherwise loop and process instructions.
405 // One way to hack infinite width is to set width and maxInstBufferSize
406 // both really high. Inelegant, but probably will work.
407 while (num_inst < width &&
408 instBufferSize < maxInstBufferSize) {
409 // Get instruction from cache line.
410 DynInstPtr inst = getInstFromCacheline();
411
412 if (!inst) {
413 // PC is no longer in the cache line, end fetch.
414 // Might want to check this at the end of the cycle so that
415 // there's no cycle lost to checking for a new cache line.
416 DPRINTF(FE, "Need to get new cache line\n");
417 fetchCacheLineNextCycle = true;
418 break;
419 }
420
421 processInst(inst);
422
423 if (status == SerializeBlocked) {
424 break;
425 }
426
427 // Possibly push into a time buffer that estimates the front end
428 // latency
429 instBuffer.push_back(inst);
430 ++instBufferSize;
431 numInstsReady[0]++;
432 ++num_inst;
433
434 #if FULL_SYSTEM
435 if (inst->isQuiesce()) {
436 // warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
437 status = QuiescePending;
438 break;
439 }
440 #endif
441
442 if (inst->predTaken()) {
443 // Start over with tick?
444 break;
445 } else if (freeRegs <= 0) {
446 DPRINTF(FE, "Ran out of free registers to rename to!\n");
447 status = RenameBlocked;
448 break;
449 } else if (serializeNext) {
450 break;
451 }
452 }
453
454 fetchNisnDist.sample(num_inst);
455 checkBE();
456
457 DPRINTF(FE, "Num insts processed: %i, Inst Buffer size: %i, Free "
458 "Regs %i\n", num_inst, instBufferSize, freeRegs);
459 }
460
461 template <class Impl>
462 Fault
463 FrontEnd<Impl>::fetchCacheLine()
464 {
465 // Read a cache line, based on the current PC.
466 #if FULL_SYSTEM
467 // Flag to say whether or not address is physical addr.
468 unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0;
469 #else
470 unsigned flags = 0;
471 #endif // FULL_SYSTEM
472 Fault fault = NoFault;
473
474 if (interruptPending && flags == 0) {
475 return fault;
476 }
477
478 // Align the fetch PC so it's at the start of a cache block.
479 Addr fetch_PC = icacheBlockAlignPC(PC);
480
481 DPRINTF(FE, "Fetching cache line starting at %#x.\n", fetch_PC);
482
483 // Setup the memReq to do a read of the first isntruction's address.
484 // Set the appropriate read size and flags as well.
485 memReq = new Request(0, fetch_PC, cacheBlkSize, flags,
486 fetch_PC, cpu->readCpuId(), 0);
487
488 // Translate the instruction request.
489 fault = cpu->translateInstReq(memReq, thread);
490
491 // Now do the timing access to see whether or not the instruction
492 // exists within the cache.
493 if (fault == NoFault) {
494 #if 0
495 if (cpu->system->memctrl->badaddr(memReq->paddr) ||
496 memReq->isUncacheable()) {
497 DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a "
498 "misspeculating path!",
499 memReq->paddr);
500 return TheISA::genMachineCheckFault();
501 }
502 #endif
503
504 // Build packet here.
505 PacketPtr data_pkt = new Packet(memReq,
506 Packet::ReadReq, Packet::Broadcast);
507 data_pkt->dataStatic(cacheData);
508
509 if (!icachePort.sendTiming(data_pkt)) {
510 assert(retryPkt == NULL);
511 DPRINTF(Fetch, "Out of MSHRs!\n");
512 status = IcacheWaitRetry;
513 retryPkt = data_pkt;
514 cacheBlocked = true;
515 return NoFault;
516 }
517
518 status = IcacheWaitResponse;
519 }
520
521 // Note that this will set the cache block PC a bit earlier than it should
522 // be set.
523 cacheBlkPC = fetch_PC;
524
525 ++fetchedCacheLines;
526
527 DPRINTF(FE, "Done fetching cache line.\n");
528
529 return fault;
530 }
531
532 template <class Impl>
533 void
534 FrontEnd<Impl>::processInst(DynInstPtr &inst)
535 {
536 if (processBarriers(inst)) {
537 return;
538 }
539
540 Addr inst_PC = inst->readPC();
541
542 if (!inst->isControl()) {
543 inst->setPredTarg(inst->readNextPC());
544 } else {
545 fetchedBranches++;
546 if (branchPred.predict(inst, inst_PC, inst->threadNumber)) {
547 predictedBranches++;
548 }
549 }
550
551 Addr next_PC = inst->readPredTarg();
552
553 DPRINTF(FE, "[sn:%lli] Predicted and processed inst PC %#x, next PC "
554 "%#x\n", inst->seqNum, inst_PC, next_PC);
555
556 // inst->setNextPC(next_PC);
557
558 // Not sure where I should set this
559 PC = next_PC;
560
561 renameInst(inst);
562 }
563
564 template <class Impl>
565 bool
566 FrontEnd<Impl>::processBarriers(DynInstPtr &inst)
567 {
568 if (serializeNext) {
569 inst->setSerializeBefore();
570 serializeNext = false;
571 } else if (!inst->isSerializing() &&
572 !inst->isIprAccess() &&
573 !inst->isStoreConditional()) {
574 return false;
575 }
576
577 if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
578 !inst->isSerializeHandled()) {
579 DPRINTF(FE, "Serialize before instruction encountered.\n");
580
581 if (!inst->isTempSerializeBefore()) {
582 dispatchedSerializing++;
583 inst->setSerializeHandled();
584 } else {
585 dispatchedTempSerializing++;
586 }
587
588 // Change status over to SerializeBlocked so that other stages know
589 // what this is blocked on.
590 // status = SerializeBlocked;
591
592 // barrierInst = inst;
593 // return true;
594 } else if ((inst->isStoreConditional() || inst->isSerializeAfter())
595 && !inst->isSerializeHandled()) {
596 DPRINTF(FE, "Serialize after instruction encountered.\n");
597
598 inst->setSerializeHandled();
599
600 dispatchedSerializing++;
601
602 serializeNext = true;
603 return false;
604 }
605 return false;
606 }
607
608 template <class Impl>
609 void
610 FrontEnd<Impl>::handleFault(Fault &fault)
611 {
612 DPRINTF(FE, "Fault at fetch, telling commit\n");
613
614 // We're blocked on the back end until it handles this fault.
615 status = TrapPending;
616
617 // Get a sequence number.
618 InstSeqNum inst_seq = getAndIncrementInstSeq();
619 // We will use a nop in order to carry the fault.
620 ExtMachInst ext_inst = TheISA::NoopMachInst;
621
622 // Create a new DynInst from the dummy nop.
623 DynInstPtr instruction = new DynInst(ext_inst, PC,
624 PC+sizeof(MachInst),
625 inst_seq, cpu);
626 instruction->setPredTarg(instruction->readNextPC());
627 // instruction->setThread(tid);
628
629 // instruction->setASID(tid);
630
631 instruction->setThreadState(thread);
632
633 instruction->traceData = NULL;
634
635 instruction->fault = fault;
636 instruction->setCanIssue();
637 instBuffer.push_back(instruction);
638 numInstsReady[0]++;
639 ++instBufferSize;
640 }
641
642 template <class Impl>
643 void
644 FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
645 const bool is_branch, const bool branch_taken)
646 {
647 DPRINTF(FE, "Squashing from [sn:%lli], setting PC to %#x\n",
648 squash_num, next_PC);
649
650 if (fetchFault != NoFault)
651 fetchFault = NoFault;
652
653 while (!instBuffer.empty() &&
654 instBuffer.back()->seqNum > squash_num) {
655 DynInstPtr inst = instBuffer.back();
656
657 DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n",
658 inst->seqNum, inst->readPC());
659
660 inst->clearDependents();
661
662 instBuffer.pop_back();
663 --instBufferSize;
664
665 freeRegs+= inst->numDestRegs();
666 }
667
668 while (!feBuffer.empty() &&
669 feBuffer.back()->seqNum > squash_num) {
670 DynInstPtr inst = feBuffer.back();
671
672 DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n",
673 inst->seqNum, inst->readPC());
674
675 inst->clearDependents();
676
677 feBuffer.pop_back();
678 --instBufferSize;
679
680 freeRegs+= inst->numDestRegs();
681 }
682
683 // Copy over rename table from the back end.
684 renameTable.copyFrom(backEnd->renameTable);
685
686 PC = next_PC;
687
688 // Update BP with proper information.
689 if (is_branch) {
690 branchPred.squash(squash_num, next_PC, branch_taken, 0);
691 } else {
692 branchPred.squash(squash_num, 0);
693 }
694
695 // Clear the icache miss if it's outstanding.
696 if (status == IcacheWaitResponse) {
697 DPRINTF(FE, "Squashing outstanding Icache access.\n");
698 memReq = NULL;
699 }
700 /*
701 if (status == SerializeBlocked) {
702 assert(barrierInst->seqNum > squash_num);
703 barrierInst = NULL;
704 }
705 */
706 // Unless this squash originated from the front end, we're probably
707 // in running mode now.
708 // Actually might want to make this latency dependent.
709 status = Running;
710 fetchCacheLineNextCycle = true;
711 }
712
713 template <class Impl>
714 typename Impl::DynInstPtr
715 FrontEnd<Impl>::getInst()
716 {
717 if (feBuffer.empty()) {
718 return NULL;
719 }
720
721 DynInstPtr inst = feBuffer.front();
722
723 if (inst->isSerializeBefore() || inst->isIprAccess()) {
724 DPRINTF(FE, "Back end is getting a serialize before inst\n");
725 if (!backEnd->robEmpty()) {
726 DPRINTF(FE, "Rob is not empty yet, not returning inst\n");
727 return NULL;
728 }
729 inst->clearSerializeBefore();
730 }
731
732 feBuffer.pop_front();
733
734 --instBufferSize;
735
736 dispatchCountStat++;
737
738 return inst;
739 }
740
741 template <class Impl>
742 void
743 FrontEnd<Impl>::processCacheCompletion(PacketPtr pkt)
744 {
745 DPRINTF(FE, "Processing cache completion\n");
746
747 // Do something here.
748 if (status != IcacheWaitResponse ||
749 pkt->req != memReq ||
750 switchedOut) {
751 DPRINTF(FE, "Previous fetch was squashed.\n");
752 fetchIcacheSquashes++;
753 delete pkt->req;
754 delete pkt;
755 return;
756 }
757
758 status = IcacheAccessComplete;
759
760 /* if (checkStall(tid)) {
761 fetchStatus[tid] = Blocked;
762 } else {
763 fetchStatus[tid] = IcacheMissComplete;
764 }
765 */
766 // memcpy(cacheData, memReq->data, memReq->size);
767
768 // Reset the completion event to NULL.
769 // memReq->completionEvent = NULL;
770 delete pkt->req;
771 delete pkt;
772 memReq = NULL;
773 }
774
775 template <class Impl>
776 void
777 FrontEnd<Impl>::addFreeRegs(int num_freed)
778 {
779 if (status == RenameBlocked && freeRegs + num_freed > 0) {
780 status = Running;
781 }
782
783 DPRINTF(FE, "Adding %i freed registers\n", num_freed);
784
785 freeRegs+= num_freed;
786
787 // assert(freeRegs <= numPhysRegs);
788 if (freeRegs > numPhysRegs)
789 freeRegs = numPhysRegs;
790 }
791
792 template <class Impl>
793 void
794 FrontEnd<Impl>::recvRetry()
795 {
796 assert(cacheBlocked);
797 if (retryPkt != NULL) {
798 assert(status == IcacheWaitRetry);
799
800 if (icachePort.sendTiming(retryPkt)) {
801 status = IcacheWaitResponse;
802 retryPkt = NULL;
803 cacheBlocked = false;
804 }
805 } else {
806 // Access has been squashed since it was sent out. Just clear
807 // the cache being blocked.
808 cacheBlocked = false;
809 }
810
811 }
812
813 template <class Impl>
814 bool
815 FrontEnd<Impl>::updateStatus()
816 {
817 bool serialize_block = !backEnd->robEmpty() || instBufferSize;
818 bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
819 bool ret_val = false;
820
821 if (status == SerializeBlocked && !serialize_block) {
822 status = SerializeComplete;
823 ret_val = true;
824 }
825
826 if (status == BEBlocked && !be_block) {
827 // if (barrierInst) {
828 // status = SerializeBlocked;
829 // } else {
830 status = Running;
831 // }
832 ret_val = true;
833 }
834 return ret_val;
835 }
836
837 template <class Impl>
838 void
839 FrontEnd<Impl>::checkBE()
840 {
841 bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
842 if (be_block) {
843 if (status == Running || status == Idle) {
844 status = BEBlocked;
845 }
846 }
847 }
848
849 template <class Impl>
850 typename Impl::DynInstPtr
851 FrontEnd<Impl>::getInstFromCacheline()
852 {
853 /*
854 if (status == SerializeComplete) {
855 DynInstPtr inst = barrierInst;
856 status = Running;
857 barrierInst = NULL;
858 inst->clearSerializeBefore();
859 return inst;
860 }
861 */
862 InstSeqNum inst_seq;
863 MachInst inst;
864 // @todo: Fix this magic number used here to handle word offset (and
865 // getting rid of PAL bit)
866 unsigned offset = (PC & cacheBlkMask) & ~3;
867
868 // PC of inst is not in this cache block
869 if (PC >= (cacheBlkPC + cacheBlkSize) || PC < cacheBlkPC || !cacheBlkValid) {
870 return NULL;
871 }
872
873 //////////////////////////
874 // Fetch one instruction
875 //////////////////////////
876
877 // Get a sequence number.
878 inst_seq = getAndIncrementInstSeq();
879
880 // Make sure this is a valid index.
881 assert(offset <= cacheBlkSize - sizeof(MachInst));
882
883 // Get the instruction from the array of the cache line.
884 inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset]));
885
886 ExtMachInst decode_inst = TheISA::makeExtMI(inst, PC);
887
888 // Create a new DynInst from the instruction fetched.
889 DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst),
890 inst_seq, cpu);
891
892 instruction->setThreadState(thread);
893
894 DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n",
895 inst_seq, instruction->readPC(),
896 instruction->staticInst->disassemble(PC));
897
898 instruction->traceData =
899 Trace::getInstRecord(curTick, tc,
900 instruction->staticInst,
901 instruction->readPC());
902
903 // Increment stat of fetched instructions.
904 ++fetchedInsts;
905
906 return instruction;
907 }
908
909 template <class Impl>
910 void
911 FrontEnd<Impl>::renameInst(DynInstPtr &inst)
912 {
913 DynInstPtr src_inst = NULL;
914 int num_src_regs = inst->numSrcRegs();
915 if (num_src_regs == 0) {
916 inst->setCanIssue();
917 } else {
918 for (int i = 0; i < num_src_regs; ++i) {
919 src_inst = renameTable[inst->srcRegIdx(i)];
920
921 inst->setSrcInst(src_inst, i);
922
923 DPRINTF(FE, "[sn:%lli]: Src reg %i is inst [sn:%lli]\n",
924 inst->seqNum, (int)inst->srcRegIdx(i), src_inst->seqNum);
925
926 if (src_inst->isResultReady()) {
927 DPRINTF(FE, "Reg ready.\n");
928 inst->markSrcRegReady(i);
929 } else {
930 DPRINTF(FE, "Adding to dependent list.\n");
931 src_inst->addDependent(inst);
932 }
933 }
934 }
935
936 for (int i = 0; i < inst->numDestRegs(); ++i) {
937 RegIndex idx = inst->destRegIdx(i);
938
939 DPRINTF(FE, "Dest reg %i is now inst [sn:%lli], was previously "
940 "[sn:%lli]\n",
941 (int)inst->destRegIdx(i), inst->seqNum,
942 renameTable[idx]->seqNum);
943
944 inst->setPrevDestInst(renameTable[idx], i);
945
946 renameTable[idx] = inst;
947 --freeRegs;
948 }
949 }
950
951 template <class Impl>
952 void
953 FrontEnd<Impl>::wakeFromQuiesce()
954 {
955 DPRINTF(FE, "Waking up from quiesce\n");
956 // Hopefully this is safe
957 status = Running;
958 }
959
960 template <class Impl>
961 void
962 FrontEnd<Impl>::switchOut()
963 {
964 switchedOut = true;
965 cpu->signalSwitched();
966 }
967
968 template <class Impl>
969 void
970 FrontEnd<Impl>::doSwitchOut()
971 {
972 memReq = NULL;
973 squash(0, 0);
974 instBuffer.clear();
975 instBufferSize = 0;
976 feBuffer.clear();
977 status = Idle;
978 }
979
980 template <class Impl>
981 void
982 FrontEnd<Impl>::takeOverFrom(ThreadContext *old_tc)
983 {
984 assert(freeRegs == numPhysRegs);
985 fetchCacheLineNextCycle = true;
986
987 cacheBlkValid = false;
988
989 #if !FULL_SYSTEM
990 // pTable = params->pTable;
991 #endif
992 fetchFault = NoFault;
993 serializeNext = false;
994 barrierInst = NULL;
995 status = Running;
996 switchedOut = false;
997 interruptPending = false;
998 }
999
1000 template <class Impl>
1001 void
1002 FrontEnd<Impl>::dumpInsts()
1003 {
1004 cprintf("instBuffer size: %i\n", instBuffer.size());
1005
1006 InstBuffIt buff_it = instBuffer.begin();
1007
1008 for (int num = 0; buff_it != instBuffer.end(); num++) {
1009 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1010 "Squashed:%i\n\n",
1011 num, (*buff_it)->readPC(), (*buff_it)->threadNumber,
1012 (*buff_it)->seqNum, (*buff_it)->isIssued(),
1013 (*buff_it)->isSquashed());
1014 buff_it++;
1015 }
1016 }