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
), bdelaySeqNum(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 instSrc
[i
].integer
= 0;
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::setMachInst(ExtMachInst machInst
)
94 staticInst
= StaticInst::decode(machInst
, pc
.instAddr());
96 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
97 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
100 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
101 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
102 this->_readySrcRegIdx
[i
] = 0;
107 InOrderDynInst::initVars()
115 split2ndAccess
= false;
117 splitInstSked
= false;
127 for(int i
= 0; i
< MaxInstDestRegs
; i
++)
128 instResult
[i
].val
.integer
= 0;
132 memAddrReady
= false;
135 predictTaken
= false;
136 procDelaySlotOnMispred
= false;
141 // Also make this a parameter, or perhaps get it from xc or cpu.
146 // Initialize the fault to be NoFault.
149 // Make sure to have the renamed register entries set to the same
150 // as the normal register entries. It will allow the IQ to work
151 // without any modifications.
152 if (this->staticInst
) {
153 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
154 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
157 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
158 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
159 this->_readySrcRegIdx
[i
] = 0;
163 // Update Instruction Count for this instruction
164 if (instcount
> 100) {
165 fatal("Number of Active Instructions in CPU is too high. "
166 "(Not Dereferencing Ptrs. Correctly?)\n");
171 InOrderDynInst::resetInstCount()
177 InOrderDynInst::~InOrderDynInst()
179 if (fetchMemReq
!= 0x0) {
184 if (dataMemReq
!= 0x0) {
189 if (splitMemReq
!= 0x0) {
198 delete [] splitMemData
;
204 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
205 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
209 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
211 this->staticInst
= static_inst
;
213 // Make sure to have the renamed register entries set to the same
214 // as the normal register entries. It will allow the IQ to work
215 // without any modifications.
216 if (this->staticInst
) {
217 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
218 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
221 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
222 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
223 this->_readySrcRegIdx
[i
] = 0;
229 InOrderDynInst::execute()
231 // @todo: Pretty convoluted way to avoid squashing from happening
232 // when using the TC during an instruction's execution
233 // (specifically for instructions that have side-effects that use
234 // the TC). Fix this.
235 bool in_syscall
= this->thread
->inSyscall
;
236 this->thread
->inSyscall
= true;
238 this->fault
= this->staticInst
->execute(this, this->traceData
);
240 this->thread
->inSyscall
= in_syscall
;
246 InOrderDynInst::calcEA()
248 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
253 InOrderDynInst::initiateAcc()
255 // @todo: Pretty convoluted way to avoid squashing from happening
256 // when using the TC during an instruction's execution
257 // (specifically for instructions that have side-effects that use
258 // the TC). Fix this.
259 bool in_syscall
= this->thread
->inSyscall
;
260 this->thread
->inSyscall
= true;
262 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
264 this->thread
->inSyscall
= in_syscall
;
271 InOrderDynInst::completeAcc(Packet
*pkt
)
273 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
279 InOrderDynInst::memAccess()
281 return initiateAcc();
288 InOrderDynInst::hwrei()
290 panic("InOrderDynInst: hwrei: unimplemented\n");
296 InOrderDynInst::trap(Fault fault
)
298 this->cpu
->trap(fault
, this->threadNumber
, this);
303 InOrderDynInst::simPalCheck(int palFunc
)
305 #if THE_ISA != ALPHA_ISA
306 panic("simPalCheck called, but PAL only exists in Alpha!\n");
308 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
312 InOrderDynInst::syscall(int64_t callnum
)
314 cpu
->syscall(callnum
, this->threadNumber
);
319 InOrderDynInst::setSquashInfo(unsigned stage_num
)
321 squashingStage
= stage_num
;
322 bdelaySeqNum
= seqNum
;
324 #if ISA_HAS_DELAY_SLOT
326 TheISA::PCState nextPC
= pc
;
327 TheISA::advancePC(nextPC
, staticInst
);
329 // Check to see if we should squash after the
330 // branch or after a branch delay slot.
331 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
332 bdelaySeqNum
= seqNum
+ 1;
334 bdelaySeqNum
= seqNum
;
341 InOrderDynInst::releaseReq(ResourceRequest
* req
)
343 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
344 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
346 while(list_it
!= list_end
) {
347 if((*list_it
)->getResIdx() == req
->getResIdx() &&
348 (*list_it
)->getSlot() == req
->getSlot()) {
349 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
350 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
351 reqList
.erase(list_it
);
357 panic("Releasing Res. Request That Isnt There!\n");
360 /** Records an integer source register being set to a value. */
362 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
364 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i being set "
365 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
366 instSrc
[idx
].integer
= val
;
369 /** Records an fp register being set to a value. */
371 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
373 instSrc
[idx
].dbl
= val
;
376 /** Records an fp register being set to an integer value. */
378 InOrderDynInst::setFloatRegBitsSrc(int idx
, uint64_t val
)
380 instSrc
[idx
].integer
= val
;
383 /** Reads a integer register. */
385 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
387 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
388 threadNumber
, seqNum
, idx
, instSrc
[idx
].integer
);
389 return instSrc
[idx
].integer
;
392 /** Reads a FP register. */
394 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
396 return instSrc
[idx
].dbl
;
400 /** Reads a FP register as a integer. */
402 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
404 return instSrc
[idx
].integer
;
407 /** Reads a miscellaneous register. */
409 InOrderDynInst::readMiscReg(int misc_reg
)
411 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
415 /** Reads a misc. register, including any side-effects the read
416 * might have as defined by the architecture.
419 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
421 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
422 " read as %#x.\n", threadNumber
, seqNum
, idx
,
423 instSrc
[idx
].integer
);
424 return instSrc
[idx
].integer
;
428 /** Sets a misc. register, including any side-effects the write
429 * might have as defined by the architecture.
432 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
435 instResult
[idx
].type
= Integer
;
436 instResult
[idx
].val
.integer
= val
;
437 instResult
[idx
].tick
= curTick();
439 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
440 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
444 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
447 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
450 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
451 return this->cpu
->readIntReg(reg_idx
, tid
);
452 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
453 reg_idx
-= FP_Base_DepTag
;
454 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
456 reg_idx
-= Ctrl_Base_DepTag
;
457 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
461 /** Sets a Integer register. */
463 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
465 instResult
[idx
].type
= Integer
;
466 instResult
[idx
].val
.integer
= val
;
467 instResult
[idx
].tick
= curTick();
469 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
470 "being set to %#x (result-tick:%i).\n",
471 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
474 /** Sets a FP register. */
476 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
478 instResult
[idx
].val
.dbl
= val
;
479 instResult
[idx
].type
= Float
;
480 instResult
[idx
].tick
= curTick();
482 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
483 "being set to %#x (result-tick:%i).\n",
484 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
487 /** Sets a FP register as a integer. */
489 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
492 instResult
[idx
].type
= Integer
;
493 instResult
[idx
].val
.integer
= val
;
494 instResult
[idx
].tick
= curTick();
496 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
497 "being set to %#x (result-tick:%i).\n",
498 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
501 /** Sets a misc. register, including any side-effects the write
502 * might have as defined by the architecture.
504 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
506 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
508 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
512 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
515 if (tid
== InvalidThreadID
) {
516 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
519 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
520 this->cpu
->setIntReg(reg_idx
, val
, tid
);
521 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
522 reg_idx
-= FP_Base_DepTag
;
523 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
525 reg_idx
-= Ctrl_Base_DepTag
;
526 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
531 InOrderDynInst::deallocateContext(int thread_num
)
533 this->cpu
->deallocateContext(thread_num
);
537 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
538 unsigned size
, unsigned flags
)
540 return cpu
->read(this, addr
, data
, size
, flags
);
545 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
548 traceData
->setAddr(addr
);
549 traceData
->setData(data
);
551 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
552 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
553 data
= TheISA::gtoh(data
);
554 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
557 traceData
->setData(data
);
561 #ifndef DOXYGEN_SHOULD_SKIP_THIS
565 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
569 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
573 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
577 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
581 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
585 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
587 #endif //DOXYGEN_SHOULD_SKIP_THIS
591 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
593 return read(addr
, *(uint64_t*)&data
, flags
);
598 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
600 return read(addr
, *(uint32_t*)&data
, flags
);
605 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
607 return read(addr
, (uint32_t&)data
, flags
);
611 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
612 Addr addr
, unsigned flags
, uint64_t *res
)
614 assert(sizeof(storeData
) >= size
);
615 memcpy(&storeData
, data
, size
);
616 DPRINTF(InOrderDynInst
, "(2) [tid:%i]: [sn:%i] Setting store data to %#x.\n",
617 threadNumber
, seqNum
, storeData
);
618 return cpu
->write(this, (uint8_t *)&storeData
, size
, addr
, flags
, res
);
623 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
626 traceData
->setAddr(addr
);
627 traceData
->setData(data
);
629 data
= TheISA::htog(data
);
630 DPRINTF(InOrderDynInst
, "(1) [tid:%i]: [sn:%i] Setting store data to %#x.\n",
631 threadNumber
, seqNum
, data
);
632 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
635 #ifndef DOXYGEN_SHOULD_SKIP_THIS
639 InOrderDynInst::write(Twin32_t data
, Addr addr
,
640 unsigned flags
, uint64_t *res
);
644 InOrderDynInst::write(Twin64_t data
, Addr addr
,
645 unsigned flags
, uint64_t *res
);
648 InOrderDynInst::write(uint64_t data
, Addr addr
,
649 unsigned flags
, uint64_t *res
);
653 InOrderDynInst::write(uint32_t data
, Addr addr
,
654 unsigned flags
, uint64_t *res
);
658 InOrderDynInst::write(uint16_t data
, Addr addr
,
659 unsigned flags
, uint64_t *res
);
663 InOrderDynInst::write(uint8_t data
, Addr addr
,
664 unsigned flags
, uint64_t *res
);
666 #endif //DOXYGEN_SHOULD_SKIP_THIS
670 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
672 return write(*(uint64_t*)&data
, addr
, flags
, res
);
677 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
679 return write(*(uint32_t*)&data
, addr
, flags
, res
);
685 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
687 return write((uint32_t)data
, addr
, flags
, res
);
692 InOrderDynInst::dump()
694 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
695 cout
<< staticInst
->disassemble(pc
.instAddr());
700 InOrderDynInst::dump(std::string
&outstring
)
702 std::ostringstream s
;
703 s
<< "T" << threadNumber
<< " : " << pc
<< " "
704 << staticInst
->disassemble(pc
.instAddr());
713 #include "base/hashmap.hh"
715 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
717 unsigned a
= (unsigned)addr
;
718 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
723 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,