From ce34e879e348cecd4e21329be5974cc4162fa6c4 Mon Sep 17 00:00:00 2001 From: neonloop Date: Wed, 9 Feb 2022 07:15:14 +0000 Subject: Adds experimental ARM dynarec Supports ARMv5 and higher, enable with USE_DYNAREC Makefile variable --- source/arm_dynarec/armgen.h | 576 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 576 insertions(+) create mode 100644 source/arm_dynarec/armgen.h (limited to 'source/arm_dynarec/armgen.h') diff --git a/source/arm_dynarec/armgen.h b/source/arm_dynarec/armgen.h new file mode 100644 index 0000000..bec7a58 --- /dev/null +++ b/source/arm_dynarec/armgen.h @@ -0,0 +1,576 @@ +#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]); + } +} -- cgit v1.2.3