ARM: Fix RFE macrop.

This changes the RFE macroop into 3 microops:

URa = [sp]; URb = [sp+4]; // load CPSR,PC values from stack
sp = sp + offset;         // optionally auto-increment
PC = URa; CPSR = URb;     // write to the PC and CPSR.

Importantly:
- writing to PC is handled in the last micro-op.
- loading occurs prior to state changes.
This commit is contained in:
Matt Horsnell 2011-03-17 19:20:19 -05:00
parent e65f480d62
commit 031f396c71
9 changed files with 146 additions and 34 deletions

View file

@ -895,6 +895,15 @@ MicroIntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
return ss.str();
}
std::string
MicroSetPCCPSR::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
printMnemonic(ss);
ss << "[PC,CPSR]";
return ss.str();
}
std::string
MicroIntMov::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{

View file

@ -134,6 +134,27 @@ class MicroNeonMixLaneOp : public MicroNeonMixOp
{
}
};
/**
* Microops of the form
* PC = IntRegA
* CPSR = IntRegB
*/
class MicroSetPCCPSR : public MicroOp
{
protected:
IntRegIndex ura, urb, urc;
MicroSetPCCPSR(const char *mnem, ExtMachInst machInst, OpClass __opClass,
IntRegIndex _ura, IntRegIndex _urb, IntRegIndex _urc)
: MicroOp(mnem, machInst, __opClass),
ura(_ura), urb(_urb), urc(_urc)
{
}
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
/**
* Microops of the form IntRegA = IntRegB
*/

View file

@ -97,14 +97,18 @@ class RfeOp : public MightBeMicro
IntRegIndex base;
AddrMode mode;
bool wb;
static const unsigned numMicroops = 2;
IntRegIndex ura, urb, urc;
static const unsigned numMicroops = 3;
StaticInstPtr *uops;
RfeOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
IntRegIndex _base, AddrMode _mode, bool _wb)
: MightBeMicro(mnem, _machInst, __opClass),
base(_base), mode(_mode), wb(_wb), uops(NULL)
base(_base), mode(_mode), wb(_wb),
ura(INTREG_UREG0), urb(INTREG_UREG1),
urc(INTREG_UREG2),
uops(NULL)
{}
virtual

View file

@ -110,6 +110,8 @@ enum IntRegIndex
INTREG_ZERO, // Dummy zero reg since there has to be one.
INTREG_UREG0,
INTREG_UREG1,
INTREG_UREG2,
INTREG_CONDCODES,
INTREG_FPCONDCODES,

View file

