ISA,CPU,etc: Create an ISA defined PC type that abstracts out ISA behaviors.

This change is a low level and pervasive reorganization of how PCs are managed
in M5. Back when Alpha was the only ISA, there were only 2 PCs to worry about,
the PC and the NPC, and the lsb of the PC signaled whether or not you were in
PAL mode. As other ISAs were added, we had to add an NNPC, micro PC and next
micropc, x86 and ARM introduced variable length instruction sets, and ARM
started to keep track of mode bits in the PC. Each CPU model handled PCs in
its own custom way that needed to be updated individually to handle the new
dimensions of variability, or, in the case of ARMs mode-bit-in-the-pc hack,
the complexity could be hidden in the ISA at the ISA implementation's expense.
Areas like the branch predictor hadn't been updated to handle branch delay
slots or micropcs, and it turns out that had introduced a significant (10s of
percent) performance bug in SPARC and to a lesser extend MIPS. Rather than
perpetuate the problem by reworking O3 again to handle the PC features needed
by x86, this change was introduced to rework PC handling in a more modular,
transparent, and hopefully efficient way.


PC type:

Rather than having the superset of all possible elements of PC state declared
in each of the CPU models, each ISA defines its own PCState type which has
exactly the elements it needs. A cross product of canned PCState classes are
defined in the new "generic" ISA directory for ISAs with/without delay slots
and microcode. These are either typedef-ed or subclassed by each ISA. To read
or write this structure through a *Context, you use the new pcState() accessor
which reads or writes depending on whether it has an argument. If you just
want the address of the current or next instruction or the current micro PC,
you can get those through read-only accessors on either the PCState type or
the *Contexts. These are instAddr(), nextInstAddr(), and microPC(). Note the
move away from readPC. That name is ambiguous since it's not clear whether or
not it should be the actual address to fetch from, or if it should have extra
bits in it like the PAL mode bit. Each class is free to define its own
functions to get at whatever values it needs however it needs to to be used in
ISA specific code. Eventually Alpha's PAL mode bit could be moved out of the
PC and into a separate field like ARM.

These types can be reset to a particular pc (where npc = pc +
sizeof(MachInst), nnpc = npc + sizeof(MachInst), upc = 0, nupc = 1 as
appropriate), printed, serialized, and compared. There is a branching()
function which encapsulates code in the CPU models that checked if an
instruction branched or not. Exactly what that means in the context of branch
delay slots which can skip an instruction when not taken is ambiguous, and
ideally this function and its uses can be eliminated. PCStates also generally
know how to advance themselves in various ways depending on if they point at
an instruction, a microop, or the last microop of a macroop. More on that
later.

Ideally, accessing all the PCs at once when setting them will improve
performance of M5 even though more data needs to be moved around. This is
because often all the PCs need to be manipulated together, and by getting them
all at once you avoid multiple function calls. Also, the PCs of a particular
thread will have spatial locality in the cache. Previously they were grouped
by element in arrays which spread out accesses.


Advancing the PC:

The PCs were previously managed entirely by the CPU which had to know about PC
semantics, try to figure out which dimension to increment the PC in, what to
set NPC/NNPC, etc. These decisions are best left to the ISA in conjunction
with the PC type itself. Because most of the information about how to
increment the PC (mainly what type of instruction it refers to) is contained
in the instruction object, a new advancePC virtual function was added to the
StaticInst class. Subclasses provide an implementation that moves around the
right element of the PC with a minimal amount of decision making. In ISAs like
Alpha, the instructions always simply assign NPC to PC without having to worry
about micropcs, nnpcs, etc. The added cost of a virtual function call should
be outweighed by not having to figure out as much about what to do with the
PCs and mucking around with the extra elements.

One drawback of making the StaticInsts advance the PC is that you have to
actually have one to advance the PC. This would, superficially, seem to
require decoding an instruction before fetch could advance. This is, as far as
I can tell, realistic. fetch would advance through memory addresses, not PCs,
perhaps predicting new memory addresses using existing ones. More
sophisticated decisions about control flow would be made later on, after the
instruction was decoded, and handed back to fetch. If branching needs to
happen, some amount of decoding needs to happen to see that it's a branch,
what the target is, etc. This could get a little more complicated if that gets
done by the predecoder, but I'm choosing to ignore that for now.


Variable length instructions:

To handle variable length instructions in x86 and ARM, the predecoder now
takes in the current PC by reference to the getExtMachInst function. It can
modify the PC however it needs to (by setting NPC to be the PC + instruction
length, for instance). This could be improved since the CPU doesn't know if
the PC was modified and always has to write it back.


ISA parser:

