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:
parent
373154a25a
commit
6f4bd2c1da
171 changed files with 2512 additions and 2302 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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] =
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 §ion)
|
||||
{
|
||||
Base::unserialize(cp, section);
|
||||
UNSERIALIZE_SCALAR(flags);
|
||||
UNSERIALIZE_SCALAR(nextFlags);
|
||||
}
|
||||
};
|
||||
|
||||
// Shift types for ARM instructions
|
||||
enum ArmShiftType {
|
||||
LSL = 0,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
432
src/arch/generic/types.hh
Normal 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 §ion)
|
||||
{
|
||||
UNSERIALIZE_SCALAR(_pc);
|
||||
UNSERIALIZE_SCALAR(_npc);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Different flavors of PC state. Only ISA specific code should rely on
|
||||
* any particular type of PC state being available. All other code should
|
||||
* use the interface above.
|
||||
*/
|
||||
|
||||
// The most basic type of PC.
|
||||
template <class MachInst>
|
||||
class SimplePCState : public PCStateBase
|
||||
{
|
||||
protected:
|
||||
typedef PCStateBase Base;
|
||||
|
||||
public:
|
||||
|
||||
Addr pc() const { return _pc; }
|
||||
void pc(Addr val) { _pc = val; }
|
||||
|
||||
Addr npc() const { return _npc; }
|
||||
void npc(Addr val) { _npc = val; }
|
||||
|
||||
void
|
||||
set(Addr val)
|
||||
{
|
||||
pc(val);
|
||||
npc(val + sizeof(MachInst));
|
||||
};
|
||||
|
||||
SimplePCState() {}
|
||||
SimplePCState(Addr val) { set(val); }
|
||||
|
||||
bool
|
||||
branching() const
|
||||
{
|
||||
return this->npc() != this->pc() + sizeof(MachInst);
|
||||
}
|
||||
|
||||
// Advance the PC.
|
||||
void
|
||||
advance()
|
||||
{
|
||||
_pc = _npc;
|
||||
_npc += sizeof(MachInst);
|
||||
}
|
||||
};
|
||||
|
||||
template <class MachInst>
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, const SimplePCState<MachInst> &pc)
|
||||
{
|
||||
ccprintf(os, "(%#x=>%#x)", pc.pc(), pc.npc());
|
||||
return os;
|
||||
}
|
||||
|
||||
// A PC and microcode PC.
|
||||
template <class MachInst>
|
||||
class UPCState : public SimplePCState<MachInst>
|
||||
{
|
||||
protected:
|
||||
typedef SimplePCState<MachInst> Base;
|
||||
|
||||
MicroPC _upc;
|
||||
MicroPC _nupc;
|
||||
|
||||
public:
|
||||
|
||||
MicroPC upc() const { return _upc; }
|
||||
void upc(MicroPC val) { _upc = val; }
|
||||
|
||||
MicroPC nupc() const { return _nupc; }
|
||||
void nupc(MicroPC val) { _nupc = val; }
|
||||
|
||||
MicroPC
|
||||
microPC() const
|
||||
{
|
||||
return _upc;
|
||||
}
|
||||
|
||||
void
|
||||
set(Addr val)
|
||||
{
|
||||
Base::set(val);
|
||||
upc(0);
|
||||
nupc(1);
|
||||
}
|
||||
|
||||
UPCState() {}
|
||||
UPCState(Addr val) { set(val); }
|
||||
|
||||
bool
|
||||
branching() const
|
||||
{
|
||||
return this->npc() != this->pc() + sizeof(MachInst) ||
|
||||
this->nupc() != this->upc() + 1;
|
||||
}
|
||||
|
||||
// Advance the upc within the instruction.
|
||||
void
|
||||
uAdvance()
|
||||
{
|
||||
_upc = _nupc;
|
||||
_nupc++;
|
||||
}
|
||||
|
||||
// End the macroop by resetting the upc and advancing the regular pc.
|
||||
void
|
||||
uEnd()
|
||||
{
|
||||
this->advance();
|
||||
_upc = 0;
|
||||
_nupc = 1;
|
||||
}
|
||||
|
||||
bool
|
||||
operator == (const UPCState<MachInst> &opc) const
|
||||
{
|
||||
return Base::_pc == opc._pc &&
|
||||
Base::_npc == opc._npc &&
|
||||
_upc == opc._upc && _nupc == opc._nupc;
|
||||
}
|
||||
|
||||
void
|
||||
serialize(std::ostream &os)
|
||||
{
|
||||
Base::serialize(os);
|
||||
SERIALIZE_SCALAR(_upc);
|
||||
SERIALIZE_SCALAR(_nupc);
|
||||
}
|
||||
|
||||
void
|
||||
unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
Base::unserialize(cp, section);
|
||||
UNSERIALIZE_SCALAR(_upc);
|
||||
UNSERIALIZE_SCALAR(_nupc);
|
||||
}
|
||||
};
|
||||
|
||||
template <class MachInst>
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, const UPCState<MachInst> &pc)
|
||||
{
|
||||
ccprintf(os, "(%#x=>%#x).(%d=>%d)",
|
||||
pc.pc(), pc.npc(), pc.upc(), pc.npc());
|
||||
return os;
|
||||
}
|
||||
|
||||
// A PC with a delay slot.
|
||||
template <class MachInst>
|
||||
class DelaySlotPCState : public SimplePCState<MachInst>
|
||||
{
|
||||
protected:
|
||||
typedef SimplePCState<MachInst> Base;
|
||||
|
||||
Addr _nnpc;
|
||||
|
||||
public:
|
||||
|
||||
Addr nnpc() const { return _nnpc; }
|
||||
void nnpc(Addr val) { _nnpc = val; }
|
||||
|
||||
void
|
||||
set(Addr val)
|
||||
{
|
||||
Base::set(val);
|
||||
nnpc(val + 2 * sizeof(MachInst));
|
||||
}
|
||||
|
||||
DelaySlotPCState() {}
|
||||
DelaySlotPCState(Addr val) { set(val); }
|
||||
|
||||
bool
|
||||
branching() const
|
||||
{
|
||||
return !(this->nnpc() == this->npc() + sizeof(MachInst) &&
|
||||
(this->npc() == this->pc() + sizeof(MachInst) ||
|
||||
this->npc() == this->pc() + 2 * sizeof(MachInst)));
|
||||
}
|
||||
|
||||
// Advance the PC.
|
||||
void
|
||||
advance()
|
||||
{
|
||||
Base::_pc = Base::_npc;
|
||||
Base::_npc = _nnpc;
|
||||
_nnpc += sizeof(MachInst);
|
||||
}
|
||||
|
||||
bool
|
||||
operator == (const DelaySlotPCState<MachInst> &opc) const
|
||||
{
|
||||
return Base::_pc == opc._pc &&
|
||||
Base::_npc == opc._npc &&
|
||||
_nnpc == opc._nnpc;
|
||||
}
|
||||
|
||||
void
|
||||
serialize(std::ostream &os)
|
||||
{
|
||||
Base::serialize(os);
|
||||
SERIALIZE_SCALAR(_nnpc);
|
||||
}
|
||||
|
||||
void
|
||||
unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
Base::unserialize(cp, section);
|
||||
UNSERIALIZE_SCALAR(_nnpc);
|
||||
}
|
||||
};
|
||||
|
||||
template <class MachInst>
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, const DelaySlotPCState<MachInst> &pc)
|
||||
{
|
||||
ccprintf(os, "(%#x=>%#x=>%#x)",
|
||||
pc.pc(), pc.npc(), pc.nnpc());
|
||||
return os;
|
||||
}
|
||||
|
||||
// A PC with a delay slot and a microcode PC.
|
||||
template <class MachInst>
|
||||
class DelaySlotUPCState : public DelaySlotPCState<MachInst>
|
||||
{
|
||||
protected:
|
||||
typedef DelaySlotPCState<MachInst> Base;
|
||||
|
||||
MicroPC _upc;
|
||||
MicroPC _nupc;
|
||||
|
||||
public:
|
||||
|
||||
MicroPC upc() const { return _upc; }
|
||||
void upc(MicroPC val) { _upc = val; }
|
||||
|
||||
MicroPC nupc() const { return _nupc; }
|
||||
void nupc(MicroPC val) { _nupc = val; }
|
||||
|
||||
MicroPC
|
||||
microPC() const
|
||||
{
|
||||
return _upc;
|
||||
}
|
||||
|
||||
void
|
||||
set(Addr val)
|
||||
{
|
||||
Base::set(val);
|
||||
upc(0);
|
||||
nupc(1);
|
||||
}
|
||||
|
||||
DelaySlotUPCState() {}
|
||||
DelaySlotUPCState(Addr val) { set(val); }
|
||||
|
||||
bool
|
||||
branching() const
|
||||
{
|
||||
return Base::branching() || this->nupc() != this->upc() + 1;
|
||||
}
|
||||
|
||||
// Advance the upc within the instruction.
|
||||
void
|
||||
uAdvance()
|
||||
{
|
||||
_upc = _nupc;
|
||||
_nupc++;
|
||||
}
|
||||
|
||||
// End the macroop by resetting the upc and advancing the regular pc.
|
||||
void
|
||||
uEnd()
|
||||
{
|
||||
this->advance();
|
||||
_upc = 0;
|
||||
_nupc = 1;
|
||||
}
|
||||
|
||||
bool
|
||||
operator == (const DelaySlotUPCState<MachInst> &opc) const
|
||||
{
|
||||
return Base::_pc == opc._pc &&
|
||||
Base::_npc == opc._npc &&
|
||||
Base::_nnpc == opc._nnpc &&
|
||||
_upc == opc._upc && _nupc == opc._nupc;
|
||||
}
|
||||
|
||||
void
|
||||
serialize(std::ostream &os)
|
||||
{
|
||||
Base::serialize(os);
|
||||
SERIALIZE_SCALAR(_upc);
|
||||
SERIALIZE_SCALAR(_nupc);
|
||||
}
|
||||
|
||||
void
|
||||
unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
Base::unserialize(cp, section);
|
||||
UNSERIALIZE_SCALAR(_upc);
|
||||
UNSERIALIZE_SCALAR(_nupc);
|
||||
}
|
||||
};
|
||||
|
||||
template <class MachInst>
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, const DelaySlotUPCState<MachInst> &pc)
|
||||
{
|
||||
ccprintf(os, "(%#x=>%#x=>%#x).(%d=>%d)",
|
||||
pc.pc(), pc.npc(), pc.nnpc(), pc.upc(), pc.nupc());
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
}};
|
||||
|
|
|
@ -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)
|
||||
}};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}};
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -158,6 +158,12 @@ namespace X86ISA
|
|||
panic("Tried to pick with unrecognized size %d.\n", size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
advancePC(PCState &pcState) const
|
||||
{
|
||||
pcState.advance();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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!
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue