diff options
Diffstat (limited to 'src/arch/arm/arm-codegen.h')
-rw-r--r-- | src/arch/arm/arm-codegen.h | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/src/arch/arm/arm-codegen.h b/src/arch/arm/arm-codegen.h new file mode 100644 index 0000000..d4d7f7c --- /dev/null +++ b/src/arch/arm/arm-codegen.h @@ -0,0 +1,1127 @@ +/* + * arm-codegen.h + * Copyright (c) 2002-2003 Sergey Chaban <serge@wildwestsoftware.com> + * Copyright 2005-2011 Novell Inc + * Copyright 2011 Xamarin Inc + */ + + +#ifndef ARM_H +#define ARM_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int arminstr_t; +typedef unsigned int armword_t; + +/* Helper functions */ +arminstr_t* arm_emit_std_prologue(arminstr_t* p, unsigned int local_size); +arminstr_t* arm_emit_std_epilogue(arminstr_t* p, unsigned int local_size, int pop_regs); +arminstr_t* arm_emit_lean_prologue(arminstr_t* p, unsigned int local_size, int push_regs); +int arm_is_power_of_2(armword_t val); +int calc_arm_mov_const_shift(armword_t val); +int is_arm_const(armword_t val); +int arm_bsf(armword_t val); +arminstr_t* arm_mov_reg_imm32_cond(arminstr_t* p, int reg, armword_t imm32, int cond); +arminstr_t* arm_mov_reg_imm32(arminstr_t* p, int reg, armword_t imm32); + + + +#if defined(_MSC_VER) || defined(__CC_NORCROFT) + void __inline _arm_emit(arminstr_t** p, arminstr_t i) {**p = i; (*p)++;} +# define ARM_EMIT(p, i) _arm_emit((arminstr_t**)&p, (arminstr_t)(i)) +#else +# define ARM_EMIT(p, i) do { arminstr_t *__ainstrp = (void*)(p); *__ainstrp = (arminstr_t)(i); (p) = (void*)(__ainstrp+1);} while (0) +#endif + +#if defined(_MSC_VER) && !defined(ARM_NOIASM) +# define ARM_IASM(_expr) __emit (_expr) +#else +# define ARM_IASM(_expr) +#endif + +/* even_scale = rot << 1 */ +#define ARM_SCALE(imm8, even_scale) ( ((imm8) >> (even_scale)) | ((imm8) << (32 - even_scale)) ) + + + +typedef enum { + ARMREG_R0 = 0, + ARMREG_R1, + ARMREG_R2, + ARMREG_R3, + ARMREG_R4, + ARMREG_R5, + ARMREG_R6, + ARMREG_R7, + ARMREG_R8, + ARMREG_R9, + ARMREG_R10, + ARMREG_R11, + ARMREG_R12, + ARMREG_R13, + ARMREG_R14, + ARMREG_R15, + + + /* aliases */ + /* args */ + ARMREG_A1 = ARMREG_R0, + ARMREG_A2 = ARMREG_R1, + ARMREG_A3 = ARMREG_R2, + ARMREG_A4 = ARMREG_R3, + + /* local vars */ + ARMREG_V1 = ARMREG_R4, + ARMREG_V2 = ARMREG_R5, + ARMREG_V3 = ARMREG_R6, + ARMREG_V4 = ARMREG_R7, + ARMREG_V5 = ARMREG_R8, + ARMREG_V6 = ARMREG_R9, + ARMREG_V7 = ARMREG_R10, + + ARMREG_FP = ARMREG_R11, + ARMREG_IP = ARMREG_R12, + ARMREG_SP = ARMREG_R13, + ARMREG_LR = ARMREG_R14, + ARMREG_PC = ARMREG_R15, + + /* co-processor */ + ARMREG_CR0 = 0, + ARMREG_CR1, + ARMREG_CR2, + ARMREG_CR3, + ARMREG_CR4, + ARMREG_CR5, + ARMREG_CR6, + ARMREG_CR7, + ARMREG_CR8, + ARMREG_CR9, + ARMREG_CR10, + ARMREG_CR11, + ARMREG_CR12, + ARMREG_CR13, + ARMREG_CR14, + ARMREG_CR15, + + /* XScale: acc0 on CP0 */ + ARMREG_ACC0 = ARMREG_CR0, + + ARMREG_MAX = ARMREG_R15 +} ARMReg; + +/* number of argument registers */ +#define ARM_NUM_ARG_REGS 4 + +/* bitvector for all argument regs (A1-A4) */ +#define ARM_ALL_ARG_REGS \ + (1 << ARMREG_A1) | (1 << ARMREG_A2) | (1 << ARMREG_A3) | (1 << ARMREG_A4) + + +typedef enum { + ARMCOND_EQ = 0x0, /* Equal; Z = 1 */ + ARMCOND_NE = 0x1, /* Not equal, or unordered; Z = 0 */ + ARMCOND_CS = 0x2, /* Carry set; C = 1 */ + ARMCOND_HS = ARMCOND_CS, /* Unsigned higher or same; */ + ARMCOND_CC = 0x3, /* Carry clear; C = 0 */ + ARMCOND_LO = ARMCOND_CC, /* Unsigned lower */ + ARMCOND_MI = 0x4, /* Negative; N = 1 */ + ARMCOND_PL = 0x5, /* Positive or zero; N = 0 */ + ARMCOND_VS = 0x6, /* Overflow; V = 1 */ + ARMCOND_VC = 0x7, /* No overflow; V = 0 */ + ARMCOND_HI = 0x8, /* Unsigned higher; C = 1 && Z = 0 */ + ARMCOND_LS = 0x9, /* Unsigned lower or same; C = 0 || Z = 1 */ + ARMCOND_GE = 0xA, /* Signed greater than or equal; N = V */ + ARMCOND_LT = 0xB, /* Signed less than; N != V */ + ARMCOND_GT = 0xC, /* Signed greater than; Z = 0 && N = V */ + ARMCOND_LE = 0xD, /* Signed less than or equal; Z = 1 && N != V */ + ARMCOND_AL = 0xE, /* Always */ + ARMCOND_NV = 0xF, /* Never */ + + ARMCOND_SHIFT = 28 +} ARMCond; + +#define ARMCOND_MASK (ARMCOND_NV << ARMCOND_SHIFT) + +#define ARM_DEF_COND(cond) (((cond) & 0xF) << ARMCOND_SHIFT) + + + +typedef enum { + ARMSHIFT_LSL = 0, + ARMSHIFT_LSR = 1, + ARMSHIFT_ASR = 2, + ARMSHIFT_ROR = 3, + + ARMSHIFT_ASL = ARMSHIFT_LSL + /* rrx = (ror, 1) */ +} ARMShiftType; + + +typedef struct { + armword_t PSR_c : 8; + armword_t PSR_x : 8; + armword_t PSR_s : 8; + armword_t PSR_f : 8; +} ARMPSR; + +typedef enum { + ARMOP_AND = 0x0, + ARMOP_EOR = 0x1, + ARMOP_SUB = 0x2, + ARMOP_RSB = 0x3, + ARMOP_ADD = 0x4, + ARMOP_ADC = 0x5, + ARMOP_SBC = 0x6, + ARMOP_RSC = 0x7, + ARMOP_TST = 0x8, + ARMOP_TEQ = 0x9, + ARMOP_CMP = 0xa, + ARMOP_CMN = 0xb, + ARMOP_ORR = 0xc, + ARMOP_MOV = 0xd, + ARMOP_BIC = 0xe, + ARMOP_MVN = 0xf, + + + /* not really opcodes */ + + ARMOP_STR = 0x0, + ARMOP_LDR = 0x1, + + /* ARM2+ */ + ARMOP_MUL = 0x0, /* Rd := Rm*Rs */ + ARMOP_MLA = 0x1, /* Rd := (Rm*Rs)+Rn */ + + /* ARM3M+ */ + ARMOP_UMULL = 0x4, + ARMOP_UMLAL = 0x5, + ARMOP_SMULL = 0x6, + ARMOP_SMLAL = 0x7, + + /* for data transfers with register offset */ + ARM_UP = 1, + ARM_DOWN = 0 +} ARMOpcode; + +typedef enum { + THUMBOP_AND = 0, + THUMBOP_EOR = 1, + THUMBOP_LSL = 2, + THUMBOP_LSR = 3, + THUMBOP_ASR = 4, + THUMBOP_ADC = 5, + THUMBOP_SBC = 6, + THUMBOP_ROR = 7, + THUMBOP_TST = 8, + THUMBOP_NEG = 9, + THUMBOP_CMP = 10, + THUMBOP_CMN = 11, + THUMBOP_ORR = 12, + THUMBOP_MUL = 13, + THUMBOP_BIC = 14, + THUMBOP_MVN = 15, + THUMBOP_MOV = 16, + THUMBOP_CMPI = 17, + THUMBOP_ADD = 18, + THUMBOP_SUB = 19, + THUMBOP_CMPH = 19, + THUMBOP_MOVH = 20 +} ThumbOpcode; + + +/* Generic form - all ARM instructions are conditional. */ +typedef struct { + arminstr_t icode : 28; + arminstr_t cond : 4; +} ARMInstrGeneric; + + + +/* Branch or Branch with Link instructions. */ +typedef struct { + arminstr_t offset : 24; + arminstr_t link : 1; + arminstr_t tag : 3; /* 1 0 1 */ + arminstr_t cond : 4; +} ARMInstrBR; + +#define ARM_BR_ID 5 +#define ARM_BR_MASK 7 << 25 +#define ARM_BR_TAG ARM_BR_ID << 25 + +#define ARM_DEF_BR(offs, l, cond) ((offs) | ((l) << 24) | (ARM_BR_TAG) | (cond << ARMCOND_SHIFT)) + +/* branch */ +#define ARM_B_COND(p, cond, offset) ARM_EMIT(p, ARM_DEF_BR(offset, 0, cond)) +#define ARM_B(p, offs) ARM_B_COND((p), ARMCOND_AL, (offs)) +/* branch with link */ +#define ARM_BL_COND(p, cond, offset) ARM_EMIT(p, ARM_DEF_BR(offset, 1, cond)) +#define ARM_BL(p, offs) ARM_BL_COND((p), ARMCOND_AL, (offs)) + +#define ARM_DEF_BX(reg,sub,cond) (0x12fff << 8 | (reg) | ((sub) << 4) | ((cond) << ARMCOND_SHIFT)) + +#define ARM_BX_COND(p, cond, reg) ARM_EMIT(p, ARM_DEF_BX(reg, 1, cond)) +#define ARM_BX(p, reg) ARM_BX_COND((p), ARMCOND_AL, (reg)) + +#define ARM_BLX_REG_COND(p, cond, reg) ARM_EMIT(p, ARM_DEF_BX(reg, 3, cond)) +#define ARM_BLX_REG(p, reg) ARM_BLX_REG_COND((p), ARMCOND_AL, (reg)) + +/* Data Processing Instructions - there are 3 types. */ + +typedef struct { + arminstr_t imm : 8; + arminstr_t rot : 4; +} ARMDPI_op2_imm; + +typedef struct { + arminstr_t rm : 4; + arminstr_t tag : 1; /* 0 - immediate shift, 1 - reg shift */ + arminstr_t type : 2; /* shift type - logical, arithmetic, rotate */ +} ARMDPI_op2_reg_shift; + + +/* op2 is reg shift by imm */ +typedef union { + ARMDPI_op2_reg_shift r2; + struct { + arminstr_t _dummy_r2 : 7; + arminstr_t shift : 5; + } imm; +} ARMDPI_op2_reg_imm; + +/* op2 is reg shift by reg */ +typedef union { + ARMDPI_op2_reg_shift r2; + struct { + arminstr_t _dummy_r2 : 7; + arminstr_t pad : 1; /* always 0, to differentiate from HXFER etc. */ + arminstr_t rs : 4; + } reg; +} ARMDPI_op2_reg_reg; + +/* Data processing instrs */ +typedef union { + ARMDPI_op2_imm op2_imm; + + ARMDPI_op2_reg_shift op2_reg; + ARMDPI_op2_reg_imm op2_reg_imm; + ARMDPI_op2_reg_reg op2_reg_reg; + + struct { + arminstr_t op2 : 12; /* raw operand 2 */ + arminstr_t rd : 4; /* destination reg */ + arminstr_t rn : 4; /* first operand reg */ + arminstr_t s : 1; /* S-bit controls PSR update */ + arminstr_t opcode : 4; /* arithmetic/logic operation */ + arminstr_t type : 1; /* type of op2, 0 = register, 1 = immediate */ + arminstr_t tag : 2; /* 0 0 */ + arminstr_t cond : 4; + } all; +} ARMInstrDPI; + +#define ARM_DPI_ID 0 +#define ARM_DPI_MASK 3 << 26 +#define ARM_DPI_TAG ARM_DPI_ID << 26 + +#define ARM_DEF_DPI_IMM_COND(imm8, rot, rd, rn, s, op, cond) \ + ((imm8) & 0xFF) | \ + (((rot) & 0xF) << 8) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((s) << 20) | \ + ((op) << 21) | \ + (1 << 25) | \ + (ARM_DPI_TAG) | \ + ARM_DEF_COND(cond) + + +#define ARM_DEF_DPI_IMM(imm8, rot, rd, rn, s, op) \ + ARM_DEF_DPI_IMM_COND(imm8, rot, rd, rn, s, op, ARMCOND_AL) + +/* codegen */ +#define ARM_DPIOP_REG_IMM8ROT_COND(p, op, rd, rn, imm8, rot, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_IMM_COND((imm8), ((rot) >> 1), (rd), (rn), 0, (op), cond)) +#define ARM_DPIOP_S_REG_IMM8ROT_COND(p, op, rd, rn, imm8, rot, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_IMM_COND((imm8), ((rot) >> 1), (rd), (rn), 1, (op), cond)) + +/* inline */ +#define ARM_IASM_DPIOP_REG_IMM8ROT_COND(p, op, rd, rn, imm8, rot, cond) \ + ARM_IASM(ARM_DEF_DPI_IMM_COND((imm8), ((rot) >> 1), (rd), (rn), 0, (op), cond)) +#define ARM_IASM_DPIOP_S_REG_IMM8ROT_COND(p, op, rd, rn, imm8, rot, cond) \ + ARM_IASM(ARM_DEF_DPI_IMM_COND((imm8), ((rot) >> 1), (rd), (rn), 1, (op), cond)) + + + +#define ARM_DEF_DPI_REG_IMMSHIFT_COND(rm, shift_type, imm_shift, rd, rn, s, op, cond) \ + (rm) | \ + ((shift_type & 3) << 5) | \ + (((imm_shift) & 0x1F) << 7) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((s) << 20) | \ + ((op) << 21) | \ + (ARM_DPI_TAG) | \ + ARM_DEF_COND(cond) + +/* codegen */ +#define ARM_DPIOP_REG_IMMSHIFT_COND(p, op, rd, rn, rm, shift_t, imm_shift, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), shift_t, imm_shift, (rd), (rn), 0, (op), cond)) + +#define ARM_DPIOP_S_REG_IMMSHIFT_COND(p, op, rd, rn, rm, shift_t, imm_shift, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), shift_t, imm_shift, (rd), (rn), 1, (op), cond)) + +#define ARM_DPIOP_REG_REG_COND(p, op, rd, rn, rm, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), ARMSHIFT_LSL, 0, (rd), (rn), 0, (op), cond)) + +#define ARM_DPIOP_S_REG_REG_COND(p, op, rd, rn, rm, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), ARMSHIFT_LSL, 0, (rd), (rn), 1, (op), cond)) + +/* inline */ +#define ARM_IASM_DPIOP_REG_IMMSHIFT_COND(p, op, rd, rn, rm, shift_t, imm_shift, cond) \ + ARM_IASM(ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), shift_t, imm_shift, (rd), (rn), 0, (op), cond)) + +#define ARM_IASM_DPIOP_S_REG_IMMSHIFT_COND(p, op, rd, rn, rm, shift_t, imm_shift, cond) \ + ARM_IASM(ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), shift_t, imm_shift, (rd), (rn), 1, (op), cond)) + +#define ARM_IASM_DPIOP_REG_REG_COND(p, op, rd, rn, rm, cond) \ + ARM_IASM(ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), ARMSHIFT_LSL, 0, (rd), (rn), 0, (op), cond)) + +#define ARM_IASM_DPIOP_S_REG_REG_COND(p, op, rd, rn, rm, cond) \ + ARM_IASM_EMIT(ARM_DEF_DPI_REG_IMMSHIFT_COND((rm), ARMSHIFT_LSL, 0, (rd), (rn), 1, (op), cond)) + + +/* Rd := Rn op (Rm shift_type Rs) */ +#define ARM_DEF_DPI_REG_REGSHIFT_COND(rm, shift_type, rs, rd, rn, s, op, cond) \ + (rm) | \ + (1 << 4) | \ + ((shift_type & 3) << 5) | \ + ((rs) << 8) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((s) << 20) | \ + ((op) << 21) | \ + (ARM_DPI_TAG) | \ + ARM_DEF_COND(cond) + +/* codegen */ +#define ARM_DPIOP_REG_REGSHIFT_COND(p, op, rd, rn, rm, shift_t, rs, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_REG_REGSHIFT_COND((rm), shift_t, (rs), (rd), (rn), 0, (op), cond)) + +#define ARM_DPIOP_S_REG_REGSHIFT_COND(p, op, rd, rn, rm, shift_t, rs, cond) \ + ARM_EMIT(p, ARM_DEF_DPI_REG_REGSHIFT_COND((rm), shift_t, (rs), (rd), (rn), 1, (op), cond)) + +/* inline */ +#define ARM_IASM_DPIOP_REG_REGSHIFT_COND(p, op, rd, rn, rm, shift_t, rs, cond) \ + ARM_IASM(ARM_DEF_DPI_REG_REGSHIFT_COND((rm), shift_t, (rs), (rd), (rn), 0, (op), cond)) + +#define ARM_IASM_DPIOP_S_REG_REGSHIFT_COND(p, op, rd, rn, rm, shift_t, rs, cond) \ + ARM_IASM(ARM_DEF_DPI_REG_REGSHIFT_COND((rm), shift_t, (rs), (rd), (rn), 1, (op), cond)) + + + +/* Multiple register transfer. */ +typedef struct { + arminstr_t reg_list : 16; /* bitfield */ + arminstr_t rn : 4; /* base reg */ + arminstr_t ls : 1; /* load(1)/store(0) */ + arminstr_t wb : 1; /* write-back "!" */ + arminstr_t s : 1; /* restore PSR, force user bit */ + arminstr_t u : 1; /* up/down */ + arminstr_t p : 1; /* pre(1)/post(0) index */ + arminstr_t tag : 3; /* 1 0 0 */ + arminstr_t cond : 4; +} ARMInstrMRT; + +#define ARM_MRT_ID 4 +#define ARM_MRT_MASK 7 << 25 +#define ARM_MRT_TAG ARM_MRT_ID << 25 + +#define ARM_DEF_MRT(regs, rn, l, w, s, u, p, cond) \ + (regs) | \ + (rn << 16) | \ + (l << 20) | \ + (w << 21) | \ + (s << 22) | \ + (u << 23) | \ + (p << 24) | \ + (ARM_MRT_TAG) | \ + ARM_DEF_COND(cond) + + +#define ARM_LDM(p, base, regs) ARM_EMIT(p, ARM_DEF_MRT(regs, base, 1, 0, 0, 1, 0, ARMCOND_AL)) +#define ARM_STM(p, base, regs) ARM_EMIT(p, ARM_DEF_MRT(regs, base, 0, 0, 0, 1, 0, ARMCOND_AL)) + +/* stmdb sp!, {regs} */ +#define ARM_PUSH(p, regs) ARM_EMIT(p, ARM_DEF_MRT(regs, ARMREG_SP, 0, 1, 0, 0, 1, ARMCOND_AL)) +#define ARM_IASM_PUSH(regs) ARM_IASM(ARM_DEF_MRT(regs, ARMREG_SP, 0, 1, 0, 0, 1, ARMCOND_AL)) + +/* ldmia sp!, {regs} */ +#define ARM_POP(p, regs) ARM_EMIT(p, ARM_DEF_MRT(regs, ARMREG_SP, 1, 1, 0, 1, 0, ARMCOND_AL)) +#define ARM_IASM_POP(regs) ARM_IASM_EMIT(ARM_DEF_MRT(regs, ARMREG_SP, 1, 1, 0, 1, 0, ARMCOND_AL)) + +/* ldmia sp, {regs} ; (no write-back) */ +#define ARM_POP_NWB(p, regs) ARM_EMIT(p, ARM_DEF_MRT(regs, ARMREG_SP, 1, 0, 0, 1, 0, ARMCOND_AL)) +#define ARM_IASM_POP_NWB(regs) ARM_IASM_EMIT(ARM_DEF_MRT(regs, ARMREG_SP, 1, 0, 0, 1, 0, ARMCOND_AL)) + +#define ARM_PUSH1(p, r1) ARM_PUSH(p, (1 << r1)) +#define ARM_PUSH2(p, r1, r2) ARM_PUSH(p, (1 << r1) | (1 << r2)) +#define ARM_PUSH3(p, r1, r2, r3) ARM_PUSH(p, (1 << r1) | (1 << r2) | (1 << r3)) +#define ARM_PUSH4(p, r1, r2, r3, r4) ARM_PUSH(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4)) +#define ARM_PUSH5(p, r1, r2, r3, r4, r5) ARM_PUSH(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5)) +#define ARM_PUSH6(p, r1, r2, r3, r4, r5, r6) ARM_PUSH(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5) | (1 << r6)) +#define ARM_PUSH7(p, r1, r2, r3, r4, r5, r6, r7) ARM_PUSH(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5) | (1 << r6) | (1 << r7)) +#define ARM_PUSH8(p, r1, r2, r3, r4, r5, r6, r7, r8) ARM_PUSH(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5) | (1 << r6) | (1 << r7) | (1 << r8)) + +#define ARM_POP8(p, r1, r2, r3, r4, r5, r6, r7, r8) ARM_POP(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5) | (1 << r6) | (1 << r7) | (1 << r8)) +#define ARM_POP7(p, r1, r2, r3, r4, r5, r6, r7) ARM_POP(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5) | (1 << r6) | (1 << r7)) +#define ARM_POP6(p, r1, r2, r3, r4, r5, r6) ARM_POP(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5) | (1 << r6)) +#define ARM_POP5(p, r1, r2, r3, r4, r5) ARM_POP(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4) | (1 << r5)) +#define ARM_POP4(p, r1, r2, r3, r4) ARM_POP(p, (1 << r1) | (1 << r2) | (1 << r3) | (1 << r4)) +#define ARM_POP3(p, r1, r2, r3) ARM_POP(p, (1 << r1) | (1 << r2) | (1 << r3)) +#define ARM_POP2(p, r1, r2) ARM_POP(p, (1 << r1) | (1 << r2)) +#define ARM_POP1(p, r1) ARM_POP(p, (1 << r1)) + + +/* Multiply instructions */ +typedef struct { + arminstr_t rm : 4; + arminstr_t tag2 : 4; /* 9 */ + arminstr_t rs : 4; + arminstr_t rn : 4; + arminstr_t rd : 4; + arminstr_t s : 1; + arminstr_t opcode : 3; + arminstr_t tag : 4; + arminstr_t cond : 4; +} ARMInstrMul; + +#define ARM_MUL_ID 0 +#define ARM_MUL_ID2 9 +#define ARM_MUL_MASK ((0xF << 24) | (0xF << 4)) +#define ARM_MUL_TAG ((ARM_MUL_ID << 24) | (ARM_MUL_ID2 << 4)) + +#define ARM_DEF_MUL_COND(op, rd, rm, rs, rn, s, cond) \ + (rm) | \ + ((rs) << 8) | \ + ((rn) << 12) | \ + ((rd) << 16) | \ + ((s & 1) << 17) | \ + ((op & 7) << 18) | \ + ARM_MUL_TAG | \ + ARM_DEF_COND(cond) + +/* Rd := (Rm * Rs)[31:0]; 32 x 32 -> 32 */ +#define ARM_MUL_COND(p, rd, rm, rs, cond) \ + ARM_EMIT(p, ARM_DEF_MUL_COND(ARMOP_MUL, rd, rm, rs, 0, 0, cond)) +#define ARM_MUL(p, rd, rm, rs) \ + ARM_MUL_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_MULS_COND(p, rd, rm, rs, cond) \ + ARM_EMIT(p, ARM_DEF_MUL_COND(ARMOP_MUL, rd, rm, rs, 0, 1, cond)) +#define ARM_MULS(p, rd, rm, rs) \ + ARM_MULS_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_MUL_REG_REG(p, rd, rm, rs) ARM_MUL(p, rd, rm, rs) +#define ARM_MULS_REG_REG(p, rd, rm, rs) ARM_MULS(p, rd, rm, rs) + +/* inline */ +#define ARM_IASM_MUL_COND(rd, rm, rs, cond) \ + ARM_IASM_EMIT(ARM_DEF_MUL_COND(ARMOP_MUL, rd, rm, rs, 0, 0, cond)) +#define ARM_IASM_MUL(rd, rm, rs) \ + ARM_IASM_MUL_COND(rd, rm, rs, ARMCOND_AL) +#define ARM_IASM_MULS_COND(rd, rm, rs, cond) \ + ARM_IASM_EMIT(ARM_DEF_MUL_COND(ARMOP_MUL, rd, rm, rs, 0, 1, cond)) +#define ARM_IASM_MULS(rd, rm, rs) \ + ARM_IASM_MULS_COND(rd, rm, rs, ARMCOND_AL) + + +/* Rd := (Rm * Rs) + Rn; 32x32+32->32 */ +#define ARM_MLA_COND(p, rd, rm, rs, rn, cond) \ + ARM_EMIT(p, ARM_DEF_MUL_COND(ARMOP_MLA, rd, rm, rs, rn, 0, cond)) +#define ARM_MLA(p, rd, rm, rs, rn) \ + ARM_MLA_COND(p, rd, rm, rs, rn, ARMCOND_AL) +#define ARM_MLAS_COND(p, rd, rm, rs, rn, cond) \ + ARM_EMIT(p, ARM_DEF_MUL_COND(ARMOP_MLA, rd, rm, rs, rn, 1, cond)) +#define ARM_MLAS(p, rd, rm, rs, rn) \ + ARM_MLAS_COND(p, rd, rm, rs, rn, ARMCOND_AL) + +/* inline */ +#define ARM_IASM_MLA_COND(rd, rm, rs, rn, cond) \ + ARM_IASM_EMIT(ARM_DEF_MUL_COND(ARMOP_MLA, rd, rm, rs, rn, 0, cond)) +#define ARM_IASM_MLA(rd, rm, rs, rn) \ + ARM_IASM_MLA_COND(rd, rm, rs, rn, ARMCOND_AL) +#define ARM_IASM_MLAS_COND(rd, rm, rs, rn, cond) \ + ARM_IASM_EMIT(ARM_DEF_MUL_COND(ARMOP_MLA, rd, rm, rs, rn, 1, cond)) +#define ARM_IASM_MLAS(rd, rm, rs, rn) \ + ARM_IASM_MLAS_COND(rd, rm, rs, rn, ARMCOND_AL) + + + +/* Word/byte transfer */ +typedef union { + ARMDPI_op2_reg_imm op2_reg_imm; + struct { + arminstr_t op2_imm : 12; + arminstr_t rd : 4; + arminstr_t rn : 4; + arminstr_t ls : 1; + arminstr_t wb : 1; + arminstr_t b : 1; + arminstr_t u : 1; /* down(0) / up(1) */ + arminstr_t p : 1; /* post-index(0) / pre-index(1) */ + arminstr_t type : 1; /* imm(0) / register(1) */ + arminstr_t tag : 2; /* 0 1 */ + arminstr_t cond : 4; + } all; +} ARMInstrWXfer; + +#define ARM_WXFER_ID 1 +#define ARM_WXFER_MASK 3 << 26 +#define ARM_WXFER_TAG ARM_WXFER_ID << 26 + + +#define ARM_DEF_WXFER_IMM(imm12, rd, rn, ls, wb, b, p, cond) \ + ((((int)imm12) < 0) ? -(int)(imm12) : (imm12)) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((ls) << 20) | \ + ((wb) << 21) | \ + ((b) << 22) | \ + (((int)(imm12) >= 0) << 23) | \ + ((p) << 24) | \ + ARM_WXFER_TAG | \ + ARM_DEF_COND(cond) + +#define ARM_WXFER_MAX_OFFS 0xFFF + +/* this macro checks for imm12 bounds */ +#define ARM_EMIT_WXFER_IMM(ptr, imm12, rd, rn, ls, wb, b, p, cond) \ + do { \ + int _imm12 = (int)(imm12) < -ARM_WXFER_MAX_OFFS \ + ? -ARM_WXFER_MAX_OFFS \ + : (int)(imm12) > ARM_WXFER_MAX_OFFS \ + ? ARM_WXFER_MAX_OFFS \ + : (int)(imm12); \ + ARM_EMIT((ptr), \ + ARM_DEF_WXFER_IMM(_imm12, (rd), (rn), (ls), (wb), (b), (p), (cond))); \ + } while (0) + + +/* LDRx */ +/* immediate offset, post-index */ +#define ARM_LDR_IMM_POST_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_LDR, 0, 0, 0, cond)) + +#define ARM_LDR_IMM_POST(p, rd, rn, imm) ARM_LDR_IMM_POST_COND(p, rd, rn, imm, ARMCOND_AL) + +#define ARM_LDRB_IMM_POST_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_LDR, 0, 1, 0, cond)) + +#define ARM_LDRB_IMM_POST(p, rd, rn, imm) ARM_LDRB_IMM_POST_COND(p, rd, rn, imm, ARMCOND_AL) + +/* immediate offset, pre-index */ +#define ARM_LDR_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_LDR, 0, 0, 1, cond)) + +#define ARM_LDR_IMM(p, rd, rn, imm) ARM_LDR_IMM_COND(p, rd, rn, imm, ARMCOND_AL) + +#define ARM_LDRB_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_LDR, 0, 1, 1, cond)) + +#define ARM_LDRB_IMM(p, rd, rn, imm) ARM_LDRB_IMM_COND(p, rd, rn, imm, ARMCOND_AL) + +/* STRx */ +/* immediate offset, post-index */ +#define ARM_STR_IMM_POST_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_STR, 0, 0, 0, cond)) + +#define ARM_STR_IMM_POST(p, rd, rn, imm) ARM_STR_IMM_POST_COND(p, rd, rn, imm, ARMCOND_AL) + +#define ARM_STRB_IMM_POST_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_STR, 0, 1, 0, cond)) + +#define ARM_STRB_IMM_POST(p, rd, rn, imm) ARM_STRB_IMM_POST_COND(p, rd, rn, imm, ARMCOND_AL) + +/* immediate offset, pre-index */ +#define ARM_STR_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT_WXFER_IMM(p, imm, rd, rn, ARMOP_STR, 0, 0, 1, cond) +/* ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_STR, 0, 0, 1, cond)) */ + +#define ARM_STR_IMM(p, rd, rn, imm) ARM_STR_IMM_COND(p, rd, rn, imm, ARMCOND_AL) + +#define ARM_STRB_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_IMM(imm, rd, rn, ARMOP_STR, 0, 1, 1, cond)) + +#define ARM_STRB_IMM(p, rd, rn, imm) ARM_STRB_IMM_COND(p, rd, rn, imm, ARMCOND_AL) + +/* write-back */ +#define ARM_STR_IMM_WB_COND(p, rd, rn, imm, cond) \ + ARM_EMIT_WXFER_IMM(p, imm, rd, rn, ARMOP_STR, 1, 0, 1, cond) +#define ARM_STR_IMM_WB(p, rd, rn, imm) ARM_STR_IMM_WB_COND(p, rd, rn, imm, ARMCOND_AL) + + +#define ARM_DEF_WXFER_REG_REG_UPDOWN_COND(rm, shift_type, shift, rd, rn, ls, wb, b, u, p, cond) \ + (rm) | \ + ((shift_type) << 5) | \ + ((shift) << 7) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((ls) << 20) | \ + ((wb) << 21) | \ + ((b) << 22) | \ + ((u) << 23) | \ + ((p) << 24) | \ + (1 << 25) | \ + ARM_WXFER_TAG | \ + ARM_DEF_COND(cond) + +#define ARM_DEF_WXFER_REG_REG_COND(rm, shift_type, shift, rd, rn, ls, wb, b, p, cond) \ + ARM_DEF_WXFER_REG_REG_UPDOWN_COND(rm, shift_type, shift, rd, rn, ls, wb, b, ARM_UP, p, cond) +#define ARM_DEF_WXFER_REG_MINUS_REG_COND(rm, shift_type, shift, rd, rn, ls, wb, b, p, cond) \ + ARM_DEF_WXFER_REG_REG_UPDOWN_COND(rm, shift_type, shift, rd, rn, ls, wb, b, ARM_DOWN, p, cond) + + +#define ARM_LDR_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_REG_REG_COND(rm, shift_type, shift, rd, rn, ARMOP_LDR, 0, 0, 1, cond)) +#define ARM_LDR_REG_REG_SHIFT(p, rd, rn, rm, shift_type, shift) \ + ARM_LDR_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, ARMCOND_AL) +#define ARM_LDR_REG_REG(p, rd, rn, rm) \ + ARM_LDR_REG_REG_SHIFT(p, rd, rn, rm, ARMSHIFT_LSL, 0) + +#define ARM_LDRB_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_REG_REG_COND(rm, shift_type, shift, rd, rn, ARMOP_LDR, 0, 1, 1, cond)) +#define ARM_LDRB_REG_REG_SHIFT(p, rd, rn, rm, shift_type, shift) \ + ARM_LDRB_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, ARMCOND_AL) +#define ARM_LDRB_REG_REG(p, rd, rn, rm) \ + ARM_LDRB_REG_REG_SHIFT(p, rd, rn, rm, ARMSHIFT_LSL, 0) + +#define ARM_STR_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_REG_REG_COND(rm, shift_type, shift, rd, rn, ARMOP_STR, 0, 0, 1, cond)) +#define ARM_STR_REG_REG_SHIFT(p, rd, rn, rm, shift_type, shift) \ + ARM_STR_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, ARMCOND_AL) +#define ARM_STR_REG_REG(p, rd, rn, rm) \ + ARM_STR_REG_REG_SHIFT(p, rd, rn, rm, ARMSHIFT_LSL, 0) + +/* zero-extend */ +#define ARM_STRB_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, cond) \ + ARM_EMIT(p, ARM_DEF_WXFER_REG_REG_COND(rm, shift_type, shift, rd, rn, ARMOP_STR, 0, 1, 1, cond)) +#define ARM_STRB_REG_REG_SHIFT(p, rd, rn, rm, shift_type, shift) \ + ARM_STRB_REG_REG_SHIFT_COND(p, rd, rn, rm, shift_type, shift, ARMCOND_AL) +#define ARM_STRB_REG_REG(p, rd, rn, rm) \ + ARM_STRB_REG_REG_SHIFT(p, rd, rn, rm, ARMSHIFT_LSL, 0) + + +/* ARMv4+ */ +/* Half-word or byte (signed) transfer. */ +typedef struct { + arminstr_t rm : 4; /* imm_lo */ + arminstr_t tag3 : 1; /* 1 */ + arminstr_t h : 1; /* half-word or byte */ + arminstr_t s : 1; /* sign-extend or zero-extend */ + arminstr_t tag2 : 1; /* 1 */ + arminstr_t imm_hi : 4; + arminstr_t rd : 4; + arminstr_t rn : 4; + arminstr_t ls : 1; + arminstr_t wb : 1; + arminstr_t type : 1; /* imm(1) / reg(0) */ + arminstr_t u : 1; /* +- */ + arminstr_t p : 1; /* pre/post-index */ + arminstr_t tag : 3; + arminstr_t cond : 4; +} ARMInstrHXfer; + +#define ARM_HXFER_ID 0 +#define ARM_HXFER_ID2 1 +#define ARM_HXFER_ID3 1 +#define ARM_HXFER_MASK ((0x7 << 25) | (0x9 << 4)) +#define ARM_HXFER_TAG ((ARM_HXFER_ID << 25) | (ARM_HXFER_ID2 << 7) | (ARM_HXFER_ID3 << 4)) + +#define ARM_DEF_HXFER_IMM_COND(imm, h, s, rd, rn, ls, wb, p, cond) \ + ((imm) < 0?(-(imm)) & 0xF:(imm) & 0xF) | \ + ((h) << 5) | \ + ((s) << 6) | \ + ((imm) < 0?((-(imm)) << 4) & 0xF00:((imm) << 4) & 0xF00) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((ls) << 20) | \ + ((wb) << 21) | \ + (1 << 22) | \ + (((int)(imm) >= 0) << 23) | \ + ((p) << 24) | \ + ARM_HXFER_TAG | \ + ARM_DEF_COND(cond) + +#define ARM_LDRH_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_IMM_COND(imm, 1, 0, rd, rn, ARMOP_LDR, 0, 1, cond)) +#define ARM_LDRH_IMM(p, rd, rn, imm) \ + ARM_LDRH_IMM_COND(p, rd, rn, imm, ARMCOND_AL) +#define ARM_LDRSH_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_IMM_COND(imm, 1, 1, rd, rn, ARMOP_LDR, 0, 1, cond)) +#define ARM_LDRSH_IMM(p, rd, rn, imm) \ + ARM_LDRSH_IMM_COND(p, rd, rn, imm, ARMCOND_AL) +#define ARM_LDRSB_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_IMM_COND(imm, 0, 1, rd, rn, ARMOP_LDR, 0, 1, cond)) +#define ARM_LDRSB_IMM(p, rd, rn, imm) \ + ARM_LDRSB_IMM_COND(p, rd, rn, imm, ARMCOND_AL) + + +#define ARM_STRH_IMM_COND(p, rd, rn, imm, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_IMM_COND(imm, 1, 0, rd, rn, ARMOP_STR, 0, 1, cond)) +#define ARM_STRH_IMM(p, rd, rn, imm) \ + ARM_STRH_IMM_COND(p, rd, rn, imm, ARMCOND_AL) + + +#define ARM_DEF_HXFER_REG_REG_UPDOWN_COND(rm, h, s, rd, rn, ls, wb, u, p, cond) \ + ((rm) & 0xF) | \ + ((h) << 5) | \ + ((s) << 6) | \ + ((rd) << 12) | \ + ((rn) << 16) | \ + ((ls) << 20) | \ + ((wb) << 21) | \ + (0 << 22) | \ + ((u) << 23) | \ + ((p) << 24) | \ + ARM_HXFER_TAG | \ + ARM_DEF_COND(cond) + +#define ARM_DEF_HXFER_REG_REG_COND(rm, h, s, rd, rn, ls, wb, p, cond) \ + ARM_DEF_HXFER_REG_REG_UPDOWN_COND(rm, h, s, rd, rn, ls, wb, ARM_UP, p, cond) +#define ARM_DEF_HXFER_REG_MINUS_REG_COND(rm, h, s, rd, rn, ls, wb, p, cond) \ + ARM_DEF_HXFER_REG_REG_UPDOWN_COND(rm, h, s, rd, rn, ls, wb, ARM_DOWN, p, cond) + +#define ARM_LDRH_REG_REG_COND(p, rd, rm, rn, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_REG_REG_COND(rm, 1, 0, rd, rn, ARMOP_LDR, 0, 1, cond)) +#define ARM_LDRH_REG_REG(p, rd, rm, rn) \ + ARM_LDRH_REG_REG_COND(p, rd, rm, rn, ARMCOND_AL) +#define ARM_LDRSH_REG_REG_COND(p, rd, rm, rn, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_REG_REG_COND(rm, 1, 1, rd, rn, ARMOP_LDR, 0, 1, cond)) +#define ARM_LDRSH_REG_REG(p, rd, rm, rn) \ + ARM_LDRSH_REG_REG_COND(p, rd, rm, rn, ARMCOND_AL) +#define ARM_LDRSB_REG_REG_COND(p, rd, rm, rn, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_REG_REG_COND(rm, 0, 1, rd, rn, ARMOP_LDR, 0, 1, cond)) +#define ARM_LDRSB_REG_REG(p, rd, rm, rn) ARM_LDRSB_REG_REG_COND(p, rd, rm, rn, ARMCOND_AL) + +#define ARM_STRH_REG_REG_COND(p, rd, rm, rn, cond) \ + ARM_EMIT(p, ARM_DEF_HXFER_REG_REG_COND(rm, 1, 0, rd, rn, ARMOP_STR, 0, 1, cond)) +#define ARM_STRH_REG_REG(p, rd, rm, rn) \ + ARM_STRH_REG_REG_COND(p, rd, rm, rn, ARMCOND_AL) + + + +/* Swap */ +typedef struct { + arminstr_t rm : 4; + arminstr_t tag3 : 8; /* 0x9 */ + arminstr_t rd : 4; + arminstr_t rn : 4; + arminstr_t tag2 : 2; + arminstr_t b : 1; + arminstr_t tag : 5; /* 0x2 */ + arminstr_t cond : 4; +} ARMInstrSwap; + +#define ARM_SWP_ID 2 +#define ARM_SWP_ID2 9 +#define ARM_SWP_MASK ((0x1F << 23) | (3 << 20) | (0xFF << 4)) +#define ARM_SWP_TAG ((ARM_SWP_ID << 23) | (ARM_SWP_ID2 << 4)) + + + +/* Software interrupt */ +typedef struct { + arminstr_t num : 24; + arminstr_t tag : 4; + arminstr_t cond : 4; +} ARMInstrSWI; + +#define ARM_SWI_ID 0xF +#define ARM_SWI_MASK (0xF << 24) +#define ARM_SWI_TAG (ARM_SWI_ID << 24) + + + +/* Co-processor Data Processing */ +typedef struct { + arminstr_t crm : 4; + arminstr_t tag2 : 1; /* 0 */ + arminstr_t op2 : 3; + arminstr_t cpn : 4; /* CP number */ + arminstr_t crd : 4; + arminstr_t crn : 4; + arminstr_t op : 4; + arminstr_t tag : 4; /* 0xE */ + arminstr_t cond : 4; +} ARMInstrCDP; + +#define ARM_CDP_ID 0xE +#define ARM_CDP_ID2 0 +#define ARM_CDP_MASK ((0xF << 24) | (1 << 4)) +#define ARM_CDP_TAG ((ARM_CDP_ID << 24) | (ARM_CDP_ID2 << 4)) + + +/* Co-processor Data Transfer (ldc/stc) */ +typedef struct { + arminstr_t offs : 8; + arminstr_t cpn : 4; + arminstr_t crd : 4; + arminstr_t rn : 4; + arminstr_t ls : 1; + arminstr_t wb : 1; + arminstr_t n : 1; + arminstr_t u : 1; + arminstr_t p : 1; + arminstr_t tag : 3; + arminstr_t cond : 4; +} ARMInstrCDT; + +#define ARM_CDT_ID 6 +#define ARM_CDT_MASK (7 << 25) +#define ARM_CDT_TAG (ARM_CDT_ID << 25) + + +/* Co-processor Register Transfer (mcr/mrc) */ +typedef struct { + arminstr_t crm : 4; + arminstr_t tag2 : 1; + arminstr_t op2 : 3; + arminstr_t cpn : 4; + arminstr_t rd : 4; + arminstr_t crn : 4; + arminstr_t ls : 1; + arminstr_t op1 : 3; + arminstr_t tag : 4; + arminstr_t cond : 4; +} ARMInstrCRT; + +#define ARM_CRT_ID 0xE +#define ARM_CRT_ID2 0x1 +#define ARM_CRT_MASK ((0xF << 24) | (1 << 4)) +#define ARM_CRT_TAG ((ARM_CRT_ID << 24) | (ARM_CRT_ID2 << 4)) + +/* Move register to PSR. */ +typedef union { + ARMDPI_op2_imm op2_imm; + struct { + arminstr_t rm : 4; + arminstr_t pad : 8; /* 0 */ + arminstr_t tag4 : 4; /* 0xF */ + arminstr_t fld : 4; + arminstr_t tag3 : 2; /* 0x2 */ + arminstr_t sel : 1; + arminstr_t tag2 : 2; /* 0x2 */ + arminstr_t type : 1; + arminstr_t tag : 2; /* 0 */ + arminstr_t cond : 4; + } all; +} ARMInstrMSR; + +#define ARM_MSR_ID 0 +#define ARM_MSR_ID2 2 +#define ARM_MSR_ID3 2 +#define ARM_MSR_ID4 0xF +#define ARM_MSR_MASK ((3 << 26) | \ + (3 << 23) | \ + (3 << 20) | \ + (0xF << 12)) +#define ARM_MSR_TAG ((ARM_MSR_ID << 26) | \ + (ARM_MSR_ID2 << 23) | \ + (ARM_MSR_ID3 << 20) | \ + (ARM_MSR_ID4 << 12)) + + +/* Move PSR to register. */ +typedef struct { + arminstr_t tag3 : 12; + arminstr_t rd : 4; + arminstr_t tag2 : 6; + arminstr_t sel : 1; /* CPSR | SPSR */ + arminstr_t tag : 5; + arminstr_t cond : 4; +} ARMInstrMRS; + +#define ARM_MRS_ID 2 +#define ARM_MRS_ID2 0xF +#define ARM_MRS_ID3 0 +#define ARM_MRS_MASK ((0x1F << 23) | (0x3F << 16) | 0xFFF) +#define ARM_MRS_TAG ((ARM_MRS_ID << 23) | (ARM_MRS_ID2 << 16) | ARM_MRS_ID3) + + + +#include "mono/arch/arm/arm_dpimacros.h" + +#define ARM_NOP(p) ARM_MOV_REG_REG(p, ARMREG_R0, ARMREG_R0) + + +#define ARM_SHL_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOV_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_LSL, imm, cond) +#define ARM_SHL_IMM(p, rd, rm, imm) \ + ARM_SHL_IMM_COND(p, rd, rm, imm, ARMCOND_AL) +#define ARM_SHLS_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOVS_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_LSL, imm, cond) +#define ARM_SHLS_IMM(p, rd, rm, imm) \ + ARM_SHLS_IMM_COND(p, rd, rm, imm, ARMCOND_AL) + +#define ARM_SHR_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOV_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_LSR, imm, cond) +#define ARM_SHR_IMM(p, rd, rm, imm) \ + ARM_SHR_IMM_COND(p, rd, rm, imm, ARMCOND_AL) +#define ARM_SHRS_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOVS_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_LSR, imm, cond) +#define ARM_SHRS_IMM(p, rd, rm, imm) \ + ARM_SHRS_IMM_COND(p, rd, rm, imm, ARMCOND_AL) + +#define ARM_SAR_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOV_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_ASR, imm, cond) +#define ARM_SAR_IMM(p, rd, rm, imm) \ + ARM_SAR_IMM_COND(p, rd, rm, imm, ARMCOND_AL) +#define ARM_SARS_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOVS_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_ASR, imm, cond) +#define ARM_SARS_IMM(p, rd, rm, imm) \ + ARM_SARS_IMM_COND(p, rd, rm, imm, ARMCOND_AL) + +#define ARM_ROR_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOV_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_ROR, imm, cond) +#define ARM_ROR_IMM(p, rd, rm, imm) \ + ARM_ROR_IMM_COND(p, rd, rm, imm, ARMCOND_AL) +#define ARM_RORS_IMM_COND(p, rd, rm, imm, cond) \ + ARM_MOVS_REG_IMMSHIFT_COND(p, rd, rm, ARMSHIFT_ROR, imm, cond) +#define ARM_RORS_IMM(p, rd, rm, imm) \ + ARM_RORS_IMM_COND(p, rd, rm, imm, ARMCOND_AL) + +#define ARM_SHL_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOV_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_LSL, rs, cond) +#define ARM_SHL_REG(p, rd, rm, rs) \ + ARM_SHL_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_SHLS_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOVS_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_LSL, rs, cond) +#define ARM_SHLS_REG(p, rd, rm, rs) \ + ARM_SHLS_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_SHLS_REG_REG(p, rd, rm, rs) ARM_SHLS_REG(p, rd, rm, rs) + +#define ARM_SHR_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOV_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_LSR, rs, cond) +#define ARM_SHR_REG(p, rd, rm, rs) \ + ARM_SHR_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_SHRS_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOVS_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_LSR, rs, cond) +#define ARM_SHRS_REG(p, rd, rm, rs) \ + ARM_SHRS_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_SHRS_REG_REG(p, rd, rm, rs) ARM_SHRS_REG(p, rd, rm, rs) + +#define ARM_SAR_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOV_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_ASR, rs, cond) +#define ARM_SAR_REG(p, rd, rm, rs) \ + ARM_SAR_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_SARS_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOVS_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_ASR, rs, cond) +#define ARM_SARS_REG(p, rd, rm, rs) \ + ARM_SARS_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_SARS_REG_REG(p, rd, rm, rs) ARM_SARS_REG(p, rd, rm, rs) + +#define ARM_ROR_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOV_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_ROR, rs, cond) +#define ARM_ROR_REG(p, rd, rm, rs) \ + ARM_ROR_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_RORS_REG_COND(p, rd, rm, rs, cond) \ + ARM_MOVS_REG_REGSHIFT_COND(p, rd, rm, ARMSHIFT_ROR, rs, cond) +#define ARM_RORS_REG(p, rd, rm, rs) \ + ARM_RORS_REG_COND(p, rd, rm, rs, ARMCOND_AL) +#define ARM_RORS_REG_REG(p, rd, rm, rs) ARM_RORS_REG(p, rd, rm, rs) + +#ifdef __native_client_codegen__ +#define ARM_DBRK(p) ARM_EMIT(p, 0xE7FEDEF0) +#else +#define ARM_DBRK(p) ARM_EMIT(p, 0xE6000010) +#endif +#define ARM_IASM_DBRK() ARM_IASM_EMIT(0xE6000010) + +#define ARM_INC(p, reg) ARM_ADD_REG_IMM8(p, reg, reg, 1) +#define ARM_DEC(p, reg) ARM_SUB_REG_IMM8(p, reg, reg, 1) + +#define ARM_MLS(p, rd, rn, rm, ra) ARM_EMIT((p), (ARMCOND_AL << 28) | (0x6 << 20) | ((rd) << 16) | ((ra) << 12) | ((rm) << 8) | (0x9 << 4) | ((rn) << 0)) + +/* ARM V5 */ + +/* Count leading zeros, CLZ{cond} Rd, Rm */ +typedef struct { + arminstr_t rm : 4; + arminstr_t tag2 : 8; + arminstr_t rd : 4; + arminstr_t tag : 12; + arminstr_t cond : 4; +} ARMInstrCLZ; + +#define ARM_CLZ_ID 0x16F +#define ARM_CLZ_ID2 0xF1 +#define ARM_CLZ_MASK ((0xFFF << 16) | (0xFF < 4)) +#define ARM_CLZ_TAG ((ARM_CLZ_ID << 16) | (ARM_CLZ_ID2 << 4)) + + + + +typedef union { + ARMInstrBR br; + ARMInstrDPI dpi; + ARMInstrMRT mrt; + ARMInstrMul mul; + ARMInstrWXfer wxfer; + ARMInstrHXfer hxfer; + ARMInstrSwap swp; + ARMInstrCDP cdp; + ARMInstrCDT cdt; + ARMInstrCRT crt; + ARMInstrSWI swi; + ARMInstrMSR msr; + ARMInstrMRS mrs; + ARMInstrCLZ clz; + + ARMInstrGeneric generic; + arminstr_t raw; +} ARMInstr; + +/* ARMv6t2 */ + +#define ARM_MOVW_REG_IMM_COND(p, rd, imm16, cond) ARM_EMIT(p, (((cond) << 28) | (3 << 24) | (0 << 20) | ((((guint32)(imm16)) >> 12) << 16) | ((rd) << 12) | (((guint32)(imm16)) & 0xfff))) +#define ARM_MOVW_REG_IMM(p, rd, imm16) ARM_MOVW_REG_IMM_COND ((p), (rd), (imm16), ARMCOND_AL) + +#define ARM_MOVT_REG_IMM_COND(p, rd, imm16, cond) ARM_EMIT(p, (((cond) << 28) | (3 << 24) | (4 << 20) | ((((guint32)(imm16)) >> 12) << 16) | ((rd) << 12) | (((guint32)(imm16)) & 0xfff))) +#define ARM_MOVT_REG_IMM(p, rd, imm16) ARM_MOVT_REG_IMM_COND ((p), (rd), (imm16), ARMCOND_AL) + +/* MCR */ +#define ARM_DEF_MCR_COND(coproc, opc1, rt, crn, crm, opc2, cond) \ + ARM_DEF_COND ((cond)) | ((0xe << 24) | (((opc1) & 0x7) << 21) | (0 << 20) | (((crn) & 0xf) << 16) | (((rt) & 0xf) << 12) | (((coproc) & 0xf) << 8) | (((opc2) & 0x7) << 5) | (1 << 4) | (((crm) & 0xf) << 0)) + +#define ARM_MCR_COND(p, coproc, opc1, rt, crn, crm, opc2, cond) \ + ARM_EMIT(p, ARM_DEF_MCR_COND ((coproc), (opc1), (rt), (crn), (crm), (opc2), (cond))) + +#define ARM_MCR(p, coproc, opc1, rt, crn, crm, opc2) \ + ARM_MCR_COND ((p), (coproc), (opc1), (rt), (crn), (crm), (opc2), ARMCOND_AL) + +/* ARMv7VE */ +#define ARM_SDIV_COND(p, rd, rn, rm, cond) ARM_EMIT (p, (((cond) << 28) | (0xe << 23) | (0x1 << 20) | ((rd) << 16) | (0xf << 12) | ((rm) << 8) | (0x0 << 5) | (0x1 << 4) | ((rn) << 0))) +#define ARM_SDIV(p, rd, rn, rm) ARM_SDIV_COND ((p), (rd), (rn), (rm), ARMCOND_AL) + +#define ARM_UDIV_COND(p, rd, rn, rm, cond) ARM_EMIT (p, (((cond) << 28) | (0xe << 23) | (0x3 << 20) | ((rd) << 16) | (0xf << 12) | ((rm) << 8) | (0x0 << 5) | (0x1 << 4) | ((rn) << 0))) +#define ARM_UDIV(p, rd, rn, rm) ARM_UDIV_COND ((p), (rd), (rn), (rm), ARMCOND_AL) + +/* ARMv7 */ + +typedef enum { + ARM_DMB_SY = 0xf, +} ArmDmbFlags; + +#define ARM_DMB(p, option) ARM_EMIT ((p), ((0xf << 28) | (0x57 << 20) | (0xf << 16) | (0xf << 12) | (0x0 << 8) | (0x5 << 4) | ((option) << 0))) + +#define ARM_LDREX_REG(p, rt, rn) ARM_EMIT ((p), ((ARMCOND_AL << 28) | (0xc << 21) | (0x1 << 20) | ((rn) << 16) | ((rt) << 12)) | (0xf << 8) | (0x9 << 4) | 0xf << 0) + +#define ARM_STREX_REG(p, rd, rt, rn) ARM_EMIT ((p), ((ARMCOND_AL << 28) | (0xc << 21) | (0x0 << 20) | ((rn) << 16) | ((rd) << 12)) | (0xf << 8) | (0x9 << 4) | ((rt) << 0)) + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_H */ + |