To support the new API, all PC related operand types were removed from the
parser and replaced with a PCState type. There are two warts on this
implementation. First, as with all the other operand types, the PCState still
has to have a valid operand type even though it doesn't use it. Second, using
syntax like PCS.npc(target) doesn't work for two reasons, this looks like the
syntax for operand type overriding, and the parser can't figure out if you're
reading or writing. Instructions that use the PCS operand (which I've
consistently called it) need to first read it into a local variable,
manipulate it, and then write it back out.


Return address stack:

The return address stack needed a little extra help because, in the presence
of branch delay slots, it has to merge together elements of the return PC and
the call PC. To handle that, a buildRetPC utility function was added. There
are basically only two versions in all the ISAs, but it didn't seem short
enough to put into the generic ISA directory. Also, the branch predictor code
in O3 and InOrder were adjusted so that they always store the PC of the actual
call instruction in the RAS, not the next PC. If the call instruction is a
microop, the next PC refers to the next microop in the same macroop which is
probably not desirable. The buildRetPC function advances the PC intelligently
to the next macroop (in an ISA specific way) so that that case works.


Change in stats:

There were no change in stats except in MIPS and SPARC in the O3 model. MIPS
runs in about 9% fewer ticks. SPARC runs with 30%-50% fewer ticks, which could
likely be improved further by setting call/return instruction flags and taking
advantage of the RAS.


TODO:

Add != operators to the PCState classes, defined trivially to be !(a==b).
Smooth out places where PCs are split apart, passed around, and put back
together later. I think this might happen in SPARC's fault code. Add ISA
specific constructors that allow setting PC elements without calling a bunch
of accessors. Try to eliminate the need for the branching() function. Factor
out Alpha's PAL mode pc bit into a separate flag field, and eliminate places
where it's blindly masked out or tested in the PC.
This commit is contained in:
Gabe Black 2010-10-31 00:07:20 -07:00
parent 373154a25a
commit 6f4bd2c1da
171 changed files with 2512 additions and 2302 deletions

View file

@ -60,8 +60,7 @@ initCPU(ThreadContext *tc, int cpuId)
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;
}
@ -494,12 +493,14 @@ using namespace AlphaISA;
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)

View file

@ -115,9 +115,11 @@ AlphaFault::invoke(ThreadContext *tc, StaticInstPtr inst)
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.
@ -125,8 +127,8 @@ AlphaFault::invoke(ThreadContext *tc, StaticInstPtr inst)
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

View file

@ -133,7 +133,7 @@ class Interrupts : public SimObject
bool
checkInterrupts(ThreadContext *tc) const
{
return (intstatus != 0) && !(tc->readPC() & 0x3);
return (intstatus != 0) && !(tc->pcState().pc() & 0x3);
}
Fault

View file

@ -81,7 +81,7 @@ output header {{
{
}
Addr branchTarget(Addr branchPC) const;
AlphaISA::PCState branchTarget(const AlphaISA::PCState &branchPC) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
@ -106,7 +106,7 @@ output header {{
{
}
Addr branchTarget(ThreadContext *tc) const;
AlphaISA::PCState branchTarget(ThreadContext *tc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
@ -114,18 +114,19 @@ output header {{
}};
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 &
@ -217,7 +218,14 @@ def template JumpOrBranchDecode {{
}};
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)
@ -229,16 +237,18 @@ def format CondBranch(code) {{
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)
@ -253,13 +263,13 @@ def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
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)
}};

View file

@ -856,15 +856,16 @@ decode OPCODE default Unknown::unknown() {
// 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);
@ -1030,13 +1031,14 @@ decode OPCODE default Unknown::unknown() {
}}, 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);

View file

@ -46,6 +46,7 @@ output header {{
#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
@ -185,7 +186,7 @@ def operands {{
'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),
@ -233,6 +234,12 @@ output header {{
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
void
advancePC(AlphaISA::PCState &pcState) const
{
pcState.advance();
}
};
}};

View file

@ -76,11 +76,11 @@ class Predecoder
// 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
}
@ -98,7 +98,7 @@ class Predecoder
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst()
getExtMachInst(PCState &pc)
{
return ext_inst;
}

View file

@ -162,15 +162,7 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
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

View file

@ -211,7 +211,7 @@ RemoteGDB::getregs()
{
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])) {
@ -254,7 +254,7 @@ RemoteGDB::setregs()
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
@ -273,30 +273,28 @@ RemoteGDB::clearSingleStep()
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.

View file

@ -145,7 +145,7 @@ StackTrace::trace(ThreadContext *_tc, bool is_call)
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) {
@ -168,7 +168,7 @@ StackTrace::trace(ThreadContext *_tc, bool is_call)
panic("could not find address %#x", pc);
stack.push_back(addr);
pc = tc->readPC();
pc = tc->pcState().pc();
}
while (ksp > bottom) {

View file

@ -443,8 +443,6 @@ TLB::translateInst(RequestPtr req, ThreadContext *tc)
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));
@ -458,7 +456,7 @@ TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
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))

