all repos — mgba @ 49ec1ed7024493a52059c2d7c84c2cde2e026b75

mGBA Game Boy Advance Emulator

ARM: Fix long and accumulate multiply timing
Vicki Pfau vi@endrift.com
Mon, 15 Feb 2021 23:40:00 -0800
commit

49ec1ed7024493a52059c2d7c84c2cde2e026b75

parent

232aab5a088543d11712fc9e18bfe56f616e1f73

4 files changed, 21 insertions(+), 22 deletions(-)

jump to
M CHANGESCHANGES

@@ -24,6 +24,7 @@ - ARM: Fix ALU reading PC after shifting

- ARM: Fix STR storing PC after address calculation - ARM: Fix Addressing mode 1 shifter on rs == pc (fixes mgba.io/i/1926) - ARM: Fix long multiply-and-accumulate register write order (fixes mgba.io/1/1956) + - ARM: Fix long and accumulate multiply timing - GB: Partially fix timing for skipped BIOS - GB: Downgrade DMG-only ROMs from CGB mode even without boot ROM - GB Audio: Fix serializing sweep time
M include/mgba/internal/arm/isa-inlines.hinclude/mgba/internal/arm/isa-inlines.h

@@ -37,17 +37,17 @@ #define ARM_BORROW_FROM_CARRY(M, N, D, C) (ARM_UXT_64(M) >= (ARM_UXT_64(N)) + (uint64_t) (C))

#define ARM_V_ADDITION(M, N, D) (!(ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) #define ARM_V_SUBTRACTION(M, N, D) ((ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D)))) -#define ARM_WAIT_MUL(R) \ +#define ARM_WAIT_MUL(R, WAIT) \ { \ - int32_t wait; \ + int32_t wait = WAIT; \ if ((R & 0xFFFFFF00) == 0xFFFFFF00 || !(R & 0xFFFFFF00)) { \ - wait = 1; \ + wait += 1; \ } else if ((R & 0xFFFF0000) == 0xFFFF0000 || !(R & 0xFFFF0000)) { \ - wait = 2; \ + wait += 2; \ } else if ((R & 0xFF000000) == 0xFF000000 || !(R & 0xFF000000)) { \ - wait = 3; \ + wait += 3; \ } else { \ - wait = 4; \ + wait += 4; \ } \ currentCycles += cpu->memory.stall(cpu, wait); \ }
M src/arm/isa-arm.csrc/arm/isa-arm.c

