AlphaFault *reset = new ResetFault;
- tc->setPC(tc->readMiscRegNoEffect(IPR_PAL_BASE) + reset->vect());
- tc->setNextPC(tc->readPC() + sizeof(MachInst));
+ tc->pcState(tc->readMiscRegNoEffect(IPR_PAL_BASE) + reset->vect());
delete reset;
}
Fault
SimpleThread::hwrei()
{
- if (!(readPC() & 0x3))
+ PCState pc = pcState();
+ if (!(pc.pc() & 0x3))
return new UnimplementedOpcodeFault;
- setNextPC(readMiscRegNoEffect(IPR_EXC_ADDR));
+ pc.npc(readMiscRegNoEffect(IPR_EXC_ADDR));
+ pcState(pc);
- CPA::cpa()->swAutoBegin(tc, readNextPC());
+ CPA::cpa()->swAutoBegin(tc, pc.npc());
if (!misspeculating()) {
if (kernelStats)
FaultBase::invoke(tc);
countStat()++;
+ PCState pc = tc->pcState();
+
// exception restart address
- if (setRestartAddress() || !(tc->readPC() & 0x3))
- tc->setMiscRegNoEffect(IPR_EXC_ADDR, tc->readPC());
+ if (setRestartAddress() || !(pc.pc() & 0x3))
+ tc->setMiscRegNoEffect(IPR_EXC_ADDR, pc.pc());
if (skipFaultingInstruction()) {
// traps... skip faulting instruction.
tc->readMiscRegNoEffect(IPR_EXC_ADDR) + 4);
}
- tc->setPC(tc->readMiscRegNoEffect(IPR_PAL_BASE) + vect());
- tc->setNextPC(tc->readPC() + sizeof(MachInst));
+ pc.set(tc->readMiscRegNoEffect(IPR_PAL_BASE) + vect());
+ tc->pcState(pc);
}
void
bool
checkInterrupts(ThreadContext *tc) const
{
- return (intstatus != 0) && !(tc->readPC() & 0x3);
+ return (intstatus != 0) && !(tc->pcState().pc() & 0x3);
}
Fault
{
}
- Addr branchTarget(Addr branchPC) const;
+ AlphaISA::PCState branchTarget(const AlphaISA::PCState &branchPC) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
{
}
- Addr branchTarget(ThreadContext *tc) const;
+ AlphaISA::PCState branchTarget(ThreadContext *tc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
}};
output decoder {{
- Addr
- Branch::branchTarget(Addr branchPC) const
+ AlphaISA::PCState
+ Branch::branchTarget(const AlphaISA::PCState &branchPC) const
{
- return branchPC + 4 + disp;
+ return branchPC.pc() + 4 + disp;
}
- Addr
+ AlphaISA::PCState
Jump::branchTarget(ThreadContext *tc) const
{
- Addr NPC = tc->readPC() + 4;
+ PCState pc = tc->pcState();
uint64_t Rb = tc->readIntReg(_srcRegIdx[0]);
- return (Rb & ~3) | (NPC & 1);
+ pc.set((Rb & ~3) | (pc.pc() & 1));
+ return pc;
}
const std::string &
}};
def format CondBranch(code) {{
- code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
+ code = '''
+ bool cond;
+ %(code)s;
+ PCState pc = PCS;
+ if (cond)
+ pc.npc(pc.npc() + disp);
+ PCS = pc;
+ ''' % { "code" : code }
iop = InstObjParams(name, Name, 'Branch', code,
('IsDirectControl', 'IsCondControl'))
header_output = BasicDeclare.subst(iop)
let {{
def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
# Declare basic control transfer w/o link (i.e. link reg is R31)
- nolink_code = 'NPC = %s;\n' % npc_expr
- nolink_iop = InstObjParams(name, Name, base_class, nolink_code, flags)
+ readpc_code = 'PCState pc = PCS;'
+ nolink_code = 'pc.npc(%s);\nPCS = pc' % npc_expr
+ nolink_iop = InstObjParams(name, Name, base_class,
+ readpc_code + nolink_code, flags)
header_output = BasicDeclare.subst(nolink_iop)
decoder_output = BasicConstructor.subst(nolink_iop)
exec_output = BasicExecute.subst(nolink_iop)
# Generate declaration of '*AndLink' version, append to decls
- link_code = 'Ra = NPC & ~3;\n' + nolink_code
+ link_code = 'Ra = pc.npc() & ~3;\n' + nolink_code
link_iop = InstObjParams(name, Name + 'AndLink', base_class,
- link_code, flags)
+ readpc_code + link_code, flags)
header_output += BasicDeclare.subst(link_iop)
decoder_output += BasicConstructor.subst(link_iop)
exec_output += BasicExecute.subst(link_iop)
def format UncondBranch(*flags) {{
flags += ('IsUncondControl', 'IsDirectControl')
(header_output, decoder_output, decode_block, exec_output) = \
- UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
+ UncondCtrlBase(name, Name, 'Branch', 'pc.npc() + disp', flags)
}};
def format Jump(*flags) {{
flags += ('IsUncondControl', 'IsIndirectControl')
(header_output, decoder_output, decode_block, exec_output) = \
- UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
+ UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (pc.npc() & 1)', flags)
}};
// invalid pal function code, or attempt to do privileged
// PAL call in non-kernel mode
fault = new UnimplementedOpcodeFault;
- }
- else {
+ } else {
// check to see if simulator wants to do something special
// on this PAL call (including maybe suppress it)
bool dopal = xc->simPalCheck(palFunc);
if (dopal) {
- xc->setMiscReg(IPR_EXC_ADDR, NPC);
- NPC = xc->readMiscReg(IPR_PAL_BASE) + palOffset;
+ PCState pc = PCS;
+ xc->setMiscReg(IPR_EXC_ADDR, pc.npc());
+ pc.npc(xc->readMiscReg(IPR_PAL_BASE) + palOffset);
+ PCS = pc;
}
}
}}, IsNonSpeculative);
}}, IsNonSpeculative);
#endif
0x54: m5panic({{
- panic("M5 panic instruction called at pc=%#x.", xc->readPC());
+ panic("M5 panic instruction called at pc=%#x.",
+ xc->pcState().pc());
}}, IsNonSpeculative);
#define CPANN(lbl) CPA::cpa()->lbl(xc->tcBase())
0x55: decode RA {
0x00: m5a_old({{
panic("Deprecated M5 annotate instruction executed at pc=%#x\n",
- xc->readPC());
+ xc->pcState().pc());
}}, IsNonSpeculative);
0x01: m5a_bsm({{
CPANN(swSmBegin);
#include <iomanip>
#include "arch/alpha/faults.hh"
+#include "arch/alpha/types.hh"
#include "config/ss_compatible_fp.hh"
#include "cpu/static_inst.hh"
#include "mem/request.hh" // some constructors use MemReq flags
'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2),
'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3),
'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4),
- 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4),
+ 'PCS': ('PCState', 'uq', None, ( None, None, 'IsControl' ), 4),
'Runiq': ('ControlReg', 'uq', 'MISCREG_UNIQ', None, 1),
'FPCR': ('ControlReg', 'uq', 'MISCREG_FPCR', None, 1),
'IntrFlag': ('ControlReg', 'uq', 'MISCREG_INTR', None, 1),
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ void
+ advancePC(AlphaISA::PCState &pcState) const
+ {
+ pcState.advance();
+ }
};
}};
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
- moreBytes(Addr pc, Addr fetchPC, MachInst inst)
+ moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
ext_inst = inst;
#if FULL_SYSTEM
- ext_inst |= (static_cast<ExtMachInst>(pc & 0x1) << 32);
+ ext_inst |= (static_cast<ExtMachInst>(pc.pc() & 0x1) << 32);
#endif
}
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
- getExtMachInst()
+ getExtMachInst(PCState &pc)
{
return ext_inst;
}
setSyscallArg(tc, 1, argv_array_base);
tc->setIntReg(StackPointerReg, stack_min);
- Addr prog_entry = objFile->entryPoint();
- tc->setPC(prog_entry);
- tc->setNextPC(prog_entry + sizeof(MachInst));
-
- // MIPS/Sparc need NNPC for delay slot handling, while
- // Alpha has no delay slots... However, CPU models
- // cycle PCs by PC=NPC, NPC=NNPC, etc. so setting this
- // here ensures CPU-Model Compatibility across board
- tc->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ tc->pcState(objFile->entryPoint());
}
void
{
memset(gdbregs.regs, 0, gdbregs.bytes());
- gdbregs.regs[KGDB_REG_PC] = context->readPC();
+ gdbregs.regs[KGDB_REG_PC] = context->pcState().pc();
// @todo: Currently this is very Alpha specific.
if (PcPAL(gdbregs.regs[KGDB_REG_PC])) {
context->setFloatRegBits(i, gdbregs.regs[i + KGDB_REG_F0]);
}
#endif
- context->setPC(gdbregs.regs[KGDB_REG_PC]);
+ context->pcState(gdbregs.regs[KGDB_REG_PC]);
}
void
void
RemoteGDB::setSingleStep()
{
- Addr pc = context->readPC();
- Addr npc, bpc;
+ PCState pc = context->pcState();
+ PCState bpc;
bool set_bt = false;
- npc = pc + sizeof(MachInst);
-
// User was stopped at pc, e.g. the instruction at pc was not
// executed.
- MachInst inst = read<MachInst>(pc);
- StaticInstPtr si(inst, pc);
+ MachInst inst = read<MachInst>(pc.pc());
+ StaticInstPtr si(inst, pc.pc());
if (si->hasBranchTarget(pc, context, bpc)) {
// Don't bother setting a breakpoint on the taken branch if it
// is the same as the next pc
- if (bpc != npc)
+ if (bpc.pc() != pc.npc())
set_bt = true;
}
DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
takenBkpt, notTakenBkpt);
- setTempBreakpoint(notTakenBkpt = npc);
+ setTempBreakpoint(notTakenBkpt = pc.npc());
if (set_bt)
- setTempBreakpoint(takenBkpt = bpc);
+ setTempBreakpoint(takenBkpt = bpc.pc());
}
// Write bytes to kernel address space for debugger.
bool usermode =
(tc->readMiscRegNoEffect(IPR_DTB_CM) & 0x18) != 0;
- Addr pc = tc->readNextPC();
+ Addr pc = tc->pcState().pc();
bool kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd;
if (usermode) {
panic("could not find address %#x", pc);
stack.push_back(addr);
- pc = tc->readPC();
+ pc = tc->pcState().pc();
}
while (ksp > bottom) {
Fault
TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
{
- Addr pc = tc->readPC();
-
mode_type mode =
(mode_type)DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM));
return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags);
}
- if (PcPAL(pc)) {
+ if (PcPAL(tc->pcState().pc())) {
mode = (req->getFlags() & Request::ALTMODE) ?
(mode_type)ALT_MODE_AM(
tc->readMiscRegNoEffect(IPR_ALT_MODE))
#define __ARCH_ALPHA_TYPES_HH__
#include "base/types.hh"
+#include "arch/generic/types.hh"
namespace AlphaISA {
typedef uint32_t MachInst;
typedef uint64_t ExtMachInst;
+typedef GenericISA::SimplePCState<MachInst> PCState;
+
typedef uint64_t LargestRead;
enum annotes
copyMiscRegs(src, dest);
// Lastly copy PC/NPC
- dest->setPC(src->readPC());
- dest->setNextPC(src->readNextPC());
+ dest->pcState(src->pcState());
}
void
void
skipFunction(ThreadContext *tc)
{
- Addr newpc = tc->readIntReg(ReturnAddressReg);
- tc->setPC(newpc);
- tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst));
+ TheISA::PCState newPC = tc->pcState();
+ newPC.set(tc->readIntReg(ReturnAddressReg));
+ tc->pcState(newPC);
}
#include "arch/alpha/registers.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
+#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
namespace AlphaISA {
+inline PCState
+buildRetPC(const PCState &curPC, const PCState &callPC)
+{
+ PCState retPC = callPC;
+ retPC.advance();
+ return retPC;
+}
+
uint64_t getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp);
inline bool
void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
void skipFunction(ThreadContext *tc);
+
+inline void
+advancePC(PCState &pc, const StaticInstPtr inst)
+{
+ pc.advance();
+}
+
} // namespace AlphaISA
#endif // __ARCH_ALPHA_UTILITY_HH__
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
CPSR saved_cpsr = tc->readMiscReg(MISCREG_CPSR) |
tc->readIntReg(INTREG_CONDCODES);
+ Addr curPc M5_VAR_USED = tc->pcState().pc();
cpsr.mode = nextMode();
cpsr.i = 1;
cpsr.e = sctlr.ee;
tc->setMiscReg(MISCREG_CPSR, cpsr);
- tc->setIntReg(INTREG_LR, tc->readPC() +
+ tc->setIntReg(INTREG_LR, curPc +
(saved_cpsr.t ? thumbPcOffset() : armPcOffset()));
switch (nextMode()) {
panic("unknown Mode\n");
}
- Addr pc M5_VAR_USED = tc->readPC();
- Addr newPc = getVector(tc) | (sctlr.te ? PcTBit : 0);
+ Addr newPc = getVector(tc);
DPRINTF(Faults, "Invoking Fault:%s cpsr:%#x PC:%#x lr:%#x newVec: %#x\n",
- name(), cpsr, pc, tc->readIntReg(INTREG_LR), newPc);
- tc->setPC(newPc);
- tc->setNextPC(newPc + cpsr.t ? 2 : 4 );
- tc->setMicroPC(0);
- tc->setNextMicroPC(1);
+ name(), cpsr, curPc, tc->readIntReg(INTREG_LR), newPc);
+ PCState pc(newPc);
+ pc.thumb(cpsr.t);
+ pc.nextThumb(pc.thumb());
+ pc.jazelle(cpsr.j);
+ pc.nextJazelle(pc.jazelle());
+ tc->pcState(pc);
}
void
tc->syscall(callNum);
// Advance the PC since that won't happen automatically.
- tc->setPC(tc->readNextPC());
- tc->setNextPC(tc->readNextNPC());
- tc->setMicroPC(0);
- tc->setNextMicroPC(1);
+ PCState pc = tc->pcState();
+ assert(inst);
+ inst->advancePC(pc);
+ tc->pcState(pc);
}
#endif // FULL_SYSTEM
// Set the PC to the next instruction of the faulting instruction.
// Net effect is simply squashing all instructions behind and
// start refetching from the next instruction.
- tc->setPC(tc->readNextPC());
- tc->setNextPC(tc->readNextNPC());
- tc->setMicroPC(0);
- tc->setNextMicroPC(1);
+ PCState pc = tc->pcState();
+ assert(inst);
+ inst->advancePC(pc);
+ tc->pcState(pc);
}
template void AbortFault<PrefetchAbort>::invoke(ThreadContext *tc,
{
flags[IsDelayedCommit] = true;
}
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ if (flags[IsLastMicroop]) {
+ pcState.uEnd();
+ } else if (flags[IsMicroop]) {
+ pcState.uAdvance();
+ } else {
+ pcState.advance();
+ }
+ }
};
/**
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
+class MightBeMicro : public PredOp
+{
+ protected:
+ MightBeMicro(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
+ : PredOp(mnem, _machInst, __opClass)
+ {}
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ if (flags[IsLastMicroop]) {
+ pcState.uEnd();
+ } else if (flags[IsMicroop]) {
+ pcState.uAdvance();
+ } else {
+ pcState.advance();
+ }
+ }
+};
+
// The address is a base register plus an immediate.
-class RfeOp : public PredOp
+class RfeOp : public MightBeMicro
{
public:
enum AddrMode {
RfeOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _base, AddrMode _mode, bool _wb)
- : PredOp(mnem, _machInst, __opClass),
+ : MightBeMicro(mnem, _machInst, __opClass),
base(_base), mode(_mode), wb(_wb), uops(NULL)
{}
}
StaticInstPtr
- fetchMicroop(MicroPC microPC)
+ fetchMicroop(MicroPC microPC) const
{
assert(uops != NULL && microPC < numMicroops);
return uops[microPC];
};
// The address is a base register plus an immediate.
-class SrsOp : public PredOp
+class SrsOp : public MightBeMicro
{
public:
enum AddrMode {
SrsOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
uint32_t _regMode, AddrMode _mode, bool _wb)
- : PredOp(mnem, _machInst, __opClass),
+ : MightBeMicro(mnem, _machInst, __opClass),
regMode(_regMode), mode(_mode), wb(_wb), uops(NULL)
{}
}
StaticInstPtr
- fetchMicroop(MicroPC microPC)
+ fetchMicroop(MicroPC microPC) const
{
assert(uops != NULL && microPC < numMicroops);
return uops[microPC];
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
-class Memory : public PredOp
+class Memory : public MightBeMicro
{
public:
enum AddrMode {
Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _dest, IntRegIndex _base, bool _add)
- : PredOp(mnem, _machInst, __opClass),
+ : MightBeMicro(mnem, _machInst, __opClass),
dest(_dest), base(_base), add(_add), uops(NULL)
{}
}
StaticInstPtr
- fetchMicroop(MicroPC microPC)
+ fetchMicroop(MicroPC microPC) const
{
assert(uops != NULL && microPC < numMicroops);
return uops[microPC];
}
StaticInstPtr
- fetchMicroop(MicroPC microPC)
+ fetchMicroop(MicroPC microPC) const
{
assert(microPC < numMicroops);
return microOps[microPC];
{
flags[IsMicroop] = true;
}
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ if (flags[IsLastMicroop])
+ pcState.uEnd();
+ else
+ pcState.uAdvance();
+ }
};
}
IntRegIndex rs, uint32_t shiftAmt, ArmShiftType type,
uint32_t imm) const;
+ void
+ advancePC(PCState &pcState) const
+ {
+ pcState.advance();
+ }
+
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
static inline uint32_t
static inline Addr
readPC(XC *xc)
{
- Addr pc = xc->readPC();
- if (isThumb(pc))
- return pc + 4;
- else
- return pc + 8;
+ return xc->pcState().instPC();
}
- // Perform an regular branch.
template<class XC>
static inline void
setNextPC(XC *xc, Addr val)
{
- Addr npc = xc->readNextPC();
- if (isThumb(npc)) {
- val &= ~mask(1);
- } else {
- val &= ~mask(2);
- }
- xc->setNextPC((npc & PcModeMask) |
- (val & ~PcModeMask));
+ PCState pc = xc->pcState();
+ pc.instNPC(val);
+ xc->pcState(pc);
}
template<class T>
static inline void
setIWNextPC(XC *xc, Addr val)
{
- Addr stateBits = xc->readPC() & PcModeMask;
- Addr jBit = PcJBit;
- Addr tBit = PcTBit;
- bool thumbEE = (stateBits == (tBit | jBit));
-
- Addr newPc = (val & ~PcModeMask);
- if (thumbEE) {
- if (bits(newPc, 0)) {
- newPc = newPc & ~mask(1);
- } else {
- panic("Bad thumbEE interworking branch address %#x.\n", newPc);
- }
- } else {
- if (bits(newPc, 0)) {
- stateBits = tBit;
- newPc = newPc & ~mask(1);
- } else if (!bits(newPc, 1)) {
- stateBits = 0;
- } else {
- warn("Bad interworking branch address %#x.\n", newPc);
- }
- }
- newPc = newPc | stateBits;
- xc->setNextPC(newPc);
+ PCState pc = xc->pcState();
+ pc.instIWNPC(val);
+ xc->pcState(pc);
}
// Perform an interworking branch in ARM mode, a regular branch
static inline void
setAIWNextPC(XC *xc, Addr val)
{
- Addr stateBits = xc->readPC() & PcModeMask;
- Addr jBit = PcJBit;
- Addr tBit = PcTBit;
- if (!jBit && !tBit) {
- setIWNextPC(xc, val);
- } else {
- setNextPC(xc, val);
- }
+ PCState pc = xc->pcState();
+ pc.instAIWNPC(val);
+ xc->pcState(pc);
}
inline Fault
unaryOp(FPSCR &fpscr, fpType op1,
fpType (*func)(fpType),
bool flush, uint32_t rMode) const;
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ if (flags[IsLastMicroop]) {
+ pcState.uEnd();
+ } else if (flags[IsMicroop]) {
+ pcState.uAdvance();
+ } else {
+ pcState.advance();
+ }
+ }
};
class FpRegRegOp : public FpOp
{
if (misc_reg == MISCREG_CPSR) {
CPSR cpsr = miscRegs[misc_reg];
- Addr pc = tc->readPC();
- if (pc & (ULL(1) << PcJBitShift))
- cpsr.j = 1;
- else
- cpsr.j = 0;
- if (isThumb(pc))
- cpsr.t = 1;
- else
- cpsr.t = 0;
+ PCState pc = tc->pcState();
+ cpsr.j = pc.jazelle() ? 1 : 0;
+ cpsr.t = pc.thumb() ? 1 : 0;
return cpsr;
}
if (misc_reg >= MISCREG_CP15_UNIMP_START &&
CPSR cpsr = val;
DPRINTF(Arm, "Updating CPSR from %#x to %#x f:%d i:%d a:%d mode:%#x\n",
miscRegs[misc_reg], cpsr, cpsr.f, cpsr.i, cpsr.a, cpsr.mode);
- Addr npc = tc->readNextPC() & ~PcModeMask;
- if (cpsr.j)
- npc = npc | PcJBit;
- if (cpsr.t)
- npc = npc | PcTBit;
-
- tc->setNextPC(npc);
+ PCState pc = tc->pcState();
+ pc.nextThumb(cpsr.t);
+ pc.nextJazelle(cpsr.j);
+ tc->pcState(pc);
} else if (misc_reg >= MISCREG_CP15_UNIMP_START &&
misc_reg < MISCREG_CP15_END) {
panic("Unimplemented CP15 register %s wrote with %#x.\n",
default:
panic("Security Extensions not implemented!");
}
- req->setVirt(0, val, 1, flags, tc->readPC());
+ req->setVirt(0, val, 1, flags, tc->pcState().pc());
fault = tc->getDTBPtr()->translateAtomic(req, tc, mode);
if (fault == NoFault) {
miscRegs[MISCREG_PAR] =
Breakpoint::execute(%(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const
{
- return new PrefetchAbort(xc->readPC(), ArmFault::DebugEvent);
+ return new PrefetchAbort(xc->pcState().pc(), ArmFault::DebugEvent);
}
}};
# B, BL
for (mnem, link) in (("b", False), ("bl", True)):
bCode = '''
- Addr curPc = readPC(xc);
- NPC = ((curPc + imm) & mask(32)) | (curPc & ~mask(32));
+ ArmISA::PCState pc = PCS;
+ Addr curPc = pc.instPC();
+ pc.instNPC((uint32_t)(curPc + imm));
+ PCS = pc;
'''
if (link):
bCode += '''
- if (!isThumb(curPc))
- LR = curPc - 4;
- else
+ if (pc.thumb())
LR = curPc | 1;
+ else
+ LR = curPc - 4;
'''
bIop = InstObjParams(mnem, mnem.capitalize(), "BranchImmCond",
# BX, BLX
blxCode = '''
- Addr curPc M5_VAR_USED = readPC(xc);
+ ArmISA::PCState pc = PCS;
+ Addr curPc M5_VAR_USED = pc.instPC();
%(link)s
// Switch modes
%(branch)s
+ PCS = pc;
'''
blxList = (("blx", True, True),
if imm:
Name += "Imm"
# Since we're switching ISAs, the target ISA will be the opposite
- # of the current ISA. !arm is whether the target is ARM.
- newPC = '(isThumb(curPc) ? (roundDown(curPc, 4) + imm) : (curPc + imm))'
+ # of the current ISA. pc.thumb() is whether the target is ARM.
+ newPC = '(pc.thumb() ? (roundDown(curPc, 4) + imm) : (curPc + imm))'
base = "BranchImmCond"
declare = BranchImmCondDeclare
constructor = BranchImmCondConstructor
// The immediate version of the blx thumb instruction
// is 32 bits wide, but "next pc" doesn't reflect that
// so we don't want to substract 2 from it at this point
- if (!isThumb(curPc))
- LR = curPc - 4;
- else
+ if (pc.thumb())
LR = curPc | 1;
+ else
+ LR = curPc - 4;
'''
elif link:
linkStr = '''
- if (!isThumb(curPc))
- LR = curPc - 4;
- else
+ if (pc.thumb())
LR = (curPc - 2) | 1;
+ else
+ LR = curPc - 4;
'''
else:
linkStr = ""
if imm and link: #blx with imm
branchStr = '''
- Addr tempPc = ((%(newPC)s) & mask(32)) | (curPc & ~mask(32));
- FNPC = tempPc ^ PcTBit;
+ pc.nextThumb(!pc.thumb());
+ pc.instNPC(%(newPC)s);
'''
else:
- branchStr = "IWNPC = %(newPC)s;"
+ branchStr = "pc.instIWNPC(%(newPC)s);"
branchStr = branchStr % { "newPC" : newPC }
code = blxCode % {"link": linkStr,
#CBNZ, CBZ. These are always unconditional as far as predicates
for (mnem, test) in (("cbz", "=="), ("cbnz", "!=")):
code = '''
- Addr curPc = readPC(xc);
- NPC = ((curPc + imm) & mask(32)) | (curPc & ~mask(32));
+ ArmISA::PCState pc = PCS;
+ Addr curPc = pc.instPC();
+ pc.instNPC((uint32_t)(curPc + imm));
+ PCS = pc;
'''
predTest = "Op1 %(test)s 0" % {"test": test}
iop = InstObjParams(mnem, mnem.capitalize(), "BranchImmReg",
ArmISA::TLB::MustBeOne;
EA = Op1 + Op2 * 2
'''
- accCode = "NPC = readPC(xc) + 2 * (Mem.uh);"
+ accCode = '''
+ ArmISA::PCState pc = PCS;
+ pc.instNPC(pc.instPC() + 2 * (Mem.uh));
+ PCS = pc;
+ '''
mnem = "tbh"
else:
eaCode = '''
ArmISA::TLB::MustBeOne;
EA = Op1 + Op2
'''
- accCode = "NPC = readPC(xc) + 2 * (Mem.ub);"
+ accCode = '''
+ ArmISA::PCState pc = PCS;
+ pc.instNPC(pc.instPC() + 2 * (Mem.ub));
+ PCS = pc;
+ '''
mnem = "tbb"
iop = InstObjParams(mnem, mnem.capitalize(), "BranchRegReg",
{'ea_code': eaCode,
cpsrWriteByInstr(Cpsr | CondCodes, Spsr, 0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
+ ArmISA::PCState pc = PCS;
+ pc.nextThumb(((CPSR)newCpsr).t);
+ pc.nextJazelle(((CPSR)newCpsr).j);
+ PCS = pc;
'''
buildImmDataInst(mnem + 's', code, flagType,
suffix = "ImmPclr", buildCc = False,
buildDataInst("rsb", "Dest = resTemp = secondOp - Op1;", "rsb")
buildDataInst("add", "Dest = resTemp = Op1 + secondOp;", "add")
buildImmDataInst("adr", '''
- Dest = resTemp = (readPC(xc) & ~0x3) +
+ ArmISA::PCState pc = PCS;
+ Dest = resTemp = (pc.instPC() & ~0x3) +
(op1 ? secondOp : -secondOp);
''')
buildDataInst("adc", "Dest = resTemp = Op1 + secondOp + %s;" % oldC, "add")
accCode = '''
CPSR cpsr = Cpsr;
SCTLR sctlr = Sctlr;
- NPC = cSwap<uint32_t>(Mem.ud, cpsr.e);
+ ArmISA::PCState pc = PCS;
+ pc.instNPC(cSwap<uint32_t>(Mem.ud, cpsr.e));
uint32_t newCpsr =
cpsrWriteByInstr(cpsr | CondCodes,
cSwap<uint32_t>(Mem.ud >> 32, cpsr.e),
0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
+ pc.nextThumb(((CPSR)newCpsr).t);
+ pc.nextJazelle(((CPSR)newCpsr).j);
+ PCS = pc;
CondCodes = CondCodesMask & newCpsr;
'''
self.codeBlobs["memacc_code"] = accCode
cpsrWriteByInstr(cpsr | CondCodes, Spsr, 0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
- IWNPC = cSwap(Mem.uw, cpsr.e) | ((Spsr & 0x20) ? 1 : 0);
+ ArmISA::PCState pc = PCS;
+ pc.instIWNPC(cSwap(Mem.uw, cpsr.e) | ((Spsr & 0x20) ? 1 : 0));
+ PCS = pc;
'''
microLdrRetUopIop = InstObjParams('ldr_ret_uop', 'MicroLdrRetUop',
'MicroMemOp',
uint32_t newCpsr =
cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
+ ArmISA::PCState pc = PCS;
+ pc.nextThumb(((CPSR)newCpsr).t);
+ pc.nextJazelle(((CPSR)newCpsr).j);
+ PCS = pc;
CondCodes = CondCodesMask & newCpsr;
'''
msrCpsrRegIop = InstObjParams("msr", "MsrCpsrReg", "MsrRegOp",
uint32_t newCpsr =
cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
+ ArmISA::PCState pc = PCS;
+ pc.nextThumb(((CPSR)newCpsr).t);
+ pc.nextJazelle(((CPSR)newCpsr).j);
+ PCS = pc;
CondCodes = CondCodesMask & newCpsr;
'''
msrCpsrImmIop = InstObjParams("msr", "MsrCpsrImm", "MsrImmOp",
decoder_output += RegRegRegRegOpConstructor.subst(usada8Iop)
exec_output += PredOpExecute.subst(usada8Iop)
+ bkptCode = '''
+ ArmISA::PCState pc = PCS;
+ return new PrefetchAbort(pc.pc(), ArmFault::DebugEvent);
+ '''
bkptIop = InstObjParams("bkpt", "BkptInst", "ArmStaticInst",
- "return new PrefetchAbort(PC, ArmFault::DebugEvent);")
+ bkptCode)
header_output += BasicDeclare.subst(bkptIop)
decoder_output += BasicConstructor.subst(bkptIop)
exec_output += BasicExecute.subst(bkptIop)
exec_output += PredOpExecute.subst(mcr15UserIop)
enterxCode = '''
- FNPC = NPC | PcJBit | PcTBit;
+ ArmISA::PCState pc = PCS;
+ pc.nextThumb(true);
+ pc.nextJazelle(true);
+ PCS = pc;
'''
enterxIop = InstObjParams("enterx", "Enterx", "PredOp",
{ "code": enterxCode,
exec_output += PredOpExecute.subst(enterxIop)
leavexCode = '''
- FNPC = (NPC & ~PcJBit) | PcTBit;
+ ArmISA::PCState pc = PCS;
+ pc.nextThumb(true);
+ pc.nextJazelle(false);
+ PCS = pc;
'''
leavexIop = InstObjParams("leavex", "Leavex", "PredOp",
{ "code": leavexCode,
let {{
maybePCRead = '''
- ((%(reg_idx)s == PCReg) ? (readPC(xc) & ~PcModeMask) :
- xc->%(func)s(this, %(op_idx)s))
+ ((%(reg_idx)s == PCReg) ? readPC(xc) : xc->%(func)s(this, %(op_idx)s))
'''
maybeAlignedPCRead = '''
- ((%(reg_idx)s == PCReg) ? (roundDown(readPC(xc) & ~PcModeMask, 4)) :
+ ((%(reg_idx)s == PCReg) ? (roundDown(readPC(xc), 4)) :
xc->%(func)s(this, %(op_idx)s))
'''
maybePCWrite = '''
xc->%(func)s(this, %(op_idx)s, %(final_val)s);
}
'''
-
- readNPC = 'xc->readNextPC() & ~PcModeMask'
- writeNPC = 'setNextPC(xc, %(final_val)s)'
- writeIWNPC = 'setIWNextPC(xc, %(final_val)s)'
- forceNPC = 'xc->setNextPC(%(final_val)s)'
}};
def operands {{
#Abstracted integer reg operands
- 'Dest': ('IntReg', 'uw', 'dest', 'IsInteger', 2,
+ 'Dest': ('IntReg', 'uw', 'dest', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'FpDest': ('FloatReg', 'sf', '(dest + 0)', 'IsFloating', 2),
- 'FpDestP0': ('FloatReg', 'sf', '(dest + 0)', 'IsFloating', 2),
- 'FpDestP1': ('FloatReg', 'sf', '(dest + 1)', 'IsFloating', 2),
- 'FpDestP2': ('FloatReg', 'sf', '(dest + 2)', 'IsFloating', 2),
- 'FpDestP3': ('FloatReg', 'sf', '(dest + 3)', 'IsFloating', 2),
- 'FpDestP4': ('FloatReg', 'sf', '(dest + 4)', 'IsFloating', 2),
- 'FpDestP5': ('FloatReg', 'sf', '(dest + 5)', 'IsFloating', 2),
- 'FpDestP6': ('FloatReg', 'sf', '(dest + 6)', 'IsFloating', 2),
- 'FpDestP7': ('FloatReg', 'sf', '(dest + 7)', 'IsFloating', 2),
- 'FpDestS0P0': ('FloatReg', 'sf', '(dest + step * 0 + 0)', 'IsFloating', 2),
- 'FpDestS0P1': ('FloatReg', 'sf', '(dest + step * 0 + 1)', 'IsFloating', 2),
- 'FpDestS1P0': ('FloatReg', 'sf', '(dest + step * 1 + 0)', 'IsFloating', 2),
- 'FpDestS1P1': ('FloatReg', 'sf', '(dest + step * 1 + 1)', 'IsFloating', 2),
- 'FpDestS2P0': ('FloatReg', 'sf', '(dest + step * 2 + 0)', 'IsFloating', 2),
- 'FpDestS2P1': ('FloatReg', 'sf', '(dest + step * 2 + 1)', 'IsFloating', 2),
- 'FpDestS3P0': ('FloatReg', 'sf', '(dest + step * 3 + 0)', 'IsFloating', 2),
- 'FpDestS3P1': ('FloatReg', 'sf', '(dest + step * 3 + 1)', 'IsFloating', 2),
- 'Result': ('IntReg', 'uw', 'result', 'IsInteger', 2,
+ 'FpDest': ('FloatReg', 'sf', '(dest + 0)', 'IsFloating', 3),
+ 'FpDestP0': ('FloatReg', 'sf', '(dest + 0)', 'IsFloating', 3),
+ 'FpDestP1': ('FloatReg', 'sf', '(dest + 1)', 'IsFloating', 3),
+ 'FpDestP2': ('FloatReg', 'sf', '(dest + 2)', 'IsFloating', 3),
+ 'FpDestP3': ('FloatReg', 'sf', '(dest + 3)', 'IsFloating', 3),
+ 'FpDestP4': ('FloatReg', 'sf', '(dest + 4)', 'IsFloating', 3),
+ 'FpDestP5': ('FloatReg', 'sf', '(dest + 5)', 'IsFloating', 3),
+ 'FpDestP6': ('FloatReg', 'sf', '(dest + 6)', 'IsFloating', 3),
+ 'FpDestP7': ('FloatReg', 'sf', '(dest + 7)', 'IsFloating', 3),
+ 'FpDestS0P0': ('FloatReg', 'sf', '(dest + step * 0 + 0)', 'IsFloating', 3),
+ 'FpDestS0P1': ('FloatReg', 'sf', '(dest + step * 0 + 1)', 'IsFloating', 3),
+ 'FpDestS1P0': ('FloatReg', 'sf', '(dest + step * 1 + 0)', 'IsFloating', 3),
+ 'FpDestS1P1': ('FloatReg', 'sf', '(dest + step * 1 + 1)', 'IsFloating', 3),
+ 'FpDestS2P0': ('FloatReg', 'sf', '(dest + step * 2 + 0)', 'IsFloating', 3),
+ 'FpDestS2P1': ('FloatReg', 'sf', '(dest + step * 2 + 1)', 'IsFloating', 3),
+ 'FpDestS3P0': ('FloatReg', 'sf', '(dest + step * 3 + 0)', 'IsFloating', 3),
+ 'FpDestS3P1': ('FloatReg', 'sf', '(dest + step * 3 + 1)', 'IsFloating', 3),
+ 'Result': ('IntReg', 'uw', 'result', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Dest2': ('IntReg', 'uw', 'dest2', 'IsInteger', 2,
+ 'Dest2': ('IntReg', 'uw', 'dest2', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'FpDest2': ('FloatReg', 'sf', '(dest2 + 0)', 'IsFloating', 2),
- 'FpDest2P0': ('FloatReg', 'sf', '(dest2 + 0)', 'IsFloating', 2),
- 'FpDest2P1': ('FloatReg', 'sf', '(dest2 + 1)', 'IsFloating', 2),
- 'FpDest2P2': ('FloatReg', 'sf', '(dest2 + 2)', 'IsFloating', 2),
- 'FpDest2P3': ('FloatReg', 'sf', '(dest2 + 3)', 'IsFloating', 2),
- 'IWDest': ('IntReg', 'uw', 'dest', 'IsInteger', 2,
+ 'FpDest2': ('FloatReg', 'sf', '(dest2 + 0)', 'IsFloating', 3),
+ 'FpDest2P0': ('FloatReg', 'sf', '(dest2 + 0)', 'IsFloating', 3),
+ 'FpDest2P1': ('FloatReg', 'sf', '(dest2 + 1)', 'IsFloating', 3),
+ 'FpDest2P2': ('FloatReg', 'sf', '(dest2 + 2)', 'IsFloating', 3),
+ 'FpDest2P3': ('FloatReg', 'sf', '(dest2 + 3)', 'IsFloating', 3),
+ 'IWDest': ('IntReg', 'uw', 'dest', 'IsInteger', 3,
maybePCRead, maybeIWPCWrite),
- 'AIWDest': ('IntReg', 'uw', 'dest', 'IsInteger', 2,
+ 'AIWDest': ('IntReg', 'uw', 'dest', 'IsInteger', 3,
maybePCRead, maybeAIWPCWrite),
'SpMode': ('IntReg', 'uw',
'intRegInMode((OperatingMode)regMode, INTREG_SP)',
- 'IsInteger', 2),
- 'MiscDest': ('ControlReg', 'uw', 'dest', (None, None, 'IsControl'), 2),
- 'Base': ('IntReg', 'uw', 'base', 'IsInteger', 0,
+ 'IsInteger', 3),
+ 'MiscDest': ('ControlReg', 'uw', 'dest', (None, None, 'IsControl'), 3),
+ 'Base': ('IntReg', 'uw', 'base', 'IsInteger', 1,
maybeAlignedPCRead, maybePCWrite),
- 'Index': ('IntReg', 'uw', 'index', 'IsInteger', 2,
+ 'Index': ('IntReg', 'uw', 'index', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Op1': ('IntReg', 'uw', 'op1', 'IsInteger', 2,
+ 'Op1': ('IntReg', 'uw', 'op1', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'FpOp1': ('FloatReg', 'sf', '(op1 + 0)', 'IsFloating', 2),
- 'FpOp1P0': ('FloatReg', 'sf', '(op1 + 0)', 'IsFloating', 2),
- 'FpOp1P1': ('FloatReg', 'sf', '(op1 + 1)', 'IsFloating', 2),
- 'FpOp1P2': ('FloatReg', 'sf', '(op1 + 2)', 'IsFloating', 2),
- 'FpOp1P3': ('FloatReg', 'sf', '(op1 + 3)', 'IsFloating', 2),
- 'FpOp1P4': ('FloatReg', 'sf', '(op1 + 4)', 'IsFloating', 2),
- 'FpOp1P5': ('FloatReg', 'sf', '(op1 + 5)', 'IsFloating', 2),
- 'FpOp1P6': ('FloatReg', 'sf', '(op1 + 6)', 'IsFloating', 2),
- 'FpOp1P7': ('FloatReg', 'sf', '(op1 + 7)', 'IsFloating', 2),
- 'FpOp1S0P0': ('FloatReg', 'sf', '(op1 + step * 0 + 0)', 'IsFloating', 2),
- 'FpOp1S0P1': ('FloatReg', 'sf', '(op1 + step * 0 + 1)', 'IsFloating', 2),
- 'FpOp1S1P0': ('FloatReg', 'sf', '(op1 + step * 1 + 0)', 'IsFloating', 2),
- 'FpOp1S1P1': ('FloatReg', 'sf', '(op1 + step * 1 + 1)', 'IsFloating', 2),
- 'FpOp1S2P0': ('FloatReg', 'sf', '(op1 + step * 2 + 0)', 'IsFloating', 2),
- 'FpOp1S2P1': ('FloatReg', 'sf', '(op1 + step * 2 + 1)', 'IsFloating', 2),
- 'FpOp1S3P0': ('FloatReg', 'sf', '(op1 + step * 3 + 0)', 'IsFloating', 2),
- 'FpOp1S3P1': ('FloatReg', 'sf', '(op1 + step * 3 + 1)', 'IsFloating', 2),
- 'MiscOp1': ('ControlReg', 'uw', 'op1', (None, None, 'IsControl'), 2),
- 'Op2': ('IntReg', 'uw', 'op2', 'IsInteger', 2,
+ 'FpOp1': ('FloatReg', 'sf', '(op1 + 0)', 'IsFloating', 3),
+ 'FpOp1P0': ('FloatReg', 'sf', '(op1 + 0)', 'IsFloating', 3),
+ 'FpOp1P1': ('FloatReg', 'sf', '(op1 + 1)', 'IsFloating', 3),
+ 'FpOp1P2': ('FloatReg', 'sf', '(op1 + 2)', 'IsFloating', 3),
+ 'FpOp1P3': ('FloatReg', 'sf', '(op1 + 3)', 'IsFloating', 3),
+ 'FpOp1P4': ('FloatReg', 'sf', '(op1 + 4)', 'IsFloating', 3),
+ 'FpOp1P5': ('FloatReg', 'sf', '(op1 + 5)', 'IsFloating', 3),
+ 'FpOp1P6': ('FloatReg', 'sf', '(op1 + 6)', 'IsFloating', 3),
+ 'FpOp1P7': ('FloatReg', 'sf', '(op1 + 7)', 'IsFloating', 3),
+ 'FpOp1S0P0': ('FloatReg', 'sf', '(op1 + step * 0 + 0)', 'IsFloating', 3),
+ 'FpOp1S0P1': ('FloatReg', 'sf', '(op1 + step * 0 + 1)', 'IsFloating', 3),
+ 'FpOp1S1P0': ('FloatReg', 'sf', '(op1 + step * 1 + 0)', 'IsFloating', 3),
+ 'FpOp1S1P1': ('FloatReg', 'sf', '(op1 + step * 1 + 1)', 'IsFloating', 3),
+ 'FpOp1S2P0': ('FloatReg', 'sf', '(op1 + step * 2 + 0)', 'IsFloating', 3),
+ 'FpOp1S2P1': ('FloatReg', 'sf', '(op1 + step * 2 + 1)', 'IsFloating', 3),
+ 'FpOp1S3P0': ('FloatReg', 'sf', '(op1 + step * 3 + 0)', 'IsFloating', 3),
+ 'FpOp1S3P1': ('FloatReg', 'sf', '(op1 + step * 3 + 1)', 'IsFloating', 3),
+ 'MiscOp1': ('ControlReg', 'uw', 'op1', (None, None, 'IsControl'), 3),
+ 'Op2': ('IntReg', 'uw', 'op2', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'FpOp2': ('FloatReg', 'sf', '(op2 + 0)', 'IsFloating', 2),
- 'FpOp2P0': ('FloatReg', 'sf', '(op2 + 0)', 'IsFloating', 2),
- 'FpOp2P1': ('FloatReg', 'sf', '(op2 + 1)', 'IsFloating', 2),
- 'FpOp2P2': ('FloatReg', 'sf', '(op2 + 2)', 'IsFloating', 2),
- 'FpOp2P3': ('FloatReg', 'sf', '(op2 + 3)', 'IsFloating', 2),
- 'Op3': ('IntReg', 'uw', 'op3', 'IsInteger', 2,
+ 'FpOp2': ('FloatReg', 'sf', '(op2 + 0)', 'IsFloating', 3),
+ 'FpOp2P0': ('FloatReg', 'sf', '(op2 + 0)', 'IsFloating', 3),
+ 'FpOp2P1': ('FloatReg', 'sf', '(op2 + 1)', 'IsFloating', 3),
+ 'FpOp2P2': ('FloatReg', 'sf', '(op2 + 2)', 'IsFloating', 3),
+ 'FpOp2P3': ('FloatReg', 'sf', '(op2 + 3)', 'IsFloating', 3),
+ 'Op3': ('IntReg', 'uw', 'op3', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Shift': ('IntReg', 'uw', 'shift', 'IsInteger', 2,
+ 'Shift': ('IntReg', 'uw', 'shift', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Reg0': ('IntReg', 'uw', 'reg0', 'IsInteger', 2,
+ 'Reg0': ('IntReg', 'uw', 'reg0', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Reg1': ('IntReg', 'uw', 'reg1', 'IsInteger', 2,
+ 'Reg1': ('IntReg', 'uw', 'reg1', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Reg2': ('IntReg', 'uw', 'reg2', 'IsInteger', 2,
+ 'Reg2': ('IntReg', 'uw', 'reg2', 'IsInteger', 3,
maybePCRead, maybePCWrite),
- 'Reg3': ('IntReg', 'uw', 'reg3', 'IsInteger', 2,
+ 'Reg3': ('IntReg', 'uw', 'reg3', 'IsInteger', 3,
maybePCRead, maybePCWrite),
#General Purpose Integer Reg Operands
- 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 2, maybePCRead, maybePCWrite),
- 'Rm': ('IntReg', 'uw', 'RM', 'IsInteger', 2, maybePCRead, maybePCWrite),
- 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 2, maybePCRead, maybePCWrite),
- 'Rn': ('IntReg', 'uw', 'RN', 'IsInteger', 2, maybePCRead, maybePCWrite),
- 'R7': ('IntReg', 'uw', '7', 'IsInteger', 2),
- 'R0': ('IntReg', 'uw', '0', 'IsInteger', 2),
+ 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 3, maybePCRead, maybePCWrite),
+ 'Rm': ('IntReg', 'uw', 'RM', 'IsInteger', 3, maybePCRead, maybePCWrite),
+ 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 3, maybePCRead, maybePCWrite),
+ 'Rn': ('IntReg', 'uw', 'RN', 'IsInteger', 3, maybePCRead, maybePCWrite),
+ 'R7': ('IntReg', 'uw', '7', 'IsInteger', 3),
+ 'R0': ('IntReg', 'uw', '0', 'IsInteger', 3),
- 'LR': ('IntReg', 'uw', 'INTREG_LR', 'IsInteger', 2),
- 'CondCodes': ('IntReg', 'uw', 'INTREG_CONDCODES', None, 2),
+ 'LR': ('IntReg', 'uw', 'INTREG_LR', 'IsInteger', 3),
+ 'CondCodes': ('IntReg', 'uw', 'INTREG_CONDCODES', None, 3),
'OptCondCodes': ('IntReg', 'uw',
'''(condCode == COND_AL || condCode == COND_UC) ?
- INTREG_ZERO : INTREG_CONDCODES''', None, 2),
- 'FpCondCodes': ('IntReg', 'uw', 'INTREG_FPCONDCODES', None, 2),
+ INTREG_ZERO : INTREG_CONDCODES''', None, 3),
+ 'FpCondCodes': ('IntReg', 'uw', 'INTREG_FPCONDCODES', None, 3),
#Register fields for microops
- 'Ra' : ('IntReg', 'uw', 'ura', 'IsInteger', 2, maybePCRead, maybePCWrite),
- 'IWRa' : ('IntReg', 'uw', 'ura', 'IsInteger', 2,
+ 'Ra' : ('IntReg', 'uw', 'ura', 'IsInteger', 3, maybePCRead, maybePCWrite),
+ 'IWRa' : ('IntReg', 'uw', 'ura', 'IsInteger', 3,
maybePCRead, maybeIWPCWrite),
- 'Fa' : ('FloatReg', 'sf', 'ura', 'IsFloating', 2),
- 'Rb' : ('IntReg', 'uw', 'urb', 'IsInteger', 2, maybePCRead, maybePCWrite),
- 'Rc' : ('IntReg', 'uw', 'urc', 'IsInteger', 2, maybePCRead, maybePCWrite),
+ 'Fa' : ('FloatReg', 'sf', 'ura', 'IsFloating', 3),
+ 'Rb' : ('IntReg', 'uw', 'urb', 'IsInteger', 3, maybePCRead, maybePCWrite),
+ 'Rc' : ('IntReg', 'uw', 'urc', 'IsInteger', 3, maybePCRead, maybePCWrite),
#General Purpose Floating Point Reg Operands
- 'Fd': ('FloatReg', 'df', 'FD', 'IsFloating', 2),
- 'Fn': ('FloatReg', 'df', 'FN', 'IsFloating', 2),
- 'Fm': ('FloatReg', 'df', 'FM', 'IsFloating', 2),
+ 'Fd': ('FloatReg', 'df', 'FD', 'IsFloating', 3),
+ 'Fn': ('FloatReg', 'df', 'FN', 'IsFloating', 3),
+ 'Fm': ('FloatReg', 'df', 'FM', 'IsFloating', 3),
#Memory Operand
- 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 2),
+ 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 3),
- 'Cpsr': ('ControlReg', 'uw', 'MISCREG_CPSR', (None, None, 'IsControl'), 1),
- 'Itstate': ('ControlReg', 'ub', 'MISCREG_ITSTATE', None, 2),
- 'Spsr': ('ControlReg', 'uw', 'MISCREG_SPSR', None, 2),
- 'Fpsr': ('ControlReg', 'uw', 'MISCREG_FPSR', None, 2),
- 'Fpsid': ('ControlReg', 'uw', 'MISCREG_FPSID', None, 2),
- 'Fpscr': ('ControlReg', 'uw', 'MISCREG_FPSCR', None, 2),
- 'Cpacr': ('ControlReg', 'uw', 'MISCREG_CPACR', (None, None, 'IsControl'), 2),
- 'Fpexc': ('ControlReg', 'uw', 'MISCREG_FPEXC', None, 2),
- 'Sctlr': ('ControlReg', 'uw', 'MISCREG_SCTLR', None, 2),
- 'SevMailbox': ('ControlReg', 'uw', 'MISCREG_SEV_MAILBOX', None, 2),
- 'PC': ('PC', 'ud', None, None, 2),
- 'NPC': ('NPC', 'ud', None, (None, None, 'IsControl'), 2,
- readNPC, writeNPC),
- 'FNPC': ('NPC', 'ud', None, (None, None, 'IsControl'), 2,
- readNPC, forceNPC),
- 'IWNPC': ('NPC', 'ud', None, (None, None, 'IsControl'), 2,
- readNPC, writeIWNPC),
+ 'Cpsr': ('ControlReg', 'uw', 'MISCREG_CPSR', (None, None, 'IsControl'), 2),
+ 'Itstate': ('ControlReg', 'ub', 'MISCREG_ITSTATE', None, 3),
+ 'Spsr': ('ControlReg', 'uw', 'MISCREG_SPSR', None, 3),
+ 'Fpsr': ('ControlReg', 'uw', 'MISCREG_FPSR', None, 3),
+ 'Fpsid': ('ControlReg', 'uw', 'MISCREG_FPSID', None, 3),
+ 'Fpscr': ('ControlReg', 'uw', 'MISCREG_FPSCR', None, 3),
+ 'Cpacr': ('ControlReg', 'uw', 'MISCREG_CPACR', (None, None, 'IsControl'), 3),
+ 'Fpexc': ('ControlReg', 'uw', 'MISCREG_FPEXC', None, 3),
+ 'Sctlr': ('ControlReg', 'uw', 'MISCREG_SCTLR', None, 3),
+ 'SevMailbox': ('ControlReg', 'uw', 'MISCREG_SEV_MAILBOX', None, 3),
+ #PCS needs to have a sorting index (the number at the end) less than all
+ #the integer registers which might update the PC. That way if the flag
+ #bits of the pc state are updated and a branch happens through R15, the
+ #updates are layered properly and the R15 update isn't lost.
+ 'PCS': ('PCState', 'uw', None, (None, None, 'IsControl'), 0)
}};
INT_FIQ,
NumInterruptTypes
};
-
- // These otherwise unused bits of the PC are used to select a mode
- // like the J and T bits of the CPSR.
- static const Addr PcJBitShift = 33;
- static const Addr PcJBit = ULL(1) << PcJBitShift;
- static const Addr PcTBitShift = 34;
- static const Addr PcTBit = ULL(1) << PcTBitShift;
- static const Addr PcModeMask = (ULL(1) << PcJBitShift) |
- (ULL(1) << PcTBitShift);
};
using namespace ArmISA;
ThreadContext *tc = threadContexts[0];
// Set the initial PC to be at start of the kernel code
- tc->setPC(tc->getSystemPtr()->kernelEntry & loadAddrMask);
- tc->setNextPC(tc->readPC() + sizeof(MachInst));
+ tc->pcState(tc->getSystemPtr()->kernelEntry & loadAddrMask);
// Setup the machine type
tc->setIntReg(0, 0);
}
//R15, aliased with the PC
- newState[STATE_PC] = tc->readNextPC();
+ newState[STATE_PC] = tc->pcState().npc();
changed[STATE_PC] = (newState[STATE_PC] != oldState[STATE_PC]);
//CPSR
ThreadContext *tc = record->getThread();
// This area is read only on the target. It can't stop there to tell us
// what's going on, so we should skip over anything there also.
- if (tc->readNextPC() > 0xffff0000)
+ if (tc->nextInstAddr() > 0xffff0000)
return;
nState.update(this);
mState.update(tc);
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void
-Predecoder::moreBytes(Addr pc, Addr fetchPC, MachInst inst)
+Predecoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
data = inst;
- offset = (fetchPC >= pc) ? 0 : pc - fetchPC;
- emi.thumb = isThumb(pc);
+ offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
+ emi.thumb = pc.thumb();
FPSCR fpscr = tc->readMiscReg(MISCREG_FPSCR);
emi.fpscrLen = fpscr.len;
emi.fpscrStride = fpscr.stride;
//Use this to give data to the predecoder. This should be used
//when there is control flow.
- void moreBytes(Addr pc, Addr fetchPC, MachInst inst);
+ void moreBytes(const PCState &pc, Addr fetchPC, MachInst inst);
//Use this to give data to the predecoder. This should be used
//when instructions are executed in order.
}
//This returns a constant reference to the ExtMachInst to avoid a copy
- ExtMachInst getExtMachInst()
+ ExtMachInst getExtMachInst(PCState &pc)
{
ExtMachInst thisEmi = emi;
+ pc.npc(pc.pc() + getInstSize());
emi = 0;
return thisEmi;
}
tc->setIntReg(ArgumentReg2, 0);
}
- Addr prog_entry = objFile->entryPoint();
- if (arch == ObjectFile::Thumb)
- prog_entry = (prog_entry & ~mask(1)) | PcTBit;
- tc->setPC(prog_entry);
- tc->setNextPC(prog_entry + sizeof(MachInst));
+ PCState pc;
+ pc.thumb(arch == ObjectFile::Thumb);
+ pc.nextThumb(pc.thumb());
+ pc.set(objFile->entryPoint() & ~mask(1));
+ tc->pcState(pc);
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
// Remove the low bit that thumb symbols have set
// but that aren't actually odd aligned
if (addr & 0x1)
- return (addr & ~1) | PcTBit;
+ return addr & ~1;
return addr;
}
};
/** @todo These should be cached or grabbed from cached copies in
the TLB, all these miscreg reads are expensive */
- currState->vaddr = currState->req->getVaddr() & ~PcModeMask;
+ currState->vaddr = currState->req->getVaddr();
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR);
sctlr = currState->sctlr;
currState->N = currState->tc->readMiscReg(MISCREG_TTBCR);
Translation *translation, bool &delay, bool timing)
{
// XXX Cache misc registers and have miscreg write function inv cache
- Addr vaddr = req->getVaddr() & ~PcModeMask;
+ Addr vaddr = req->getVaddr();
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
uint32_t flags = req->getFlags();
Translation *translation, bool &delay, bool timing)
{
// XXX Cache misc registers and have miscreg write function inv cache
- Addr vaddr = req->getVaddr() & ~PcModeMask;
+ Addr vaddr = req->getVaddr();
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
uint32_t flags = req->getFlags();
#ifndef __ARCH_ARM_TYPES_HH__
#define __ARCH_ARM_TYPES_HH__
+#include "arch/generic/types.hh"
#include "base/bitunion.hh"
#include "base/hashmap.hh"
+#include "base/misc.hh"
#include "base/types.hh"
namespace ArmISA
Bitfield<11, 8> ltcoproc;
EndBitUnion(ExtMachInst)
+ class PCState : public GenericISA::UPCState<MachInst>
+ {
+ protected:
+
+ typedef GenericISA::UPCState<MachInst> Base;
+
+ enum FlagBits {
+ ThumbBit = (1 << 0),
+ JazelleBit = (1 << 1)
+ };
+ uint8_t flags;
+ uint8_t nextFlags;
+
+ public:
+ PCState() : flags(0), nextFlags(0)
+ {}
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ npc(val + (thumb() ? 2 : 4));
+ }
+
+ PCState(Addr val) : flags(0), nextFlags(0)
+ { set(val); }
+
+ bool
+ thumb() const
+ {
+ return flags & ThumbBit;
+ }
+
+ void
+ thumb(bool val)
+ {
+ if (val)
+ flags |= ThumbBit;
+ else
+ flags &= ~ThumbBit;
+ }
+
+ bool
+ nextThumb() const
+ {
+ return nextFlags & ThumbBit;
+ }
+
+ void
+ nextThumb(bool val)
+ {
+ if (val)
+ nextFlags |= ThumbBit;
+ else
+ nextFlags &= ~ThumbBit;
+ }
+
+ bool
+ jazelle() const
+ {
+ return flags & JazelleBit;
+ }
+
+ void
+ jazelle(bool val)
+ {
+ if (val)
+ flags |= JazelleBit;
+ else
+ flags &= ~JazelleBit;
+ }
+
+ bool
+ nextJazelle() const
+ {
+ return nextFlags & JazelleBit;
+ }
+
+ void
+ nextJazelle(bool val)
+ {
+ if (val)
+ nextFlags |= JazelleBit;
+ else
+ nextFlags &= ~JazelleBit;
+ }
+
+ void
+ advance()
+ {
+ Base::advance();
+ npc(pc() + (thumb() ? 2 : 4));
+ flags = nextFlags;
+ }
+
+ void
+ uEnd()
+ {
+ advance();
+ upc(0);
+ nupc(1);
+ }
+
+ Addr
+ instPC() const
+ {
+ return pc() + (thumb() ? 4 : 8);
+ }
+
+ void
+ instNPC(uint32_t val)
+ {
+ npc(val &~ mask(nextThumb() ? 1 : 2));
+ }
+
+ Addr
+ instNPC() const
+ {
+ return npc();
+ }
+
+ // Perform an interworking branch.
+ void
+ instIWNPC(uint32_t val)
+ {
+ bool thumbEE = (thumb() && jazelle());
+
+ Addr newPC = val;
+ if (thumbEE) {
+ if (bits(newPC, 0)) {
+ newPC = newPC & ~mask(1);
+ } else {
+ panic("Bad thumbEE interworking branch address %#x.\n",
+ newPC);
+ }
+ } else {
+ if (bits(newPC, 0)) {
+ nextThumb(true);
+ newPC = newPC & ~mask(1);
+ } else if (!bits(newPC, 1)) {
+ nextThumb(false);
+ } else {
+ warn("Bad interworking branch address %#x.\n", newPC);
+ }
+ }
+ npc(newPC);
+ }
+
+ // Perform an interworking branch in ARM mode, a regular branch
+ // otherwise.
+ void
+ instAIWNPC(uint32_t val)
+ {
+ if (!thumb() && !jazelle())
+ instIWNPC(val);
+ else
+ instNPC(val);
+ }
+
+ bool
+ operator == (const PCState &opc) const
+ {
+ return Base::operator == (opc) &&
+ flags == opc.flags && nextFlags == opc.nextFlags;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(flags);
+ SERIALIZE_SCALAR(nextFlags);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string §ion)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(flags);
+ UNSERIALIZE_SCALAR(nextFlags);
+ }
+ };
+
// Shift types for ARM instructions
enum ArmShiftType {
LSL = 0,
void
skipFunction(ThreadContext *tc)
{
- Addr newpc = tc->readIntReg(ReturnAddressReg);
- newpc &= ~ULL(1);
- if (isThumb(tc->readPC()))
- tc->setPC(newpc | PcTBit);
- else
- tc->setPC(newpc);
- tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst));
+ TheISA::PCState newPC = tc->pcState();
+ newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1));
+ tc->pcState(newPC);
}
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
+#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
namespace ArmISA {
+ inline PCState
+ buildRetPC(const PCState &curPC, const PCState &callPC)
+ {
+ PCState retPC = callPC;
+ retPC.uEnd();
+ return retPC;
+ }
+
inline bool
testPredicate(CPSR cpsr, ConditionCode code)
{
tc->activate(0);
}
- static inline bool
- isThumb(Addr pc)
- {
- return (pc & PcTBit);
- }
-
static inline void
copyRegs(ThreadContext *src, ThreadContext *dest)
{
void skipFunction(ThreadContext *tc);
+inline void
+advancePC(PCState &pc, const StaticInstPtr inst)
+{
+ inst->advancePC(pc);
+}
+
};
--- /dev/null
+/*
+ * Copyright (c) 2010 Gabe Black
+ * 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: Gabe Black
+ */
+
+#ifndef __ARCH_GENERIC_TYPES_HH__
+#define __ARCH_GENERIC_TYPES_HH__
+
+#include <iostream>
+
+#include "base/types.hh"
+#include "base/trace.hh"
+#include "sim/serialize.hh"
+
+namespace GenericISA
+{
+
+// The guaranteed interface.
+class PCStateBase
+{
+ protected:
+ Addr _pc;
+ Addr _npc;
+
+ PCStateBase() {}
+ PCStateBase(Addr val) { set(val); }
+
+ public:
+ /**
+ * Returns the memory address the bytes of this instruction came from.
+ *
+ * @return Memory address of the current instruction's encoding.
+ */
+ Addr
+ instAddr() const
+ {
+ return _pc;
+ }
+
+ /**
+ * Returns the memory address the bytes of the next instruction came from.
+ *
+ * @return Memory address of the next instruction's encoding.
+ */
+ Addr
+ nextInstAddr() const
+ {
+ return _npc;
+ }
+
+ /**
+ * Returns the current micropc.
+ *
+ * @return The current micropc.
+ */
+ MicroPC
+ microPC() const
+ {
+ return 0;
+ }
+
+ /**
+ * Force this PC to reflect a particular value, resetting all its other
+ * fields around it. This is useful for in place (re)initialization.
+ *
+ * @param val The value to set the PC to.
+ */
+ void set(Addr val);
+
+ bool
+ operator == (const PCStateBase &opc) const
+ {
+ return _pc == opc._pc && _npc == opc._npc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ SERIALIZE_SCALAR(_pc);
+ SERIALIZE_SCALAR(_npc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string §ion)
+ {
+ UNSERIALIZE_SCALAR(_pc);
+ UNSERIALIZE_SCALAR(_npc);
+ }
+};
+
+
+/*
+ * Different flavors of PC state. Only ISA specific code should rely on
+ * any particular type of PC state being available. All other code should
+ * use the interface above.
+ */
+
+// The most basic type of PC.
+template <class MachInst>
+class SimplePCState : public PCStateBase
+{
+ protected:
+ typedef PCStateBase Base;
+
+ public:
+
+ Addr pc() const { return _pc; }
+ void pc(Addr val) { _pc = val; }
+
+ Addr npc() const { return _npc; }
+ void npc(Addr val) { _npc = val; }
+
+ void
+ set(Addr val)
+ {
+ pc(val);
+ npc(val + sizeof(MachInst));
+ };
+
+ SimplePCState() {}
+ SimplePCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return this->npc() != this->pc() + sizeof(MachInst);
+ }
+
+ // Advance the PC.
+ void
+ advance()
+ {
+ _pc = _npc;
+ _npc += sizeof(MachInst);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const SimplePCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x)", pc.pc(), pc.npc());
+ return os;
+}
+
+// A PC and microcode PC.
+template <class MachInst>
+class UPCState : public SimplePCState<MachInst>
+{
+ protected:
+ typedef SimplePCState<MachInst> Base;
+
+ MicroPC _upc;
+ MicroPC _nupc;
+
+ public:
+
+ MicroPC upc() const { return _upc; }
+ void upc(MicroPC val) { _upc = val; }
+
+ MicroPC nupc() const { return _nupc; }
+ void nupc(MicroPC val) { _nupc = val; }
+
+ MicroPC
+ microPC() const
+ {
+ return _upc;
+ }
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ upc(0);
+ nupc(1);
+ }
+
+ UPCState() {}
+ UPCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return this->npc() != this->pc() + sizeof(MachInst) ||
+ this->nupc() != this->upc() + 1;
+ }
+
+ // Advance the upc within the instruction.
+ void
+ uAdvance()
+ {
+ _upc = _nupc;
+ _nupc++;
+ }
+
+ // End the macroop by resetting the upc and advancing the regular pc.
+ void
+ uEnd()
+ {
+ this->advance();
+ _upc = 0;
+ _nupc = 1;
+ }
+
+ bool
+ operator == (const UPCState<MachInst> &opc) const
+ {
+ return Base::_pc == opc._pc &&
+ Base::_npc == opc._npc &&
+ _upc == opc._upc && _nupc == opc._nupc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(_upc);
+ SERIALIZE_SCALAR(_nupc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string §ion)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(_upc);
+ UNSERIALIZE_SCALAR(_nupc);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const UPCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x).(%d=>%d)",
+ pc.pc(), pc.npc(), pc.upc(), pc.npc());
+ return os;
+}
+
+// A PC with a delay slot.
+template <class MachInst>
+class DelaySlotPCState : public SimplePCState<MachInst>
+{
+ protected:
+ typedef SimplePCState<MachInst> Base;
+
+ Addr _nnpc;
+
+ public:
+
+ Addr nnpc() const { return _nnpc; }
+ void nnpc(Addr val) { _nnpc = val; }
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ nnpc(val + 2 * sizeof(MachInst));
+ }
+
+ DelaySlotPCState() {}
+ DelaySlotPCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return !(this->nnpc() == this->npc() + sizeof(MachInst) &&
+ (this->npc() == this->pc() + sizeof(MachInst) ||
+ this->npc() == this->pc() + 2 * sizeof(MachInst)));
+ }
+
+ // Advance the PC.
+ void
+ advance()
+ {
+ Base::_pc = Base::_npc;
+ Base::_npc = _nnpc;
+ _nnpc += sizeof(MachInst);
+ }
+
+ bool
+ operator == (const DelaySlotPCState<MachInst> &opc) const
+ {
+ return Base::_pc == opc._pc &&
+ Base::_npc == opc._npc &&
+ _nnpc == opc._nnpc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(_nnpc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string §ion)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(_nnpc);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const DelaySlotPCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x=>%#x)",
+ pc.pc(), pc.npc(), pc.nnpc());
+ return os;
+}
+
+// A PC with a delay slot and a microcode PC.
+template <class MachInst>
+class DelaySlotUPCState : public DelaySlotPCState<MachInst>
+{
+ protected:
+ typedef DelaySlotPCState<MachInst> Base;
+
+ MicroPC _upc;
+ MicroPC _nupc;
+
+ public:
+
+ MicroPC upc() const { return _upc; }
+ void upc(MicroPC val) { _upc = val; }
+
+ MicroPC nupc() const { return _nupc; }
+ void nupc(MicroPC val) { _nupc = val; }
+
+ MicroPC
+ microPC() const
+ {
+ return _upc;
+ }
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ upc(0);
+ nupc(1);
+ }
+
+ DelaySlotUPCState() {}
+ DelaySlotUPCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return Base::branching() || this->nupc() != this->upc() + 1;
+ }
+
+ // Advance the upc within the instruction.
+ void
+ uAdvance()
+ {
+ _upc = _nupc;
+ _nupc++;
+ }
+
+ // End the macroop by resetting the upc and advancing the regular pc.
+ void
+ uEnd()
+ {
+ this->advance();
+ _upc = 0;
+ _nupc = 1;
+ }
+
+ bool
+ operator == (const DelaySlotUPCState<MachInst> &opc) const
+ {
+ return Base::_pc == opc._pc &&
+ Base::_npc == opc._npc &&
+ Base::_nnpc == opc._nnpc &&
+ _upc == opc._upc && _nupc == opc._nupc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(_upc);
+ SERIALIZE_SCALAR(_nupc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string §ion)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(_upc);
+ UNSERIALIZE_SCALAR(_nupc);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const DelaySlotUPCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x=>%#x).(%d=>%d)",
+ pc.pc(), pc.npc(), pc.nnpc(), pc.upc(), pc.nupc());
+ return os;
+}
+
+}
+
+#endif
def makeAccSize(self):
return self.size
-class PCOperand(Operand):
+class PCStateOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
- return '%s = xc->readPC();\n' % self.base_name
+ return '%s = xc->pcState();\n' % self.base_name
def makeWrite(self):
- return 'xc->setPC(%s);\n' % self.base_name
+ return 'xc->pcState(%s);\n' % self.base_name
-class UPCOperand(Operand):
- def makeConstructor(self):
- return ''
-
- def makeRead(self):
- if self.read_code != None:
- return self.buildReadCode('readMicroPC')
- return '%s = xc->readMicroPC();\n' % self.base_name
-
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setMicroPC')
- return 'xc->setMicroPC(%s);\n' % self.base_name
+ def makeDecl(self):
+ return 'TheISA::PCState ' + self.base_name + ' M5_VAR_USED;\n';
-class NUPCOperand(Operand):
+class PCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
- if self.read_code != None:
- return self.buildReadCode('readNextMicroPC')
- return '%s = xc->readNextMicroPC();\n' % self.base_name
+ return '%s = xc->instAddr();\n' % self.base_name
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setNextMicroPC')
- return 'xc->setNextMicroPC(%s);\n' % self.base_name
-
-class NPCOperand(Operand):
+class UPCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
if self.read_code != None:
- return self.buildReadCode('readNextPC')
- return '%s = xc->readNextPC();\n' % self.base_name
-
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setNextPC')
- return 'xc->setNextPC(%s);\n' % self.base_name
+ return self.buildReadCode('microPC')
+ return '%s = xc->microPC();\n' % self.base_name
-class NNPCOperand(Operand):
+class NPCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
if self.read_code != None:
- return self.buildReadCode('readNextNPC')
- return '%s = xc->readNextNPC();\n' % self.base_name
-
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setNextNPC')
- return 'xc->setNextNPC(%s);\n' % self.base_name
+ return self.buildReadCode('nextInstAddr')
+ return '%s = xc->nextInstAddr();\n' % self.base_name
class OperandList(object):
'''Find all the operands in the given code block. Returns an operand
void printReg(std::ostream &os, int reg) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ public:
+ void
+ advancePC(MipsISA::PCState &pc) const
+ {
+ pc.advance();
+ }
};
}};
0x1: jr_hb({{
Config1Reg config1 = Config1;
if (config1.ca == 0) {
- NNPC = Rs;
+ pc.nnpc(Rs);
} else {
panic("MIPS16e not supported\n");
}
+ PCS = pc;
}}, IsReturn, ClearHazards);
default: jr({{
Config1Reg config1 = Config1;
if (config1.ca == 0) {
- NNPC = Rs;
+ pc.nnpc(Rs);
} else {
panic("MIPS16e not supported\n");
}
+ PCS = pc;
}}, IsReturn);
}
0x1: decode HINT {
- 0x1: jalr_hb({{ Rd = NNPC; NNPC = Rs; }}, IsCall
- , ClearHazards);
- default: jalr({{ Rd = NNPC; NNPC = Rs; }}, IsCall);
+ 0x1: jalr_hb({{
+ Rd = pc.nnpc();
+ pc.nnpc(Rs);
+ PCS = pc;
+ }}, IsCall, ClearHazards);
+ default: jalr({{
+ Rd = pc.nnpc();
+ pc.nnpc(Rs);
+ PCS = pc;
+ }}, IsCall);
}
}
}
format Jump {
- 0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }});
- 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }},
- IsCall, Link);
+ 0x2: j({{
+ pc.nnpc((pc.npc() & 0xF0000000) | (JMPTARG << 2));
+ PCS = pc;
+ }});
+ 0x3: jal({{
+ pc.nnpc((pc.npc() & 0xF0000000) | (JMPTARG << 2));
+ PCS = pc;
+ }}, IsCall, Link);
}
format Branch {
ConfigReg config = Config;
SRSCtlReg srsCtl = SRSCtl;
DPRINTF(MipsPRA,"Restoring PC - %x\n",EPC);
+ MipsISA::PCState pc = PCS;
if (status.erl == 1) {
status.erl = 0;
- NPC = ErrorEPC;
+ pc.npc(ErrorEPC);
// Need to adjust NNPC, otherwise things break
- NNPC = ErrorEPC + sizeof(MachInst);
+ pc.nnpc(ErrorEPC + sizeof(MachInst));
} else {
- NPC = EPC;
+ pc.npc(EPC);
// Need to adjust NNPC, otherwise things break
- NNPC = EPC + sizeof(MachInst);
+ pc.nnpc(EPC + sizeof(MachInst));
status.exl = 0;
if (config.ar >=1 &&
srsCtl.hss > 0 &&
//xc->setShadowSet(srsCtl.pss);
}
}
+ PCS = pc;
LLFlag = 0;
Status = status;
SRSCtl = srsCtl;
0x1F: deret({{
DebugReg debug = Debug;
+ MipsISA::PCState pc = PCS;
if (debug.dm == 1) {
debug.dm = 1;
debug.iexi = 0;
- NPC = DEPC;
+ pc.npc(DEPC);
} else {
// Undefined;
}
+ PCS = pc;
Debug = debug;
}}, IsReturn, IsSerializing, IsERET);
}
}
}
- Addr branchTarget(Addr branchPC) const;
+ MipsISA::PCState branchTarget(const MipsISA::PCState &branchPC) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
{
}
- Addr branchTarget(ThreadContext *tc) const;
+ MipsISA::PCState branchTarget(ThreadContext *tc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
}};
output decoder {{
- Addr
- Branch::branchTarget(Addr branchPC) const
+ MipsISA::PCState
+ Branch::branchTarget(const MipsISA::PCState &branchPC) const
{
- return branchPC + 4 + disp;
+ MipsISA::PCState target = branchPC;
+ target.advance();
+ target.npc(branchPC.pc() + sizeof(MachInst) + disp);
+ target.nnpc(target.npc() + sizeof(MachInst));
+ return target;
}
- Addr
+ MipsISA::PCState
Jump::branchTarget(ThreadContext *tc) const
{
- Addr NPC = tc->readNextPC();
- return (NPC & 0xF0000000) | (disp);
+ MipsISA::PCState target = tc->pcState();
+ Addr pc = target.pc();
+ target.advance();
+ target.npc((pc & 0xF0000000) | disp);
+ target.nnpc(target.npc() + sizeof(MachInst));
+ return target;
}
const std::string &
}};
def format Branch(code, *opt_flags) {{
- not_taken_code = ' NNPC = NNPC;\n'
- not_taken_code += '} \n'
+ not_taken_code = ''
#Build Instruction Flags
#Use Link & Likely Flags to Add Link/Condition Code
inst_flags = ('IsDirectControl', )
for x in opt_flags:
if x == 'Link':
- code += 'R31 = NNPC;\n'
+ code += 'R31 = pc.nnpc();\n'
elif x == 'Likely':
- not_taken_code = ' NPC = NNPC;\n'
- not_taken_code += ' NNPC = NNPC + 4;\n'
- not_taken_code += '} \n'
+ not_taken_code = 'pc.advance();'
inst_flags += ('IsCondDelaySlot', )
else:
inst_flags += (x, )
inst_flags += ('IsCondControl', )
#Condition code
- code = 'bool cond;\n' + code
- code += 'if (cond) {\n'
- code += ' NNPC = NPC + disp;\n'
- code += '} else {\n'
- code += not_taken_code
+ code = '''
+ bool cond;
+ MipsISA::PCState pc = PCS;
+ %(code)s
+ if (cond) {
+ pc.nnpc(pc.npc() + disp);
+ } else {
+ %(not_taken_code)s
+ }
+ PCS = pc;
+ ''' % { "code" : code, "not_taken_code" : not_taken_code }
iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
header_output = BasicDeclare.subst(iop)
}};
def format DspBranch(code, *opt_flags) {{
- not_taken_code = ' NNPC = NNPC;\n'
- not_taken_code += '} \n'
+ not_taken_code = ''
#Build Instruction Flags
#Use Link & Likely Flags to Add Link/Condition Code
inst_flags = ('IsDirectControl', )
for x in opt_flags:
if x == 'Link':
- code += 'R31 = NNPC;\n'
+ code += 'R32 = pc.nnpc();'
elif x == 'Likely':
- not_taken_code = ' NPC = NNPC;\n'
- not_taken_code += ' NNPC = NNPC + 4;\n'
- not_taken_code += '} \n'
+ not_taken_code = 'pc.advance();'
inst_flags += ('IsCondDelaySlot', )
else:
inst_flags += (x, )
else:
inst_flags += ('IsCondControl', )
- #Declaration code
- decl_code = 'bool cond;\n'
- decl_code += 'uint32_t dspctl;\n'
-
- #Fetch code
- fetch_code = 'dspctl = DSPControl;\n'
-
#Condition code
- code = decl_code + fetch_code + code
- code += 'if (cond) {\n'
- code += ' NNPC = NPC + disp;\n'
- code += '} else {\n'
- code += not_taken_code
+ code = '''
+ MipsISA::PCState pc = PCS;
+ bool cond;
+ uint32_t dspctl = DSPControl;
+ %(code)s
+ if (cond) {
+ pc.nnpc(pc.npc() + disp);
+ } else {
+ %(not_taken_code)s
+ }
+ PCS = pc;
+ ''' % { "code" : code, "not_taken_code" : not_taken_code }
iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
header_output = BasicDeclare.subst(iop)
inst_flags = ('IsIndirectControl', 'IsUncondControl')
for x in opt_flags:
if x == 'Link':
- code = 'R31 = NNPC;\n' + code
+ code = '''
+ R31 = pc.nnpc();
+ ''' + code
elif x == 'ClearHazards':
code += '/* Code Needed to Clear Execute & Inst Hazards */\n'
else:
inst_flags += (x, )
+ code = '''
+ MipsISA::PCState pc = PCS;
+ ''' + code
+
iop = InstObjParams(name, Name, 'Jump', code, inst_flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
#include <iomanip>
#include "arch/mips/isa_traits.hh"
+#include "arch/mips/types.hh"
#include "cpu/static_inst.hh"
#include "mem/packet.hh"
}};
'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4),
#Program Counter Operands
- 'NPC': ('NPC', 'uw', None, 'IsControl', 4),
- 'NNPC':('NNPC', 'uw', None, 'IsControl', 4)
+ 'PCS': ('PCState', 'uw', None, (None, None, 'IsControl'), 4)
}};
// Save last known PC in TCRestart
// @TODO: Needs to check if this is a branch and if so,
// take previous instruction
- tc->setMiscReg(MISCREG_TC_RESTART, tc->readNextPC());
+ PCState pc = tc->pcState();
+ tc->setMiscReg(MISCREG_TC_RESTART, pc.npc());
warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x",
curTick, tc->threadId(), tc->getCpuPtr()->name(),
- tc->readPC(), tc->readNextPC());
+ pc.pc(), pc.npc());
}
}
{
if (tc->status() != TC::Active) {
// Restore PC from TCRestart
- IntReg pc = tc->readMiscRegNoEffect(MISCREG_TC_RESTART);
+ Addr restartPC = tc->readMiscRegNoEffect(MISCREG_TC_RESTART);
// TODO: SET PC WITH AN EVENT INSTEAD OF INSTANTANEOUSLY
- tc->setPC(pc);
- tc->setNextPC(pc + 4);
- tc->setNextNPC(pc + 8);
+ tc->pcState(restartPC);
tc->activate(0);
warn("%i: Restoring thread %i in %s @ PC %x",
- curTick, tc->threadId(), tc->getCpuPtr()->name(),
- tc->readPC());
+ curTick, tc->threadId(), tc->getCpuPtr()->name(), restartPC);
}
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void
- moreBytes(Addr pc, Addr fetchPC, MachInst inst)
+ moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
- getExtMachInst()
+ getExtMachInst(PCState &pc)
{
return emi;
}
setSyscallArg(tc, 1, argv_array_base);
tc->setIntReg(StackPointerReg, stack_min);
- Addr prog_entry = objFile->entryPoint();
- tc->setPC(prog_entry);
- tc->setNextPC(prog_entry + sizeof(MachInst));
- tc->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ tc->pcState(objFile->entryPoint());
}
#ifndef __ARCH_MIPS_TYPES_HH__
#define __ARCH_MIPS_TYPES_HH__
+#include "arch/generic/types.hh"
#include "base/types.hh"
namespace MipsISA
typedef uint32_t MachInst;
typedef uint64_t ExtMachInst;
+typedef GenericISA::DelaySlotPCState<MachInst> PCState;
+
typedef uint64_t LargestRead;
//used in FP convert & round function
void
skipFunction(ThreadContext *tc)
{
- Addr newpc = tc->readIntReg(ReturnAddressReg);
- tc->setPC(newpc);
- tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst));
- tc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
+ TheISA::PCState newPC = tc->pcState();
+ newPC.set(tc->readIntReg(ReturnAddressReg));
+ tc->pcState(newPC);
}
#include "base/misc.hh"
#include "base/types.hh"
#include "config/full_system.hh"
+#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
class ThreadContext;
namespace MipsISA {
+inline PCState
+buildRetPC(const PCState &curPC, const PCState &callPC)
+{
+ PCState ret = callPC;
+ ret.advance();
+ ret.pc(curPC.npc());
+ return ret;
+}
+
uint64_t getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp);
////////////////////////////////////////////////////////////////////////
void skipFunction(ThreadContext *tc);
+inline void
+advancePC(PCState &pc, const StaticInstPtr inst)
+{
+ pc.advance();
+}
+
};
return *cachedDisassembly;
}
-Addr
-BranchPCRel::branchTarget(Addr pc) const
+PowerISA::PCState
+BranchPCRel::branchTarget(const PowerISA::PCState &pc) const
{
- return (uint32_t)(pc + disp);
+ return (uint32_t)(pc.pc() + disp);
}
std::string
return ss.str();
}
-Addr
-BranchNonPCRel::branchTarget(Addr pc) const
+PowerISA::PCState
+BranchNonPCRel::branchTarget(const PowerISA::PCState &pc) const
{
return targetAddr;
}
return ss.str();
}
-Addr
-BranchPCRelCond::branchTarget(Addr pc) const
+PowerISA::PCState
+BranchPCRelCond::branchTarget(const PowerISA::PCState &pc) const
{
- return (uint32_t)(pc + disp);
+ return (uint32_t)(pc.pc() + disp);
}
std::string
return ss.str();
}
-Addr
-BranchNonPCRelCond::branchTarget(Addr pc) const
+PowerISA::PCState
+BranchNonPCRelCond::branchTarget(const PowerISA::PCState &pc) const
{
return targetAddr;
}
return ss.str();
}
-Addr
+PowerISA::PCState
BranchRegCond::branchTarget(ThreadContext *tc) const
{
uint32_t regVal = tc->readIntReg(_srcRegIdx[_numSrcRegs - 1]);
- return (regVal & 0xfffffffc);
+ return regVal & 0xfffffffc;
}
std::string
}
}
- Addr branchTarget(Addr pc) const;
+ PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
}
}
- Addr branchTarget(Addr pc) const;
+ PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
}
}
- Addr branchTarget(Addr pc) const;
+ PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
}
}
- Addr branchTarget(Addr pc) const;
+ PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
{
}
- Addr branchTarget(ThreadContext *tc) const;
+ PowerISA::PCState branchTarget(ThreadContext *tc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ void
+ advancePC(PowerISA::PCState &pcState) const
+ {
+ pcState.advance();
+ }
};
} // PowerISA namespace
// Conditionally branch relative to PC based on CR and CTR.
format BranchPCRelCondCtr {
- 0: bc({{ NPC = PC + disp; }});
+ 0: bc({{
+ PowerISA::PCState pc = PCS;
+ pc.npc((uint32_t)(pc.pc() + disp));
+ PCS = pc;
+ }});
}
// Conditionally branch to fixed address based on CR and CTR.
format BranchNonPCRelCondCtr {
- 1: bca({{ NPC = targetAddr; }});
+ 1: bca({{
+ PowerISA::PCState pc = PCS;
+ pc.npc(targetAddr);
+ PCS = pc;
+ }});
}
}
// Unconditionally branch relative to PC.
format BranchPCRel {
- 0: b({{ NPC = PC + disp; }});
+ 0: b({{
+ PowerISA::PCState pc = PCS;
+ pc.npc((uint32_t)(pc.pc() + disp));
+ PCS = pc;
+ }});
}
// Unconditionally branch to fixed address.
format BranchNonPCRel {
- 1: ba({{ NPC = targetAddr; }});
+ 1: ba({{
+ PowerISA::PCState pc = PCS;
+ pc.npc(targetAddr);
+ PCS = pc;
+ }});
}
}
// Conditionally branch to address in LR based on CR and CTR.
format BranchLrCondCtr {
- 16: bclr({{ NPC = LR & 0xfffffffc; }});
+ 16: bclr({{
+ PowerISA::PCState pc = PCS;
+ pc.npc(LR & 0xfffffffc);
+ PCS = pc;
+ }});
}
// Conditionally branch to address in CTR based on CR.
format BranchCtrCond {
- 528: bcctr({{ NPC = CTR & 0xfffffffc; }});
+ 528: bcctr({{
+ PowerISA::PCState pc = PCS;
+ pc.npc(CTR & 0xfffffffc);
+ PCS = pc;
+ }});
}
// Condition register manipulation instructions.
let {{
# Simple code to update link register (LR).
-updateLrCode = 'LR = PC + 4;'
+updateLrCode = 'PowerISA::PCState lrpc = PCS; LR = lrpc.pc() + 4;'
}};
cond_code = 'if(condOk(CR)) {\n'
cond_code += ' ' + br_code + '\n'
cond_code += '} else {\n'
- cond_code += ' NPC = NPC;\n'
+ cond_code += ' PCS = PCS;\n'
cond_code += '}\n'
return cond_code
cond_code += 'if(ctr_ok && cond_ok) {\n'
cond_code += ' ' + br_code + '\n'
cond_code += '} else {\n'
- cond_code += ' NPC = NPC;\n'
+ cond_code += ' PCS = PCS;\n'
cond_code += '}\n'
cond_code += 'CTR = ctr;\n'
return cond_code
{
panic("attempt to execute unknown instruction at %#x"
"(inst 0x%08x, opcode 0x%x, binary: %s)",
- xc->readPC(), machInst, OPCODE, inst2string(machInst));
+ xc->pcState().pc(), machInst, OPCODE, inst2string(machInst));
return new UnimplementedOpcodeFault;
}
}};
'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 8),
# Program counter and next
- 'PC': ('PC', 'uw', None, (None, None, 'IsControl'), 9),
- 'NPC': ('NPC', 'uw', None, (None, None, 'IsControl'), 9),
+ 'PCS': ('PCState', 'uq', None, (None, None, 'IsControl'), 9),
# Control registers
'CR': ('IntReg', 'uw', 'INTREG_CR', 'IsInteger', 9),
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
- moreBytes(Addr pc, Addr fetchPC, MachInst inst)
+ moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
}
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
- getExtMachInst()
+ getExtMachInst(PCState &pcState)
{
return emi;
}
//Set the stack pointer register
tc->setIntReg(StackPointerReg, stack_min);
- Addr prog_entry = objFile->entryPoint();
- tc->setPC(prog_entry);
- tc->setNextPC(prog_entry + sizeof(MachInst));
+ tc->pcState(objFile->entryPoint());
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
#ifndef __ARCH_POWER_TYPES_HH__
#define __ARCH_POWER_TYPES_HH__
+#include "arch/generic/types.hh"
#include "base/bitunion.hh"
#include "base/hashmap.hh"
#include "base/types.hh"
Bitfield<19, 12> fxm;
EndBitUnion(ExtMachInst)
+typedef GenericISA::SimplePCState<MachInst> PCState;
+
// typedef uint64_t LargestRead;
// // Need to use 64 bits to make sure that read requests get handled properly
copyMiscRegs(src, dest);
// Lastly copy PC/NPC
- dest->setPC(src->readPC());
- dest->setNextPC(src->readNextPC());
+ dest->pcState(src->pcState());
}
void
#define __ARCH_POWER_UTILITY_HH__
#include "base/types.hh"
+#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
namespace PowerISA {
+inline PCState
+buildRetPC(const PCState &curPC, const PCState &callPC)
+{
+ PCState retPC = callPC;
+ retPC.advance();
+ return retPC;
+}
+
/**
* Function to ensure ISA semantics about 0 registers.
* @param tc The thread context.
void skipFunction(ThreadContext *tc);
+inline void
+advancePC(PCState &pc, const StaticInstPtr inst)
+{
+ pc.advance();
+}
+
} // PowerISA namespace
#endif // __ARCH_POWER_UTILITY_HH__
//MiscReg CANSAVE = tc->readMiscRegNoEffect(MISCREG_CANSAVE);
MiscReg CANSAVE = tc->readMiscRegNoEffect(NumIntArchRegs + 3);
MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);
- MiscReg PC = tc->readPC();
- MiscReg NPC = tc->readNextPC();
+ PCState pc = tc->pcState();
TL++;
- if (bits(PSTATE, 3,3)) {
- PC &= mask(32);
- NPC &= mask(32);
- }
+ Addr pcMask = bits(PSTATE, 3) ? mask(32) : mask(64);
//set TSTATE.gl to gl
replaceBits(TSTATE, 42, 40, GL);
tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);
//set TPC to PC
- tc->setMiscRegNoEffect(MISCREG_TPC, PC);
+ tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask);
//set TNPC to NPC
- tc->setMiscRegNoEffect(MISCREG_TNPC, NPC);
+ tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask);
//set HTSTATE.hpstate to hpstate
tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE);
//MiscReg CANSAVE = tc->readMiscRegNoEffect(MISCREG_CANSAVE);
MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3);
MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);
- MiscReg PC = tc->readPC();
- MiscReg NPC = tc->readNextPC();
-
- if (bits(PSTATE, 3,3)) {
- PC &= mask(32);
- NPC &= mask(32);
- }
+ PCState pc = tc->pcState();
//Increment the trap level
TL++;
tc->setMiscRegNoEffect(MISCREG_TL, TL);
+ Addr pcMask = bits(PSTATE, 3) ? mask(32) : mask(64);
+
//Save off state
//set TSTATE.gl to gl
tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);
//set TPC to PC
- tc->setMiscRegNoEffect(MISCREG_TPC, PC);
+ tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask);
//set TNPC to NPC
- tc->setMiscRegNoEffect(MISCREG_TNPC, NPC);
+ tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask);
//set HTSTATE.hpstate to hpstate
tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE);
}
}
-void getREDVector(MiscReg TT, Addr & PC, Addr & NPC)
+void getREDVector(MiscReg TT, Addr &PC, Addr &NPC)
{
//XXX The following constant might belong in a header file.
const Addr RSTVAddr = 0xFFF0000000ULL;
getPrivVector(tc, PC, NPC, trapType(), tl+1);
}
- tc->setPC(PC);
- tc->setNextPC(NPC);
- tc->setNextNPC(NPC + sizeof(MachInst));
+ PCState pc;
+ pc.pc(PC);
+ pc.npc(NPC);
+ pc.nnpc(NPC + sizeof(MachInst));
+ pc.upc(0);
+ pc.nupc(1);
+ tc->pcState(pc);
}
void PowerOnReset::invoke(ThreadContext * tc, StaticInstPtr inst)
Addr PC, NPC;
getREDVector(trapType(), PC, NPC);
- tc->setPC(PC);
- tc->setNextPC(NPC);
- tc->setNextNPC(NPC + sizeof(MachInst));
+
+ PCState pc;
+ pc.pc(PC);
+ pc.npc(NPC);
+ pc.nnpc(NPC + sizeof(MachInst));
+ pc.upc(0);
+ pc.nupc(1);
+ tc->pcState(pc);
//These registers are specified as "undefined" after a POR, and they
//should have reasonable values after the miscregfile is reset
assert(lp);
//Then adjust the PC and NPC
- Addr spillStart = lp->readSpillStart();
- tc->setPC(spillStart);
- tc->setNextPC(spillStart + sizeof(MachInst));
- tc->setNextNPC(spillStart + 2*sizeof(MachInst));
+ tc->pcState(lp->readSpillStart());
}
void FillNNormal::invoke(ThreadContext *tc, StaticInstPtr inst)
assert(lp);
//Then adjust the PC and NPC
- Addr fillStart = lp->readFillStart();
- tc->setPC(fillStart);
- tc->setNextPC(fillStart + sizeof(MachInst));
- tc->setNextNPC(fillStart + 2*sizeof(MachInst));
+ tc->pcState(lp->readFillStart());
}
void TrapInstruction::invoke(ThreadContext *tc, StaticInstPtr inst)
//We need to explicitly advance the pc, since that's not done for us
//on a faulting instruction
- tc->setPC(tc->readNextPC());
- tc->setNextPC(tc->readNextNPC());
- tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst));
+ PCState pc = tc->pcState();
+ pc.advance();
+ tc->pcState(pc);
}
#endif
void printRegArray(std::ostream &os,
const RegIndex indexArray[], int num) const;
+
+ void advancePC(SparcISA::PCState &pcState) const;
};
bool passesFpCondition(uint32_t fcc, uint32_t condition);
}
}
+ void
+ SparcStaticInst::advancePC(SparcISA::PCState &pcState) const
+ {
+ pcState.advance();
+ }
+
void
SparcStaticInst::printSrcReg(std::ostream &os, int reg) const
{
{
//Branch Always
0x8: bpa(19, annul_code={{
- NPC = xc->readPC() + disp;
- NNPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.npc(pc.pc() + disp);
+ pc.nnpc(pc.npc() + 4);
+ PCS = pc;
}});
//Branch Never
0x0: bpn(19, {{;}},
annul_code={{
- NNPC = NPC + 8;
- NPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(pc.npc() + 8);
+ pc.npc(pc.npc() + 4);
+ PCS = pc;
}});
default: decode BPCC
{
{
//Branch Always
0x8: ba(22, annul_code={{
- NPC = xc->readPC() + disp;
- NNPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.npc(pc.pc() + disp);
+ pc.nnpc(pc.npc() + 4);
+ PCS = pc;
}});
//Branch Never
0x0: bn(22, {{;}},
annul_code={{
- NNPC = NPC + 8;
- NPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(pc.npc() + 8);
+ pc.npc(pc.npc() + 4);
+ PCS = pc;
}});
default: bicc(22, test={{passesCondition(Ccr<3:0>, COND2)}});
}
format BranchN {
//Branch Always
0x8: fbpa(22, annul_code={{
- NPC = xc->readPC() + disp;
- NNPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.npc(pc.pc() + disp);
+ pc.nnpc(pc.npc() + 4);
+ PCS = pc;
}});
//Branch Never
0x0: fbpn(22, {{;}},
annul_code={{
- NNPC = NPC + 8;
- NPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(pc.npc() + 8);
+ pc.npc(pc.npc() + 4);
+ PCS = pc;
}});
default: decode BPCC {
0x0: fbpfcc0(19, test=
format BranchN {
//Branch Always
0x8: fba(22, annul_code={{
- NPC = xc->readPC() + disp;
- NNPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.npc(pc.pc() + disp);
+ pc.nnpc(pc.npc() + 4);
+ PCS = pc;
}});
//Branch Never
0x0: fbn(22, {{;}},
annul_code={{
- NNPC = NPC + 8;
- NPC = NPC + 4;
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(pc.npc() + 8);
+ pc.npc(pc.npc() + 4);
+ PCS = pc;
}});
default: fbfcc(22, test=
{{passesFpCondition(Fsr<11:10>, COND2)}});
}
}
0x1: BranchN::call(30, {{
+ SparcISA::PCState pc = PCS;
if (Pstate<3:>)
- R15 = (xc->readPC())<31:0>;
+ R15 = (pc.pc())<31:0>;
else
- R15 = xc->readPC();
- NNPC = R15 + disp;
+ R15 = pc.pc();
+ pc.nnpc(R15 + disp);
+ PCS = pc;
}});
0x2: decode OP3 {
format IntOp {
0x03: NoPriv::rdasi({{Rd = Asi;}});
0x04: Priv::rdtick({{Rd = Tick;}}, {{Tick<63:>}});
0x05: NoPriv::rdpc({{
+ SparcISA::PCState pc = PCS;
if(Pstate<3:>)
- Rd = (xc->readPC())<31:0>;
+ Rd = (pc.pc())<31:0>;
else
- Rd = xc->readPC();}});
+ Rd = pc.pc();
+ }});
0x06: NoPriv::rdfprs({{
//Wait for all fpops to finish.
Rd = Fprs;
0x51: m5break({{PseudoInst::debugbreak(xc->tcBase());
}}, IsNonSpeculative);
0x54: m5panic({{
- panic("M5 panic instruction called at pc=%#x.", xc->readPC());
+ SparcISA::PCState pc = PCS;
+ panic("M5 panic instruction called at pc=%#x.", pc.pc());
}}, No_OpClass, IsNonSpeculative);
}
#endif
fault = new MemAddressNotAligned;
else
{
+ SparcISA::PCState pc = PCS;
if (Pstate<3:>)
- Rd = (xc->readPC())<31:0>;
+ Rd = (pc.pc())<31:0>;
else
- Rd = xc->readPC();
- NNPC = target;
+ Rd = pc.pc();
+ pc.nnpc(target);
+ PCS = pc;
}
}});
0x39: Branch::return({{
fault = new MemAddressNotAligned;
else
{
- NNPC = target;
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(target);
+ PCS = pc;
Cwp = (Cwp - 1 + NWindows) % NWindows;
Cansave = Cansave + 1;
Canrestore = Canrestore - 1;
Ccr = Tstate<39:32>;
Gl = Tstate<42:40>;
Hpstate = Htstate;
- NPC = Tnpc;
- NNPC = Tnpc + 4;
+ SparcISA::PCState pc = PCS;
+ pc.npc(Tnpc);
+ pc.nnpc(Tnpc + 4);
+ PCS = pc;
Tl = Tl - 1;
}}, checkTl=true);
0x1: Priv::retry({{
Ccr = Tstate<39:32>;
Gl = Tstate<42:40>;
Hpstate = Htstate;
- NPC = Tpc;
- NNPC = Tnpc;
+ SparcISA::PCState pc = PCS;
+ pc.npc(Tpc);
+ pc.nnpc(Tnpc);
+ PCS = pc;
Tl = Tl - 1;
}}, checkTl=true);
}
%(op_decl)s;
%(op_rd)s;
- NNPC = xc->readNextNPC();
+ PCS = PCS;
%(code)s;
if(fault == NoFault)
def doCondBranch(name, Name, base, cond, code, opt_flags):
return doBranch(name, Name, base, cond, code, code,
- 'NPC = NPC; NNPC = NNPC;',
- 'NNPC = NPC + 8; NPC = NPC + 4',
+ 'PCS = PCS;',
+ '''
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(pc.npc() + 8);
+ pc.npc(pc.npc() + 4);
+ PCS = pc;
+ ''',
opt_flags)
def doUncondBranch(name, Name, base, code, annul_code, opt_flags):
return doBranch(name, Name, base, "true", code, annul_code,
";", ";", opt_flags)
- default_branch_code = "NNPC = xc->readPC() + disp;"
+ default_branch_code = '''
+ SparcISA::PCState pc = PCS;
+ pc.nnpc(pc.pc() + disp);
+ PCS = pc;
+ '''
}};
// Format for branch instructions with n bit displacements:
StaticInstPtr * microops;
- StaticInstPtr fetchMicroop(MicroPC microPC)
+ StaticInstPtr
+ fetchMicroop(MicroPC upc) const
{
- assert(microPC < numMicroops);
- return microops[microPC];
+ assert(upc < numMicroops);
+ return microops[upc];
}
%(MacroExecute)s
{
flags[IsMicroop] = true;
}
+
+ void
+ advancePC(SparcISA::PCState &pcState) const
+ {
+ if (flags[IsLastMicroop])
+ pcState.uEnd();
+ else
+ pcState.uAdvance();
+ }
};
class SparcDelayedMicroInst : public SparcMicroInst
#'Frs2': ('FloatReg', 'df', 'dfpr(RS2)', 'IsFloating', 12),
'Frs2_low': ('FloatReg', 'uw', 'dfprl(RS2)', 'IsFloating', 12),
'Frs2_high': ('FloatReg', 'uw', 'dfprh(RS2)', 'IsFloating', 12),
- 'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 31),
- 'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 32),
+ 'PCS': ('PCState', 'udw', None, (None, None, 'IsControl'), 30),
# Registers which are used explicitly in instructions
'R0': ('IntReg', 'udw', '0', None, 6),
'R1': ('IntReg', 'udw', '1', None, 7),
checkReg(*(regName++), regVal, realRegVal);
}
+ SparcISA::PCState pc = tc->pcState();
// PC
read(&realRegVal, sizeof(realRegVal));
realRegVal = SparcISA::gtoh(realRegVal);
- regVal = tc->readNextPC();
+ regVal = pc.npc();
checkReg("pc", regVal, realRegVal);
// NPC
read(&realRegVal, sizeof(realRegVal));
realRegVal = SparcISA::gtoh(realRegVal);
- regVal = tc->readNextNPC();
+ pc.nnpc();
checkReg("npc", regVal, realRegVal);
// CCR
//Use this to give data to the predecoder. This should be used
//when there is control flow.
- void moreBytes(Addr pc, Addr fetchPC, MachInst inst)
+ void moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
//The I bit, bit 13, is used to figure out where the ASI
}
//This returns a constant reference to the ExtMachInst to avoid a copy
- const ExtMachInst & getExtMachInst()
+ const ExtMachInst & getExtMachInst(PCState &pcState)
{
return emi;
}
void SparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc)
{
+ PCState pc = tc->pcState();
switch(trapNum)
{
case 0x01: //Software breakpoint
- warn("Software breakpoint encountered at pc %#x.\n", tc->readPC());
+ warn("Software breakpoint encountered at pc %#x.\n", pc.pc());
break;
case 0x02: //Division by zero
- warn("Software signaled a division by zero at pc %#x.\n",
- tc->readPC());
+ warn("Software signaled a division by zero at pc %#x.\n", pc.pc());
break;
case 0x03: //Flush window trap
flushWindows(tc);
break;
case 0x04: //Clean windows
warn("Ignoring process request for clean register "
- "windows at pc %#x.\n", tc->readPC());
+ "windows at pc %#x.\n", pc.pc());
break;
case 0x05: //Range check
- warn("Software signaled a range check at pc %#x.\n",
- tc->readPC());
+ warn("Software signaled a range check at pc %#x.\n", pc.pc());
break;
case 0x06: //Fix alignment
warn("Ignoring process request for os assisted unaligned accesses "
- "at pc %#x.\n", tc->readPC());
+ "at pc %#x.\n", pc.pc());
break;
case 0x07: //Integer overflow
- warn("Software signaled an integer overflow at pc %#x.\n",
- tc->readPC());
+ warn("Software signaled an integer overflow at pc %#x.\n", pc.pc());
break;
case 0x32: //Get integer condition codes
warn("Ignoring process request to get the integer condition codes "
- "at pc %#x.\n", tc->readPC());
+ "at pc %#x.\n", pc.pc());
break;
case 0x33: //Set integer condition codes
warn("Ignoring process request to set the integer condition codes "
- "at pc %#x.\n", tc->readPC());
+ "at pc %#x.\n", pc.pc());
break;
default:
panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum);
// don't have anything like that, it should be set to 0.
tc->setIntReg(1, 0);
- Addr prog_entry = objFile->entryPoint();
- tc->setPC(prog_entry);
- tc->setNextPC(prog_entry + sizeof(MachInst));
- tc->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ tc->pcState(objFile->entryPoint());
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
{
memset(gdbregs.regs, 0, gdbregs.size);
+ PCState pc = context->pcState();
+
if (context->readMiscReg(MISCREG_PSTATE) &
PSTATE::am) {
uint32_t *regs;
regs = (uint32_t*)gdbregs.regs;
- regs[Reg32Pc] = htobe((uint32_t)context->readPC());
- regs[Reg32Npc] = htobe((uint32_t)context->readNextPC());
+ regs[Reg32Pc] = htobe((uint32_t)pc.pc());
+ regs[Reg32Npc] = htobe((uint32_t)pc.npc());
for(int x = RegG0; x <= RegI0 + 7; x++)
regs[x] = htobe((uint32_t)context->readIntReg(x - RegG0));
regs[Reg32Fsr] = htobe((uint32_t)context->readMiscReg(MISCREG_FSR));
regs[Reg32Csr] = htobe((uint32_t)context->readIntReg(NumIntArchRegs + 2));
} else {
- gdbregs.regs[RegPc] = htobe(context->readPC());
- gdbregs.regs[RegNpc] = htobe(context->readNextPC());
+ gdbregs.regs[RegPc] = htobe(pc.pc());
+ gdbregs.regs[RegNpc] = htobe(pc.npc());
for(int x = RegG0; x <= RegI0 + 7; x++)
gdbregs.regs[x] = htobe(context->readIntReg(x - RegG0));
void
RemoteGDB::setregs()
{
- context->setPC(gdbregs.regs[RegPc]);
- context->setNextPC(gdbregs.regs[RegNpc]);
+ PCState pc;
+ pc.pc(gdbregs.regs[RegPc]);
+ pc.npc(gdbregs.regs[RegNpc]);
+ pc.nnpc(pc.npc() + sizeof(MachInst));
+ pc.upc(0);
+ pc.nupc(1);
+ context->pcState(pc);
for(int x = RegG0; x <= RegI0 + 7; x++)
context->setIntReg(x - RegG0, gdbregs.regs[x]);
//Only the integer registers, pc and npc are set in netbsd
void
RemoteGDB::setSingleStep()
{
- nextBkpt = context->readNextPC();
+ nextBkpt = context->pcState().npc();
setTempBreakpoint(nextBkpt);
}
#include "base/bigint.hh"
#include "base/types.hh"
+#include "arch/generic/types.hh"
namespace SparcISA
{
typedef uint32_t MachInst;
typedef uint64_t ExtMachInst;
+ typedef GenericISA::DelaySlotUPCState<MachInst> PCState;
+
typedef Twin64_t LargestRead;
struct CoreSpecific {
// Copy misc. registers
copyMiscRegs(src, dest);
-
// Lastly copy PC/NPC
- dest->setPC(src->readPC());
- dest->setNextPC(src->readNextPC());
- dest->setNextNPC(src->readNextNPC());
+ dest->pcState(src->pcState());
}
void
skipFunction(ThreadContext *tc)
{
- Addr newpc = tc->readIntReg(ReturnAddressReg);
- tc->setPC(newpc);
- tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst));
- tc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
+ TheISA::PCState newPC = tc->pcState();
+ newPC.set(tc->readIntReg(ReturnAddressReg));
+ tc->pcState(newPC);
}
#include "arch/sparc/tlb.hh"
#include "base/misc.hh"
#include "base/bitfield.hh"
+#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "sim/fault.hh"
namespace SparcISA
{
+
+ inline PCState
+ buildRetPC(const PCState &curPC, const PCState &callPC)
+ {
+ PCState ret = callPC;
+ ret.uEnd();
+ ret.pc(curPC.npc());
+ return ret;
+ }
+
uint64_t
getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp);
void skipFunction(ThreadContext *tc);
+ inline void
+ advancePC(PCState &pc, const StaticInstPtr inst)
+ {
+ inst->advancePC(pc);
+ }
+
} // namespace SparcISA
#endif
#if FULL_SYSTEM
void X86FaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
{
- Addr pc = tc->readPC();
+ PCState pcState = tc->pcState();
+ Addr pc = pcState.pc();
DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc, vector, describe());
using namespace X86ISAInst::RomLabels;
HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
assert(!isSoft());
tc->setIntReg(INTREG_MICRO(15), errorCode);
}
- tc->setMicroPC(romMicroPC(entry));
- tc->setNextMicroPC(romMicroPC(entry) + 1);
+ pcState.upc(romMicroPC(entry));
+ pcState.nupc(romMicroPC(entry) + 1);
+ tc->pcState(pcState);
}
std::string
{
X86FaultBase::invoke(tc);
// This is the same as a fault, but it happens -after- the instruction.
- tc->setPC(tc->readNextPC());
- tc->setNextPC(tc->readNextNPC());
- tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst));
+ PCState pc = tc->pcState();
+ pc.uEnd();
}
void X86Abort::invoke(ThreadContext * tc, StaticInstPtr inst)
tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);
- tc->setPC(0x000000000000fff0ULL +
- tc->readMiscReg(MISCREG_CS_BASE));
- tc->setNextPC(tc->readPC() + sizeof(MachInst));
+ PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE));
+ tc->pcState(pc);
tc->setMiscReg(MISCREG_TSG_BASE, 0);
tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);
// Update the handy M5 Reg.
tc->setMiscReg(MISCREG_M5_REG, 0);
MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt;
- tc->setMicroPC(romMicroPC(entry));
- tc->setNextMicroPC(romMicroPC(entry) + 1);
+ pc.upc(romMicroPC(entry));
+ pc.nupc(romMicroPC(entry) + 1);
+ tc->pcState(pc);
}
void
// This has the base value pre-added.
tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff);
- tc->setPC(tc->readMiscReg(MISCREG_CS_BASE));
- tc->setNextPC(tc->readPC() + sizeof(MachInst));
+ tc->pcState(tc->readMiscReg(MISCREG_CS_BASE));
}
#else
StaticInstPtr * microops;
- StaticInstPtr fetchMicroop(MicroPC microPC)
+ StaticInstPtr
+ fetchMicroop(MicroPC microPC) const
{
assert(microPC < numMicroops);
return microops[microPC];
}
bool checkCondition(uint64_t flags, int condition) const;
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ if (flags[IsLastMicroop])
+ pcState.uEnd();
+ else
+ pcState.uAdvance();
+ }
};
}
panic("Tried to pick with unrecognized size %d.\n", size);
}
}
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ pcState.advance();
+ }
};
}
#endif
0x54: m5panic({{
panic("M5 panic instruction called at pc=%#x.\n",
- xc->readPC());
+ xc->pcState().pc());
}}, IsNonSpeculative);
0x55: m5reserved1({{
warn("M5 reserved opcode 1 ignored.\n");
/**
* Class for Unknown/Illegal instructions
*/
- class Unknown : public StaticInst
+ class Unknown : public X86ISA::X86StaticInst
{
public:
// Constructor
Unknown(ExtMachInst _machInst) :
- StaticInst("unknown", _machInst, No_OpClass)
+ X86ISA::X86StaticInst("unknown", _machInst, No_OpClass)
{
}
code = 'DoubleBits = psrc1 ^ op2;'
class Wrip(WrRegOp, CondRegOp):
- code = 'RIP = psrc1 + sop2 + CSBase'
- else_code="RIP = RIP;"
+ code = '''
+ X86ISA::PCState pc = PCS;
+ pc.npc(psrc1 + sop2 + CSBase);
+ PCS = pc;
+ '''
+ else_code = "PCS = PCS;"
class Wruflags(WrRegOp):
code = 'ccFlagBits = psrc1 ^ op2'
'''
class Rdip(RdRegOp):
- code = 'DestReg = RIP - CSBase'
+ code = '''
+ X86ISA::PCState pc = PCS;
+ DestReg = pc.npc() - CSBase;
+ '''
class Ruflags(RdRegOp):
code = 'DestReg = ccFlagBits'
return super(Eret, self).getAllocator(microFlags)
iop = InstObjParams("br", "MicroBranchFlags", "SeqOpBase",
- {"code": "nuIP = target",
- "else_code": "nuIP = nuIP",
+ {"code": '''
+ X86ISA::PCState pc = PCS;
+ pc.nupc(target);
+ PCS = pc;
+ ''',
+ "else_code": "PCS = PCS",
"cond_test": "checkCondition(ccFlagBits, cc)"})
exec_output += SeqOpExecute.subst(iop)
header_output += SeqOpDeclare.subst(iop)
decoder_output += SeqOpConstructor.subst(iop)
iop = InstObjParams("br", "MicroBranch", "SeqOpBase",
- {"code": "nuIP = target",
- "else_code": "nuIP = nuIP",
+ {"code": '''
+ X86ISA::PCState pc = PCS;
+ pc.nupc(target);
+ PCS = pc;
+ ''',
+ "else_code": "PCS = PCS",
"cond_test": "true"})
exec_output += SeqOpExecute.subst(iop)
header_output += SeqOpDeclare.subst(iop)
'FpSrcReg2': floatReg('src2', 21),
'FpDestReg': floatReg('dest', 22),
'FpData': floatReg('data', 23),
- 'RIP': ('NPC', 'uqw', None, (None, None, 'IsControl'), 50),
- 'uIP': ('UPC', 'uqw', None, (None, None, 'IsControl'), 51),
- 'nuIP': ('NUPC', 'uqw', None, (None, None, 'IsControl'), 52),
+ 'PCS': ('PCState', 'udw', None,
+ (None, None, 'IsControl'), 50),
# This holds the condition code portion of the flag register. The
# nccFlagBits version holds the rest.
'ccFlagBits': intReg('INTREG_PSEUDO(0)', 60),
r13 = tc->readIntReg(X86ISA::INTREG_R13);
r14 = tc->readIntReg(X86ISA::INTREG_R14);
r15 = tc->readIntReg(X86ISA::INTREG_R15);
- rip = tc->readNextPC();
+ rip = tc->pcState().pc();
//This should be expanded if x87 registers are considered
for (int i = 0; i < 8; i++)
mmx[i] = tc->readFloatRegBits(X86ISA::FLOATREG_MMX(i));
//Use this to give data to the predecoder. This should be used
//when there is control flow.
- void moreBytes(Addr pc, Addr fetchPC, MachInst data)
+ void moreBytes(const PCState &pc, Addr fetchPC, MachInst data)
{
DPRINTF(Predecoder, "Getting more bytes.\n");
basePC = fetchPC;
- offset = (fetchPC >= pc) ? 0 : pc - fetchPC;
+ offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
fetchChunk = data;
outOfBytes = false;
process();
return emiIsReady;
}
+ int
+ getInstSize()
+ {
+ int size = basePC + offset - origPC;
+ DPRINTF(Predecoder,
+ "Calculating the instruction size: "
+ "basePC: %#x offset: %#x origPC: %#x size: %d\n",
+ basePC, offset, origPC, size);
+ return size;
+ }
+
//This returns a constant reference to the ExtMachInst to avoid a copy
- const ExtMachInst & getExtMachInst()
+ const ExtMachInst &
+ getExtMachInst(X86ISA::PCState &nextPC)
{
assert(emiIsReady);
emiIsReady = false;
+ nextPC.npc(nextPC.pc() + getInstSize());
return emi;
}
-
- int getInstSize()
- {
- DPRINTF(Predecoder,
- "Calculating the instruction size: "
- "basePC: %#x offset: %#x origPC: %#x\n",
- basePC, offset, origPC);
- return basePC + offset - origPC;
- }
};
};
void
I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
{
- Addr eip = tc->readPC();
+ TheISA::PCState pc = tc->pcState();
+ Addr eip = pc.pc();
if (eip >= vsyscallPage.base &&
eip < vsyscallPage.base + vsyscallPage.size) {
- tc->setNextPC(vsyscallPage.base + vsyscallPage.vsysexitOffset);
+ pc.npc(vsyscallPage.base + vsyscallPage.vsysexitOffset);
+ tc->pcState(pc);
}
X86LiveProcess::syscall(callnum, tc);
}
//Set the stack pointer register
tc->setIntReg(StackPointerReg, stack_min);
- Addr prog_entry = objFile->entryPoint();
// There doesn't need to be any segment base added in since we're dealing
// with the flat segmentation model.
- tc->setPC(prog_entry);
- tc->setNextPC(prog_entry + sizeof(MachInst));
+ tc->pcState(objFile->entryPoint());
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
cr0.pg = 1;
tc->setMiscReg(MISCREG_CR0, cr0);
- tc->setPC(tc->getSystemPtr()->kernelEntry);
- tc->setNextPC(tc->readPC());
+ tc->pcState(tc->getSystemPtr()->kernelEntry);
// We should now be in long mode. Yay!
#else
DPRINTF(TLB, "Handling a TLB miss for "
"address %#x at pc %#x.\n",
- vaddr, tc->readPC());
+ vaddr, tc->instAddr());
Process *p = tc->getProcessPtr();
TlbEntry newEntry;
#include <iostream>
+#include "arch/generic/types.hh"
#include "base/bitunion.hh"
#include "base/cprintf.hh"
#include "base/hashmap.hh"
return true;
}
+ typedef GenericISA::UPCState<MachInst> PCState;
+
struct CoreSpecific {
int core_type;
};
InitInterrupt init(0);
init.invoke(tc);
- tc->setMicroPC(0);
- tc->setNextMicroPC(1);
+ PCState pc = tc->pcState();
+ pc.upc(0);
+ pc.nupc(1);
+ tc->pcState(pc);
// These next two loops zero internal microcode and implicit registers.
// They aren't specified by the ISA but are used internally by M5's
//copy float regs
copyMiscRegs(src, dest);
- dest->setPC(src->readPC());
- dest->setNextPC(src->readNextPC());
+ dest->pcState(src->pcState());
}
void
#include "base/misc.hh"
#include "base/types.hh"
#include "config/full_system.hh"
+#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
class ThreadContext;
namespace X86ISA
{
+
+ inline PCState
+ buildRetPC(const PCState &curPC, const PCState &callPC)
+ {
+ PCState retPC = callPC;
+ retPC.uEnd();
+ return retPC;
+ }
+
uint64_t
getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp);
void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
void skipFunction(ThreadContext *tc);
+
+ inline void
+ advancePC(PCState &pc, const StaticInstPtr inst)
+ {
+ inst->advancePC(pc);
+ }
};
#endif // __ARCH_X86_UTILITY_HH__
bufferSize = gdbregs.bytes() * 2 + 256;
buffer = (char*)malloc(bufferSize);
- DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n",
- context->readPC(), context->readNextPC());
+ TheISA::PCState pc = context->pcState();
+ DPRINTF(GDBMisc, "trap: PC=%s\n", pc);
clearSingleStep();
subcmd = hex2i(&p);
if (*p++ == ';') {
val = hex2i(&p);
- context->setPC(val);
- context->setNextPC(val + sizeof(MachInst));
+ context->pcState(val);
}
clearSingleStep();
goto out;
case GDBCont:
if (p - data < (ptrdiff_t)datalen) {
val = hex2i(&p);
- context->setPC(val);
- context->setNextPC(val + sizeof(MachInst));
+ context->pcState(val);
}
clearSingleStep();
goto out;
subcmd = hex2i(&p);
if (*p++ == ';') {
val = hex2i(&p);
- context->setPC(val);
- context->setNextPC(val + sizeof(MachInst));
+ context->pcState(val);
}
setSingleStep();
goto out;
case GDBStep:
if (p - data < (ptrdiff_t)datalen) {
val = hex2i(&p);
- context->setPC(val);
- context->setNextPC(val + sizeof(MachInst));
+ context->pcState(val);
}
setSingleStep();
goto out;
*/
typedef uint64_t Addr;
+typedef uint16_t MicroPC;
+
+static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1);
+
+static inline MicroPC
+romMicroPC(MicroPC upc)
+{
+ return upc | MicroPCRomBit;
+}
+
+static inline MicroPC
+normalMicroPC(MicroPC upc)
+{
+ return upc & ~MicroPCRomBit;
+}
+
+static inline bool
+isRomMicroPC(MicroPC upc)
+{
+ return MicroPCRomBit & upc;
+}
+
const Addr MaxAddr = (Addr)-1;
/**
#include <string>
#include "arch/faults.hh"
+#include "arch/utility.hh"
#include "base/fast_alloc.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
/** Records changes to result? */
bool recordResult;
- /** PC of this instruction. */
- Addr PC;
-
- /** Micro PC of this instruction. */
- Addr microPC;
-
/** Did this instruction execute, or is it predicated false */
bool predicate;
protected:
- /** Next non-speculative PC. It is not filled in at fetch, but rather
- * once the target of the branch is truly known (either decode or
- * execute).
- */
- Addr nextPC;
-
- /** Next non-speculative NPC. Target PC for Mips or Sparc. */
- Addr nextNPC;
+ /** PC state for this instruction. */
+ TheISA::PCState pc;
- /** Next non-speculative micro PC. */
- Addr nextMicroPC;
-
- /** Predicted next PC. */
- Addr predPC;
-
- /** Predicted next NPC. */
- Addr predNPC;
-
- /** Predicted next microPC */
- Addr predMicroPC;
+ /** Predicted PC state after this instruction. */
+ TheISA::PCState predPC;
/** If this is a branch that was predicted taken */
bool predTaken;
}
/** BaseDynInst constructor given a binary instruction.
* @param staticInst A StaticInstPtr to the underlying instruction.
- * @param PC The PC of the instruction.
- * @param pred_PC The predicted next PC.
- * @param pred_NPC The predicted next NPC.
+ * @param pc The PC state for the instruction.
+ * @param predPC The predicted next PC state for the instruction.
* @param seq_num The sequence number of the instruction.
* @param cpu Pointer to the instruction's CPU.
*/
- BaseDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
- Addr pred_PC, Addr pred_NPC, Addr pred_MicroPC,
- InstSeqNum seq_num, ImplCPU *cpu);
+ BaseDynInst(StaticInstPtr staticInst, TheISA::PCState pc,
+ TheISA::PCState predPC, InstSeqNum seq_num, ImplCPU *cpu);
/** BaseDynInst constructor given a binary instruction.
* @param inst The binary instruction.
- * @param PC The PC of the instruction.
- * @param pred_PC The predicted next PC.
- * @param pred_NPC The predicted next NPC.
+ * @param _pc The PC state for the instruction.
+ * @param _predPC The predicted next PC state for the instruction.
* @param seq_num The sequence number of the instruction.
* @param cpu Pointer to the instruction's CPU.
*/
- BaseDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
- Addr pred_PC, Addr pred_NPC, Addr pred_MicroPC,
- InstSeqNum seq_num, ImplCPU *cpu);
+ BaseDynInst(TheISA::ExtMachInst inst, TheISA::PCState pc,
+ TheISA::PCState predPC, InstSeqNum seq_num, ImplCPU *cpu);
/** BaseDynInst constructor given a StaticInst pointer.
* @param _staticInst The StaticInst for this BaseDynInst.
*/
bool doneTargCalc() { return false; }
- /** Returns the next PC. This could be the speculative next PC if it is
- * called prior to the actual branch target being calculated.
- */
- Addr readNextPC() { return nextPC; }
-
- /** Returns the next NPC. This could be the speculative next NPC if it is
- * called prior to the actual branch target being calculated.
- */
- Addr readNextNPC()
- {
-#if ISA_HAS_DELAY_SLOT
- return nextNPC;
-#else
- return nextPC + sizeof(TheISA::MachInst);
-#endif
- }
-
- Addr readNextMicroPC()
- {
- return nextMicroPC;
- }
-
/** Set the predicted target of this current instruction. */
- void setPredTarg(Addr predicted_PC, Addr predicted_NPC,
- Addr predicted_MicroPC)
+ void setPredTarg(const TheISA::PCState &_predPC)
{
- predPC = predicted_PC;
- predNPC = predicted_NPC;
- predMicroPC = predicted_MicroPC;
+ predPC = _predPC;
}
+ const TheISA::PCState &readPredTarg() { return predPC; }
+
/** Returns the predicted PC immediately after the branch. */
- Addr readPredPC() { return predPC; }
+ Addr predInstAddr() { return predPC.instAddr(); }
/** Returns the predicted PC two instructions after the branch */
- Addr readPredNPC() { return predNPC; }
+ Addr predNextInstAddr() { return predPC.nextInstAddr(); }
/** Returns the predicted micro PC after the branch */
- Addr readPredMicroPC() { return predMicroPC; }
+ Addr predMicroPC() { return predPC.microPC(); }
/** Returns whether the instruction was predicted taken or not. */
bool readPredTaken()
/** Returns whether the instruction mispredicted. */
bool mispredicted()
{
- return readPredPC() != readNextPC() ||
- readPredNPC() != readNextNPC() ||
- readPredMicroPC() != readNextMicroPC();
+ TheISA::PCState tempPC = pc;
+ TheISA::advancePC(tempPC, staticInst);
+ return !(tempPC == predPC);
}
//
OpClass opClass() const { return staticInst->opClass(); }
/** Returns the branch target address. */
- Addr branchTarget() const { return staticInst->branchTarget(PC); }
+ TheISA::PCState branchTarget() const
+ { return staticInst->branchTarget(pc); }
/** Returns the number of source registers. */
int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
/** Returns whether or not this instruction is squashed in the ROB. */
bool isSquashedInROB() const { return status[SquashedInROB]; }
- /** Read the PC of this instruction. */
- const Addr readPC() const { return PC; }
+ /** Read the PC state of this instruction. */
+ const TheISA::PCState pcState() const { return pc; }
- /**Read the micro PC of this instruction. */
- const Addr readMicroPC() const { return microPC; }
+ /** Set the PC state of this instruction. */
+ const void pcState(const TheISA::PCState &val) { pc = val; }
- /** Set the next PC of this instruction (its actual target). */
- void setNextPC(Addr val)
- {
- nextPC = val;
- }
+ /** Read the PC of this instruction. */
+ const Addr instAddr() const { return pc.instAddr(); }
- /** Set the next NPC of this instruction (the target in Mips or Sparc).*/
- void setNextNPC(Addr val)
- {
-#if ISA_HAS_DELAY_SLOT
- nextNPC = val;
-#endif
- }
+ /** Read the PC of the next instruction. */
+ const Addr nextInstAddr() const { return pc.nextInstAddr(); }
- void setNextMicroPC(Addr val)
- {
- nextMicroPC = val;
- }
+ /**Read the micro PC of this instruction. */
+ const Addr microPC() const { return pc.microPC(); }
bool readPredicate()
{
unsigned size, unsigned flags)
{
reqMade = true;
- Request *req = new Request(asid, addr, size, flags, this->PC,
+ Request *req = new Request(asid, addr, size, flags, this->pc.instAddr(),
thread->contextId(), threadNumber);
Request *sreqLow = NULL;
}
reqMade = true;
- Request *req = new Request(asid, addr, size, flags, this->PC,
+ Request *req = new Request(asid, addr, size, flags, this->pc.instAddr(),
thread->contextId(), threadNumber);
Request *sreqLow = NULL;
template <class Impl>
BaseDynInst<Impl>::BaseDynInst(StaticInstPtr _staticInst,
- Addr inst_PC, Addr inst_NPC,
- Addr inst_MicroPC,
- Addr pred_PC, Addr pred_NPC,
- Addr pred_MicroPC,
+ TheISA::PCState _pc, TheISA::PCState _predPC,
InstSeqNum seq_num, ImplCPU *cpu)
: staticInst(_staticInst), traceData(NULL), cpu(cpu)
{
seqNum = seq_num;
- bool nextIsMicro =
- staticInst->isMicroop() && !staticInst->isLastMicroop();
-
- PC = inst_PC;
- microPC = inst_MicroPC;
- if (nextIsMicro) {
- nextPC = inst_PC;
- nextNPC = inst_NPC;
- nextMicroPC = microPC + 1;
- } else {
- nextPC = inst_NPC;
- nextNPC = nextPC + sizeof(TheISA::MachInst);
- nextMicroPC = 0;
- }
- predPC = pred_PC;
- predNPC = pred_NPC;
- predMicroPC = pred_MicroPC;
+ pc = _pc;
+ predPC = _predPC;
predTaken = false;
initVars();
template <class Impl>
BaseDynInst<Impl>::BaseDynInst(TheISA::ExtMachInst inst,
- Addr inst_PC, Addr inst_NPC,
- Addr inst_MicroPC,
- Addr pred_PC, Addr pred_NPC,
- Addr pred_MicroPC,
+ TheISA::PCState _pc, TheISA::PCState _predPC,
InstSeqNum seq_num, ImplCPU *cpu)
- : staticInst(inst, inst_PC), traceData(NULL), cpu(cpu)
+ : staticInst(inst, _pc.instAddr()), traceData(NULL), cpu(cpu)
{
seqNum = seq_num;
- bool nextIsMicro =
- staticInst->isMicroop() && !staticInst->isLastMicroop();
-
- PC = inst_PC;
- microPC = inst_MicroPC;
- if (nextIsMicro) {
- nextPC = inst_PC;
- nextNPC = inst_NPC;
- nextMicroPC = microPC + 1;
- } else {
- nextPC = inst_NPC;
- nextNPC = nextPC + sizeof(TheISA::MachInst);
- nextMicroPC = 0;
- }
- predPC = pred_PC;
- predNPC = pred_NPC;
- predMicroPC = pred_MicroPC;
+ pc = _pc;
+ predPC = _predPC;
predTaken = false;
initVars();
void
BaseDynInst<Impl>::dump()
{
- cprintf("T%d : %#08d `", threadNumber, PC);
- std::cout << staticInst->disassemble(PC);
+ cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
+ std::cout << staticInst->disassemble(pc.instAddr());
cprintf("'\n");
}
BaseDynInst<Impl>::dump(std::string &outstring)
{
std::ostringstream s;
- s << "T" << threadNumber << " : 0x" << PC << " "
- << staticInst->disassemble(PC);
+ s << "T" << threadNumber << " : 0x" << pc.instAddr() << " "
+ << staticInst->disassemble(pc.instAddr());
outstring = s.str();
}
result.integer = val;
}
- uint64_t readPC() { return thread->readPC(); }
+ uint64_t instAddr() { return thread->instAddr(); }
- uint64_t readNextPC() { return thread->readNextPC(); }
-
- void setNextPC(uint64_t val) {
- thread->setNextPC(val);
- }
+ uint64_t nextInstAddr() { return thread->nextInstAddr(); }
MiscReg readMiscRegNoEffect(int misc_reg)
{
std::string sym_str;
Addr sym_addr;
- Addr cur_pc = PC;
-#if THE_ISA == ARM_ISA
- cur_pc &= ~PcModeMask;
-#endif
+ Addr cur_pc = pc.instAddr();
if (debugSymbolTable
&& IsOn(ExecSymbol)
#if FULL_SYSTEM
if (cur_pc != sym_addr)
sym_str += csprintf("+%d",cur_pc - sym_addr);
outs << "@" << sym_str;
- }
- else {
+ } else {
outs << "0x" << hex << cur_pc;
}
if (inst->isMicroop()) {
- outs << "." << setw(2) << dec << upc;
+ outs << "." << setw(2) << dec << pc.microPC();
} else {
outs << " ";
}
{
public:
ExeTracerRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr _staticInst, Addr _pc, bool spec,
- const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ const StaticInstPtr _staticInst, TheISA::PCState _pc,
+ bool spec, const StaticInstPtr _macroStaticInst = NULL)
: InstRecord(_when, _thread, _staticInst, _pc, spec,
- _macroStaticInst, _upc)
+ _macroStaticInst)
{
}
InstRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
+ const StaticInstPtr staticInst, TheISA::PCState pc,
+ const StaticInstPtr macroStaticInst = NULL)
{
if (!IsOn(ExecEnable))
return NULL;
return NULL;
return new ExeTracerRecord(when, tc,
- staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
+ staticInst, pc, tc->misspeculating(), macroStaticInst);
}
};
// struct as it is used pretty frequently.
bool branchMispredict;
bool branchTaken;
- uint64_t mispredPC;
- uint64_t nextPC;
+ Addr mispredPC;
+ TheISA::PCState nextPC;
unsigned branchCount;
return pipelineStage[stage_num];
}
-uint64_t
-InOrderCPU::readPC(ThreadID tid)
-{
- return PC[tid];
-}
-
-
-void
-InOrderCPU::setPC(Addr new_PC, ThreadID tid)
-{
- PC[tid] = new_PC;
-}
-
-
-uint64_t
-InOrderCPU::readNextPC(ThreadID tid)
-{
- return nextPC[tid];
-}
-
-
-void
-InOrderCPU::setNextPC(uint64_t new_NPC, ThreadID tid)
-{
- nextPC[tid] = new_NPC;
-}
-
-
-uint64_t
-InOrderCPU::readNextNPC(ThreadID tid)
-{
- return nextNPC[tid];
-}
-
-
-void
-InOrderCPU::setNextNPC(uint64_t new_NNPC, ThreadID tid)
-{
- nextNPC[tid] = new_NNPC;
-}
-
uint64_t
InOrderCPU::readIntReg(int reg_idx, ThreadID tid)
{
// Set the CPU's PCs - This contributes to the precise state of the CPU
// which can be used when restoring a thread to the CPU after after any
// type of context switching activity (fork, exception, etc.)
- setPC(inst->readPC(), tid);
- setNextPC(inst->readNextPC(), tid);
- setNextNPC(inst->readNextNPC(), tid);
+ pcState(inst->pcState(), tid);
if (inst->isControl()) {
thread[tid]->lastGradIsBranch = true;
- thread[tid]->lastBranchPC = inst->readPC();
- thread[tid]->lastBranchNextPC = inst->readNextPC();
- thread[tid]->lastBranchNextNPC = inst->readNextNPC();
+ thread[tid]->lastBranchPC = inst->pcState();
+ TheISA::advancePC(thread[tid]->lastBranchPC, inst->staticInst);
} else {
thread[tid]->lastGradIsBranch = false;
}
{
removeInstsThisCycle = true;
if (!inst->isRemoveList()) {
- DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %#x "
+ DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %s "
"[sn:%lli] to remove list\n",
- inst->threadNumber, inst->readPC(), inst->seqNum);
+ inst->threadNumber, inst->pcState(), inst->seqNum);
inst->setRemoveList();
removeList.push(inst->getInstListIt());
} else {
- DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i] PC %#x "
+ DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i] PC %s "
"[sn:%lli], already remove list\n",
- inst->threadNumber, inst->readPC(), inst->seqNum);
+ inst->threadNumber, inst->pcState(), inst->seqNum);
}
}
void
InOrderCPU::removeInst(DynInstPtr &inst)
{
- DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x "
+ DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %s "
"[sn:%lli]\n",
- inst->threadNumber, inst->readPC(), inst->seqNum);
+ inst->threadNumber, inst->pcState(), inst->seqNum);
removeInstsThisCycle = true;
// Remove the instruction.
if (!inst->isRemoveList()) {
- DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %#x "
+ DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %s "
"[sn:%lli] to remove list\n",
- inst->threadNumber, inst->readPC(), inst->seqNum);
+ inst->threadNumber, inst->pcState(), inst->seqNum);
inst->setRemoveList();
removeList.push(inst->getInstListIt());
} else {
- DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i] PC %#x "
+ DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i] PC %s "
"[sn:%lli], already on remove list\n",
- inst->threadNumber, inst->readPC(), inst->seqNum);
+ inst->threadNumber, inst->pcState(), inst->seqNum);
}
}
{
if ((*instIt)->threadNumber == tid) {
DPRINTF(InOrderCPU, "Squashing instruction, "
- "[tid:%i] [sn:%lli] PC %#x\n",
+ "[tid:%i] [sn:%lli] PC %s\n",
(*instIt)->threadNumber,
(*instIt)->seqNum,
- (*instIt)->readPC());
+ (*instIt)->pcState());
(*instIt)->setSquashed();
if (!(*instIt)->isRemoveList()) {
- DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %#x "
+ DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %s "
"[sn:%lli] to remove list\n",
- (*instIt)->threadNumber, (*instIt)->readPC(),
+ (*instIt)->threadNumber, (*instIt)->pcState(),
(*instIt)->seqNum);
(*instIt)->setRemoveList();
removeList.push(instIt);
} else {
DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i]"
- " PC %#x [sn:%lli], already on remove list\n",
- (*instIt)->threadNumber, (*instIt)->readPC(),
+ " PC %s [sn:%lli], already on remove list\n",
+ (*instIt)->threadNumber, (*instIt)->pcState(),
(*instIt)->seqNum);
}
{
while (!removeList.empty()) {
DPRINTF(InOrderCPU, "Removing instruction, "
- "[tid:%i] [sn:%lli] PC %#x\n",
+ "[tid:%i] [sn:%lli] PC %s\n",
(*removeList.front())->threadNumber,
(*removeList.front())->seqNum,
- (*removeList.front())->readPC());
+ (*removeList.front())->pcState());
DynInstPtr inst = *removeList.front();
ThreadID tid = inst->threadNumber;
cprintf("Dumping Instruction List\n");
while (inst_list_it != instList[0].end()) {
- cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
+ cprintf("Instruction:%i\nPC:%s\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
"Squashed:%i\n\n",
- num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
+ num, (*inst_list_it)->pcState(),
+ (*inst_list_it)->threadNumber,
(*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
(*inst_list_it)->isSquashed());
inst_list_it++;
PipelineStage *pipelineStage[ThePipeline::NumStages];
/** Program Counters */
- TheISA::IntReg PC[ThePipeline::MaxThreads];
- TheISA::IntReg nextPC[ThePipeline::MaxThreads];
- TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
+ TheISA::PCState pc[ThePipeline::MaxThreads];
/** The Register File for the CPU */
union {
ThreadID tid);
/** Reads the commit PC of a specific thread. */
- uint64_t readPC(ThreadID tid);
+ TheISA::PCState
+ pcState(ThreadID tid)
+ {
+ return pc[tid];
+ }
/** Sets the commit PC of a specific thread. */
- void setPC(Addr new_PC, ThreadID tid);
-
- /** Reads the next PC of a specific thread. */
- uint64_t readNextPC(ThreadID tid);
-
- /** Sets the next PC of a specific thread. */
- void setNextPC(uint64_t val, ThreadID tid);
-
- /** Reads the next NPC of a specific thread. */
- uint64_t readNextNPC(ThreadID tid);
+ void
+ pcState(const TheISA::PCState &newPC, ThreadID tid)
+ {
+ pc[tid] = newPC;
+ }
- /** Sets the next NPC of a specific thread. */
- void setNextNPC(uint64_t val, ThreadID tid);
+ Addr instAddr(ThreadID tid) { return pc[tid].instAddr(); }
+ Addr nextInstAddr(ThreadID tid) { return pc[tid].nextInstAddr(); }
+ MicroPC microPC(ThreadID tid) { return pc[tid].microPC(); }
/** Function to add instruction onto the head of the list of the
* instructions. Used when new instructions are fetched.
break;
}
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] "
- "PC %08p.\n", tid, insts[tid].front()->seqNum,
- insts[tid].front()->PC);
+ "PC %s.\n", tid, insts[tid].front()->seqNum,
+ insts[tid].front()->pc);
insts[tid].pop();
}
using namespace TheISA;
using namespace ThePipeline;
-InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC,
- Addr pred_PC, InstSeqNum seq_num,
- InOrderCPU *cpu)
- : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu)
+InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst,
+ const TheISA::PCState &instPC,
+ const TheISA::PCState &_predPC,
+ InstSeqNum seq_num, InOrderCPU *cpu)
+ : staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu)
{
seqNum = seq_num;
- PC = inst_PC;
- nextPC = PC + sizeof(MachInst);
- nextNPC = nextPC + sizeof(MachInst);
- predPC = pred_PC;
+ pc = instPC;
+ predPC = _predPC;
initVars();
}
void
InOrderDynInst::setMachInst(ExtMachInst machInst)
{
- staticInst = StaticInst::decode(machInst, PC);
+ staticInst = StaticInst::decode(machInst, pc.instAddr());
for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
void
InOrderDynInst::dump()
{
- cprintf("T%d : %#08d `", threadNumber, PC);
- cout << staticInst->disassemble(PC);
+ cprintf("T%d : %#08d `", threadNumber, pc.instAddr());
+ cout << staticInst->disassemble(pc.instAddr());
cprintf("'\n");
}
InOrderDynInst::dump(std::string &outstring)
{
std::ostringstream s;
- s << "T" << threadNumber << " : 0x" << PC << " "
- << staticInst->disassemble(PC);
+ s << "T" << threadNumber << " : " << pc << " "
+ << staticInst->disassemble(pc.instAddr());
outstring = s.str();
}
#include "arch/isa_traits.hh"
#include "arch/mt.hh"
#include "arch/types.hh"
+#include "arch/utility.hh"
#include "base/fast_alloc.hh"
#include "base/trace.hh"
#include "base/types.hh"
/** BaseDynInst constructor given a binary instruction.
* @param inst The binary instruction.
* @param PC The PC of the instruction.
- * @param pred_PC The predicted next PC.
+ * @param predPC The predicted next PC.
* @param seq_num The sequence number of the instruction.
* @param cpu Pointer to the instruction's CPU.
*/
- InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num,
- InOrderCPU *cpu);
+ InOrderDynInst(ExtMachInst inst, const TheISA::PCState &PC,
+ const TheISA::PCState &predPC, InstSeqNum seq_num,
+ InOrderCPU *cpu);
/** BaseDynInst constructor given a binary instruction.
* @param seq_num The sequence number of the instruction.
InstResult instResult[MaxInstDestRegs];
/** PC of this instruction. */
- Addr PC;
-
- /** Next non-speculative PC. It is not filled in at fetch, but rather
- * once the target of the branch is truly known (either decode or
- * execute).
- */
- Addr nextPC;
-
- /** Next next non-speculative PC. It is not filled in at fetch, but rather
- * once the target of the branch is truly known (either decode or
- * execute).
- */
- Addr nextNPC;
+ TheISA::PCState pc;
/** Predicted next PC. */
- Addr predPC;
-
- /** Predicted next NPC. */
- Addr predNPC;
-
- /** Predicted next microPC */
- Addr predMicroPC;
+ TheISA::PCState predPC;
/** Address to fetch from */
Addr fetchAddr;
//
////////////////////////////////////////////////////////////
/** Read the PC of this instruction. */
- const Addr readPC() const { return PC; }
+ const TheISA::PCState &pcState() const { return pc; }
/** Sets the PC of this instruction. */
- void setPC(Addr pc) { PC = pc; }
-
- /** Returns the next PC. This could be the speculative next PC if it is
- * called prior to the actual branch target being calculated.
- */
- Addr readNextPC() { return nextPC; }
+ void pcState(const TheISA::PCState &_pc) { pc = _pc; }
- /** Set the next PC of this instruction (its actual target). */
- void setNextPC(uint64_t val) { nextPC = val; }
-
- /** Returns the next NPC. This could be the speculative next NPC if it is
- * called prior to the actual branch target being calculated.
- */
- Addr readNextNPC()
- {
-#if ISA_HAS_DELAY_SLOT
- return nextNPC;
-#else
- return nextPC + sizeof(TheISA::MachInst);
-#endif
- }
-
- /** Set the next PC of this instruction (its actual target). */
- void setNextNPC(uint64_t val) { nextNPC = val; }
+ const Addr instAddr() { return pc.instAddr(); }
+ const Addr nextInstAddr() { return pc.nextInstAddr(); }
+ const MicroPC microPC() { return pc.microPC(); }
////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////
/** Set the predicted target of this current instruction. */
- void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; }
+ void setPredTarg(const TheISA::PCState &predictedPC)
+ { predPC = predictedPC; }
/** Returns the predicted target of the branch. */
- Addr readPredTarg() { return predPC; }
+ TheISA::PCState readPredTarg() { return predPC; }
/** Returns the predicted PC immediately after the branch. */
- Addr readPredPC() { return predPC; }
+ Addr predInstAddr() { return predPC.instAddr(); }
/** Returns the predicted PC two instructions after the branch */
- Addr readPredNPC() { return predNPC; }
+ Addr predNextInstAddr() { return predPC.nextInstAddr(); }
/** Returns the predicted micro PC after the branch */
- Addr readPredMicroPC() { return predMicroPC; }
+ Addr readPredMicroPC() { return predPC.microPC(); }
/** Returns whether the instruction was predicted taken or not. */
bool predTaken() { return predictTaken; }
/** Returns whether the instruction mispredicted. */
- bool mispredicted()
+ bool
+ mispredicted()
{
-#if ISA_HAS_DELAY_SLOT
- return predPC != nextNPC;
-#else
- return predPC != nextPC;
-#endif
+ TheISA::PCState nextPC = pc;
+ TheISA::advancePC(nextPC, staticInst);
+ return !(nextPC == predPC);
}
- /** Returns whether the instruction mispredicted. */
- bool mistargeted() { return predPC != nextNPC; }
-
/** Returns the branch target address. */
- Addr branchTarget() const { return staticInst->branchTarget(PC); }
+ TheISA::PCState branchTarget() const
+ { return staticInst->branchTarget(pc); }
/** Checks whether or not this instruction has had its branch target
* calculated yet. For now it is not utilized and is hacked to be
if (!Trace::enabled)
return NULL;
- return new InOrderTraceRecord(num_stages, stage_tracing, tc);
+ return new InOrderTraceRecord(num_stages, stage_tracing, tc, 0);
}
InOrderTraceRecord *
InOrderTrace::getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst, MicroPC upc)
+ const StaticInstPtr staticInst, TheISA::PCState _pc,
+ const StaticInstPtr macroStaticInst)
{
- return new InOrderTraceRecord(ThePipeline::NumStages, true, tc);
+ return new InOrderTraceRecord(ThePipeline::NumStages, true, tc, _pc);
}
/* namespace Trace */ }
{
public:
InOrderTraceRecord(unsigned num_stages, bool _stage_tracing,
- ThreadContext *_thread, bool spec = false)
- : ExeTracerRecord(0, _thread, NULL, 0, spec)
+ ThreadContext *_thread, TheISA::PCState _pc, bool spec = false)
+ : ExeTracerRecord(0, _thread, NULL, _pc, spec)
{
stageTrace = _stage_tracing;
stageCycle.resize(num_stages);
{
staticInst = _staticInst;
}
- void setPC(Addr _pc) { PC = _pc; }
+
+ void setPC(TheISA::PCState _pc) { pc = _pc; }
};
class InOrderTrace : public InstTracer
InOrderTraceRecord *
getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc);
- virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0);
+ InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
+ const StaticInstPtr staticInst, TheISA::PCState pc,
+ const StaticInstPtr macroStaticInst = NULL);
};
/* namespace Trace */ }
toPrevStages->stageInfo[stageNum][tid].squash = true;
toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg();
+ toPrevStages->stageInfo[stageNum][tid].branchTaken =
+ inst->pcState().branching();
#if ISA_HAS_DELAY_SLOT
- toPrevStages->stageInfo[stageNum][tid].branchTaken =
- inst->readNextNPC() !=
- (inst->readNextPC() + sizeof(TheISA::MachInst));
-
- toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum =
+ toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum =
inst->bdelaySeqNum;
InstSeqNum squash_seq_num = inst->bdelaySeqNum;
#else
- toPrevStages->stageInfo[stageNum][tid].branchTaken =
- inst->readNextPC() !=
- (inst->readPC() + sizeof(TheISA::MachInst));
-
toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->seqNum;
InstSeqNum squash_seq_num = inst->seqNum;
#endif
DPRINTF(InOrderStage, "Target being re-set to %08p\n",
- inst->readPredTarg());
+ inst->predInstAddr());
DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], "
"due to [sn:%i] branch.\n", tid, squash_seq_num,
inst->seqNum);
prevStage->insts[i]->seqNum > squash_seq_num) {
// Change Comment to Annulling previous instruction
DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, "
- "[sn:%i] PC %08p.\n",
+ "[sn:%i] PC %s.\n",
tid,
prevStage->insts[i]->seqNum,
- prevStage->insts[i]->readPC());
+ prevStage->insts[i]->pcState());
prevStage->insts[i]->setSquashed();
prevStage->insts[i] = cpu->dummyBufferInst;
break;
}
DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] "
- " PC %08p.\n", tid, skidBuffer[tid].front()->seqNum,
- skidBuffer[tid].front()->PC);
+ " PC %s.\n", tid, skidBuffer[tid].front()->seqNum,
+ skidBuffer[tid].front()->pc);
skidBuffer[tid].pop();
}
assert(tid == inst->threadNumber);
- DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage "
- "skidBuffer %i\n", tid, inst->seqNum, inst->readPC(),
+ DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%s into stage "
+ "skidBuffer %i\n", tid, inst->seqNum, inst->pcState(),
inst->threadNumber);
skidBuffer[tid].push(inst);
} else {
DynInstPtr inst = switchedOutBuffer[tid];
- DPRINTF(InOrderStage,"[tid:%i]: Re-Inserting [sn:%lli] PC:%#x into"
+ DPRINTF(InOrderStage,"[tid:%i]: Re-Inserting [sn:%lli] PC:%s into"
" stage skidBuffer %i\n", tid, inst->seqNum,
- inst->readPC(), inst->threadNumber);
+ inst->pcState(), inst->threadNumber);
// Make instruction available for pipeline processing
skidBuffer[tid].push(inst);
inst = insts_to_stage.front();
DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] "
- "with PC %#x\n",
- tid, inst->seqNum, inst->readPC());
+ "with PC %s\n", tid, inst->seqNum, inst->pcState());
if (inst->isSquashed()) {
- DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %#x is "
+ DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %s is "
"squashed, skipping.\n",
- tid, inst->seqNum, inst->readPC());
+ tid, inst->seqNum, inst->pcState());
insts_to_stage.pop();
switchedOutValid[tid] = true;
// Remove Thread From Pipeline & Resource Pool
- inst->squashingStage = stageNum;
- inst->bdelaySeqNum = inst->seqNum;
+ inst->squashingStage = stageNum;
+ inst->bdelaySeqNum = inst->seqNum;
cpu->squashFromMemStall(inst, tid);
// Switch On Cache Miss
res_stage_num = inst->nextResStage();
}
} else {
- DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %#x "
+ DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %s "
" needed no resources in stage %i.\n",
- tid, inst->seqNum, inst->readPC(), stageNum);
+ tid, inst->seqNum, inst->pcState(), stageNum);
}
return last_req_completed;
while (!copy_buff.empty()) {
DynInstPtr inst = copy_buff.front();
- cprintf("Inst. PC:%#x\n[tid:%i]\n[sn:%i]\n\n",
- inst->readPC(), inst->threadNumber, inst->seqNum);
+ cprintf("Inst. PC:%s\n[tid:%i]\n[sn:%i]\n\n",
+ inst->pcState(), inst->threadNumber, inst->seqNum);
copy_buff.pop();
}
/** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */
Addr bdelayDoneSeqNum[ThePipeline::MaxThreads];
- /** Instruction used for squashing branch (used for MIPS) */
- DynInstPtr squashInst[ThePipeline::MaxThreads];
-
/** Tells when their is a pending delay slot inst. to send
* to rename. If there is, then wait squash after the next
* instruction (used for MIPS).
*/
bool squashAfterDelaySlot[ThePipeline::MaxThreads];
+ /** Instruction used for squashing branch (used for MIPS) */
+ DynInstPtr squashInst[ThePipeline::MaxThreads];
+
/** Maximum size of the inter-stage buffer connecting the previous stage to
* this stage (which we call a skid buffer) */
unsigned stageBufferMax;
#include <list>
#include <vector>
+#include "arch/utility.hh"
#include "base/trace.hh"
#include "base/traceflags.hh"
#include "config/the_isa.hh"
bool
-BPredUnit::predict(DynInstPtr &inst, Addr &pred_PC, ThreadID tid)
+BPredUnit::predict(DynInstPtr &inst, TheISA::PCState &predPC, ThreadID tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
int asid = inst->asid;
bool pred_taken = false;
- Addr target;
+ TheISA::PCState target;
++lookups;
- DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] %s ... PC%#x doing branch "
+ DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
"prediction\n", tid, inst->seqNum,
- inst->staticInst->disassemble(inst->PC), inst->readPC());
+ inst->staticInst->disassemble(inst->instAddr()),
+ inst->pcState());
void *bp_history = NULL;
} else {
++condPredicted;
- pred_taken = BPLookup(pred_PC, bp_history);
+ pred_taken = BPLookup(predPC.instAddr(), bp_history);
DPRINTF(InOrderBPred, "[tid:%i]: Branch predictor predicted %i "
- "for PC %#x\n",
- tid, pred_taken, inst->readPC());
+ "for PC %s\n",
+ tid, pred_taken, inst->pcState());
}
- PredictorHistory predict_record(inst->seqNum, pred_PC, pred_taken,
+ PredictorHistory predict_record(inst->seqNum, predPC, pred_taken,
bp_history, tid);
// Now lookup in the BTB or RAS.
// If it's a function return call, then look up the address
// in the RAS.
- target = RAS[tid].top();
+ TheISA::PCState rasTop = RAS[tid].top();
+ target = TheISA::buildRetPC(inst->pcState(), rasTop);
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
- predict_record.RASTarget = target;
+ predict_record.rasTarget = rasTop;
assert(predict_record.RASIndex < 16);
RAS[tid].pop();
- DPRINTF(InOrderBPred, "[tid:%i]: Instruction %#x is a return, "
- "RAS predicted target: %#x, RAS index: %i.\n",
- tid, inst->readPC(), target, predict_record.RASIndex);
+ DPRINTF(InOrderBPred, "[tid:%i]: Instruction %s is a return, "
+ "RAS predicted target: %s, RAS index: %i.\n",
+ tid, inst->pcState(), target,
+ predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
-#if ISA_HAS_DELAY_SLOT
- Addr ras_pc = pred_PC + instSize; // Next Next PC
-#else
- Addr ras_pc = pred_PC; // Next PC
-#endif
-
- RAS[tid].push(ras_pc);
+ RAS[tid].push(inst->pcState());
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
predict_record.wasCall = true;
- DPRINTF(InOrderBPred, "[tid:%i]: Instruction %#x was a call"
- ", adding %#x to the RAS index: %i.\n",
- tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
+ DPRINTF(InOrderBPred, "[tid:%i]: Instruction %s was a call"
+ ", adding %s to the RAS index: %i.\n",
+ tid, inst->pcState(), predPC,
+ RAS[tid].topIdx());
}
if (inst->isCall() &&
inst->isDirectCtrl()) {
target = inst->branchTarget();
- DPRINTF(InOrderBPred, "[tid:%i]: Setting %#x predicted"
- " target to %#x.\n",
- tid, inst->readPC(), target);
- } else if (BTB.valid(pred_PC, asid)) {
+ DPRINTF(InOrderBPred, "[tid:%i]: Setting %s predicted"
+ " target to %s.\n",
+ tid, inst->pcState(), target);
+ } else if (BTB.valid(predPC.instAddr(), asid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
- target = BTB.lookup(pred_PC, asid);
+ target = BTB.lookup(predPC.instAddr(), asid);
- DPRINTF(InOrderBPred, "[tid:%i]: [asid:%i] Instruction %#x "
- "predicted target is %#x.\n",
- tid, asid, inst->readPC(), target);
+ DPRINTF(InOrderBPred, "[tid:%i]: [asid:%i] Instruction %s "
+ "predicted target is %s.\n",
+ tid, asid, inst->pcState(), target);
} else {
DPRINTF(InOrderBPred, "[tid:%i]: BTB doesn't have a "
"valid entry.\n",tid);
if (pred_taken) {
// Set the PC and the instruction's predicted target.
- pred_PC = target;
- } else {
-#if ISA_HAS_DELAY_SLOT
- // This value will be inst->PC + 4 (nextPC)
- // Delay Slot archs need this to be inst->PC + 8 (nextNPC)
- // so we increment one more time here.
- pred_PC = pred_PC + instSize;
-#endif
+ predPC = target;
}
predHist[tid].push_front(predict_record);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
- BPUpdate(predHist[tid].back().PC,
+ BPUpdate(predHist[tid].back().pc.instAddr(),
predHist[tid].back().predTaken,
predHist[tid].back().bpHistory);
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().usedRAS) {
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Restoring top of RAS "
- "to: %i, target: %#x.\n",
+ "to: %i, target: %s.\n",
tid,
pred_hist.front().RASIndex,
- pred_hist.front().RASTarget);
+ pred_hist.front().rasTarget);
RAS[tid].restore(pred_hist.front().RASIndex,
- pred_hist.front().RASTarget);
+ pred_hist.front().rasTarget);
} else if (pred_hist.front().wasCall) {
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Removing speculative "
void
BPredUnit::squash(const InstSeqNum &squashed_sn,
- const Addr &corr_target,
+ const TheISA::PCState &corrTarget,
bool actually_taken,
ThreadID tid,
ThreadID asid)
++condIncorrect;
DPRINTF(InOrderBPred, "[tid:%i]: Squashing from sequence number %i, "
- "setting target to %#x.\n",
- tid, squashed_sn, corr_target);
+ "setting target to %s.\n",
+ tid, squashed_sn, corrTarget);
squash(squashed_sn, tid);
++RASIncorrect;
}
- BPUpdate((*hist_it).PC, actually_taken,
+ BPUpdate((*hist_it).pc.instAddr(), actually_taken,
pred_hist.front().bpHistory);
- BTB.update((*hist_it).PC, corr_target, asid);
+ BTB.update((*hist_it).pc.instAddr(), corrTarget, asid);
DPRINTF(InOrderBPred, "[tid:%i]: Removing history for [sn:%i] "
- "PC %#x.\n", tid, (*hist_it).seqNum, (*hist_it).PC);
+ "PC %s.\n", tid, (*hist_it).seqNum, (*hist_it).pc);
pred_hist.erase(hist_it);
bool
-BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history)
+BPredUnit::BPLookup(Addr inst_PC, void * &bp_history)
{
if (predictor == Local) {
return localBP->lookup(inst_PC, bp_history);
void
-BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+BPredUnit::BPUpdate(Addr inst_PC, bool taken, void *bp_history)
{
if (predictor == Local) {
localBP->update(inst_PC, taken, bp_history);
* Predicts whether or not the instruction is a taken branch, and the
* target of the branch if it is taken.
* @param inst The branch instruction.
- * @param pred_PC The predicted PC is passed back through this parameter.
+ * @param predPC The predicted PC is passed back through this parameter.
* @param tid The thread id.
* @return Returns if the branch is taken or not.
*/
- bool predict(ThePipeline::DynInstPtr &inst, Addr &pred_PC, ThreadID tid);
+ bool predict(ThePipeline::DynInstPtr &inst,
+ TheISA::PCState &predPC, ThreadID tid);
// @todo: Rename this function.
void BPUncond(void * &bp_history);
* corrects that sn's update with the proper address and taken/not taken.
* @param squashed_sn The sequence number to squash any younger updates up
* until.
- * @param corr_target The correct branch target.
+ * @param corrTarget The correct branch target.
* @param actually_taken The correct branch direction.
* @param tid The thread id.
*/
- void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
- bool actually_taken, ThreadID tid, ThreadID asid = 0);
+ void squash(const InstSeqNum &squashed_sn,
+ const TheISA::PCState &corrTarget, bool actually_taken,
+ ThreadID tid, ThreadID asid = 0);
/**
* @param bp_history Pointer to the history object. The predictor
* has the branch predictor state associated with the lookup.
* @return Whether the branch is taken or not taken.
*/
- bool BPLookup(Addr &inst_PC, void * &bp_history);
+ bool BPLookup(Addr instPC, void * &bp_history);
/**
* Looks up a given PC in the BTB to see if a matching entry exists.
* @param inst_PC The PC to look up.
* @return The address of the target of the branch.
*/
- Addr BTBLookup(Addr &inst_PC)
- { return BTB.lookup(inst_PC, 0); }
+ TheISA::PCState BTBLookup(Addr instPC)
+ { return BTB.lookup(instPC, 0); }
/**
* Updates the BP with taken/not taken information.
- * @param inst_PC The branch's PC that will be updated.
+ * @param instPC The branch's PC that will be updated.
* @param taken Whether the branch was taken or not taken.
* @param bp_history Pointer to the branch predictor state that is
* associated with the branch lookup that is being updated.
* @todo Make this update flexible enough to handle a global predictor.
*/
- void BPUpdate(Addr &inst_PC, bool taken, void *bp_history);
+ void BPUpdate(Addr instPC, bool taken, void *bp_history);
/**
* Updates the BTB with the target of a branch.
* @param inst_PC The branch's PC that will be updated.
* @param target_PC The branch's target that will be added to the BTB.
*/
- void BTBUpdate(Addr &inst_PC, Addr &target_PC)
- { BTB.update(inst_PC, target_PC,0); }
+ void BTBUpdate(Addr instPC, const TheISA::PCState &targetPC)
+ { BTB.update(instPC, targetPC, 0); }
void dump();
* Makes a predictor history struct that contains any
* information needed to update the predictor, BTB, and RAS.
*/
- PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
- bool pred_taken, void *bp_history,
- ThreadID _tid)
- : seqNum(seq_num), PC(inst_PC), RASTarget(0),
- RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0),
- wasCall(0), bpHistory(bp_history)
- { }
+ PredictorHistory(const InstSeqNum &seq_num,
+ const TheISA::PCState &instPC, bool pred_taken,
+ void *bp_history, ThreadID _tid)
+ : seqNum(seq_num), pc(instPC), rasTarget(0), RASIndex(0),
+ tid(_tid), predTaken(pred_taken), usedRAS(0), wasCall(0),
+ bpHistory(bp_history)
+ {}
/** The sequence number for the predictor history entry. */
InstSeqNum seqNum;
/** The PC associated with the sequence number. */
- Addr PC;
+ TheISA::PCState pc;
/** The RAS target (only valid if a return). */
- Addr RASTarget;
+ TheISA::PCState rasTarget;
/** The RAS index of the instruction (only valid if a call). */
unsigned RASIndex;
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, "
"skipping prediction \n", tid, inst->seqNum);
} else {
- Addr pred_PC = inst->readNextPC();
+ TheISA::PCState predPC = inst->pcState();
+ TheISA::advancePC(predPC, inst->staticInst);
if (inst->isControl()) {
// If not, the pred_PC be updated to pc+8
// If predicted, the pred_PC will be updated to new target
// value
- bool predict_taken = branchPred.predict(inst, pred_PC, tid);
+ bool predict_taken = branchPred.predict(inst, predPC, tid);
if (predict_taken) {
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch "
"predicted true.\n", tid, seq_num);
-
- inst->setPredTarg(pred_PC);
-
predictedTaken++;
} else {
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch "
"predicted false.\n", tid, seq_num);
-
- if (inst->isCondDelaySlot())
- {
- inst->setPredTarg(inst->readPC() + (2 * instSize));
- } else {
- inst->setPredTarg(pred_PC);
- }
-
predictedNotTaken++;
}
+ inst->setPredTarg(predPC);
+
inst->setBranchPred(predict_taken);
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is "
- "%08p.\n", tid, seq_num, pred_PC);
+ "%s.\n", tid, seq_num, predPC);
} else {
+ inst->setPredTarg(predPC);
//DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] "
// "because this isn't "
// "a control instruction.\n", tid, seq_num);
squash_seq_num = squash_seq_num - 1;
#endif
- if(squash_stage>=ThePipeline::BackEndStartStage) {
- Addr corr_targ=inst->readPredPC();
- bool taken=inst->predTaken();
- branchPred.squash(squash_seq_num,corr_targ,taken,tid);
+ if (squash_stage >= ThePipeline::BackEndStartStage) {
+ bool taken = inst->predTaken();
+ branchPred.squash(squash_seq_num, inst->readPredTarg(), taken, tid);
} else {
branchPred.squash(squash_seq_num, tid);
}
unsigned slot_idx = cache_req->getSlot();
if (tlb_mode == TheISA::TLB::Execute) {
- inst->fetchMemReq = new Request(inst->readTid(), aligned_addr,
- acc_size, flags, inst->readPC(),
- cpu->readCpuId(), inst->readTid());
- cache_req->memReq = inst->fetchMemReq;
+ inst->fetchMemReq =
+ new Request(inst->readTid(), aligned_addr, acc_size, flags,
+ inst->instAddr(), cpu->readCpuId(), inst->readTid());
+ cache_req->memReq = inst->fetchMemReq;
} else {
if (!cache_req->is2ndSplit()) {
- inst->dataMemReq = new Request(cpu->asid[tid], aligned_addr,
- acc_size, flags, inst->readPC(),
- cpu->readCpuId(), inst->readTid());
+ inst->dataMemReq =
+ new Request(cpu->asid[tid], aligned_addr, acc_size, flags,
+ inst->instAddr(), cpu->readCpuId(),
+ inst->readTid());
cache_req->memReq = inst->dataMemReq;
} else {
assert(inst->splitInst);
inst->split2ndAddr,
acc_size,
flags,
- inst->readPC(),
+ inst->instAddr(),
cpu->readCpuId(),
tid);
cache_req->memReq = inst->splitMemReq;
DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n",
- tid, seq_num, inst->staticInst->disassemble(inst->PC));
+ tid, seq_num,
+ inst->staticInst->disassemble(inst->instAddr()));
removeAddrDependency(inst);
tid, inst->seqNum);
DPRINTF(InOrderStall,
"STALL: [tid:%i]: Fetch miss from %08p\n",
- tid, cache_req->inst->readPC());
+ tid, cache_req->inst->instAddr());
cache_req->setCompleted(false);
//cache_req->setMemStall(true);
}
// @todo: update thsi
ExtMachInst ext_inst;
StaticInstPtr staticInst = NULL;
- Addr inst_pc = inst->readPC();
+ TheISA::PCState instPC = inst->pcState();
MachInst mach_inst =
TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
(cache_pkt->getPtr<uint8_t>()));
predecoder.setTC(cpu->thread[tid]->getTC());
- predecoder.moreBytes(inst_pc, inst_pc, mach_inst);
- ext_inst = predecoder.getExtMachInst();
+ predecoder.moreBytes(instPC, inst->instAddr(), mach_inst);
+ ext_inst = predecoder.getExtMachInst(instPC);
+ inst->pcState(instPC);
inst->setMachInst(ext_inst);
// Set Up More TraceData info
if (inst->traceData) {
inst->traceData->setStaticInst(inst->staticInst);
- inst->traceData->setPC(inst->readPC());
+ inst->traceData->setPC(instPC);
}
} else if (inst->staticInst && inst->isMemRef()) {
} else {
DPRINTF(InOrderCachePort,
"[tid:%u] Miss on block @ %08p completed, but squashed\n",
- tid, cache_req->inst->readPC());
+ tid, cache_req->inst->instAddr());
cache_req->setMemAccCompleted();
}
}
exec_req->fault = NoFault;
- DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%#x] %s.\n",
- tid, seq_num, inst->readPC(), inst->instName());
+ DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%s] %s.\n",
+ tid, seq_num, inst->pcState(), inst->instName());
switch (exec_req->cmd)
{
if (inst->isDirectCtrl()) {
assert(!inst->isIndirectCtrl());
+ TheISA::PCState pc = inst->pcState();
+ TheISA::advancePC(pc, inst->staticInst);
+ inst->setPredTarg(pc);
+
if (inst->predTaken() && inst->isCondDelaySlot()) {
inst->bdelaySeqNum = seq_num;
- inst->setPredTarg(inst->nextPC);
DPRINTF(InOrderExecute, "[tid:%i]: Conditional"
- " branch inst [sn:%i] PC %#x mis"
+ " branch inst [sn:%i] PC %s mis"
"predicted as taken.\n", tid,
- seq_num, inst->PC);
+ seq_num, inst->pcState());
} else if (!inst->predTaken() &&
inst->isCondDelaySlot()) {
inst->bdelaySeqNum = seq_num;
- inst->setPredTarg(inst->nextPC);
inst->procDelaySlotOnMispred = true;
DPRINTF(InOrderExecute, "[tid:%i]: Conditional"
- " branch inst [sn:%i] PC %#x mis"
+ " branch inst [sn:%i] PC %s mis"
"predicted as not taken.\n", tid,
- seq_num, inst->PC);
+ seq_num, inst->pcState());
} else {
#if ISA_HAS_DELAY_SLOT
inst->bdelaySeqNum = seq_num + 1;
- inst->setPredTarg(inst->nextNPC);
#else
inst->bdelaySeqNum = seq_num;
- inst->setPredTarg(inst->nextPC);
#endif
DPRINTF(InOrderExecute, "[tid:%i]: "
"Misprediction detected at "
- "[sn:%i] PC %#x,\n\t squashing after "
+ "[sn:%i] PC %s,\n\t squashing after "
"delay slot instruction [sn:%i].\n",
- tid, seq_num, inst->PC,
+ tid, seq_num, inst->pcState(),
inst->bdelaySeqNum);
DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch"
- " misprediction at %#x\n",
- tid, inst->PC);
+ " misprediction at %s\n",
+ tid, inst->pcState());
}
DPRINTF(InOrderExecute, "[tid:%i] Redirecting "
- "fetch to %#x.\n", tid,
+ "fetch to %s.\n", tid,
inst->readPredTarg());
- } else if(inst->isIndirectCtrl()){
+ } else if (inst->isIndirectCtrl()){
+ TheISA::PCState pc = inst->pcState();
+ TheISA::advancePC(pc, inst->staticInst);
+ inst->seqNum = seq_num;
+ inst->setPredTarg(pc);
+
#if ISA_HAS_DELAY_SLOT
- inst->setPredTarg(inst->nextNPC);
inst->bdelaySeqNum = seq_num + 1;
#else
- inst->setPredTarg(inst->nextPC);
inst->bdelaySeqNum = seq_num;
#endif
DPRINTF(InOrderExecute, "[tid:%i] Redirecting"
- " fetch to %#x.\n", tid,
+ " fetch to %s.\n", tid,
inst->readPredTarg());
} else {
panic("Non-control instruction (%s) mispredict"
if (inst->predTaken()) {
predictedTakenIncorrect++;
- DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ... PC%#x ... Mispredicts! (Taken)\n",
- tid, inst->seqNum, inst->staticInst->disassemble(inst->PC),
- inst->readPC());
+ DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
+ "PC %s ... Mispredicts! (Taken)\n",
+ tid, inst->seqNum,
+ inst->staticInst->disassemble(
+ inst->instAddr()),
+ inst->pcState());
} else {
predictedNotTakenIncorrect++;
- DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ... PC%#x ... Mispredicts! (Not Taken)\n",
- tid, inst->seqNum, inst->staticInst->disassemble(inst->PC),
- inst->readPC());
+ DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ..."
+ "PC %s ... Mispredicts! (Not Taken)\n",
+ tid, inst->seqNum,
+ inst->staticInst->disassemble(
+ inst->instAddr()),
+ inst->pcState());
}
predictedIncorrect++;
} else {
instSize(sizeof(MachInst))
{
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
- delaySlotInfo[tid].numInsts = 0;
- delaySlotInfo[tid].targetReady = false;
-
pcValid[tid] = false;
pcBlockStage[tid] = 0;
case AssignNextPC:
{
if (pcValid[tid]) {
+ inst->pcState(pc[tid]);
+ inst->setMemAddr(pc[tid].instAddr());
- if (delaySlotInfo[tid].targetReady &&
- delaySlotInfo[tid].numInsts == 0) {
- // Set PC to target
- PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC
- nextPC[tid] = PC[tid] + instSize; //next_NPC
- nextNPC[tid] = PC[tid] + (2 * instSize);
-
- delaySlotInfo[tid].targetReady = false;
-
- DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to delay "
- "slot target\n",tid);
- }
+ pc[tid].advance(); //XXX HACK!
+ inst->setPredTarg(pc[tid]);
- inst->setPC(PC[tid]);
- inst->setNextPC(PC[tid] + instSize);
- inst->setNextNPC(PC[tid] + (instSize * 2));
-
-#if ISA_HAS_DELAY_SLOT
- inst->setPredTarg(inst->readNextNPC());
-#else
- inst->setPredTarg(inst->readNextPC());
-#endif
- inst->setMemAddr(PC[tid]);
inst->setSeqNum(cpu->getAndIncrementInstSeq(tid));
DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to "
- "PC %08p, NPC %08p, NNPC %08p\n", tid,
- inst->seqNum, inst->readPC(), inst->readNextPC(),
- inst->readNextNPC());
-
- if (delaySlotInfo[tid].numInsts > 0) {
- --delaySlotInfo[tid].numInsts;
-
- // It's OK to set PC to target of branch
- if (delaySlotInfo[tid].numInsts == 0) {
- delaySlotInfo[tid].targetReady = true;
- }
-
- DPRINTF(InOrderFetchSeq, "[tid:%i]: %i delay slot inst(s) "
- "left to process.\n", tid,
- delaySlotInfo[tid].numInsts);
- }
-
- PC[tid] = nextPC[tid];
- nextPC[tid] = nextNPC[tid];
- nextNPC[tid] += instSize;
+ "PC %s\n", tid, inst->seqNum,
+ inst->pcState());
fs_req->done();
} else {
if (inst->isControl()) {
// If it's a return, then we must wait for resolved address.
if (inst->isReturn() && !inst->predTaken()) {
- cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true;
+ cpu->pipelineStage[stage_num]->
+ toPrevStages->stageBlock[stage_num][tid] = true;
pcValid[tid] = false;
pcBlockStage[tid] = stage_num;
} else if (inst->isCondDelaySlot() && !inst->predTaken()) {
// Not-Taken AND Conditional Control
- DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%08p] "
- "Predicted Not-Taken Cond. "
- "Delay inst. Skipping delay slot and Updating PC to %08p\n",
- tid, inst->seqNum, inst->readPC(), inst->readPredTarg());
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%s] "
+ "Predicted Not-Taken Cond. Delay inst. Skipping "
+ "delay slot and Updating PC to %s\n",
+ tid, inst->seqNum, inst->pcState(),
+ inst->readPredTarg());
- DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
- tid, stage_num, seq_num);
+ DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
+ "start from stage %i, after [sn:%i].\n", tid,
+ stage_num, seq_num);
inst->bdelaySeqNum = seq_num;
inst->squashingStage = stage_num;
// Not-Taken Control
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted "
"Not-Taken Control "
- "inst. updating PC to %08p\n", tid, inst->seqNum,
- inst->readNextPC());
+ "inst. updating PC to %s\n", tid, inst->seqNum,
+ inst->readPredTarg());
#if ISA_HAS_DELAY_SLOT
- ++delaySlotInfo[tid].numInsts;
- delaySlotInfo[tid].targetReady = false;
- delaySlotInfo[tid].targetAddr = inst->readNextNPC();
-#else
- assert(delaySlotInfo[tid].numInsts == 0);
+ pc[tid] = inst->pcState();
+ advancePC(pc[tid], inst->staticInst);
#endif
} else if (inst->predTaken()) {
// Taken Control
#if ISA_HAS_DELAY_SLOT
- ++delaySlotInfo[tid].numInsts;
- delaySlotInfo[tid].targetReady = false;
- delaySlotInfo[tid].targetAddr = inst->readPredTarg();
+ pc[tid] = inst->readPredTarg();
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i] Updating delay"
- " slot target to PC %08p\n", tid, inst->seqNum,
+ " slot target to PC %s\n", tid, inst->seqNum,
inst->readPredTarg());
inst->bdelaySeqNum = seq_num + 1;
#else
inst->bdelaySeqNum = seq_num;
- assert(delaySlotInfo[tid].numInsts == 0);
#endif
inst->squashingStage = stage_num;
-
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
"start from stage %i, after [sn:%i].\n",
tid, stage_num, inst->bdelaySeqNum);
// Squash inside current resource, so if there needs to be fetching on
// same cycle the fetch information will be correct.
- // squash(inst, stage_num, inst->bdelaySeqNum, tid);
// Schedule Squash Through-out Resource Pool
- cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
+ cpu->resPool->scheduleEvent(
+ (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
}
+
void
FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
InstSeqNum squash_seq_num, ThreadID tid)
// Handles the case where we are squashing because of something that is
// not a branch...like a memory stall
- Addr new_PC = (inst->isControl()) ?
- inst->readPredTarg() : inst->readPC() + instSize;
+ TheISA::PCState newPC;
+ if (inst->isControl()) {
+ newPC = inst->readPredTarg();
+ } else {
+ TheISA::PCState thisPC = inst->pcState();
+ assert(inst->staticInst);
+ advancePC(thisPC, inst->staticInst);
+ newPC = thisPC;
+ }
if (squashSeqNum[tid] <= done_seq_num &&
lastSquashCycle[tid] == curTick) {
// the last done_seq_num then this is the delay slot inst.
if (cpu->nextInstSeqNum(tid) != done_seq_num &&
!inst->procDelaySlotOnMispred) {
- delaySlotInfo[tid].numInsts = 0;
- delaySlotInfo[tid].targetReady = false;
// Reset PC
- PC[tid] = new_PC;
- nextPC[tid] = new_PC + instSize;
- nextNPC[tid] = new_PC + (2 * instSize);
+ pc[tid] = newPC;
+#if ISA_HAS_DELAY_SLOT
+ TheISA::advancePC(pc[tid], inst->staticInst);
+#endif
- DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %08p.\n",
- tid, PC[tid]);
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
+ tid, newPC);
} else {
-#if !ISA_HAS_DELAY_SLOT
- assert(0);
-#endif
+ assert(ISA_HAS_DELAY_SLOT);
- delaySlotInfo[tid].numInsts = 1;
- delaySlotInfo[tid].targetReady = false;
- delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ?
- inst->branchTarget() : new_PC;
+ pc[tid] = (inst->procDelaySlotOnMispred) ?
+ inst->branchTarget() : newPC;
// Reset PC to Delay Slot Instruction
if (inst->procDelaySlotOnMispred) {
- PC[tid] = new_PC;
- nextPC[tid] = new_PC + instSize;
- nextNPC[tid] = new_PC + (2 * instSize);
+ // Reset PC
+ pc[tid] = newPC;
}
}
FetchSeqUnit* fs_res = dynamic_cast<FetchSeqUnit*>(resource);
assert(fs_res);
- for (int i=0; i < MaxThreads; i++) {
- fs_res->PC[i] = fs_res->cpu->readPC(i);
- fs_res->nextPC[i] = fs_res->cpu->readNextPC(i);
- fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i);
- DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC:%08p NPC:%08p "
- "NNPC:%08p.\n", fs_res->PC[i], fs_res->nextPC[i],
- fs_res->nextNPC[i]);
+ for (int i = 0; i < MaxThreads; i++) {
+ fs_res->pc[i] = fs_res->cpu->pcState(i);
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC: %s.\n",
+ fs_res->pc[i]);
fs_res->pcValid[i] = true;
}
-
- //cpu->fetchPriorityList.push_back(tid);
}
{
pcValid[tid] = true;
- PC[tid] = cpu->readPC(tid);
- nextPC[tid] = cpu->readNextPC(tid);
- nextNPC[tid] = cpu->readNextNPC(tid);
+ pc[tid] = cpu->pcState(tid);
cpu->fetchPriorityList.push_back(tid);
- DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC:%08p NPC:%08p "
- "NNPC:%08p.\n", tid, PC[tid], nextPC[tid], nextNPC[tid]);
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC: %s.\n",
+ tid, pc[tid]);
}
void
FetchSeqUnit::deactivateThread(ThreadID tid)
{
- delaySlotInfo[tid].numInsts = 0;
- delaySlotInfo[tid].targetReady = false;
-
pcValid[tid] = false;
pcBlockStage[tid] = 0;
* switch was right after the branch. Thus, if it's not, then
* we are updating incorrectly here
*/
- assert(cpu->thread[tid]->lastBranchNextPC == inst->readPC());
-
- PC[tid] = cpu->thread[tid]->lastBranchNextNPC;
- nextPC[tid] = PC[tid] + instSize;
- nextNPC[tid] = nextPC[tid] + instSize;
+ assert(cpu->nextInstAddr(tid) == inst->instAddr());
+ pc[tid] = cpu->thread[tid]->lastBranchPC;
} else {
- PC[tid] = inst->readNextPC();
- nextPC[tid] = inst->readNextNPC();
- nextNPC[tid] = inst->readNextNPC() + instSize;
+ pc[tid] = inst->pcState();
}
+ assert(inst->staticInst);
+ advancePC(pc[tid], inst->staticInst);
DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating PCs due to Context Switch."
- "Assigning PC:%08p NPC:%08p NNPC:%08p.\n", tid, PC[tid],
- nextPC[tid], nextNPC[tid]);
+ "Assigning PC: %s.\n", tid, pc[tid]);
}
bool pcValid[ThePipeline::MaxThreads];
int pcBlockStage[ThePipeline::MaxThreads];
- TheISA::IntReg PC[ThePipeline::MaxThreads];
- TheISA::IntReg nextPC[ThePipeline::MaxThreads];
- TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
-
- /** Tracks delay slot information for threads in ISAs which use
- * delay slots;
- */
- struct DelaySlotInfo {
- InstSeqNum delaySlotSeqNum;
- InstSeqNum branchSeqNum;
- int numInsts;
- Addr targetAddr;
- bool targetReady;
- };
-
- DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads];
+ TheISA::PCState pc[ThePipeline::MaxThreads];
/** Squash Seq. Nums*/
InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
aligned_addr = inst->getMemAddr();
req_size = sizeof(TheISA::MachInst);
flags = 0;
- inst->fetchMemReq = new Request(inst->readTid(), aligned_addr, req_size,
- flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid());
+ inst->fetchMemReq = new Request(inst->readTid(), aligned_addr,
+ req_size, flags, inst->instAddr(),
+ res->cpu->readCpuId(),
+ inst->readTid());
memReq = inst->fetchMemReq;
} else {
aligned_addr = inst->getMemAddr();;
req_size = 8;
}
- inst->dataMemReq = new Request(inst->readTid(), aligned_addr, req_size,
- flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid());
+ inst->dataMemReq = new Request(inst->readTid(), aligned_addr,
+ req_size, flags, inst->instAddr(),
+ res->cpu->readCpuId(),
+ inst->readTid());
memReq = inst->dataMemReq;
}
}
cpu->setRegOtherThread(misc_reg, val, tid);
}
-void
-InOrderThreadContext::setPC(uint64_t val)
-{
- DPRINTF(InOrderCPU, "[tid:%i] Setting PC to %08p\n",
- thread->readTid(), val);
- cpu->setPC(val, thread->readTid());
-}
-
-void
-InOrderThreadContext::setNextPC(uint64_t val)
-{
- DPRINTF(InOrderCPU, "[tid:%i] Setting NPC to %08p\n",
- thread->readTid(), val);
- cpu->setNextPC(val, thread->readTid());
-}
-
-void
-InOrderThreadContext::setNextNPC(uint64_t val)
-{
- DPRINTF(InOrderCPU, "[tid:%i] Setting NNPC to %08p\n",
- thread->readTid(), val);
- cpu->setNextNPC(val, thread->readTid());
-}
-
void
InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
ThreadID tid);
/** Reads this thread's PC. */
- uint64_t readPC()
- { return cpu->readPC(thread->readTid()); }
+ TheISA::PCState pcState()
+ { return cpu->pcState(thread->readTid()); }
/** Sets this thread's PC. */
- void setPC(uint64_t val);
+ void pcState(const TheISA::PCState &val)
+ { cpu->pcState(val, thread->readTid()); }
- /** Reads this thread's next PC. */
- uint64_t readNextPC()
- { return cpu->readNextPC(thread->readTid()); }
+ Addr instAddr()
+ { return cpu->instAddr(thread->readTid()); }
- /** Sets this thread's next PC. */
- void setNextPC(uint64_t val);
+ Addr nextInstAddr()
+ { return cpu->nextInstAddr(thread->readTid()); }
- uint64_t readNextNPC()
- { return cpu->readNextNPC(thread->readTid()); }
-
- void setNextNPC(uint64_t val);
+ MicroPC microPC()
+ { return cpu->microPC(thread->readTid()); }
/** Reads a miscellaneous register. */
MiscReg readMiscRegNoEffect(int misc_reg)
/** Is last instruction graduated a branch? */
bool lastGradIsBranch;
- Addr lastBranchPC;
- Addr lastBranchNextPC;
- Addr lastBranchNextNPC;
+ TheISA::PCState lastBranchPC;
};
#endif // __CPU_INORDER_THREAD_STATE_HH__
{
ostream &outs = Trace::output();
ccprintf(outs, "%7d ) ", when);
- outs << "0x" << hex << PC << ":\t";
+ outs << "0x" << hex << pc.instAddr() << ":\t";
if (staticInst->isLoad()) {
ccprintf(outs, "<RD %#x>", addr);
} else if (staticInst->isStore()) {
{
public:
IntelTraceRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr _staticInst, Addr _pc, bool spec,
- const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ const StaticInstPtr _staticInst, TheISA::PCState _pc,
+ bool spec, const StaticInstPtr _macroStaticInst = NULL)
: InstRecord(_when, _thread, _staticInst, _pc, spec,
- _macroStaticInst, _upc)
+ _macroStaticInst)
{
}
IntelTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
+ const StaticInstPtr staticInst, TheISA::PCState pc,
+ const StaticInstPtr macroStaticInst = NULL)
{
if (!IsOn(ExecEnable))
return NULL;
return NULL;
return new IntelTraceRecord(when, tc,
- staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
+ staticInst, pc, tc->misspeculating(), macroStaticInst);
}
};
if(!staticInst->isMicroop() || staticInst->isLastMicroop()) {
while (!compared) {
if (shared_data->flags == OWN_M5) {
- m5Pc = PC & SparcISA::PAddrImplMask;
+ m5Pc = pc.instAddr() & SparcISA::PAddrImplMask;
if (bits(shared_data->pstate,3,3)) {
m5Pc &= mask(32);
}
<< endl;
predecoder.setTC(thread);
- predecoder.moreBytes(m5Pc, m5Pc,
- shared_data->instruction);
+ predecoder.moreBytes(m5Pc, m5Pc, shared_data->instruction);
assert(predecoder.extMachInstReady());
+ PCState tempPC = pc;
StaticInstPtr legionInst =
- StaticInst::decode(predecoder.getExtMachInst(), lgnPc);
+ StaticInst::decode(predecoder.getExtMachInst(tempPC),
+ lgnPc);
outs << setfill(' ') << setw(15)
<< " Legion Inst: "
<< "0x" << setw(8) << setfill('0') << hex
{
public:
LegionTraceRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr _staticInst, Addr _pc, bool spec,
- const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ const StaticInstPtr _staticInst, TheISA::PCState _pc,
+ bool spec, const StaticInstPtr _macroStaticInst = NULL)
: InstRecord(_when, _thread, _staticInst, _pc, spec,
- _macroStaticInst, _upc)
+ _macroStaticInst)
{
}
LegionTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
+ const StaticInstPtr staticInst, TheISA::PCState pc,
+ const StaticInstPtr macroStaticInst = NULL)
{
if (tc->misspeculating())
return NULL;
return new LegionTraceRecord(when, tc,
- staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
+ staticInst, pc, tc->misspeculating(), macroStaticInst);
}
};
public:
NativeTraceRecord(NativeTrace * _parent,
Tick _when, ThreadContext *_thread,
- const StaticInstPtr _staticInst, Addr _pc, bool spec,
- const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ const StaticInstPtr _staticInst, TheISA::PCState _pc,
+ bool spec, const StaticInstPtr _macroStaticInst = NULL)
: ExeTracerRecord(_when, _thread, _staticInst, _pc, spec,
- _macroStaticInst, _upc),
+ _macroStaticInst),
parent(_parent)
{
}
NativeTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
+ const StaticInstPtr staticInst, TheISA::PCState pc,
+ const StaticInstPtr macroStaticInst = NULL)
{
if (tc->misspeculating())
return NULL;
return new NativeTraceRecord(this, when, tc,
- staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
+ staticInst, pc, tc->misspeculating(), macroStaticInst);
}
template<class T>
* @param tid The thread id.
* @return Returns if the branch is taken or not.
*/
- bool predict(DynInstPtr &inst, Addr &PC, ThreadID tid);
+ bool predict(DynInstPtr &inst, TheISA::PCState &pc, ThreadID tid);
// @todo: Rename this function.
void BPUncond(void * &bp_history);
* @param actually_taken The correct branch direction.
* @param tid The thread id.
*/
- void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
+ void squash(const InstSeqNum &squashed_sn,
+ const TheISA::PCState &corr_target,
bool actually_taken, ThreadID tid);
/**
* has the branch predictor state associated with the lookup.
* @return Whether the branch is taken or not taken.
*/
- bool BPLookup(Addr &inst_PC, void * &bp_history);
+ bool BPLookup(Addr instPC, void * &bp_history);
/**
* Looks up a given PC in the BTB to see if a matching entry exists.
* @param inst_PC The PC to look up.
* @return Whether the BTB contains the given PC.
*/
- bool BTBValid(Addr &inst_PC)
- { return BTB.valid(inst_PC, 0); }
+ bool BTBValid(Addr instPC)
+ { return BTB.valid(instPC, 0); }
/**
* Looks up a given PC in the BTB to get the predicted target.
* @param inst_PC The PC to look up.
* @return The address of the target of the branch.
*/
- Addr BTBLookup(Addr &inst_PC)
- { return BTB.lookup(inst_PC, 0); }
+ TheISA::PCState BTBLookup(Addr instPC)
+ { return BTB.lookup(instPC, 0); }
/**
* Updates the BP with taken/not taken information.
* associated with the branch lookup that is being updated.
* @todo Make this update flexible enough to handle a global predictor.
*/
- void BPUpdate(Addr &inst_PC, bool taken, void *bp_history);
+ void BPUpdate(Addr instPC, bool taken, void *bp_history);
/**
* Updates the BTB with the target of a branch.
* @param inst_PC The branch's PC that will be updated.
* @param target_PC The branch's target that will be added to the BTB.
*/
- void BTBUpdate(Addr &inst_PC, Addr &target_PC)
- { BTB.update(inst_PC, target_PC,0); }
+ void BTBUpdate(Addr instPC, const TheISA::PCState &target)
+ { BTB.update(instPC, target, 0); }
void dump();
* Makes a predictor history struct that contains any
* information needed to update the predictor, BTB, and RAS.
*/
- PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
+ PredictorHistory(const InstSeqNum &seq_num, Addr instPC,
bool pred_taken, void *bp_history,
ThreadID _tid)
- : seqNum(seq_num), PC(inst_PC), RASTarget(0),
- RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0),
+ : seqNum(seq_num), pc(instPC), RASTarget(0), RASIndex(0),
+ tid(_tid), predTaken(pred_taken), usedRAS(0),
wasCall(0), bpHistory(bp_history)
- { }
+ {}
bool operator==(const PredictorHistory &entry) const {
return this->seqNum == entry.seqNum;
InstSeqNum seqNum;
/** The PC associated with the sequence number. */
- Addr PC;
+ Addr pc;
/** The RAS target (only valid if a return). */
- Addr RASTarget;
+ TheISA::PCState RASTarget;
/** The RAS index of the instruction (only valid if a call). */
unsigned RASIndex;
#include <algorithm>
#include "arch/types.hh"
+#include "arch/utility.hh"
#include "arch/isa_traits.hh"
#include "base/trace.hh"
#include "base/traceflags.hh"
template <class Impl>
bool
-BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, ThreadID tid)
+BPredUnit<Impl>::predict(DynInstPtr &inst, TheISA::PCState &pc, ThreadID tid)
{
// See if branch predictor predicts taken.
// If so, get its target addr either from the BTB or the RAS.
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
- using TheISA::MachInst;
-
bool pred_taken = false;
- Addr target = PC;
+ TheISA::PCState target = pc;
++lookups;
} else {
++condPredicted;
- pred_taken = BPLookup(PC, bp_history);
+ pred_taken = BPLookup(pc.instAddr(), bp_history);
DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i "
- "for PC %#x\n",
- tid, pred_taken, inst->readPC());
+ "for PC %s\n",
+ tid, pred_taken, inst->pcState());
}
DPRINTF(Fetch, "BranchPred: [tid:%i]: [sn:%i] Creating prediction history "
- "for PC %#x\n",
- tid, inst->seqNum, inst->readPC());
+ "for PC %s\n",
+ tid, inst->seqNum, inst->pcState());
- PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
- bp_history, tid);
+ PredictorHistory predict_record(inst->seqNum, pc.instAddr(),
+ pred_taken, bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
// If it's a function return call, then look up the address
// in the RAS.
- target = RAS[tid].top();
+ TheISA::PCState rasTop = RAS[tid].top();
+ target = TheISA::buildRetPC(pc, rasTop);
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
predict_record.RASIndex = RAS[tid].topIdx();
- predict_record.RASTarget = target;
+ predict_record.RASTarget = rasTop;
assert(predict_record.RASIndex < 16);
RAS[tid].pop();
- DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, "
- "RAS predicted target: %#x, RAS index: %i.\n",
- tid, inst->readPC(), target, predict_record.RASIndex);
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %s is a return, "
+ "RAS predicted target: %s, RAS index: %i.\n",
+ tid, inst->pcState(), target, predict_record.RASIndex);
} else {
++BTBLookups;
if (inst->isCall()) {
-#if ISA_HAS_DELAY_SLOT
- Addr ras_pc = PC + (2 * sizeof(MachInst)); // Next Next PC
-#else
- Addr ras_pc = PC + sizeof(MachInst); // Next PC
-#endif
- RAS[tid].push(ras_pc);
+ RAS[tid].push(pc);
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
predict_record.wasCall = true;
- DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x was a call"
- ", adding %#x to the RAS index: %i.\n",
- tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %s was a "
+ "call, adding %s to the RAS index: %i.\n",
+ tid, inst->pcState(), pc, RAS[tid].topIdx());
}
- if (BTB.valid(PC, tid)) {
+ if (BTB.valid(pc.instAddr(), tid)) {
++BTBHits;
// If it's not a return, use the BTB to get the target addr.
- target = BTB.lookup(PC, tid);
+ target = BTB.lookup(pc.instAddr(), tid);
- DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted"
- " target is %#x.\n",
- tid, inst->readPC(), target);
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %s predicted"
+ " target is %s.\n", tid, inst->pcState(), target);
} else {
DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a "
"valid entry.\n",tid);
pred_taken = false;
+ TheISA::advancePC(target, inst->staticInst);
}
}
+ } else {
+ TheISA::advancePC(target, inst->staticInst);
}
- PC = target;
+ pc = target;
predHist[tid].push_front(predict_record);
while (!predHist[tid].empty() &&
predHist[tid].back().seqNum <= done_sn) {
// Update the branch predictor with the correct results.
- BPUpdate(predHist[tid].back().PC,
+ BPUpdate(predHist[tid].back().pc,
predHist[tid].back().predTaken,
predHist[tid].back().bpHistory);
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().usedRAS) {
DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
- " target: %#x.\n",
- tid,
- pred_hist.front().RASIndex,
- pred_hist.front().RASTarget);
+ " target: %s.\n", tid,
+ pred_hist.front().RASIndex, pred_hist.front().RASTarget);
RAS[tid].restore(pred_hist.front().RASIndex,
pred_hist.front().RASTarget);
BPSquash(pred_hist.front().bpHistory);
DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing history for [sn:%i] "
- "PC %#x.\n", tid, pred_hist.front().seqNum, pred_hist.front().PC);
+ "PC %s.\n", tid, pred_hist.front().seqNum,
+ pred_hist.front().pc);
pred_hist.pop_front();
- DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());
+ DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n",
+ tid, predHist[tid].size());
}
}
template <class Impl>
void
BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
- const Addr &corr_target,
+ const TheISA::PCState &corrTarget,
bool actually_taken,
ThreadID tid)
{
++condIncorrect;
DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
- "setting target to %#x.\n",
- tid, squashed_sn, corr_target);
+ "setting target to %s.\n",
+ tid, squashed_sn, corrTarget);
// Squash All Branches AFTER this mispredicted branch
squash(squashed_sn, tid);
++RASIncorrect;
}
- BPUpdate((*hist_it).PC, actually_taken,
+ BPUpdate((*hist_it).pc, actually_taken,
pred_hist.front().bpHistory);
- BTB.update((*hist_it).PC, corr_target, tid);
+ BTB.update((*hist_it).pc, corrTarget, tid);
DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing history for [sn:%i] "
- "PC %#x.\n", tid, (*hist_it).seqNum, (*hist_it).PC);
+ "PC %s.\n", tid, (*hist_it).seqNum, (*hist_it).pc);
pred_hist.erase(hist_it);
template <class Impl>
bool
-BPredUnit<Impl>::BPLookup(Addr &inst_PC, void * &bp_history)
+BPredUnit<Impl>::BPLookup(Addr instPC, void * &bp_history)
{
if (predictor == Local) {
- return localBP->lookup(inst_PC, bp_history);
+ return localBP->lookup(instPC, bp_history);
} else if (predictor == Tournament) {
- return tournamentBP->lookup(inst_PC, bp_history);
+ return tournamentBP->lookup(instPC, bp_history);
} else {
panic("Predictor type is unexpected value!");
}
template <class Impl>
void
-BPredUnit<Impl>::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+BPredUnit<Impl>::BPUpdate(Addr instPC, bool taken, void *bp_history)
{
if (predictor == Local) {
- localBP->update(inst_PC, taken, bp_history);
+ localBP->update(instPC, taken, bp_history);
} else if (predictor == Tournament) {
- tournamentBP->update(inst_PC, taken, bp_history);
+ tournamentBP->update(instPC, taken, bp_history);
} else {
panic("Predictor type is unexpected value!");
}
while (pred_hist_it != predHist[i].end()) {
cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
"bpHistory:%#x\n",
- (*pred_hist_it).seqNum, (*pred_hist_it).PC,
- (*pred_hist_it).tid, (*pred_hist_it).predTaken,
- (*pred_hist_it).bpHistory);
+ pred_hist_it->seqNum, pred_hist_it->pc,
+ pred_hist_it->tid, pred_hist_it->predTaken,
+ pred_hist_it->bpHistory);
pred_hist_it++;
}
#include <vector>
+#include "arch/types.hh"
#include "base/types.hh"
#include "cpu/inst_seq.hh"
#include "sim/faults.hh"
bool branchMispredict[Impl::MaxThreads];
bool branchTaken[Impl::MaxThreads];
Addr mispredPC[Impl::MaxThreads];
- Addr nextPC[Impl::MaxThreads];
- Addr nextNPC[Impl::MaxThreads];
- Addr nextMicroPC[Impl::MaxThreads];
+ TheISA::PCState pc[Impl::MaxThreads];
InstSeqNum squashedSeqNum[Impl::MaxThreads];
bool includeSquashInst[Impl::MaxThreads];
bool branchMispredict;
bool branchTaken;
Addr mispredPC;
- Addr nextPC;
- Addr nextNPC;
- Addr nextMicroPC;
+ TheISA::PCState nextPC;
unsigned branchCount;
};
bool branchMispredict;
bool branchTaken;
Addr mispredPC;
- Addr nextPC;
- Addr nextNPC;
- Addr nextMicroPC;
+ TheISA::PCState pc;
// Represents the instruction that has either been retired or
// squashed. Similar to having a single bus that broadcasts the
ThreadID oldestReady();
public:
- /** Returns the PC of the head instruction of the ROB.
- * @todo: Probably remove this function as it returns only thread 0.
- */
- Addr readPC() { return PC[0]; }
-
- /** Returns the PC of a specific thread. */
- Addr readPC(ThreadID tid) { return PC[tid]; }
+ /** Reads the PC of a specific thread. */
+ TheISA::PCState pcState(ThreadID tid) { return pc[tid]; }
/** Sets the PC of a specific thread. */
- void setPC(Addr val, ThreadID tid) { PC[tid] = val; }
-
- /** Reads the micro PC of a specific thread. */
- Addr readMicroPC(ThreadID tid) { return microPC[tid]; }
-
- /** Sets the micro PC of a specific thread */
- void setMicroPC(Addr val, ThreadID tid) { microPC[tid] = val; }
-
- /** Reads the next PC of a specific thread. */
- Addr readNextPC(ThreadID tid) { return nextPC[tid]; }
-
- /** Sets the next PC of a specific thread. */
- void setNextPC(Addr val, ThreadID tid) { nextPC[tid] = val; }
+ void pcState(const TheISA::PCState &val, ThreadID tid)
+ { pc[tid] = val; }
- /** Reads the next NPC of a specific thread. */
- Addr readNextNPC(ThreadID tid) { return nextNPC[tid]; }
+ /** Returns the PC of a specific thread. */
+ Addr instAddr(ThreadID tid) { return pc[tid].instAddr(); }
- /** Sets the next NPC of a specific thread. */
- void setNextNPC(Addr val, ThreadID tid) { nextNPC[tid] = val; }
+ /** Returns the next PC of a specific thread. */
+ Addr nextInstAddr(ThreadID tid) { return pc[tid].nextInstAddr(); }
/** Reads the micro PC of a specific thread. */
- Addr readNextMicroPC(ThreadID tid) { return nextMicroPC[tid]; }
-
- /** Sets the micro PC of a specific thread */
- void setNextMicroPC(Addr val, ThreadID tid) { nextMicroPC[tid] = val; }
+ Addr microPC(ThreadID tid) { return pc[tid].microPC(); }
private:
/** Time buffer interface. */
/** The interrupt fault. */
Fault interrupt;
- /** The commit PC of each thread. Refers to the instruction that
- * is currently being processed/committed.
- */
- Addr PC[Impl::MaxThreads];
-
- /** The commit micro PC of each thread. Refers to the instruction that
+ /** The commit PC state of each thread. Refers to the instruction that
* is currently being processed/committed.
*/
- Addr microPC[Impl::MaxThreads];
-
- /** The next PC of each thread. */
- Addr nextPC[Impl::MaxThreads];
-
- /** The next NPC of each thread. */
- Addr nextNPC[Impl::MaxThreads];
-
- /** The next micro PC of each thread. */
- Addr nextMicroPC[Impl::MaxThreads];
+ TheISA::PCState pc[Impl::MaxThreads];
/** The sequence number of the youngest valid instruction in the ROB. */
InstSeqNum youngestSeqNum[Impl::MaxThreads];
committedStores[tid] = false;
trapSquash[tid] = false;
tcSquash[tid] = false;
- microPC[tid] = 0;
- nextMicroPC[tid] = 0;
- PC[tid] = 0;
- nextPC[tid] = 0;
- nextNPC[tid] = 0;
+ pc[tid].set(0);
}
#if FULL_SYSTEM
interrupt = NoFault;
toIEW->commitInfo[tid].branchMispredict = false;
- toIEW->commitInfo[tid].nextPC = PC[tid];
- toIEW->commitInfo[tid].nextNPC = nextPC[tid];
- toIEW->commitInfo[tid].nextMicroPC = nextMicroPC[tid];
+ toIEW->commitInfo[tid].pc = pc[tid];
}
template <class Impl>
{
squashAll(tid);
- DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
+ DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", pc[tid]);
thread[tid]->trapPending = false;
thread[tid]->inSyscall = false;
{
squashAll(tid);
- DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
+ DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", pc[tid]);
thread[tid]->inSyscall = false;
assert(!thread[tid]->trapPending);
DynInstPtr inst = rob->readHeadInst(tid);
- DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
+ DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %s is head of"
" ROB and ready to commit\n",
- tid, inst->seqNum, inst->readPC());
+ tid, inst->seqNum, inst->pcState());
} else if (!rob->isEmpty(tid)) {
DynInstPtr inst = rob->readHeadInst(tid);
DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
- "%#x is head of ROB and not ready\n",
- tid, inst->seqNum, inst->readPC());
+ "%s is head of ROB and not ready\n",
+ tid, inst->seqNum, inst->pcState());
}
DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
tid,
- fromIEW->nextPC[tid]);
+ fromIEW->pc[tid].nextInstAddr());
commitStatus[tid] = ROBSquashing;
toIEW->commitInfo[tid].branchTaken =
fromIEW->branchTaken[tid];
- toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
- toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];
- toIEW->commitInfo[tid].nextMicroPC = fromIEW->nextMicroPC[tid];
+ toIEW->commitInfo[tid].pc = fromIEW->pc[tid];
toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
// Record that the number of ROB entries has changed.
changedROBNumEntries[tid] = true;
} else {
- PC[tid] = head_inst->readPC();
- nextPC[tid] = head_inst->readNextPC();
- nextNPC[tid] = head_inst->readNextNPC();
- nextMicroPC[tid] = head_inst->readNextMicroPC();
+ pc[tid] = head_inst->pcState();
// Increment the total number of non-speculative instructions
// executed.
cpu->instDone(tid);
}
- PC[tid] = nextPC[tid];
- nextPC[tid] = nextNPC[tid];
- nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst);
- microPC[tid] = nextMicroPC[tid];
- nextMicroPC[tid] = microPC[tid] + 1;
+ TheISA::advancePC(pc[tid], head_inst->staticInst);
int count = 0;
Addr oldpc;
// currently updating state while handling PC events.
assert(!thread[tid]->inSyscall && !thread[tid]->trapPending);
do {
- oldpc = PC[tid];
+ oldpc = pc[tid].instAddr();
cpu->system->pcEventQueue.service(thread[tid]->getTC());
count++;
- } while (oldpc != PC[tid]);
+ } while (oldpc != pc[tid].instAddr());
if (count > 1) {
DPRINTF(Commit,
"PC skip function event, stopping commit\n");
break;
}
} else {
- DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
+ DPRINTF(Commit, "Unable to commit head instruction PC:%s "
"[tid:%i] [sn:%i].\n",
- head_inst->readPC(), tid ,head_inst->seqNum);
+ head_inst->pcState(), tid ,head_inst->seqNum);
break;
}
}
head_inst->isWriteBarrier()) {
DPRINTF(Commit, "Encountered a barrier or non-speculative "
- "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
- head_inst->seqNum, head_inst->readPC());
+ "instruction [sn:%lli] at the head of the ROB, PC %s.\n",
+ head_inst->seqNum, head_inst->pcState());
if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
DPRINTF(Commit, "Waiting for all stores to writeback.\n");
}
assert(head_inst->uncacheable());
- DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
- head_inst->seqNum, head_inst->readPC());
+ DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %s.\n",
+ head_inst->seqNum, head_inst->pcState());
// Send back the non-speculative instruction's sequence
// number. Tell the lsq to re-execute the load.
#endif
if (inst_fault != NoFault) {
- DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
- head_inst->seqNum, head_inst->readPC());
+ DPRINTF(Commit, "Inst [sn:%lli] PC %s has a fault\n",
+ head_inst->seqNum, head_inst->pcState());
if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
// Generate trap squash event.
generateTrapEvent(tid);
-// warn("%lli fault (%d) handled @ PC %08p", curTick, inst_fault->name(), head_inst->readPC());
return false;
}
#if FULL_SYSTEM
if (thread[tid]->profile) {
-// bool usermode = TheISA::inUserMode(thread[tid]->getTC());
-// thread[tid]->profilePC = usermode ? 1 : head_inst->readPC();
- thread[tid]->profilePC = head_inst->readPC();
+ thread[tid]->profilePC = head_inst->instAddr();
ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(),
head_inst->staticInst);
if (CPA::available()) {
if (head_inst->isControl()) {
ThreadContext *tc = thread[tid]->getTC();
- CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC());
+ CPA::cpa()->swAutoBegin(tc, head_inst->nextInstAddr());
}
}
#endif
commitStatus[tid] != TrapPending) {
changedROBNumEntries[tid] = true;
- DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
- inst->readPC(), inst->seqNum, tid);
+ DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ROB.\n",
+ inst->pcState(), inst->seqNum, tid);
rob->insertInst(inst);
youngestSeqNum[tid] = inst->seqNum;
} else {
- DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
+ DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
"squashed, skipping.\n",
- inst->readPC(), inst->seqNum, tid);
+ inst->pcState(), inst->seqNum, tid);
}
}
}
DynInstPtr inst = fromRename->insts[inst_num];
if (!inst->isSquashed()) {
- DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
- "skidBuffer.\n", inst->readPC(), inst->seqNum,
+ DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ",
+ "skidBuffer.\n", inst->pcState(), inst->seqNum,
inst->threadNumber);
skidBuffer.push(inst);
} else {
- DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
+ DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
"squashed, skipping.\n",
- inst->readPC(), inst->seqNum, inst->threadNumber);
+ inst->pcState(), inst->seqNum, inst->threadNumber);
}
}
}
++inst_num)
{
if (!fromIEW->insts[inst_num]->isSquashed()) {
- DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
+ DPRINTF(Commit, "[tid:%i]: Marking PC %s, [sn:%lli] ready "
"within ROB.\n",
fromIEW->insts[inst_num]->threadNumber,
- fromIEW->insts[inst_num]->readPC(),
+ fromIEW->insts[inst_num]->pcState(),
fromIEW->insts[inst_num]->seqNum);
// Mark the instruction as ready to commit.
//this->copyFromTC(tid);
//Set PC/NPC/NNPC
- setPC(src_tc->readPC(), tid);
- setNextPC(src_tc->readNextPC(), tid);
- setNextNPC(src_tc->readNextNPC(), tid);
+ pcState(src_tc->pcState(), tid);
src_tc->setStatus(ThreadContext::Active);
// Squash Throughout Pipeline
InstSeqNum squash_seq_num = commit.rob->readHeadInst(tid)->seqNum;
- fetch.squash(0, sizeof(TheISA::MachInst), 0, squash_seq_num, tid);
+ fetch.squash(0, squash_seq_num, tid);
decode.squash(tid);
rename.squash(squash_seq_num, tid);
iew.squash(tid);
}
template <class Impl>
-uint64_t
-FullO3CPU<Impl>::readPC(ThreadID tid)
+TheISA::PCState
+FullO3CPU<Impl>::pcState(ThreadID tid)
{
- return commit.readPC(tid);
+ return commit.pcState(tid);
}
template <class Impl>
void
-FullO3CPU<Impl>::setPC(Addr new_PC, ThreadID tid)
-{
- commit.setPC(new_PC, tid);
-}
-
-template <class Impl>
-uint64_t
-FullO3CPU<Impl>::readMicroPC(ThreadID tid)
+FullO3CPU<Impl>::pcState(const TheISA::PCState &val, ThreadID tid)
{
- return commit.readMicroPC(tid);
+ commit.pcState(val, tid);
}
template <class Impl>
-void
-FullO3CPU<Impl>::setMicroPC(Addr new_PC, ThreadID tid)
+Addr
+FullO3CPU<Impl>::instAddr(ThreadID tid)
{
- commit.setMicroPC(new_PC, tid);
+ return commit.instAddr(tid);
}
template <class Impl>
-uint64_t
-FullO3CPU<Impl>::readNextPC(ThreadID tid)
+Addr
+FullO3CPU<Impl>::nextInstAddr(ThreadID tid)
{
- return commit.readNextPC(tid);
+ return commit.nextInstAddr(tid);
}
template <class Impl>
-void
-FullO3CPU<Impl>::setNextPC(uint64_t val, ThreadID tid)
-{
- commit.setNextPC(val, tid);
-}
-
-template <class Impl>
-uint64_t
-FullO3CPU<Impl>::readNextNPC(ThreadID tid)
-{
- return commit.readNextNPC(tid);
-}
-
-template <class Impl>
-void
-FullO3CPU<Impl>::setNextNPC(uint64_t val, ThreadID tid)
-{
- commit.setNextNPC(val, tid);
-}
-
-template <class Impl>
-uint64_t
-FullO3CPU<Impl>::readNextMicroPC(ThreadID tid)
-{
- return commit.readNextMicroPC(tid);
-}
-
-template <class Impl>
-void
-FullO3CPU<Impl>::setNextMicroPC(Addr new_PC, ThreadID tid)
+MicroPC
+FullO3CPU<Impl>::microPC(ThreadID tid)
{
- commit.setNextMicroPC(new_PC, tid);
+ return commit.microPC(tid);
}
template <class Impl>
void
FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
{
- DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %#x "
+ DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %s "
"[sn:%lli]\n",
- inst->threadNumber, inst->readPC(), inst->seqNum);
+ inst->threadNumber, inst->pcState(), inst->seqNum);
removeInstsThisCycle = true;
{
if ((*instIt)->threadNumber == tid) {
DPRINTF(O3CPU, "Squashing instruction, "
- "[tid:%i] [sn:%lli] PC %#x\n",
+ "[tid:%i] [sn:%lli] PC %s\n",
(*instIt)->threadNumber,
(*instIt)->seqNum,
- (*instIt)->readPC());
+ (*instIt)->pcState());
// Mark it as squashed.
(*instIt)->setSquashed();
{
while (!removeList.empty()) {
DPRINTF(O3CPU, "Removing instruction, "
- "[tid:%i] [sn:%lli] PC %#x\n",
+ "[tid:%i] [sn:%lli] PC %s\n",
(*removeList.front())->threadNumber,
(*removeList.front())->seqNum,
- (*removeList.front())->readPC());
+ (*removeList.front())->pcState());
instList.erase(removeList.front());
while (inst_list_it != instList.end()) {
cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
"Squashed:%i\n\n",
- num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
+ num, (*inst_list_it)->instAddr(), (*inst_list_it)->threadNumber,
(*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
(*inst_list_it)->isSquashed());
inst_list_it++;
void setArchFloatRegInt(int reg_idx, uint64_t val, ThreadID tid);
- /** Reads the commit PC of a specific thread. */
- Addr readPC(ThreadID tid);
+ /** Sets the commit PC state of a specific thread. */
+ void pcState(const TheISA::PCState &newPCState, ThreadID tid);
- /** Sets the commit PC of a specific thread. */
- void setPC(Addr new_PC, ThreadID tid);
+ /** Reads the commit PC state of a specific thread. */
+ TheISA::PCState pcState(ThreadID tid);
- /** Reads the commit micro PC of a specific thread. */
- Addr readMicroPC(ThreadID tid);
+ /** Reads the commit PC of a specific thread. */
+ Addr instAddr(ThreadID tid);
- /** Sets the commmit micro PC of a specific thread. */
- void setMicroPC(Addr new_microPC, ThreadID tid);
+ /** Reads the commit micro PC of a specific thread. */
+ MicroPC microPC(ThreadID tid);
/** Reads the next PC of a specific thread. */
- Addr readNextPC(ThreadID tid);
-
- /** Sets the next PC of a specific thread. */
- void setNextPC(Addr val, ThreadID tid);
-
- /** Reads the next NPC of a specific thread. */
- Addr readNextNPC(ThreadID tid);
-
- /** Sets the next NPC of a specific thread. */
- void setNextNPC(Addr val, ThreadID tid);
-
- /** Reads the commit next micro PC of a specific thread. */
- Addr readNextMicroPC(ThreadID tid);
-
- /** Sets the commit next micro PC of a specific thread. */
- void setNextMicroPC(Addr val, ThreadID tid);
+ Addr nextInstAddr(ThreadID tid);
/** Initiates a squash of all in-flight instructions for a given
* thread. The source of the squash is an external update of
void
DefaultDecode<Impl>::squash(DynInstPtr &inst, ThreadID tid)
{
- DPRINTF(Decode, "[tid:%i]: [sn:%i] Squashing due to incorrect branch prediction "
- "detected at decode.\n", tid, inst->seqNum);
+ DPRINTF(Decode, "[tid:%i]: [sn:%i] Squashing due to incorrect branch "
+ "prediction detected at decode.\n", tid, inst->seqNum);
// Send back mispredict information.
toFetch->decodeInfo[tid].branchMispredict = true;
toFetch->decodeInfo[tid].predIncorrect = true;
toFetch->decodeInfo[tid].squash = true;
toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum;
- toFetch->decodeInfo[tid].nextMicroPC = inst->readMicroPC();
-
-#if ISA_HAS_DELAY_SLOT
- toFetch->decodeInfo[tid].nextPC = inst->readPC() + sizeof(TheISA::MachInst);
- toFetch->decodeInfo[tid].nextNPC = inst->branchTarget();
- toFetch->decodeInfo[tid].branchTaken = inst->readNextNPC() !=
- (inst->readNextPC() + sizeof(TheISA::MachInst));
-#else
toFetch->decodeInfo[tid].nextPC = inst->branchTarget();
- toFetch->decodeInfo[tid].nextNPC =
- inst->branchTarget() + sizeof(TheISA::MachInst);
- toFetch->decodeInfo[tid].branchTaken =
- inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst));
-#endif
-
+ toFetch->decodeInfo[tid].branchTaken = inst->pcState().branching();
InstSeqNum squash_seq_num = inst->seqNum;
assert(tid == inst->threadNumber);
- DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n",
- inst->seqNum, inst->readPC(), inst->threadNumber);
+ DPRINTF(Decode,"Inserting [sn:%lli] PC: %s into decode skidBuffer %i\n",
+ inst->seqNum, inst->pcState(), inst->threadNumber);
skidBuffer[tid].push(inst);
}
insts_to_decode.pop();
DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with "
- "PC %#x\n",
- tid, inst->seqNum, inst->readPC());
+ "PC %s\n", tid, inst->seqNum, inst->pcState());
if (inst->isSquashed()) {
- DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is "
+ DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %s is "
"squashed, skipping.\n",
- tid, inst->seqNum, inst->readPC());
+ tid, inst->seqNum, inst->pcState());
++decodeSquashedInsts;
// Ensure that if it was predicted as a branch, it really is a
// branch.
if (inst->readPredTaken() && !inst->isControl()) {
- DPRINTF(Decode, "PredPC : %#x != NextPC: %#x\n",
- inst->readPredPC(), inst->readNextPC() + 4);
-
panic("Instruction predicted as a branch!");
++decodeControlMispred;
if (inst->isDirectCtrl() && inst->isUncondCtrl()) {
++decodeBranchResolved;
- if (inst->branchTarget() != inst->readPredPC()) {
+ if (!(inst->branchTarget() == inst->readPredTarg())) {
++decodeBranchMispred;
// Might want to set some sort of boolean and just do
// a check at the end
squash(inst, inst->threadNumber);
- Addr target = inst->branchTarget();
+ TheISA::PCState target = inst->branchTarget();
-#if ISA_HAS_DELAY_SLOT
- DPRINTF(Decode, "[sn:%i]: Updating predictions: PredPC: %#x PredNextPC: %#x\n",
- inst->seqNum, inst->readPC() + sizeof(TheISA::MachInst), target);
-
- //The micro pc after an instruction level branch should be 0
- inst->setPredTarg(inst->readPC() + sizeof(TheISA::MachInst), target, 0);
-#else
- DPRINTF(Decode, "[sn:%i]: Updating predictions: PredPC: %#x PredNextPC: %#x\n",
- inst->seqNum, target, target + sizeof(TheISA::MachInst));
+ DPRINTF(Decode, "[sn:%i]: Updating predictions: PredPC: %s\n",
+ inst->seqNum, target);
//The micro pc after an instruction level branch should be 0
- inst->setPredTarg(target, target + sizeof(TheISA::MachInst), 0);
-#endif
+ inst->setPredTarg(target);
break;
}
}
curr = &dependGraph[i];
if (curr->inst) {
- cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ",
- i, curr->inst->readPC(), curr->inst->seqNum);
+ cprintf("dependGraph[%i]: producer: %s [sn:%lli] consumer: ",
+ i, curr->inst->pcState(), curr->inst->seqNum);
} else {
cprintf("dependGraph[%i]: No producer. consumer: ", i);
}
while (curr->next != NULL) {
curr = curr->next;
- cprintf("%#x [sn:%lli] ",
- curr->inst->readPC(), curr->inst->seqNum);
+ cprintf("%s [sn:%lli] ",
+ curr->inst->pcState(), curr->inst->seqNum);
}
cprintf("\n");
public:
/** BaseDynInst constructor given a binary instruction. */
- BaseO3DynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
+ BaseO3DynInst(StaticInstPtr staticInst,
+ TheISA::PCState pc, TheISA::PCState predPC,
+ InstSeqNum seq_num, O3CPU *cpu);
/** BaseDynInst constructor given a binary instruction. */
- BaseO3DynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
+ BaseO3DynInst(ExtMachInst inst,
+ TheISA::PCState pc, TheISA::PCState predPC,
+ InstSeqNum seq_num, O3CPU *cpu);
/** BaseDynInst constructor given a static inst pointer. */
BaseO3DynInst(StaticInstPtr &_staticInst);
template <class Impl>
BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC,
- Addr Pred_MicroPC,
+ TheISA::PCState pc, TheISA::PCState predPC,
InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
+ : BaseDynInst<Impl>(staticInst, pc, predPC, seq_num, cpu)
{
initVars();
}
template <class Impl>
BaseO3DynInst<Impl>::BaseO3DynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC,
- Addr Pred_MicroPC,
+ TheISA::PCState pc, TheISA::PCState predPC,
InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
+ : BaseDynInst<Impl>(inst, pc, predPC, seq_num, cpu)
{
initVars();
}
{
#if THE_ISA == ALPHA_ISA
// Can only do a hwrei when in pal mode.
- if (!(this->readPC() & 0x3))
+ if (!(this->instAddr() & 0x3))
return new AlphaISA::UnimplementedOpcodeFault;
// Set the next PC based on the value of the EXC_ADDR IPR.
- this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
- this->threadNumber));
+ 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->readNextPC());
+ CPA::cpa()->swAutoBegin(tc, this->nextInstAddr());
}
// Tell CPU to clear any state it needs to if a hwrei is taken.
// HACK: check CPU's nextPC before and after syscall. If it
// changes, update this instruction's nextPC because the syscall
// must have changed the nextPC.
- Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber);
+ TheISA::PCState curPC = this->cpu->pcState(this->threadNumber);
this->cpu->syscall(callnum, this->threadNumber);
- Addr new_next_pc = this->cpu->readNextPC(this->threadNumber);
- if (cpu_next_pc != new_next_pc) {
- this->setNextPC(new_next_pc);
+ TheISA::PCState newPC = this->cpu->pcState(this->threadNumber);
+ if (!(curPC == newPC)) {
+ this->pcState(newPC);
}
}
#endif
* @param next_NPC Used for ISAs which use delay slots.
* @return Whether or not a branch was predicted as taken.
*/
- bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC, Addr &next_NPC, Addr &next_MicroPC);
+ bool lookupAndUpdateNextPC(DynInstPtr &inst, TheISA::PCState &pc);
/**
* Fetches the cache line that contains fetch_PC. Returns any
bool fetchCacheLine(Addr fetch_PC, Fault &ret_fault, ThreadID tid);
/** Squashes a specific thread and resets the PC. */
- inline void doSquash(const Addr &new_PC, const Addr &new_NPC,
- const Addr &new_MicroPC, ThreadID tid);
+ inline void doSquash(const TheISA::PCState &newPC, ThreadID tid);
/** Squashes a specific thread and resets the PC. Also tells the CPU to
* remove any instructions between fetch and decode that should be sqaushed.
*/
- void squashFromDecode(const Addr &new_PC, const Addr &new_NPC,
- const Addr &new_MicroPC,
+ void squashFromDecode(const TheISA::PCState &newPC,
const InstSeqNum &seq_num, ThreadID tid);
/** Checks if a thread is stalled. */
* remove any instructions that are not in the ROB. The source of this
* squash should be the commit stage.
*/
- void squash(const Addr &new_PC, const Addr &new_NPC,
- const Addr &new_MicroPC,
+ void squash(const TheISA::PCState &newPC,
const InstSeqNum &seq_num, ThreadID tid);
/** Ticks the fetch stage, processing all inputs signals and fetching
/** Predecoder. */
TheISA::Predecoder predecoder;
- /** Per-thread fetch PC. */
- Addr PC[Impl::MaxThreads];
-
- /** Per-thread fetch micro PC. */
- Addr microPC[Impl::MaxThreads];
-
- /** Per-thread next PC. */
- Addr nextPC[Impl::MaxThreads];
+ TheISA::PCState pc[Impl::MaxThreads];
/** Memory request used to access cache. */
RequestPtr memReq[Impl::MaxThreads];
{
// Setup PC and nextPC with initial state.
for (ThreadID tid = 0; tid < numThreads; tid++) {
- PC[tid] = cpu->readPC(tid);
- nextPC[tid] = cpu->readNextPC(tid);
- microPC[tid] = cpu->readMicroPC(tid);
+ pc[tid] = cpu->pcState(tid);
}
for (ThreadID tid = 0; tid < numThreads; tid++) {
stalls[i].rename = 0;
stalls[i].iew = 0;
stalls[i].commit = 0;
- PC[i] = cpu->readPC(i);
- nextPC[i] = cpu->readNextPC(i);
- microPC[i] = cpu->readMicroPC(i);
+ pc[i] = cpu->pcState(i);
fetchStatus[i] = Running;
}
numInst = 0;
template <class Impl>
bool
-DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
- Addr &next_NPC, Addr &next_MicroPC)
+DefaultFetch<Impl>::lookupAndUpdateNextPC(
+ DynInstPtr &inst, TheISA::PCState &nextPC)
{
// Do branch prediction check here.
// A bit of a misnomer...next_PC is actually the current PC until
bool predict_taken;
if (!inst->isControl()) {
- if (inst->isMicroop() && !inst->isLastMicroop()) {
- next_MicroPC++;
- } else {
- next_PC = next_NPC;
- next_NPC = next_NPC + instSize;
- next_MicroPC = 0;
- }
- inst->setPredTarg(next_PC, next_NPC, next_MicroPC);
+ TheISA::advancePC(nextPC, inst->staticInst);
+ inst->setPredTarg(nextPC);
inst->setPredTaken(false);
return false;
}
- //Assume for now that all control flow is to a different macroop which
- //would reset the micro pc to 0.
- next_MicroPC = 0;
-
ThreadID tid = inst->threadNumber;
- Addr pred_PC = next_PC;
- predict_taken = branchPred.predict(inst, pred_PC, tid);
+ predict_taken = branchPred.predict(inst, nextPC, tid);
if (predict_taken) {
- DPRINTF(Fetch, "[tid:%i]: [sn:%i]: Branch predicted to be taken to %#x.\n",
- tid, inst->seqNum, pred_PC);
+ DPRINTF(Fetch, "[tid:%i]: [sn:%i]: Branch predicted to be taken to %s.\n",
+ tid, inst->seqNum, nextPC);
} else {
DPRINTF(Fetch, "[tid:%i]: [sn:%i]:Branch predicted to be not taken.\n",
tid, inst->seqNum);
}
-#if ISA_HAS_DELAY_SLOT
- next_PC = next_NPC;
- if (predict_taken)
- next_NPC = pred_PC;
- else
- next_NPC += instSize;
-#else
- if (predict_taken)
- next_PC = pred_PC;
- else
- next_PC += instSize;
- next_NPC = next_PC + instSize;
-#endif
-
- DPRINTF(Fetch, "[tid:%i]: [sn:%i] Branch predicted to go to %#x and then %#x.\n",
- tid, inst->seqNum, next_PC, next_NPC);
- inst->setPredTarg(next_PC, next_NPC, next_MicroPC);
+ DPRINTF(Fetch, "[tid:%i]: [sn:%i] Branch predicted to go to %s.\n",
+ tid, inst->seqNum, nextPC);
+ inst->setPredTarg(nextPC);
inst->setPredTaken(predict_taken);
++fetchedBranches;
template <class Impl>
inline void
-DefaultFetch<Impl>::doSquash(const Addr &new_PC,
- const Addr &new_NPC, const Addr &new_microPC, ThreadID tid)
+DefaultFetch<Impl>::doSquash(const TheISA::PCState &newPC, ThreadID tid)
{
- DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x, NPC to: %#x.\n",
- tid, new_PC, new_NPC);
+ DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %s.\n",
+ tid, newPC);
- PC[tid] = new_PC;
- nextPC[tid] = new_NPC;
- microPC[tid] = new_microPC;
+ pc[tid] = newPC;
// Clear the icache miss if it's outstanding.
if (fetchStatus[tid] == IcacheWaitResponse) {
template<class Impl>
void
-DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, const Addr &new_NPC,
- const Addr &new_MicroPC,
+DefaultFetch<Impl>::squashFromDecode(const TheISA::PCState &newPC,
const InstSeqNum &seq_num, ThreadID tid)
{
- DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
+ DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n", tid);
- doSquash(new_PC, new_NPC, new_MicroPC, tid);
+ doSquash(newPC, tid);
// Tell the CPU to remove any instructions that are in flight between
// fetch and decode.
template <class Impl>
void
-DefaultFetch<Impl>::squash(const Addr &new_PC, const Addr &new_NPC,
- const Addr &new_MicroPC,
+DefaultFetch<Impl>::squash(const TheISA::PCState &newPC,
const InstSeqNum &seq_num, ThreadID tid)
{
- DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
+ DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n", tid);
- doSquash(new_PC, new_NPC, new_MicroPC, tid);
+ doSquash(newPC, tid);
// Tell the CPU to remove any instructions that are not in the ROB.
cpu->removeInstsNotInROB(tid);
DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
"from commit.\n",tid);
// In any case, squash.
- squash(fromCommit->commitInfo[tid].nextPC,
- fromCommit->commitInfo[tid].nextNPC,
- fromCommit->commitInfo[tid].nextMicroPC,
+ squash(fromCommit->commitInfo[tid].pc,
fromCommit->commitInfo[tid].doneSeqNum,
tid);
// Also check if there's a mispredict that happened.
if (fromCommit->commitInfo[tid].branchMispredict) {
branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
- fromCommit->commitInfo[tid].nextPC,
+ fromCommit->commitInfo[tid].pc,
fromCommit->commitInfo[tid].branchTaken,
tid);
} else {
if (fetchStatus[tid] != Squashing) {
- DPRINTF(Fetch, "Squashing from decode with PC = %#x, NPC = %#x\n",
- fromDecode->decodeInfo[tid].nextPC,
- fromDecode->decodeInfo[tid].nextNPC);
+ TheISA::PCState nextPC = fromDecode->decodeInfo[tid].nextPC;
+ DPRINTF(Fetch, "Squashing from decode with PC = %s\n", nextPC);
// Squash unless we're already squashing
squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
- fromDecode->decodeInfo[tid].nextNPC,
- fromDecode->decodeInfo[tid].nextMicroPC,
fromDecode->decodeInfo[tid].doneSeqNum,
tid);
DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
// The current PC.
- Addr fetch_PC = PC[tid];
- Addr fetch_NPC = nextPC[tid];
- Addr fetch_MicroPC = microPC[tid];
+ TheISA::PCState fetchPC = pc[tid];
// Fault code for memory access.
Fault fault = NoFault;
status_change = true;
} else if (fetchStatus[tid] == Running) {
DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "
- "instruction, starting at PC %08p.\n",
- tid, fetch_PC);
+ "instruction, starting at PC %s.\n", tid, fetchPC);
- bool fetch_success = fetchCacheLine(fetch_PC, fault, tid);
+ bool fetch_success = fetchCacheLine(fetchPC.instAddr(), fault, tid);
if (!fetch_success) {
if (cacheBlocked) {
++icacheStallCycles;
return;
}
- Addr next_PC = fetch_PC;
- Addr next_NPC = fetch_NPC;
- Addr next_MicroPC = fetch_MicroPC;
+ TheISA::PCState nextPC = fetchPC;
InstSeqNum inst_seq;
MachInst inst;
ExtMachInst ext_inst;
- // @todo: Fix this hack.
- unsigned offset = (fetch_PC & cacheBlkMask) & ~3;
StaticInstPtr staticInst = NULL;
StaticInstPtr macroop = NULL;
if (fault == NoFault) {
+ //XXX Masking out pal mode bit. This will break x86. Alpha needs
+ //to pull the pal mode bit ouf ot the instruction address.
+ unsigned offset = (fetchPC.instAddr() & ~1) - cacheDataPC[tid];
+ assert(offset < cacheBlkSize);
+
// If the read of the first instruction was successful, then grab the
// instructions from the rest of the cache line and put them into the
// queue heading to decode.
numInst < fetchWidth &&
!predicted_branch) {
- // If we're branching after this instruction, quite fetching
- // from the same block then.
- predicted_branch =
- (fetch_PC + sizeof(TheISA::MachInst) != fetch_NPC);
- if (predicted_branch) {
- DPRINTF(Fetch, "Branch detected with PC = %#x, NPC = %#x\n",
- fetch_PC, fetch_NPC);
- }
-
// Make sure this is a valid index.
assert(offset <= cacheBlkSize - instSize);
(&cacheData[tid][offset]));
predecoder.setTC(cpu->thread[tid]->getTC());
- predecoder.moreBytes(fetch_PC, fetch_PC, inst);
+ predecoder.moreBytes(fetchPC, fetchPC.instAddr(), inst);
- ext_inst = predecoder.getExtMachInst();
- staticInst = StaticInstPtr(ext_inst, fetch_PC);
+ ext_inst = predecoder.getExtMachInst(fetchPC);
+ staticInst = StaticInstPtr(ext_inst, fetchPC.instAddr());
if (staticInst->isMacroop())
macroop = staticInst;
}
do {
if (macroop) {
- staticInst = macroop->fetchMicroop(fetch_MicroPC);
+ staticInst = macroop->fetchMicroop(fetchPC.microPC());
if (staticInst->isLastMicroop())
macroop = NULL;
}
// Create a new DynInst from the instruction fetched.
DynInstPtr instruction = new DynInst(staticInst,
- fetch_PC, fetch_NPC, fetch_MicroPC,
- next_PC, next_NPC, next_MicroPC,
+ fetchPC, nextPC,
inst_seq, cpu);
instruction->setTid(tid);
instruction->setThreadState(cpu->thread[tid]);
- DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x (%d) created "
- "[sn:%lli]\n", tid, instruction->readPC(),
- instruction->readMicroPC(), inst_seq);
+ DPRINTF(Fetch, "[tid:%i]: Instruction PC %s (%d) created "
+ "[sn:%lli]\n", tid, instruction->pcState(),
+ instruction->microPC(), inst_seq);
//DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);
- DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
- tid, instruction->staticInst->disassemble(fetch_PC));
+ DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid,
+ instruction->staticInst->
+ disassemble(fetchPC.instAddr()));
#if TRACING_ON
instruction->traceData =
cpu->getTracer()->getInstRecord(curTick, cpu->tcBase(tid),
- instruction->staticInst, instruction->readPC(),
- macroop, instruction->readMicroPC());
+ instruction->staticInst, fetchPC, macroop);
#else
instruction->traceData = NULL;
#endif
- ///FIXME This needs to be more robust in dealing with delay slots
+ // If we're branching after this instruction, quite fetching
+ // from the same block then.
+ predicted_branch = fetchPC.branching();
predicted_branch |=
- lookupAndUpdateNextPC(instruction, next_PC, next_NPC, next_MicroPC);
+ lookupAndUpdateNextPC(instruction, nextPC);
+ if (predicted_branch) {
+ DPRINTF(Fetch, "Branch detected with PC = %s\n", fetchPC);
+ }
// Add instruction to the CPU's list of instructions.
instruction->setInstListIt(cpu->addInst(instruction));
++fetchedInsts;
// Move to the next instruction, unless we have a branch.
- fetch_PC = next_PC;
- fetch_NPC = next_NPC;
- fetch_MicroPC = next_MicroPC;
+ fetchPC = nextPC;
if (instruction->isQuiesce()) {
DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",
} while (staticInst->isMicroop() &&
!staticInst->isLastMicroop() &&
numInst < fetchWidth);
- offset += instSize;
+ //XXX Masking out pal mode bit.
+ offset = (fetchPC.instAddr() & ~1) - cacheDataPC[tid];
}
if (predicted_branch) {
// Now that fetching is completed, update the PC to signify what the next
// cycle will be.
if (fault == NoFault) {
- PC[tid] = next_PC;
- nextPC[tid] = next_NPC;
- microPC[tid] = next_MicroPC;
- DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n", tid, next_PC);
+ pc[tid] = nextPC;
+ DPRINTF(Fetch, "[tid:%i]: Setting PC to %s.\n", tid, nextPC);
} else {
// We shouldn't be in an icache miss and also have a fault (an ITB
// miss)
ext_inst = TheISA::NoopMachInst;
// Create a new DynInst from the dummy nop.
- DynInstPtr instruction = new DynInst(ext_inst,
- fetch_PC, fetch_NPC, fetch_MicroPC,
- next_PC, next_NPC, next_MicroPC,
+ DynInstPtr instruction = new DynInst(ext_inst, fetchPC, nextPC,
inst_seq, cpu);
- instruction->setPredTarg(next_NPC, next_NPC + instSize, 0);
+ TheISA::advancePC(nextPC, instruction->staticInst);
+ instruction->setPredTarg(nextPC);
instruction->setTid(tid);
instruction->setASID(tid);
fetchStatus[tid] = TrapPending;
status_change = true;
- DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %08p",
- tid, fault->name(), PC[tid]);
+ DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s",
+ tid, fault->name(), pc[tid]);
}
}
void
DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, ThreadID tid)
{
- DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, PC: %#x "
- "[sn:%i].\n", tid, inst->readPC(), inst->seqNum);
+ DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, PC: %s "
+ "[sn:%i].\n", tid, inst->pcState(), inst->seqNum);
toCommit->squash[tid] = true;
toCommit->squashedSeqNum[tid] = inst->seqNum;
- toCommit->mispredPC[tid] = inst->readPC();
+ toCommit->mispredPC[tid] = inst->instAddr();
toCommit->branchMispredict[tid] = true;
-#if ISA_HAS_DELAY_SLOT
- int instSize = sizeof(TheISA::MachInst);
- toCommit->branchTaken[tid] =
- !(inst->readNextPC() + instSize == inst->readNextNPC() &&
- (inst->readNextPC() == inst->readPC() + instSize ||
- inst->readNextPC() == inst->readPC() + 2 * instSize));
-#else
- toCommit->branchTaken[tid] = inst->readNextPC() !=
- (inst->readPC() + sizeof(TheISA::MachInst));
-#endif
- toCommit->nextPC[tid] = inst->readNextPC();
- toCommit->nextNPC[tid] = inst->readNextNPC();
- toCommit->nextMicroPC[tid] = inst->readNextMicroPC();
+ toCommit->branchTaken[tid] = inst->pcState().branching();
+ TheISA::PCState pc = inst->pcState();
+ TheISA::advancePC(pc, inst->staticInst);
+ toCommit->pc[tid] = pc;
toCommit->includeSquashInst[tid] = false;
DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, ThreadID tid)
{
DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, "
- "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum);
+ "PC: %s [sn:%i].\n", tid, inst->pcState(), inst->seqNum);
toCommit->squash[tid] = true;
toCommit->squashedSeqNum[tid] = inst->seqNum;
- toCommit->nextPC[tid] = inst->readNextPC();
- toCommit->nextNPC[tid] = inst->readNextNPC();
+ TheISA::PCState pc = inst->pcState();
+ TheISA::advancePC(pc, inst->staticInst);
+ toCommit->pc[tid] = pc;
toCommit->branchMispredict[tid] = false;
toCommit->includeSquashInst[tid] = false;
DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, ThreadID tid)
{
DPRINTF(IEW, "[tid:%i]: Memory blocked, squashing load and younger insts, "
- "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum);
+ "PC: %s [sn:%i].\n", tid, inst->pcState(), inst->seqNum);
toCommit->squash[tid] = true;
toCommit->squashedSeqNum[tid] = inst->seqNum;
- toCommit->nextPC[tid] = inst->readPC();
- toCommit->nextNPC[tid] = inst->readNextPC();
+ toCommit->pc[tid] = inst->pcState();
toCommit->branchMispredict[tid] = false;
// Must include the broadcasted SN in the squash.
insts[tid].pop();
- DPRINTF(Decode,"[tid:%i]: Inserting [sn:%lli] PC:%#x into "
+ DPRINTF(Decode,"[tid:%i]: Inserting [sn:%lli] PC:%s into "
"dispatch skidBuffer %i\n",tid, inst->seqNum,
- inst->readPC(),tid);
+ inst->pcState(),tid);
skidBuffer[tid].push(inst);
}
// Make sure there's a valid instruction there.
assert(inst);
- DPRINTF(IEW, "[tid:%i]: Issue: Adding PC %#x [sn:%lli] [tid:%i] to "
+ DPRINTF(IEW, "[tid:%i]: Issue: Adding PC %s [sn:%lli] [tid:%i] to "
"IQ.\n",
- tid, inst->readPC(), inst->seqNum, inst->threadNumber);
+ tid, inst->pcState(), inst->seqNum, inst->threadNumber);
// Be sure to mark these instructions as ready so that the
// commit stage can go ahead and execute them, and mark
if (inst%3==0) std::cout << "\n\t";
- std::cout << "PC: " << fromIssue->insts[inst]->readPC()
+ std::cout << "PC: " << fromIssue->insts[inst]->pcState()
<< " TN: " << fromIssue->insts[inst]->threadNumber
<< " SN: " << fromIssue->insts[inst]->seqNum << " | ";
DynInstPtr inst = instQueue.getInstToExecute();
- DPRINTF(IEW, "Execute: Processing PC %#x, [tid:%i] [sn:%i].\n",
- inst->readPC(), inst->threadNumber,inst->seqNum);
+ DPRINTF(IEW, "Execute: Processing PC %s, [tid:%i] [sn:%i].\n",
+ inst->pcState(), inst->threadNumber,inst->seqNum);
// Check if the instruction is squashed; if so then skip it
if (inst->isSquashed()) {
DPRINTF(IEW, "Execute: Branch mispredict detected.\n");
DPRINTF(IEW, "Predicted target was PC:%#x, NPC:%#x.\n",
- inst->readPredPC(), inst->readPredNPC());
- DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x,"
- " NPC: %#x.\n", inst->readNextPC(),
- inst->readNextNPC());
+ inst->predInstAddr(), inst->predNextInstAddr());
+ DPRINTF(IEW, "Execute: Redirecting fetch to PC: %s.\n",
+ inst->pcState(), inst->nextInstAddr());
// If incorrect, then signal the ROB that it must be squashed.
squashDueToBranch(inst, tid);
DynInstPtr violator;
violator = ldstQueue.getMemDepViolator(tid);
- DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: %#x "
- "[sn:%lli], inst PC: %#x [sn:%lli]. Addr is: %#x.\n",
- violator->readPC(), violator->seqNum,
- inst->readPC(), inst->seqNum, inst->physEffAddr);
- // Ensure the violating instruction is older than
- // current squash
-/* if (fetchRedirect[tid] &&
- violator->seqNum >= toCommit->squashedSeqNum[tid] + 1)
- continue;
-*/
+ DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: %s "
+ "[sn:%lli], inst PC: %s [sn:%lli]. Addr is: %#x.\n",
+ violator->pcState(), violator->seqNum,
+ inst->pcState(), inst->seqNum, inst->physEffAddr);
+
fetchRedirect[tid] = true;
// Tell the instruction queue that a violation has occured.
fetchRedirect[tid] = true;
DPRINTF(IEW, "Load operation couldn't execute because the "
- "memory system is blocked. PC: %#x [sn:%lli]\n",
- inst->readPC(), inst->seqNum);
+ "memory system is blocked. PC: %s [sn:%lli]\n",
+ inst->pcState(), inst->seqNum);
squashDueToMemBlocked(inst, tid);
}
DynInstPtr violator = ldstQueue.getMemDepViolator(tid);
DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: "
- "%#x, inst PC: %#x. Addr is: %#x.\n",
- violator->readPC(), inst->readPC(), inst->physEffAddr);
+ "%s, inst PC: %s. Addr is: %#x.\n",
+ violator->pcState(), inst->pcState(),
+ inst->physEffAddr);
DPRINTF(IEW, "Violation will not be handled because "
"already squashing\n");
if (ldstQueue.loadBlocked(tid) &&
!ldstQueue.isLoadBlockedHandled(tid)) {
DPRINTF(IEW, "Load operation couldn't execute because the "
- "memory system is blocked. PC: %#x [sn:%lli]\n",
- inst->readPC(), inst->seqNum);
+ "memory system is blocked. PC: %s [sn:%lli]\n",
+ inst->pcState(), inst->seqNum);
DPRINTF(IEW, "Blocked load will not be handled because "
"already squashing\n");
DynInstPtr inst = toCommit->insts[inst_num];
ThreadID tid = inst->threadNumber;
- DPRINTF(IEW, "Sending instructions to commit, [sn:%lli] PC %#x.\n",
- inst->seqNum, inst->readPC());
+ DPRINTF(IEW, "Sending instructions to commit, [sn:%lli] PC %s.\n",
+ inst->seqNum, inst->pcState());
iewInstsToCommit[tid]++;
DPRINTF(IEW, "Execute: Branch mispredict detected.\n");
DPRINTF(IEW, "Predicted target was PC:%#x, NPC:%#x.\n",
- inst->readPredPC(), inst->readPredNPC());
+ inst->predInstAddr(), inst->predNextInstAddr());
DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x,"
- " NPC: %#x.\n", inst->readNextPC(),
- inst->readNextNPC());
+ " NPC: %#x.\n", inst->nextInstAddr(),
+ inst->nextInstAddr());
// If incorrect, then signal the ROB that it must be squashed.
squashDueToBranch(inst, tid);
// Make sure the instruction is valid
assert(new_inst);
- DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n",
- new_inst->seqNum, new_inst->readPC());
+ DPRINTF(IQ, "Adding instruction [sn:%lli] PC %s to the IQ.\n",
+ new_inst->seqNum, new_inst->pcState());
assert(freeEntries != 0);
nonSpecInsts[new_inst->seqNum] = new_inst;
- DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x "
+ DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %s "
"to the IQ.\n",
- new_inst->seqNum, new_inst->readPC());
+ new_inst->seqNum, new_inst->pcState());
assert(freeEntries != 0);
}
}
- DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x "
+ DPRINTF(IQ, "Thread %i: Issuing instruction PC %s "
"[sn:%lli]\n",
- tid, issuing_inst->readPC(),
+ tid, issuing_inst->pcState(),
issuing_inst->seqNum);
readyInsts[op_class].pop();
while (dep_inst) {
DPRINTF(IQ, "Waking up a dependent instruction, [sn:%lli] "
- "PC%#x.\n", dep_inst->seqNum, dep_inst->readPC());
+ "PC %s.\n", dep_inst->seqNum, dep_inst->pcState());
// Might want to give more information to the instruction
// so that it knows which of its source registers is
}
DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
- "the ready list, PC %#x opclass:%i [sn:%lli].\n",
- ready_inst->readPC(), op_class, ready_inst->seqNum);
+ "the ready list, PC %s opclass:%i [sn:%lli].\n",
+ ready_inst->pcState(), op_class, ready_inst->seqNum);
}
template <class Impl>
{
ThreadID tid = completed_inst->threadNumber;
- DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n",
- completed_inst->readPC(), completed_inst->seqNum);
+ DPRINTF(IQ, "Completing mem instruction PC: %s [sn:%lli]\n",
+ completed_inst->pcState(), completed_inst->seqNum);
++freeEntries;
(squashed_inst->isMemRef() &&
!squashed_inst->memOpDone)) {
- DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x "
- "squashed.\n",
- tid, squashed_inst->seqNum, squashed_inst->readPC());
+ DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %s squashed.\n",
+ tid, squashed_inst->seqNum, squashed_inst->pcState());
// Remove the instruction from the dependency list.
if (!squashed_inst->isNonSpeculative() &&
if (src_reg >= numPhysRegs) {
continue;
} else if (regScoreboard[src_reg] == false) {
- DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
+ DPRINTF(IQ, "Instruction PC %s has src reg %i that "
"is being added to the dependency chain.\n",
- new_inst->readPC(), src_reg);
+ new_inst->pcState(), src_reg);
dependGraph.insert(src_reg, new_inst);
// was added to the dependency graph.
return_val = true;
} else {
- DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
+ DPRINTF(IQ, "Instruction PC %s has src reg %i that "
"became ready before it reached the IQ.\n",
- new_inst->readPC(), src_reg);
+ new_inst->pcState(), src_reg);
// Mark a register ready within the instruction.
new_inst->markSrcRegReady(src_reg_idx);
}
OpClass op_class = inst->opClass();
DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
- "the ready list, PC %#x opclass:%i [sn:%lli].\n",
- inst->readPC(), op_class, inst->seqNum);
+ "the ready list, PC %s opclass:%i [sn:%lli].\n",
+ inst->pcState(), op_class, inst->seqNum);
readyInsts[op_class].push(inst);
cprintf("Non speculative list: ");
while (non_spec_it != non_spec_end_it) {
- cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(),
+ cprintf("%s [sn:%lli]", (*non_spec_it).second->pcState(),
(*non_spec_it).second->seqNum);
++non_spec_it;
}
}
}
- cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ cprintf("PC: %s\n[sn:%lli]\n[tid:%i]\n"
"Issued:%i\nSquashed:%i\n",
- (*inst_list_it)->readPC(),
+ (*inst_list_it)->pcState(),
(*inst_list_it)->seqNum,
(*inst_list_it)->threadNumber,
(*inst_list_it)->isIssued(),
}
}
- cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ cprintf("PC: %s\n[sn:%lli]\n[tid:%i]\n"
"Issued:%i\nSquashed:%i\n",
- (*inst_list_it)->readPC(),
+ (*inst_list_it)->pcState(),
(*inst_list_it)->seqNum,
(*inst_list_it)->threadNumber,
(*inst_list_it)->isIssued(),
(load_idx != loadHead || !load_inst->isAtCommit())) {
iewStage->rescheduleMemInst(load_inst);
++lsqRescheduledLoads;
- DPRINTF(LSQUnit, "Uncachable load [sn:%lli] PC %#x\n",
- load_inst->seqNum, load_inst->readPC());
+ DPRINTF(LSQUnit, "Uncachable load [sn:%lli] PC %s\n",
+ load_inst->seqNum, load_inst->pcState());
// Must delete request now that it wasn't handed off to
// memory. This is quite ugly. @todo: Figure out the proper
}
// If there's no forwarding case, then go access memory
- DPRINTF(LSQUnit, "Doing memory access for inst [sn:%lli] PC %#x\n",
- load_inst->seqNum, load_inst->readPC());
+ DPRINTF(LSQUnit, "Doing memory access for inst [sn:%lli] PC %s\n",
+ load_inst->seqNum, load_inst->pcState());
assert(!load_inst->memData);
load_inst->memData = new uint8_t[64];
assert((loadTail + 1) % LQEntries != loadHead);
assert(loads < LQEntries);
- DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
- load_inst->readPC(), loadTail, load_inst->seqNum);
+ DPRINTF(LSQUnit, "Inserting load PC %s, idx:%i [sn:%lli]\n",
+ load_inst->pcState(), loadTail, load_inst->seqNum);
load_inst->lqIdx = loadTail;
assert((storeTail + 1) % SQEntries != storeHead);
assert(stores < SQEntries);
- DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
- store_inst->readPC(), storeTail, store_inst->seqNum);
+ DPRINTF(LSQUnit, "Inserting store PC %s, idx:%i [sn:%lli]\n",
+ store_inst->pcState(), storeTail, store_inst->seqNum);
store_inst->sqIdx = storeTail;
store_inst->lqIdx = loadTail;
// Execute a specific load.
Fault load_fault = NoFault;
- DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
- inst->readPC(),inst->seqNum);
+ DPRINTF(LSQUnit, "Executing load PC %s, [sn:%lli]\n",
+ inst->pcState(),inst->seqNum);
assert(!inst->isSquashed());
int store_idx = store_inst->sqIdx;
- DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
- store_inst->readPC(), store_inst->seqNum);
+ DPRINTF(LSQUnit, "Executing store PC %s [sn:%lli]\n",
+ store_inst->pcState(), store_inst->seqNum);
assert(!store_inst->isSquashed());
Fault store_fault = store_inst->initiateAcc();
if (storeQueue[store_idx].size == 0) {
- DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
- store_inst->readPC(),store_inst->seqNum);
+ DPRINTF(LSQUnit,"Fault on Store PC %s, [sn:%lli],Size = 0\n",
+ store_inst->pcState(), store_inst->seqNum);
return store_fault;
}
{
assert(loadQueue[loadHead]);
- DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
- loadQueue[loadHead]->readPC());
+ DPRINTF(LSQUnit, "Committing head load instruction, PC %s\n",
+ loadQueue[loadHead]->pcState());
loadQueue[loadHead] = NULL;
break;
}
DPRINTF(LSQUnit, "Marking store as able to write back, PC "
- "%#x [sn:%lli]\n",
- storeQueue[store_idx].inst->readPC(),
+ "%s [sn:%lli]\n",
+ storeQueue[store_idx].inst->pcState(),
storeQueue[store_idx].inst->seqNum);
storeQueue[store_idx].canWB = true;
req = sreqLow;
}
- DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
+ DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%s "
"to Addr:%#x, data:%#x [sn:%lli]\n",
- storeWBIdx, inst->readPC(),
+ storeWBIdx, inst->pcState(),
req->getPaddr(), (int)*(inst->memData),
inst->seqNum);
decrLdIdx(load_idx);
while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
- DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
+ DPRINTF(LSQUnit,"Load Instruction PC %s squashed, "
"[sn:%lli]\n",
- loadQueue[load_idx]->readPC(),
+ loadQueue[load_idx]->pcState(),
loadQueue[load_idx]->seqNum);
if (isStalled() && load_idx == stallingLoadIdx) {
break;
}
- DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
+ DPRINTF(LSQUnit,"Store Instruction PC %s squashed, "
"idx:%i [sn:%lli]\n",
- storeQueue[store_idx].inst->readPC(),
+ storeQueue[store_idx].inst->pcState(),
store_idx, storeQueue[store_idx].inst->seqNum);
// I don't think this can happen. It should have been cleared
int load_idx = loadHead;
while (load_idx != loadTail && loadQueue[load_idx]) {
- cprintf("%#x ", loadQueue[load_idx]->readPC());
+ cprintf("%s ", loadQueue[load_idx]->pcState());
incrLdIdx(load_idx);
}
int store_idx = storeHead;
while (store_idx != storeTail && storeQueue[store_idx].inst) {
- cprintf("%#x ", storeQueue[store_idx].inst->readPC());
+ cprintf("%s ", storeQueue[store_idx].inst->pcState());
incrStIdx(store_idx);
}
storeBarrierSN);
producing_store = storeBarrierSN;
} else {
- producing_store = depPred.checkInst(inst->readPC());
+ producing_store = depPred.checkInst(inst->instAddr());
}
MemDepEntryPtr store_entry = NULL;
// are ready.
if (!store_entry) {
DPRINTF(MemDepUnit, "No dependency for inst PC "
- "%#x [sn:%lli].\n", inst->readPC(), inst->seqNum);
+ "%s [sn:%lli].\n", inst->pcState(), inst->seqNum);
inst_entry->memDepReady = true;
} else {
// Otherwise make the instruction dependent on the store/barrier.
DPRINTF(MemDepUnit, "Adding to dependency list; "
- "inst PC %#x is dependent on [sn:%lli].\n",
- inst->readPC(), producing_store);
+ "inst PC %s is dependent on [sn:%lli].\n",
+ inst->pcState(), producing_store);
if (inst->readyToIssue()) {
inst_entry->regsReady = true;
}
if (inst->isStore()) {
- DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n",
- inst->readPC(), inst->seqNum);
+ DPRINTF(MemDepUnit, "Inserting store PC %s [sn:%lli].\n",
+ inst->pcState(), inst->seqNum);
- depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber);
+ depPred.insertStore(inst->instAddr(), inst->seqNum, inst->threadNumber);
++insertedStores;
} else if (inst->isLoad()) {
// Might want to turn this part into an inline function or something.
// It's shared between both insert functions.
if (inst->isStore()) {
- DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n",
- inst->readPC(), inst->seqNum);
+ DPRINTF(MemDepUnit, "Inserting store PC %s [sn:%lli].\n",
+ inst->pcState(), inst->seqNum);
- depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber);
+ depPred.insertStore(inst->instAddr(), inst->seqNum, inst->threadNumber);
++insertedStores;
} else if (inst->isLoad()) {
MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst)
{
DPRINTF(MemDepUnit, "Marking registers as ready for "
- "instruction PC %#x [sn:%lli].\n",
- inst->readPC(), inst->seqNum);
+ "instruction PC %s [sn:%lli].\n",
+ inst->pcState(), inst->seqNum);
MemDepEntryPtr inst_entry = findInHash(inst);
MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst)
{
DPRINTF(MemDepUnit, "Marking non speculative "
- "instruction PC %#x as ready [sn:%lli].\n",
- inst->readPC(), inst->seqNum);
+ "instruction PC %s as ready [sn:%lli].\n",
+ inst->pcState(), inst->seqNum);
MemDepEntryPtr inst_entry = findInHash(inst);
MemDepEntryPtr inst_entry = findInHash(temp_inst);
- DPRINTF(MemDepUnit, "Replaying mem instruction PC %#x "
- "[sn:%lli].\n",
- temp_inst->readPC(), temp_inst->seqNum);
+ DPRINTF(MemDepUnit, "Replaying mem instruction PC %s [sn:%lli].\n",
+ temp_inst->pcState(), temp_inst->seqNum);
moveToReady(inst_entry);
void
MemDepUnit<MemDepPred, Impl>::completed(DynInstPtr &inst)
{
- DPRINTF(MemDepUnit, "Completed mem instruction PC %#x "
- "[sn:%lli].\n",
- inst->readPC(), inst->seqNum);
+ DPRINTF(MemDepUnit, "Completed mem instruction PC %s [sn:%lli].\n",
+ inst->pcState(), inst->seqNum);
ThreadID tid = inst->threadNumber;
DynInstPtr &violating_load)
{
DPRINTF(MemDepUnit, "Passing violating PCs to store sets,"
- " load: %#x, store: %#x\n", violating_load->readPC(),
- store_inst->readPC());
+ " load: %#x, store: %#x\n", violating_load->instAddr(),
+ store_inst->instAddr());
// Tell the memory dependence unit of the violation.
- depPred.violation(violating_load->readPC(), store_inst->readPC());
+ depPred.violation(violating_load->instAddr(), store_inst->instAddr());
}
template <class MemDepPred, class Impl>
MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst)
{
DPRINTF(MemDepUnit, "Issuing instruction PC %#x [sn:%lli].\n",
- inst->readPC(), inst->seqNum);
+ inst->instAddr(), inst->seqNum);
- depPred.issued(inst->readPC(), inst->seqNum, inst->isStore());
+ depPred.issued(inst->instAddr(), inst->seqNum, inst->isStore());
}
template <class MemDepPred, class Impl>
int num = 0;
while (inst_list_it != instList[tid].end()) {
- cprintf("Instruction:%i\nPC:%#x\n[sn:%i]\n[tid:%i]\nIssued:%i\n"
+ cprintf("Instruction:%i\nPC: %s\n[sn:%i]\n[tid:%i]\nIssued:%i\n"
"Squashed:%i\n\n",
- num, (*inst_list_it)->readPC(),
+ num, (*inst_list_it)->pcState(),
(*inst_list_it)->seqNum,
(*inst_list_it)->threadNumber,
(*inst_list_it)->isIssued(),
insts_to_rename.pop_front();
if (renameStatus[tid] == Unblocking) {
- DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%#x from rename "
- "skidBuffer\n",
- tid, inst->seqNum, inst->readPC());
+ DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%s from rename "
+ "skidBuffer\n", tid, inst->seqNum, inst->pcState());
}
if (inst->isSquashed()) {
- DPRINTF(Rename, "[tid:%u]: instruction %i with PC %#x is "
- "squashed, skipping.\n",
- tid, inst->seqNum, inst->readPC());
+ DPRINTF(Rename, "[tid:%u]: instruction %i with PC %s is "
+ "squashed, skipping.\n", tid, inst->seqNum,
+ inst->pcState());
++renameSquashedInsts;
}
DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with "
- "PC %#x.\n",
- tid, inst->seqNum, inst->readPC());
+ "PC %s.\n", tid, inst->seqNum, inst->pcState());
// Handle serializeAfter/serializeBefore instructions.
// serializeAfter marks the next instruction as serializeBefore.
assert(tid == inst->threadNumber);
- DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC:%#x into Rename "
- "skidBuffer\n", tid, inst->seqNum, inst->readPC());
+ DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC: %s into Rename "
+ "skidBuffer\n", tid, inst->seqNum, inst->pcState());
++renameSkidInsts;
for(it = skidBuffer[tid].begin(); it != skidBuffer[tid].end(); it++)
{
warn("[tid:%u]: %s [sn:%i].\n", tid,
- (*it)->staticInst->disassemble(inst->readPC()),
+ (*it)->staticInst->disassemble(inst->instAddr()),
(*it)->seqNum);
}
panic("Skidbuffer Exceeded Max Size");
unblock(tid);
DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with "
- "PC %#x.\n",
- tid, serial_inst->seqNum, serial_inst->readPC());
+ "PC %s.\n", tid, serial_inst->seqNum, serial_inst->pcState());
// Put instruction into queue here.
serial_inst->clearSerializeBefore();
{
assert(inst);
- DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC());
+ DPRINTF(ROB, "Adding inst PC %s to the ROB.\n", inst->pcState());
assert(numInstsInROB != numEntries);
assert(head_inst->readyToCommit());
DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
- "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(),
+ "instruction PC %s, [sn:%lli]\n", tid, head_inst->pcState(),
head_inst->seqNum);
--numInstsInROB;
(*squashIt[tid])->seqNum > squashedSeqNum[tid];
++numSquashed)
{
- DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
+ DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %s, seq num %i.\n",
(*squashIt[tid])->threadNumber,
- (*squashIt[tid])->readPC(),
+ (*squashIt[tid])->pcState(),
(*squashIt[tid])->seqNum);
// Mark the instruction as squashed, and ready to commit so that
virtual void setFloatRegBits(int reg_idx, FloatRegBits val);
- /** Reads this thread's PC. */
- virtual uint64_t readPC()
- { return cpu->readPC(thread->threadId()); }
-
- /** Sets this thread's PC. */
- virtual void setPC(uint64_t val);
-
- /** Reads this thread's next PC. */
- virtual uint64_t readNextPC()
- { return cpu->readNextPC(thread->threadId()); }
+ /** Reads this thread's PC state. */
+ virtual TheISA::PCState pcState()
+ { return cpu->pcState(thread->threadId()); }
- /** Sets this thread's next PC. */
- virtual void setNextPC(uint64_t val);
+ /** Sets this thread's PC state. */
+ virtual void pcState(const TheISA::PCState &val);
- virtual uint64_t readMicroPC()
- { return cpu->readMicroPC(thread->threadId()); }
-
- virtual void setMicroPC(uint64_t val);
+ /** Reads this thread's PC. */
+ virtual Addr instAddr()
+ { return cpu->instAddr(thread->threadId()); }
- virtual uint64_t readNextMicroPC()
- { return cpu->readNextMicroPC(thread->threadId()); }
+ /** Reads this thread's next PC. */
+ virtual Addr nextInstAddr()
+ { return cpu->nextInstAddr(thread->threadId()); }
- virtual void setNextMicroPC(uint64_t val);
+ /** Reads this thread's next PC. */
+ virtual MicroPC microPC()
+ { return cpu->microPC(thread->threadId()); }
/** Reads a miscellaneous register. */
virtual MiscReg readMiscRegNoEffect(int misc_reg)
}
#endif
- virtual uint64_t readNextNPC()
- {
- return this->cpu->readNextNPC(this->thread->threadId());
- }
-
- virtual void setNextNPC(uint64_t val)
- {
- this->cpu->setNextNPC(val, this->thread->threadId());
- }
};
#endif
// Then finally set the PC, the next PC, the nextNPC, the micropc, and the
// next micropc.
- cpu->setPC(tc->readPC(), tid);
- cpu->setNextPC(tc->readNextPC(), tid);
- cpu->setNextNPC(tc->readNextNPC(), tid);
- cpu->setMicroPC(tc->readMicroPC(), tid);
- cpu->setNextMicroPC(tc->readNextMicroPC(), tid);
+ cpu->pcState(tc->pcState(), tid);
#if !FULL_SYSTEM
this->thread->funcExeInst = tc->readFuncExeInst();
#endif
template <class Impl>
void
-O3ThreadContext<Impl>::setPC(uint64_t val)
+O3ThreadContext<Impl>::pcState(const TheISA::PCState &val)
{
- cpu->setPC(val, thread->threadId());
-
- // Squash if we're not already in a state update mode.
- if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->threadId());
- }
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setNextPC(uint64_t val)
-{
- cpu->setNextPC(val, thread->threadId());
-
- // Squash if we're not already in a state update mode.
- if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->threadId());
- }
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setMicroPC(uint64_t val)
-{
- cpu->setMicroPC(val, thread->threadId());
-
- // Squash if we're not already in a state update mode.
- if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->threadId());
- }
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setNextMicroPC(uint64_t val)
-{
- cpu->setNextMicroPC(val, thread->threadId());
+ cpu->pcState(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
bool
PCEventQueue::doService(ThreadContext *tc)
{
- Addr pc = tc->readPC() & ~0x3;
+ Addr pc = tc->instAddr() & ~0x3;
int serviced = 0;
range_t range = equal_range(pc);
for (iterator i = range.first; i != range.second; ++i) {
// another event. This for example, prevents two invocations
// of the SkipFuncEvent. Maybe we should have separate PC
// event queues for each processor?
- if (pc != (tc->readPC() & ~0x3))
+ if (pc != (tc->instAddr() & ~0x3))
continue;
DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n",
inline
unsigned
-DefaultBTB::getIndex(const Addr &inst_PC)
+DefaultBTB::getIndex(Addr instPC)
{
// Need to shift PC over by the word offset.
- return (inst_PC >> instShiftAmt) & idxMask;
+ return (instPC >> instShiftAmt) & idxMask;
}
inline
Addr
-DefaultBTB::getTag(const Addr &inst_PC)
+DefaultBTB::getTag(Addr instPC)
{
- return (inst_PC >> tagShiftAmt) & tagMask;
+ return (instPC >> tagShiftAmt) & tagMask;
}
bool
-DefaultBTB::valid(const Addr &inst_PC, ThreadID tid)
+DefaultBTB::valid(Addr instPC, ThreadID tid)
{
- unsigned btb_idx = getIndex(inst_PC);
+ unsigned btb_idx = getIndex(instPC);
- Addr inst_tag = getTag(inst_PC);
+ Addr inst_tag = getTag(instPC);
assert(btb_idx < numEntries);
// @todo Create some sort of return struct that has both whether or not the
// address is valid, and also the address. For now will just use addr = 0 to
// represent invalid entry.
-Addr
-DefaultBTB::lookup(const Addr &inst_PC, ThreadID tid)
+TheISA::PCState
+DefaultBTB::lookup(Addr instPC, ThreadID tid)
{
- unsigned btb_idx = getIndex(inst_PC);
+ unsigned btb_idx = getIndex(instPC);
- Addr inst_tag = getTag(inst_PC);
+ Addr inst_tag = getTag(instPC);
assert(btb_idx < numEntries);
}
void
-DefaultBTB::update(const Addr &inst_PC, const Addr &target, ThreadID tid)
+DefaultBTB::update(Addr instPC, const TheISA::PCState &target, ThreadID tid)
{
- unsigned btb_idx = getIndex(inst_PC);
+ unsigned btb_idx = getIndex(instPC);
assert(btb_idx < numEntries);
btb[btb_idx].tid = tid;
btb[btb_idx].valid = true;
btb[btb_idx].target = target;
- btb[btb_idx].tag = getTag(inst_PC);
+ btb[btb_idx].tag = getTag(instPC);
}
#ifndef __CPU_O3_BTB_HH__
#define __CPU_O3_BTB_HH__
+#include "arch/types.hh"
#include "base/misc.hh"
#include "base/types.hh"
+#include "config/the_isa.hh"
class DefaultBTB
{
{
BTBEntry()
: tag(0), target(0), valid(false)
- {
- }
+ {}
/** The entry's tag. */
Addr tag;
/** The entry's target. */
- Addr target;
+ TheISA::PCState target;
/** The entry's thread id. */
ThreadID tid;
* @param tid The thread id.
* @return Returns the target of the branch.
*/
- Addr lookup(const Addr &inst_PC, ThreadID tid);
+ TheISA::PCState lookup(Addr instPC, ThreadID tid);
/** Checks if a branch is in the BTB.
* @param inst_PC The address of the branch to look up.
* @param tid The thread id.
* @return Whether or not the branch exists in the BTB.
*/
- bool valid(const Addr &inst_PC, ThreadID tid);
+ bool valid(Addr instPC, ThreadID tid);
/** Updates the BTB with the target of a branch.
* @param inst_PC The address of the branch being updated.
* @param target_PC The target address of the branch.
* @param tid The thread id.
*/
- void update(const Addr &inst_PC, const Addr &target_PC,
+ void update(Addr instPC, const TheISA::PCState &targetPC,
ThreadID tid);
private:
* @param inst_PC The branch to look up.
* @return Returns the index into the BTB.
*/
- inline unsigned getIndex(const Addr &inst_PC);
+ inline unsigned getIndex(Addr instPC);
/** Returns the tag bits of a given address.
* @param inst_PC The branch's address.
* @return Returns the tag bits.
*/
- inline Addr getTag(const Addr &inst_PC);
+ inline Addr getTag(Addr instPC);
/** The actual BTB. */
std::vector<BTBEntry> btb;
ReturnAddrStack::init(unsigned _numEntries)
{
numEntries = _numEntries;
- usedEntries = 0;
- tos = 0;
-
addrStack.resize(numEntries);
-
- for (unsigned i = 0; i < numEntries; ++i)
- addrStack[i] = 0;
+ reset();
}
void
usedEntries = 0;
tos = 0;
for (unsigned i = 0; i < numEntries; ++i)
- addrStack[i] = 0;
+ addrStack[i].set(0);
}
void
-ReturnAddrStack::push(const Addr &return_addr)
+ReturnAddrStack::push(const TheISA::PCState &return_addr)
{
incrTos();
void
ReturnAddrStack::restore(unsigned top_entry_idx,
- const Addr &restored_target)
+ const TheISA::PCState &restored)
{
tos = top_entry_idx;
- addrStack[tos] = restored_target;
+ addrStack[tos] = restored;
}
#include <vector>
+#include "arch/types.hh"
#include "base/types.hh"
+#include "config/the_isa.hh"
/** Return address stack class, implements a simple RAS. */
class ReturnAddrStack
void reset();
/** Returns the top address on the RAS. */
- Addr top()
+ TheISA::PCState top()
{ return addrStack[tos]; }
/** Returns the index of the top of the RAS. */
{ return tos; }
/** Pushes an address onto the RAS. */
- void push(const Addr &return_addr);
+ void push(const TheISA::PCState &return_addr);
/** Pops the top address from the RAS. */
void pop();
/** Changes index to the top of the RAS, and replaces the top address with
* a new target.
* @param top_entry_idx The index of the RAS that will now be the top.
- * @param restored_target The new target address of the new top of the RAS.
+ * @param restored The new target address of the new top of the RAS.
*/
- void restore(unsigned top_entry_idx, const Addr &restored_target);
+ void restore(unsigned top_entry_idx, const TheISA::PCState &restored);
bool empty() { return usedEntries == 0; }
{ tos = (tos == 0 ? numEntries - 1 : tos - 1); }
/** The RAS itself. */
- std::vector<Addr> addrStack;
+ std::vector<TheISA::PCState> addrStack;
/** The number of entries in the RAS. */
unsigned numEntries;
dcache_latency = 0;
while (1) {
- req->setVirt(0, addr, size, flags, thread->readPC());
+ req->setVirt(0, addr, size, flags, thread->pcState().instAddr());
// translate to physical address
Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
dcache_latency = 0;
while(1) {
- req->setVirt(0, addr, size, flags, thread->readPC());
+ req->setVirt(0, addr, size, flags, thread->pcState().instAddr());
// translate to physical address
Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
Fault fault = NoFault;
- bool fromRom = isRomMicroPC(thread->readMicroPC());
- if (!fromRom && !curMacroStaticInst) {
+ TheISA::PCState pcState = thread->pcState();
+
+ bool needToFetch = !isRomMicroPC(pcState.microPC()) &&
+ !curMacroStaticInst;
+ if (needToFetch) {
setupFetchRequest(&ifetch_req);
fault = thread->itb->translateAtomic(&ifetch_req, tc,
BaseTLB::Execute);
bool icache_access = false;
dcache_access = false; // assume no dcache access
- if (!fromRom && !curMacroStaticInst) {
+ if (needToFetch) {
// This is commented out because the predecoder would act like
// a tiny cache otherwise. It wouldn't be flushed when needed
// like the I cache. It should be flushed, and when that works
void
BaseSimpleCPU::setupFetchRequest(Request *req)
{
- Addr threadPC = thread->readPC();
+ Addr instAddr = thread->instAddr();
// set up memory request for instruction fetch
-#if ISA_HAS_DELAY_SLOT
- DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",threadPC,
- thread->readNextPC(),thread->readNextNPC());
-#else
- DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p\n",threadPC,
- thread->readNextPC());
-#endif
+ DPRINTF(Fetch, "Fetch: PC:%08p\n", instAddr);
- Addr fetchPC = (threadPC & PCMask) + fetchOffset;
- req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, threadPC);
+ Addr fetchPC = (instAddr & PCMask) + fetchOffset;
+ req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, instAddr);
}
// decode the instruction
inst = gtoh(inst);
- MicroPC upc = thread->readMicroPC();
+ TheISA::PCState pcState = thread->pcState();
- if (isRomMicroPC(upc)) {
+ if (isRomMicroPC(pcState.microPC())) {
stayAtPC = false;
- curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst);
+ curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(),
+ curMacroStaticInst);
} else if (!curMacroStaticInst) {
//We're not in the middle of a macro instruction
StaticInstPtr instPtr = NULL;
//This should go away once the constructor can be set up properly
predecoder.setTC(thread->getTC());
//If more fetch data is needed, pass it in.
- Addr fetchPC = (thread->readPC() & PCMask) + fetchOffset;
+ Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
//if(predecoder.needMoreBytes())
- predecoder.moreBytes(thread->readPC(), fetchPC, inst);
+ predecoder.moreBytes(pcState, fetchPC, inst);
//else
// predecoder.process();
//If an instruction is ready, decode it. Otherwise, we'll have to
//fetch beyond the MachInst at the current pc.
if (predecoder.extMachInstReady()) {
-#if THE_ISA == X86_ISA || THE_ISA == ARM_ISA
- thread->setNextPC(thread->readPC() + predecoder.getInstSize());
-#endif // X86_ISA
stayAtPC = false;
- instPtr = StaticInst::decode(predecoder.getExtMachInst(),
- thread->readPC());
+ ExtMachInst machInst = predecoder.getExtMachInst(pcState);
+ thread->pcState(pcState);
+ instPtr = StaticInst::decode(machInst, pcState.instAddr());
} else {
stayAtPC = true;
fetchOffset += sizeof(MachInst);
//out micro ops
if (instPtr && instPtr->isMacroop()) {
curMacroStaticInst = instPtr;
- curStaticInst = curMacroStaticInst->fetchMicroop(upc);
+ curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
} else {
curStaticInst = instPtr;
}
} else {
//Read the next micro op from the macro op
- curStaticInst = curMacroStaticInst->fetchMicroop(upc);
+ curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
}
//If we decoded an instruction this "tick", record information about it.
{
#if TRACING_ON
traceData = tracer->getInstRecord(curTick, tc,
- curStaticInst, thread->readPC(),
- curMacroStaticInst, thread->readMicroPC());
+ curStaticInst, thread->pcState(), curMacroStaticInst);
DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
curStaticInst->getName(), curStaticInst->machInst);
void
BaseSimpleCPU::postExecute()
{
+ assert(curStaticInst);
+
+ TheISA::PCState pc = tc->pcState();
+ Addr instAddr = pc.instAddr();
#if FULL_SYSTEM
- if (thread->profile && curStaticInst) {
+ if (thread->profile) {
bool usermode = TheISA::inUserMode(tc);
- thread->profilePC = usermode ? 1 : thread->readPC();
+ thread->profilePC = usermode ? 1 : instAddr;
ProfileNode *node = thread->profile->consume(tc, curStaticInst);
if (node)
thread->profileNode = node;
}
if (CPA::available()) {
- CPA::cpa()->swAutoBegin(tc, thread->readNextPC());
+ CPA::cpa()->swAutoBegin(tc, pc.nextInstAddr());
}
- traceFunctions(thread->readPC());
+ traceFunctions(instAddr);
if (traceData) {
traceData->dump();
fault->invoke(tc, curStaticInst);
predecoder.reset();
} else {
- //If we're at the last micro op for this instruction
- if (curStaticInst && curStaticInst->isLastMicroop()) {
- //We should be working with a macro op or be in the ROM
- assert(curMacroStaticInst ||
- isRomMicroPC(thread->readMicroPC()));
- //Close out this macro op, and clean up the
- //microcode state
- curMacroStaticInst = StaticInst::nullStaticInstPtr;
- thread->setMicroPC(normalMicroPC(0));
- thread->setNextMicroPC(normalMicroPC(1));
- }
- //If we're still in a macro op
- if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) {
- //Advance the micro pc
- thread->setMicroPC(thread->readNextMicroPC());
- //Advance the "next" micro pc. Note that there are no delay
- //slots, and micro ops are "word" addressed.
- thread->setNextMicroPC(thread->readNextMicroPC() + 1);
- } else {
- // go to the next instruction
- thread->setPC(thread->readNextPC());
- thread->setNextPC(thread->readNextNPC());
- thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
- assert(thread->readNextPC() != thread->readNextNPC());
+ if (curStaticInst) {
+ if (curStaticInst->isLastMicroop())
+ curMacroStaticInst = StaticInst::nullStaticInstPtr;
+ TheISA::PCState pcState = thread->pcState();
+ TheISA::advancePC(pcState, curStaticInst);
+ thread->pcState(pcState);
}
}
}
Trace::InstRecord *traceData;
inline void checkPcEventQueue() {
- Addr oldpc;
+ Addr oldpc, pc = thread->instAddr();
do {
- oldpc = thread->readPC();
+ oldpc = pc;
system->pcEventQueue.service(tc);
- } while (oldpc != thread->readPC());
+ pc = thread->instAddr();
+ } while (oldpc != pc);
}
public:
thread->setFloatRegBits(reg_idx, val);
}
- uint64_t readPC() { return thread->readPC(); }
- uint64_t readMicroPC() { return thread->readMicroPC(); }
- uint64_t readNextPC() { return thread->readNextPC(); }
- uint64_t readNextMicroPC() { return thread->readNextMicroPC(); }
- uint64_t readNextNPC() { return thread->readNextNPC(); }
bool readPredicate() { return thread->readPredicate(); }
-
- void setPC(uint64_t val) { thread->setPC(val); }
- void setMicroPC(uint64_t val) { thread->setMicroPC(val); }
- void setNextPC(uint64_t val) { thread->setNextPC(val); }
- void setNextMicroPC(uint64_t val) { thread->setNextMicroPC(val); }
- void setNextNPC(uint64_t val) { thread->setNextNPC(val); }
void setPredicate(bool val)
{
thread->setPredicate(val);
traceData->setPredicate(val);
}
}
+ TheISA::PCState pcState() { return thread->pcState(); }
+ void pcState(const TheISA::PCState &val) { thread->pcState(val); }
+ Addr instAddr() { return thread->instAddr(); }
+ Addr nextInstAddr() { return thread->nextInstAddr(); }
+ MicroPC microPC() { return thread->microPC(); }
MiscReg readMiscRegNoEffect(int misc_reg)
{
Fault fault;
const int asid = 0;
const ThreadID tid = 0;
- const Addr pc = thread->readPC();
+ const Addr pc = thread->instAddr();
unsigned block_size = dcachePort.peerBlockSize();
BaseTLB::Mode mode = BaseTLB::Read;
{
const int asid = 0;
const ThreadID tid = 0;
- const Addr pc = thread->readPC();
+ const Addr pc = thread->instAddr();
unsigned block_size = dcachePort.peerBlockSize();
BaseTLB::Mode mode = BaseTLB::Write;
checkPcEventQueue();
- bool fromRom = isRomMicroPC(thread->readMicroPC());
+ TheISA::PCState pcState = thread->pcState();
+ bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst;
- if (!fromRom && !curMacroStaticInst) {
+ if (needToFetch) {
Request *ifetch_req = new Request();
ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
setupFetchRequest(ifetch_req);
ThreadState::serialize(os);
SERIALIZE_ARRAY(floatRegs.i, TheISA::NumFloatRegs);
SERIALIZE_ARRAY(intRegs, TheISA::NumIntRegs);
- SERIALIZE_SCALAR(microPC);
- SERIALIZE_SCALAR(nextMicroPC);
- SERIALIZE_SCALAR(PC);
- SERIALIZE_SCALAR(nextPC);
- SERIALIZE_SCALAR(nextNPC);
+ _pcState.serialize(os);
// thread_num and cpu_id are deterministic from the config
//
ThreadState::unserialize(cp, section);
UNSERIALIZE_ARRAY(floatRegs.i, TheISA::NumFloatRegs);
UNSERIALIZE_ARRAY(intRegs, TheISA::NumIntRegs);
- UNSERIALIZE_SCALAR(microPC);
- UNSERIALIZE_SCALAR(nextMicroPC);
- UNSERIALIZE_SCALAR(PC);
- UNSERIALIZE_SCALAR(nextPC);
- UNSERIALIZE_SCALAR(nextNPC);
+ _pcState.unserialize(cp, section);
// thread_num and cpu_id are deterministic from the config
//
TheISA::IntReg intRegs[TheISA::NumIntRegs];
TheISA::ISA isa; // one "instance" of the current ISA.
- /** The current microcode pc for the currently executing macro
- * operation.
- */
- MicroPC microPC;
-
- /** The next microcode pc for the currently executing macro
- * operation.
- */
- MicroPC nextMicroPC;
-
- /** The current pc.
- */
- Addr PC;
-
- /** The next pc.
- */
- Addr nextPC;
-
- /** The next next pc.
- */
- Addr nextNPC;
+ TheISA::PCState _pcState;
/** Did this instruction execute or is it predicated false */
bool predicate;
void clearArchRegs()
{
- microPC = 0;
- nextMicroPC = 1;
- PC = nextPC = nextNPC = 0;
+ _pcState = 0;
memset(intRegs, 0, sizeof(intRegs));
memset(floatRegs.i, 0, sizeof(floatRegs.i));
isa.clear();
reg_idx, flatIndex, val, floatRegs.f[flatIndex]);
}
- uint64_t readPC()
- {
- return PC;
- }
-
- void setPC(uint64_t val)
- {
- PC = val;
- }
-
- uint64_t readMicroPC()
- {
- return microPC;
- }
-
- void setMicroPC(uint64_t val)
- {
- microPC = val;
- }
-
- uint64_t readNextPC()
+ TheISA::PCState
+ pcState()
{
- return nextPC;
+ return _pcState;
}
- void setNextPC(uint64_t val)
+ void
+ pcState(const TheISA::PCState &val)
{
- nextPC = val;
+ _pcState = val;
}
- uint64_t readNextMicroPC()
+ Addr
+ instAddr()
{
- return nextMicroPC;
+ return _pcState.instAddr();
}
- void setNextMicroPC(uint64_t val)
+ Addr
+ nextInstAddr()
{
- nextMicroPC = val;
+ return _pcState.nextInstAddr();
}
- uint64_t readNextNPC()
+ MicroPC
+ microPC()
{
-#if ISA_HAS_DELAY_SLOT
- return nextNPC;
-#else
- return nextPC + sizeof(TheISA::MachInst);
-#endif
- }
-
- void setNextNPC(uint64_t val)
- {
-#if ISA_HAS_DELAY_SLOT
- nextNPC = val;
-#endif
+ return _pcState.microPC();
}
bool readPredicate()
}
bool
-StaticInst::hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const
+StaticInst::hasBranchTarget(const TheISA::PCState &pc, ThreadContext *tc,
+ TheISA::PCState &tgt) const
{
if (isDirectCtrl()) {
tgt = branchTarget(pc);
}
StaticInstPtr
-StaticInst::fetchMicroop(MicroPC micropc)
+StaticInst::fetchMicroop(MicroPC upc) const
{
panic("StaticInst::fetchMicroop() called on instruction "
"that is not microcoded.");
}
-Addr
-StaticInst::branchTarget(Addr branchPC) const
+TheISA::PCState
+StaticInst::branchTarget(const TheISA::PCState &pc) const
{
panic("StaticInst::branchTarget() called on instruction "
"that is not a PC-relative branch.");
M5_DUMMY_RETURN;
}
-Addr
+TheISA::PCState
StaticInst::branchTarget(ThreadContext *tc) const
{
panic("StaticInst::branchTarget() called on instruction "
#include <string>
#include "arch/isa_traits.hh"
+#include "arch/types.hh"
#include "arch/registers.hh"
#include "config/the_isa.hh"
#include "base/hashmap.hh"
class InstRecord;
}
-typedef uint16_t MicroPC;
-
-static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1);
-
-static inline MicroPC
-romMicroPC(MicroPC upc)
-{
- return upc | MicroPCRomBit;
-}
-
-static inline MicroPC
-normalMicroPC(MicroPC upc)
-{
- return upc & ~MicroPCRomBit;
-}
-
-static inline bool
-isRomMicroPC(MicroPC upc)
-{
- return MicroPCRomBit & upc;
-}
-
/**
* Base, ISA-independent static instruction class.
*
*/
#include "cpu/static_inst_exec_sigs.hh"
+ virtual void advancePC(TheISA::PCState &pcState) const = 0;
+
/**
* Return the microop that goes with a particular micropc. This should
* only be defined/used in macroops which will contain microops
*/
- virtual StaticInstPtr fetchMicroop(MicroPC micropc);
+ virtual StaticInstPtr fetchMicroop(MicroPC upc) const;
/**
* Return the target address for a PC-relative branch.
* Invalid if not a PC-relative branch (i.e. isDirectCtrl()
* should be true).
*/
- virtual Addr branchTarget(Addr branchPC) const;
+ virtual TheISA::PCState branchTarget(const TheISA::PCState &pc) const;
/**
* Return the target address for an indirect branch (jump). The
* execute the branch in question. Invalid if not an indirect
* branch (i.e. isIndirectCtrl() should be true).
*/
- virtual Addr branchTarget(ThreadContext *tc) const;
+ virtual TheISA::PCState branchTarget(ThreadContext *tc) const;
/**
* Return true if the instruction is a control transfer, and if so,
* return the target address as well.
*/
- bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const;
+ bool hasBranchTarget(const TheISA::PCState &pc, ThreadContext *tc,
+ TheISA::PCState &tgt) const;
/**
* Return string representation of disassembled instruction.
}
#endif
- Addr pc1 = one->readPC();
- Addr pc2 = two->readPC();
- if (pc1 != pc2)
- panic("PCs doesn't match, one: %#x, two: %#x", pc1, pc2);
-
- Addr npc1 = one->readNextPC();
- Addr npc2 = two->readNextPC();
- if (npc1 != npc2)
- panic("NPCs doesn't match, one: %#x, two: %#x", npc1, npc2);
-
+ if (!(one->pcState() == two->pcState()))
+ panic("PC state doesn't match.");
int id1 = one->cpuId();
int id2 = two->cpuId();
if (id1 != id2)
virtual void setFloatRegBits(int reg_idx, FloatRegBits val) = 0;
- virtual uint64_t readPC() = 0;
+ virtual TheISA::PCState pcState() = 0;
- virtual void setPC(uint64_t val) = 0;
+ virtual void pcState(const TheISA::PCState &val) = 0;
- virtual uint64_t readNextPC() = 0;
+ virtual Addr instAddr() = 0;
- virtual void setNextPC(uint64_t val) = 0;
+ virtual Addr nextInstAddr() = 0;
- virtual uint64_t readNextNPC() = 0;
-
- virtual void setNextNPC(uint64_t val) = 0;
-
- virtual uint64_t readMicroPC() = 0;
-
- virtual void setMicroPC(uint64_t val) = 0;
-
- virtual uint64_t readNextMicroPC() = 0;
-
- virtual void setNextMicroPC(uint64_t val) = 0;
+ virtual MicroPC microPC() = 0;
virtual MiscReg readMiscRegNoEffect(int misc_reg) = 0;
void setFloatRegBits(int reg_idx, FloatRegBits val)
{ actualTC->setFloatRegBits(reg_idx, val); }
- uint64_t readPC() { return actualTC->readPC(); }
-
- void setPC(uint64_t val) { actualTC->setPC(val); }
-
- uint64_t readNextPC() { return actualTC->readNextPC(); }
-
- void setNextPC(uint64_t val) { actualTC->setNextPC(val); }
-
- uint64_t readNextNPC() { return actualTC->readNextNPC(); }
-
- void setNextNPC(uint64_t val) { actualTC->setNextNPC(val); }
-
- uint64_t readMicroPC() { return actualTC->readMicroPC(); }
-
- void setMicroPC(uint64_t val) { actualTC->setMicroPC(val); }
+ TheISA::PCState pcState() { return actualTC->pcState(); }
- uint64_t readNextMicroPC() { return actualTC->readMicroPC(); }
+ void pcState(const TheISA::PCState &val) { actualTC->pcState(val); }
- void setNextMicroPC(uint64_t val) { actualTC->setNextMicroPC(val); }
+ Addr instAddr() { return actualTC->instAddr(); }
+ Addr nextInstAddr() { return actualTC->nextInstAddr(); }
+ MicroPC microPC() { return actualTC->microPC(); }
bool readPredicate() { return actualTC->readPredicate(); }
void
SkipFuncEvent::process(ThreadContext *tc)
{
- DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
- tc->readPC(), tc->readIntReg(ReturnAddressReg));
+ TheISA::PCState oldPC M5_VAR_USED = tc->pcState();
// Call ISA specific code to do the skipping
TheISA::skipFunction(tc);
+ DPRINTF(PCEvent, "skipping %s: pc = %s, newpc = %s\n", description,
+ oldPC, tc->pcState());
}
// Note that we'll advance PC <- NPC before the end of the cycle,
// so we need to restore the desired PC into NPC.
// The current regs->pc will get clobbered.
- tc->setNextPC(htog(sc->sc_pc));
+ PCState pc = tc->pcState();
+ pc.npc(htog(sc->sc_pc));
+ tc->pcState(pc);
for (int i = 0; i < 31; ++i) {
tc->setIntReg(i, htog(sc->sc_regs[i]));
tc->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp));
tc->setMiscRegNoEffect(AlphaISA::MISCREG_UNIQ, uniq_val);
- tc->setPC(gtoh(attrp->registers.pc));
- tc->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst));
+ tc->pcState(gtoh(attrp->registers.pc));
tc->activate();
}
#if !FULL_SYSTEM
void FaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
{
- panic("fault (%s) detected @ PC %p", name(), tc->readPC());
+ panic("fault (%s) detected @ PC %s", name(), tc->pcState());
}
#else
void FaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
{
- DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), tc->readPC());
-
+ DPRINTF(Fault, "Fault %s at PC: %s\n", name(), tc->pcState());
assert(!tc->misspeculating());
}
#endif
// need to make this ref-counted so it doesn't go away before we
// dump the record
StaticInstPtr staticInst;
- Addr PC;
+ TheISA::PCState pc;
StaticInstPtr macroStaticInst;
- MicroPC upc;
bool misspeculating;
bool predicate;
public:
InstRecord(Tick _when, ThreadContext *_thread,
const StaticInstPtr _staticInst,
- Addr _pc, bool spec,
- const StaticInstPtr _macroStaticInst = NULL,
- MicroPC _upc = 0)
+ TheISA::PCState _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL)
: when(_when), thread(_thread),
- staticInst(_staticInst), PC(_pc),
- macroStaticInst(_macroStaticInst), upc(_upc),
+ staticInst(_staticInst), pc(_pc),
+ macroStaticInst(_macroStaticInst),
misspeculating(spec), predicate(true)
{
data_status = DataInvalid;
Tick getWhen() { return when; }
ThreadContext *getThread() { return thread; }
StaticInstPtr getStaticInst() { return staticInst; }
- Addr getPC() { return PC; }
+ TheISA::PCState getPCState() { return pc; }
StaticInstPtr getMacroStaticInst() { return macroStaticInst; }
- MicroPC getUPC() { return upc; }
bool getMisspeculating() { return misspeculating; }
Addr getAddr() { return addr; }
virtual InstRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc,
- const StaticInstPtr macroStaticInst = NULL,
- MicroPC _upc = 0) = 0;
+ const StaticInstPtr staticInst, TheISA::PCState pc,
+ const StaticInstPtr macroStaticInst = NULL) = 0;
};
ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
#endif
- ctc->setPC(tc->readNextPC());
- ctc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
- ctc->setNextNPC(tc->readNextNPC() + sizeof(TheISA::MachInst));
+ ctc->pcState(tc->nextInstAddr());
ctc->activate();
return -ENOTTY;
default:
- fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
- fd, req, tc->readPC());
+ fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
+ fd, req, tc->pcState());
}
}