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