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/cprintf.hh"
40 #include "base/trace.hh"
41 #include "config/the_isa.hh"
42 #include "cpu/inorder/cpu.hh"
43 #include "cpu/inorder/inorder_dyn_inst.hh"
44 #include "cpu/exetrace.hh"
45 #include "debug/InOrderDynInst.hh"
46 #include "mem/request.hh"
49 using namespace TheISA
;
50 using namespace ThePipeline
;
52 InOrderDynInst::InOrderDynInst(InOrderCPU
*cpu
,
53 InOrderThreadState
*state
,
57 : seqNum(seq_num
), squashSeqNum(0), threadNumber(tid
), asid(_asid
),
58 virtProcNumber(0), staticInst(NULL
), traceData(NULL
), cpu(cpu
),
59 thread(state
), fault(NoFault
), memData(NULL
), loadData(0),
60 storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
61 readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
62 memTime(0), splitMemData(NULL
), splitMemReq(NULL
), totalSize(0),
63 split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
64 split2ndDataPtr(NULL
), split2ndFlags(0), splitInst(false),
65 splitFinishCnt(0), split2ndStoreDataPtr(NULL
), splitInstSked(false),
66 inFrontEnd(true), frontSked(NULL
), backSked(NULL
),
67 squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
68 fetchMemReq(NULL
), dataMemReq(NULL
), instEffAddr(0), eaCalcDone(false),
69 lqIdx(0), sqIdx(0), instListIt(NULL
), onInstList(false)
71 for(int i
= 0; i
< MaxInstSrcRegs
; i
++) {
72 _readySrcRegIdx
[i
] = false;
76 for(int j
= 0; j
< MaxInstDestRegs
; j
++) {
78 _prevDestRegIdx
[j
] = 0;
82 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction created."
83 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
87 int InOrderDynInst::instcount
= 0;
90 InOrderDynInst::setMachInst(ExtMachInst machInst
)
92 staticInst
= StaticInst::decode(machInst
, pc
.instAddr());
94 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
95 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
98 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
99 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
100 this->_readySrcRegIdx
[i
] = 0;
105 InOrderDynInst::initVars()
113 split2ndAccess
= false;
115 splitInstSked
= false;
127 memAddrReady
= false;
130 predictTaken
= false;
131 procDelaySlotOnMispred
= false;
136 // Also make this a parameter, or perhaps get it from xc or cpu.
141 // Initialize the fault to be NoFault.
144 // Make sure to have the renamed register entries set to the same
145 // as the normal register entries. It will allow the IQ to work
146 // without any modifications.
147 if (this->staticInst
) {
148 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
149 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
152 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
153 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
154 this->_readySrcRegIdx
[i
] = 0;
158 // Update Instruction Count for this instruction
159 if (instcount
> 100) {
160 fatal("Number of Active Instructions in CPU is too high. "
161 "(Not Dereferencing Ptrs. Correctly?)\n");
166 InOrderDynInst::resetInstCount()
172 InOrderDynInst::~InOrderDynInst()
178 delete [] splitMemData
;
184 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
185 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
189 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
191 this->staticInst
= static_inst
;
193 // Make sure to have the renamed register entries set to the same
194 // as the normal register entries. It will allow the IQ to work
195 // without any modifications.
196 if (this->staticInst
) {
197 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
198 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
201 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
202 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
203 this->_readySrcRegIdx
[i
] = 0;
209 InOrderDynInst::execute()
211 // @todo: Pretty convoluted way to avoid squashing from happening
212 // when using the TC during an instruction's execution
213 // (specifically for instructions that have side-effects that use
214 // the TC). Fix this.
215 bool in_syscall
= this->thread
->inSyscall
;
216 this->thread
->inSyscall
= true;
218 this->fault
= this->staticInst
->execute(this, this->traceData
);
220 this->thread
->inSyscall
= in_syscall
;
226 InOrderDynInst::calcEA()
228 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
233 InOrderDynInst::initiateAcc()
235 // @todo: Pretty convoluted way to avoid squashing from happening
236 // when using the TC during an instruction's execution
237 // (specifically for instructions that have side-effects that use
238 // the TC). Fix this.
239 bool in_syscall
= this->thread
->inSyscall
;
240 this->thread
->inSyscall
= true;
242 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
244 this->thread
->inSyscall
= in_syscall
;
251 InOrderDynInst::completeAcc(Packet
*pkt
)
253 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
259 InOrderDynInst::memAccess()
261 return initiateAcc();
268 InOrderDynInst::hwrei()
270 panic("InOrderDynInst: hwrei: unimplemented\n");
276 InOrderDynInst::trap(Fault fault
)
278 this->cpu
->trap(fault
, this->threadNumber
, this);
283 InOrderDynInst::simPalCheck(int palFunc
)
285 #if THE_ISA != ALPHA_ISA
286 panic("simPalCheck called, but PAL only exists in Alpha!\n");
288 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
292 InOrderDynInst::syscall(int64_t callnum
)
294 syscallNum
= callnum
;
295 cpu
->syscallContext(NoFault
, this->threadNumber
, this);
300 InOrderDynInst::setSquashInfo(unsigned stage_num
)
302 squashingStage
= stage_num
;
304 // If it's a fault, then we need to squash
305 // the faulting instruction too. Squash
306 // functions squash above a seqNum, so we
307 // decrement here for that case
308 if (fault
!= NoFault
) {
309 squashSeqNum
= seqNum
- 1;
312 squashSeqNum
= seqNum
;
314 #if ISA_HAS_DELAY_SLOT
316 TheISA::PCState nextPC
= pc
;
317 TheISA::advancePC(nextPC
, staticInst
);
319 // Check to see if we should squash after the
320 // branch or after a branch delay slot.
321 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
322 squashSeqNum
= seqNum
+ 1;
324 squashSeqNum
= seqNum
;
330 InOrderDynInst::releaseReq(ResourceRequest
* req
)
332 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
333 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
335 while(list_it
!= list_end
) {
336 if((*list_it
)->getResIdx() == req
->getResIdx() &&
337 (*list_it
)->getSlot() == req
->getSlot()) {
338 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
339 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
340 reqList
.erase(list_it
);
346 panic("Releasing Res. Request That Isnt There!\n");
349 /** Records an integer source register being set to a value. */
351 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
353 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] Int being set "
354 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
355 instSrc
[idx
].intVal
= val
;
358 /** Records an fp register being set to a value. */
360 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
362 instSrc
[idx
].fpVal
.f
= val
;
363 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FP being set "
364 "to %x, %08f...%08f\n", threadNumber
, seqNum
, idx
,
365 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
368 /** Records an fp register being set to an integer value. */
370 InOrderDynInst::setFloatRegBitsSrc(int idx
, FloatRegBits val
)
372 instSrc
[idx
].fpVal
.i
= val
;
373 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
374 "to %x, %08f...%x\n", threadNumber
, seqNum
, idx
,
375 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
, val
);
378 /** Reads a integer register. */
380 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
382 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
383 threadNumber
, seqNum
, idx
, instSrc
[idx
].intVal
);
384 return instSrc
[idx
].intVal
;
387 /** Reads a FP register. */
389 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
391 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
392 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
393 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
394 return instSrc
[idx
].fpVal
.f
;
398 /** Reads a FP register as a integer. */
400 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
402 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
403 "as %x, %08f.\n", threadNumber
, seqNum
, idx
,
404 instSrc
[idx
].fpVal
.i
, instSrc
[idx
].fpVal
.f
);
405 return instSrc
[idx
].fpVal
.i
;
408 /** Reads a miscellaneous register. */
410 InOrderDynInst::readMiscReg(int misc_reg
)
412 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
416 /** Reads a misc. register, including any side-effects the read
417 * might have as defined by the architecture.
420 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
422 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
423 " read as %#x.\n", threadNumber
, seqNum
, idx
,
424 instSrc
[idx
].intVal
);
425 return instSrc
[idx
].intVal
;
429 /** Sets a misc. register, including any side-effects the write
430 * might have as defined by the architecture.
433 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
436 instResult
[idx
].type
= Integer
;
437 instResult
[idx
].res
.intVal
= val
;
438 instResult
[idx
].tick
= curTick();
440 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
441 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
445 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
448 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
451 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
452 return this->cpu
->readIntReg(reg_idx
, tid
);
453 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
454 reg_idx
-= FP_Base_DepTag
;
455 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
457 reg_idx
-= Ctrl_Base_DepTag
;
458 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
462 /** Sets a Integer register. */
464 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
466 instResult
[idx
].type
= Integer
;
467 instResult
[idx
].res
.intVal
= val
;
468 instResult
[idx
].tick
= curTick();
470 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
471 "being set to %#x (result-tick:%i).\n",
472 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
475 /** Sets a FP register. */
477 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
479 instResult
[idx
].res
.fpVal
.f
= val
;
480 instResult
[idx
].type
= Float
;
481 instResult
[idx
].tick
= curTick();
483 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. %i "
484 "being set to %#x, %08f (result-tick:%i).\n",
485 threadNumber
, seqNum
, idx
, val
, val
, instResult
[idx
].tick
);
488 /** Sets a FP register as a integer. */
490 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
493 instResult
[idx
].type
= Integer
;
494 instResult
[idx
].res
.fpVal
.i
= val
;
495 instResult
[idx
].tick
= curTick();
497 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
498 "being set to %#x (result-tick:%i).\n",
499 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
502 /** Sets a misc. register, including any side-effects the write
503 * might have as defined by the architecture.
505 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
507 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
509 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
513 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
516 if (tid
== InvalidThreadID
) {
517 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
520 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
521 this->cpu
->setIntReg(reg_idx
, val
, tid
);
522 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
523 reg_idx
-= FP_Base_DepTag
;
524 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
526 reg_idx
-= Ctrl_Base_DepTag
;
527 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
532 InOrderDynInst::deallocateContext(int thread_num
)
534 this->cpu
->deallocateContext(thread_num
);
538 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
539 unsigned size
, unsigned flags
)
541 return cpu
->read(this, addr
, data
, size
, flags
);
546 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
549 traceData
->setAddr(addr
);
550 traceData
->setData(data
);
552 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
553 //@todo: the below lines should be unnecessary, timing access
554 // wont have valid data right here
555 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
556 data
= TheISA::gtoh(data
);
557 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
560 traceData
->setData(data
);
564 #ifndef DOXYGEN_SHOULD_SKIP_THIS
568 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
572 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
576 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
580 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
584 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
588 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
590 #endif //DOXYGEN_SHOULD_SKIP_THIS
594 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
596 return read(addr
, *(uint64_t*)&data
, flags
);
601 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
603 return read(addr
, *(uint32_t*)&data
, flags
);
608 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
610 return read(addr
, (uint32_t&)data
, flags
);
614 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
615 Addr addr
, unsigned flags
, uint64_t *res
)
617 return cpu
->write(this, data
, size
, addr
, flags
, res
);
622 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
625 traceData
->setAddr(addr
);
626 traceData
->setData(data
);
628 data
= TheISA::htog(data
);
629 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
632 #ifndef DOXYGEN_SHOULD_SKIP_THIS
636 InOrderDynInst::write(Twin32_t data
, Addr addr
,
637 unsigned flags
, uint64_t *res
);
641 InOrderDynInst::write(Twin64_t data
, Addr addr
,
642 unsigned flags
, uint64_t *res
);
645 InOrderDynInst::write(uint64_t data
, Addr addr
,
646 unsigned flags
, uint64_t *res
);
650 InOrderDynInst::write(uint32_t data
, Addr addr
,
651 unsigned flags
, uint64_t *res
);
655 InOrderDynInst::write(uint16_t data
, Addr addr
,
656 unsigned flags
, uint64_t *res
);
660 InOrderDynInst::write(uint8_t data
, Addr addr
,
661 unsigned flags
, uint64_t *res
);
663 #endif //DOXYGEN_SHOULD_SKIP_THIS
667 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
669 return write(*(uint64_t*)&data
, addr
, flags
, res
);
674 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
676 return write(*(uint32_t*)&data
, addr
, flags
, res
);
682 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
684 return write((uint32_t)data
, addr
, flags
, res
);
689 InOrderDynInst::dump()
691 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
692 cout
<< staticInst
->disassemble(pc
.instAddr());
697 InOrderDynInst::dump(std::string
&outstring
)
699 std::ostringstream s
;
700 s
<< "T" << threadNumber
<< " : " << pc
<< " "
701 << staticInst
->disassemble(pc
.instAddr());
710 #include "base/hashmap.hh"
712 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
714 unsigned a
= (unsigned)addr
;
715 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
720 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,