aboutsummaryrefslogtreecommitdiff
path: root/source/arm_dynarec/armgen.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/arm_dynarec/armgen.h')
-rw-r--r--source/arm_dynarec/armgen.h576
1 files changed, 576 insertions, 0 deletions
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 <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+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]);
+ }
+}