blob: aafab40f11ad74c9bfdfb80877e91dc1d30347c8 [file] [log] [blame]
// -*- mode:c++ -*-
// Copyright (c) 2011-2013, 2016-2020 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// 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.
let {{
header_output = ""
decoder_output = ""
exec_output = ""
def createCcCode64(carry, overflow):
code = ""
code += '''
uint16_t _iz, _in;
_in = bits(resTemp, intWidth - 1);
_iz = ((resTemp & mask(intWidth)) == 0);
CondCodesNZ = (_in << 1) | _iz;
DPRINTF(Arm, "(in, iz) = (%d, %d)\\n", _in, _iz);
'''
if overflow and overflow != "none":
code += '''
uint16_t _iv;
_iv = %s & 1;
CondCodesV = _iv;
DPRINTF(Arm, "(iv) = (%%d)\\n", _iv);
''' % overflow
if carry and carry != "none":
code += '''
uint16_t _ic;
_ic = %s & 1;
CondCodesC = _ic;
DPRINTF(Arm, "(ic) = (%%d)\\n", _ic);
''' % carry
return code
oldC = 'CondCodesC'
oldV = 'CondCodesV'
# Dicts of ways to set the carry flag.
carryCode64 = {
"none": "none",
"add": 'findCarry(intWidth, resTemp, Op164, secOp)',
"sub": 'findCarry(intWidth, resTemp, Op164, ~secOp)',
"logic": '0'
}
# Dict of ways to set the overflow flag.
overflowCode64 = {
"none": "none",
"add": 'findOverflow(intWidth, resTemp, Op164, secOp)',
"sub": 'findOverflow(intWidth, resTemp, Op164, ~secOp)',
"logic": '0'
}
immOp2 = "[[maybe_unused]] uint64_t secOp = imm;"
sRegOp2 = "[[maybe_unused]] uint64_t secOp = " + \
"shiftReg64(Op264, shiftAmt, shiftType, intWidth);"
eRegOp2 = "[[maybe_unused]] uint64_t secOp = " + \
"extendReg64(Op264, extendType, shiftAmt, intWidth);"
def buildDataWork(mnem, code, flagType, suffix, buildCc, buildNonCc,
base, templateBase):
code = '''
[[maybe_unused]] uint64_t resTemp = 0;
''' + code
ccCode = createCcCode64(carryCode64[flagType], overflowCode64[flagType])
Name = mnem.capitalize() + suffix
iop = ArmInstObjParams(mnem, Name, base, code)
iopCc = ArmInstObjParams(mnem + "s", Name + "Cc", base, code + ccCode)
def subst(iop):
global header_output, decoder_output, exec_output
header_output += eval(templateBase + "Declare").subst(iop)
decoder_output += eval(templateBase + "Constructor").subst(iop)
exec_output += BasicExecute.subst(iop)
if buildNonCc:
subst(iop)
if buildCc:
subst(iopCc)
def buildXImmDataInst(mnem, code, flagType = "logic", \
buildCc = True, buildNonCc = True, \
suffix = "XImm"):
buildDataWork(mnem, immOp2 + code, flagType, suffix,
buildCc, buildNonCc, "DataXImmOp", "DataXImm")
def buildXSRegDataInst(mnem, code, flagType = "logic", \
buildCc = True, buildNonCc = True, \
suffix = "XSReg"):
buildDataWork(mnem, sRegOp2 + code, flagType, suffix,
buildCc, buildNonCc, "DataXSRegOp", "DataXSReg")
def buildXERegDataInst(mnem, code, flagType = "logic", \
buildCc = True, buildNonCc = True, \
suffix = "XEReg"):
buildDataWork(mnem, eRegOp2 + code, flagType, suffix,
buildCc, buildNonCc, "DataXERegOp", "DataXEReg")
def buildDataInst(mnem, code, flagType = "logic",
buildCc = True, buildNonCc = True):
buildXImmDataInst(mnem, code, flagType, buildCc, buildNonCc)
buildXSRegDataInst(mnem, code, flagType, buildCc, buildNonCc)
buildXERegDataInst(mnem, code, flagType, buildCc, buildNonCc)
buildXImmDataInst("adr", "Dest64 = RawPC + imm", buildCc = False);
buildXImmDataInst("adrp", "Dest64 = (RawPC & ~mask(12)) + imm",
buildCc = False);
buildDataInst("and", "Dest64 = resTemp = Op164 & secOp;")
buildDataInst("eor", "Dest64 = Op164 ^ secOp;", buildCc = False)
buildXSRegDataInst("eon", "Dest64 = Op164 ^ ~secOp;", buildCc = False)
buildDataInst("sub", "Dest64 = resTemp = Op164 - secOp;", "sub")
buildDataInst("add", "Dest64 = resTemp = Op164 + secOp;", "add")
buildXSRegDataInst("adc",
"Dest64 = resTemp = Op164 + secOp + %s;" % oldC, "add")
buildXSRegDataInst("sbc",
"Dest64 = resTemp = Op164 - secOp - !%s;" % oldC, "sub")
buildDataInst("orr", "Dest64 = Op164 | secOp;", buildCc = False)
buildXSRegDataInst("orn", "Dest64 = Op164 | ~secOp;", buildCc = False)
buildXSRegDataInst("bic", "Dest64 = resTemp = Op164 & ~secOp;")
def buildDataXImmInst(mnem, code, optArgs = []):
global header_output, decoder_output, exec_output
classNamePrefix = mnem[0].upper() + mnem[1:]
templateBase = "DataXImm"
iop = ArmInstObjParams(mnem, classNamePrefix + "64",
templateBase + "Op", code, optArgs)
header_output += eval(templateBase + "Declare").subst(iop)
decoder_output += eval(templateBase + "Constructor").subst(iop)
exec_output += BasicExecute.subst(iop)
def buildDataXRegInst(mnem, regOps, code, optArgs = [],
overrideOpClass=None):
global header_output, decoder_output, exec_output
templateBase = "DataX%dReg" % regOps
classNamePrefix = mnem[0].upper() + mnem[1:]
if overrideOpClass:
iop = ArmInstObjParams(mnem, classNamePrefix + "64",
templateBase + "Op",
{ 'code': code,
'op_class': overrideOpClass },
optArgs)
else:
iop = ArmInstObjParams(mnem, classNamePrefix + "64",
templateBase + "Op", code, optArgs)
header_output += eval(templateBase + "Declare").subst(iop)
decoder_output += eval(templateBase + "Constructor").subst(iop)
exec_output += BasicExecute.subst(iop)
buildDataXRegInst("madd", 3, "Dest64 = Op164 + Op264 * Op364",
overrideOpClass="IntMultOp")
buildDataXRegInst("msub", 3, "Dest64 = Op164 - Op264 * Op364",
overrideOpClass="IntMultOp")
buildDataXRegInst("smaddl", 3,
"XDest = XOp1 + sext<32>(WOp2) * sext<32>(WOp3)",
overrideOpClass="IntMultOp")
buildDataXRegInst("smsubl", 3,
"XDest = XOp1 - sext<32>(WOp2) * sext<32>(WOp3)",
overrideOpClass="IntMultOp")
buildDataXRegInst("smulh", 2, '''
uint64_t op1H = (int32_t)(XOp1 >> 32);
uint64_t op1L = (uint32_t)XOp1;
uint64_t op2H = (int32_t)(XOp2 >> 32);
uint64_t op2L = (uint32_t)XOp2;
uint64_t mid1 = ((op1L * op2L) >> 32) + op1H * op2L;
uint64_t mid2 = op1L * op2H;
uint64_t result = ((uint64_t)(uint32_t)mid1 + (uint32_t)mid2) >> 32;
result += shiftReg64(mid1, 32, ASR, intWidth);
result += shiftReg64(mid2, 32, ASR, intWidth);
XDest = result + op1H * op2H;
''', overrideOpClass="IntMultOp")
buildDataXRegInst("umaddl", 3, "XDest = XOp1 + WOp2 * WOp3",
overrideOpClass="IntMultOp")
buildDataXRegInst("umsubl", 3, "XDest = XOp1 - WOp2 * WOp3",
overrideOpClass="IntMultOp")
buildDataXRegInst("umulh", 2, '''
uint64_t op1H = (uint32_t)(XOp1 >> 32);
uint64_t op1L = (uint32_t)XOp1;
uint64_t op2H = (uint32_t)(XOp2 >> 32);
uint64_t op2L = (uint32_t)XOp2;
uint64_t mid1 = ((op1L * op2L) >> 32) + op1H * op2L;
uint64_t mid2 = op1L * op2H;
uint64_t result = ((uint64_t)(uint32_t)mid1 + (uint32_t)mid2) >> 32;
result += mid1 >> 32;
result += mid2 >> 32;
XDest = result + op1H * op2H;
''', overrideOpClass="IntMultOp")
buildDataXRegInst("asrv", 2,
"Dest64 = shiftReg64(Op164, Op264, ASR, intWidth)")
buildDataXRegInst("lslv", 2,
"Dest64 = shiftReg64(Op164, Op264, LSL, intWidth)")
buildDataXRegInst("lsrv", 2,
"Dest64 = shiftReg64(Op164, Op264, LSR, intWidth)")
buildDataXRegInst("rorv", 2,
"Dest64 = shiftReg64(Op164, Op264, ROR, intWidth)")
crcCode = '''
constexpr uint8_t size_bytes = %(sz)d;
constexpr uint32_t poly = %(polynom)s;
// Initial value is often a previously evaluated
// crc value hence is always 32bit in CRC32
uint32_t initial_crc = Op164 & 0xFFFFFFFF;
uint64_t data = htole(Op264);
auto data_buffer = reinterpret_cast<uint8_t*>(&data);
Dest = crc32<poly>(
data_buffer, /* Message register */
initial_crc, /* Initial value of the CRC */
size_bytes /* Size of the original Message */
);
'''
buildDataXRegInst("crc32b", 2,
crcCode % {"sz": 1, "polynom": "0x04C11DB7"})
buildDataXRegInst("crc32h", 2,
crcCode % {"sz": 2, "polynom": "0x04C11DB7"})
buildDataXRegInst("crc32w", 2,
crcCode % {"sz": 4, "polynom": "0x04C11DB7"})
buildDataXRegInst("crc32x", 2,
crcCode % {"sz": 8, "polynom": "0x04C11DB7"})
buildDataXRegInst("crc32cb", 2,
crcCode % {"sz": 1, "polynom": "0x1EDC6F41"})
buildDataXRegInst("crc32ch", 2,
crcCode % {"sz": 2, "polynom": "0x1EDC6F41"})
buildDataXRegInst("crc32cw", 2,
crcCode % {"sz": 4, "polynom": "0x1EDC6F41"})
buildDataXRegInst("crc32cx", 2,
crcCode % {"sz": 8, "polynom": "0x1EDC6F41"})
buildDataXRegInst("sdiv", 2, '''
int64_t op1 = Op164;
int64_t op2 = Op264;
if (intWidth == 32) {
op1 = sext<32>(op1);
op2 = sext<32>(op2);
}
Dest64 = op2 == -1 ? -op1 : op2 ? op1 / op2 : 0;
''', overrideOpClass="IntDivOp")
buildDataXRegInst("udiv", 2, "Dest64 = Op264 ? Op164 / Op264 : 0",
overrideOpClass="IntDivOp")
buildDataXRegInst("cls", 1, '''
uint64_t op1 = Op164;
if (bits(op1, intWidth - 1))
op1 ^= mask(intWidth);
Dest64 = (op1 == 0) ? intWidth - 1 : (intWidth - 2 - findMsbSet(op1));
''')
buildDataXRegInst("clz", 1, '''
Dest64 = (Op164 == 0) ? intWidth : (intWidth - 1 - findMsbSet(Op164));
''')
buildDataXRegInst("rbit", 1, '''
Dest64 = reverseBits(Op164, intWidth/8);
''')
buildDataXRegInst("rev", 1, '''
if (intWidth == 32)
Dest64 = betole<uint32_t>(Op164);
else
Dest64 = betole<uint64_t>(Op164);
''')
buildDataXRegInst("rev16", 1, '''
int count = intWidth / 16;
uint64_t result = 0;
for (unsigned i = 0; i < count; i++) {
uint16_t hw = Op164 >> (i * 16);
result |= (uint64_t)betole<uint16_t>(hw) << (i * 16);
}
Dest64 = result;
''')
buildDataXRegInst("rev32", 1, '''
int count = intWidth / 32;
uint64_t result = 0;
for (unsigned i = 0; i < count; i++) {
uint32_t hw = Op164 >> (i * 32);
result |= (uint64_t)betole<uint32_t>(hw) << (i * 32);
}
Dest64 = result;
''')
msrMrs64EnabledCheckCode = '''
// Check for read/write access right
if (!can%sAArch64SysReg(flat_idx, Hcr64, Scr64, cpsr, xc->tcBase())) {
return std::make_shared<UndefinedInstruction>(machInst, false,
mnemonic);
}
fault = this->trap(xc->tcBase(), flat_idx, el, imm);
if (fault != NoFault) return fault;
'''
msr_check_code = '''
auto pre_flat = (MiscRegIndex)snsBankedIndex64(dest, xc->tcBase());
MiscRegIndex flat_idx = (MiscRegIndex) xc->tcBase()->
flattenRegId(RegId(MiscRegClass, pre_flat)).index();
CPSR cpsr = Cpsr;
ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el;
%s
''' % (msrMrs64EnabledCheckCode % ('Write'),)
mrs_check_code = '''
auto pre_flat = (MiscRegIndex)snsBankedIndex64(op1, xc->tcBase());
MiscRegIndex flat_idx = (MiscRegIndex) xc->tcBase()->
flattenRegId(RegId(MiscRegClass, pre_flat)).index();
CPSR cpsr = Cpsr;
ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el;
%s
''' % (msrMrs64EnabledCheckCode % ('Read'),)
mrsCode = mrs_check_code + '''
XDest = MiscOp1_ud;
'''
mrsIop = ArmInstObjParams("mrs", "Mrs64", "RegMiscRegImmOp64",
mrsCode,
["IsSerializeBefore"])
header_output += RegMiscRegOp64Declare.subst(mrsIop)
decoder_output += RegMiscRegOp64Constructor.subst(mrsIop)
exec_output += BasicExecute.subst(mrsIop)
buildDataXRegInst("mrsNZCV", 1, '''
CPSR cpsr = 0;
cpsr.nz = CondCodesNZ;
cpsr.c = CondCodesC;
cpsr.v = CondCodesV;
XDest = cpsr;
''')
msrCode = msr_check_code + '''
MiscDest_ud = XOp1;
'''
msrIop = ArmInstObjParams("msr", "Msr64", "MiscRegRegImmOp64",
msrCode,
["IsSerializeAfter", "IsNonSpeculative"])
header_output += MiscRegRegOp64Declare.subst(msrIop)
decoder_output += MiscRegRegOp64Constructor.subst(msrIop)
exec_output += BasicExecute.subst(msrIop)
buildDataXRegInst("msrNZCV", 1, '''
CPSR cpsr = XOp1;
CondCodesNZ = cpsr.nz;
CondCodesC = cpsr.c;
CondCodesV = cpsr.v;
''')
msrdczva_ea_code = msr_check_code
msrdczva_ea_code += '''
Request::Flags memAccessFlags = Request::CACHE_BLOCK_ZERO;
EA = XBase;
assert(!(Dczid & 0x10));
uint64_t op_size = 1ULL << (Dczid + 2);
EA &= ~(op_size - 1);
'''
msrDCZVAIop = ArmInstObjParams("dc zva", "Dczva", "SysDC64",
{ "ea_code" : msrdczva_ea_code,
"memacc_code" : ';',
"use_uops" : 0,
"op_wb" : ";",
"fa_code" : ";"},
['IsStore']);
header_output += DCStore64Declare.subst(msrDCZVAIop);
decoder_output += DCStore64Constructor.subst(msrDCZVAIop);
exec_output += DCStore64Execute.subst(msrDCZVAIop);
exec_output += DCStore64InitiateAcc.subst(msrDCZVAIop);
exec_output += Store64CompleteAcc.subst(msrDCZVAIop);
# Cache maintenance fault annotation
# The DC ZVA instruction is not classified as a cache maintenance
# instruction, and therefore we shouldn't annotate it.
cachem_fa = '''
fault->annotate(ArmISA::ArmFault::CM, 1);
fault->annotate(ArmISA::ArmFault::OFA, faultAddr);
'''
msrdccvau_ea_code = msr_check_code
msrdccvau_ea_code += '''
Request::Flags memAccessFlags = Request::CLEAN | Request::DST_POU;
EA = XBase;
faultAddr = EA;
System *sys = xc->tcBase()->getSystemPtr();
Addr op_size = sys->cacheLineSize();
EA &= ~(op_size - 1);
'''
msrDCCVAUIop = ArmInstObjParams("dc cvau", "Dccvau", "SysDC64",
{ "ea_code" : msrdccvau_ea_code,
"memacc_code" : ';',
"use_uops" : 0,
"op_wb" : ";",
"fa_code" : cachem_fa},
['IsStore']);
header_output += DCStore64Declare.subst(msrDCCVAUIop);
decoder_output += DCStore64Constructor.subst(msrDCCVAUIop);
exec_output += DCStore64Execute.subst(msrDCCVAUIop);
exec_output += DCStore64InitiateAcc.subst(msrDCCVAUIop);
exec_output += Store64CompleteAcc.subst(msrDCCVAUIop);
msrdccvac_ea_code = msr_check_code
msrdccvac_ea_code += '''
Request::Flags memAccessFlags = Request::CLEAN | Request::DST_POC;
EA = XBase;
faultAddr = EA;
System *sys = xc->tcBase()->getSystemPtr();
Addr op_size = sys->cacheLineSize();
EA &= ~(op_size - 1);
'''
msrDCCVACIop = ArmInstObjParams("dc cvac", "Dccvac", "SysDC64",
{ "ea_code" : msrdccvac_ea_code,
"memacc_code" : ';',
"use_uops" : 0,
"op_wb" : ";",
"fa_code" : cachem_fa},
['IsStore']);
header_output += DCStore64Declare.subst(msrDCCVACIop);
decoder_output += DCStore64Constructor.subst(msrDCCVACIop);
exec_output += DCStore64Execute.subst(msrDCCVACIop);
exec_output += DCStore64InitiateAcc.subst(msrDCCVACIop);
exec_output += Store64CompleteAcc.subst(msrDCCVACIop);
msrdccivac_ea_code = msr_check_code
msrdccivac_ea_code += '''
Request::Flags memAccessFlags = Request::CLEAN |
Request::INVALIDATE | Request::DST_POC;
EA = XBase;
faultAddr = EA;
System *sys = xc->tcBase()->getSystemPtr();
Addr op_size = sys->cacheLineSize();
EA &= ~(op_size - 1);
'''
msrDCCIVACIop = ArmInstObjParams("dc civac", "Dccivac", "SysDC64",
{ "ea_code" : msrdccivac_ea_code,
"memacc_code" : ';',
"use_uops" : 0,
"op_wb" : ";",
"fa_code" : cachem_fa},
['IsStore']);
header_output += DCStore64Declare.subst(msrDCCIVACIop);
decoder_output += DCStore64Constructor.subst(msrDCCIVACIop);
exec_output += DCStore64Execute.subst(msrDCCIVACIop);
exec_output += DCStore64InitiateAcc.subst(msrDCCIVACIop);
exec_output += Store64CompleteAcc.subst(msrDCCIVACIop);
msrdcivac_ea_code = msr_check_code
msrdcivac_ea_code += '''
Request::Flags memAccessFlags = Request::INVALIDATE |
Request::DST_POC;
EA = XBase;
faultAddr = EA;
HCR hcr = Hcr64;
SCR scr = Scr64;
if (el == EL1 && ArmSystem::haveEL(xc->tcBase(), EL2) &&
hcr.vm && (scr.ns || !ArmSystem::haveEL(xc->tcBase(), EL3))) {
memAccessFlags = memAccessFlags | Request::CLEAN;
}
System *sys = xc->tcBase()->getSystemPtr();
Addr op_size = sys->cacheLineSize();
EA &= ~(op_size - 1);
'''
msrDCIVACIop = ArmInstObjParams("dc ivac", "Dcivac", "SysDC64",
{ "ea_code" : msrdcivac_ea_code,
"memacc_code" : ';',
"use_uops" : 0,
"op_wb" : ";",
"fa_code" : cachem_fa},
['IsStore']);
header_output += DCStore64Declare.subst(msrDCIVACIop);
decoder_output += DCStore64Constructor.subst(msrDCIVACIop);
exec_output += DCStore64Execute.subst(msrDCIVACIop);
exec_output += DCStore64InitiateAcc.subst(msrDCIVACIop);
exec_output += Store64CompleteAcc.subst(msrDCIVACIop);
def buildMsrImmInst(mnem, inst_name, code):
global header_output, decoder_output, exec_output
msrImmPermission = '''
auto pre_flat =
(MiscRegIndex)snsBankedIndex64(dest, xc->tcBase());
MiscRegIndex misc_index = (MiscRegIndex) xc->tcBase()->
flattenRegId(RegId(MiscRegClass, pre_flat)).index();
if (!miscRegInfo[misc_index][MISCREG_IMPLEMENTED]) {
return std::make_shared<UndefinedInstruction>(
machInst, false,
mnemonic);
}
if (!canWriteAArch64SysReg(misc_index, Hcr64,
Scr64, Cpsr, xc->tcBase())) {
return std::make_shared<UndefinedInstruction>(
machInst, 0, EC_TRAPPED_MSR_MRS_64,
mnemonic);
}
'''
msrIop = ArmInstObjParams("msr", inst_name, "MiscRegImmOp64",
msrImmPermission + code,
["IsSerializeAfter", "IsNonSpeculative"])
header_output += MiscRegOp64Declare.subst(msrIop)
decoder_output += MiscRegOp64Constructor.subst(msrIop)
exec_output += BasicExecute.subst(msrIop)
buildMsrImmInst("msr", "MsrImm64", '''
// Mask and shift immediate (depending on PSTATE field)
// before assignment
MiscDest_ud = miscRegImm();
''')
buildMsrImmInst("msr", "MsrImmDAIFSet64", '''
CPSR cpsr = Cpsr;
cpsr.daif = cpsr.daif | imm;
Cpsr = cpsr;
''')
buildMsrImmInst("msr", "MsrImmDAIFClr64", '''
CPSR cpsr = Cpsr;
cpsr.daif = cpsr.daif & ~imm;
Cpsr = cpsr;
''')
def buildDataXCompInst(mnem, instType, suffix, code):
global header_output, decoder_output, exec_output
templateBase = "DataXCond%s" % instType
iop = ArmInstObjParams(mnem, mnem.capitalize() + suffix + "64",
templateBase + "Op", code)
header_output += eval(templateBase + "Declare").subst(iop)
decoder_output += eval(templateBase + "Constructor").subst(iop)
exec_output += BasicExecute.subst(iop)
def buildDataXCondImmInst(mnem, code):
buildDataXCompInst(mnem, "CompImm", "Imm", code)
def buildDataXCondRegInst(mnem, code):
buildDataXCompInst(mnem, "CompReg", "Reg", code)
def buildDataXCondSelInst(mnem, code):
buildDataXCompInst(mnem, "Sel", "", code)
def condCompCode(flagType, op, imm):
ccCode = createCcCode64(carryCode64[flagType], overflowCode64[flagType])
opDecl = "[[maybe_unused]] uint64_t secOp = imm;"
if not imm:
opDecl = "[[maybe_unused]] uint64_t secOp = Op264;"
return opDecl + '''
if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) {
uint64_t resTemp = Op164 ''' + op + ''' secOp;
''' + ccCode + '''
} else {
CondCodesNZ = (defCc >> 2) & 0x3;
CondCodesC = (defCc >> 1) & 0x1;
CondCodesV = defCc & 0x1;
}
'''
buildDataXCondImmInst("ccmn", condCompCode("add", "+", True))
buildDataXCondImmInst("ccmp", condCompCode("sub", "-", True))
buildDataXCondRegInst("ccmn", condCompCode("add", "+", False))
buildDataXCondRegInst("ccmp", condCompCode("sub", "-", False))
condSelCode = '''
if (testPredicate(CondCodesNZ, CondCodesC, CondCodesV, condCode)) {
Dest64 = Op164;
} else {
Dest64 = %(altVal)s;
}
'''
buildDataXCondSelInst("csel", condSelCode % {"altVal" : "Op264"})
buildDataXCondSelInst("csinc", condSelCode % {"altVal" : "Op264 + 1"})
buildDataXCondSelInst("csinv", condSelCode % {"altVal" : "~Op264"})
buildDataXCondSelInst("csneg", condSelCode % {"altVal" : "-Op264"})
}};