#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "decode.h"
#include "pcode.h"
int BitCount(uint32_t x)
{
int result = 0;
while (x)
{
if (x & 1)
result += 1;
x >>= 1;
}
return result;
}
bool BFXPreferred(uint32_t sf, uint32_t uns, uint32_t imms, uint32_t immr)
{
if (imms < immr)
return false;
if (imms == ((sf << 5) | 0x1F))
return false;
if (immr == 0)
{
if (sf == 0 && (imms == 7 || imms == 15))
return false;
if ((sf == 1 && uns == 0) && (imms == 7 || imms == 15 || imms == 31))
return false;
}
return true;
}
uint64_t rotate_right(uint64_t x, unsigned width, unsigned amount)
{
amount = amount % width;
x = (x >> amount) | (x << (width - amount));
x = (width < 64) ? x & (((uint64_t)1 << width) - 1) : x;
return x;
}
DecodeBitMasks_ReturnType DecodeBitMasks(
uint8_t immN, uint8_t imms, uint8_t immr)
{
int ones_nbits = 0;
if (immN == 1)
ones_nbits = 6;
else if ((imms & 0x3E) == 0x3C)
ones_nbits = 1;
else if ((imms & 0x3C) == 0x38)
ones_nbits = 2;
else if ((imms & 0x38) == 0x30)
ones_nbits = 3;
else if ((imms & 0x30) == 0x20)
ones_nbits = 4;
else if ((imms & 0x20) == 0)
ones_nbits = 5;
int ones_n = (imms & ((1 << ones_nbits) - 1)) + 1;
uint64_t result = ((uint64_t)1 << ones_n) - 1;
int elem_width = 1 << ones_nbits;
result = rotate_right(result, elem_width, immr);
while (elem_width < 64)
{
result = (result << elem_width) | result;
elem_width *= 2;
}
DecodeBitMasks_ReturnType dbmrt;
dbmrt.wmask = result;
dbmrt.tmask = result;
return dbmrt;
}
bool MoveWidePreferred(uint32_t sf, uint32_t immN, uint32_t immS, uint32_t immR)
{
uint32_t splat = (immN << 6) | immS;
if (sf == 1 && !((splat & 0x40) == 0x40))
return false;
if (sf == 0 && !((splat & 0x60) == 0x00))
return false;
DecodeBitMasks_ReturnType dbmrt = DecodeBitMasks(sf, immS, immR);
uint64_t imm = dbmrt.wmask;
if (sf == 0)
imm &= 0xffffffff;
if (((imm & 0xffffffffffff0000) == 0) || ((imm & 0xffffffff0000ffff) == 0) ||
((imm & 0xffff0000ffffffff) == 0) || ((imm & 0x0000ffffffffffff) == 0))
return true;
imm = ~imm;
if (sf == 0)
imm &= 0xffffffff;
if (((imm & 0xffffffffffff0000) == 0) || ((imm & 0xffffffff0000ffff) == 0) ||
((imm & 0xffff0000ffffffff) == 0) || ((imm & 0x0000ffffffffffff) == 0))
return true;
return false;
}
int HighestSetBit(uint64_t x)
{
for (int i = 63; i >= 0 && x; --i)
{
if (x & 0x8000000000000000)
return i;
x <<= 1;
}
return -1;
}
int HighestSetBitNZ(uint64_t x)
{
if (x == 0)
return -1;
return HighestSetBit(x);
}
int LowestSetBit(uint64_t x)
{
for (int i = 0; i < 64; ++i)
{
if (x & 1)
return i;
x >>= 1;
}
return -1;
}
int LowestSetBitNZ(uint64_t x)
{
if (x == 0)
return -1;
return LowestSetBit(x);
}
bool SVEMoveMaskPreferred(uint32_t imm13)
{
return true;
}
enum ShiftType DecodeRegExtend(uint8_t op)
{
switch (op & 7)
{
case 0b000:
return ShiftType_UXTB;
case 0b001:
return ShiftType_UXTH;
case 0b010:
return ShiftType_UXTW;
case 0b011:
return ShiftType_UXTX;
case 0b100:
return ShiftType_SXTB;
case 0b101:
return ShiftType_SXTH;
case 0b110:
return ShiftType_SXTW;
case 0b111:
return ShiftType_SXTX;
default:
return ShiftType_NONE;
}
}
enum ShiftType DecodeShift(uint8_t op)
{
switch (op & 3)
{
case 0b00:
return ShiftType_LSL;
case 0b01:
return ShiftType_LSR;
case 0b10:
return ShiftType_ASR;
case 0b11:
return ShiftType_ROR;
default:
return ShiftType_NONE;
}
}
enum SystemOp SysOp(uint32_t op1, uint32_t CRn, uint32_t CRm, uint32_t op2)
{
uint32_t tmp = (((op1 & 7) << 11) | ((CRn & 0xF) << 7) | ((CRm & 0xF) << 3) | ((op2) & 7));
switch (tmp)
{
case AT_OP_S1E1R:
case AT_OP_S1E1W:
case AT_OP_S1E0R:
case AT_OP_S1E0W:
case AT_OP_S1E1RP:
case AT_OP_S1E1WP:
case AT_OP_S1E1A:
case AT_OP_S1E2R:
case AT_OP_S1E2W:
case AT_OP_S12E1R:
case AT_OP_S12E1W:
case AT_OP_S12E0R:
case AT_OP_S12E0W:
case AT_OP_S1E2A:
case AT_OP_S1E3R:
case AT_OP_S1E3W:
case AT_OP_S1E3A:
return Sys_AT;
case DC_OP_IVAC:
case DC_OP_ISW:
case DC_OP_IGVAC:
case DC_OP_IGSW:
case DC_OP_IGDVAC:
case DC_OP_IGDSW:
case DC_OP_CSW:
case DC_OP_CGSW:
case DC_OP_CGDSW:
case DC_OP_CISW:
case DC_OP_CIGSW:
case DC_OP_CIGDSW:
case DC_OP_CIVAPS:
case DC_OP_CIGDVAPS:
case DC_OP_ZVA:
case DC_OP_GVA:
case DC_OP_GZVA:
case DC_OP_CVAC:
case DC_OP_CGVAC:
case DC_OP_CGDVAC:
case DC_OP_CVAOC:
case DC_OP_CVAU:
case DC_OP_CGDVAOC:
case DC_OP_CVAP:
case DC_OP_CGVAP:
case DC_OP_CGDVAP:
case DC_OP_CVADP:
case DC_OP_CGVADP:
case DC_OP_CGDVADP:
case DC_OP_CIVAC:
case DC_OP_CIGVAC:
case DC_OP_CIGDVAC:
case DC_OP_CIVAOC:
case DC_OP_CIGDVAOC:
case DC_OP_CIPAE:
case DC_OP_CIGDPAE:
case DC_OP_CIPAPA:
case DC_OP_CIGDPAPA:
return Sys_DC;
case 0b00001110001000:
return Sys_IC; case 0b00001110101000:
return Sys_IC; case 0b01101110101001:
return Sys_IC; case TLBI_VMALLE1OS:
case TLBI_VAE1OS:
case TLBI_ASIDE1OS:
case TLBI_VAAE1OS:
case TLBI_VALE1OS:
case TLBI_VAALE1OS:
case TLBI_RVAE1IS:
case TLBI_RVAAE1IS:
case TLBI_RVALE1IS:
case TLBI_RVAALE1IS:
case TLBI_VMALLE1IS:
case TLBI_VAE1IS:
case TLBI_ASIDE1IS:
case TLBI_VAAE1IS:
case TLBI_VALE1IS:
case TLBI_VAALE1IS:
case TLBI_RVAE1OS:
case TLBI_RVAAE1OS:
case TLBI_RVALE1OS:
case TLBI_RVAALE1OS:
case TLBI_RVAE1:
case TLBI_RVAAE1:
case TLBI_RVALE1:
case TLBI_RVAALE1:
case TLBI_VMALLE1:
case TLBI_VAE1:
case TLBI_ASIDE1:
case TLBI_VAAE1:
case TLBI_VALE1:
case TLBI_VAALE1:
case TLBI_VMALLE1OSNXS:
case TLBI_VAE1OSNXS:
case TLBI_ASIDE1OSNXS:
case TLBI_VAAE1OSNXS:
case TLBI_VALE1OSNXS:
case TLBI_VAALE1OSNXS:
case TLBI_RVAE1ISNXS:
case TLBI_RVAAE1ISNXS:
case TLBI_RVALE1ISNXS:
case TLBI_RVAALE1ISNXS:
case TLBI_VMALLE1ISNXS:
case TLBI_VAE1ISNXS:
case TLBI_ASIDE1ISNXS:
case TLBI_VAAE1ISNXS:
case TLBI_VALE1ISNXS:
case TLBI_VAALE1ISNXS:
case TLBI_RVAE1OSNXS:
case TLBI_RVAAE1OSNXS:
case TLBI_RVALE1OSNXS:
case TLBI_RVAALE1OSNXS:
case TLBI_RVAE1NXS:
case TLBI_RVAAE1NXS:
case TLBI_RVALE1NXS:
case TLBI_RVAALE1NXS:
case TLBI_VMALLE1NXS:
case TLBI_VAE1NXS:
case TLBI_ASIDE1NXS:
case TLBI_VAAE1NXS:
case TLBI_VALE1NXS:
case TLBI_VAALE1NXS:
case TLBI_IPAS2E1IS:
case TLBI_RIPAS2E1IS:
case TLBI_IPAS2LE1IS:
case TLBI_RIPAS2LE1IS:
case TLBI_ALLE2OS:
case TLBI_VAE2OS:
case TLBI_ALLE1OS:
case TLBI_VALE2OS:
case TLBI_VMALLS12E1OS:
case TLBI_RVAE2IS:
case TLBI_VMALLWS2E1IS:
case TLBI_RVALE2IS:
case TLBI_ALLE2IS:
case TLBI_VAE2IS:
case TLBI_ALLE1IS:
case TLBI_VALE2IS:
case TLBI_VMALLS12E1IS:
case TLBI_IPAS2E1OS:
case TLBI_IPAS2E1:
case TLBI_RIPAS2E1:
case TLBI_RIPAS2E1OS:
case TLBI_IPAS2LE1OS:
case TLBI_IPAS2LE1:
case TLBI_RIPAS2LE1:
case TLBI_RIPAS2LE1OS:
case TLBI_RVAE2OS:
case TLBI_VMALLWS2E1OS:
case TLBI_RVALE2OS:
case TLBI_RVAE2:
case TLBI_VMALLWS2E1:
case TLBI_RVALE2:
case TLBI_ALLE2:
case TLBI_VAE2:
case TLBI_ALLE1:
case TLBI_VALE2:
case TLBI_VMALLS12E1:
case TLBI_IPAS2E1ISNXS:
case TLBI_RIPAS2E1ISNXS:
case TLBI_IPAS2LE1ISNXS:
case TLBI_RIPAS2LE1ISNXS:
case TLBI_ALLE2OSNXS:
case TLBI_VAE2OSNXS:
case TLBI_ALLE1OSNXS:
case TLBI_VALE2OSNXS:
case TLBI_VMALLS12E1OSNXS:
case TLBI_RVAE2ISNXS:
case TLBI_VMALLWS2E1ISNXS:
case TLBI_RVALE2ISNXS:
case TLBI_ALLE2ISNXS:
case TLBI_VAE2ISNXS:
case TLBI_ALLE1ISNXS:
case TLBI_VALE2ISNXS:
case TLBI_VMALLS12E1ISNXS:
case TLBI_IPAS2E1OSNXS:
case TLBI_IPAS2E1NXS:
case TLBI_RIPAS2E1NXS:
case TLBI_RIPAS2E1OSNXS:
case TLBI_IPAS2LE1OSNXS:
case TLBI_IPAS2LE1NXS:
case TLBI_RIPAS2LE1NXS:
case TLBI_RIPAS2LE1OSNXS:
case TLBI_RVAE2OSNXS:
case TLBI_VMALLWS2E1OSNXS:
case TLBI_RVALE2OSNXS:
case TLBI_RVAE2NXS:
case TLBI_VMALLWS2E1NXS:
case TLBI_RVALE2NXS:
case TLBI_ALLE2NXS:
case TLBI_VAE2NXS:
case TLBI_ALLE1NXS:
case TLBI_VALE2NXS:
case TLBI_VMALLS12E1NXS:
case TLBI_ALLE3OS:
case TLBI_VAE3OS:
case TLBI_PAALLOS:
case TLBI_VALE3OS:
case TLBI_RVAE3IS:
case TLBI_RVALE3IS:
case TLBI_ALLE3IS:
case TLBI_VAE3IS:
case TLBI_VALE3IS:
case TLBI_RPAOS:
case TLBI_RPALOS:
case TLBI_RVAE3OS:
case TLBI_RVALE3OS:
case TLBI_RVAE3:
case TLBI_RVALE3:
case TLBI_ALLE3:
case TLBI_VAE3:
case TLBI_PAALL:
case TLBI_VALE3:
case TLBI_ALLE3OSNXS:
case TLBI_VAE3OSNXS:
case TLBI_VALE3OSNXS:
case TLBI_RVAE3ISNXS:
case TLBI_RVALE3ISNXS:
case TLBI_ALLE3ISNXS:
case TLBI_VAE3ISNXS:
case TLBI_VALE3ISNXS:
case TLBI_RVAE3OSNXS:
case TLBI_RVALE3OSNXS:
case TLBI_RVAE3NXS:
case TLBI_RVALE3NXS:
case TLBI_ALLE3NXS:
case TLBI_VAE3NXS:
case TLBI_VALE3NXS:
return Sys_TLBI; default:
return Sys_ERROR;
}
}
uint32_t UInt(uint32_t foo)
{
return foo;
}
uint32_t BitSlice(uint64_t foo, int hi, int lo) {
int width = hi - lo + 1;
uint64_t mask = (1 << width) - 1;
return (foo >> lo) & mask;
}
bool IsZero(uint64_t foo)
{
return foo == 0;
}
bool IsOnes(uint64_t foo, int width)
{
return foo == (1 << width) - 1;
}
uint64_t Replicate(uint64_t val, uint8_t times, uint64_t width)
{
switch (times)
{
case 64:
val |= val << width;
width <<= 1;
case 32:
val |= val << width;
width <<= 1;
case 16:
val |= val << width;
width <<= 1;
case 8:
val |= val << width;
width <<= 1;
case 4:
val |= val << width;
width <<= 1;
case 2:
val |= val << width;
case 1:
return val;
case 0:
return 0;
default:
break;
}
uint64_t orig = val;
for (size_t i = 0; i < times; ++i)
{
val <<= width;
val |= orig;
}
return val;
}
uint64_t AdvSIMDExpandImm(uint8_t op, uint8_t cmode, uint64_t imm8)
{
switch ((cmode >> 1) & 0b111)
{
case 0b000:
return Replicate(imm8, 2, 32);
case 0b001:
return Replicate(imm8 << 8, 2, 32);
case 0b010:
return Replicate(imm8 << 16, 2, 32);
case 0b011:
return Replicate(imm8 << 24, 2, 32);
case 0b100:
return Replicate(imm8, 4, 16);
case 0b101:
return Replicate(imm8 << 8, 4, 16);
case 0b110:
return Replicate(imm8 << (8 << (cmode & 0b1)), 2, 32);
case 0b111:
switch (((cmode & 0b1) << 1) | op)
{
case 0b00:
return Replicate(imm8, 8, 8);
case 0b01:
{
#if 0#else
uint64_t imm64 = imm8 | (imm8 << (0x08 - 1)) | (imm8 << (0x10 - 2)) | (imm8 << (0x18 - 3)) |
(imm8 << (0x20 - 4)) | (imm8 << (0x28 - 5)) | (imm8 << (0x30 - 6)) |
(imm8 << (0x38 - 7));
imm64 &= 0x0101010101010101;
return Replicate(imm64, 8, 1);
#endif
}
case 0b10:
return Replicate((((imm8 & 0xc0) ^ 0x80) << 24) |
(Replicate((imm8 >> 6) & 0b1, 5, 1) << 25) | ((imm8 & 0x3f) << 19),
2, 32);
case 0b11:
return (((imm8 & 0xc0) ^ 0x80) << 56) | (Replicate((imm8 >> 6) & 0b1, 8, 1) << 54) |
((imm8 & 0x3f) << 48);
}
break;
}
return 0;
}
bool BTypeCompatible_BTI(uint8_t hintcode, uint8_t pstate_btype)
{
switch (hintcode & 3)
{
case 0b00:
return false;
case 0b01:
return pstate_btype != 0b11;
case 0b10:
return pstate_btype != 0b10;
case 0b11:
return true;
}
return false;
}
bool BTypeCompatible_PACIXSP(void)
{
return BTypeCompatible_PAC(PACIxSP);
}
bool BTypeCompatible_PAC(enum PACInstType pacinst)
{
return true;
}
enum FPRounding FPDecodeRounding(uint8_t RMode)
{
switch (RMode & 3)
{
case 0b00:
return FPRounding_TIEEVEN; case 0b01:
return FPRounding_POSINF; case 0b10:
return FPRounding_NEGINF; case 0b11:
return FPRounding_ZERO; }
return FPRounding_ERROR;
}
enum FPRounding FPRoundingMode(uint64_t fpcr)
{
return FPDecodeRounding(FPCR_GET_RMode(fpcr));
}
bool HaltingAllowed(void)
{
return true;
}
void SystemAccessTrap(uint32_t a, uint32_t b)
{
while (0)
;
}
void CheckSystemAccess(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g)
{
while (0)
;
}
uint64_t VFPExpandImm(unsigned char byte, unsigned N)
{
uint64_t Result;
unsigned bit6 = SLICE(byte, 6, 6);
if (N == 32)
{
Result = SLICE(byte, 7, 7) << 31 | SLICE(byte, 5, 0) << 19;
if (bit6)
Result |= 0x1f << 25;
else
Result |= 0x1 << 30;
}
else
{
Result = (uint64_t)SLICE(byte, 7, 7) << 63 | (uint64_t)SLICE(byte, 5, 0) << 48;
if (bit6)
Result |= 0xffULL << 54;
else
Result |= 0x1ULL << 62;
}
return Result;
}
bool EL2Enabled(void)
{
return true;
}
bool ELUsingAArch32(uint8_t x)
{
return true;
}
bool HaveEL(uint8_t el)
{
return true;
}
uint64_t FPOne(bool sign, int N)
{
int E;
switch (N)
{
case 16:
E = 5;
break;
case 32:
E = 8;
break;
case 64:
E = 11;
break;
default:
E = 11;
}
int F = N - (E + 1);
uint64_t exp = (1ULL << (E - 1)) - 1;
uint64_t frac = 0;
return ((uint64_t)sign << (N - 1)) | (exp << F) | frac;
}
uint64_t FPTwo(bool sign, int N)
{
int E;
switch (N)
{
case 16:
E = 5;
break;
case 32:
E = 8;
break;
case 64:
E = 11;
break;
default:
E = 11;
}
int F = N - (E + 1);
uint64_t exp = 1ULL << (E - 1);
uint64_t frac = 0;
return ((uint64_t)sign << (N - 1)) | (exp << F) | frac;
}
uint64_t FPPointFive(bool sign, int N)
{
int E, F, exp;
switch (N)
{
case 16:
E = 5;
case 32:
E = 8;
default:
E = 11;
}
F = N - (E + 1);
exp = BITMASK(E - 2) << 1;
return (sign << (E - 2 + F)) | (exp << F);
}
uint64_t SignExtend(uint64_t x, int width)
{
uint64_t result = -1;
if (x & ((uint64_t)1 << (width - 1)))
{
result ^= (((uint64_t)1 << width) - 1);
result |= x;
}
else
{
result = x;
}
return result;
}
enum Constraint ConstrainUnpredictable(enum Unpredictable u)
{
switch (u)
{
case Unpredictable_VMSR:
return Constraint_UNDEF;
case Unpredictable_WBOVERLAPLD:
return Constraint_WBSUPPRESS; case Unpredictable_WBOVERLAPST:
return Constraint_NONE; case Unpredictable_LDPOVERLAP:
return Constraint_UNDEF; case Unpredictable_BASEOVERLAP:
return Constraint_NONE; case Unpredictable_DATAOVERLAP:
return Constraint_NONE; case Unpredictable_DEVPAGE2:
return Constraint_FAULT; case Unpredictable_DEVICETAGSTORE:
return Constraint_NONE; case Unpredictable_INSTRDEVICE:
return Constraint_NONE; case Unpredictable_RESCPACR:
return Constraint_TRUE; case Unpredictable_RESMAIR:
return Constraint_UNKNOWN; case Unpredictable_RESTEXCB:
return Constraint_UNKNOWN; case Unpredictable_RESDACR:
return Constraint_UNKNOWN; case Unpredictable_RESPRRR:
return Constraint_UNKNOWN; case Unpredictable_RESVTCRS:
return Constraint_UNKNOWN; case Unpredictable_RESTnSZ:
return Constraint_FORCE; case Unpredictable_OORTnSZ:
return Constraint_FORCE; case Unpredictable_LARGEIPA:
return Constraint_FORCE; case Unpredictable_ESRCONDPASS:
return Constraint_FALSE; case Unpredictable_ILZEROIT:
return Constraint_FALSE; case Unpredictable_ILZEROT:
return Constraint_FALSE; case Unpredictable_BPVECTORCATCHPRI:
return Constraint_TRUE; case Unpredictable_VCMATCHHALF:
return Constraint_FALSE; case Unpredictable_VCMATCHDAPA:
return Constraint_FALSE; case Unpredictable_WPMASKANDBAS:
return Constraint_FALSE; case Unpredictable_WPBASCONTIGUOUS:
return Constraint_FALSE; case Unpredictable_RESWPMASK:
return Constraint_DISABLED; case Unpredictable_WPMASKEDBITS:
return Constraint_FALSE; case Unpredictable_RESBPWPCTRL:
return Constraint_DISABLED; case Unpredictable_BPNOTIMPL:
return Constraint_DISABLED; case Unpredictable_RESBPTYPE:
return Constraint_DISABLED; case Unpredictable_BPNOTCTXCMP:
return Constraint_DISABLED; case Unpredictable_BPMATCHHALF:
return Constraint_FALSE; case Unpredictable_BPMISMATCHHALF:
return Constraint_FALSE; case Unpredictable_RESTARTALIGNPC:
return Constraint_FALSE; case Unpredictable_RESTARTZEROUPPERPC:
return Constraint_TRUE; case Unpredictable_ZEROUPPER:
return Constraint_TRUE; case Unpredictable_ERETZEROUPPERPC:
return Constraint_TRUE; case Unpredictable_A32FORCEALIGNPC:
return Constraint_FALSE; case Unpredictable_SMD:
return Constraint_UNDEF; case Unpredictable_NONFAULT:
return Constraint_FALSE; case Unpredictable_SVEZEROUPPER:
return Constraint_TRUE; case Unpredictable_SVELDNFDATA:
return Constraint_TRUE; case Unpredictable_SVELDNFZERO:
return Constraint_TRUE; case Unpredictable_CHECKSPNONEACTIVE:
return Constraint_TRUE; case Unpredictable_AFUPDATE:
return Constraint_TRUE;
case Unpredictable_IESBinDebug:
return Constraint_TRUE;
case Unpredictable_BADPMSFCR:
return Constraint_TRUE;
case Unpredictable_ZEROBTYPE:
return Constraint_TRUE; case Unpredictable_CLEARERRITEZERO:
return Constraint_FALSE;
case Unpredictable_ALUEXCEPTIONRETURN:
return Constraint_UNDEF;
case Unpredictable_DBGxVR_RESS:
return Constraint_FALSE;
case Unpredictable_WFxTDEBUG:
return Constraint_FALSE; case Unpredictable_LS64UNSUPPORTED:
return Constraint_LIMITED_ATOMICITY; default:
return Constraint_ERROR;
}
}