summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2010-10-31 00:07:20 -0700
committerGabe Black <gblack@eecs.umich.edu>2010-10-31 00:07:20 -0700
commit6f4bd2c1da0dc7783da87c4877a41332901199b2 (patch)
tree99f2898e2b659338fd0b01d86eb9a4f8d981e21a /src/arch
parent373154a25afb1bed946e5a2a7cfd411e4bd7fad6 (diff)
downloadgem5-6f4bd2c1da0dc7783da87c4877a41332901199b2.tar.xz
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.
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/alpha/ev5.cc11
-rw-r--r--src/arch/alpha/faults.cc10
-rw-r--r--src/arch/alpha/interrupts.hh2
-rw-r--r--src/arch/alpha/isa/branch.isa40
-rw-r--r--src/arch/alpha/isa/decoder.isa14
-rw-r--r--src/arch/alpha/isa/main.isa9
-rw-r--r--src/arch/alpha/predecoder.hh6
-rw-r--r--src/arch/alpha/process.cc10
-rw-r--r--src/arch/alpha/remote_gdb.cc20
-rw-r--r--src/arch/alpha/stacktrace.cc4
-rw-r--r--src/arch/alpha/tlb.cc4
-rw-r--r--src/arch/alpha/types.hh3
-rw-r--r--src/arch/alpha/utility.cc9
-rw-r--r--src/arch/alpha/utility.hh16
-rw-r--r--src/arch/arm/faults.cc34
-rw-r--r--src/arch/arm/insts/macromem.hh12
-rw-r--r--src/arch/arm/insts/mem.hh38
-rw-r--r--src/arch/arm/insts/pred_inst.hh11
-rw-r--r--src/arch/arm/insts/static_inst.hh62
-rw-r--r--src/arch/arm/insts/vfp.hh12
-rw-r--r--src/arch/arm/isa.cc25
-rw-r--r--src/arch/arm/isa/formats/breakpoint.isa2
-rw-r--r--src/arch/arm/isa/insts/branch.isa56
-rw-r--r--src/arch/arm/isa/insts/data.isa7
-rw-r--r--src/arch/arm/isa/insts/ldr.isa6
-rw-r--r--src/arch/arm/isa/insts/macromem.isa4
-rw-r--r--src/arch/arm/isa/insts/misc.isa24
-rw-r--r--src/arch/arm/isa/operands.isa204
-rw-r--r--src/arch/arm/isa_traits.hh9
-rw-r--r--src/arch/arm/linux/system.cc3
-rw-r--r--src/arch/arm/nativetrace.cc4
-rw-r--r--src/arch/arm/predecoder.cc6
-rw-r--r--src/arch/arm/predecoder.hh5
-rw-r--r--src/arch/arm/process.cc10
-rw-r--r--src/arch/arm/system.hh2
-rw-r--r--src/arch/arm/table_walker.cc2
-rw-r--r--src/arch/arm/tlb.cc4
-rw-r--r--src/arch/arm/types.hh185
-rw-r--r--src/arch/arm/utility.cc10
-rw-r--r--src/arch/arm/utility.hh21
-rw-r--r--src/arch/generic/types.hh432
-rwxr-xr-xsrc/arch/isa_parser.py54
-rw-r--r--src/arch/mips/isa/base.isa7
-rw-r--r--src/arch/mips/isa/decoder.isa44
-rw-r--r--src/arch/mips/isa/formats/branch.isa90
-rw-r--r--src/arch/mips/isa/includes.isa1
-rw-r--r--src/arch/mips/isa/operands.isa3
-rwxr-xr-xsrc/arch/mips/mt.hh14
-rw-r--r--src/arch/mips/predecoder.hh4
-rw-r--r--src/arch/mips/process.cc5
-rw-r--r--src/arch/mips/types.hh3
-rw-r--r--src/arch/mips/utility.cc7
-rw-r--r--src/arch/mips/utility.hh16
-rw-r--r--src/arch/power/insts/branch.cc24
-rw-r--r--src/arch/power/insts/branch.hh10
-rw-r--r--src/arch/power/insts/static_inst.hh6
-rw-r--r--src/arch/power/isa/decoder.isa36
-rw-r--r--src/arch/power/isa/formats/branch.isa6
-rw-r--r--src/arch/power/isa/formats/unknown.isa2
-rw-r--r--src/arch/power/isa/operands.isa3
-rw-r--r--src/arch/power/predecoder.hh4
-rw-r--r--src/arch/power/process.cc4
-rw-r--r--src/arch/power/types.hh3
-rw-r--r--src/arch/power/utility.cc3
-rw-r--r--src/arch/power/utility.hh15
-rw-r--r--src/arch/sparc/faults.cc65
-rw-r--r--src/arch/sparc/isa/base.isa8
-rw-r--r--src/arch/sparc/isa/decoder.isa89
-rw-r--r--src/arch/sparc/isa/formats/branch.isa17
-rw-r--r--src/arch/sparc/isa/formats/micro.isa16
-rw-r--r--src/arch/sparc/isa/operands.isa3
-rw-r--r--src/arch/sparc/nativetrace.cc5
-rw-r--r--src/arch/sparc/predecoder.hh4
-rw-r--r--src/arch/sparc/process.cc25
-rw-r--r--src/arch/sparc/remote_gdb.cc21
-rw-r--r--src/arch/sparc/types.hh3
-rw-r--r--src/arch/sparc/utility.cc12
-rw-r--r--src/arch/sparc/utility.hh17
-rw-r--r--src/arch/x86/faults.cc26
-rw-r--r--src/arch/x86/insts/macroop.hh3
-rw-r--r--src/arch/x86/insts/microop.hh9
-rw-r--r--src/arch/x86/insts/static_inst.hh6
-rw-r--r--src/arch/x86/isa/decoder/two_byte_opcodes.isa2
-rw-r--r--src/arch/x86/isa/formats/unknown.isa4
-rw-r--r--src/arch/x86/isa/microops/regop.isa13
-rw-r--r--src/arch/x86/isa/microops/seqop.isa16
-rw-r--r--src/arch/x86/isa/operands.isa5
-rw-r--r--src/arch/x86/nativetrace.cc2
-rw-r--r--src/arch/x86/predecoder.hh28
-rw-r--r--src/arch/x86/process.cc10
-rw-r--r--src/arch/x86/system.cc3
-rw-r--r--src/arch/x86/tlb.cc2
-rw-r--r--src/arch/x86/types.hh3
-rw-r--r--src/arch/x86/utility.cc9
-rw-r--r--src/arch/x86/utility.hh16
95 files changed, 1518 insertions, 636 deletions
diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc
index 0db75df46..f97244260 100644
--- a/src/arch/alpha/ev5.cc
+++ b/src/arch/alpha/ev5.cc
@@ -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)
diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc
index 9d4eeda8a..38386cce1 100644
--- a/src/arch/alpha/faults.cc
+++ b/src/arch/alpha/faults.cc
@@ -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
diff --git a/src/arch/alpha/interrupts.hh b/src/arch/alpha/interrupts.hh
index 3200201db..cbaa8e9bf 100644
--- a/src/arch/alpha/interrupts.hh
+++ b/src/arch/alpha/interrupts.hh
@@ -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
diff --git a/src/arch/alpha/isa/branch.isa b/src/arch/alpha/isa/branch.isa
index 974193efd..feb15b158 100644
--- a/src/arch/alpha/isa/branch.isa
+++ b/src/arch/alpha/isa/branch.isa
@@ -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)
}};
diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa
index fe70e4d16..e2947cf4a 100644
--- a/src/arch/alpha/isa/decoder.isa
+++ b/src/arch/alpha/isa/decoder.isa
@@ -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);
diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa
index 2a0699354..ffc267cd2 100644
--- a/src/arch/alpha/isa/main.isa
+++ b/src/arch/alpha/isa/main.isa
@@ -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();
+ }
};
}};
diff --git a/src/arch/alpha/predecoder.hh b/src/arch/alpha/predecoder.hh
index 913bd8764..f9a716b7f 100644
--- a/src/arch/alpha/predecoder.hh
+++ b/src/arch/alpha/predecoder.hh
@@ -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;
}
diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc
index f68a53a6f..3c3fd9b25 100644
--- a/src/arch/alpha/process.cc
+++ b/src/arch/alpha/process.cc
@@ -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
diff --git a/src/arch/alpha/remote_gdb.cc b/src/arch/alpha/remote_gdb.cc
index 5391d2056..9a2a5f23f 100644
--- a/src/arch/alpha/remote_gdb.cc
+++ b/src/arch/alpha/remote_gdb.cc
@@ -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.
diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc
index 1b5a9be34..9c6b3cff0 100644
--- a/src/arch/alpha/stacktrace.cc
+++ b/src/arch/alpha/stacktrace.cc
@@ -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) {
diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc
index b578741d9..614061ddd 100644
--- a/src/arch/alpha/tlb.cc
+++ b/src/arch/alpha/tlb.cc
@@ -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))
diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh
index 0d285c3b2..06c0168cf 100644
--- a/src/arch/alpha/types.hh
+++ b/src/arch/alpha/types.hh
@@ -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
diff --git a/src/arch/alpha/utility.cc b/src/arch/alpha/utility.cc
index 11560259f..2d56ca9b8 100644
--- a/src/arch/alpha/utility.cc
+++ b/src/arch/alpha/utility.cc
@@ -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);
}
diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh
index 6d5b8baf6..fdac8b8d1 100644
--- a/src/arch/alpha/utility.hh
+++ b/src/arch/alpha/utility.hh
@@ -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__
diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc
index 6e138119c..54cf5cfe5 100644
--- a/src/arch/arm/faults.cc
+++ b/src/arch/arm/faults.cc
@@ -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,
diff --git a/src/arch/arm/insts/macromem.hh b/src/arch/arm/insts/macromem.hh
index c1c8383da..018cb1de5 100644
--- a/src/arch/arm/insts/macromem.hh
+++ b/src/arch/arm/insts/macromem.hh
@@ -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();
+ }
+ }
};
/**
diff --git a/src/arch/arm/insts/mem.hh b/src/arch/arm/insts/mem.hh
index 1baba5112..2aa4de1d7 100644
--- a/src/arch/arm/insts/mem.hh
+++ b/src/arch/arm/insts/mem.hh
@@ -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];
diff --git a/src/arch/arm/insts/pred_inst.hh b/src/arch/arm/insts/pred_inst.hh
index b7d4c4709..f779b46f5 100644
--- a/src/arch/arm/insts/pred_inst.hh
+++ b/src/arch/arm/insts/pred_inst.hh
@@ -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();
+ }
};
}
diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh
index ad89a1a79..fa850190f 100644
--- a/src/arch/arm/insts/static_inst.hh
+++ b/src/arch/arm/insts/static_inst.hh
@@ -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
diff --git a/src/arch/arm/insts/vfp.hh b/src/arch/arm/insts/vfp.hh
index 964b62673..e962704e0 100644
--- a/src/arch/arm/insts/vfp.hh
+++ b/src/arch/arm/insts/vfp.hh
@@ -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
diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc
index d557cecbb..0ba62f08d 100644
--- a/src/arch/arm/isa.cc
+++ b/src/arch/arm/isa.cc
@@ -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] =
diff --git a/src/arch/arm/isa/formats/breakpoint.isa b/src/arch/arm/isa/formats/breakpoint.isa
index d59f6a712..1825d0878 100644
--- a/src/arch/arm/isa/formats/breakpoint.isa
+++ b/src/arch/arm/isa/formats/breakpoint.isa
@@ -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);
}
}};
diff --git a/src/arch/arm/isa/insts/branch.isa b/src/arch/arm/isa/insts/branch.isa
index e9ddd77b7..3ff9042e6 100644
--- a/src/arch/arm/isa/insts/branch.isa
+++ b/src/arch/arm/isa/insts/branch.isa
@@ -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,
diff --git a/src/arch/arm/isa/insts/data.isa b/src/arch/arm/isa/insts/data.isa
index 74eeee3b2..4d368e181 100644
--- a/src/arch/arm/isa/insts/data.isa
+++ b/src/arch/arm/isa/insts/data.isa
@@ -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")
diff --git a/src/arch/arm/isa/insts/ldr.isa b/src/arch/arm/isa/insts/ldr.isa
index dc043ed8e..92ad52a6d 100644
--- a/src/arch/arm/isa/insts/ldr.isa
+++ b/src/arch/arm/isa/insts/ldr.isa
@@ -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
diff --git a/src/arch/arm/isa/insts/macromem.isa b/src/arch/arm/isa/insts/macromem.isa
index 6bf789efd..a81050b1e 100644
--- a/src/arch/arm/isa/insts/macromem.isa
+++ b/src/arch/arm/isa/insts/macromem.isa
@@ -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',
diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa
index 5742f84ab..1abbc3de1 100644
--- a/src/arch/arm/isa/insts/misc.isa
+++ b/src/arch/arm/isa/insts/misc.isa
@@ -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,
diff --git a/src/arch/arm/isa/operands.isa b/src/arch/arm/isa/operands.isa
index 4f1b7f610..8e856e74d 100644
--- a/src/arch/arm/isa/operands.isa
+++ b/src/arch/arm/isa/operands.isa
@@ -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)
}};
diff --git a/src/arch/arm/isa_traits.hh b/src/arch/arm/isa_traits.hh
index 8d3f0ffe3..f6aa7fcf0 100644
--- a/src/arch/arm/isa_traits.hh
+++ b/src/arch/arm/isa_traits.hh
@@ -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;
diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc
index 7c4e00921..40658976b 100644
--- a/src/arch/arm/linux/system.cc
+++ b/src/arch/arm/linux/system.cc
@@ -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);
diff --git a/src/arch/arm/nativetrace.cc b/src/arch/arm/nativetrace.cc
index d97be88a2..75546f8de 100644
--- a/src/arch/arm/nativetrace.cc
+++ b/src/arch/arm/nativetrace.cc
@@ -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);
diff --git a/src/arch/arm/predecoder.cc b/src/arch/arm/predecoder.cc
index 04cec59b9..456b9e4c4 100644
--- a/src/arch/arm/predecoder.cc
+++ b/src/arch/arm/predecoder.cc
@@ -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;
diff --git a/src/arch/arm/predecoder.hh b/src/arch/arm/predecoder.hh
index 2db550024..47242b8ff 100644
--- a/src/arch/arm/predecoder.hh
+++ b/src/arch/arm/predecoder.hh
@@ -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;
}
diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc
index bc2aee4c8..a5460ac19 100644
--- a/src/arch/arm/process.cc
+++ b/src/arch/arm/process.cc
@@ -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);
diff --git a/src/arch/arm/system.hh b/src/arch/arm/system.hh
index fe5ba6447..c64673df5 100644
--- a/src/arch/arm/system.hh
+++ b/src/arch/arm/system.hh
@@ -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;
}
};
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index 73dd24e1c..06bb10219 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -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);
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index c0ebb52b2..239d5d8a2 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -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();
diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh
index 3c3b29494..57f34e3c2 100644
--- a/src/arch/arm/types.hh
+++ b/src/arch/arm/types.hh
@@ -43,8 +43,10 @@
#ifndef __ARCH_ARM_TYPES_HH__
#define __ARCH_ARM_TYPES_HH__
+#include "arch/generic/types.hh"
#include "base/bitunion.hh"
#include "base/hashmap.hh"
+#include "base/misc.hh"
#include "base/types.hh"
namespace ArmISA
@@ -188,6 +190,189 @@ namespace ArmISA
Bitfield<11, 8> ltcoproc;
EndBitUnion(ExtMachInst)
+ class PCState : public GenericISA::UPCState<MachInst>
+ {
+ protected:
+
+ typedef GenericISA::UPCState<MachInst> Base;
+
+ enum FlagBits {
+ ThumbBit = (1 << 0),
+ JazelleBit = (1 << 1)
+ };
+ uint8_t flags;
+ uint8_t nextFlags;
+
+ public:
+ PCState() : flags(0), nextFlags(0)
+ {}
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ npc(val + (thumb() ? 2 : 4));
+ }
+
+ PCState(Addr val) : flags(0), nextFlags(0)
+ { set(val); }
+
+ bool
+ thumb() const
+ {
+ return flags & ThumbBit;
+ }
+
+ void
+ thumb(bool val)
+ {
+ if (val)
+ flags |= ThumbBit;
+ else
+ flags &= ~ThumbBit;
+ }
+
+ bool
+ nextThumb() const
+ {
+ return nextFlags & ThumbBit;
+ }
+
+ void
+ nextThumb(bool val)
+ {
+ if (val)
+ nextFlags |= ThumbBit;
+ else
+ nextFlags &= ~ThumbBit;
+ }
+
+ bool
+ jazelle() const
+ {
+ return flags & JazelleBit;
+ }
+
+ void
+ jazelle(bool val)
+ {
+ if (val)
+ flags |= JazelleBit;
+ else
+ flags &= ~JazelleBit;
+ }
+
+ bool
+ nextJazelle() const
+ {
+ return nextFlags & JazelleBit;
+ }
+
+ void
+ nextJazelle(bool val)
+ {
+ if (val)
+ nextFlags |= JazelleBit;
+ else
+ nextFlags &= ~JazelleBit;
+ }
+
+ void
+ advance()
+ {
+ Base::advance();
+ npc(pc() + (thumb() ? 2 : 4));
+ flags = nextFlags;
+ }
+
+ void
+ uEnd()
+ {
+ advance();
+ upc(0);
+ nupc(1);
+ }
+
+ Addr
+ instPC() const
+ {
+ return pc() + (thumb() ? 4 : 8);
+ }
+
+ void
+ instNPC(uint32_t val)
+ {
+ npc(val &~ mask(nextThumb() ? 1 : 2));
+ }
+
+ Addr
+ instNPC() const
+ {
+ return npc();
+ }
+
+ // Perform an interworking branch.
+ void
+ instIWNPC(uint32_t val)
+ {
+ bool thumbEE = (thumb() && jazelle());
+
+ Addr newPC = val;
+ if (thumbEE) {
+ if (bits(newPC, 0)) {
+ newPC = newPC & ~mask(1);
+ } else {
+ panic("Bad thumbEE interworking branch address %#x.\n",
+ newPC);
+ }
+ } else {
+ if (bits(newPC, 0)) {
+ nextThumb(true);
+ newPC = newPC & ~mask(1);
+ } else if (!bits(newPC, 1)) {
+ nextThumb(false);
+ } else {
+ warn("Bad interworking branch address %#x.\n", newPC);
+ }
+ }
+ npc(newPC);
+ }
+
+ // Perform an interworking branch in ARM mode, a regular branch
+ // otherwise.
+ void
+ instAIWNPC(uint32_t val)
+ {
+ if (!thumb() && !jazelle())
+ instIWNPC(val);
+ else
+ instNPC(val);
+ }
+
+ bool
+ operator == (const PCState &opc) const
+ {
+ return Base::operator == (opc) &&
+ flags == opc.flags && nextFlags == opc.nextFlags;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(flags);
+ SERIALIZE_SCALAR(nextFlags);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(flags);
+ UNSERIALIZE_SCALAR(nextFlags);
+ }
+ };
+
// Shift types for ARM instructions
enum ArmShiftType {
LSL = 0,
diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc
index 7609b3991..a114ec5e0 100644
--- a/src/arch/arm/utility.cc
+++ b/src/arch/arm/utility.cc
@@ -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);
}
diff --git a/src/arch/arm/utility.hh b/src/arch/arm/utility.hh
index 571a74ef8..a92ab072c 100644
--- a/src/arch/arm/utility.hh
+++ b/src/arch/arm/utility.hh
@@ -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);
+}
+
};
diff --git a/src/arch/generic/types.hh b/src/arch/generic/types.hh
new file mode 100644
index 000000000..214b01926
--- /dev/null
+++ b/src/arch/generic/types.hh
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2010 Gabe Black
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_GENERIC_TYPES_HH__
+#define __ARCH_GENERIC_TYPES_HH__
+
+#include <iostream>
+
+#include "base/types.hh"
+#include "base/trace.hh"
+#include "sim/serialize.hh"
+
+namespace GenericISA
+{
+
+// The guaranteed interface.
+class PCStateBase
+{
+ protected:
+ Addr _pc;
+ Addr _npc;
+
+ PCStateBase() {}
+ PCStateBase(Addr val) { set(val); }
+
+ public:
+ /**
+ * Returns the memory address the bytes of this instruction came from.
+ *
+ * @return Memory address of the current instruction's encoding.
+ */
+ Addr
+ instAddr() const
+ {
+ return _pc;
+ }
+
+ /**
+ * Returns the memory address the bytes of the next instruction came from.
+ *
+ * @return Memory address of the next instruction's encoding.
+ */
+ Addr
+ nextInstAddr() const
+ {
+ return _npc;
+ }
+
+ /**
+ * Returns the current micropc.
+ *
+ * @return The current micropc.
+ */
+ MicroPC
+ microPC() const
+ {
+ return 0;
+ }
+
+ /**
+ * Force this PC to reflect a particular value, resetting all its other
+ * fields around it. This is useful for in place (re)initialization.
+ *
+ * @param val The value to set the PC to.
+ */
+ void set(Addr val);
+
+ bool
+ operator == (const PCStateBase &opc) const
+ {
+ return _pc == opc._pc && _npc == opc._npc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ SERIALIZE_SCALAR(_pc);
+ SERIALIZE_SCALAR(_npc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
+ {
+ UNSERIALIZE_SCALAR(_pc);
+ UNSERIALIZE_SCALAR(_npc);
+ }
+};
+
+
+/*
+ * Different flavors of PC state. Only ISA specific code should rely on
+ * any particular type of PC state being available. All other code should
+ * use the interface above.
+ */
+
+// The most basic type of PC.
+template <class MachInst>
+class SimplePCState : public PCStateBase
+{
+ protected:
+ typedef PCStateBase Base;
+
+ public:
+
+ Addr pc() const { return _pc; }
+ void pc(Addr val) { _pc = val; }
+
+ Addr npc() const { return _npc; }
+ void npc(Addr val) { _npc = val; }
+
+ void
+ set(Addr val)
+ {
+ pc(val);
+ npc(val + sizeof(MachInst));
+ };
+
+ SimplePCState() {}
+ SimplePCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return this->npc() != this->pc() + sizeof(MachInst);
+ }
+
+ // Advance the PC.
+ void
+ advance()
+ {
+ _pc = _npc;
+ _npc += sizeof(MachInst);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const SimplePCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x)", pc.pc(), pc.npc());
+ return os;
+}
+
+// A PC and microcode PC.
+template <class MachInst>
+class UPCState : public SimplePCState<MachInst>
+{
+ protected:
+ typedef SimplePCState<MachInst> Base;
+
+ MicroPC _upc;
+ MicroPC _nupc;
+
+ public:
+
+ MicroPC upc() const { return _upc; }
+ void upc(MicroPC val) { _upc = val; }
+
+ MicroPC nupc() const { return _nupc; }
+ void nupc(MicroPC val) { _nupc = val; }
+
+ MicroPC
+ microPC() const
+ {
+ return _upc;
+ }
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ upc(0);
+ nupc(1);
+ }
+
+ UPCState() {}
+ UPCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return this->npc() != this->pc() + sizeof(MachInst) ||
+ this->nupc() != this->upc() + 1;
+ }
+
+ // Advance the upc within the instruction.
+ void
+ uAdvance()
+ {
+ _upc = _nupc;
+ _nupc++;
+ }
+
+ // End the macroop by resetting the upc and advancing the regular pc.
+ void
+ uEnd()
+ {
+ this->advance();
+ _upc = 0;
+ _nupc = 1;
+ }
+
+ bool
+ operator == (const UPCState<MachInst> &opc) const
+ {
+ return Base::_pc == opc._pc &&
+ Base::_npc == opc._npc &&
+ _upc == opc._upc && _nupc == opc._nupc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(_upc);
+ SERIALIZE_SCALAR(_nupc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(_upc);
+ UNSERIALIZE_SCALAR(_nupc);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const UPCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x).(%d=>%d)",
+ pc.pc(), pc.npc(), pc.upc(), pc.npc());
+ return os;
+}
+
+// A PC with a delay slot.
+template <class MachInst>
+class DelaySlotPCState : public SimplePCState<MachInst>
+{
+ protected:
+ typedef SimplePCState<MachInst> Base;
+
+ Addr _nnpc;
+
+ public:
+
+ Addr nnpc() const { return _nnpc; }
+ void nnpc(Addr val) { _nnpc = val; }
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ nnpc(val + 2 * sizeof(MachInst));
+ }
+
+ DelaySlotPCState() {}
+ DelaySlotPCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return !(this->nnpc() == this->npc() + sizeof(MachInst) &&
+ (this->npc() == this->pc() + sizeof(MachInst) ||
+ this->npc() == this->pc() + 2 * sizeof(MachInst)));
+ }
+
+ // Advance the PC.
+ void
+ advance()
+ {
+ Base::_pc = Base::_npc;
+ Base::_npc = _nnpc;
+ _nnpc += sizeof(MachInst);
+ }
+
+ bool
+ operator == (const DelaySlotPCState<MachInst> &opc) const
+ {
+ return Base::_pc == opc._pc &&
+ Base::_npc == opc._npc &&
+ _nnpc == opc._nnpc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(_nnpc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(_nnpc);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const DelaySlotPCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x=>%#x)",
+ pc.pc(), pc.npc(), pc.nnpc());
+ return os;
+}
+
+// A PC with a delay slot and a microcode PC.
+template <class MachInst>
+class DelaySlotUPCState : public DelaySlotPCState<MachInst>
+{
+ protected:
+ typedef DelaySlotPCState<MachInst> Base;
+
+ MicroPC _upc;
+ MicroPC _nupc;
+
+ public:
+
+ MicroPC upc() const { return _upc; }
+ void upc(MicroPC val) { _upc = val; }
+
+ MicroPC nupc() const { return _nupc; }
+ void nupc(MicroPC val) { _nupc = val; }
+
+ MicroPC
+ microPC() const
+ {
+ return _upc;
+ }
+
+ void
+ set(Addr val)
+ {
+ Base::set(val);
+ upc(0);
+ nupc(1);
+ }
+
+ DelaySlotUPCState() {}
+ DelaySlotUPCState(Addr val) { set(val); }
+
+ bool
+ branching() const
+ {
+ return Base::branching() || this->nupc() != this->upc() + 1;
+ }
+
+ // Advance the upc within the instruction.
+ void
+ uAdvance()
+ {
+ _upc = _nupc;
+ _nupc++;
+ }
+
+ // End the macroop by resetting the upc and advancing the regular pc.
+ void
+ uEnd()
+ {
+ this->advance();
+ _upc = 0;
+ _nupc = 1;
+ }
+
+ bool
+ operator == (const DelaySlotUPCState<MachInst> &opc) const
+ {
+ return Base::_pc == opc._pc &&
+ Base::_npc == opc._npc &&
+ Base::_nnpc == opc._nnpc &&
+ _upc == opc._upc && _nupc == opc._nupc;
+ }
+
+ void
+ serialize(std::ostream &os)
+ {
+ Base::serialize(os);
+ SERIALIZE_SCALAR(_upc);
+ SERIALIZE_SCALAR(_nupc);
+ }
+
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
+ {
+ Base::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(_upc);
+ UNSERIALIZE_SCALAR(_nupc);
+ }
+};
+
+template <class MachInst>
+std::ostream &
+operator<<(std::ostream & os, const DelaySlotUPCState<MachInst> &pc)
+{
+ ccprintf(os, "(%#x=>%#x=>%#x).(%d=>%d)",
+ pc.pc(), pc.npc(), pc.nnpc(), pc.upc(), pc.nupc());
+ return os;
+}
+
+}
+
+#endif
diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py
index 4e06c2ded..8e13b6a6a 100755
--- a/src/arch/isa_parser.py
+++ b/src/arch/isa_parser.py
@@ -681,71 +681,43 @@ class MemOperand(Operand):
def makeAccSize(self):
return self.size
-class PCOperand(Operand):
+class PCStateOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
- return '%s = xc->readPC();\n' % self.base_name
+ return '%s = xc->pcState();\n' % self.base_name
def makeWrite(self):
- return 'xc->setPC(%s);\n' % self.base_name
+ return 'xc->pcState(%s);\n' % self.base_name
-class UPCOperand(Operand):
- def makeConstructor(self):
- return ''
-
- def makeRead(self):
- if self.read_code != None:
- return self.buildReadCode('readMicroPC')
- return '%s = xc->readMicroPC();\n' % self.base_name
-
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setMicroPC')
- return 'xc->setMicroPC(%s);\n' % self.base_name
+ def makeDecl(self):
+ return 'TheISA::PCState ' + self.base_name + ' M5_VAR_USED;\n';
-class NUPCOperand(Operand):
+class PCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
- if self.read_code != None:
- return self.buildReadCode('readNextMicroPC')
- return '%s = xc->readNextMicroPC();\n' % self.base_name
+ return '%s = xc->instAddr();\n' % self.base_name
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setNextMicroPC')
- return 'xc->setNextMicroPC(%s);\n' % self.base_name
-
-class NPCOperand(Operand):
+class UPCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
if self.read_code != None:
- return self.buildReadCode('readNextPC')
- return '%s = xc->readNextPC();\n' % self.base_name
-
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setNextPC')
- return 'xc->setNextPC(%s);\n' % self.base_name
+ return self.buildReadCode('microPC')
+ return '%s = xc->microPC();\n' % self.base_name
-class NNPCOperand(Operand):
+class NPCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
if self.read_code != None:
- return self.buildReadCode('readNextNPC')
- return '%s = xc->readNextNPC();\n' % self.base_name
-
- def makeWrite(self):
- if self.write_code != None:
- return self.buildWriteCode('setNextNPC')
- return 'xc->setNextNPC(%s);\n' % self.base_name
+ return self.buildReadCode('nextInstAddr')
+ return '%s = xc->nextInstAddr();\n' % self.base_name
class OperandList(object):
'''Find all the operands in the given code block. Returns an operand
diff --git a/src/arch/mips/isa/base.isa b/src/arch/mips/isa/base.isa
index 4e2b12fc4..cd6faf0f3 100644
--- a/src/arch/mips/isa/base.isa
+++ b/src/arch/mips/isa/base.isa
@@ -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();
+ }
};
}};
diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa
index 9832937b5..3f3bd370a 100644
--- a/src/arch/mips/isa/decoder.isa
+++ b/src/arch/mips/isa/decoder.isa
@@ -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);
}
diff --git a/src/arch/mips/isa/formats/branch.isa b/src/arch/mips/isa/formats/branch.isa
index 78f973a70..232a743a7 100644
--- a/src/arch/mips/isa/formats/branch.isa
+++ b/src/arch/mips/isa/formats/branch.isa
@@ -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)
diff --git a/src/arch/mips/isa/includes.isa b/src/arch/mips/isa/includes.isa
index 22eb3bf13..d5e1448ac 100644
--- a/src/arch/mips/isa/includes.isa
+++ b/src/arch/mips/isa/includes.isa
@@ -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"
}};
diff --git a/src/arch/mips/isa/operands.isa b/src/arch/mips/isa/operands.isa
index 27cb4357a..1bb5ae5b3 100644
--- a/src/arch/mips/isa/operands.isa
+++ b/src/arch/mips/isa/operands.isa
@@ -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)
}};
diff --git a/src/arch/mips/mt.hh b/src/arch/mips/mt.hh
index 7217c335e..3ec6cbe70 100755
--- a/src/arch/mips/mt.hh
+++ b/src/arch/mips/mt.hh
@@ -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);
}
}
diff --git a/src/arch/mips/predecoder.hh b/src/arch/mips/predecoder.hh
index c20fe1f5f..f059710e5 100644
--- a/src/arch/mips/predecoder.hh
+++ b/src/arch/mips/predecoder.hh
@@ -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;
}
diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc
index fa3e3bff9..26a2a0ddb 100644
--- a/src/arch/mips/process.cc
+++ b/src/arch/mips/process.cc
@@ -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());
}
diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh
index c7ef6afe1..f21db51b1 100644
--- a/src/arch/mips/types.hh
+++ b/src/arch/mips/types.hh
@@ -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
diff --git a/src/arch/mips/utility.cc b/src/arch/mips/utility.cc
index faae1e937..0859eb80f 100644
--- a/src/arch/mips/utility.cc
+++ b/src/arch/mips/utility.cc
@@ -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);
}
diff --git a/src/arch/mips/utility.hh b/src/arch/mips/utility.hh
index bc50027c0..2f6726c59 100644
--- a/src/arch/mips/utility.hh
+++ b/src/arch/mips/utility.hh
@@ -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();
+}
+
};
diff --git a/src/arch/power/insts/branch.cc b/src/arch/power/insts/branch.cc
index c10f7c996..352c4ea57 100644
--- a/src/arch/power/insts/branch.cc
+++ b/src/arch/power/insts/branch.cc
@@ -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
diff --git a/src/arch/power/insts/branch.hh b/src/arch/power/insts/branch.hh
index dd00e42c3..7b9e78dee 100644
--- a/src/arch/power/insts/branch.hh
+++ b/src/arch/power/insts/branch.hh
@@ -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;
};
diff --git a/src/arch/power/insts/static_inst.hh b/src/arch/power/insts/static_inst.hh
index 399e75371..91eca6fb0 100644
--- a/src/arch/power/insts/static_inst.hh
+++ b/src/arch/power/insts/static_inst.hh
@@ -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
diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa
index 3252ff14a..671f57389 100644
--- a/src/arch/power/isa/decoder.isa
+++ b/src/arch/power/isa/decoder.isa
@@ -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.
diff --git a/src/arch/power/isa/formats/branch.isa b/src/arch/power/isa/formats/branch.isa
index d51ed5c25..da1579ea8 100644
--- a/src/arch/power/isa/formats/branch.isa
+++ b/src/arch/power/isa/formats/branch.isa
@@ -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
diff --git a/src/arch/power/isa/formats/unknown.isa b/src/arch/power/isa/formats/unknown.isa
index 06e6ece26..8914cf9a6 100644
--- a/src/arch/power/isa/formats/unknown.isa
+++ b/src/arch/power/isa/formats/unknown.isa
@@ -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;
}
}};
diff --git a/src/arch/power/isa/operands.isa b/src/arch/power/isa/operands.isa
index fc6c32685..908e6e0e7 100644
--- a/src/arch/power/isa/operands.isa
+++ b/src/arch/power/isa/operands.isa
@@ -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),
diff --git a/src/arch/power/predecoder.hh b/src/arch/power/predecoder.hh
index 1f3ac41cb..b1f2b6e38 100644
--- a/src/arch/power/predecoder.hh
+++ b/src/arch/power/predecoder.hh
@@ -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;
}
diff --git a/src/arch/power/process.cc b/src/arch/power/process.cc
index 9fb69b9f8..a34a874bc 100644
--- a/src/arch/power/process.cc
+++ b/src/arch/power/process.cc
@@ -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);
diff --git a/src/arch/power/types.hh b/src/arch/power/types.hh
index 6a8d1e9d3..d049cdec1 100644
--- a/src/arch/power/types.hh
+++ b/src/arch/power/types.hh
@@ -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
diff --git a/src/arch/power/utility.cc b/src/arch/power/utility.cc
index d48d4870a..399ec1f56 100644
--- a/src/arch/power/utility.cc
+++ b/src/arch/power/utility.cc
@@ -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
diff --git a/src/arch/power/utility.hh b/src/arch/power/utility.hh
index c8cd441ba..a47fcdc46 100644
--- a/src/arch/power/utility.hh
+++ b/src/arch/power/utility.hh
@@ -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__
diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
index df0a283b9..28ee64321 100644
--- a/src/arch/sparc/faults.cc
+++ b/src/arch/sparc/faults.cc
@@ -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
diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa
index ce063bcdc..c6055b3a3 100644
--- a/src/arch/sparc/isa/base.isa
+++ b/src/arch/sparc/isa/base.isa
@@ -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);
@@ -261,6 +263,12 @@ output decoder {{
}
void
+ SparcStaticInst::advancePC(SparcISA::PCState &pcState) const
+ {
+ pcState.advance();
+ }
+
+ void
SparcStaticInst::printSrcReg(std::ostream &os, int reg) const
{
if(_numSrcRegs > reg)
diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa
index b9b38b569..80b29398c 100644
--- a/src/arch/sparc/isa/decoder.isa
+++ b/src/arch/sparc/isa/decoder.isa
@@ -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);
}
diff --git a/src/arch/sparc/isa/formats/branch.isa b/src/arch/sparc/isa/formats/branch.isa
index faaee8842..e62e0035a 100644
--- a/src/arch/sparc/isa/formats/branch.isa
+++ b/src/arch/sparc/isa/formats/branch.isa
@@ -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:
diff --git a/src/arch/sparc/isa/formats/micro.isa b/src/arch/sparc/isa/formats/micro.isa
index c1d0c4f36..b5a53a68b 100644
--- a/src/arch/sparc/isa/formats/micro.isa
+++ b/src/arch/sparc/isa/formats/micro.isa
@@ -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
diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa
index a627a2e6f..8bf6450be 100644
--- a/src/arch/sparc/isa/operands.isa
+++ b/src/arch/sparc/isa/operands.isa
@@ -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),
diff --git a/src/arch/sparc/nativetrace.cc b/src/arch/sparc/nativetrace.cc
index 8a1eb7a58..9bccaaf7d 100644
--- a/src/arch/sparc/nativetrace.cc
+++ b/src/arch/sparc/nativetrace.cc
@@ -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
diff --git a/src/arch/sparc/predecoder.hh b/src/arch/sparc/predecoder.hh
index c4ab4fe79..8a2587929 100644
--- a/src/arch/sparc/predecoder.hh
+++ b/src/arch/sparc/predecoder.hh
@@ -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;
}
diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
index 0cd8889a9..a6e21977a 100644
--- a/src/arch/sparc/process.cc
+++ b/src/arch/sparc/process.cc
@@ -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);
diff --git a/src/arch/sparc/remote_gdb.cc b/src/arch/sparc/remote_gdb.cc
index 4eea0c077..aea40ea22 100644
--- a/src/arch/sparc/remote_gdb.cc
+++ b/src/arch/sparc/remote_gdb.cc
@@ -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);
}
diff --git a/src/arch/sparc/types.hh b/src/arch/sparc/types.hh
index 70558ec6d..122fd808f 100644
--- a/src/arch/sparc/types.hh
+++ b/src/arch/sparc/types.hh
@@ -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 {
diff --git a/src/arch/sparc/utility.cc b/src/arch/sparc/utility.cc
index be4dfac84..6de44d8a3 100644
--- a/src/arch/sparc/utility.cc
+++ b/src/arch/sparc/utility.cc
@@ -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);
}
diff --git a/src/arch/sparc/utility.hh b/src/arch/sparc/utility.hh
index f6a585e23..0d5a4bb93 100644
--- a/src/arch/sparc/utility.hh
+++ b/src/arch/sparc/utility.hh
@@ -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
diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc
index 4f2d97f90..7fb677c69 100644
--- a/src/arch/x86/faults.cc
+++ b/src/arch/x86/faults.cc
@@ -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
diff --git a/src/arch/x86/insts/macroop.hh b/src/arch/x86/insts/macroop.hh
index 7ead7bdc2..fcf051a37 100644
--- a/src/arch/x86/insts/macroop.hh
+++ b/src/arch/x86/insts/macroop.hh
@@ -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];
diff --git a/src/arch/x86/insts/microop.hh b/src/arch/x86/insts/microop.hh
index 9b0497efc..6fc215452 100644
--- a/src/arch/x86/insts/microop.hh
+++ b/src/arch/x86/insts/microop.hh
@@ -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();
+ }
};
}
diff --git a/src/arch/x86/insts/static_inst.hh b/src/arch/x86/insts/static_inst.hh
index 2df5df092..8813f216c 100644
--- a/src/arch/x86/insts/static_inst.hh
+++ b/src/arch/x86/insts/static_inst.hh
@@ -158,6 +158,12 @@ namespace X86ISA
panic("Tried to pick with unrecognized size %d.\n", size);
}
}
+
+ void
+ advancePC(PCState &pcState) const
+ {
+ pcState.advance();
+ }
};
}
diff --git a/src/arch/x86/isa/decoder/two_byte_opcodes.isa b/src/arch/x86/isa/decoder/two_byte_opcodes.isa
index de167d1c1..def9b7f9d 100644
--- a/src/arch/x86/isa/decoder/two_byte_opcodes.isa
+++ b/src/arch/x86/isa/decoder/two_byte_opcodes.isa
@@ -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");
diff --git a/src/arch/x86/isa/formats/unknown.isa b/src/arch/x86/isa/formats/unknown.isa
index 11751e861..1108fd4a4 100644
--- a/src/arch/x86/isa/formats/unknown.isa
+++ b/src/arch/x86/isa/formats/unknown.isa
@@ -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)
{
}
diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa
index 9ccea82dd..86ebac174 100644
--- a/src/arch/x86/isa/microops/regop.isa
+++ b/src/arch/x86/isa/microops/regop.isa
@@ -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'
diff --git a/src/arch/x86/isa/microops/seqop.isa b/src/arch/x86/isa/microops/seqop.isa
index 57c44d48c..a3e22b0aa 100644
--- a/src/arch/x86/isa/microops/seqop.isa
+++ b/src/arch/x86/isa/microops/seqop.isa
@@ -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)
diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa
index d4140e414..25b73a8f2 100644
--- a/src/arch/x86/isa/operands.isa
+++ b/src/arch/x86/isa/operands.isa
@@ -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),
diff --git a/src/arch/x86/nativetrace.cc b/src/arch/x86/nativetrace.cc
index c5c891be9..6f92cfacf 100644
--- a/src/arch/x86/nativetrace.cc
+++ b/src/arch/x86/nativetrace.cc
@@ -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));
diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh
index 5b38402e0..c06ec18bc 100644
--- a/src/arch/x86/predecoder.hh
+++ b/src/arch/x86/predecoder.hh
@@ -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;
- }
};
};
diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc
index 946a7cbe1..bb875686e 100644
--- a/src/arch/x86/process.cc
+++ b/src/arch/x86/process.cc
@@ -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);
diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc
index ae47b14fd..3fc16e729 100644
--- a/src/arch/x86/system.cc
+++ b/src/arch/x86/system.cc
@@ -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!
diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc
index 71e0b3adb..dbba52af0 100644
--- a/src/arch/x86/tlb.cc
+++ b/src/arch/x86/tlb.cc
@@ -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;
diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh
index 2a0da7d65..5a208446a 100644
--- a/src/arch/x86/types.hh
+++ b/src/arch/x86/types.hh
@@ -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;
};
diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc
index 624e8132f..88d5bfe58 100644
--- a/src/arch/x86/utility.cc
+++ b/src/arch/x86/utility.cc
@@ -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
diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh
index 05ce53347..143fde00c 100644
--- a/src/arch/x86/utility.hh
+++ b/src/arch/x86/utility.hh
@@ -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__