2 * Copyright (c) 2007 MIPS Technologies, Inc.
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.
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.
28 * Authors: Korey Sewell
37 #include "arch/faults.hh"
38 #include "base/bigint.hh"
39 #include "base/cp_annotate.hh"
40 #include "base/cprintf.hh"
41 #include "base/trace.hh"
42 #include "config/the_isa.hh"
43 #include "cpu/inorder/cpu.hh"
44 #include "cpu/inorder/inorder_dyn_inst.hh"
45 #include "cpu/exetrace.hh"
46 #include "debug/InOrderDynInst.hh"
47 #include "mem/request.hh"
48 #include "sim/full_system.hh"
51 using namespace TheISA
;
52 using namespace ThePipeline
;
54 InOrderDynInst::InOrderDynInst(InOrderCPU
*cpu
,
55 InOrderThreadState
*state
,
59 : seqNum(seq_num
), squashSeqNum(0), threadNumber(tid
), asid(_asid
),
60 virtProcNumber(0), staticInst(NULL
), traceData(NULL
), cpu(cpu
),
61 thread(state
), fault(NoFault
), memData(NULL
), loadData(0),
62 storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
63 readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
64 memTime(0), splitMemData(NULL
), splitMemReq(NULL
), totalSize(0),
65 split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
66 split2ndDataPtr(NULL
), split2ndFlags(0), splitInst(false),
67 splitFinishCnt(0), split2ndStoreDataPtr(NULL
), splitInstSked(false),
68 inFrontEnd(true), frontSked(NULL
), backSked(NULL
),
69 squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
70 fetchMemReq(NULL
), dataMemReq(NULL
), instEffAddr(0), eaCalcDone(false),
71 lqIdx(0), sqIdx(0), instListIt(NULL
), onInstList(false)
73 for(int i
= 0; i
< MaxInstSrcRegs
; i
++) {
74 _readySrcRegIdx
[i
] = false;
78 for(int j
= 0; j
< MaxInstDestRegs
; j
++) {
80 _prevDestRegIdx
[j
] = 0;
84 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction created."
85 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
89 int InOrderDynInst::instcount
= 0;
92 InOrderDynInst::cpuId()
98 InOrderDynInst::setStaticInst(StaticInstPtr si
)
102 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
103 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
106 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
107 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
108 this->_readySrcRegIdx
[i
] = 0;
113 InOrderDynInst::initVars()
121 split2ndAccess
= false;
123 splitInstSked
= false;
135 memAddrReady
= false;
138 predictTaken
= false;
139 procDelaySlotOnMispred
= false;
144 // Also make this a parameter, or perhaps get it from xc or cpu.
149 // Initialize the fault to be NoFault.
152 // Make sure to have the renamed register entries set to the same
153 // as the normal register entries. It will allow the IQ to work
154 // without any modifications.
155 if (this->staticInst
) {
156 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
157 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
160 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
161 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
162 this->_readySrcRegIdx
[i
] = 0;
166 // Update Instruction Count for this instruction
167 if (instcount
> 100) {
168 fatal("Number of Active Instructions in CPU is too high. "
169 "(Not Dereferencing Ptrs. Correctly?)\n");
174 InOrderDynInst::resetInstCount()
180 InOrderDynInst::~InOrderDynInst()
186 delete [] splitMemData
;
192 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
193 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
197 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
199 this->staticInst
= static_inst
;
201 // Make sure to have the renamed register entries set to the same
202 // as the normal register entries. It will allow the IQ to work
203 // without any modifications.
204 if (this->staticInst
) {
205 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
206 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
209 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
210 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
211 this->_readySrcRegIdx
[i
] = 0;
217 InOrderDynInst::execute()
219 // @todo: Pretty convoluted way to avoid squashing from happening
220 // when using the TC during an instruction's execution
221 // (specifically for instructions that have side-effects that use
222 // the TC). Fix this.
223 bool in_syscall
= this->thread
->inSyscall
;
224 this->thread
->inSyscall
= true;
226 this->fault
= this->staticInst
->execute(this, this->traceData
);
228 this->thread
->inSyscall
= in_syscall
;
234 InOrderDynInst::calcEA()
236 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
241 InOrderDynInst::initiateAcc()
243 // @todo: Pretty convoluted way to avoid squashing from happening
244 // when using the TC during an instruction's execution
245 // (specifically for instructions that have side-effects that use
246 // the TC). Fix this.
247 bool in_syscall
= this->thread
->inSyscall
;
248 this->thread
->inSyscall
= true;
250 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
252 this->thread
->inSyscall
= in_syscall
;
259 InOrderDynInst::completeAcc(Packet
*pkt
)
261 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
267 InOrderDynInst::memAccess()
269 return initiateAcc();
274 InOrderDynInst::hwrei()
276 #if THE_ISA == ALPHA_ISA
277 // Can only do a hwrei when in pal mode.
278 if (!(this->instAddr() & 0x3))
279 return new AlphaISA::UnimplementedOpcodeFault
;
281 // Set the next PC based on the value of the EXC_ADDR IPR.
282 AlphaISA::PCState pc
= this->pcState();
283 pc
.npc(this->cpu
->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR
,
284 this->threadNumber
));
286 if (CPA::available()) {
287 ThreadContext
*tc
= this->cpu
->tcBase(this->threadNumber
);
288 CPA::cpa()->swAutoBegin(tc
, this->nextInstAddr());
291 // Tell CPU to clear any state it needs to if a hwrei is taken.
292 this->cpu
->hwrei(this->threadNumber
);
299 InOrderDynInst::trap(Fault fault
)
301 this->cpu
->trap(fault
, this->threadNumber
, this);
306 InOrderDynInst::simPalCheck(int palFunc
)
308 #if THE_ISA != ALPHA_ISA
309 panic("simPalCheck called, but PAL only exists in Alpha!\n");
311 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
315 InOrderDynInst::syscall(int64_t callnum
)
318 panic("Syscall emulation isn't available in FS mode.\n");
320 syscallNum
= callnum
;
321 cpu
->syscallContext(NoFault
, this->threadNumber
, this);
326 InOrderDynInst::setSquashInfo(unsigned stage_num
)
328 squashingStage
= stage_num
;
330 // If it's a fault, then we need to squash
331 // the faulting instruction too. Squash
332 // functions squash above a seqNum, so we
333 // decrement here for that case
334 if (fault
!= NoFault
) {
335 squashSeqNum
= seqNum
- 1;
338 squashSeqNum
= seqNum
;
340 #if ISA_HAS_DELAY_SLOT
341 if (staticInst
&& isControl()) {
342 TheISA::PCState nextPC
= pc
;
343 TheISA::advancePC(nextPC
, staticInst
);
345 // Check to see if we should squash after the
346 // branch or after a branch delay slot.
347 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
348 squashSeqNum
= seqNum
+ 1;
350 squashSeqNum
= seqNum
;
356 InOrderDynInst::releaseReq(ResourceRequest
* req
)
358 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
359 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
361 while(list_it
!= list_end
) {
362 if((*list_it
)->getResIdx() == req
->getResIdx() &&
363 (*list_it
)->getSlot() == req
->getSlot()) {
364 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
365 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
366 reqList
.erase(list_it
);
372 panic("Releasing Res. Request That Isnt There!\n");
375 /** Records an integer source register being set to a value. */
377 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
379 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] Int being set "
380 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
381 instSrc
[idx
].intVal
= val
;
384 /** Records an fp register being set to a value. */
386 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
388 instSrc
[idx
].fpVal
.f
= val
;
389 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FP being set "
390 "to %x, %08f...%08f\n", threadNumber
, seqNum
, idx
,
391 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
394 /** Records an fp register being set to an integer value. */
396 InOrderDynInst::setFloatRegBitsSrc(int idx
, FloatRegBits val
)
398 instSrc
[idx
].fpVal
.i
= val
;
399 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
400 "to %x, %08f...%x\n", threadNumber
, seqNum
, idx
,
401 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
404 /** Reads a integer register. */
406 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
408 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
409 threadNumber
, seqNum
, idx
, instSrc
[idx
].intVal
);
410 return instSrc
[idx
].intVal
;
413 /** Reads a FP register. */
415 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
417 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
418 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
419 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
420 return instSrc
[idx
].fpVal
.f
;
424 /** Reads a FP register as a integer. */
426 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
428 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
429 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
430 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
431 return instSrc
[idx
].fpVal
.i
;
434 /** Reads a miscellaneous register. */
436 InOrderDynInst::readMiscReg(int misc_reg
)
438 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
442 /** Reads a misc. register, including any side-effects the read
443 * might have as defined by the architecture.
446 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
448 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
449 " read as %#x.\n", threadNumber
, seqNum
, idx
,
450 instSrc
[idx
].intVal
);
451 return instSrc
[idx
].intVal
;
455 /** Sets a misc. register, including any side-effects the write
456 * might have as defined by the architecture.
459 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
462 instResult
[idx
].type
= Integer
;
463 instResult
[idx
].res
.intVal
= val
;
464 instResult
[idx
].tick
= curTick();
466 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
467 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
471 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
474 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
477 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
478 return this->cpu
->readIntReg(reg_idx
, tid
);
479 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
480 reg_idx
-= FP_Base_DepTag
;
481 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
483 reg_idx
-= Ctrl_Base_DepTag
;
484 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
488 /** Sets a Integer register. */
490 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
492 instResult
[idx
].type
= Integer
;
493 instResult
[idx
].res
.intVal
= val
;
494 instResult
[idx
].tick
= curTick();
496 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
497 "being set to %#x (result-tick:%i).\n",
498 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
501 /** Sets a FP register. */
503 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
505 instResult
[idx
].type
= Float
;
506 instResult
[idx
].res
.fpVal
.f
= val
;
507 instResult
[idx
].tick
= curTick();
509 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. %i "
510 "being set to %#x, %08f (result-tick:%i).\n",
511 threadNumber
, seqNum
, idx
, val
, val
, instResult
[idx
].tick
);
514 /** Sets a FP register as a integer. */
516 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
519 instResult
[idx
].type
= FloatBits
;
520 instResult
[idx
].res
.fpVal
.i
= val
;
521 instResult
[idx
].tick
= curTick();
523 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
524 "being set to %#x (result-tick:%i).\n",
525 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
528 /** Sets a misc. register, including any side-effects the write
529 * might have as defined by the architecture.
531 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
533 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
535 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
539 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
542 if (tid
== InvalidThreadID
) {
543 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
546 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
547 this->cpu
->setIntReg(reg_idx
, val
, tid
);
548 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
549 reg_idx
-= FP_Base_DepTag
;
550 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
552 reg_idx
-= Ctrl_Base_DepTag
;
553 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
558 InOrderDynInst::deallocateContext(int thread_num
)
560 this->cpu
->deallocateContext(thread_num
);
564 InOrderDynInst::readMem(Addr addr
, uint8_t *data
,
565 unsigned size
, unsigned flags
)
567 return cpu
->read(this, addr
, data
, size
, flags
);
571 InOrderDynInst::writeMem(uint8_t *data
, unsigned size
,
572 Addr addr
, unsigned flags
, uint64_t *res
)
574 return cpu
->write(this, data
, size
, addr
, flags
, res
);
579 InOrderDynInst::dump()
581 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
582 cout
<< staticInst
->disassemble(pc
.instAddr());
587 InOrderDynInst::dump(std::string
&outstring
)
589 std::ostringstream s
;
590 s
<< "T" << threadNumber
<< " : " << pc
<< " "
591 << staticInst
->disassemble(pc
.instAddr());
600 #include "base/hashmap.hh"
602 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
604 unsigned a
= (unsigned)addr
;
605 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
610 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,