ARM: Fix ALU reading PC after shifting

This commit is contained in:
Vicki Pfau 2020-01-24 01:46:15 -08:00
parent 8b9cd78d0f
commit 27882fbded
2 changed files with 23 additions and 25 deletions

View File

@ -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

View File

@ -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