blob: dcf0ce6ae9beea2eec3577b40c246521926a03d4 [file] [log] [blame]
/*
* Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Korey Sewell
*
*/
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include "base/bigint.hh"
#include "base/cp_annotate.hh"
#include "base/cprintf.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "cpu/inorder/cpu.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/exetrace.hh"
#include "debug/InOrderDynInst.hh"
#include "mem/request.hh"
#include "sim/fault_fwd.hh"
#include "sim/full_system.hh"
using namespace std;
using namespace TheISA;
using namespace ThePipeline;
InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
InOrderThreadState *state,
InstSeqNum seq_num,
ThreadID tid,
unsigned _asid)
: seqNum(seq_num), squashSeqNum(0), threadNumber(tid), asid(_asid),
virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu),
thread(state), fault(NoFault), memData(NULL), loadData(0),
storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
readyRegs(0), pc(0), predPC(0), memAddr(0), nextStage(0),
memTime(0), splitMemData(NULL), splitMemReq(NULL), totalSize(0),
split2ndSize(0), split2ndAddr(0), split2ndAccess(false),
split2ndDataPtr(NULL), split2ndFlags(0), splitInst(false),
splitFinishCnt(0), split2ndStoreDataPtr(NULL), splitInstSked(false),
inFrontEnd(true), frontSked(NULL), backSked(NULL),
squashingStage(0), predictTaken(false), procDelaySlotOnMispred(false),
fetchMemReq(NULL), dataMemReq(NULL), instEffAddr(0), eaCalcDone(false),
lqIdx(0), sqIdx(0), onInstList(false)
{
for(int i = 0; i < MaxInstSrcRegs; i++) {
_readySrcRegIdx[i] = false;
_srcRegIdx[i] = 0;
}
for(int j = 0; j < MaxInstDestRegs; j++) {
_destRegIdx[j] = 0;
_prevDestRegIdx[j] = 0;
}
++instcount;
DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created."
" (active insts: %i)\n", threadNumber, seqNum, instcount);
}
int InOrderDynInst::instcount = 0;
int
InOrderDynInst::cpuId()
{
return cpu->cpuId();
}
void
InOrderDynInst::setStaticInst(StaticInstPtr si)
{
staticInst = si;
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
}
void
InOrderDynInst::initVars()
{
inFrontEnd = true;
fetchMemReq = NULL;
dataMemReq = NULL;
splitMemData = NULL;
split2ndAddr = 0;
split2ndAccess = false;
splitInst = false;
splitInstSked = false;
splitFinishCnt = 0;
effAddr = 0;
physEffAddr = 0;
readyRegs = 0;
nextStage = 0;
status.reset();
memAddrReady = false;
eaCalcDone = false;
predictTaken = false;
procDelaySlotOnMispred = false;
lqIdx = -1;
sqIdx = -1;
// Also make this a parameter, or perhaps get it from xc or cpu.
asid = 0;
virtProcNumber = 0;
// Initialize the fault to be NoFault.
fault = NoFault;
// Make sure to have the renamed register entries set to the same
// as the normal register entries. It will allow the IQ to work
// without any modifications.
if (this->staticInst) {
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
}
// Update Instruction Count for this instruction
if (instcount > 100) {
fatal("Number of Active Instructions in CPU is too high. "
"(Not Dereferencing Ptrs. Correctly?)\n");
}
}
void
InOrderDynInst::resetInstCount()
{
instcount = 0;
}
InOrderDynInst::~InOrderDynInst()
{
if (traceData)
delete traceData;
if (splitMemData)
delete [] splitMemData;
fault = NoFault;
--instcount;
DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed"
" (active insts: %i)\n", threadNumber, seqNum, instcount);
}
void
InOrderDynInst::setStaticInst(StaticInstPtr &static_inst)
{
this->staticInst = static_inst;
// Make sure to have the renamed register entries set to the same
// as the normal register entries. It will allow the IQ to work
// without any modifications.
if (this->staticInst) {
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
}
}
Fault
InOrderDynInst::execute()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
// (specifically for instructions that have side-effects that use
// the TC). Fix this.
bool no_squash_from_TC = this->thread->noSquashFromTC;
this->thread->noSquashFromTC = true;
this->fault = this->staticInst->execute(this, this->traceData);
this->thread->noSquashFromTC = no_squash_from_TC;
return this->fault;
}
Fault
InOrderDynInst::calcEA()
{
this->fault = this->staticInst->eaComp(this, this->traceData);
return this->fault;
}
Fault
InOrderDynInst::initiateAcc()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
// (specifically for instructions that have side-effects that use
// the TC). Fix this.
bool no_squash_from_TC = this->thread->noSquashFromTC;
this->thread->noSquashFromTC = true;
this->fault = this->staticInst->initiateAcc(this, this->traceData);
this->thread->noSquashFromTC = no_squash_from_TC;
return this->fault;
}
Fault
InOrderDynInst::completeAcc(Packet *pkt)
{
this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
return this->fault;
}
Fault
InOrderDynInst::memAccess()
{
return initiateAcc();
}
Fault
InOrderDynInst::hwrei()
{
#if THE_ISA == ALPHA_ISA
// Can only do a hwrei when in pal mode.
if (!(this->instAddr() & 0x3))
return new AlphaISA::UnimplementedOpcodeFault;
// Set the next PC based on the value of the EXC_ADDR IPR.
AlphaISA::PCState pc = this->pcState();
pc.npc(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
this->threadNumber));
this->pcState(pc);
if (CPA::available()) {
ThreadContext *tc = this->cpu->tcBase(this->threadNumber);
CPA::cpa()->swAutoBegin(tc, this->nextInstAddr());
}
// Tell CPU to clear any state it needs to if a hwrei is taken.
this->cpu->hwrei(this->threadNumber);
#endif
return NoFault;
}
void
InOrderDynInst::trap(Fault fault)
{
this->cpu->trap(fault, this->threadNumber, this);
}
bool
InOrderDynInst::simPalCheck(int palFunc)
{
#if THE_ISA != ALPHA_ISA
panic("simPalCheck called, but PAL only exists in Alpha!\n");
#endif
return this->cpu->simPalCheck(palFunc, this->threadNumber);
}
void
InOrderDynInst::syscall(int64_t callnum)
{
if (FullSystem)
panic("Syscall emulation isn't available in FS mode.\n");
syscallNum = callnum;
cpu->syscallContext(NoFault, this->threadNumber, this);
}
void
InOrderDynInst::setSquashInfo(unsigned stage_num)
{
squashingStage = stage_num;
// If it's a fault, then we need to squash
// the faulting instruction too. Squash
// functions squash above a seqNum, so we
// decrement here for that case
if (fault != NoFault) {
squashSeqNum = seqNum - 1;
return;
} else
squashSeqNum = seqNum;
#if ISA_HAS_DELAY_SLOT
if (staticInst && isControl()) {
TheISA::PCState nextPC = pc;
TheISA::advancePC(nextPC, staticInst);
// Check to see if we should squash after the
// branch or after a branch delay slot.
if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
squashSeqNum = seqNum + 1;
else
squashSeqNum = seqNum;
}
#endif
}
void
InOrderDynInst::releaseReq(ResourceRequest* req)
{
std::list<ResourceRequest*>::iterator list_it = reqList.begin();
std::list<ResourceRequest*>::iterator list_end = reqList.end();
while(list_it != list_end) {
if((*list_it)->getResIdx() == req->getResIdx() &&
(*list_it)->getSlot() == req->getSlot()) {
DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request "
"to %s.\n", threadNumber, seqNum, req->res->name());
reqList.erase(list_it);
return;
}
list_it++;
}
panic("Releasing Res. Request That Isnt There!\n");
}
/** Records an integer source register being set to a value. */
void
InOrderDynInst::setIntSrc(int idx, uint64_t val)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] Int being set "
"to %#x.\n", threadNumber, seqNum, idx, val);
instSrc[idx].intVal = val;
}
/** Records an fp register being set to a value. */
void
InOrderDynInst::setFloatSrc(int idx, FloatReg val)
{
instSrc[idx].fpVal.f = val;
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FP being set "
"to %x, %08f...%08f\n", threadNumber, seqNum, idx,
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
}
/** Records an fp register being set to an integer value. */
void
InOrderDynInst::setFloatRegBitsSrc(int idx, FloatRegBits val)
{
instSrc[idx].fpVal.i = val;
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being set "
"to %x, %08f...%x\n", threadNumber, seqNum, idx,
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f, val);
}
/** Reads a integer register. */
IntReg
InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, ThreadID tid)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] IntVal read as %#x.\n",
threadNumber, seqNum, idx, instSrc[idx].intVal);
return instSrc[idx].intVal;
}
/** Reads a FP register. */
FloatReg
InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPVal being read "
"as %x, %08f.\n", threadNumber, seqNum, idx,
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
return instSrc[idx].fpVal.f;
}
/** Reads a FP register as a integer. */
FloatRegBits
InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] [src:%i] FPBits being read "
"as %x, %08f.\n", threadNumber, seqNum, idx,
instSrc[idx].fpVal.i, instSrc[idx].fpVal.f);
return instSrc[idx].fpVal.i;
}
/** Reads a miscellaneous register. */
MiscReg
InOrderDynInst::readMiscReg(int misc_reg)
{
return this->cpu->readMiscReg(misc_reg, threadNumber);
}
/** Reads a misc. register, including any side-effects the read
* might have as defined by the architecture.
*/
MiscReg
InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx)
{
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Misc. Reg Source Value %i"
" read as %#x.\n", threadNumber, seqNum, idx,
instSrc[idx].intVal);
return instSrc[idx].intVal;
}
/** Sets a misc. register, including any side-effects the write
* might have as defined by the architecture.
*/
void
InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
const MiscReg &val)
{
instResult[idx].type = Integer;
instResult[idx].res.intVal = val;
instResult[idx].tick = curTick();
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Misc Reg. Operand %i "
"being set to %#x.\n", threadNumber, seqNum, idx, val);
}
MiscReg
InOrderDynInst::readRegOtherThread(unsigned reg_idx, ThreadID tid)
{
if (tid == -1) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
}
if (reg_idx < FP_Base_DepTag) { // Integer Register File
return this->cpu->readIntReg(reg_idx, tid);
} else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
reg_idx -= FP_Base_DepTag;
return this->cpu->readFloatRegBits(reg_idx, tid);
} else {
reg_idx -= Ctrl_Base_DepTag;
return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File
}
}
/** Sets a Integer register. */
void
InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
instResult[idx].type = Integer;
instResult[idx].res.intVal = val;
instResult[idx].tick = curTick();
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting Result Int Reg. %i "
"being set to %#x (result-tick:%i).\n",
threadNumber, seqNum, idx, val, instResult[idx].tick);
}
/** Sets a FP register. */
void
InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
{
instResult[idx].type = Float;
instResult[idx].res.fpVal.f = val;
instResult[idx].tick = curTick();
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. %i "
"being set to %#x, %08f (result-tick:%i).\n",
threadNumber, seqNum, idx, val, val, instResult[idx].tick);
}
/** Sets a FP register as a integer. */
void
InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
FloatRegBits val)
{
instResult[idx].type = FloatBits;
instResult[idx].res.fpVal.i = val;
instResult[idx].tick = curTick();
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Result Float Reg. Bits %i "
"being set to %#x (result-tick:%i).\n",
threadNumber, seqNum, idx, val, instResult[idx].tick);
}
/** Sets a misc. register, including any side-effects the write
* might have as defined by the architecture.
*/
/* Alter this if/when wanting to *speculate* on Miscellaneous registers */
void
InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
{
this->cpu->setMiscReg(misc_reg, val, threadNumber);
}
void
InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
ThreadID tid)
{
if (tid == InvalidThreadID) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
}
if (reg_idx < FP_Base_DepTag) { // Integer Register File
this->cpu->setIntReg(reg_idx, val, tid);
} else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
reg_idx -= FP_Base_DepTag;
this->cpu->setFloatRegBits(reg_idx, val, tid);
} else {
reg_idx -= Ctrl_Base_DepTag;
this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File
}
}
void
InOrderDynInst::deallocateContext(int thread_num)
{
this->cpu->deallocateContext(thread_num);
}
Fault
InOrderDynInst::readMem(Addr addr, uint8_t *data,
unsigned size, unsigned flags)
{
return cpu->read(this, addr, data, size, flags);
}
Fault
InOrderDynInst::writeMem(uint8_t *data, unsigned size,
Addr addr, unsigned flags, uint64_t *res)
{
return cpu->write(this, data, size, addr, flags, res);
}
void
InOrderDynInst::dump()
{
cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
cout << staticInst->disassemble(pc.instAddr());
cprintf("'\n");
}
void
InOrderDynInst::dump(std::string &outstring)
{
std::ostringstream s;
s << "T" << threadNumber << " : " << pc << " "
<< staticInst->disassemble(pc.instAddr());
outstring = s.str();
}