/* Copyright © 2019 Michal Schulz https://github.com/michalsc This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _A64_H #define _A64_H #include /* Context pointer is stored in TPIDRRO_EL0 */ /* SR is stored in TPIDR_EL0 */ /* last_PC is stored in TPIDR_EL1 */ #define REG_PC 18 #define REG_D0 19 #define REG_D1 20 #define REG_D2 21 #define REG_D3 22 #define REG_D4 23 #define REG_D5 24 #define REG_D6 25 #define REG_D7 26 #define REG_A0 13 #define REG_A1 14 #define REG_A2 15 #define REG_A3 16 #define REG_A4 17 #define REG_A5 27 #define REG_A6 28 #define REG_A7 29 #define REG_PROTECT ((1 << 30) | (1 << (REG_A0)) | (1 << (REG_A1)) | (1 << (REG_A2)) | (1 << (REG_A3)) | (1 << (REG_A4)) | (1 << (REG_PC))) #define REG_FP0 8 #define REG_FP1 9 #define REG_FP2 10 #define REG_FP3 11 #define REG_FP4 12 #define REG_FP5 13 #define REG_FP6 14 #define REG_FP7 15 #define A64_CC_EQ 0x00 /* Z=1 */ #define A64_CC_NE 0x01 /* Z=0 */ #define A64_CC_CS 0x02 /* C=1 */ #define A64_CC_CC 0x03 /* C=0 */ #define A64_CC_MI 0x04 /* N=1 */ #define A64_CC_PL 0x05 /* N=0 */ #define A64_CC_VS 0x06 /* V=1 */ #define A64_CC_VC 0x07 /* V=0 */ #define A64_CC_HI 0x08 #define A64_CC_LS 0x09 #define A64_CC_GE 0x0a /* N == V */ #define A64_CC_LT 0x0b /* N != V */ #define A64_CC_GT 0x0c /* Z == 0 && N == V */ #define A64_CC_LE 0x0d /* Z == 1 || N != V */ #define A64_CC_AL 0x0e /* Always */ #define A64_CC_NV 0x0f /* Always */ #define ARM_CC_EQ 0x00 /* Z=1 */ #define ARM_CC_NE 0x01 /* Z=0 */ #define ARM_CC_CS 0x02 /* C=1 */ #define ARM_CC_CC 0x03 /* C=0 */ #define ARM_CC_MI 0x04 /* N=1 */ #define ARM_CC_PL 0x05 /* N=0 */ #define ARM_CC_VS 0x06 /* V=1 */ #define ARM_CC_VC 0x07 /* V=0 */ #define ARM_CC_HI 0x08 #define ARM_CC_LS 0x09 #define ARM_CC_GE 0x0a /* N == V */ #define ARM_CC_LT 0x0b /* N != V */ #define ARM_CC_GT 0x0c /* Z == 0 && N == V */ #define ARM_CC_LE 0x0d /* Z == 1 || N != V */ #define ARM_CC_AL 0x0e /* Always */ #define ARM_CC_NV 0x0f /* Always */ #define MMU_NG 0x800 #define MMU_ACCESS 0x400 #define MMU_ISHARE 0x300 #define MMU_OSHARE 0x200 #define MMU_READ_ONLY 0x080 #define MMU_ALLOW_EL0 0x040 #define MMU_NS 0x020 #define MMU_ATTR(x) (((x) & 7) << 2) #define MMU_DIR 0x003 #define MMU_PAGE 0x001 #define ATTR_DEVICE_nGnRnE 0x00 #define ATTR_DEVICE_nGnRE 0x04 #define ATTR_NOCACHE 0x44 #define ATTR_CACHED 0xff #define ATTR_WRTHROUGH 0xbb /* Keep MMU_ATTR_ENTRIES and following MMU_ATTR_x in sync!!!! */ #define MMU_ATTR_ENTRIES ((ATTR_CACHED << 8) | (ATTR_DEVICE_nGnRE) | (ATTR_NOCACHE << 16) | (ATTR_WRTHROUGH << 24)) #define MMU_ATTR_CACHED MMU_ATTR(1) #define MMU_ATTR_DEVICE MMU_ATTR(0) #define MMU_ATTR_UNCACHED MMU_ATTR(2) #define MMU_ATTR_WRITETHROUGH MMU_ATTR(3) #define SP 31 /* 31 encodes SP base, or */ #define ZR 31 /* Zero register, depending on usage */ /* Converts generated ARM instruction to little-endian */ static inline uint32_t I32(uint32_t insn) { union { uint32_t u32; uint8_t u8[4]; } val; val.u8[3] = (insn >> 24) & 0xff; val.u8[2] = (insn >> 16) & 0xff; val.u8[1] = (insn >> 8) & 0xff; val.u8[0] = (insn)&0xff; return val.u32; } static inline uint32_t INSN_TO_LE(uint32_t insn) { return I32(insn); } void kprintf(const char * format, ...); #define ASSERT_REG(reg) \ do { if ((reg) > 31) kprintf("[ASSERT] %s: Using uninitialized register (%x) at line %d?\n", __PRETTY_FUNCTION__, (reg), __LINE__); } while(0) #if 0 #define ASSERT_OFFSET(offset, mask) \ do { if ((offset) & ~(mask)) kprintf("[ASSERT] %s: Offset out of range: %x mask %x at line %d\n", __PRETTY_FUNCTION__, (offset), (mask), __LINE__); } while(0) #else #define ASSERT_OFFSET(offset, mask) /* */ #endif /* Branches */ static inline uint32_t b_cc(uint8_t cc, int32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); return I32(0x54000000 | (cc & 15) | ((offset19 & 0x7ffff) << 5)); } static inline uint32_t b(uint32_t offset) { ASSERT_OFFSET(offset, 0x3ffffff); return I32(0x14000000 | (offset & 0x3ffffff)); } static inline uint32_t bl(uint32_t offset) { ASSERT_OFFSET(offset, 0x3ffffff); return I32(0x94000000 | (offset & 0x3ffffff)); } static inline uint32_t blr(uint8_t rt) { ASSERT_REG(rt); return I32(0xd63f0000 | ((rt & 31) << 5));} static inline uint32_t br(uint8_t rt) { ASSERT_REG(rt); return I32(0xd61f0000 | ((rt & 31) << 5));} static inline uint32_t cbnz(uint8_t rt, uint32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); ASSERT_REG(rt); return I32(0x35000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } static inline uint32_t cbnz_64(uint8_t rt, uint32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); ASSERT_REG(rt); return I32(0xb5000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } static inline uint32_t cbz(uint8_t rt, uint32_t offset19) { ASSERT_REG(rt); return I32(0x34000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } static inline uint32_t cbz_64(uint8_t rt, uint32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); ASSERT_REG(rt); return I32(0xb4000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } static inline uint32_t ret() { return I32(0xd65f0000 | (30 << 5));} static inline uint32_t ret_reg(uint8_t rt) { ASSERT_REG(rt); return I32(0xd65f0000 | ((rt & 31) << 5));} static inline uint32_t tbnz(uint8_t rt, uint8_t bit, uint16_t offset) { ASSERT_OFFSET(offset, 0x3fff); ASSERT_REG(rt); return I32(bit & 32 ? 0xb7000000 : 0x37000000 | ((bit & 31) << 19) | ((offset & 0x3fff) << 5) | (rt & 31)); } static inline uint32_t tbz(uint8_t rt, uint8_t bit, uint16_t offset) { ASSERT_OFFSET(offset, 0x3fff); ASSERT_REG(rt); return I32(bit & 32 ? 0xb6000000 : 0x36000000 | ((bit & 31) << 19) | ((offset & 0x3fff) << 5) | (rt & 31)); } static inline uint32_t bx_lr() { return ret(); } /* System instructions */ static inline uint32_t mrs(uint8_t rt, uint8_t op0, uint8_t op1, uint8_t crn, uint8_t crm, uint8_t op2) { ASSERT_REG(rt); return I32(0xd5300000 | (rt & 31) | (op0 == 3 ? 0x80000 : 0) | ((op1 & 7) << 16) | ((crn & 15) << 12) | ((crm & 15) << 8) | ((op2 & 7) << 5)); } static inline uint32_t msr(uint8_t rt, uint8_t op0, uint8_t op1, uint8_t crn, uint8_t crm, uint8_t op2) { ASSERT_REG(rt); return I32(0xd5100000 | (rt & 31) | (op0 == 3 ? 0x80000 : 0) | ((op1 & 7) << 16) | ((crn & 15) << 12) | ((crm & 15) << 8) | ((op2 & 7) << 5)); } static inline uint32_t msr_imm(uint8_t op1, uint8_t op2, uint8_t imm) { return I32(0xd500401f | ((op1 & 7) << 16) | ((op2 & 7) << 5) | ((imm & 15) << 8)); } static inline uint32_t brk(uint16_t imm16) { return I32(0xd4200000 | (imm16 << 5)); } static inline uint32_t hlt(uint16_t imm16) { return I32(0xd4400000 | (imm16 << 5)); } static inline uint32_t udf(uint16_t imm16) { return hlt(imm16); } static inline uint32_t hint(uint8_t h) { return I32(0xd503201f | ((h & 0x7f) << 5)); } static inline uint32_t wfe() { return hint(2); } static inline uint32_t wfi() { return hint(3); } static inline uint32_t sev() { return hint(4); } static inline uint32_t get_nzcv(uint8_t rt) { ASSERT_REG(rt); return mrs(rt, 3, 3, 4, 2, 0); } static inline uint32_t set_nzcv(uint8_t rt) { ASSERT_REG(rt); return msr(rt, 3, 3, 4, 2, 0); } static inline uint32_t get_fpcr(uint8_t rt) { ASSERT_REG(rt); return mrs(rt, 3, 3, 4, 4, 0); } static inline uint32_t set_fpcr(uint8_t rt) { ASSERT_REG(rt); return msr(rt, 3, 3, 4, 4, 0); } static inline uint32_t cfinv() { return I32(0xd500401f); } static inline uint32_t sys(uint8_t rt, uint8_t op1, uint8_t cn, uint8_t cm, uint8_t op2) { ASSERT_REG(rt); return I32(0xd5080000 | ((op1 & 7) << 16) | ((op2 & 7) << 5) | ((cn & 15) << 12) | ((cm & 15) << 8) | (rt & 31)); } static inline uint32_t sysl(uint8_t rt, uint8_t op1, uint8_t cn, uint8_t cm, uint8_t op2) { ASSERT_REG(rt); return I32(0xd5280000 | ((op1 & 7) << 16) | ((op2 & 7) << 5) | ((cn & 15) << 12) | ((cm & 15) << 8) | (rt & 31)); } static inline uint32_t dc_ivac(uint8_t rt) { ASSERT_REG(rt); return sys(rt, 0, 7, 6, 1); } static inline uint32_t dc_civac(uint8_t rt) { ASSERT_REG(rt); return sys(rt, 3, 7, 14, 1); } static inline uint32_t dsb_sy() { return I32(0xd5033f9f); } static inline uint32_t dmb_ish() { return I32(0xd5033bbf); } static inline uint32_t nop() { return I32(0xd503201f); } static inline uint32_t svc(uint16_t code) { return I32(0xd4000001 | (code << 5)); } /* Load PC-relatve address */ static inline uint32_t adr(uint8_t rd, uint32_t imm21) { ASSERT_OFFSET(imm21, 0x1fffff); ASSERT_REG(rd); return I32(0x10000000 | (rd & 31) | ((imm21 & 3) << 29) | (((imm21 >> 2) & 0x7ffff) << 5)); } static inline uint32_t adrp(uint8_t rd, uint32_t imm21) { ASSERT_OFFSET(imm21, 0x1fffff); ASSERT_REG(rd); return I32(0x90000000 | (rd & 31) | ((imm21 & 3) << 29) | (((imm21 >> 2) & 0x7ffff) << 5)); } /* Load/Store instructions */ static inline uint32_t ldr_pcrel(uint8_t rt, int32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); ASSERT_REG(rt); return I32(0x18000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } static inline uint32_t ldr64_pcrel(uint8_t rt, int32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); ASSERT_REG(rt); return I32(0x58000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } static inline uint32_t ldrsw_pcrel(uint8_t rt, int32_t offset19) { ASSERT_OFFSET(offset19, 0x7ffff); ASSERT_REG(rt); return I32(0x98000000 | ((offset19 & 0x7ffff) << 5) | (rt & 31)); } typedef enum { UXTB = 0, UXTH = 1, UXTW = 2, UXTX = 3, SXTB = 4, SXTH = 5, SXTW = 6, SXTX = 7} reg_extend_t; /* Load/Store with reg offset */ static inline uint32_t ldr_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl2) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8600800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl2 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t ldr64_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl3) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xf8600800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl3 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t ldrb_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x38600800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((ext & 7) << 13)); } static inline uint32_t ldrsb_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x38e00800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((ext & 7) << 13)); } static inline uint32_t ldrsb64_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x38a00800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((ext & 7) << 13)); } static inline uint32_t ldrh_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl1) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x78600800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl1 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t ldrsh_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl1) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x78e00800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl1 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t ldrsh64_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl1) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x78a00800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl1 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t ldrsw_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl2) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xb8a00800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl2 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t str_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl2) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xb8200800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl2 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t str64_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl3) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xf8200800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl3 ? 0x1000 : 0) | ((ext & 7) << 13)); } static inline uint32_t strb_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x38200800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((ext & 7) << 13)); } static inline uint32_t strh_regoffset(uint8_t rn, uint8_t rt, uint8_t rm, reg_extend_t ext, uint8_t lsl1) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x78200800 | (rt & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | (lsl1 ? 0x1000 : 0) | ((ext & 7) << 13)); } /* Load/Store with scaled offset */ static inline uint32_t ldr_offset(uint8_t rn, uint8_t rt, uint16_t offset14) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb9400000 | (rt & 31) | ((rn & 31) << 5) | (((offset14 >> 2) & 0xfff) << 10)); } static inline uint32_t ldr_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8400400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldr_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8400c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldr64_offset(uint8_t rn, uint8_t rt, uint16_t offset15) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf9400000 | (rt & 31) | ((rn & 31) << 5) | (((offset15 >> 3) & 0xfff) << 10)); } static inline uint32_t ldr64_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf8400400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldr64_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf8400c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrb_offset(uint8_t rn, uint8_t rt, uint16_t offset12) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x39400000 | (rt & 31) | ((rn & 31) << 5) | ((offset12 & 0xfff) << 10)); } static inline uint32_t ldrb_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38400400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrb_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38400c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsb_offset(uint8_t rn, uint8_t rt, uint16_t offset12) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x39c00000 | (rt & 31) | ((rn & 31) << 5) | ((offset12 & 0xfff) << 10)); } static inline uint32_t ldrsb_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38c00400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsb_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38c00c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsb64_offset(uint8_t rn, uint8_t rt, uint16_t offset12) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x39800000 | (rt & 31) | ((rn & 31) << 5) | ((offset12 & 0xfff) << 10)); } static inline uint32_t ldrsb64_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38800400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsb64_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38800c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrh_offset(uint8_t rn, uint8_t rt, uint16_t offset13) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x79400000 | (rt & 31) | ((rn & 31) << 5) | (((offset13 >> 1) & 0xfff) << 10)); } static inline uint32_t ldrh_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78400400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrh_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78400c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsh_offset(uint8_t rn, uint8_t rt, uint16_t offset13) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x79c00000 | (rt & 31) | ((rn & 31) << 5) | (((offset13 >> 1) & 0xfff) << 10)); } static inline uint32_t ldrsh_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78c00400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsh_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78c00c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsh64_offset(uint8_t rn, uint8_t rt, uint16_t offset13) { return I32(0x79800000 | (rt & 31) | ((rn & 31) << 5) | (((offset13 >> 1) & 0xfff) << 10)); } static inline uint32_t ldrsh64_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78800400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsh64_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78800c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsw_offset(uint8_t rn, uint8_t rt, uint16_t offset14) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb9800000 | (rt & 31) | ((rn & 31) << 5) | (((offset14 >> 2) & 0xfff) << 10)); } static inline uint32_t ldrsw_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8800400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldrsw_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8800c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t str_offset(uint8_t rn, uint8_t rt, uint16_t offset14) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb9000000 | (rt & 31) | ((rn & 31) << 5) | (((offset14 >> 2) & 0xfff) << 10)); } static inline uint32_t str_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8000400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t str_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8000c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t str64_offset(uint8_t rn, uint8_t rt, uint16_t offset15) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf9000000 | (rt & 31) | ((rn & 31) << 5) | (((offset15 >> 3) & 0xfff) << 10)); } static inline uint32_t str64_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf8000400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t str64_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf8000c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t strh_offset(uint8_t rn, uint8_t rt, uint16_t offset13) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x79000000 | (rt & 31) | ((rn & 31) << 5) | (((offset13 >> 1) & 0xfff) << 10)); } static inline uint32_t strh_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78000400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t strh_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78000c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t strb_offset(uint8_t rn, uint8_t rt, uint16_t offset12) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x39000000 | (rt & 31) | ((rn & 31) << 5) | ((offset12 & 0xfff) << 10)); } static inline uint32_t strb_offset_postindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38000400 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t strb_offset_preindex(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38000c00 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } /* Load/Store exclusive */ static inline uint32_t ldxr(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x885f7c00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldxr64(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xc85f7c00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldxrh(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x485f7c00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldxrb(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x085f7c00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldxp(uint8_t rn, uint8_t rt, uint8_t rt2) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rt2); return I32(0x887f0000 | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldxp64(uint8_t rn, uint8_t rt, uint8_t rt2) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rt2); return I32(0xc87f0000 | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stxr(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x88007c00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stxr64(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xc8007c00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stxrh(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x48007c00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stxrb(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x08007c00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stxp(uint8_t rn, uint8_t rt, uint8_t rt2, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rt2); ASSERT_REG(rs); return I32(0x88200000 | ((rs & 31) << 16) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stxp64(uint8_t rn, uint8_t rt, uint8_t rt2, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rt2); ASSERT_REG(rs); return I32(0xc8200000 | ((rs & 31) << 16) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } /* Load-Acquire/Store-Release exclusive */ static inline uint32_t ldaxr(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x885ffc00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldaxr64(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xc85ffc00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldaxrh(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x485ffc00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldaxrb(uint8_t rn, uint8_t rt) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x085ffc00 | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldaxp(uint8_t rn, uint8_t rt, uint8_t rt2) { ASSERT_REG(rt); ASSERT_REG(rt2); ASSERT_REG(rn); return I32(0x887f8000 | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t ldaxp64(uint8_t rn, uint8_t rt, uint8_t rt2) { ASSERT_REG(rt); ASSERT_REG(rt2); ASSERT_REG(rn); return I32(0xc87f8000 | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stlxr(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rs); return I32(0x8800fc00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stlxr64(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rs); return I32(0xc800fc00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stlxrh(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rs); return I32(0x4800fc00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stlxrb(uint8_t rn, uint8_t rt, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rn); ASSERT_REG(rs); return I32(0x0800fc00 | ((rs & 31) << 16) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stlxp(uint8_t rn, uint8_t rt, uint8_t rt2, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rt2); ASSERT_REG(rn); ASSERT_REG(rs); return I32(0x88208000 | ((rs & 31) << 16) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } static inline uint32_t stlxp64(uint8_t rn, uint8_t rt, uint8_t rt2, uint8_t rs) { ASSERT_REG(rt); ASSERT_REG(rt2); ASSERT_REG(rn); ASSERT_REG(rs); return I32(0xc8208000 | ((rs & 31) << 16) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (rt & 31)); } /* Load/Store pair */ static inline uint32_t ldp(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x29400000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t ldpsw(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x69400000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t ldp64(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0xa9400000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 8) & 0x7f) << 15)); } static inline uint32_t ldp_postindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x28c00000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t ldpsw_postindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x68c00000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t ldp64_postindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0xa8c00000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 8) & 0x7f) << 15)); } static inline uint32_t ldp_preindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x29c00000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t ldpsw_preindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x69c00000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t ldp64_preindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0xa9c00000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 8) & 0x7f) << 15)); } static inline uint32_t stp(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x29000000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t stp64(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0xa9000000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 8) & 0x7f) << 15)); } static inline uint32_t stp_postindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x28800000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t stp64_postindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0xa8800000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 8) & 0x7f) << 15)); } static inline uint32_t stp_preindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0x29800000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 4) & 0x7f) << 15)); } static inline uint32_t stp64_preindex(uint8_t rn, uint8_t rt1, uint8_t rt2, int16_t imm) { ASSERT_REG(rn); ASSERT_REG(rt1); ASSERT_REG(rt2); return I32(0xa9800000 | (rt1 & 31) | ((rt2 & 31) << 10) | ((rn & 31) << 5) | (((imm / 8) & 0x7f) << 15)); } /* Load/Store with unscaled offset */ static inline uint32_t ldur_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8400000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldur64_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf8400000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldurb_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38400000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldursb_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38c00000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldursb64_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38800000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldurh_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78400000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldursh_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78c00000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldursh64_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78800000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t ldursw_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8800000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t stur_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xb8000000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t stur64_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0xf8000000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t sturb_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x38000000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t sturh_offset(uint8_t rn, uint8_t rt, int16_t offset9) { ASSERT_REG(rt); ASSERT_REG(rn); return I32(0x78000000 | (rt & 31) | ((rn & 31) << 5) | ((offset9 & 0x1ff) << 12)); } /* Data processing: immediate */ static inline uint32_t add_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x11000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t add64_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x91000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t adds_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x31000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t adds64_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xb1000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t sub_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x51000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t sub64_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xd1000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t subs_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x71000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t subs64_immed(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xf1000000 | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t cmp_immed(uint8_t rn, uint16_t imm12) { return subs_immed(31, rn, imm12); } static inline uint32_t cmp64_immed(uint8_t rn, uint16_t imm12) { return subs64_immed(31, rn, imm12); } static inline uint32_t cmn_immed(uint8_t rn, uint16_t imm12) { return adds_immed(31, rn, imm12); } static inline uint32_t cmn64_immed(uint8_t rn, uint16_t imm12) { return adds64_immed(31, rn, imm12); } static inline uint32_t add_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x11000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t add64_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x91000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t adds_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x31000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t adds64_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xb1000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t sub_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x51000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t sub64_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xd1000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t subs_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x71000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t subs64_immed_lsl12(uint8_t rd, uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xf1000000 | (1 << 22) | ((imm12 & 0xfff) << 10) | ((rn & 31) << 5) | (rd & 31)); } static inline uint32_t cmp_immed_lsl12(uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); return subs_immed_lsl12(31, rn, imm12); } static inline uint32_t cmp64_immed_lsl12(uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); return subs64_immed_lsl12(31, rn, imm12); } static inline uint32_t cmn_immed_lsl12(uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); return adds_immed_lsl12(31, rn, imm12); } static inline uint32_t cmn64_immed_lsl12(uint8_t rn, uint16_t imm12) { ASSERT_REG(rn); return adds64_immed_lsl12(31, rn, imm12); } static inline uint32_t and_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x12000000 | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t and64_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror, uint8_t n) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x92000000 | (n ? (1 << 22) : 0) | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t bic_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); ASSERT_REG(rd); return and_immed(rd, rn, 32 - width, ror - width); } static inline uint32_t bic64_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror, uint8_t n) { ASSERT_REG(rn); ASSERT_REG(rd); return and64_immed(rd, rn, 64 - width, ror - width, n); } static inline uint32_t ands_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x72000000 | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t ands64_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror, uint8_t n) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xf2000000 | (n ? (1 << 22) : 0) | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t bics_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); ASSERT_REG(rd); return ands_immed(rd, rn, 32 - width, ror - width); } static inline uint32_t eor_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x52000000 | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t eor64_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror, uint8_t n) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xd2000000 | (n ? (1 << 22) : 0) | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t orr_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x32000000 | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t orr64_immed(uint8_t rd, uint8_t rn, uint8_t width, uint8_t ror, uint8_t n) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xb2000000 | (n ? (1 << 22) : 0) | (rd & 31) | ((rn & 31) << 5) | (((width - 1) & 0x3f) << 10) | ((ror & 0x3f) << 16)); } static inline uint32_t tst_immed(uint8_t rn, uint8_t width, uint8_t ror) { ASSERT_REG(rn); return ands_immed(31, rn, width, ror); } static inline uint32_t tst64_immed(uint8_t rn, uint8_t width, uint8_t ror, uint8_t n) { ASSERT_REG(rn); return ands64_immed(31, rn, width, ror, n); } /* Data processing: bitfields */ static inline uint32_t bfm(uint8_t rd, uint8_t rn, uint8_t immr, uint8_t imms) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x33000000 | (rd & 31) | ((rn & 31) << 5) | ((immr & 0x3f) << 16) | ((imms & 0x3f) << 10)); } static inline uint32_t bfm64(uint8_t rd, uint8_t rn, uint8_t immr, uint8_t imms) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xb3400000 | (rd & 31) | ((rn & 31) << 5) | ((immr & 0x3f) << 16) | ((imms & 0x3f) << 10)); } static inline uint32_t sbfm(uint8_t rd, uint8_t rn, uint8_t immr, uint8_t imms) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x13000000 | (rd & 31) | ((rn & 31) << 5) | ((immr & 0x3f) << 16) | ((imms & 0x3f) << 10)); } static inline uint32_t sbfm64(uint8_t rd, uint8_t rn, uint8_t immr, uint8_t imms) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x93400000 | (rd & 31) | ((rn & 31) << 5) | ((immr & 0x3f) << 16) | ((imms & 0x3f) << 10)); } static inline uint32_t ubfm(uint8_t rd, uint8_t rn, uint8_t immr, uint8_t imms) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0x53000000 | (rd & 31) | ((rn & 31) << 5) | ((immr & 0x3f) << 16) | ((imms & 0x3f) << 10)); } static inline uint32_t ubfm64(uint8_t rd, uint8_t rn, uint8_t immr, uint8_t imms) { ASSERT_REG(rn); ASSERT_REG(rd); return I32(0xd3400000 | (rd & 31) | ((rn & 31) << 5) | ((immr & 0x3f) << 16) | ((imms & 0x3f) << 10)); } static inline uint32_t bfi(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return bfm(rd, rn, 31 & (32-lsb), width - 1); } static inline uint32_t bfi64(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return bfm64(rd, rn, 63 & (64-lsb), width - 1); } static inline uint32_t bfxil(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return bfm(rd, rn, lsb, lsb + width - 1); } static inline uint32_t bfxil64(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return bfm64(rd, rn, lsb, lsb + width - 1); } static inline uint32_t sbfx(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm(rd, rn, lsb, lsb + width - 1); } static inline uint32_t sbfx64(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm64(rd, rn, lsb, lsb + width - 1); } static inline uint32_t sbfiz(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm(rd, rn, 31 & (32-lsb), width - 1); } static inline uint32_t sbfiz64(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm64(rd, rn, 63 & (64-lsb), width - 1); } static inline uint32_t ubfx(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm(rd, rn, lsb, lsb + width - 1); } static inline uint32_t ubfx64(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm64(rd, rn, lsb, lsb + width - 1); } static inline uint32_t ubfiz(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm(rd, rn, 31 & (32-lsb), width - 1); } static inline uint32_t ubfiz64(uint8_t rd, uint8_t rn, uint8_t lsb, uint8_t width) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm64(rd, rn, 63 & (64-lsb), width - 1); } /* Data processing: register extract */ static inline uint32_t extr(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x13800000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((lsb & 63) << 10)); } static inline uint32_t extr64(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x93c00000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((lsb & 63) << 10)); } /* Data processing: shift immediate */ static inline uint32_t asr(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return sbfm(rd, rn, lsb, 31); } static inline uint32_t asr64(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return sbfm64(rd, rn, lsb, 63); } static inline uint32_t lsl(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return ubfm(rd, rn, 31 & (32 - lsb), 31 - lsb); } static inline uint32_t lsl64(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return ubfm64(rd, rn, 63 & (64 - lsb), 63 - lsb); } static inline uint32_t lsr(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return ubfm(rd, rn, lsb, 31); } static inline uint32_t lsr64(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return ubfm64(rd, rn, lsb, 63); } static inline uint32_t ror(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return extr(rd, rn, rn, lsb); } static inline uint32_t ror64(uint8_t rd, uint8_t rn, uint8_t lsb) { ASSERT_REG(rd); ASSERT_REG(rn); return extr64(rd, rn, rn, lsb); } /* Data processing: extending */ static inline uint32_t sxtb(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm(rd, rn, 0, 7); } static inline uint32_t sxtb64(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm64(rd, rn, 0, 7); } static inline uint32_t sxth(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm(rd, rn, 0, 15); } static inline uint32_t sxth64(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm64(rd, rn, 0, 15); } static inline uint32_t sxtw64(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return sbfm64(rd, rn, 0, 31); } static inline uint32_t uxtb(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm(rd, rn, 0, 7); } static inline uint32_t uxtb64(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm64(rd, rn, 0, 7); } static inline uint32_t uxth(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm(rd, rn, 0, 15); } static inline uint32_t uxth64(uint8_t rd, uint8_t rn) { ASSERT_REG(rn); ASSERT_REG(rd); return ubfm64(rd, rn, 0, 15); } /* Data processing: move */ static inline uint32_t mov_immed_u16(uint8_t reg, uint16_t val, uint8_t shift16) { ASSERT_REG(reg); return I32(0x52800000 | ((shift16 & 3) << 21) | (val << 5) | (reg & 31)); } static inline uint32_t mov64_immed_u16(uint8_t reg, uint16_t val, uint8_t shift16) { ASSERT_REG(reg); return I32(0xd2800000 | ((shift16 & 3) << 21) | (val << 5) | (reg & 31)); } static inline uint32_t movk_immed_u16(uint8_t reg, uint16_t val, uint8_t shift16) { ASSERT_REG(reg); return I32(0x72800000 | ((shift16 & 3) << 21) | (val << 5) | (reg & 31)); } static inline uint32_t movk64_immed_u16(uint8_t reg, uint16_t val, uint8_t shift16) { ASSERT_REG(reg); return I32(0xf2800000 | ((shift16 & 3) << 21) | (val << 5) | (reg & 31)); } static inline uint32_t movn_immed_u16(uint8_t reg, uint16_t val, uint8_t shift16) { ASSERT_REG(reg); return I32(0x12800000 | ((shift16 & 3) << 21) | (val << 5) | (reg & 31)); } static inline uint32_t movn64_immed_u16(uint8_t reg, uint16_t val, uint8_t shift16) { ASSERT_REG(reg); return I32(0x92800000 | ((shift16 & 3) << 21) | (val << 5) | (reg & 31)); } static inline uint32_t movw_immed_u16(uint8_t reg, uint16_t val) { ASSERT_REG(reg); return mov_immed_u16(reg, val, 0); } static inline uint32_t movt_immed_u16(uint8_t reg, uint16_t val) { ASSERT_REG(reg); return movk_immed_u16(reg, val, 1); } static inline uint32_t mov_immed_s8(uint8_t reg, int8_t val) { ASSERT_REG(reg); if (val < 0) return movn_immed_u16(reg, -val - 1, 0); else return mov_immed_u16(reg, val, 0); } static inline uint32_t mov_immed_u8(uint8_t reg, uint8_t val) { ASSERT_REG(reg); return mov_immed_u16(reg, val, 0); } typedef enum { LSL = 0, LSR = 1, ASR = 2, ROR = 3 } shift_t; /* Data processing: register */ static inline uint32_t add_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x0b000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t add64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x8b000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t adds_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x2b000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t adds64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xab000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t sub_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x4b000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t sub64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xcb000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t subs_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x6b000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t subs64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xeb000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t cmn_reg(uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { return adds_reg(31, rn, rm, shift, amount); } static inline uint32_t cmn64_reg(uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { return adds64_reg(31, rn, rm, shift, amount); } static inline uint32_t cmp_reg(uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { return subs_reg(31, rn, rm, shift, amount); } static inline uint32_t cmp64_reg(uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { return subs64_reg(31, rn, rm, shift, amount); } static inline uint32_t ccmp_reg(uint8_t rn, uint8_t rm, uint8_t alt_cc, uint8_t cond) { ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x7a400000 | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12) | (alt_cc & 15)); } static inline uint32_t ccmp64_reg(uint8_t rn, uint8_t rm, uint8_t alt_cc, uint8_t cond) { ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xfa400000 | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12) | (alt_cc & 15)); } static inline uint32_t ccmn_reg(uint8_t rn, uint8_t rm, uint8_t alt_cc, uint8_t cond) { ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x3a400000 | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12) | (alt_cc & 15)); } static inline uint32_t ccmn64_reg(uint8_t rn, uint8_t rm, uint8_t alt_cc, uint8_t cond) { ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xba400000 | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12) | (alt_cc & 15)); } static inline uint32_t neg_reg(uint8_t rd, uint8_t rm, shift_t shift, uint8_t amount) { return sub_reg(rd, 31, rm, shift, amount); } static inline uint32_t neg64_reg(uint8_t rd, uint8_t rm, shift_t shift, uint8_t amount) { return sub64_reg(rd, 31, rm, shift, amount); } static inline uint32_t negs_reg(uint8_t rd, uint8_t rm, shift_t shift, uint8_t amount) { return subs_reg(rd, 31, rm, shift, amount); } static inline uint32_t negs64_reg(uint8_t rd, uint8_t rm, shift_t shift, uint8_t amount) { return subs64_reg(rd, 31, rm, shift, amount); } /* Data processing: register with extend */ static inline uint32_t add_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x0b200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t add64_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x8b200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t adds_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x2b200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t adds64_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xab200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t sub_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x4b200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t sub64_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xcb200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t subs_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x6b200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t subs64_reg_ext(uint8_t rd, uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xeb200000 | ((lsl & 7) << 10) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((extend & 7) << 13)); } static inline uint32_t cmn_reg_ext(uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return adds_reg_ext(31, rn, rm, extend, lsl); } static inline uint32_t cmn64_reg_ext(uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return adds64_reg_ext(31, rn, rm, extend, lsl); } static inline uint32_t cmp_reg_ext(uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return subs_reg_ext(31, rn, rm, extend, lsl); } static inline uint32_t cmp64_reg_ext(uint8_t rn, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return subs64_reg_ext(31, rn, rm, extend, lsl); } static inline uint32_t neg_reg_ext(uint8_t rd, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return sub_reg_ext(rd, 31, rm, extend, lsl); } static inline uint32_t neg64_reg_ext(uint8_t rd, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return sub64_reg_ext(rd, 31, rm, extend, lsl); } static inline uint32_t negs_reg_ext(uint8_t rd, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return subs_reg_ext(rd, 31, rm, extend, lsl); } static inline uint32_t negs64_reg_ext(uint8_t rd, uint8_t rm, reg_extend_t extend, uint8_t lsl) { return subs64_reg_ext(rd, 31, rm, extend, lsl); } /* Data prcessing: arithmetic with carry */ static inline uint32_t adc(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1a000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t adc64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9a000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t adcs(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x3a000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t adcs64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xba000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t sbc(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x5a000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t sbc64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xda000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t sbcs(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x7a000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t sbcs64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xfa000000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t ngc(uint8_t rd, uint8_t rm) { return sbc(rd, 31, rm); } static inline uint32_t ngc64(uint8_t rd, uint8_t rm) { return sbc64(rd, 31, rm); } static inline uint32_t ngcs(uint8_t rd, uint8_t rm) { return sbcs(rd, 31, rm); } static inline uint32_t ngcs64(uint8_t rd, uint8_t rm) { return sbcs64(rd, 31, rm); } /* Data processing: conditional select */ static inline uint32_t csel(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t cond) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1a800000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12)); } static inline uint32_t csel64(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t cond) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9a800000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 6) | ((cond & 15) << 12)); } static inline uint32_t csinc(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t cond) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1a800400 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12)); } static inline uint32_t csinc64(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t cond) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9a800400 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12)); } static inline uint32_t csinv(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t cond) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x5a800000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12)); } static inline uint32_t csinv64(uint8_t rd, uint8_t rn, uint8_t rm, uint8_t cond) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xda800000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((cond & 15) << 12)); } static inline uint32_t csetm(uint8_t rd, uint8_t cond) { return csinv(rd, 31, 31, cond ^ 1); } static inline uint32_t csetm64(uint8_t rd, uint8_t cond) { return csinv64(rd, 31, 31, cond ^ 1); } static inline uint32_t cset(uint8_t rd, uint8_t cond) { return csinc(rd, 31, 31, cond ^ 1); } static inline uint32_t cset64(uint8_t rd, uint8_t cond) { return csinc64(rd, 31, 31, cond ^ 1); } /* Data processing: logic */ static inline uint32_t and_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x0a000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t and64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x8a000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t ands_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x6a000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t ands64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xea000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t bic_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x0a200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t bic64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x8a200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t bics_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x6a200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t bics64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xea200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t eon_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x4a200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t eon64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xca200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t eor_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x4a000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t eor64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xca000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t orr_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x2a000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t orr64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xaa000000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t orn_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x2a200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t orn64_reg(uint8_t rd, uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0xaa200000 | (shift << 22) | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16) | ((amount & 63) << 10)); } static inline uint32_t mvn_reg(uint8_t rd, uint8_t rm, shift_t shift, uint8_t amount) { return orn_reg(rd, 31, rm, shift, amount); } static inline uint32_t mvn64_reg(uint8_t rd, uint8_t rm, shift_t shift, uint8_t amount) { return orn64_reg(rd, 31, rm, shift, amount); } static inline uint32_t tst_reg(uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { return ands_reg(31, rn, rm, shift, amount); } static inline uint32_t tst64_reg(uint8_t rn, uint8_t rm, shift_t shift, uint8_t amount) { return ands64_reg(31, rn, rm, shift, amount); } /* Data processing: move register */ static inline uint32_t mov_reg(uint8_t rd, uint8_t rm) {ASSERT_REG(rd); ASSERT_REG(rm); return orr_reg(rd, 31, rm, LSL, 0); } static inline uint32_t mov64_reg(uint8_t rd, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rm); return orr64_reg(rd, 31, rm, LSL, 0); } /* Data processing: shift reg */ static inline uint32_t asrv(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1ac02800 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t asrv64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ac02800 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t lslv(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1ac02000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t lslv64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ac02000 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t lsrv(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1ac02400 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t lsrv64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ac02400 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t rorv(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1ac02c00 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t rorv64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ac02c00 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } /* Data processing: multiply */ static inline uint32_t madd(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1b000000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t madd64(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9b000000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t msub(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1b008000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t msub64(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9b008000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t mneg(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return msub(rd, 31, rn, rm); } static inline uint32_t mneg64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return msub64(rd, 31, rn, rm); } static inline uint32_t mul(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return madd(rd, 31, rn, rm); } static inline uint32_t mul64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return madd64(rd, 31, rn, rm); } static inline uint32_t smaddl(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9b200000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t smsubl(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9b208000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t smnegl(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return smsubl(rd, 31, rn, rm); } static inline uint32_t smull(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return smaddl(rd, 31, rn, rm); } static inline uint32_t umaddl(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ba00000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t umsubl(uint8_t rd, uint8_t ra, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(ra); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ba08000 | (rd & 31) | ((rn & 31) << 5) | ((ra & 31) << 10) | ((rm & 31) << 16)); } static inline uint32_t umnegl(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return umsubl(rd, 31, rn, rm); } static inline uint32_t umull(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return umaddl(rd, 31, rn, rm); } /* Data processing: divide */ static inline uint32_t sdiv(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1ac00c00 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t sdiv64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ac00c00 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t udiv(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x1ac00800 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } static inline uint32_t udiv64(uint8_t rd, uint8_t rn, uint8_t rm) { ASSERT_REG(rd); ASSERT_REG(rn); ASSERT_REG(rm); return I32(0x9ac00800 | (rd & 31) | ((rn & 31) << 5) | ((rm & 31) << 16)); } /* Data processing: bit operations */ static inline uint32_t cls(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0x5ac01400 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t cls64(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0xdac01400 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t clz(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0x5ac01000 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t clz64(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0xdac01000 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rbit(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0x5ac00000 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rbit64(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0xdac00000 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rev(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0x5ac00800 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rev16(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0x5ac00400 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rev16_64(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0xdac00400 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rev32(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0xdac00800 | (rd & 31) | ((rn & 31) << 5)); } static inline uint32_t rev64(uint8_t rd, uint8_t rn) { ASSERT_REG(rd); ASSERT_REG(rn); return I32(0xdac00c00 | (rd & 31) | ((rn & 31) << 5)); } /* Floating point */ static inline uint32_t fabsd(uint8_t v_dst, uint8_t v_src) { return I32(0x1e60c000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t fabss(uint8_t v_dst, uint8_t v_src) { return I32(0x1e20c000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t faddd(uint8_t v_dst, uint8_t v_first, uint8_t v_second) { return I32(0x1e602800 | (v_dst & 31) | ((v_first & 31) << 5) | ((v_second & 31) << 16)); } static inline uint32_t fadds(uint8_t v_dst, uint8_t v_first, uint8_t v_second) { return I32(0x1e202800 | (v_dst & 31) | ((v_first & 31) << 5) | ((v_second & 31) << 16)); } static inline uint32_t fcmpd(uint8_t v_dst, uint8_t v_src) { return INSN_TO_LE(0x1e602000 | ((v_dst & 31) << 5) | ((v_src & 31) << 16)); } static inline uint32_t fcmps(uint8_t v_dst, uint8_t v_src) { return INSN_TO_LE(0x1e202000 | ((v_dst & 31) << 5) | ((v_src & 31) << 16)); } static inline uint32_t fcmpzd(uint8_t v_src) { return INSN_TO_LE(0x1e602008 | ((v_src & 31) << 5)); } static inline uint32_t fcmpzs(uint8_t v_src) { return INSN_TO_LE(0x1e202008 | ((v_src & 31) << 5)); } static inline uint32_t fcpyd(uint8_t v_dst, uint8_t v_src) { return I32(0x1e604000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t fcvtds(uint8_t d_dst, uint8_t s_src) { return I32(0x1e22c000 | (d_dst & 31) | ((s_src & 31) << 5)); } static inline uint32_t fcvtsd(uint8_t s_dst, uint8_t d_src) { return I32(0x1e624000 | (s_dst & 31) | ((d_src & 31) << 5)); } static inline uint32_t fdivd(uint8_t v_dst, uint8_t v_dividend, uint8_t v_divisor) { return I32(0x1e601800 | (v_dst & 31) | ((v_dividend & 31) << 5) | ((v_divisor & 31) << 16)); } static inline uint32_t fldd(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xfc400000 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fldd_preindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xfc400c00 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fldd_postindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xfc400400 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fldd_pimm(uint8_t v_dst, uint8_t base, uint16_t offset12) { return I32(0xfd400000 | ((base & 31) << 5) | (v_dst & 31) | ((offset12 & 0xfff) << 10)); } static inline uint32_t flds_preindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xbc400c00 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t flds_postindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xbc400400 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t flds(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xbc400000 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t flds_pimm(uint8_t v_dst, uint8_t base, uint16_t offset12) { return I32(0xbd400000 | ((base & 31) << 5) | (v_dst & 31) | ((offset12 & 0xfff) << 10)); } static inline uint32_t fldq_preindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0x3cc00c00 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fldq_postindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0x3cc00400 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fldq(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0x3cc00000 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fldq_pimm(uint8_t v_dst, uint8_t base, uint16_t offset12) { return I32(0x3dc00000 | ((base & 31) << 5) | (v_dst & 31) | ((offset12 & 0xfff) << 10)); } static inline uint32_t fldd_pcrel(uint8_t v_dst, int32_t imm19) { return I32(0x5c000000 | (v_dst & 31) | ((imm19 & 0x7ffff) << 5)); } static inline uint32_t flds_pcrel(uint8_t v_dst, int32_t imm19) { return I32(0x1c000000 | (v_dst & 31) | ((imm19 & 0x7ffff) << 5)); } static inline uint32_t fldq_pcrel(uint8_t v_dst, int32_t imm19) { return I32(0x9c000000 | (v_dst & 31) | ((imm19 & 0x7ffff) << 5)); } enum TS { TS_B = 1, TS_H = 2, TS_S = 4, TS_D = 8 }; static inline uint32_t mov_reg_to_simd(uint8_t v_dst, enum TS ts, uint8_t index, uint8_t rn) { return I32(0x4e001c00 | (ts == TS_B ? ((index & 0xf) << 17) : ts == TS_H ? ((index & 7) << 18) : ts == TS_S ? ((index & 3) << 19) : ts == TS_D ? ((index & 1) << 20) : 0) | ((ts & 31) << 16) | (v_dst & 31) | ((rn & 31) << 5)); } static inline uint32_t mov_simd_to_reg(uint8_t rd, uint8_t v_src, enum TS ts, uint8_t index) { return I32((ts == TS_D ? 0x4e003c00 : 0x0e003c00) | (ts == TS_B ? ((index & 0xf) << 17) : ts == TS_H ? ((index & 7) << 18) : ts == TS_S ? ((index & 3) << 19) : ts == TS_D ? ((index & 1) << 20) : 0) | ((ts & 31) << 16) | (rd & 31) | ((v_src & 31) << 5)); } static inline uint32_t fmsr(uint8_t v_dst, uint8_t src) { return mov_reg_to_simd(v_dst, TS_S, 0, src); } static inline uint32_t fmdhr(uint8_t v_dst, uint8_t src) { return mov_reg_to_simd(v_dst, TS_S, 1, src); } static inline uint32_t fmdlr(uint8_t v_dst, uint8_t src) { return mov_reg_to_simd(v_dst, TS_S, 0, src); } static inline uint32_t fmdxr(uint8_t v_dst, uint8_t src) { return mov_reg_to_simd(v_dst, TS_D, 0, src); } static inline uint32_t fmrs(uint8_t dst, uint8_t v_src) { return mov_simd_to_reg(dst, v_src, TS_S, 0); } static inline uint32_t fmov_from_reg(uint8_t v_dst, uint8_t src) { return I32(0x9e670000 | (v_dst & 31) | ((src & 31) << 5)); } static inline uint32_t fmuld(uint8_t v_dst, uint8_t v_first, uint8_t v_second) { return I32(0x1e600800 | (v_dst & 31) | ((v_first & 31) << 5) | ((v_second & 31) << 16)); } static inline uint32_t fnegd(uint8_t v_dst, uint8_t v_src) { return I32(0x1e614000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t fsqrtd(uint8_t v_dst, uint8_t v_src) { return I32(0x1e61c000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t fsubd(uint8_t v_dst, uint8_t v_first, uint8_t v_second) { return I32(0x1e603800 | (v_dst & 31) | ((v_first & 31) << 5) | ((v_second & 31) << 16)); } static inline uint32_t fstd_preindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xfc000c00 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fstd_postindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xfc000400 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fstd(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xfc000000 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fstd_pimm(uint8_t v_dst, uint8_t base, uint16_t offset12) { return I32(0xfd000000 | ((base & 31) << 5) | (v_dst & 31) | ((offset12 & 0xfff) << 10)); } static inline uint32_t fsts_preindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xbc000c00 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fsts_postindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xbc000400 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fsts(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0xbc000000 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fsts_pimm(uint8_t v_dst, uint8_t base, uint16_t offset12) { return I32(0xbd000000 | ((base & 31) << 5) | (v_dst & 31) | ((offset12 & 0xfff) << 10)); } static inline uint32_t fstq_preindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0x3c800c00 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fstq_postindex(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0x3c800400 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fstq(uint8_t v_dst, uint8_t base, int16_t offset9) { return I32(0x3c800000 | ((base & 31) << 5) | (v_dst & 31) | ((offset9 & 0x1ff) << 12)); } static inline uint32_t fstq_pimm(uint8_t v_dst, uint8_t base, uint16_t offset12) { return I32(0x3d800000 | ((base & 31) << 5) | (v_dst & 31) | ((offset12 & 0xfff) << 10)); } static inline uint32_t fmov_f64(uint8_t v_dst, uint8_t imm) { return I32(0x1e601000 | (imm << 13) | (v_dst & 31)); } static inline uint32_t fmov_f32(uint8_t v_dst, uint8_t imm) { return I32(0x1e201000 | (imm << 13) | (v_dst & 31)); } static inline uint32_t fmov(uint8_t v_dst, uint8_t imm) { return fmov_f64(v_dst, imm); } static inline uint32_t movi_f64(uint8_t v_dst, uint8_t imm) { return I32(0x2f00e400 | (v_dst & 31) | ((imm & 31) << 5) | (((imm > 5) & 7) << 16)); } static inline uint32_t movi_v64(uint8_t v_dst, uint8_t imm) { return I32(0x6f00e400 | (v_dst & 31) | ((imm & 31) << 5) | (((imm > 5) & 7) << 16)); } static inline uint32_t fmov_0(uint8_t v_dst) { return movi_f64(v_dst, 0); } static inline uint32_t fmov_1(uint8_t v_dst) { return fmov_f64(v_dst, 112); } static inline uint32_t scvtf_32toS(uint8_t v_dst, uint8_t src) { return I32(0x1e220000 | (v_dst & 31) | ((src & 31) << 5)); } static inline uint32_t scvtf_32toD(uint8_t v_dst, uint8_t src) { return I32(0x1e620000 | (v_dst & 31) | ((src & 31) << 5)); } static inline uint32_t scvtf_64toS(uint8_t v_dst, uint8_t src) { return I32(0x9e220000 | (v_dst & 31) | ((src & 31) << 5)); } static inline uint32_t scvtf_64toD(uint8_t v_dst, uint8_t src) { return I32(0x9e620000 | (v_dst & 31) | ((src & 31) << 5)); } static inline uint32_t fcvtzs(uint8_t dst, uint8_t v_src, uint8_t sf, uint8_t ftype) { return I32(0x1e380000 | ((sf & 1) << 31) | ((ftype & 3) << 22) | ((v_src & 31) << 5) | (dst & 31)); } static inline uint32_t fcvtzs_Sto32(uint8_t dst, uint8_t v_src) { return fcvtzs(dst, v_src, 0, 0); } static inline uint32_t fcvtzs_Sto64(uint8_t dst, uint8_t v_src) { return fcvtzs(dst, v_src, 1, 0); } static inline uint32_t fcvtzs_Dto32(uint8_t dst, uint8_t v_src) { return fcvtzs(dst, v_src, 0, 1); } static inline uint32_t fcvtzs_Dto64(uint8_t dst, uint8_t v_src) { return fcvtzs(dst, v_src, 1, 1); } static inline uint32_t frint64x(uint8_t v_dst, uint8_t v_src) { return I32(0x1e67c000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t frint64z(uint8_t v_dst, uint8_t v_src) { return I32(0x1e65c000 | (v_dst & 31) | ((v_src & 31) << 5)); } static inline uint32_t vadd_2d(uint8_t v_dst, uint8_t v_rn, uint8_t v_rm) { return I32(0x4ee08400 | (v_dst & 31) | ((v_rn & 31) << 5) | ((v_rm & 31) << 16)); } static inline uint32_t vldur(uint8_t rn, uint8_t v_rt, uint16_t imm9) { return I32(0x3cc00000 | ((rn & 31) << 5) | (v_rt & 31) | ((imm9 & 0x1ff) << 12)); } static inline uint32_t vldr_pcrel(uint8_t v_rt, uint32_t imm19) { return I32(0x9c000000 | (v_rt & 31) | ((imm19 & 0x7ffff) << 5)); } #if 0 enum VFP_REG { FPSID = 0, FPSCR = 1, FPEXT = 8 }; static inline uint32_t fmrx_cc(uint8_t cc, enum VFP_REG sr, uint8_t src) { return INSN_TO_LE(0x0ee00a10 | (cc << 28) | (src << 12) | (sr << 16)); } static inline uint32_t fmrx(enum VFP_REG sr, uint8_t src) { return fmrx_cc(ARM_CC_AL, sr, src); } static inline uint32_t fmxr_cc(uint8_t cc, uint8_t dest, enum VFP_REG sr) { return INSN_TO_LE(0x0ef00a10 | (cc << 28) | (dest << 12) | (sr << 16)); } static inline uint32_t fmxr(uint8_t dest, enum VFP_REG sr) { return fmxr_cc(ARM_CC_AL, dest, sr); } static inline uint32_t fsitod_cc(uint8_t cc, uint8_t d_dst, uint8_t s_src) { return INSN_TO_LE(0x0eb80bc0 | (cc << 28) | (d_dst << 12) | (s_src >> 1) | (s_src & 1 ? 0x20:0)); } static inline uint32_t fsitod(uint8_t d_dst, uint8_t s_src) { return fsitod_cc(ARM_CC_AL, d_dst, s_src); } static inline uint32_t ftosid_cc(uint8_t cc, uint8_t s_dst, uint8_t d_src) { return INSN_TO_LE(0x0ebd0b40 | (cc << 28) | ((s_dst >> 1) << 12) | d_src | (s_dst & 1 ? (1 << 22):0)); } static inline uint32_t ftosid(uint8_t s_dst, uint8_t d_src) { return ftosid_cc(ARM_CC_AL, s_dst, d_src); } static inline uint32_t ftosidrz_cc(uint8_t cc, uint8_t s_dst, uint8_t d_src) { return INSN_TO_LE(0x0ebd0bc0 | (cc << 28) | ((s_dst >> 1) << 12) | d_src | (s_dst & 1 ? (1 << 22):0)); } static inline uint32_t ftosidrz(uint8_t s_dst, uint8_t d_src) { return ftosidrz_cc(ARM_CC_AL, s_dst, d_src); } #endif #include static inline __attribute__((always_inline)) uint32_t * EMIT_GetFPUFlags(uint32_t * ptr, uint8_t fpsr) { uint8_t tmp_reg = RA_AllocARMRegister(&ptr); #if 1 *ptr++ = bic_immed(fpsr, fpsr, 4, 8); *ptr++ = get_nzcv(tmp_reg); *ptr++ = bic_immed(tmp_reg, tmp_reg, 1, 3); *ptr++ = orr_reg(fpsr, fpsr, tmp_reg, LSR, 4); #else *ptr++ = get_nzcv(tmp_reg); *ptr++ = bic_immed(tmp_reg, tmp_reg, 1, 3); *ptr++ = ror(tmp_reg, tmp_reg, 28); *ptr++ = bfi(fpsr, tmp_reg, 24, 4); #endif RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_ClearFlags(uint32_t * ptr, uint8_t cc, uint8_t flags) { uint8_t tmp_reg; switch (flags) { case 0: break; case 1: *ptr++ = bic_immed(cc, cc, 1, 0); break; case 3: *ptr++ = bic_immed(cc, cc, 2, 0); break; case 7: *ptr++ = bic_immed(cc, cc, 3, 0); break; case 15: *ptr++ = bic_immed(cc, cc, 4, 0); break; case 31: *ptr++ = bic_immed(cc, cc, 5, 0); break; case 2: *ptr++ = bic_immed(cc, cc, 1, 31); break; case 6: *ptr++ = bic_immed(cc, cc, 2, 31); break; case 14: *ptr++ = bic_immed(cc, cc, 3, 31); break; case 30: *ptr++ = bic_immed(cc, cc, 4, 31); break; case 4: *ptr++ = bic_immed(cc, cc, 1, 30); break; case 12: *ptr++ = bic_immed(cc, cc, 2, 30); break; case 28: *ptr++ = bic_immed(cc, cc, 3, 30); break; case 8: *ptr++ = bic_immed(cc, cc, 1, 29); break; case 24: *ptr++ = bic_immed(cc, cc, 2, 29); break; case 16: *ptr++ = bic_immed(cc, cc, 1, 28); break; default: tmp_reg = RA_AllocARMRegister(&ptr); *ptr++ = mov_immed_u16(tmp_reg, flags, 0); *ptr++ = bic_reg(cc, cc, tmp_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp_reg); } return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_GetNZ00(uint32_t * ptr, uint8_t cc, uint8_t *not_done) { if (*not_done == 0) return ptr; uint8_t tmp_reg = RA_AllocARMRegister(&ptr); if (__builtin_popcount(*not_done) == 1) { switch(*not_done) { case 1: // M68K C *ptr++ = bic_immed(cc, cc, 1, 31); (*not_done) &= ~0x01; break; case 2: // M68K V *ptr++ = bic_immed(cc, cc, 1, 0); (*not_done) &= ~0x02; break; case 4: // M68K Z *ptr++ = cset(tmp_reg, A64_CC_EQ); *ptr++ = bfi(cc, tmp_reg, 2, 1); (*not_done) &= ~0x04; break; case 8: // M68K N *ptr++ = cset(tmp_reg, A64_CC_MI); *ptr++ = bfi(cc, tmp_reg, 3, 1); (*not_done) &= ~0x08; break; default: break; } } else { *ptr++ = get_nzcv(tmp_reg); *ptr++ = bfxil(cc, tmp_reg, 28, 4); // Clear C+V only if needed if (*not_done & 3) *ptr++ = bic_immed(cc, cc, 2, 0); (*not_done) &= 0x10; } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_GetNZxx(uint32_t * ptr, uint8_t cc, uint8_t *not_done) { if (*not_done == 0) return ptr; uint8_t tmp_reg = RA_AllocARMRegister(&ptr); if (__builtin_popcount(*not_done) == 1) { switch(*not_done) { case 4: // M68K Z *ptr++ = cset(tmp_reg, A64_CC_EQ); *ptr++ = bfi(cc, tmp_reg, 2, 1); (*not_done) &= ~0x04; break; case 8: // M68K N *ptr++ = cset(tmp_reg, A64_CC_MI); *ptr++ = bfi(cc, tmp_reg, 3, 1); (*not_done) &= ~0x08; break; default: break; } } else { *ptr++ = get_nzcv(tmp_reg); *ptr++ = ror(tmp_reg, tmp_reg, 30); *ptr++ = bfi(cc, tmp_reg, 2, 2); (*not_done) &= 0x13; } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_GetNZCV(uint32_t * ptr, uint8_t cc, uint8_t *not_done) { if (*not_done == 0) return ptr; uint8_t tmp_reg = RA_AllocARMRegister(&ptr); if (__builtin_popcount(*not_done) == 1) { switch(*not_done) { case 1: // M68K C *ptr++ = cset(tmp_reg, A64_CC_CS); *ptr++ = bfi(cc, tmp_reg, 1, 1); (*not_done) &= ~0x01; break; case 2: // M68K V *ptr++ = cset(tmp_reg, A64_CC_VS); *ptr++ = bfi(cc, tmp_reg, 0, 1); (*not_done) &= ~0x02; break; case 4: // M68K Z *ptr++ = cset(tmp_reg, A64_CC_EQ); *ptr++ = bfi(cc, tmp_reg, 2, 1); (*not_done) &= ~0x04; break; case 8: // M68K N *ptr++ = cset(tmp_reg, A64_CC_MI); *ptr++ = bfi(cc, tmp_reg, 3, 1); (*not_done) &= ~0x08; break; default: break; } } else { *ptr++ = get_nzcv(tmp_reg); *ptr++ = bfxil(cc, tmp_reg, 28, 4); (*not_done) &= 0x10; } if (*not_done) { uint8_t clr_flags = *not_done; if ((clr_flags & 3) != 0 && (clr_flags & 3) < 3) clr_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, clr_flags); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_GetNZCVX(uint32_t * ptr, uint8_t cc, uint8_t *not_done) { if (*not_done == 0) return ptr; uint8_t tmp_reg = RA_AllocARMRegister(&ptr); if (__builtin_popcount(*not_done) == 1) { switch(*not_done) { case 1: // M68K C *ptr++ = cset(tmp_reg, A64_CC_CS); *ptr++ = bfi(cc, tmp_reg, 1, 1); (*not_done) &= ~0x01; break; case 2: // M68K V *ptr++ = cset(tmp_reg, A64_CC_VS); *ptr++ = bfi(cc, tmp_reg, 0, 1); (*not_done) &= ~0x02; break; case 4: // M68K Z *ptr++ = cset(tmp_reg, A64_CC_EQ); *ptr++ = bfi(cc, tmp_reg, 2, 1); (*not_done) &= ~0x04; break; case 8: // M68K N *ptr++ = cset(tmp_reg, A64_CC_MI); *ptr++ = bfi(cc, tmp_reg, 3, 1); (*not_done) &= ~0x08; break; case 16: // M68K X *ptr++ = cset(tmp_reg, A64_CC_CS); *ptr++ = bfi(cc, tmp_reg, 4, 1); (*not_done) &= ~0x10; break; default: break; } } else if (__builtin_popcount(*not_done) > 2) { *ptr++ = get_nzcv(tmp_reg); *ptr++ = bfxil(cc, tmp_reg, 28, 4); if (*not_done & 0x10) { #if 1 *ptr++ = cset(tmp_reg, A64_CC_CS); *ptr++ = bfi(cc, tmp_reg, 4, 1); #else *ptr++ = orr_immed(tmp_reg, cc, 1, 28); *ptr++ = bic_immed(cc, cc, 1, 28); *ptr++ = csel(cc, tmp_reg, cc, A64_CC_CS); #endif } (*not_done) = 0; } if (*not_done) { uint8_t clr_flags = *not_done; if ((clr_flags & 3) != 0 && (clr_flags & 3) < 3) clr_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, clr_flags); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_GetNZnCV(uint32_t * ptr, uint8_t cc, uint8_t *not_done) { if (*not_done == 0) return ptr; uint8_t tmp_reg = RA_AllocARMRegister(&ptr); if (__builtin_popcount(*not_done) == 1) { switch(*not_done) { case 1: // M68K C *ptr++ = cset(tmp_reg, A64_CC_CC); *ptr++ = bfi(cc, tmp_reg, 1, 1); (*not_done) &= ~0x01; break; case 2: // M68K V *ptr++ = cset(tmp_reg, A64_CC_VS); *ptr++ = bfi(cc, tmp_reg, 0, 1); (*not_done) &= ~0x02; break; case 4: // M68K Z *ptr++ = cset(tmp_reg, A64_CC_EQ); *ptr++ = bfi(cc, tmp_reg, 2, 1); (*not_done) &= ~0x04; break; case 8: // M68K N *ptr++ = cset(tmp_reg, A64_CC_MI); *ptr++ = bfi(cc, tmp_reg, 3, 1); (*not_done) &= ~0x08; break; default: break; } } else { *ptr++ = get_nzcv(tmp_reg); /* If C is needed, inverse it */ if (*not_done & 0x01) *ptr++ = eor_immed(tmp_reg, tmp_reg, 1, 3); *ptr++ = bfxil(cc, tmp_reg, 28, 4); (*not_done) &= 0x10; } if (*not_done) { uint8_t clr_flags = *not_done; if ((clr_flags & 3) != 0 && (clr_flags & 3) < 3) clr_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, clr_flags); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_GetNZnCVX(uint32_t * ptr, uint8_t cc, uint8_t *not_done) { if (*not_done == 0) return ptr; uint8_t tmp_reg = RA_AllocARMRegister(&ptr); if (__builtin_popcount(*not_done) == 1) { switch(*not_done) { case 1: // M68K C *ptr++ = cset(tmp_reg, A64_CC_CC); *ptr++ = bfi(cc, tmp_reg, 1, 1); (*not_done) &= ~0x01; break; case 2: // M68K V *ptr++ = cset(tmp_reg, A64_CC_VS); *ptr++ = bfi(cc, tmp_reg, 0, 1); (*not_done) &= ~0x02; break; case 4: // M68K Z *ptr++ = cset(tmp_reg, A64_CC_EQ); *ptr++ = bfi(cc, tmp_reg, 2, 1); (*not_done) &= ~0x04; break; case 8: // M68K N *ptr++ = cset(tmp_reg, A64_CC_MI); *ptr++ = bfi(cc, tmp_reg, 3, 1); (*not_done) &= ~0x08; break; case 16: // M68K X *ptr++ = cset(tmp_reg, A64_CC_CC); *ptr++ = bfi(cc, tmp_reg, 4, 1); (*not_done) &= ~0x10; break; default: break; } } else if (__builtin_popcount(*not_done) > 2) { *ptr++ = get_nzcv(tmp_reg); /* If C or X requested, invert the flag */ if (*not_done & 0x11) *ptr++ = eor_immed(tmp_reg, tmp_reg, 1, 3); *ptr++ = bfxil(cc, tmp_reg, 28, 4); /* If X requested, add it now */ if (*not_done & 0x10) { #if 1 *ptr++ = cset(tmp_reg, A64_CC_CC); *ptr++ = bfi(cc, tmp_reg, 4, 1); #else *ptr++ = bic_immed(cc, cc, 1, 28); *ptr++ = orr_immed(tmp_reg, cc, 1, 28); *ptr++ = csel(cc, tmp_reg, cc, A64_CC_CC); #endif } *not_done = 0; } if (*not_done) { uint8_t clr_flags = *not_done; if ((clr_flags & 3) != 0 && (clr_flags & 3) < 3) clr_flags ^= 3; ptr = EMIT_ClearFlags(ptr, cc, clr_flags); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } static inline __attribute__((always_inline)) uint32_t * EMIT_SetFlags(uint32_t * ptr, uint8_t cc, uint8_t flags) { uint8_t tmp_reg; switch (flags) { case 0: break; case 1: *ptr++ = orr_immed(cc, cc, 1, 0); break; case 3: *ptr++ = orr_immed(cc, cc, 2, 0); break; case 7: *ptr++ = orr_immed(cc, cc, 3, 0); break; case 15: *ptr++ = orr_immed(cc, cc, 4, 0); break; case 31: *ptr++ = orr_immed(cc, cc, 5, 0); break; case 2: *ptr++ = orr_immed(cc, cc, 1, 31); break; case 6: *ptr++ = orr_immed(cc, cc, 2, 31); break; case 14: *ptr++ = orr_immed(cc, cc, 3, 31); break; case 30: *ptr++ = orr_immed(cc, cc, 4, 31); break; case 4: *ptr++ = orr_immed(cc, cc, 1, 30); break; case 12: *ptr++ = orr_immed(cc, cc, 2, 30); break; case 28: *ptr++ = orr_immed(cc, cc, 3, 30); break; case 8: *ptr++ = orr_immed(cc, cc, 1, 29); break; case 24: *ptr++ = orr_immed(cc, cc, 2, 29); break; case 16: *ptr++ = orr_immed(cc, cc, 1, 28); break; default: tmp_reg = RA_AllocARMRegister(&ptr); *ptr++ = mov_immed_u16(tmp_reg, flags, 0); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 0); RA_FreeARMRegister(&ptr, tmp_reg); } return ptr; } #if 1 static inline __attribute__((always_inline)) uint32_t * EMIT_SetFlagsConditional(uint32_t * ptr, uint8_t cc, uint8_t flags, uint8_t cond) { uint8_t tmp_reg = RA_AllocARMRegister(&ptr); switch (flags) { case 0: break; case 1: *ptr++ = orr_immed(tmp_reg, cc, 1, 0); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 3: *ptr++ = orr_immed(tmp_reg, cc, 2, 0); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 7: *ptr++ = orr_immed(tmp_reg, cc, 3, 0); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 15: *ptr++ = orr_immed(tmp_reg, cc, 4, 0); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 31: *ptr++ = orr_immed(tmp_reg, cc, 4, 0); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 2: *ptr++ = orr_immed(tmp_reg, cc, 1, 31); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 6: *ptr++ = orr_immed(tmp_reg, cc, 2, 31); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 14: *ptr++ = orr_immed(tmp_reg, cc, 3, 31); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 30: *ptr++ = orr_immed(tmp_reg, cc, 4, 31); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 4: *ptr++ = orr_immed(tmp_reg, cc, 1, 30); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 12: *ptr++ = orr_immed(tmp_reg, cc, 2, 30); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 28: *ptr++ = orr_immed(tmp_reg, cc, 3, 30); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 8: *ptr++ = orr_immed(tmp_reg, cc, 1, 29); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 24: *ptr++ = orr_immed(tmp_reg, cc, 2, 29); *ptr++ = csel(cc, tmp_reg, cc, cond); break; case 16: *ptr++ = orr_immed(tmp_reg, cc, 1, 28); *ptr++ = csel(cc, tmp_reg, cc, cond); break; default: *ptr++ = mov_immed_u16(tmp_reg, flags, 0); *ptr++ = csel(tmp_reg, tmp_reg, 31, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 0); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } #elif 0 static inline __attribute__((always_inline)) uint32_t * EMIT_SetFlagsConditional(uint32_t * ptr, uint8_t cc, uint8_t flags, uint8_t cond) { uint8_t tmp_reg = RA_AllocARMRegister(&ptr); switch (flags) { case 0: break; case 1: *ptr++ = cset(tmp_reg, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 0); break; case 2: *ptr++ = cset(tmp_reg, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 1); break; case 4: *ptr++ = cset(tmp_reg, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 2); break; case 8: *ptr++ = cset(tmp_reg, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 3); break; case 16: *ptr++ = cset(tmp_reg, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 4); break; default: *ptr++ = mov_immed_u16(tmp_reg, flags, 0); *ptr++ = csel(tmp_reg, tmp_reg, 31, cond); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 0); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } #else static inline __attribute__((always_inline)) uint32_t * EMIT_SetFlagsConditional(uint32_t * ptr, uint8_t cc, uint8_t flags, uint8_t cond) { uint8_t tmp_reg = RA_AllocARMRegister(&ptr); switch (flags) { case 0: break; case 1: *ptr++ = b_cc(cond ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, 0); break; case 2: *ptr++ = b_cc(cond ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, 31); break; case 4: *ptr++ = b_cc(cond ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, 30); break; case 8: *ptr++ = b_cc(cond ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, 29); break; case 16: *ptr++ = b_cc(cond ^ 1, 2); *ptr++ = orr_immed(cc, cc, 1, 28); break; default: *ptr++ = b_cc(cond ^ 1, 3); *ptr++ = mov_immed_u16(tmp_reg, flags, 0); *ptr++ = orr_reg(cc, cc, tmp_reg, LSL, 0); } RA_FreeARMRegister(&ptr, tmp_reg); return ptr; } #endif static inline __attribute__((always_inline)) uint32_t number_to_mask(uint32_t number) { unsigned shift = 0; unsigned width = 0; if (number == 0) return 0; if (number == 0xffffffff) return 0; shift = __builtin_ctz(number); number = number >> shift; width = 32 - __builtin_clz(number); if (number == ((1ULL << width) - 1)) return (width << 16) | shift; else { number = ~number; if (number == 0) return 0; shift = __builtin_ctz(number); number = number >> shift; width = 32 - __builtin_clz(number); if (number == ((1ULL << width) - 1)) return ((32 - width) << 16) | (shift + width); else return 0xffffffff; } } #endif /* _A64_H */