2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Authors: Korey Sewell
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 "cpu/reg_class.hh"
47 #include "debug/InOrderDynInst.hh"
48 #include "mem/request.hh"
49 #include "sim/fault_fwd.hh"
50 #include "sim/full_system.hh"
53 using namespace TheISA
;
54 using namespace ThePipeline
;
56 InOrderDynInst::InOrderDynInst(InOrderCPU
*cpu
,
57 InOrderThreadState
*state
,
61 : seqNum(seq_num
), squashSeqNum(0), threadNumber(tid
), asid(_asid
),
62 virtProcNumber(0), staticInst(NULL
), traceData(NULL
), cpu(cpu
),
63 thread(state
), fault(NoFault
), memData(NULL
), loadData(0),
64 storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
65 readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
66 memTime(0), splitMemData(NULL
), splitMemReq(NULL
), totalSize(0),
67 split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
68 split2ndDataPtr(NULL
), split2ndFlags(0), splitInst(false),
69 splitFinishCnt(0), split2ndStoreDataPtr(NULL
), splitInstSked(false),
70 inFrontEnd(true), frontSked(NULL
), backSked(NULL
),
71 squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
72 fetchMemReq(NULL
), dataMemReq(NULL
), instEffAddr(0), eaCalcDone(false),
73 lqIdx(0), sqIdx(0), onInstList(false)
75 for(int i
= 0; i
< MaxInstSrcRegs
; i
++) {
76 _readySrcRegIdx
[i
] = false;
80 for(int j
= 0; j
< MaxInstDestRegs
; j
++) {
82 _prevDestRegIdx
[j
] = 0;
86 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction created."
87 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
91 int InOrderDynInst::instcount
= 0;
94 InOrderDynInst::cpuId()
100 InOrderDynInst::setStaticInst(StaticInstPtr si
)
104 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
105 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
108 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
109 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
110 this->_readySrcRegIdx
[i
] = 0;
115 InOrderDynInst::initVars()
123 split2ndAccess
= false;
125 splitInstSked
= false;
137 memAddrReady
= false;
140 predictTaken
= false;
141 procDelaySlotOnMispred
= false;
146 // Also make this a parameter, or perhaps get it from xc or cpu.
151 // Initialize the fault to be NoFault.
154 // Make sure to have the renamed register entries set to the same
155 // as the normal register entries. It will allow the IQ to work
156 // without any modifications.
157 if (this->staticInst
) {
158 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
159 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
162 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
163 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
164 this->_readySrcRegIdx
[i
] = 0;
168 // Update Instruction Count for this instruction
169 if (instcount
> 100) {
170 fatal("Number of Active Instructions in CPU is too high. "
171 "(Not Dereferencing Ptrs. Correctly?)\n");
176 InOrderDynInst::resetInstCount()
182 InOrderDynInst::~InOrderDynInst()
188 delete [] splitMemData
;
194 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
195 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
199 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
201 this->staticInst
= static_inst
;
203 // Make sure to have the renamed register entries set to the same
204 // as the normal register entries. It will allow the IQ to work
205 // without any modifications.
206 if (this->staticInst
) {
207 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
208 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
211 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
212 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
213 this->_readySrcRegIdx
[i
] = 0;
219 InOrderDynInst::execute()
221 // @todo: Pretty convoluted way to avoid squashing from happening
222 // when using the TC during an instruction's execution
223 // (specifically for instructions that have side-effects that use
224 // the TC). Fix this.
225 bool no_squash_from_TC
= this->thread
->noSquashFromTC
;
226 this->thread
->noSquashFromTC
= true;
228 this->fault
= this->staticInst
->execute(this, this->traceData
);
230 this->thread
->noSquashFromTC
= no_squash_from_TC
;
236 InOrderDynInst::calcEA()
238 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
243 InOrderDynInst::initiateAcc()
245 // @todo: Pretty convoluted way to avoid squashing from happening
246 // when using the TC during an instruction's execution
247 // (specifically for instructions that have side-effects that use
248 // the TC). Fix this.
249 bool no_squash_from_TC
= this->thread
->noSquashFromTC
;
250 this->thread
->noSquashFromTC
= true;
252 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
254 this->thread
->noSquashFromTC
= no_squash_from_TC
;
261 InOrderDynInst::completeAcc(Packet
*pkt
)
263 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
269 InOrderDynInst::memAccess()
271 return initiateAcc();
276 InOrderDynInst::hwrei()
278 #if THE_ISA == ALPHA_ISA
279 // Can only do a hwrei when in pal mode.
280 if (!(this->instAddr() & 0x3))
281 return new AlphaISA::UnimplementedOpcodeFault
;
283 // Set the next PC based on the value of the EXC_ADDR IPR.
284 AlphaISA::PCState pc
= this->pcState();
285 pc
.npc(this->cpu
->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR
,
286 this->threadNumber
));
288 if (CPA::available()) {
289 ThreadContext
*tc
= this->cpu
->tcBase(this->threadNumber
);
290 CPA::cpa()->swAutoBegin(tc
, this->nextInstAddr());
293 // Tell CPU to clear any state it needs to if a hwrei is taken.
294 this->cpu
->hwrei(this->threadNumber
);
301 InOrderDynInst::trap(Fault fault
)
303 this->cpu
->trap(fault
, this->threadNumber
, this);
308 InOrderDynInst::simPalCheck(int palFunc
)
310 #if THE_ISA != ALPHA_ISA
311 panic("simPalCheck called, but PAL only exists in Alpha!\n");
313 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
317 InOrderDynInst::syscall(int64_t callnum
)
320 panic("Syscall emulation isn't available in FS mode.\n");
322 syscallNum
= callnum
;
323 cpu
->syscallContext(NoFault
, this->threadNumber
, this);
327 InOrderDynInst::setSquashInfo(unsigned stage_num
)
329 squashingStage
= stage_num
;
331 // If it's a fault, then we need to squash
332 // the faulting instruction too. Squash
333 // functions squash above a seqNum, so we
334 // decrement here for that case
335 if (fault
!= NoFault
) {
336 squashSeqNum
= seqNum
- 1;
339 squashSeqNum
= seqNum
;
341 #if ISA_HAS_DELAY_SLOT
342 if (staticInst
&& isControl()) {
343 TheISA::PCState nextPC
= pc
;
344 TheISA::advancePC(nextPC
, staticInst
);
346 // Check to see if we should squash after the
347 // branch or after a branch delay slot.
348 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
349 squashSeqNum
= seqNum
+ 1;
351 squashSeqNum
= seqNum
;
357 InOrderDynInst::releaseReq(ResourceRequest
* req
)
359 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
360 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
362 while(list_it
!= list_end
) {
363 if((*list_it
)->getResIdx() == req
->getResIdx() &&
364 (*list_it
)->getSlot() == req
->getSlot()) {
365 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
366 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
367 reqList
.erase(list_it
);
373 panic("Releasing Res. Request That Isnt There!\n");
376 /** Records an integer source register being set to a value. */
378 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
380 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] Int being set "
381 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
382 instSrc
[idx
].intVal
= val
;
385 /** Records an fp register being set to a value. */
387 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
389 instSrc
[idx
].fpVal
.f
= val
;
390 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FP being set "
391 "to %x, %08f...%08f\n", threadNumber
, seqNum
, idx
,
392 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
395 /** Records an fp register being set to an integer value. */
397 InOrderDynInst::setFloatRegBitsSrc(int idx
, FloatRegBits val
)
399 instSrc
[idx
].fpVal
.i
= val
;
400 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
401 "to %x, %08f...%x\n", threadNumber
, seqNum
, idx
,
402 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
405 /** Reads a integer register. */
407 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
409 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
410 threadNumber
, seqNum
, idx
, instSrc
[idx
].intVal
);
411 return instSrc
[idx
].intVal
;
414 /** Reads a FP register. */
416 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
418 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
419 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
420 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
421 return instSrc
[idx
].fpVal
.f
;
425 /** Reads a FP register as a integer. */
427 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
429 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
430 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
431 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
432 return instSrc
[idx
].fpVal
.i
;
435 /** Reads a miscellaneous register. */
437 InOrderDynInst::readMiscReg(int misc_reg
)
439 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
443 /** Reads a misc. register, including any side-effects the read
444 * might have as defined by the architecture.
447 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
449 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
450 " read as %#x.\n", threadNumber
, seqNum
, idx
,
451 instSrc
[idx
].intVal
);
452 return instSrc
[idx
].intVal
;
456 /** Sets a misc. register, including any side-effects the write
457 * might have as defined by the architecture.
460 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
463 instResult
[idx
].type
= Integer
;
464 instResult
[idx
].res
.intVal
= val
;
465 instResult
[idx
].tick
= curTick();
467 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
468 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
472 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
475 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
480 switch (regIdxToClass(reg_idx
, &rel_idx
)) {
482 return this->cpu
->readIntReg(rel_idx
, tid
);
485 return this->cpu
->readFloatRegBits(rel_idx
, tid
);
488 return this->cpu
->readMiscReg(rel_idx
, tid
); // Misc. Register File
491 panic("register %d out of range\n", reg_idx
);
496 /** Sets a Integer register. */
498 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
500 instResult
[idx
].type
= Integer
;
501 instResult
[idx
].res
.intVal
= val
;
502 instResult
[idx
].tick
= curTick();
504 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
505 "being set to %#x (result-tick:%i).\n",
506 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
509 /** Sets a FP register. */
511 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
513 instResult
[idx
].type
= Float
;
514 instResult
[idx
].res
.fpVal
.f
= val
;
515 instResult
[idx
].tick
= curTick();
517 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. %i "
518 "being set to %#x, %08f (result-tick:%i).\n",
519 threadNumber
, seqNum
, idx
, val
, val
, instResult
[idx
].tick
);
522 /** Sets a FP register as a integer. */
524 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
527 instResult
[idx
].type
= FloatBits
;
528 instResult
[idx
].res
.fpVal
.i
= val
;
529 instResult
[idx
].tick
= curTick();
531 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
532 "being set to %#x (result-tick:%i).\n",
533 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
536 /** Sets a misc. register, including any side-effects the write
537 * might have as defined by the architecture.
539 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
541 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
543 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
547 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
550 if (tid
== InvalidThreadID
) {
551 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
556 switch (regIdxToClass(reg_idx
, &rel_idx
)) {
558 this->cpu
->setIntReg(rel_idx
, val
, tid
);
562 this->cpu
->setFloatRegBits(rel_idx
, val
, tid
);
566 this->cpu
->setCCReg(rel_idx
, val
, tid
);
570 this->cpu
->setMiscReg(rel_idx
, val
, tid
); // Misc. Register File
576 InOrderDynInst::deallocateContext(int thread_num
)
578 this->cpu
->deallocateContext(thread_num
);
582 InOrderDynInst::readMem(Addr addr
, uint8_t *data
,
583 unsigned size
, unsigned flags
)
585 return cpu
->read(this, addr
, data
, size
, flags
);
589 InOrderDynInst::writeMem(uint8_t *data
, unsigned size
,
590 Addr addr
, unsigned flags
, uint64_t *res
)
592 return cpu
->write(this, data
, size
, addr
, flags
, res
);
597 InOrderDynInst::dump()
599 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
600 cout
<< staticInst
->disassemble(pc
.instAddr());
605 InOrderDynInst::dump(std::string
&outstring
)
607 std::ostringstream s
;
608 s
<< "T" << threadNumber
<< " : " << pc
<< " "
609 << staticInst
->disassemble(pc
.instAddr());