mirror of https://github.com/mgba-emu/mgba.git
Implement ADD, ADC, RSB, RSC, SUB
This commit is contained in:
parent
c1a8042db4
commit
fd4ee12eb5
162
src/arm.c
162
src/arm.c
|
@ -81,7 +81,10 @@ inline void ARMCycle(struct ARMCore* cpu) {
|
|||
// Instruction definitions
|
||||
// Beware pre-processor antics
|
||||
|
||||
#define ARM_CARRY_FROM ((((M) | (N)) >> 31) && !((D) >> 31)))
|
||||
#define ARM_CARRY_FROM(M, N, D) ((((M) | (N)) >> 31) && !((D) >> 31))
|
||||
#define ARM_BORROW_FROM(M, N, D) (((uint32_t) (M)) >= ((uint32_t) (N)))
|
||||
#define ARM_V_ADDITION(M, N, D) (!(((M) ^ (N)) >> 31) && (((M) ^ (D)) >> 31) && (((N) ^ (D)) >> 31))
|
||||
#define ARM_V_SUBTRACTION(M, N, D) ((((M) ^ (N)) >> 31) && (((M) ^ (D)) >> 31))
|
||||
|
||||
#define ARM_COND_EQ (cpu->cpsr.z)
|
||||
#define ARM_COND_NE (!cpu->cpsr.z)
|
||||
|
@ -107,7 +110,19 @@ inline void ARMCycle(struct ARMCore* cpu) {
|
|||
cpu->cpsr.n = (D) >> 31; \
|
||||
cpu->cpsr.z = !(D); \
|
||||
cpu->cpsr.c = ARM_CARRY_FROM(M, N, D); \
|
||||
} \
|
||||
cpu->cpsr.v = ARM_V_ADDITION(M, N, D); \
|
||||
}
|
||||
|
||||
#define ARM_SUBTRACTION_S(M, N, D) \
|
||||
if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \
|
||||
cpu->cpsr = cpu->spsr; \
|
||||
_ARMReadCPSR(cpu); \
|
||||
} else { \
|
||||
cpu->cpsr.n = (D) >> 31; \
|
||||
cpu->cpsr.z = !(D); \
|
||||
cpu->cpsr.c = ARM_BORROW_FROM(M, N, D); \
|
||||
cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); \
|
||||
}
|
||||
|
||||
#define ARM_NEUTRAL_S(M, N, D) \
|
||||
if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \
|
||||
|
@ -117,10 +132,10 @@ inline void ARMCycle(struct ARMCore* cpu) {
|
|||
cpu->cpsr.n = (D) >> 31; \
|
||||
cpu->cpsr.z = !(D); \
|
||||
cpu->cpsr.c = cpu->shifterCarryOut; \
|
||||
} \
|
||||
}
|
||||
|
||||
// TODO: shifter
|
||||
#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, COND, COND_BODY, S, S_BODY, BODY) \
|
||||
#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, COND, COND_BODY, S, S_BODY, BODY, POST_BODY) \
|
||||
static void _ARMInstruction ## NAME ## S ## COND (struct ARMCore* cpu, uint32_t opcode) { \
|
||||
if (!COND_BODY) { \
|
||||
return; \
|
||||
|
@ -129,47 +144,71 @@ inline void ARMCycle(struct ARMCore* cpu) {
|
|||
int rn = (opcode >> 16) & 0xF; \
|
||||
BODY; \
|
||||
S_BODY; \
|
||||
POST_BODY; \
|
||||
}
|
||||
|
||||
#define DEFINE_ALU_INSTRUCTION_ARM(NAME, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, S, S_BODY, BODY)
|
||||
#define DEFINE_ALU_INSTRUCTION_ARM(NAME, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, , , BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, S, S_BODY, BODY, POST_BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, S, S_BODY, BODY, POST_BODY)
|
||||
|
||||
// Begin ALU definitions
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(ADD, ARM_ADDITION_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), \
|
||||
cpu->gprs[rd] = cpu->gprs[rn] + cpu->shifterOperand;, )
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(ADC, ARM_ADDITION_S(cpu->gprs[rn], shifterOperand, cpu->gprs[rd]), \
|
||||
int32_t shifterOperand = cpu->shifterOperand + cpu->cpsr.c; \
|
||||
cpu->gprs[rd] = cpu->gprs[rn] + shifterOperand;, )
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), \
|
||||
cpu->gprs[rd] = cpu->gprs[rn] & cpu->shifterOperand; \
|
||||
)
|
||||
cpu->gprs[rd] = cpu->gprs[rn] & 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; \
|
||||
)
|
||||
cpu->gprs[rd] = cpu->gprs[rn] ^ cpu->shifterOperand;, )
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(RSB, ARM_SUBTRACTION_S(cpu->shifterOperand, cpu->gprs[rn], d), \
|
||||
int32_t d = cpu->shifterOperand - cpu->gprs[rn];, cpu->gprs[rd] = d)
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(RSC, ARM_SUBTRACTION_S(cpu->shifterOperand, n, d), \
|
||||
int32_t n = cpu->gprs[rn] + !cpu->cpsr.c; \
|
||||
int32_t d = cpu->shifterOperand - n;, cpu->gprs[rd] = d)
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(SBC, ARM_SUBTRACTION_S(cpu->gprs[rn], shifterOperand, d), \
|
||||
int32_t shifterOperand = cpu->shifterOperand + !cpu->cpsr.c; \
|
||||
int32_t d = cpu->gprs[rn] - shifterOperand;, cpu->gprs[rd] = d)
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(SUB, ARM_SUBTRACTION_S(cpu->gprs[rn], cpu->shifterOperand, d), \
|
||||
int32_t d = cpu->gprs[rn] - cpu->shifterOperand;, cpu->gprs[rd] = d)
|
||||
|
||||
// End ALU definitions
|
||||
|
||||
#define DECLARE_INSTRUCTION_ARM(COND, NAME) \
|
||||
_ARMInstruction ## NAME ## COND
|
||||
|
@ -187,18 +226,7 @@ DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand
|
|||
DIRECTIVE \
|
||||
|
||||
// TODO: MUL
|
||||
#define DECLARE_ARM_ALU_EX_BLOCK(COND, ALU, EX1, EX2, EX3, EX4) \
|
||||
DO_8(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DECLARE_INSTRUCTION_ARM(COND, ALU), \
|
||||
0, \
|
||||
DECLARE_INSTRUCTION_ARM(COND, ALU), \
|
||||
0, \
|
||||
DECLARE_INSTRUCTION_ARM(COND, ALU), \
|
||||
0, \
|
||||
DECLARE_INSTRUCTION_ARM(COND, ALU), \
|
||||
0
|
||||
|
||||
#define DECLARE_ARM_ALU_BLOCK(COND, ALU) \
|
||||
#define DECLARE_ARM_ALU_BLOCK(COND, ALU, EX1, EX2, EX3, EX4) \
|
||||
DO_8(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DECLARE_INSTRUCTION_ARM(COND, ALU), \
|
||||
0, \
|
||||
|
@ -210,22 +238,22 @@ DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand
|
|||
0
|
||||
|
||||
#define DECLARE_COND_BLOCK(COND) \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, AND, MUL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, ANDS, MULS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, EOR, MLA, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, EORS, MLAS, LDRH, LDRSB, LDRSH)/*, \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, SUB, 0, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, SUBS, 0, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, RSB, 0, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, RSBS, 0, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, ADD, UMULL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, ADDS, UMULLS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, ADC, UMLAL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, ADCS, UMLALS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, SBC, SMULL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, SBCS, SMULLS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, RSC, SMLAL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_EX_BLOCK(COND, RSCS, SMLALS, LDRH, LDRSB, LDRSH)*/
|
||||
DECLARE_ARM_ALU_BLOCK(COND, AND, MUL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, ANDS, MULS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, EOR, MLA, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, EORS, MLAS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, SUB, 0, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, SUBS, 0, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, RSB, 0, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, RSBS, 0, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, ADD, UMULL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, ADDS, UMULLS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, ADC, UMLAL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, ADCS, UMLALS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, SBC, SMULL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, SBCS, SMULLS, LDRH, LDRSB, LDRSH), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, RSC, SMLAL, STRH, 0, 0), \
|
||||
DECLARE_ARM_ALU_BLOCK(COND, RSCS, SMLALS, LDRH, LDRSB, LDRSH)
|
||||
|
||||
static const ARMInstruction armTable[0xF000] = {
|
||||
DECLARE_COND_BLOCK(EQ),
|
||||
|
|
Loading…
Reference in New Issue