@ -67,7 +67,7 @@ let {{
self.memFlags = ["ArmISA::TLB::MustBeOne"]
self.codeBlobs = {"postacc_code" : ""}
def emitHelper(self, base = 'Memory', wbDecl = None, instFlags = []):
def emitHelper(self, base = 'Memory', wbDecl = None, instFlags = [], pcDecl = None):
global header_output, decoder_output, exec_output
@ -76,7 +76,8 @@ let {{
(newHeader,
newDecoder,
newExec) = self.fillTemplates(self.name, self.Name, codeBlobs,
self.memFlags, instFlags, base, wbDecl)
self.memFlags, instFlags, base,
wbDecl, pcDecl)
header_output += newHeader
decoder_output += newDecoder
@ -104,26 +105,18 @@ let {{
wbDiff = 8
accCode = '''
CPSR cpsr = Cpsr;
SCTLR sctlr = Sctlr;
// Use the version of NPC that gets set before NextThumb
pNPC = cSwap<uint32_t>(Mem.ud, cpsr.e);
uint32_t tempSpsr = cSwap<uint32_t>(Mem.ud >> 32, cpsr.e);
uint32_t newCpsr =
cpsrWriteByInstr(cpsr | CondCodes, tempSpsr,
0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
NextThumb = ((CPSR)newCpsr).t;
NextJazelle = ((CPSR)newCpsr).j;
ForcedItState = ((((CPSR)tempSpsr).it2 << 2) & 0xFC)
| (((CPSR)tempSpsr).it1 & 0x3);
CondCodes = CondCodesMask & newCpsr;
URc = cpsr | CondCodes;
URa = cSwap<uint32_t>(Mem.ud, cpsr.e);
URb = cSwap<uint32_t>(Mem.ud >> 32, cpsr.e);
'''
self.codeBlobs["memacc_code"] = accCode
wbDecl = None
pcDecl = "MicroUopSetPCCPSR(machInst, INTREG_UREG0, INTREG_UREG1, INTREG_UREG2);"
if self.writeback:
wbDecl = "MicroAddiUop(machInst, base, base, %d);" % wbDiff
self.emitHelper('RfeOp', wbDecl, ["IsSerializeAfter", "IsNonSpeculative"])
self.emitHelper('RfeOp', wbDecl, ["IsSerializeAfter", "IsNonSpeculative"], pcDecl)
class LoadImmInst(LoadInst):
def __init__(self, *args, **kargs):

View file

@ -608,23 +608,48 @@ let {{
'predicate_test': predicateTest},
['IsMicroop'])
setPCCPSRDecl = '''
CPSR cpsrOrCondCodes = URc;
SCTLR sctlr = Sctlr;
pNPC = URa;
uint32_t newCpsr =
cpsrWriteByInstr(cpsrOrCondCodes, URb,
0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
NextThumb = ((CPSR)newCpsr).t;
NextJazelle = ((CPSR)newCpsr).j;
ForcedItState = ((((CPSR)URb).it2 << 2) & 0xFC)
| (((CPSR)URb).it1 & 0x3);
CondCodes = CondCodesMask & newCpsr;
'''
microUopSetPCCPSRIop = InstObjParams('uopSet_uop', 'MicroUopSetPCCPSR',
'MicroSetPCCPSR',
{'code': setPCCPSRDecl,
'predicate_test': predicateTest},
['IsMicroop'])
header_output = MicroIntImmDeclare.subst(microAddiUopIop) + \
MicroIntImmDeclare.subst(microSubiUopIop) + \
MicroIntRegDeclare.subst(microAddUopIop) + \
MicroIntRegDeclare.subst(microSubUopIop) + \
MicroIntMovDeclare.subst(microUopRegMovIop)
MicroIntMovDeclare.subst(microUopRegMovIop) + \
MicroSetPCCPSRDeclare.subst(microUopSetPCCPSRIop)
decoder_output = MicroIntImmConstructor.subst(microAddiUopIop) + \
MicroIntImmConstructor.subst(microSubiUopIop) + \
MicroIntRegConstructor.subst(microAddUopIop) + \
MicroIntRegConstructor.subst(microSubUopIop) + \
MicroIntMovConstructor.subst(microUopRegMovIop)
MicroIntMovConstructor.subst(microUopRegMovIop) + \
MicroSetPCCPSRConstructor.subst(microUopSetPCCPSRIop)
exec_output = PredOpExecute.subst(microAddiUopIop) + \
PredOpExecute.subst(microSubiUopIop) + \
PredOpExecute.subst(microAddUopIop) + \
PredOpExecute.subst(microSubUopIop) + \
PredOpExecute.subst(microUopRegMovIop)
PredOpExecute.subst(microUopRegMovIop) + \
PredOpExecute.subst(microUopSetPCCPSRIop)
}};
let {{

View file

@ -48,7 +48,7 @@ let {{
self.constructTemplate = eval(self.decConstBase + 'Constructor')
def fillTemplates(self, name, Name, codeBlobs, memFlags, instFlags,
base = 'Memory', wbDecl = None):
base = 'Memory', wbDecl = None, pcDecl = None):
# Make sure flags are in lists (convert to lists if not).
memFlags = makeList(memFlags)
instFlags = makeList(instFlags)
@ -65,12 +65,26 @@ let {{
macroName = Name
instFlagsCopy = list(instFlags)
codeBlobsCopy = dict(codeBlobs)
if wbDecl is not None:
use_uops = 0
if wbDecl is not None or pcDecl is not None:
instFlagsCopy.append('IsMicroop')
Name = Name + 'Acc'
use_uops = 1
use_wb = 0
use_pc = 0
if wbDecl is not None:
use_wb = 1
if pcDecl is not None:
use_pc = 1
codeBlobsCopy['acc_name'] = Name
codeBlobsCopy['wb_decl'] = wbDecl
codeBlobsCopy['pc_decl'] = pcDecl
codeBlobsCopy['use_uops'] = 0
codeBlobsCopy['use_wb'] = 0
codeBlobsCopy['use_pc'] = 0
iop = InstObjParams(name, Name, base,
codeBlobsCopy, instFlagsCopy)
@ -81,11 +95,14 @@ let {{
self.initiateAccTemplate.subst(iop) + \
self.completeAccTemplate.subst(iop)
if wbDecl is not None:
if wbDecl is not None or pcDecl is not None:
iop = InstObjParams(name, macroName, base,
{ "wb_decl" : wbDecl,
"pc_decl" : pcDecl,
"acc_name" : Name,
"use_uops" : 1 },
"use_uops" : use_uops,
"use_pc" : use_pc,
"use_wb" : use_wb },
['IsMacroop'])
header_output += self.declareTemplate.subst(iop)
decoder_output += self.constructTemplate.subst(iop)

View file

@ -107,6 +107,41 @@ def template MicroNeonMemDeclare {{
};
}};
////////////////////////////////////////////////////////////////////
//
// PC = Integer(ura)
// CPSR = Integer(urb)
//
def template MicroSetPCCPSRDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst,
IntRegIndex _ura,
IntRegIndex _urb,
IntRegIndex _urc);
%(BasicExecDeclare)s
};
}};
def template MicroSetPCCPSRConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst,
IntRegIndex _ura,
IntRegIndex _urb,
IntRegIndex _urc)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
_ura, _urb, _urc)
{
%(constructor)s;
if (!(condCode == COND_AL || condCode == COND_UC)) {
for (int x = 0; x < _numDestRegs; x++) {
_srcRegIdx[_numSrcRegs++] = _destRegIdx[x];
}
}
}
}};
////////////////////////////////////////////////////////////////////
//
// Integer = Integer op Integer microops

