58280bf622ecf5604d532bfe92071727d5f11e13
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::setMachInst(ExtMachInst machInst
)
93 staticInst
= StaticInst::decode(machInst
, pc
.instAddr());
95 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
96 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
99 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
100 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
101 this->_readySrcRegIdx
[i
] = 0;
106 InOrderDynInst::initVars()
114 split2ndAccess
= false;
116 splitInstSked
= false;
128 memAddrReady
= false;
131 predictTaken
= false;
132 procDelaySlotOnMispred
= false;
137 // Also make this a parameter, or perhaps get it from xc or cpu.
142 // Initialize the fault to be NoFault.
145 // Make sure to have the renamed register entries set to the same
146 // as the normal register entries. It will allow the IQ to work
147 // without any modifications.
148 if (this->staticInst
) {
149 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
150 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
153 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
154 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
155 this->_readySrcRegIdx
[i
] = 0;
159 // Update Instruction Count for this instruction
160 if (instcount
> 100) {
161 fatal("Number of Active Instructions in CPU is too high. "
162 "(Not Dereferencing Ptrs. Correctly?)\n");
167 InOrderDynInst::resetInstCount()
173 InOrderDynInst::~InOrderDynInst()
179 delete [] splitMemData
;
185 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
186 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
190 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
192 this->staticInst
= static_inst
;
194 // Make sure to have the renamed register entries set to the same
195 // as the normal register entries. It will allow the IQ to work
196 // without any modifications.
197 if (this->staticInst
) {
198 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
199 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
202 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
203 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
204 this->_readySrcRegIdx
[i
] = 0;
210 InOrderDynInst::execute()
212 // @todo: Pretty convoluted way to avoid squashing from happening
213 // when using the TC during an instruction's execution
214 // (specifically for instructions that have side-effects that use
215 // the TC). Fix this.
216 bool in_syscall
= this->thread
->inSyscall
;
217 this->thread
->inSyscall
= true;
219 this->fault
= this->staticInst
->execute(this, this->traceData
);
221 this->thread
->inSyscall
= in_syscall
;
227 InOrderDynInst::calcEA()
229 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
234 InOrderDynInst::initiateAcc()
236 // @todo: Pretty convoluted way to avoid squashing from happening
237 // when using the TC during an instruction's execution
238 // (specifically for instructions that have side-effects that use
239 // the TC). Fix this.
240 bool in_syscall
= this->thread
->inSyscall
;
241 this->thread
->inSyscall
= true;
243 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
245 this->thread
->inSyscall
= in_syscall
;
252 InOrderDynInst::completeAcc(Packet
*pkt
)
254 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
260 InOrderDynInst::memAccess()
262 return initiateAcc();
269 InOrderDynInst::hwrei()
271 #if THE_ISA == ALPHA_ISA
272 // Can only do a hwrei when in pal mode.
273 if (!(this->instAddr() & 0x3))
274 return new AlphaISA::UnimplementedOpcodeFault
;
276 // Set the next PC based on the value of the EXC_ADDR IPR.
277 AlphaISA::PCState pc
= this->pcState();
278 pc
.npc(this->cpu
->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR
,
279 this->threadNumber
));
281 if (CPA::available()) {
282 ThreadContext
*tc
= this->cpu
->tcBase(this->threadNumber
);
283 CPA::cpa()->swAutoBegin(tc
, this->nextInstAddr());
286 // Tell CPU to clear any state it needs to if a hwrei is taken.
287 this->cpu
->hwrei(this->threadNumber
);
294 InOrderDynInst::trap(Fault fault
)
296 this->cpu
->trap(fault
, this->threadNumber
, this);
301 InOrderDynInst::simPalCheck(int palFunc
)
303 #if THE_ISA != ALPHA_ISA
304 panic("simPalCheck called, but PAL only exists in Alpha!\n");
306 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
310 InOrderDynInst::syscall(int64_t callnum
)
312 syscallNum
= callnum
;
313 cpu
->syscallContext(NoFault
, this->threadNumber
, this);
318 InOrderDynInst::setSquashInfo(unsigned stage_num
)
320 squashingStage
= stage_num
;
322 // If it's a fault, then we need to squash
323 // the faulting instruction too. Squash
324 // functions squash above a seqNum, so we
325 // decrement here for that case
326 if (fault
!= NoFault
) {
327 squashSeqNum
= seqNum
- 1;
330 squashSeqNum
= seqNum
;
332 #if ISA_HAS_DELAY_SLOT
334 TheISA::PCState nextPC
= pc
;
335 TheISA::advancePC(nextPC
, staticInst
);
337 // Check to see if we should squash after the
338 // branch or after a branch delay slot.
339 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
340 squashSeqNum
= seqNum
+ 1;
342 squashSeqNum
= seqNum
;
348 InOrderDynInst::releaseReq(ResourceRequest
* req
)
350 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
351 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
353 while(list_it
!= list_end
) {
354 if((*list_it
)->getResIdx() == req
->getResIdx() &&
355 (*list_it
)->getSlot() == req
->getSlot()) {
356 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
357 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
358 reqList
.erase(list_it
);
364 panic("Releasing Res. Request That Isnt There!\n");
367 /** Records an integer source register being set to a value. */
369 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
371 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] Int being set "
372 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
373 instSrc
[idx
].intVal
= val
;
376 /** Records an fp register being set to a value. */
378 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
380 instSrc
[idx
].fpVal
.f
= val
;
381 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FP being set "
382 "to %x, %08f...%08f\n", threadNumber
, seqNum
, idx
,
383 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
386 /** Records an fp register being set to an integer value. */
388 InOrderDynInst::setFloatRegBitsSrc(int idx
, FloatRegBits val
)
390 instSrc
[idx
].fpVal
.i
= val
;
391 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
392 "to %x, %08f...%x\n", threadNumber
, seqNum
, idx
,
393 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
396 /** Reads a integer register. */
398 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
400 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
401 threadNumber
, seqNum
, idx
, instSrc
[idx
].intVal
);
402 return instSrc
[idx
].intVal
;
405 /** Reads a FP register. */
407 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
409 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
410 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
411 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
412 return instSrc
[idx
].fpVal
.f
;
416 /** Reads a FP register as a integer. */
418 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
420 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
421 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
422 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
423 return instSrc
[idx
].fpVal
.i
;
426 /** Reads a miscellaneous register. */
428 InOrderDynInst::readMiscReg(int misc_reg
)
430 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
434 /** Reads a misc. register, including any side-effects the read
435 * might have as defined by the architecture.
438 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
440 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
441 " read as %#x.\n", threadNumber
, seqNum
, idx
,
442 instSrc
[idx
].intVal
);
443 return instSrc
[idx
].intVal
;
447 /** Sets a misc. register, including any side-effects the write
448 * might have as defined by the architecture.
451 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
454 instResult
[idx
].type
= Integer
;
455 instResult
[idx
].res
.intVal
= val
;
456 instResult
[idx
].tick
= curTick();
458 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
459 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
463 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
466 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
469 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
470 return this->cpu
->readIntReg(reg_idx
, tid
);
471 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
472 reg_idx
-= FP_Base_DepTag
;
473 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
475 reg_idx
-= Ctrl_Base_DepTag
;
476 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
480 /** Sets a Integer register. */
482 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
484 instResult
[idx
].type
= Integer
;
485 instResult
[idx
].res
.intVal
= val
;
486 instResult
[idx
].tick
= curTick();
488 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
489 "being set to %#x (result-tick:%i).\n",
490 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
493 /** Sets a FP register. */
495 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
497 instResult
[idx
].res
.fpVal
.f
= val
;
498 instResult
[idx
].type
= Float
;
499 instResult
[idx
].tick
= curTick();
501 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. %i "
502 "being set to %#x, %08f (result-tick:%i).\n",
503 threadNumber
, seqNum
, idx
, val
, val
, instResult
[idx
].tick
);
506 /** Sets a FP register as a integer. */
508 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
511 instResult
[idx
].type
= Integer
;
512 instResult
[idx
].res
.fpVal
.i
= val
;
513 instResult
[idx
].tick
= curTick();
515 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
516 "being set to %#x (result-tick:%i).\n",
517 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
520 /** Sets a misc. register, including any side-effects the write
521 * might have as defined by the architecture.
523 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
525 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
527 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
531 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
534 if (tid
== InvalidThreadID
) {
535 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
538 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
539 this->cpu
->setIntReg(reg_idx
, val
, tid
);
540 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
541 reg_idx
-= FP_Base_DepTag
;
542 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
544 reg_idx
-= Ctrl_Base_DepTag
;
545 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
550 InOrderDynInst::deallocateContext(int thread_num
)
552 this->cpu
->deallocateContext(thread_num
);
556 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
557 unsigned size
, unsigned flags
)
559 return cpu
->read(this, addr
, data
, size
, flags
);
564 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
567 traceData
->setAddr(addr
);
568 traceData
->setData(data
);
570 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
571 //@todo: the below lines should be unnecessary, timing access
572 // wont have valid data right here
573 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
574 data
= TheISA::gtoh(data
);
575 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
578 traceData
->setData(data
);
582 #ifndef DOXYGEN_SHOULD_SKIP_THIS
586 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
590 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
594 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
598 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
602 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
606 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
608 #endif //DOXYGEN_SHOULD_SKIP_THIS
612 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
614 return read(addr
, *(uint64_t*)&data
, flags
);
619 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
621 return read(addr
, *(uint32_t*)&data
, flags
);
626 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
628 return read(addr
, (uint32_t&)data
, flags
);
632 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
633 Addr addr
, unsigned flags
, uint64_t *res
)
635 return cpu
->write(this, data
, size
, addr
, flags
, res
);
640 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
643 traceData
->setAddr(addr
);
644 traceData
->setData(data
);
646 data
= TheISA::htog(data
);
647 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
650 #ifndef DOXYGEN_SHOULD_SKIP_THIS
654 InOrderDynInst::write(Twin32_t data
, Addr addr
,
655 unsigned flags
, uint64_t *res
);
659 InOrderDynInst::write(Twin64_t data
, Addr addr
,
660 unsigned flags
, uint64_t *res
);
663 InOrderDynInst::write(uint64_t data
, Addr addr
,
664 unsigned flags
, uint64_t *res
);
668 InOrderDynInst::write(uint32_t data
, Addr addr
,
669 unsigned flags
, uint64_t *res
);
673 InOrderDynInst::write(uint16_t data
, Addr addr
,
674 unsigned flags
, uint64_t *res
);
678 InOrderDynInst::write(uint8_t data
, Addr addr
,
679 unsigned flags
, uint64_t *res
);
681 #endif //DOXYGEN_SHOULD_SKIP_THIS
685 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
687 return write(*(uint64_t*)&data
, addr
, flags
, res
);
692 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
694 return write(*(uint32_t*)&data
, addr
, flags
, res
);
700 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
702 return write((uint32_t)data
, addr
, flags
, res
);
707 InOrderDynInst::dump()
709 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
710 cout
<< staticInst
->disassemble(pc
.instAddr());
715 InOrderDynInst::dump(std::string
&outstring
)
717 std::ostringstream s
;
718 s
<< "T" << threadNumber
<< " : " << pc
<< " "
719 << staticInst
->disassemble(pc
.instAddr());
728 #include "base/hashmap.hh"
730 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
732 unsigned a
= (unsigned)addr
;
733 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
738 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,