diff --git a/include/mgba/internal/arm/arm.h b/include/mgba/internal/arm/arm.h index d7f7b77d0..298ee406d 100644 --- a/include/mgba/internal/arm/arm.h +++ b/include/mgba/internal/arm/arm.h @@ -75,7 +75,8 @@ union PSR { unsigned z : 1; unsigned c : 1; unsigned v : 1; - unsigned unused : 20; + unsigned q : 1; + unsigned unused : 19; unsigned i : 1; unsigned f : 1; unsigned t : 1; @@ -85,7 +86,8 @@ union PSR { unsigned t : 1; unsigned f : 1; unsigned i : 1; - unsigned unused : 20; + unsigned unused : 19; + unsigned q : 1; unsigned v : 1; unsigned c : 1; unsigned z : 1; diff --git a/include/mgba/internal/arm/decoder.h b/include/mgba/internal/arm/decoder.h index fe2240f6a..b66dd337d 100644 --- a/include/mgba/internal/arm/decoder.h +++ b/include/mgba/internal/arm/decoder.h @@ -188,6 +188,10 @@ enum ARMMnemonic { ARM_MN_RSB, ARM_MN_RSC, ARM_MN_SBC, + ARM_MN_SMLABB, + ARM_MN_SMLABT, + ARM_MN_SMLATB, + ARM_MN_SMLATT, ARM_MN_SMLAL, ARM_MN_SMULL, ARM_MN_STC, diff --git a/include/mgba/internal/arm/emitter-arm.h b/include/mgba/internal/arm/emitter-arm.h index 3dc31eeb9..12c14767d 100644 --- a/include/mgba/internal/arm/emitter-arm.h +++ b/include/mgba/internal/arm/emitter-arm.h @@ -104,13 +104,13 @@ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + MIN_V(DECLARE_INSTRUCTION_ARM(EMITTER, SMLABB), DECLARE_INSTRUCTION_ARM(EMITTER, ILL), V >= 5), \ DECLARE_INSTRUCTION_ARM(EMITTER, SWP), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + MIN_V(DECLARE_INSTRUCTION_ARM(EMITTER, SMLATB), DECLARE_INSTRUCTION_ARM(EMITTER, ILL), V >= 5), \ DECLARE_INSTRUCTION_ARM(EMITTER, STRHP), \ + MIN_V(DECLARE_INSTRUCTION_ARM(EMITTER, SMLABT), DECLARE_INSTRUCTION_ARM(EMITTER, ILL), V >= 5), \ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ - DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ + MIN_V(DECLARE_INSTRUCTION_ARM(EMITTER, SMLATT), DECLARE_INSTRUCTION_ARM(EMITTER, ILL), V >= 5), \ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ DECLARE_ARM_ALU_BLOCK(EMITTER, TST, ILL, LDRHP, LDRSBP, LDRSHP), \ DECLARE_INSTRUCTION_ARM(EMITTER, MSR), \ diff --git a/src/arm/decoder-arm.c b/src/arm/decoder-arm.c index 2d62eef7b..e479d8260 100644 --- a/src/arm/decoder-arm.c +++ b/src/arm/decoder-arm.c @@ -311,6 +311,11 @@ DEFINE_LONG_MULTIPLY_DECODER_ARM(SMULL) DEFINE_LONG_MULTIPLY_DECODER_ARM(UMLAL) DEFINE_LONG_MULTIPLY_DECODER_ARM(UMULL) +DEFINE_MULTIPLY_DECODER_EX_ARM(SMLABB, SMLABB, 0, ARM_OPERAND_REGISTER_4) +DEFINE_MULTIPLY_DECODER_EX_ARM(SMLABT, SMLABT, 0, ARM_OPERAND_REGISTER_4) +DEFINE_MULTIPLY_DECODER_EX_ARM(SMLATB, SMLATB, 0, ARM_OPERAND_REGISTER_4) +DEFINE_MULTIPLY_DECODER_EX_ARM(SMLATT, SMLATT, 0, ARM_OPERAND_REGISTER_4) + // Begin load/store definitions DEFINE_LOAD_STORE_MODE_2_DECODER_ARM(LDR, LDR, LOAD_CYCLES, ARM_ACCESS_WORD) diff --git a/src/arm/decoder.c b/src/arm/decoder.c index cd2324c87..bd8caaa07 100644 --- a/src/arm/decoder.c +++ b/src/arm/decoder.c @@ -276,6 +276,10 @@ static const char* _armMnemonicStrings[] = { "rsb", "rsc", "sbc", + "smlabb", + "smlabt", + "smlatb", + "smlatt", "smlal", "smull", "stc", diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index 2e032432b..4e6e0f733 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -355,6 +355,25 @@ static inline void _immediate(struct ARMCore* cpu, uint32_t opcode) { DEFINE_MULTIPLY_INSTRUCTION_2_EX_ARM(NAME, BODY, , WAIT) \ DEFINE_MULTIPLY_INSTRUCTION_2_EX_ARM(NAME ## S, BODY, S_BODY, WAIT) +#define DEFINE_MULTIPLY_INSTRUCTION_3_ARM(NAME, BODY) \ + DEFINE_INSTRUCTION_ARM(NAME, \ + int rd = (opcode >> 16) & 0xF; \ + int rs = (opcode >> 8) & 0xF; \ + int rn = (opcode >> 12) & 0xF; \ + int rm = opcode & 0xF; \ + if (rd == ARM_PC) { \ + return; \ + } \ + /* TODO: Timing */ \ + int32_t x; \ + int32_t y; \ + BODY; \ + int32_t dn = cpu->gprs[rn]; \ + int32_t d = x * y; \ + cpu->gprs[rd] = d + dn; \ + cpu->cpsr.q = cpu->cpsr.q || ARM_V_ADDITION(d, dn, cpu->gprs[rd]); \ + currentCycles += cpu->memory.activeNonseqCycles32 - cpu->memory.activeSeqCycles32) + #define DEFINE_LOAD_STORE_INSTRUCTION_EX_ARM(NAME, ADDRESS, WRITEBACK, BODY) \ DEFINE_INSTRUCTION_ARM(NAME, \ uint32_t address; \ @@ -522,6 +541,22 @@ DEFINE_MULTIPLY_INSTRUCTION_2_ARM(SMLAL, cpu->gprs[rdHi] = cpu->gprs[rdHi] + (d >> 32) + ARM_CARRY_FROM(dm, dn, cpu->gprs[rd]);, ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]), 3) +DEFINE_MULTIPLY_INSTRUCTION_3_ARM(SMLABB, + x = ARM_SXT_16(cpu->gprs[rm]); + y = ARM_SXT_16(cpu->gprs[rs]);) + +DEFINE_MULTIPLY_INSTRUCTION_3_ARM(SMLABT, + x = ARM_SXT_16(cpu->gprs[rm]); + y = ARM_SXT_16(cpu->gprs[rs] >> 16);) + +DEFINE_MULTIPLY_INSTRUCTION_3_ARM(SMLATB, + x = ARM_SXT_16(cpu->gprs[rm] >> 16); + y = ARM_SXT_16(cpu->gprs[rs]);) + +DEFINE_MULTIPLY_INSTRUCTION_3_ARM(SMLATT, + x = ARM_SXT_16(cpu->gprs[rm] >> 16); + y = ARM_SXT_16(cpu->gprs[rs] >> 16);) + DEFINE_MULTIPLY_INSTRUCTION_2_ARM(SMULL, int64_t d = ((int64_t) cpu->gprs[rm]) * ((int64_t) cpu->gprs[rs]); cpu->gprs[rd] = d;