d42e840162eaf867ace780a2d27899bd9f5a1b27
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()
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
;
323 // If it's a fault, then we need to squash
324 // the faulting instruction too. Squash
325 // functions squash above a seqNum, so we
326 // decrement here for that case
327 if (fault
!= NoFault
)
328 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] Source Value %i being set "
372 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
373 instSrc
[idx
].integer
= val
;
376 /** Records an fp register being set to a value. */
378 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
380 instSrc
[idx
].dbl
= val
;
383 /** Records an fp register being set to an integer value. */
385 InOrderDynInst::setFloatRegBitsSrc(int idx
, uint64_t val
)
387 instSrc
[idx
].integer
= val
;
390 /** Reads a integer register. */
392 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
394 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
395 threadNumber
, seqNum
, idx
, instSrc
[idx
].integer
);
396 return instSrc
[idx
].integer
;
399 /** Reads a FP register. */
401 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
403 return instSrc
[idx
].dbl
;
407 /** Reads a FP register as a integer. */
409 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
411 return instSrc
[idx
].integer
;
414 /** Reads a miscellaneous register. */
416 InOrderDynInst::readMiscReg(int misc_reg
)
418 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
422 /** Reads a misc. register, including any side-effects the read
423 * might have as defined by the architecture.
426 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
428 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
429 " read as %#x.\n", threadNumber
, seqNum
, idx
,
430 instSrc
[idx
].integer
);
431 return instSrc
[idx
].integer
;
435 /** Sets a misc. register, including any side-effects the write
436 * might have as defined by the architecture.
439 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
442 instResult
[idx
].type
= Integer
;
443 instResult
[idx
].val
.integer
= val
;
444 instResult
[idx
].tick
= curTick();
446 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
447 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
451 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
454 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
457 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
458 return this->cpu
->readIntReg(reg_idx
, tid
);
459 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
460 reg_idx
-= FP_Base_DepTag
;
461 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
463 reg_idx
-= Ctrl_Base_DepTag
;
464 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
468 /** Sets a Integer register. */
470 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
472 instResult
[idx
].type
= Integer
;
473 instResult
[idx
].val
.integer
= val
;
474 instResult
[idx
].tick
= curTick();
476 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
477 "being set to %#x (result-tick:%i).\n",
478 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
481 /** Sets a FP register. */
483 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
485 instResult
[idx
].val
.dbl
= val
;
486 instResult
[idx
].type
= Float
;
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 FP register as a integer. */
496 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
499 instResult
[idx
].type
= Integer
;
500 instResult
[idx
].val
.integer
= val
;
501 instResult
[idx
].tick
= curTick();
503 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
504 "being set to %#x (result-tick:%i).\n",
505 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
508 /** Sets a misc. register, including any side-effects the write
509 * might have as defined by the architecture.
511 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
513 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
515 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
519 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
522 if (tid
== InvalidThreadID
) {
523 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
526 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
527 this->cpu
->setIntReg(reg_idx
, val
, tid
);
528 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
529 reg_idx
-= FP_Base_DepTag
;
530 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
532 reg_idx
-= Ctrl_Base_DepTag
;
533 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
538 InOrderDynInst::deallocateContext(int thread_num
)
540 this->cpu
->deallocateContext(thread_num
);
544 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
545 unsigned size
, unsigned flags
)
547 return cpu
->read(this, addr
, data
, size
, flags
);
552 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
555 traceData
->setAddr(addr
);
556 traceData
->setData(data
);
558 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
559 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
560 data
= TheISA::gtoh(data
);
561 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
564 traceData
->setData(data
);
568 #ifndef DOXYGEN_SHOULD_SKIP_THIS
572 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
576 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
580 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
584 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
588 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
592 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
594 #endif //DOXYGEN_SHOULD_SKIP_THIS
598 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
600 return read(addr
, *(uint64_t*)&data
, flags
);
605 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
607 return read(addr
, *(uint32_t*)&data
, flags
);
612 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
614 return read(addr
, (uint32_t&)data
, flags
);
618 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
619 Addr addr
, unsigned flags
, uint64_t *res
)
621 assert(sizeof(storeData
) >= size
);
622 memcpy(&storeData
, data
, size
);
623 DPRINTF(InOrderDynInst
, "(2) [tid:%i]: [sn:%i] Setting store data to %#x.\n",
624 threadNumber
, seqNum
, storeData
);
625 return cpu
->write(this, (uint8_t *)&storeData
, size
, addr
, flags
, res
);
630 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
633 traceData
->setAddr(addr
);
634 traceData
->setData(data
);
636 data
= TheISA::htog(data
);
637 DPRINTF(InOrderDynInst
, "(1) [tid:%i]: [sn:%i] Setting store data to %#x.\n",
638 threadNumber
, seqNum
, data
);
639 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
642 #ifndef DOXYGEN_SHOULD_SKIP_THIS
646 InOrderDynInst::write(Twin32_t data
, Addr addr
,
647 unsigned flags
, uint64_t *res
);
651 InOrderDynInst::write(Twin64_t data
, Addr addr
,
652 unsigned flags
, uint64_t *res
);
655 InOrderDynInst::write(uint64_t data
, Addr addr
,
656 unsigned flags
, uint64_t *res
);
660 InOrderDynInst::write(uint32_t data
, Addr addr
,
661 unsigned flags
, uint64_t *res
);
665 InOrderDynInst::write(uint16_t data
, Addr addr
,
666 unsigned flags
, uint64_t *res
);
670 InOrderDynInst::write(uint8_t data
, Addr addr
,
671 unsigned flags
, uint64_t *res
);
673 #endif //DOXYGEN_SHOULD_SKIP_THIS
677 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
679 return write(*(uint64_t*)&data
, addr
, flags
, res
);
684 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
686 return write(*(uint32_t*)&data
, addr
, flags
, res
);
692 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
694 return write((uint32_t)data
, addr
, flags
, res
);
699 InOrderDynInst::dump()
701 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
702 cout
<< staticInst
->disassemble(pc
.instAddr());
707 InOrderDynInst::dump(std::string
&outstring
)
709 std::ostringstream s
;
710 s
<< "T" << threadNumber
<< " : " << pc
<< " "
711 << staticInst
->disassemble(pc
.instAddr());
720 #include "base/hashmap.hh"
722 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
724 unsigned a
= (unsigned)addr
;
725 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
730 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,