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 syscallNum
= callnum
;
300 cpu
->syscallContext(NoFault
, this->threadNumber
, this);
305 InOrderDynInst::setSquashInfo(unsigned stage_num
)
307 squashingStage
= stage_num
;
309 // If it's a fault, then we need to squash
310 // the faulting instruction too. Squash
311 // functions squash above a seqNum, so we
312 // decrement here for that case
313 if (fault
!= NoFault
) {
314 squashSeqNum
= seqNum
- 1;
317 squashSeqNum
= seqNum
;
319 #if ISA_HAS_DELAY_SLOT
321 TheISA::PCState nextPC
= pc
;
322 TheISA::advancePC(nextPC
, staticInst
);
324 // Check to see if we should squash after the
325 // branch or after a branch delay slot.
326 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
327 squashSeqNum
= seqNum
+ 1;
329 squashSeqNum
= seqNum
;
335 InOrderDynInst::releaseReq(ResourceRequest
* req
)
337 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
338 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
340 while(list_it
!= list_end
) {
341 if((*list_it
)->getResIdx() == req
->getResIdx() &&
342 (*list_it
)->getSlot() == req
->getSlot()) {
343 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
344 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
345 reqList
.erase(list_it
);
351 panic("Releasing Res. Request That Isnt There!\n");
354 /** Records an integer source register being set to a value. */
356 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
358 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i being set "
359 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
360 instSrc
[idx
].integer
= val
;
363 /** Records an fp register being set to a value. */
365 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
367 instSrc
[idx
].dbl
= val
;
370 /** Records an fp register being set to an integer value. */
372 InOrderDynInst::setFloatRegBitsSrc(int idx
, uint64_t val
)
374 instSrc
[idx
].integer
= val
;
377 /** Reads a integer register. */
379 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
381 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
382 threadNumber
, seqNum
, idx
, instSrc
[idx
].integer
);
383 return instSrc
[idx
].integer
;
386 /** Reads a FP register. */
388 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
390 return instSrc
[idx
].dbl
;
394 /** Reads a FP register as a integer. */
396 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
398 return instSrc
[idx
].integer
;
401 /** Reads a miscellaneous register. */
403 InOrderDynInst::readMiscReg(int misc_reg
)
405 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
409 /** Reads a misc. register, including any side-effects the read
410 * might have as defined by the architecture.
413 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
415 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
416 " read as %#x.\n", threadNumber
, seqNum
, idx
,
417 instSrc
[idx
].integer
);
418 return instSrc
[idx
].integer
;
422 /** Sets a misc. register, including any side-effects the write
423 * might have as defined by the architecture.
426 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
429 instResult
[idx
].type
= Integer
;
430 instResult
[idx
].val
.integer
= val
;
431 instResult
[idx
].tick
= curTick();
433 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
434 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
438 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
441 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
444 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
445 return this->cpu
->readIntReg(reg_idx
, tid
);
446 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
447 reg_idx
-= FP_Base_DepTag
;
448 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
450 reg_idx
-= Ctrl_Base_DepTag
;
451 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
455 /** Sets a Integer register. */
457 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
459 instResult
[idx
].type
= Integer
;
460 instResult
[idx
].val
.integer
= val
;
461 instResult
[idx
].tick
= curTick();
463 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
464 "being set to %#x (result-tick:%i).\n",
465 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
468 /** Sets a FP register. */
470 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
472 instResult
[idx
].val
.dbl
= val
;
473 instResult
[idx
].type
= Float
;
474 instResult
[idx
].tick
= curTick();
476 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
477 "being set to %#x (result-tick:%i).\n",
478 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
481 /** Sets a FP register as a integer. */
483 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
486 instResult
[idx
].type
= Integer
;
487 instResult
[idx
].val
.integer
= val
;
488 instResult
[idx
].tick
= curTick();
490 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
491 "being set to %#x (result-tick:%i).\n",
492 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
495 /** Sets a misc. register, including any side-effects the write
496 * might have as defined by the architecture.
498 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
500 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
502 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
506 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
509 if (tid
== InvalidThreadID
) {
510 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
513 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
514 this->cpu
->setIntReg(reg_idx
, val
, tid
);
515 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
516 reg_idx
-= FP_Base_DepTag
;
517 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
519 reg_idx
-= Ctrl_Base_DepTag
;
520 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
525 InOrderDynInst::deallocateContext(int thread_num
)
527 this->cpu
->deallocateContext(thread_num
);
531 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
532 unsigned size
, unsigned flags
)
534 return cpu
->read(this, addr
, data
, size
, flags
);
539 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
542 traceData
->setAddr(addr
);
543 traceData
->setData(data
);
545 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
546 //@todo: the below lines should be unnecessary, timing access
547 // wont have valid data right here
548 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
549 data
= TheISA::gtoh(data
);
550 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
553 traceData
->setData(data
);
557 #ifndef DOXYGEN_SHOULD_SKIP_THIS
561 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
565 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
569 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
573 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
577 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
581 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
583 #endif //DOXYGEN_SHOULD_SKIP_THIS
587 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
589 return read(addr
, *(uint64_t*)&data
, flags
);
594 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
596 return read(addr
, *(uint32_t*)&data
, flags
);
601 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
603 return read(addr
, (uint32_t&)data
, flags
);
607 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
608 Addr addr
, unsigned flags
, uint64_t *res
)
610 return cpu
->write(this, data
, size
, addr
, flags
, res
);
615 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
618 traceData
->setAddr(addr
);
619 traceData
->setData(data
);
621 data
= TheISA::htog(data
);
622 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
625 #ifndef DOXYGEN_SHOULD_SKIP_THIS
629 InOrderDynInst::write(Twin32_t data
, Addr addr
,
630 unsigned flags
, uint64_t *res
);
634 InOrderDynInst::write(Twin64_t data
, Addr addr
,
635 unsigned flags
, uint64_t *res
);
638 InOrderDynInst::write(uint64_t data
, Addr addr
,
639 unsigned flags
, uint64_t *res
);
643 InOrderDynInst::write(uint32_t data
, Addr addr
,
644 unsigned flags
, uint64_t *res
);
648 InOrderDynInst::write(uint16_t data
, Addr addr
,
649 unsigned flags
, uint64_t *res
);
653 InOrderDynInst::write(uint8_t data
, Addr addr
,
654 unsigned flags
, uint64_t *res
);
656 #endif //DOXYGEN_SHOULD_SKIP_THIS
660 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
662 return write(*(uint64_t*)&data
, addr
, flags
, res
);
667 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
669 return write(*(uint32_t*)&data
, addr
, flags
, res
);
675 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
677 return write((uint32_t)data
, addr
, flags
, res
);
682 InOrderDynInst::dump()
684 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
685 cout
<< staticInst
->disassemble(pc
.instAddr());
690 InOrderDynInst::dump(std::string
&outstring
)
692 std::ostringstream s
;
693 s
<< "T" << threadNumber
<< " : " << pc
<< " "
694 << staticInst
->disassemble(pc
.instAddr());
703 #include "base/hashmap.hh"
705 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
707 unsigned a
= (unsigned)addr
;
708 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
713 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,