mirror of https://github.com/mgba-emu/mgba.git
ARM Dynarec: Implement Thumb ADD
This commit is contained in:
parent
188d326b9a
commit
6613530534
|
@ -8,6 +8,8 @@
|
|||
#include "arm/isa-thumb.h"
|
||||
|
||||
#define OP_ADDI 0x02800000
|
||||
#define OP_ADDS 0x00900000
|
||||
#define OP_ADDSI 0x02900000
|
||||
#define OP_B 0x0A000000
|
||||
#define OP_BL 0x0B000000
|
||||
#define OP_CMP 0x01500000
|
||||
|
@ -16,12 +18,16 @@
|
|||
#define OP_MOV 0x01A00000
|
||||
#define OP_MOVT 0x03400000
|
||||
#define OP_MOVW 0x03000000
|
||||
#define OP_MRS 0x010F0000
|
||||
#define OP_POP 0x08BD0000
|
||||
#define OP_PUSH 0x092D0000
|
||||
#define OP_STMIA 0x08800000
|
||||
#define OP_STRI 0x05000000
|
||||
#define OP_STRBI 0x05400000
|
||||
#define OP_SUBS 0x00500000
|
||||
|
||||
#define ADDR1_LSRI 0x00000020
|
||||
|
||||
#define COND_EQ 0x00000000
|
||||
#define COND_NE 0x10000000
|
||||
#define COND_MI 0x40000000
|
||||
|
@ -50,6 +56,14 @@ static uint32_t emitADDI(unsigned dst, unsigned src, unsigned imm) {
|
|||
return OP_ADDI | calculateAddrMode1(imm) | (dst << 12) | (src << 16);
|
||||
}
|
||||
|
||||
static uint32_t emitADDS(unsigned dst, unsigned src, unsigned op2) {
|
||||
return OP_ADDS | (dst << 12) | (src << 16) | op2;
|
||||
}
|
||||
|
||||
static uint32_t emitADDSI(unsigned dst, unsigned src, unsigned imm) {
|
||||
return OP_ADDSI | calculateAddrMode1(imm) | (dst << 12) | (src << 16);
|
||||
}
|
||||
|
||||
static uint32_t emitB(void* base, void* target) {
|
||||
uint32_t diff = (intptr_t) target - (intptr_t) base - WORD_SIZE_ARM * 2;
|
||||
diff >>= 2;
|
||||
|
@ -86,6 +100,10 @@ static uint32_t emitMOV(unsigned dst, unsigned src) {
|
|||
return OP_MOV | (dst << 12) | src;
|
||||
}
|
||||
|
||||
static uint32_t emitMOV_LSRI(unsigned dst, unsigned src, unsigned imm) {
|
||||
return OP_MOV | ADDR1_LSRI | (dst << 12) | ((imm & 0x1F) << 7) | src;
|
||||
}
|
||||
|
||||
static uint32_t emitMOVT(unsigned dst, uint16_t value) {
|
||||
return OP_MOVT | (dst << 12) | ((value & 0xF000) << 4) | (value & 0x0FFF);
|
||||
}
|
||||
|
@ -94,6 +112,10 @@ static uint32_t emitMOVW(unsigned dst, uint16_t value) {
|
|||
return OP_MOVW | (dst << 12) | ((value & 0xF000) << 4) | (value & 0x0FFF);
|
||||
}
|
||||
|
||||
static uint32_t emitMRS(unsigned dst) {
|
||||
return OP_MRS | (dst << 12);
|
||||
}
|
||||
|
||||
static uint32_t emitPOP(unsigned mask) {
|
||||
return OP_POP | mask;
|
||||
}
|
||||
|
@ -116,6 +138,16 @@ static uint32_t emitSTRI(unsigned reg, unsigned base, int offset) {
|
|||
return op;
|
||||
}
|
||||
|
||||
static uint32_t emitSTRBI(unsigned reg, unsigned base, int offset) {
|
||||
uint32_t op = OP_STRBI | (base << 16) | (reg << 12);
|
||||
if (offset > 0) {
|
||||
op |= 0x00800000 | offset;
|
||||
} else {
|
||||
op |= -offset & 0xFFF;
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
static uint32_t emitSUBS(unsigned dst, unsigned src1, unsigned src2) {
|
||||
return OP_SUBS | (dst << 12) | (src1 << 16) | src2;
|
||||
}
|
||||
|
@ -152,6 +184,16 @@ static uint32_t* flushPrefetch(uint32_t* code, uint32_t op0, uint32_t op1) {
|
|||
return code;
|
||||
}
|
||||
|
||||
static uint32_t* loadReg(uint32_t* code, unsigned emureg, unsigned sysreg) {
|
||||
EMIT(code, LDRI, AL, sysreg, 4, emureg * sizeof(uint32_t));
|
||||
return code;
|
||||
}
|
||||
|
||||
static uint32_t* flushReg(uint32_t* code, unsigned emureg, unsigned sysreg) {
|
||||
EMIT(code, STRI, AL, sysreg, 4, emureg * sizeof(uint32_t));
|
||||
return code;
|
||||
}
|
||||
|
||||
static bool needsUpdatePrefetch(struct ARMInstructionInfo* info) {
|
||||
if ((info->operandFormat & (ARM_OPERAND_MEMORY_1 | ARM_OPERAND_AFFECTED_1)) == ARM_OPERAND_MEMORY_1) {
|
||||
return true;
|
||||
|
@ -252,9 +294,49 @@ void ARMDynarecRecompileTrace(struct ARMCore* cpu, struct ARMDynarecTrace* trace
|
|||
if (needsUpdatePrefetch(&info)) {
|
||||
code = flushPrefetch(code, cpu->memory.load16(cpu, address, 0), cpu->memory.load16(cpu, address + WORD_SIZE_THUMB, 0));
|
||||
}
|
||||
EMIT(code, MOVW, AL, 1, instruction);
|
||||
EMIT(code, MOV, AL, 0, 4);
|
||||
EMIT(code, BL, AL, code, _thumbTable[instruction >> 6]);
|
||||
|
||||
unsigned rd = 0;
|
||||
unsigned rn = 1;
|
||||
unsigned rm = 2;
|
||||
switch (info.mnemonic) {
|
||||
case ARM_MN_ADD:
|
||||
if (info.operandFormat & ARM_OPERAND_REGISTER_2) {
|
||||
code = loadReg(code, info.op2.reg, rn);
|
||||
}
|
||||
if (info.operandFormat & ARM_OPERAND_REGISTER_3) {
|
||||
code = loadReg(code, info.op3.reg, rm);
|
||||
}
|
||||
switch (info.operandFormat & (ARM_OPERAND_2 | ARM_OPERAND_3)) {
|
||||
case ARM_OPERAND_REGISTER_2 | ARM_OPERAND_REGISTER_3:
|
||||
EMIT(code, ADDS, AL, rd, rn, rm);
|
||||
break;
|
||||
case ARM_OPERAND_REGISTER_2 | ARM_OPERAND_IMMEDIATE_3:
|
||||
EMIT(code, ADDSI, AL, rd, rn, info.op3.immediate);
|
||||
break;
|
||||
case ARM_OPERAND_IMMEDIATE_2:
|
||||
code = loadReg(code, info.op1.reg, rd);
|
||||
EMIT(code, ADDSI, AL, rd, rd, info.op2.immediate);
|
||||
break;
|
||||
case ARM_OPERAND_REGISTER_2:
|
||||
code = loadReg(code, info.op1.reg, rd);
|
||||
EMIT(code, ADDS, AL, rd, rd, rn);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
code = flushReg(code, info.op1.reg, rd);
|
||||
if (info.affectsCPSR) {
|
||||
EMIT(code, MRS, AL, 1);
|
||||
EMIT(code, MOV_LSRI, AL, 1, 1, 28);
|
||||
EMIT(code, STRBI, AL, 1, 4, 16 * sizeof(uint32_t) + 3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
EMIT(code, MOVW, AL, 1, instruction);
|
||||
EMIT(code, MOV, AL, 0, 4);
|
||||
EMIT(code, BL, AL, code, _thumbTable[instruction >> 6]);
|
||||
break;
|
||||
}
|
||||
if (info.branchType == ARM_BRANCH) {
|
||||
struct Label* label = NULL;
|
||||
uint32_t base = address + info.op1.immediate + WORD_SIZE_THUMB;
|
||||
|
|
Loading…
Reference in New Issue