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 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()
183 delete [] splitMemData
;
189 DPRINTF(InOrderDynInst
, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
190 " (active insts: %i)\n", threadNumber
, seqNum
, instcount
);
194 InOrderDynInst::setStaticInst(StaticInstPtr
&static_inst
)
196 this->staticInst
= static_inst
;
198 // Make sure to have the renamed register entries set to the same
199 // as the normal register entries. It will allow the IQ to work
200 // without any modifications.
201 if (this->staticInst
) {
202 for (int i
= 0; i
< this->staticInst
->numDestRegs(); i
++) {
203 _destRegIdx
[i
] = this->staticInst
->destRegIdx(i
);
206 for (int i
= 0; i
< this->staticInst
->numSrcRegs(); i
++) {
207 _srcRegIdx
[i
] = this->staticInst
->srcRegIdx(i
);
208 this->_readySrcRegIdx
[i
] = 0;
214 InOrderDynInst::execute()
216 // @todo: Pretty convoluted way to avoid squashing from happening
217 // when using the TC during an instruction's execution
218 // (specifically for instructions that have side-effects that use
219 // the TC). Fix this.
220 bool in_syscall
= this->thread
->inSyscall
;
221 this->thread
->inSyscall
= true;
223 this->fault
= this->staticInst
->execute(this, this->traceData
);
225 this->thread
->inSyscall
= in_syscall
;
231 InOrderDynInst::calcEA()
233 this->fault
= this->staticInst
->eaComp(this, this->traceData
);
238 InOrderDynInst::initiateAcc()
240 // @todo: Pretty convoluted way to avoid squashing from happening
241 // when using the TC during an instruction's execution
242 // (specifically for instructions that have side-effects that use
243 // the TC). Fix this.
244 bool in_syscall
= this->thread
->inSyscall
;
245 this->thread
->inSyscall
= true;
247 this->fault
= this->staticInst
->initiateAcc(this, this->traceData
);
249 this->thread
->inSyscall
= in_syscall
;
256 InOrderDynInst::completeAcc(Packet
*pkt
)
258 this->fault
= this->staticInst
->completeAcc(pkt
, this, this->traceData
);
264 InOrderDynInst::memAccess()
266 return initiateAcc();
273 InOrderDynInst::hwrei()
275 panic("InOrderDynInst: hwrei: unimplemented\n");
281 InOrderDynInst::trap(Fault fault
)
283 this->cpu
->trap(fault
, this->threadNumber
, this);
288 InOrderDynInst::simPalCheck(int palFunc
)
290 #if THE_ISA != ALPHA_ISA
291 panic("simPalCheck called, but PAL only exists in Alpha!\n");
293 return this->cpu
->simPalCheck(palFunc
, this->threadNumber
);
297 InOrderDynInst::syscall(int64_t callnum
)
299 cpu
->syscall(callnum
, this->threadNumber
);
304 InOrderDynInst::setSquashInfo(unsigned stage_num
)
306 squashingStage
= stage_num
;
308 // If it's a fault, then we need to squash
309 // the faulting instruction too. Squash
310 // functions squash above a seqNum, so we
311 // decrement here for that case
312 if (fault
!= NoFault
) {
313 squashSeqNum
= seqNum
- 1;
316 squashSeqNum
= seqNum
;
318 #if ISA_HAS_DELAY_SLOT
320 TheISA::PCState nextPC
= pc
;
321 TheISA::advancePC(nextPC
, staticInst
);
323 // Check to see if we should squash after the
324 // branch or after a branch delay slot.
325 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
326 squashSeqNum
= seqNum
+ 1;
328 squashSeqNum
= seqNum
;
334 InOrderDynInst::releaseReq(ResourceRequest
* req
)
336 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
337 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
339 while(list_it
!= list_end
) {
340 if((*list_it
)->getResIdx() == req
->getResIdx() &&
341 (*list_it
)->getSlot() == req
->getSlot()) {
342 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
343 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
344 reqList
.erase(list_it
);
350 panic("Releasing Res. Request That Isnt There!\n");
353 /** Records an integer source register being set to a value. */
355 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
357 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i being set "
358 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
359 instSrc
[idx
].integer
= val
;
362 /** Records an fp register being set to a value. */
364 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
366 instSrc
[idx
].dbl
= val
;
369 /** Records an fp register being set to an integer value. */
371 InOrderDynInst::setFloatRegBitsSrc(int idx
, uint64_t val
)
373 instSrc
[idx
].integer
= val
;
376 /** Reads a integer register. */
378 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
380 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
381 threadNumber
, seqNum
, idx
, instSrc
[idx
].integer
);
382 return instSrc
[idx
].integer
;
385 /** Reads a FP register. */
387 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
389 return instSrc
[idx
].dbl
;
393 /** Reads a FP register as a integer. */
395 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
397 return instSrc
[idx
].integer
;
400 /** Reads a miscellaneous register. */
402 InOrderDynInst::readMiscReg(int misc_reg
)
404 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
408 /** Reads a misc. register, including any side-effects the read
409 * might have as defined by the architecture.
412 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
414 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
415 " read as %#x.\n", threadNumber
, seqNum
, idx
,
416 instSrc
[idx
].integer
);
417 return instSrc
[idx
].integer
;
421 /** Sets a misc. register, including any side-effects the write
422 * might have as defined by the architecture.
425 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
428 instResult
[idx
].type
= Integer
;
429 instResult
[idx
].val
.integer
= val
;
430 instResult
[idx
].tick
= curTick();
432 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
433 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
437 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
440 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
443 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
444 return this->cpu
->readIntReg(reg_idx
, tid
);
445 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
446 reg_idx
-= FP_Base_DepTag
;
447 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
449 reg_idx
-= Ctrl_Base_DepTag
;
450 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
454 /** Sets a Integer register. */
456 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
458 instResult
[idx
].type
= Integer
;
459 instResult
[idx
].val
.integer
= val
;
460 instResult
[idx
].tick
= curTick();
462 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
463 "being set to %#x (result-tick:%i).\n",
464 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
467 /** Sets a FP register. */
469 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
471 instResult
[idx
].val
.dbl
= val
;
472 instResult
[idx
].type
= Float
;
473 instResult
[idx
].tick
= curTick();
475 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
476 "being set to %#x (result-tick:%i).\n",
477 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
480 /** Sets a FP register as a integer. */
482 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
485 instResult
[idx
].type
= Integer
;
486 instResult
[idx
].val
.integer
= val
;
487 instResult
[idx
].tick
= curTick();
489 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
490 "being set to %#x (result-tick:%i).\n",
491 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
494 /** Sets a misc. register, including any side-effects the write
495 * might have as defined by the architecture.
497 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
499 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
501 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
505 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
508 if (tid
== InvalidThreadID
) {
509 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
512 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
513 this->cpu
->setIntReg(reg_idx
, val
, tid
);
514 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
515 reg_idx
-= FP_Base_DepTag
;
516 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
518 reg_idx
-= Ctrl_Base_DepTag
;
519 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
524 InOrderDynInst::deallocateContext(int thread_num
)
526 this->cpu
->deallocateContext(thread_num
);
530 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
531 unsigned size
, unsigned flags
)
533 return cpu
->read(this, addr
, data
, size
, flags
);
538 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
541 traceData
->setAddr(addr
);
542 traceData
->setData(data
);
544 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
545 //@todo: the below lines should be unnecessary, timing access
546 // wont have valid data right here
547 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
548 data
= TheISA::gtoh(data
);
549 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
552 traceData
->setData(data
);
556 #ifndef DOXYGEN_SHOULD_SKIP_THIS
560 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
564 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
568 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
572 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
576 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
580 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
582 #endif //DOXYGEN_SHOULD_SKIP_THIS
586 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
588 return read(addr
, *(uint64_t*)&data
, flags
);
593 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
595 return read(addr
, *(uint32_t*)&data
, flags
);
600 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
602 return read(addr
, (uint32_t&)data
, flags
);
606 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
607 Addr addr
, unsigned flags
, uint64_t *res
)
609 return cpu
->write(this, data
, size
, addr
, flags
, res
);
614 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
617 traceData
->setAddr(addr
);
618 traceData
->setData(data
);
620 data
= TheISA::htog(data
);
621 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
624 #ifndef DOXYGEN_SHOULD_SKIP_THIS
628 InOrderDynInst::write(Twin32_t data
, Addr addr
,
629 unsigned flags
, uint64_t *res
);
633 InOrderDynInst::write(Twin64_t data
, Addr addr
,
634 unsigned flags
, uint64_t *res
);
637 InOrderDynInst::write(uint64_t data
, Addr addr
,
638 unsigned flags
, uint64_t *res
);
642 InOrderDynInst::write(uint32_t data
, Addr addr
,
643 unsigned flags
, uint64_t *res
);
647 InOrderDynInst::write(uint16_t data
, Addr addr
,
648 unsigned flags
, uint64_t *res
);
652 InOrderDynInst::write(uint8_t data
, Addr addr
,
653 unsigned flags
, uint64_t *res
);
655 #endif //DOXYGEN_SHOULD_SKIP_THIS
659 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
661 return write(*(uint64_t*)&data
, addr
, flags
, res
);
666 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
668 return write(*(uint32_t*)&data
, addr
, flags
, res
);
674 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
676 return write((uint32_t)data
, addr
, flags
, res
);
681 InOrderDynInst::dump()
683 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
684 cout
<< staticInst
->disassemble(pc
.instAddr());
689 InOrderDynInst::dump(std::string
&outstring
)
691 std::ostringstream s
;
692 s
<< "T" << threadNumber
<< " : " << pc
<< " "
693 << staticInst
->disassemble(pc
.instAddr());
702 #include "base/hashmap.hh"
704 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
706 unsigned a
= (unsigned)addr
;
707 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
712 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,