View file

@ -917,9 +917,9 @@ def template CompleteAccDeclare {{
def template RfeConstructor {{
inline %(class_name)s::%(class_name)s(ExtMachInst machInst,
uint32_t _base, int _mode, bool _wb)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
(IntRegIndex)_base, (AddrMode)_mode, _wb)
uint32_t _base, int _mode, bool _wb)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
(IntRegIndex)_base, (AddrMode)_mode, _wb)
{
%(constructor)s;
if (!(condCode == COND_AL || condCode == COND_UC)) {
@ -928,12 +928,18 @@ def template RfeConstructor {{
}
}
#if %(use_uops)d
assert(numMicroops >= 2);
uops = new StaticInstPtr[numMicroops];
uops[0] = new %(acc_name)s(machInst, _base, _mode, _wb);
uops[0]->setDelayedCommit();
uops[1] = new %(wb_decl)s;
uops[1]->setLastMicroop();
uops = new StaticInstPtr[1 + %(use_wb)d + %(use_pc)d];
int uopIdx = 0;
uops[uopIdx] = new %(acc_name)s(machInst, _base, _mode, _wb);
uops[uopIdx]->setDelayedCommit();
#if %(use_wb)d
uops[++uopIdx] = new %(wb_decl)s;
uops[uopIdx]->setDelayedCommit();
#endif
#if %(use_pc)d
uops[++uopIdx] = new %(pc_decl)s;
#endif
uops[uopIdx]->setLastMicroop();
#endif
}
}};