#include #include #include static uint8_t *CachePtr; enum ARMCond { CondEQ, CondNE, CondCS, CondHS = CondCS, CondCC, CondLO = CondCC, CondMI, CondPL, CondVS, CondVC, CondHI, CondLS, CondGE, CondLT, CondGT, CondLE, CondAL, }; enum ARMShift { ShiftLSL, ShiftLSR, ShiftASR, ShiftROR, ShiftRRX }; enum ARMReg { RegR0, RegR1, RegR2, RegR3, RegR4, RegR5, RegR6, RegR7, RegR8, RegR9, RegR10, RegR11, RegR12, RegR13, RegR14, RegR15, RegA1 = RegR0, RegA2, RegA3, RegA4, RegV1 = RegR4, RegV2, RegV3, RegV4, RegV5, RegV6, RegV7, RegV8, RegIP = RegR12, RegSP, RegLR, RegPC, RegA = RegR4, RegX = RegR5, RegY = RegR6, RegP = RegR7, RegCPU = RegR8, RegCPUPC = RegR9, RegCycles = RegR10, RegChecks = RegR12, }; #define ASCOND(cond) (cond << 28) #define ASLIST(reg) (1 << reg) #define PCREL(pc, target) ((intptr_t)(target) - (intptr_t)(pc) - 8) #define PCOFFSET(function) ((PCREL(CachePtr, function) >> 2) & 0xFFFFFF) #define ENCODE_IMM(imm, shl) (((((32 - (shl)) & 0x1F) >> 1) << 8) | ((imm) & 0xFF)) #define DECODE_IMM(imm) (((imm) & 0xFF) << (32 - (((imm) >> 8) << 1))); #define ENCODE_SHIFT(type, imm) ((type) | (((imm) >= 32 ? 0 : (imm)) << 2)) #define CPU_ICPU_OFFSET ((uintptr_t)&ICPU - (uintptr_t)&CPU) #define CPU_OPEN_BUS_OFFSET ((uintptr_t)&OpenBus - (uintptr_t)&CPU) #define CPU_OFFSET(field) (offsetof(__typeof__(CPU), field)) #define ICPU_OFFSET(field) (CPU_ICPU_OFFSET + offsetof(__typeof__(ICPU), field)) static size_t DecomposeImm32(uint32_t imm32, uint32_t *result) { uint8_t shift = 0; size_t count = 0; if (!imm32) { result[0] = 0; return 1; } while (1) { while (shift < 32 && !(imm32 >> shift & 0x03)) shift += 2; if (shift >= 32) break; if (shift > 24) { uint8_t remaining = (1 << (shift - 24)); uint32_t firstStore = count == 0 ? 0 : DECODE_IMM(result[0]); if (firstStore && firstStore < remaining) { uint8_t bottom = imm32 >> shift; uint8_t top = (imm32 & (remaining - 1)) << (32 - shift); result[0] = ENCODE_IMM(bottom | top, shift); break; } } result[count++] = ENCODE_IMM(imm32 >> shift, shift); shift += 8; } return count; } static inline void ARMEmit(uint32_t value) { *(uint32_t *)CachePtr = value; CachePtr += 4; } enum ARMDPIOp { DPIOpAND, DPIOpEOR, DPIOpSUB, DPIOpRSB, DPIOpADD, DPIOpADC, DPIOpSBC, DPIOpRSC, DPIOpTST, DPIOpTEQ, DPIOpCMP, DPIOpCMN, DPIOpORR, DPIOpMOV, DPIOpBIC, DPIOpNOT, }; static void ARMEmitDPI_Imm(enum ARMCond cond, uint8_t op, bool s, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmit( ASCOND(cond) | 0 << 26 | /* 0b00 */ 1 << 25 | op << 21 | s << 20 | rn << 16 | rd << 12 | imm ); } static void ARMEmitDPI_Reg(enum ARMCond cond, uint8_t op, bool s, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmit( ASCOND(cond) | 0 << 26 | /* 0b00 */ 0 << 25 | op << 21 | s << 20 | rn << 16 | rd << 12 | shift << 5 | 0 << 4 | rm ); } static void ARMEmitDPI_RegShift(enum ARMCond cond, uint8_t op, bool s, enum ARMReg rd, enum ARMReg rn, enum ARMReg rs, uint8_t type, enum ARMReg rm) { ARMEmit( ASCOND(cond) | 0 << 26 | /* 0b00 */ 0 << 25 | op << 21 | s << 20 | rn << 16 | rd << 12 | rs << 8 | 0 << 7 | type << 5 | 1 << 4 | rm ); } static void GenARM_CMP_Imm(enum ARMCond cond, enum ARMReg reg, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpCMP, 1, 0, reg, imm); } static void GenARM_CMP_Reg(enum ARMCond cond, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpCMP, 1, 0, rn, shift, rm); } static void GenARM_SUB_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpSUB, 0, rd, rn, imm); } static void GenARM_SUBS_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpSUB, 1, rd, rn, imm); } static void GenARM_SUB_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpSUB, 0, rd, rn, shift, rm); } static void GenARM_SUBS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpSUB, 1, rd, rn, shift, rm); } static void GenARM_ADD_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpADD, 0, rd, rn, imm); } static void GenARM_ADD_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpADD, 0, rd, rn, shift, rm); } static void GenARM_ADDS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpADD, 1, rd, rn, shift, rm); } static void GenARM_MOV_Imm(enum ARMCond cond, enum ARMReg rd, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpMOV, 0, rd, 0, imm); } static void GenARM_MOV_Reg(enum ARMCond cond, enum ARMReg rd, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpMOV, 0, rd, 0, shift, rm); } static void GenARM_MOVS_Reg(enum ARMCond cond, enum ARMReg rd, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpMOV, 1, rd, 0, shift, rm); } static void GenARM_AND_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpAND, 0, rd, rn, imm); } static void GenARM_ANDS_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpAND, 1, rd, rn, imm); } static void GenARM_AND_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpAND, 0, rd, rn, shift, rm); } static void GenARM_ANDS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpAND, 1, rd, rn, shift, rm); } static void GenARM_EOR_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpEOR, 0, rd, rn, imm); } static void GenARM_EORS_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpEOR, 1, rd, rn, imm); } static void GenARM_EOR_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpEOR, 0, rd, rn, shift, rm); } static void GenARM_EORS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpEOR, 1, rd, rn, shift, rm); } static void GenARM_ORR_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpORR, 0, rd, rn, imm); } static void GenARM_ORRS_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpORR, 1, rd, rn, imm); } static void GenARM_ORR_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpORR, 0, rd, rn, shift, rm); } static void GenARM_ORRS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpORR, 1, rd, rn, shift, rm); } static void GenARM_TST_Imm(enum ARMCond cond, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpTST, 1, 0, rn, imm); } static void GenARM_TST_Reg(enum ARMCond cond, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpTST, 1, 0, rn, shift, rm); } static void GenARM_BIC_Imm(enum ARMCond cond, enum ARMReg rd, enum ARMReg rn, uint16_t imm) { ARMEmitDPI_Imm(cond, DPIOpBIC, 0, rd, rn, imm); } static void GenARM_MVN_Reg(enum ARMCond cond, enum ARMReg rd, uint8_t shift, enum ARMReg rm) { ARMEmitDPI_Reg(cond, DPIOpNOT, 0, rd, 0, shift, rm); } static void ARMEmitLS_Imm(enum ARMCond cond, bool p, bool w, uint8_t op, enum ARMReg rt, enum ARMReg rn, int16_t imm) { bool u = imm >= 0 ? 1 : 0; imm = (u ? imm : -imm) & 0xFFF; ARMEmit( ASCOND(cond) | 1 << 26 | /* 0b01 */ 0 << 25 | p << 24 | u << 23 | w << 21 | op << 20 | rn << 16 | rt << 12 | imm ); } static void ARMEmitLS_Reg(enum ARMCond cond, bool p, bool u, bool w, uint8_t op, enum ARMReg rt, enum ARMReg rn, uint8_t shift, enum ARMReg rm) { ARMEmit( ASCOND(cond) | 1 << 26 | /* 0b01 */ 1 << 25 | p << 24 | u << 23 | w << 21 | op << 20 | rn << 16 | rt << 12 | shift << 5 | 0 << 4 | rm ); } static void ARMEmitLSH_Imm(enum ARMCond cond, bool p, bool w, uint8_t op, enum ARMReg rt, enum ARMReg rn, int16_t imm) { bool u = imm >= 0 ? 1 : 0; imm = (u ? imm : -imm) & 0xFF; ARMEmit( ASCOND(cond) | 0 << 25 | /* 0b000 */ p << 24 | u << 23 | 1 << 22 | w << 21 | op << 20 | rn << 16 | rt << 12 | ((imm & 0xF0) << 4) | 0xb << 4 | /* 0b1011 */ (imm & 0x0F) ); } static void ARMEmitLSB_Imm(enum ARMCond cond, bool p, bool w, uint8_t op, enum ARMReg rt, enum ARMReg rn, int16_t imm) { bool u = imm >= 0 ? 1 : 0; imm = (u ? imm : -imm) & 0xFF; ARMEmit( ASCOND(cond) | 0x2 << 25 | /* 0b010 */ p << 24 | u << 23 | 1 << 22 | w << 21 | op << 20 | rn << 16 | rt << 12 | imm ); } static void GenARM_LDR_Imm(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, int16_t imm) { ARMEmitLS_Imm(cond, 1, 0, 1, rt, rn, imm); } static void GenARM_LDR_Reg(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, bool add, uint8_t shift, enum ARMReg rm) { ARMEmitLS_Reg(cond, 1, add, 0, 1, rt, rn, shift, rm); } static void GenARM_LDRH_Imm(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, int16_t imm) { ARMEmitLSH_Imm(cond, 1, 0, 1, rt, rn, imm); } static void GenARM_LDRB_Imm(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, int16_t imm) { ARMEmitLSB_Imm(cond, 1, 0, 1, rt, rn, imm); } static void GenARM_STR_Imm(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, int16_t imm) { ARMEmitLS_Imm(cond, 1, 0, 0, rt, rn, imm); } static void GenARM_STRH_Imm(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, int16_t imm) { ARMEmitLSH_Imm(cond, 1, 0, 0, rt, rn, imm); } static void GenARM_STRB_Imm(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, int16_t imm) { ARMEmitLSB_Imm(cond, 1, 0, 0, rt, rn, imm); } static void GenARM_STR_Reg(enum ARMCond cond, enum ARMReg rt, enum ARMReg rn, bool add, uint8_t shift, enum ARMReg rm) { ARMEmitLS_Reg(cond, 1, add, 0, 0, rt, rn, shift, rm); } static void GenARM_PUSH(uint16_t regs) { ARMEmit( ASCOND(CondAL) | (0x92 << 20) | /* 0b10010010 */ (RegSP << 16) | (regs) ); } static void GenARM_POP(uint16_t regs) { ARMEmit( ASCOND(CondAL) | (0x8B << 20) | /* 0b10001011 */ (RegSP << 16) | (regs) ); } static void GenARM_B(enum ARMCond cond, uint32_t offset) { ARMEmit( ASCOND(cond) | (0xA << 24) | /* 0b1010 */ (offset) ); } static void GenARM_BL(enum ARMCond cond, uint32_t offset) { ARMEmit( ASCOND(cond) | (0xB << 24) | /* 0b1011 */ (offset) ); } static void GenARM_BX_Reg(enum ARMCond cond, enum ARMReg reg) { ARMEmit( ASCOND(cond) | (0x12 << 20) | /* 0b 0001 0010 */ (0xFFF1 << 4) | /* 0b 1111 1111 1111 0001 */ (reg) ); } static void GenARM_BLX_Reg(enum ARMCond cond, enum ARMReg reg) { ARMEmit( ASCOND(cond) | (0x12 << 20) | /* 0b 0001 0010 */ (0xFFF3 << 4) | /* 0b 1111 1111 1111 0011 */ (reg) ); } static void GenARM_UXTB_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rm) { GenARM_AND_Imm(cond, rd, rm, ENCODE_IMM(0xFF, 0)); } static void GenARM_MOVB_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rm) { GenARM_MOV_Reg(cond, rd, ENCODE_SHIFT(ShiftLSR, 8), rd); GenARM_ORR_Reg(cond, rd, rd, ENCODE_SHIFT(ShiftLSL, 24), rm); GenARM_MOV_Reg(cond, rd, ENCODE_SHIFT(ShiftROR, 24), rd); } static void GenARM_MOVBS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg scratch, enum ARMReg rm) { GenARM_AND_Imm(cond, rd, rd, ENCODE_IMM(0xFF, 8)); GenARM_ANDS_Imm(CondAL, scratch, rm, ENCODE_IMM(0xFF, 0)); GenARM_ORR_Reg(CondAL, rd, rd, 0, scratch); } static void GenARM_UXTHS_Reg_(enum ARMCond cond, bool s, enum ARMReg rd, enum ARMReg rm) { GenARM_MOV_Reg(cond, rd, ENCODE_SHIFT(ShiftLSL, 16), rm); if (s) GenARM_MOVS_Reg(cond, rd, ENCODE_SHIFT(ShiftLSR, 16), rd); else GenARM_MOV_Reg(cond, rd, ENCODE_SHIFT(ShiftLSR, 16), rd); } static void GenARM_UXTH_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rm) { GenARM_UXTHS_Reg_(cond, 0, rd, rm); } static void GenARM_UXTHS_Reg(enum ARMCond cond, enum ARMReg rd, enum ARMReg rm) { GenARM_UXTHS_Reg_(cond, 1, rd, rm); } static void GenARM_MOV32_Imm(enum ARMCond cond, enum ARMReg reg, uint32_t imm) { uint32_t values[4]; uint32_t count = DecomposeImm32(imm, values); uint32_t i; GenARM_MOV_Imm(cond, reg, values[0]); for (i = 1; i < count; i++) { GenARM_ORR_Imm(cond, reg, reg, values[i]); } }