5343206c1fe105e1ab46e59fe18ba5e0f80f4f1b
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"
50 using namespace TheISA
;
51 using namespace ThePipeline
;
53 InOrderDynInst::InOrderDynInst(InOrderCPU
*cpu
,
54 InOrderThreadState
*state
,
58 : seqNum(seq_num
), squashSeqNum(0), threadNumber(tid
), asid(_asid
),
59 virtProcNumber(0), staticInst(NULL
), traceData(NULL
), cpu(cpu
),
60 thread(state
), fault(NoFault
), memData(NULL
), loadData(0),
61 storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
62 readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
63 memTime(0), splitMemData(NULL
), splitMemReq(NULL
), totalSize(0),
64 split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
65 split2ndDataPtr(NULL
), split2ndFlags(0), splitInst(false),
66 splitFinishCnt(0), split2ndStoreDataPtr(NULL
), splitInstSked(false),
67 inFrontEnd(true), frontSked(NULL
), backSked(NULL
),
68 squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
69 fetchMemReq(NULL
), dataMemReq(NULL
), instEffAddr(0), eaCalcDone(false),
70 lqIdx(0), sqIdx(0), instListIt(NULL
), onInstList(false)
72 for(int i
= 0; i
< MaxInstSrcRegs
; i
++) {
73 _readySrcRegIdx
[i
] = false;
77 for(int j
= 0; j
< MaxInstDestRegs
; j
++) {
79 _prevDestRegIdx
[j
] = 0;
83 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction created."
84 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
88 int InOrderDynInst::instcount
= 0;
91 InOrderDynInst::cpuId()
97 InOrderDynInst::setMachInst(ExtMachInst machInst
)
99 staticInst
= StaticInst::decode(machInst
, pc
.instAddr());
101 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
102 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
105 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
106 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
107 this->_readySrcRegIdx
[i
] = 0;
112 InOrderDynInst::initVars()
120 split2ndAccess
= false;
122 splitInstSked
= false;
134 memAddrReady
= false;
137 predictTaken
= false;
138 procDelaySlotOnMispred
= false;
143 // Also make this a parameter, or perhaps get it from xc or cpu.
148 // Initialize the fault to be NoFault.
151 // Make sure to have the renamed register entries set to the same
152 // as the normal register entries. It will allow the IQ to work
153 // without any modifications.
154 if (this->staticInst
) {
155 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
156 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
159 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
160 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
161 this->_readySrcRegIdx
[i
] = 0;
165 // Update Instruction Count for this instruction
166 if (instcount
> 100) {
167 fatal("Number of Active Instructions in CPU is too high. "
168 "(Not Dereferencing Ptrs. Correctly?)\n");
173 InOrderDynInst::resetInstCount()
179 InOrderDynInst::~InOrderDynInst()
185 delete [] splitMemData
;
191 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
192 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
196 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
198 this->staticInst
= static_inst
;
200 // Make sure to have the renamed register entries set to the same
201 // as the normal register entries. It will allow the IQ to work
202 // without any modifications.
203 if (this->staticInst
) {
204 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
205 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
208 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
209 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
210 this->_readySrcRegIdx
[i
] = 0;
216 InOrderDynInst::execute()
218 // @todo: Pretty convoluted way to avoid squashing from happening
219 // when using the TC during an instruction's execution
220 // (specifically for instructions that have side-effects that use
221 // the TC). Fix this.
222 bool in_syscall
= this->thread
->inSyscall
;
223 this->thread
->inSyscall
= true;
225 this->fault
= this->staticInst
->execute(this, this->traceData
);
227 this->thread
->inSyscall
= in_syscall
;
233 InOrderDynInst::calcEA()
235 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
240 InOrderDynInst::initiateAcc()
242 // @todo: Pretty convoluted way to avoid squashing from happening
243 // when using the TC during an instruction's execution
244 // (specifically for instructions that have side-effects that use
245 // the TC). Fix this.
246 bool in_syscall
= this->thread
->inSyscall
;
247 this->thread
->inSyscall
= true;
249 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
251 this->thread
->inSyscall
= in_syscall
;
258 InOrderDynInst::completeAcc(Packet
*pkt
)
260 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
266 InOrderDynInst::memAccess()
268 return initiateAcc();
275 InOrderDynInst::hwrei()
277 #if THE_ISA == ALPHA_ISA
278 // Can only do a hwrei when in pal mode.
279 if (!(this->instAddr() & 0x3))
280 return new AlphaISA::UnimplementedOpcodeFault
;
282 // Set the next PC based on the value of the EXC_ADDR IPR.
283 AlphaISA::PCState pc
= this->pcState();
284 pc
.npc(this->cpu
->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR
,
285 this->threadNumber
));
287 if (CPA::available()) {
288 ThreadContext
*tc
= this->cpu
->tcBase(this->threadNumber
);
289 CPA::cpa()->swAutoBegin(tc
, this->nextInstAddr());
292 // Tell CPU to clear any state it needs to if a hwrei is taken.
293 this->cpu
->hwrei(this->threadNumber
);
300 InOrderDynInst::trap(Fault fault
)
302 this->cpu
->trap(fault
, this->threadNumber
, this);
307 InOrderDynInst::simPalCheck(int palFunc
)
309 #if THE_ISA != ALPHA_ISA
310 panic("simPalCheck called, but PAL only exists in Alpha!\n");
312 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
316 InOrderDynInst::syscall(int64_t callnum
)
318 syscallNum
= callnum
;
319 cpu
->syscallContext(NoFault
, this->threadNumber
, this);
324 InOrderDynInst::setSquashInfo(unsigned stage_num
)
326 squashingStage
= stage_num
;
328 // If it's a fault, then we need to squash
329 // the faulting instruction too. Squash
330 // functions squash above a seqNum, so we
331 // decrement here for that case
332 if (fault
!= NoFault
) {
333 squashSeqNum
= seqNum
- 1;
336 squashSeqNum
= seqNum
;
338 #if ISA_HAS_DELAY_SLOT
339 if (staticInst
&& isControl()) {
340 TheISA::PCState nextPC
= pc
;
341 TheISA::advancePC(nextPC
, staticInst
);
343 // Check to see if we should squash after the
344 // branch or after a branch delay slot.
345 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
346 squashSeqNum
= seqNum
+ 1;
348 squashSeqNum
= seqNum
;
354 InOrderDynInst::releaseReq(ResourceRequest
* req
)
356 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
357 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
359 while(list_it
!= list_end
) {
360 if((*list_it
)->getResIdx() == req
->getResIdx() &&
361 (*list_it
)->getSlot() == req
->getSlot()) {
362 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
363 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
364 reqList
.erase(list_it
);
370 panic("Releasing Res. Request That Isnt There!\n");
373 /** Records an integer source register being set to a value. */
375 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
377 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] Int being set "
378 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
379 instSrc
[idx
].intVal
= val
;
382 /** Records an fp register being set to a value. */
384 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
386 instSrc
[idx
].fpVal
.f
= val
;
387 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FP being set "
388 "to %x, %08f...%08f\n", threadNumber
, seqNum
, idx
,
389 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
392 /** Records an fp register being set to an integer value. */
394 InOrderDynInst::setFloatRegBitsSrc(int idx
, FloatRegBits val
)
396 instSrc
[idx
].fpVal
.i
= val
;
397 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
398 "to %x, %08f...%x\n", threadNumber
, seqNum
, idx
,
399 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
402 /** Reads a integer register. */
404 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
406 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
407 threadNumber
, seqNum
, idx
, instSrc
[idx
].intVal
);
408 return instSrc
[idx
].intVal
;
411 /** Reads a FP register. */
413 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
415 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
416 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
417 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
418 return instSrc
[idx
].fpVal
.f
;
422 /** Reads a FP register as a integer. */
424 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
426 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
427 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
428 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
429 return instSrc
[idx
].fpVal
.i
;
432 /** Reads a miscellaneous register. */
434 InOrderDynInst::readMiscReg(int misc_reg
)
436 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
440 /** Reads a misc. register, including any side-effects the read
441 * might have as defined by the architecture.
444 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
446 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
447 " read as %#x.\n", threadNumber
, seqNum
, idx
,
448 instSrc
[idx
].intVal
);
449 return instSrc
[idx
].intVal
;
453 /** Sets a misc. register, including any side-effects the write
454 * might have as defined by the architecture.
457 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
460 instResult
[idx
].type
= Integer
;
461 instResult
[idx
].res
.intVal
= val
;
462 instResult
[idx
].tick
= curTick();
464 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
465 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
469 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
472 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
475 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
476 return this->cpu
->readIntReg(reg_idx
, tid
);
477 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
478 reg_idx
-= FP_Base_DepTag
;
479 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
481 reg_idx
-= Ctrl_Base_DepTag
;
482 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
486 /** Sets a Integer register. */
488 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
490 instResult
[idx
].type
= Integer
;
491 instResult
[idx
].res
.intVal
= val
;
492 instResult
[idx
].tick
= curTick();
494 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
495 "being set to %#x (result-tick:%i).\n",
496 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
499 /** Sets a FP register. */
501 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
503 instResult
[idx
].type
= Float
;
504 instResult
[idx
].res
.fpVal
.f
= val
;
505 instResult
[idx
].tick
= curTick();
507 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. %i "
508 "being set to %#x, %08f (result-tick:%i).\n",
509 threadNumber
, seqNum
, idx
, val
, val
, instResult
[idx
].tick
);
512 /** Sets a FP register as a integer. */
514 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
517 instResult
[idx
].type
= FloatBits
;
518 instResult
[idx
].res
.fpVal
.i
= val
;
519 instResult
[idx
].tick
= curTick();
521 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
522 "being set to %#x (result-tick:%i).\n",
523 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
526 /** Sets a misc. register, including any side-effects the write
527 * might have as defined by the architecture.
529 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
531 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
533 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
537 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
540 if (tid
== InvalidThreadID
) {
541 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
544 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
545 this->cpu
->setIntReg(reg_idx
, val
, tid
);
546 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
547 reg_idx
-= FP_Base_DepTag
;
548 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
550 reg_idx
-= Ctrl_Base_DepTag
;
551 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
556 InOrderDynInst::deallocateContext(int thread_num
)
558 this->cpu
->deallocateContext(thread_num
);
562 InOrderDynInst::readMem(Addr addr
, uint8_t *data
,
563 unsigned size
, unsigned flags
)
565 return cpu
->read(this, addr
, data
, size
, flags
);
569 InOrderDynInst::writeMem(uint8_t *data
, unsigned size
,
570 Addr addr
, unsigned flags
, uint64_t *res
)
572 return cpu
->write(this, data
, size
, addr
, flags
, res
);
577 InOrderDynInst::dump()
579 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
580 cout
<< staticInst
->disassemble(pc
.instAddr());
585 InOrderDynInst::dump(std::string
&outstring
)
587 std::ostringstream s
;
588 s
<< "T" << threadNumber
<< " : " << pc
<< " "
589 << staticInst
->disassemble(pc
.instAddr());
598 #include "base/hashmap.hh"
600 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
602 unsigned a
= (unsigned)addr
;
603 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
608 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,