View file

@ -33,12 +33,15 @@
#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

View file

@ -77,8 +77,7 @@ copyRegs(ThreadContext *src, ThreadContext *dest)
copyMiscRegs(src, dest);
// Lastly copy PC/NPC
dest->setPC(src->readPC());
dest->setNextPC(src->readNextPC());
dest->pcState(src->pcState());
}
void
@ -99,9 +98,9 @@ copyMiscRegs(ThreadContext *src, ThreadContext *dest)
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);
}

View file

@ -37,10 +37,19 @@
#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
@ -95,6 +104,13 @@ void copyRegs(ThreadContext *src, ThreadContext *dest);
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__

View file

@ -104,6 +104,7 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
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();
@ -116,7 +117,7 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
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()) {
@ -139,14 +140,15 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
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
@ -193,10 +195,10 @@ SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst)
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
@ -223,10 +225,10 @@ FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) {
// 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,

View file

@ -77,6 +77,18 @@ class MicroOp : public PredOp
{
flags[IsDelayedCommit] = true;
}
void
advancePC(PCState &pcState) const
{
if (flags[IsLastMicroop]) {
pcState.uEnd();
} else if (flags[IsMicroop]) {
pcState.uAdvance();
} else {
pcState.advance();
}
}
};
/**

View file

@ -63,8 +63,28 @@ class Swap : public PredOp
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 {
@ -83,7 +103,7 @@ class RfeOp : public PredOp
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)
{}
@ -94,7 +114,7 @@ class RfeOp : public PredOp
}
StaticInstPtr
fetchMicroop(MicroPC microPC)
fetchMicroop(MicroPC microPC) const
{
assert(uops != NULL && microPC < numMicroops);
return uops[microPC];
@ -104,7 +124,7 @@ class RfeOp : public PredOp
};
// The address is a base register plus an immediate.
class SrsOp : public PredOp
class SrsOp : public MightBeMicro
{
public:
enum AddrMode {
@ -123,7 +143,7 @@ class SrsOp : public PredOp
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)
{}
@ -134,7 +154,7 @@ class SrsOp : public PredOp
}
StaticInstPtr
fetchMicroop(MicroPC microPC)
fetchMicroop(MicroPC microPC) const
{
assert(uops != NULL && microPC < numMicroops);
return uops[microPC];
@ -143,7 +163,7 @@ class SrsOp : public PredOp
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
class Memory : public PredOp
class Memory : public MightBeMicro
{
public:
enum AddrMode {
@ -163,7 +183,7 @@ class Memory : public PredOp
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)
{}
@ -174,7 +194,7 @@ class Memory : public PredOp
}
StaticInstPtr
fetchMicroop(MicroPC microPC)
fetchMicroop(MicroPC microPC) const
{
assert(uops != NULL && microPC < numMicroops);
return uops[microPC];

View file

@ -312,7 +312,7 @@ class PredMacroOp : public PredOp
}
StaticInstPtr
fetchMicroop(MicroPC microPC)
fetchMicroop(MicroPC microPC) const
{
assert(microPC < numMicroops);
return microOps[microPC];
@ -332,6 +332,15 @@ class PredMicroop : public PredOp
{
flags[IsMicroop] = true;
}
void
advancePC(PCState &pcState) const
{
if (flags[IsLastMicroop])
pcState.uEnd();
else
pcState.uAdvance();
}
};
}

View file

@ -155,6 +155,12 @@ class ArmStaticInst : public StaticInst
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
@ -219,26 +225,16 @@ class ArmStaticInst : public StaticInst
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>
@ -279,30 +275,9 @@ class ArmStaticInst : public StaticInst
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
@ -311,14 +286,9 @@ class ArmStaticInst : public StaticInst
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

View file

@ -459,6 +459,18 @@ class FpOp : public PredOp
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

View file

@ -168,15 +168,9 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
{
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 &&
@ -239,13 +233,10 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
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",
@ -414,7 +405,7 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
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] =

View file

@ -83,7 +83,7 @@ output exec {{
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);
}
}};

View file

@ -46,15 +46,17 @@ let {{
# 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",
@ -66,10 +68,12 @@ let {{
# 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),
@ -81,8 +85,8 @@ let {{
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
@ -97,28 +101,28 @@ let {{
// 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,
@ -136,8 +140,10 @@ let {{
#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",
@ -155,7 +161,11 @@ let {{
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 = '''
@ -164,7 +174,11 @@ let {{
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,

View file

@ -239,6 +239,10 @@ let {{
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,
@ -253,7 +257,8 @@ let {{
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")

View file

@ -105,12 +105,16 @@ let {{
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

View file

@ -93,7 +93,9 @@ let {{
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',

View file

@ -83,6 +83,10 @@ let {{
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",
@ -107,6 +111,10 @@ let {{
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",
@ -462,8 +470,12 @@ let {{
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)
@ -638,7 +650,10 @@ let {{
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,
@ -648,7 +663,10 @@ let {{
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,

View file

@ -54,11 +54,10 @@ def operand_types {{
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 = '''
@ -81,140 +80,133 @@ let {{
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)
}};

View file

@ -123,15 +123,6 @@ namespace ArmISA
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;

View file

@ -103,8 +103,7 @@ LinuxArmSystem::startup()
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);

View file

@ -106,7 +106,7 @@ Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc)
}
//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
@ -121,7 +121,7 @@ Trace::ArmNativeTrace::check(NativeTraceRecord *record)
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);

View file

@ -148,11 +148,11 @@ Predecoder::process()
//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;

View file

@ -94,7 +94,7 @@ namespace ArmISA
//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.
@ -121,9 +121,10 @@ namespace ArmISA
}
//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;
}

View file

@ -360,11 +360,11 @@ ArmLiveProcess::argsInit(int intSize, int pageSize)
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);

View file

@ -70,7 +70,7 @@ class ArmSystem : public System
// 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;
}
};

View file

@ -107,7 +107,7 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
/** @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);

View file

@ -316,7 +316,7 @@ TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
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();
@ -362,7 +362,7 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
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();

View file

@ -43,8 +43,10 @@
#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
@ -188,6 +190,189 @@ 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 &section)
{
Base::unserialize(cp, section);
UNSERIALIZE_SCALAR(flags);
UNSERIALIZE_SCALAR(nextFlags);
}
};
// Shift types for ARM instructions
enum ArmShiftType {
LSL = 0,

View file

@ -128,13 +128,9 @@ readCp15Register(uint32_t &Rd, int CRn, int opc1, int CRm, int opc2)
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);
}

View file

@ -51,10 +51,19 @@
#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)
{
@ -93,12 +102,6 @@ namespace ArmISA {
tc->activate(0);
}
static inline bool
isThumb(Addr pc)
{
return (pc & PcTBit);
}
static inline void
copyRegs(ThreadContext *src, ThreadContext *dest)
{
@ -163,6 +166,12 @@ Fault readCp15Register(uint32_t &Rd, int CRn, int opc1, int CRm, int opc2);
void skipFunction(ThreadContext *tc);
inline void
advancePC(PCState &pc, const StaticInstPtr inst)
{
inst->advancePC(pc);
}
};

432
src/arch/generic/types.hh Normal file
View file

@ -0,0 +1,432 @@
/*
* 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 &section)
{
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 &section)
{
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 &section)
{
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 &section)
{
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

View file

@ -681,15 +681,25 @@ class MemOperand(Operand):
def makeAccSize(self):
return self.size
class PCStateOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
return '%s = xc->pcState();\n' % self.base_name
def makeWrite(self):
return 'xc->pcState(%s);\n' % self.base_name
def makeDecl(self):
return 'TheISA::PCState ' + self.base_name + ' M5_VAR_USED;\n';
class PCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
return '%s = xc->readPC();\n' % self.base_name
def makeWrite(self):
return 'xc->setPC(%s);\n' % self.base_name
return '%s = xc->instAddr();\n' % self.base_name
class UPCOperand(Operand):
def makeConstructor(self):
@ -697,27 +707,8 @@ class UPCOperand(Operand):
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
class NUPCOperand(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
def makeWrite(self):
if self.write_code != None:
return self.buildWriteCode('setNextMicroPC')
return 'xc->setNextMicroPC(%s);\n' % self.base_name
return self.buildReadCode('microPC')
return '%s = xc->microPC();\n' % self.base_name
class NPCOperand(Operand):
def makeConstructor(self):
@ -725,27 +716,8 @@ class NPCOperand(Operand):
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
class NNPCOperand(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

View file

@ -56,6 +56,13 @@ output header {{
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();
}
};
}};

View file

@ -133,25 +133,34 @@ decode OPCODE_HI default Unknown::unknown() {
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);
}
}
@ -323,9 +332,14 @@ decode OPCODE_HI default Unknown::unknown() {
}
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 {
@ -694,15 +708,16 @@ decode OPCODE_HI default Unknown::unknown() {
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 &&
@ -711,6 +726,7 @@ decode OPCODE_HI default Unknown::unknown() {
//xc->setShadowSet(srsCtl.pss);
}
}
PCS = pc;
LLFlag = 0;
Status = status;
SRSCtl = srsCtl;
@ -718,13 +734,15 @@ decode OPCODE_HI default Unknown::unknown() {
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);
}

View file

@ -89,7 +89,7 @@ output header {{
}
}
Addr branchTarget(Addr branchPC) const;
MipsISA::PCState branchTarget(const MipsISA::PCState &branchPC) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
@ -116,7 +116,7 @@ output header {{
{
}
Addr branchTarget(ThreadContext *tc) const;
MipsISA::PCState branchTarget(ThreadContext *tc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
@ -124,17 +124,25 @@ output header {{
}};
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 &
@ -217,19 +225,16 @@ output decoder {{
}};
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, )
@ -241,11 +246,17 @@ def format Branch(code, *opt_flags) {{
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)
@ -255,19 +266,16 @@ def format Branch(code, *opt_flags) {{
}};
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, )
@ -278,19 +286,19 @@ def format DspBranch(code, *opt_flags) {{
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)
@ -305,12 +313,18 @@ def format Jump(code, *opt_flags) {{
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)

View file

@ -39,6 +39,7 @@ output header {{
#include <iomanip>
#include "arch/mips/isa_traits.hh"
#include "arch/mips/types.hh"
#include "cpu/static_inst.hh"
#include "mem/packet.hh"
}};

View file

@ -151,6 +151,5 @@ def operands {{
'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)
}};

View file

@ -77,11 +77,12 @@ haltThread(TC *tc)
// 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());
}
}
@ -91,17 +92,14 @@ restoreThread(TC *tc)
{
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);
}
}

View file

@ -75,7 +75,7 @@ class Predecoder
//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;
}
@ -94,7 +94,7 @@ class Predecoder
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst()
getExtMachInst(PCState &pc)
{
return emi;
}

View file

@ -176,10 +176,7 @@ MipsLiveProcess::argsInit(int pageSize)
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());
}

View file

@ -31,6 +31,7 @@
#ifndef __ARCH_MIPS_TYPES_HH__
#define __ARCH_MIPS_TYPES_HH__
#include "arch/generic/types.hh"
#include "base/types.hh"
namespace MipsISA
@ -39,6 +40,8 @@ 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

View file

@ -267,10 +267,9 @@ copyMiscRegs(ThreadContext *src, ThreadContext *dest)
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);
}

View file

@ -39,12 +39,22 @@
#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);
////////////////////////////////////////////////////////////////////////
@ -105,6 +115,12 @@ void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
void skipFunction(ThreadContext *tc);
inline void
advancePC(PCState &pc, const StaticInstPtr inst)
{
pc.advance();
}
};

View file

@ -52,10 +52,10 @@ PCDependentDisassembly::disassemble(Addr pc, const SymbolTable *symtab) const
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
@ -76,8 +76,8 @@ BranchPCRel::generateDisassembly(Addr pc, const SymbolTable *symtab) const
return ss.str();
}
Addr
BranchNonPCRel::branchTarget(Addr pc) const
PowerISA::PCState
BranchNonPCRel::branchTarget(const PowerISA::PCState &pc) const
{
return targetAddr;
}
@ -98,10 +98,10 @@ BranchNonPCRel::generateDisassembly(Addr pc, const SymbolTable *symtab) const
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
@ -124,8 +124,8 @@ BranchPCRelCond::generateDisassembly(Addr pc, const SymbolTable *symtab) const
return ss.str();
}
Addr
BranchNonPCRelCond::branchTarget(Addr pc) const
PowerISA::PCState
BranchNonPCRelCond::branchTarget(const PowerISA::PCState &pc) const
{
return targetAddr;
}
@ -149,11 +149,11 @@ BranchNonPCRelCond::generateDisassembly(Addr pc,
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

View file

@ -86,7 +86,7 @@ class BranchPCRel : public PCDependentDisassembly
}
}
Addr branchTarget(Addr pc) const;
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
@ -112,7 +112,7 @@ class BranchNonPCRel : public PCDependentDisassembly
}
}
Addr branchTarget(Addr pc) const;
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
@ -187,7 +187,7 @@ class BranchPCRelCond : public BranchCond
}
}
Addr branchTarget(Addr pc) const;
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
@ -213,7 +213,7 @@ class BranchNonPCRelCond : public BranchCond
}
}
Addr branchTarget(Addr pc) const;
PowerISA::PCState branchTarget(const PowerISA::PCState &pc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
@ -231,7 +231,7 @@ class BranchRegCond : public BranchCond
{
}
Addr branchTarget(ThreadContext *tc) const;
PowerISA::PCState branchTarget(ThreadContext *tc) const;
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

View file

@ -63,6 +63,12 @@ class PowerStaticInst : public StaticInst
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
void
advancePC(PowerISA::PCState &pcState) const
{
pcState.advance();
}
};
} // PowerISA namespace

View file

@ -381,12 +381,20 @@ decode OPCODE default Unknown::unknown() {
// 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;
}});
}
}
@ -394,12 +402,20 @@ decode OPCODE default Unknown::unknown() {
// 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;
}});
}
}
@ -407,12 +423,20 @@ decode OPCODE default Unknown::unknown() {
// 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.

View file

@ -48,7 +48,7 @@
let {{
# Simple code to update link register (LR).
updateLrCode = 'LR = PC + 4;'
updateLrCode = 'PowerISA::PCState lrpc = PCS; LR = lrpc.pc() + 4;'
}};
@ -105,7 +105,7 @@ def GetCondCode(br_code):
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
@ -119,7 +119,7 @@ def GetCtrCondCode(br_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

View file

@ -76,7 +76,7 @@ output exec {{
{
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;
}
}};

View file

@ -59,8 +59,7 @@ def operands {{
'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),

View file

@ -83,7 +83,7 @@ class Predecoder
// 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;
}
@ -110,7 +110,7 @@ class Predecoder
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst()
getExtMachInst(PCState &pcState)
{
return emi;
}

View file

@ -256,9 +256,7 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
//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);

View file

@ -31,6 +31,7 @@
#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"
@ -78,6 +79,8 @@ BitUnion32(ExtMachInst)
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

View file

@ -52,8 +52,7 @@ copyRegs(ThreadContext *src, ThreadContext *dest)
copyMiscRegs(src, dest);
// Lastly copy PC/NPC
dest->setPC(src->readPC());
dest->setNextPC(src->readNextPC());
dest->pcState(src->pcState());
}
void

View file

@ -36,10 +36,19 @@
#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.
@ -63,6 +72,12 @@ copyMiscRegs(ThreadContext *src, ThreadContext *dest)
void skipFunction(ThreadContext *tc);
inline void
advancePC(PCState &pc, const StaticInstPtr inst)
{
pc.advance();
}
} // PowerISA namespace
#endif // __ARCH_POWER_UTILITY_HH__

View file

@ -307,15 +307,11 @@ void doREDFault(ThreadContext *tc, TrapType tt)
//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);
@ -332,9 +328,9 @@ void doREDFault(ThreadContext *tc, TrapType tt)
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);
@ -394,18 +390,14 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
//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
@ -423,9 +415,9 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
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);
@ -479,7 +471,7 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
}
}
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;
@ -554,9 +546,13 @@ void SparcFaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
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)
@ -593,9 +589,14 @@ 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
@ -664,10 +665,7 @@ void SpillNNormal::invoke(ThreadContext *tc, StaticInstPtr inst)
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)
@ -681,10 +679,7 @@ 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)
@ -702,9 +697,9 @@ 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

View file

@ -111,6 +111,8 @@ output header {{
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);
@ -260,6 +262,12 @@ output decoder {{
}
}
void
SparcStaticInst::advancePC(SparcISA::PCState &pcState) const
{
pcState.advance();
}
void
SparcStaticInst::printSrcReg(std::ostream &os, int reg) const
{

View file

@ -46,14 +46,18 @@ decode OP default Unknown::unknown()
{
//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
{
@ -66,14 +70,18 @@ decode OP default Unknown::unknown()
{
//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)}});
}
@ -97,14 +105,18 @@ decode OP default Unknown::unknown()
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=
@ -123,14 +135,18 @@ decode OP default Unknown::unknown()
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)}});
@ -138,11 +154,13 @@ decode OP default Unknown::unknown()
}
}
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 {
@ -316,10 +334,12 @@ decode OP default Unknown::unknown()
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;
@ -973,7 +993,8 @@ decode OP default Unknown::unknown()
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
@ -985,11 +1006,13 @@ decode OP default Unknown::unknown()
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({{
@ -1010,7 +1033,9 @@ decode OP default Unknown::unknown()
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;
@ -1082,8 +1107,10 @@ decode OP default Unknown::unknown()
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({{
@ -1093,8 +1120,10 @@ decode OP default Unknown::unknown()
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);
}

View file

@ -193,7 +193,7 @@ def template JumpExecute {{
%(op_decl)s;
%(op_rd)s;
NNPC = xc->readNextNPC();
PCS = PCS;
%(code)s;
if(fault == NoFault)
@ -289,15 +289,24 @@ let {{
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:

View file

@ -81,10 +81,11 @@ output header {{
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
@ -102,6 +103,15 @@ output header {{
{
flags[IsMicroop] = true;
}
void
advancePC(SparcISA::PCState &pcState) const
{
if (flags[IsLastMicroop])
pcState.uEnd();
else
pcState.uAdvance();
}
};
class SparcDelayedMicroInst : public SparcMicroInst

View file

@ -126,8 +126,7 @@ def operands {{
#'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),

View file

@ -67,16 +67,17 @@ Trace::SparcNativeTrace::check(NativeTraceRecord *record)
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

View file

@ -72,7 +72,7 @@ namespace SparcISA
//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
@ -99,7 +99,7 @@ namespace SparcISA
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst & getExtMachInst()
const ExtMachInst & getExtMachInst(PCState &pcState)
{
return emi;
}

View file

@ -69,41 +69,39 @@ SparcLiveProcess::SparcLiveProcess(LiveProcessParams * params,
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);
@ -402,10 +400,7 @@ SparcLiveProcess::argsInit(int pageSize)
// 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);

View file

@ -179,12 +179,14 @@ RemoteGDB::getregs()
{
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));
@ -193,8 +195,8 @@ RemoteGDB::getregs()
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));
@ -224,8 +226,13 @@ RemoteGDB::getregs()
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
@ -241,6 +248,6 @@ RemoteGDB::clearSingleStep()
void
RemoteGDB::setSingleStep()
{
nextBkpt = context->readNextPC();
nextBkpt = context->pcState().npc();
setTempBreakpoint(nextBkpt);
}

View file

@ -33,12 +33,15 @@
#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 {

View file

@ -213,20 +213,16 @@ copyRegs(ThreadContext *src, ThreadContext *dest)
// 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);
}

View file

@ -36,11 +36,22 @@
#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);
@ -78,6 +89,12 @@ namespace SparcISA
void skipFunction(ThreadContext *tc);
inline void
advancePC(PCState &pc, const StaticInstPtr inst)
{
inst->advancePC(pc);
}
} // namespace SparcISA
#endif

View file

@ -58,7 +58,8 @@ namespace X86ISA
#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);
@ -86,8 +87,9 @@ namespace X86ISA
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
@ -106,9 +108,8 @@ namespace X86ISA
{
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)
@ -207,9 +208,8 @@ namespace X86ISA
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);
@ -243,8 +243,9 @@ namespace X86ISA
// 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
@ -263,8 +264,7 @@ namespace X86ISA
// 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

View file

@ -73,7 +73,8 @@ class MacroopBase : public X86StaticInst
StaticInstPtr * microops;
StaticInstPtr fetchMicroop(MicroPC microPC)
StaticInstPtr
fetchMicroop(MicroPC microPC) const
{
assert(microPC < numMicroops);
return microops[microPC];

View file

@ -114,6 +114,15 @@ namespace X86ISA
}
bool checkCondition(uint64_t flags, int condition) const;
void
advancePC(PCState &pcState) const
{
if (flags[IsLastMicroop])
pcState.uEnd();
else
pcState.uAdvance();
}
};
}

View file

@ -158,6 +158,12 @@ namespace X86ISA
panic("Tried to pick with unrecognized size %d.\n", size);
}
}
void
advancePC(PCState &pcState) const
{
pcState.advance();
}
};
}

View file

@ -199,7 +199,7 @@
#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");

View file

@ -47,13 +47,13 @@ output header {{
/**
* 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)
{
}

View file

@ -944,8 +944,12 @@ let {{
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'
@ -961,7 +965,10 @@ let {{
'''
class Rdip(RdRegOp):
code = 'DestReg = RIP - CSBase'
code = '''
X86ISA::PCState pc = PCS;
DestReg = pc.npc() - CSBase;
'''
class Ruflags(RdRegOp):
code = 'DestReg = ccFlagBits'

View file

@ -169,15 +169,23 @@ let {{
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)

View file

@ -97,9 +97,8 @@ def operands {{
'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),

View file

@ -85,7 +85,7 @@ X86NativeTrace::ThreadState::update(ThreadContext *tc)
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));

View file

@ -188,11 +188,11 @@ namespace X86ISA
//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();
@ -208,22 +208,26 @@ namespace X86ISA
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;
}
};
};

View file

@ -116,10 +116,12 @@ X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params,
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);
}
@ -645,11 +647,9 @@ X86LiveProcess::argsInit(int pageSize,
//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);

View file

@ -320,8 +320,7 @@ X86System::initState()
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!

View file

@ -609,7 +609,7 @@ TLB::translate(RequestPtr req, ThreadContext *tc, Translation *translation,
#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;

View file

@ -42,6 +42,7 @@
#include <iostream>
#include "arch/generic/types.hh"
#include "base/bitunion.hh"
#include "base/cprintf.hh"
#include "base/hashmap.hh"
@ -221,6 +222,8 @@ namespace X86ISA
return true;
}
typedef GenericISA::UPCState<MachInst> PCState;
struct CoreSpecific {
int core_type;
};

View file

@ -72,8 +72,10 @@ void initCPU(ThreadContext *tc, int cpuId)
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
@ -231,8 +233,7 @@ copyRegs(ThreadContext *src, ThreadContext *dest)
//copy float regs
copyMiscRegs(src, dest);
dest->setPC(src->readPC());
dest->setNextPC(src->readNextPC());
dest->pcState(src->pcState());
}
void

View file

@ -46,12 +46,22 @@
#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);
@ -86,6 +96,12 @@ namespace X86ISA
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__

View file

@ -645,8 +645,8 @@ BaseRemoteGDB::trap(int type)
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();
@ -806,8 +806,7 @@ BaseRemoteGDB::trap(int type)
subcmd = hex2i(&p);
if (*p++ == ';') {
val = hex2i(&p);
context->setPC(val);
context->setNextPC(val + sizeof(MachInst));
context->pcState(val);
}
clearSingleStep();
goto out;
@ -815,8 +814,7 @@ BaseRemoteGDB::trap(int type)
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;
@ -825,8 +823,7 @@ BaseRemoteGDB::trap(int type)
subcmd = hex2i(&p);
if (*p++ == ';') {
val = hex2i(&p);
context->setPC(val);
context->setNextPC(val + sizeof(MachInst));
context->pcState(val);
}
setSingleStep();
goto out;
@ -834,8 +831,7 @@ BaseRemoteGDB::trap(int type)
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;

View file

@ -67,6 +67,28 @@ const Tick MaxTick = LL(0x7fffffffffffffff);
*/
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;
/**

View file

@ -38,6 +38,7 @@
#include <string>
#include "arch/faults.hh"
#include "arch/utility.hh"
#include "base/fast_alloc.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
@ -241,36 +242,15 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** 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;
/** PC state for this instruction. */
TheISA::PCState pc;
/** Next non-speculative NPC. Target PC for Mips or Sparc. */
Addr nextNPC;
/** 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;
@ -386,27 +366,23 @@ class BaseDynInst : public FastAlloc, public RefCounted
}
/** 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.
@ -443,45 +419,22 @@ class BaseDynInst : public FastAlloc, public RefCounted
*/
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()
@ -497,9 +450,9 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** 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);
}
//
@ -576,7 +529,8 @@ class BaseDynInst : public FastAlloc, public RefCounted
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(); }
@ -773,30 +727,20 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** Returns whether or not this instruction is squashed in the ROB. */
bool isSquashedInROB() const { return status[SquashedInROB]; }
/** Read the PC state of this instruction. */
const TheISA::PCState pcState() const { return pc; }
/** Set the PC state of this instruction. */
const void pcState(const TheISA::PCState &val) { pc = val; }
/** Read the PC of this instruction. */
const Addr readPC() const { return PC; }
const Addr instAddr() const { return pc.instAddr(); }
/** Read the PC of the next instruction. */
const Addr nextInstAddr() const { return pc.nextInstAddr(); }
/**Read the micro PC of this instruction. */
const Addr readMicroPC() const { return microPC; }
/** Set the next PC of this instruction (its actual target). */
void setNextPC(Addr val)
{
nextPC = val;
}
/** 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
}
void setNextMicroPC(Addr val)
{
nextMicroPC = val;
}
const Addr microPC() const { return pc.microPC(); }
bool readPredicate()
{
@ -895,7 +839,7 @@ BaseDynInst<Impl>::readBytes(Addr addr, uint8_t *data,
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;
@ -956,7 +900,7 @@ BaseDynInst<Impl>::writeBytes(uint8_t *data, unsigned size,
}
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;

View file

@ -62,32 +62,14 @@ my_hash_t thishash;
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();
@ -95,32 +77,14 @@ BaseDynInst<Impl>::BaseDynInst(StaticInstPtr _staticInst,
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();
@ -301,8 +265,8 @@ template <class Impl>
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");
}
@ -311,8 +275,8 @@ void
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();
}

View file

@ -241,13 +241,9 @@ class CheckerCPU : public BaseCPU
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)
{

Some files were not shown because too many files have changed in this diff Show more