ARM Dynarec: Implement Thumb ADD

This commit is contained in:
Jeffrey Pfau 2016-07-31 10:26:07 -07:00
parent 188d326b9a
commit 6613530534
1 changed files with 85 additions and 3 deletions

View File

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