diff --git a/include/mgba/internal/arm/emitter-arm.h b/include/mgba/internal/arm/emitter-arm.h index 9090c4611..3dc31eeb9 100644 --- a/include/mgba/internal/arm/emitter-arm.h +++ b/include/mgba/internal/arm/emitter-arm.h @@ -337,4 +337,22 @@ DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR, MRC), \ DECLARE_ARM_SWI_BLOCK(EMITTER) +#define DECLARE_ARM_F_EMITTER_BLOCK(EMITTER, V) \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(MIN_V(DECLARE_INSTRUCTION_ARM(EMITTER, BLX), DECLARE_INSTRUCTION_ARM(EMITTER, ILL), V >= 5)), \ + DO_256(MIN_V(DECLARE_INSTRUCTION_ARM(EMITTER, BLX), DECLARE_INSTRUCTION_ARM(EMITTER, ILL), V >= 5)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), \ + DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, ILL)), + #endif diff --git a/include/mgba/internal/arm/isa-arm.h b/include/mgba/internal/arm/isa-arm.h index 5296e5f44..b7652df89 100644 --- a/include/mgba/internal/arm/isa-arm.h +++ b/include/mgba/internal/arm/isa-arm.h @@ -17,6 +17,8 @@ struct ARMCore; typedef void (*ARMInstruction)(struct ARMCore*, uint32_t opcode); extern const ARMInstruction _armv4Table[0x1000]; extern const ARMInstruction _armv5Table[0x1000]; +extern const ARMInstruction _armv4FTable[0x1000]; +extern const ARMInstruction _armv5FTable[0x1000]; CXX_GUARD_END diff --git a/src/arm/arm.c b/src/arm/arm.c index 460e4228e..4771ead69 100644 --- a/src/arm/arm.c +++ b/src/arm/arm.c @@ -235,6 +235,7 @@ void ARMHalt(struct ARMCore* cpu) { cpu->gprs[ARM_PC] += WORD_SIZE_ARM; \ LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); \ \ + ARMInstruction instruction; \ unsigned condition = opcode >> 28; \ if (condition != 0xE) { \ bool conditionMet = false; \ @@ -282,14 +283,16 @@ void ARMHalt(struct ARMCore* cpu) { conditionMet = ARM_COND_LE; \ break; \ default: \ - break; \ + instruction = _arm ## VERSION ## FTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \ + instruction(cpu, opcode); \ + return; \ } \ if (!conditionMet) { \ cpu->cycles += ARM_PREFETCH_CYCLES; \ return; \ } \ } \ - ARMInstruction instruction = _arm ## VERSION ## Table[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \ + instruction = _arm ## VERSION ## Table[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \ instruction(cpu, opcode); \ } \ \ diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index abcc771e1..2e032432b 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -654,6 +654,14 @@ DEFINE_INSTRUCTION_ARM(BX, ARM_WRITE_PC; }) + +DEFINE_INSTRUCTION_ARM(BLX, + int32_t immediate = (opcode & 0x00FFFFFF) << 8; + cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - WORD_SIZE_ARM; + cpu->gprs[ARM_PC] += (immediate >> 6) + ((opcode >> 23) & 2); + _ARMSetMode(cpu, MODE_THUMB); + THUMB_WRITE_PC;) + DEFINE_INSTRUCTION_ARM(BLX2, int rm = opcode & 0x0000000F; cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - WORD_SIZE_ARM; @@ -795,3 +803,11 @@ const ARMInstruction _armv4Table[0x1000] = { const ARMInstruction _armv5Table[0x1000] = { DECLARE_ARM_EMITTER_BLOCK(_ARMInstruction, 5) }; + +const ARMInstruction _armv4FTable[0x1000] = { + DECLARE_ARM_F_EMITTER_BLOCK(_ARMInstruction, 4) +}; + +const ARMInstruction _armv5FTable[0x1000] = { + DECLARE_ARM_F_EMITTER_BLOCK(_ARMInstruction, 5) +};