diff --git a/CHANGES b/CHANGES index e565468c4..1cb136064 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,6 @@ 0.9.0: (Future) Emulation fixes: + - ARM: Fix ALU reading PC after shifting - GBA Memory: Misaligned SRAM writes are ignored Other fixes: - Qt: Only dynamically reset video scale if a game is running diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index c88345f90..e0231652e 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -302,7 +302,10 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { DEFINE_INSTRUCTION_ARM(NAME, \ int rd = (opcode >> 12) & 0xF; \ int rn = (opcode >> 16) & 0xF; \ - UNUSED(rn); \ + int32_t n = cpu->gprs[rn]; \ + if (UNLIKELY(rn == ARM_PC && (opcode & 0x02000010) == 0x00000010)) { \ + n += WORD_SIZE_ARM; \ + } \ SHIFTER(cpu, opcode); \ BODY; \ S_BODY; \ @@ -465,58 +468,52 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { // Begin ALU definitions DEFINE_ALU_INSTRUCTION_ARM(ADD, ARM_ADDITION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n + cpu->shifterOperand;) DEFINE_ALU_INSTRUCTION_ARM(ADC, ARM_ADDITION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n + cpu->shifterOperand + cpu->cpsr.c;) -DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] & cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n & cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(BIC, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] & ~cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(BIC, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n & ~cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMN, ARM_ADDITION_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] + cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMN, ARM_ADDITION_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n + cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMP, ARM_SUBTRACTION_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] - cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMP, ARM_SUBTRACTION_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n - cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] ^ cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n ^ cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(MOV, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), +DEFINE_ALU_INSTRUCTION_ARM(MOV, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), cpu->gprs[rd] = cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(MVN, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), +DEFINE_ALU_INSTRUCTION_ARM(MVN, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), cpu->gprs[rd] = ~cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(ORR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] | cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(ORR, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n | cpu->shifterOperand;) DEFINE_ALU_INSTRUCTION_ARM(RSB, ARM_SUBTRACTION_S(cpu->shifterOperand, n, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = cpu->shifterOperand - n;) DEFINE_ALU_INSTRUCTION_ARM(RSC, ARM_SUBTRACTION_CARRY_S(cpu->shifterOperand, n, cpu->gprs[rd], !cpu->cpsr.c), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = cpu->shifterOperand - n - !cpu->cpsr.c;) DEFINE_ALU_INSTRUCTION_ARM(SBC, ARM_SUBTRACTION_CARRY_S(n, cpu->shifterOperand, cpu->gprs[rd], !cpu->cpsr.c), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n - cpu->shifterOperand - !cpu->cpsr.c;) DEFINE_ALU_INSTRUCTION_ARM(SUB, ARM_SUBTRACTION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n - cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TEQ, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] ^ cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TEQ, ARM_NEUTRAL_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n ^ cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TST, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] & cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TST, ARM_NEUTRAL_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n & cpu->shifterOperand;) // End ALU definitions