@@ -325,12 +325,11 @@ DEFINE_INSTRUCTION_ARM(NAME, \

int rd = (opcode >> 16) & 0xF; \ int rs = (opcode >> 8) & 0xF; \ int rm = opcode & 0xF; \ - if (rd == ARM_PC) { \ - return; \ + if (rd != ARM_PC) { \ + ARM_WAIT_MUL(cpu->gprs[rs], 0); \ + BODY; \ + S_BODY; \ } \ - ARM_WAIT_MUL(cpu->gprs[rs]); \ - BODY; \ - S_BODY; \ currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32) #define DEFINE_MULTIPLY_INSTRUCTION_2_EX_ARM(NAME, BODY, S_BODY, WAIT) \

@@ -339,12 +338,11 @@ int rd = (opcode >> 12) & 0xF; \

int rdHi = (opcode >> 16) & 0xF; \ int rs = (opcode >> 8) & 0xF; \ int rm = opcode & 0xF; \ - if (rdHi == ARM_PC || rd == ARM_PC) { \ - return; \ + if (rdHi != ARM_PC && rd != ARM_PC) { \ + ARM_WAIT_MUL(cpu->gprs[rs], WAIT); \ + BODY; \ + S_BODY; \ } \ - currentCycles += cpu->memory.stall(cpu, WAIT); \ - BODY; \ - S_BODY; \ currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32) #define DEFINE_MULTIPLY_INSTRUCTION_ARM(NAME, BODY, S_BODY) \

@@ -522,7 +520,7 @@ // End ALU definitions

// Begin multiply definitions -DEFINE_MULTIPLY_INSTRUCTION_2_ARM(MLA, cpu->gprs[rdHi] = cpu->gprs[rm] * cpu->gprs[rs] + cpu->gprs[rd], ARM_NEUTRAL_S(, , cpu->gprs[rdHi]), 2) +DEFINE_MULTIPLY_INSTRUCTION_2_ARM(MLA, cpu->gprs[rdHi] = cpu->gprs[rm] * cpu->gprs[rs] + cpu->gprs[rd], ARM_NEUTRAL_S(, , cpu->gprs[rdHi]), 1) DEFINE_MULTIPLY_INSTRUCTION_ARM(MUL, cpu->gprs[rd] = cpu->gprs[rm] * cpu->gprs[rs], ARM_NEUTRAL_S(cpu->gprs[rm], cpu->gprs[rs], cpu->gprs[rd])) DEFINE_MULTIPLY_INSTRUCTION_2_ARM(SMLAL,

@@ -530,26 +528,26 @@ int64_t d = ((int64_t) cpu->gprs[rm]) * ((int64_t) cpu->gprs[rs]) + ((uint32_t) cpu->gprs[rd]);

int32_t dHi = cpu->gprs[rdHi] + (d >> 32); cpu->gprs[rd] = d; cpu->gprs[rdHi] = dHi;, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], dHi), 3) + ARM_NEUTRAL_HI_S(cpu->gprs[rd], dHi), 2) DEFINE_MULTIPLY_INSTRUCTION_2_ARM(SMULL, int64_t d = ((int64_t) cpu->gprs[rm]) * ((int64_t) cpu->gprs[rs]); cpu->gprs[rd] = d; cpu->gprs[rdHi] = d >> 32;, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 2) + ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 1) DEFINE_MULTIPLY_INSTRUCTION_2_ARM(UMLAL, uint64_t d = ARM_UXT_64(cpu->gprs[rm]) * ARM_UXT_64(cpu->gprs[rs]) + ((uint32_t) cpu->gprs[rd]); uint32_t dHi = ((uint32_t) cpu->gprs[rdHi]) + (d >> 32); cpu->gprs[rd] = d; cpu->gprs[rdHi] = dHi;, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], dHi), 3) + ARM_NEUTRAL_HI_S(cpu->gprs[rd], dHi), 2) DEFINE_MULTIPLY_INSTRUCTION_2_ARM(UMULL, uint64_t d = ARM_UXT_64(cpu->gprs[rm]) * ARM_UXT_64(cpu->gprs[rs]); cpu->gprs[rd] = d; cpu->gprs[rdHi] = d >> 32;, - ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 2) + ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 1) // End multiply definitions
M src/arm/isa-thumb.csrc/arm/isa-thumb.c

@@ -232,7 +232,7 @@ DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NEG, THUMB_SUBTRACTION(cpu->gprs[rd], 0, cpu->gprs[rn]))

DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(CMP2, int32_t aluOut = cpu->gprs[rd] - cpu->gprs[rn]; THUMB_SUBTRACTION_S(cpu->gprs[rd], cpu->gprs[rn], aluOut)) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(CMN, int32_t aluOut = cpu->gprs[rd] + cpu->gprs[rn]; THUMB_ADDITION_S(cpu->gprs[rd], cpu->gprs[rn], aluOut)) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ORR, cpu->gprs[rd] = cpu->gprs[rd] | cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) -DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MUL, ARM_WAIT_MUL(cpu->gprs[rd]); cpu->gprs[rd] *= cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]); currentCycles += cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16) +DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MUL, ARM_WAIT_MUL(cpu->gprs[rd], 0); cpu->gprs[rd] *= cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]); currentCycles += cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(BIC, cpu->gprs[rd] = cpu->gprs[rd] & ~cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MVN, cpu->gprs[rd] = ~cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))