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;
331 squashSeqNum
= seqNum
;
333 #if ISA_HAS_DELAY_SLOT
335 TheISA::PCState nextPC
= pc
;
336 TheISA::advancePC(nextPC
, staticInst
);
338 // Check to see if we should squash after the
339 // branch or after a branch delay slot.
340 if (pc
.nextInstAddr() == pc
.instAddr() + sizeof(MachInst
))
341 squashSeqNum
= seqNum
+ 1;
343 squashSeqNum
= seqNum
;
349 InOrderDynInst::releaseReq(ResourceRequest
* req
)
351 std::list
<ResourceRequest
*>::iterator list_it
= reqList
.begin();
352 std::list
<ResourceRequest
*>::iterator list_end
= reqList
.end();
354 while(list_it
!= list_end
) {
355 if((*list_it
)->getResIdx() == req
->getResIdx() &&
356 (*list_it
)->getSlot() == req
->getSlot()) {
357 DPRINTF(InOrderDynInst
, "[tid:%u]: [sn:%i] Done with request "
358 "to %s.\n", threadNumber
, seqNum
, req
->res
->name());
359 reqList
.erase(list_it
);
365 panic("Releasing Res. Request That Isnt There!\n");
368 /** Records an integer source register being set to a value. */
370 InOrderDynInst::setIntSrc(int idx
, uint64_t val
)
372 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i being set "
373 "to %#x.\n", threadNumber
, seqNum
, idx
, val
);
374 instSrc
[idx
].integer
= val
;
377 /** Records an fp register being set to a value. */
379 InOrderDynInst::setFloatSrc(int idx
, FloatReg val
)
381 instSrc
[idx
].dbl
= val
;
384 /** Records an fp register being set to an integer value. */
386 InOrderDynInst::setFloatRegBitsSrc(int idx
, uint64_t val
)
388 instSrc
[idx
].integer
= val
;
391 /** Reads a integer register. */
393 InOrderDynInst::readIntRegOperand(const StaticInst
*si
, int idx
, ThreadID tid
)
395 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
396 threadNumber
, seqNum
, idx
, instSrc
[idx
].integer
);
397 return instSrc
[idx
].integer
;
400 /** Reads a FP register. */
402 InOrderDynInst::readFloatRegOperand(const StaticInst
*si
, int idx
)
404 return instSrc
[idx
].dbl
;
408 /** Reads a FP register as a integer. */
410 InOrderDynInst::readFloatRegOperandBits(const StaticInst
*si
, int idx
)
412 return instSrc
[idx
].integer
;
415 /** Reads a miscellaneous register. */
417 InOrderDynInst::readMiscReg(int misc_reg
)
419 return this->cpu
->readMiscReg(misc_reg
, threadNumber
);
423 /** Reads a misc. register, including any side-effects the read
424 * might have as defined by the architecture.
427 InOrderDynInst::readMiscRegOperand(const StaticInst
*si
, int idx
)
429 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
430 " read as %#x.\n", threadNumber
, seqNum
, idx
,
431 instSrc
[idx
].integer
);
432 return instSrc
[idx
].integer
;
436 /** Sets a misc. register, including any side-effects the write
437 * might have as defined by the architecture.
440 InOrderDynInst::setMiscRegOperand(const StaticInst
*si
, int idx
,
443 instResult
[idx
].type
= Integer
;
444 instResult
[idx
].val
.integer
= val
;
445 instResult
[idx
].tick
= curTick();
447 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
448 "being set to %#x.\n", threadNumber
, seqNum
, idx
, val
);
452 InOrderDynInst::readRegOtherThread(unsigned reg_idx
, ThreadID tid
)
455 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
458 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
459 return this->cpu
->readIntReg(reg_idx
, tid
);
460 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
461 reg_idx
-= FP_Base_DepTag
;
462 return this->cpu
->readFloatRegBits(reg_idx
, tid
);
464 reg_idx
-= Ctrl_Base_DepTag
;
465 return this->cpu
->readMiscReg(reg_idx
, tid
); // Misc. Register File
469 /** Sets a Integer register. */
471 InOrderDynInst::setIntRegOperand(const StaticInst
*si
, int idx
, IntReg val
)
473 instResult
[idx
].type
= Integer
;
474 instResult
[idx
].val
.integer
= val
;
475 instResult
[idx
].tick
= curTick();
477 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
478 "being set to %#x (result-tick:%i).\n",
479 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
482 /** Sets a FP register. */
484 InOrderDynInst::setFloatRegOperand(const StaticInst
*si
, int idx
, FloatReg val
)
486 instResult
[idx
].val
.dbl
= val
;
487 instResult
[idx
].type
= Float
;
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 FP register as a integer. */
497 InOrderDynInst::setFloatRegOperandBits(const StaticInst
*si
, int idx
,
500 instResult
[idx
].type
= Integer
;
501 instResult
[idx
].val
.integer
= val
;
502 instResult
[idx
].tick
= curTick();
504 DPRINTF(InOrderDynInst
, "[tid:%i]: [sn:%i] Setting Result Float Reg. %i "
505 "being set to %#x (result-tick:%i).\n",
506 threadNumber
, seqNum
, idx
, val
, instResult
[idx
].tick
);
509 /** Sets a misc. register, including any side-effects the write
510 * might have as defined by the architecture.
512 /* Alter this if/when wanting to *speculate* on Miscellaneous registers */
514 InOrderDynInst::setMiscReg(int misc_reg
, const MiscReg
&val
)
516 this->cpu
->setMiscReg(misc_reg
, val
, threadNumber
);
520 InOrderDynInst::setRegOtherThread(unsigned reg_idx
, const MiscReg
&val
,
523 if (tid
== InvalidThreadID
) {
524 tid
= TheISA::getTargetThread(this->cpu
->tcBase(threadNumber
));
527 if (reg_idx
< FP_Base_DepTag
) { // Integer Register File
528 this->cpu
->setIntReg(reg_idx
, val
, tid
);
529 } else if (reg_idx
< Ctrl_Base_DepTag
) { // Float Register File
530 reg_idx
-= FP_Base_DepTag
;
531 this->cpu
->setFloatRegBits(reg_idx
, val
, tid
);
533 reg_idx
-= Ctrl_Base_DepTag
;
534 this->cpu
->setMiscReg(reg_idx
, val
, tid
); // Misc. Register File
539 InOrderDynInst::deallocateContext(int thread_num
)
541 this->cpu
->deallocateContext(thread_num
);
545 InOrderDynInst::readBytes(Addr addr
, uint8_t *data
,
546 unsigned size
, unsigned flags
)
548 return cpu
->read(this, addr
, data
, size
, flags
);
553 InOrderDynInst::read(Addr addr
, T
&data
, unsigned flags
)
556 traceData
->setAddr(addr
);
557 traceData
->setData(data
);
559 Fault fault
= readBytes(addr
, (uint8_t *)&data
, sizeof(T
), flags
);
560 DPRINTF(InOrderDynInst
, "[sn:%i] (1) Received Bytes %x\n", seqNum
, data
);
561 data
= TheISA::gtoh(data
);
562 DPRINTF(InOrderDynInst
, "[sn%:i] (2) Received Bytes %x\n", seqNum
, data
);
565 traceData
->setData(data
);
569 #ifndef DOXYGEN_SHOULD_SKIP_THIS
573 InOrderDynInst::read(Addr addr
, Twin32_t
&data
, unsigned flags
);
577 InOrderDynInst::read(Addr addr
, Twin64_t
&data
, unsigned flags
);
581 InOrderDynInst::read(Addr addr
, uint64_t &data
, unsigned flags
);
585 InOrderDynInst::read(Addr addr
, uint32_t &data
, unsigned flags
);
589 InOrderDynInst::read(Addr addr
, uint16_t &data
, unsigned flags
);
593 InOrderDynInst::read(Addr addr
, uint8_t &data
, unsigned flags
);
595 #endif //DOXYGEN_SHOULD_SKIP_THIS
599 InOrderDynInst::read(Addr addr
, double &data
, unsigned flags
)
601 return read(addr
, *(uint64_t*)&data
, flags
);
606 InOrderDynInst::read(Addr addr
, float &data
, unsigned flags
)
608 return read(addr
, *(uint32_t*)&data
, flags
);
613 InOrderDynInst::read(Addr addr
, int32_t &data
, unsigned flags
)
615 return read(addr
, (uint32_t&)data
, flags
);
619 InOrderDynInst::writeBytes(uint8_t *data
, unsigned size
,
620 Addr addr
, unsigned flags
, uint64_t *res
)
622 assert(sizeof(storeData
) >= size
);
623 memcpy(&storeData
, data
, size
);
624 DPRINTF(InOrderDynInst
, "(2) [tid:%i]: [sn:%i] Setting store data to %#x.\n",
625 threadNumber
, seqNum
, storeData
);
626 return cpu
->write(this, (uint8_t *)&storeData
, size
, addr
, flags
, res
);
631 InOrderDynInst::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
634 traceData
->setAddr(addr
);
635 traceData
->setData(data
);
637 data
= TheISA::htog(data
);
638 DPRINTF(InOrderDynInst
, "(1) [tid:%i]: [sn:%i] Setting store data to %#x.\n",
639 threadNumber
, seqNum
, data
);
640 return writeBytes((uint8_t*)&data
, sizeof(T
), addr
, flags
, res
);
643 #ifndef DOXYGEN_SHOULD_SKIP_THIS
647 InOrderDynInst::write(Twin32_t data
, Addr addr
,
648 unsigned flags
, uint64_t *res
);
652 InOrderDynInst::write(Twin64_t data
, Addr addr
,
653 unsigned flags
, uint64_t *res
);
656 InOrderDynInst::write(uint64_t data
, Addr addr
,
657 unsigned flags
, uint64_t *res
);
661 InOrderDynInst::write(uint32_t data
, Addr addr
,
662 unsigned flags
, uint64_t *res
);
666 InOrderDynInst::write(uint16_t data
, Addr addr
,
667 unsigned flags
, uint64_t *res
);
671 InOrderDynInst::write(uint8_t data
, Addr addr
,
672 unsigned flags
, uint64_t *res
);
674 #endif //DOXYGEN_SHOULD_SKIP_THIS
678 InOrderDynInst::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
680 return write(*(uint64_t*)&data
, addr
, flags
, res
);
685 InOrderDynInst::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
687 return write(*(uint32_t*)&data
, addr
, flags
, res
);
693 InOrderDynInst::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
695 return write((uint32_t)data
, addr
, flags
, res
);
700 InOrderDynInst::dump()
702 cprintf("T%d : %#08d `", threadNumber
, pc
.instAddr());
703 cout
<< staticInst
->disassemble(pc
.instAddr());
708 InOrderDynInst::dump(std::string
&outstring
)
710 std::ostringstream s
;
711 s
<< "T" << threadNumber
<< " : " << pc
<< " "
712 << staticInst
->disassemble(pc
.instAddr());
721 #include "base/hashmap.hh"
723 unsigned int MyHashFunc(const InOrderDynInst
*addr
)
725 unsigned a
= (unsigned)addr
;
726 unsigned hash
= (((a
>> 14) ^ ((a
>> 2) & 0xffff))) & 0x7FFFFFFF;
731 typedef m5::hash_map
<const InOrderDynInst
*, const InOrderDynInst
*,