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