GBA: Resolve shifting negative value issue in some thumb/arm opcodes

This commit is contained in:
retro-wertz 2019-01-17 09:03:14 +08:00 committed by Rafael Kitover
parent 59f76d05b8
commit 093818a1d7
2 changed files with 31 additions and 148 deletions

View File

@ -2575,10 +2575,8 @@ static INSN_REGPARM void arm9F0(uint32_t opcode)
// B <offset> // B <offset>
static INSN_REGPARM void armA00(uint32_t opcode) static INSN_REGPARM void armA00(uint32_t opcode)
{ {
int offset = opcode & 0x00FFFFFF; int32_t offset = ((int32_t)(opcode & 0x00FFFFFF) << 8) >> 6;
if (offset & 0x00800000) reg[15].I += offset;
offset |= 0xFF000000; // negative offset
reg[15].I += offset << 2;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 4; reg[15].I += 4;
ARM_PREFETCH; ARM_PREFETCH;
@ -2590,11 +2588,9 @@ static INSN_REGPARM void armA00(uint32_t opcode)
// BL <offset> // BL <offset>
static INSN_REGPARM void armB00(uint32_t opcode) static INSN_REGPARM void armB00(uint32_t opcode)
{ {
int offset = opcode & 0x00FFFFFF; int32_t offset = ((int32_t)(opcode & 0x00FFFFFF) << 8) >> 6;
if (offset & 0x00800000)
offset |= 0xFF000000; // negative offset
reg[14].I = reg[15].I - 4; reg[14].I = reg[15].I - 4;
reg[15].I += offset << 2; reg[15].I += offset;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 4; reg[15].I += 4;
ARM_PREFETCH; ARM_PREFETCH;

View File

@ -1700,215 +1700,102 @@ static INSN_REGPARM void thumbC8(uint32_t opcode)
} }
// Conditional branches /////////////////////////////////////////////////// // Conditional branches ///////////////////////////////////////////////////
#define THUMB_CONDITIONAL_BRANCH(COND) \
UPDATE_OLDREG; \
clockTicks = codeTicksAccessSeq16(armNextPC) + 1; \
if (COND) { \
uint32_t offset = (uint32_t)((int8_t)(opcode & 0xFF)) << 1; \
reg[15].I += offset; \
armNextPC = reg[15].I; \
reg[15].I += 2; \
THUMB_PREFETCH; \
clockTicks += codeTicksAccessSeq16(armNextPC) \
+ codeTicksAccess16(armNextPC) + 2; \
busPrefetchCount = 0; \
}
// BEQ offset // BEQ offset
static INSN_REGPARM void thumbD0(uint32_t opcode) static INSN_REGPARM void thumbD0(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(Z_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (Z_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BNE offset // BNE offset
static INSN_REGPARM void thumbD1(uint32_t opcode) static INSN_REGPARM void thumbD1(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(!Z_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (!Z_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BCS offset // BCS offset
static INSN_REGPARM void thumbD2(uint32_t opcode) static INSN_REGPARM void thumbD2(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(C_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (C_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BCC offset // BCC offset
static INSN_REGPARM void thumbD3(uint32_t opcode) static INSN_REGPARM void thumbD3(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(!C_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (!C_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BMI offset // BMI offset
static INSN_REGPARM void thumbD4(uint32_t opcode) static INSN_REGPARM void thumbD4(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(N_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (N_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BPL offset // BPL offset
static INSN_REGPARM void thumbD5(uint32_t opcode) static INSN_REGPARM void thumbD5(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(!N_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (!N_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BVS offset // BVS offset
static INSN_REGPARM void thumbD6(uint32_t opcode) static INSN_REGPARM void thumbD6(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(V_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (V_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BVC offset // BVC offset
static INSN_REGPARM void thumbD7(uint32_t opcode) static INSN_REGPARM void thumbD7(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(!V_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (!V_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BHI offset // BHI offset
static INSN_REGPARM void thumbD8(uint32_t opcode) static INSN_REGPARM void thumbD8(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(C_FLAG && !Z_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (C_FLAG && !Z_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BLS offset // BLS offset
static INSN_REGPARM void thumbD9(uint32_t opcode) static INSN_REGPARM void thumbD9(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(!C_FLAG || Z_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (!C_FLAG || Z_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BGE offset // BGE offset
static INSN_REGPARM void thumbDA(uint32_t opcode) static INSN_REGPARM void thumbDA(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(N_FLAG == V_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (N_FLAG == V_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BLT offset // BLT offset
static INSN_REGPARM void thumbDB(uint32_t opcode) static INSN_REGPARM void thumbDB(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(N_FLAG != V_FLAG);
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (N_FLAG != V_FLAG) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BGT offset // BGT offset
static INSN_REGPARM void thumbDC(uint32_t opcode) static INSN_REGPARM void thumbDC(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(!Z_FLAG && (N_FLAG == V_FLAG));
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if (!Z_FLAG && (N_FLAG == V_FLAG)) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// BLE offset // BLE offset
static INSN_REGPARM void thumbDD(uint32_t opcode) static INSN_REGPARM void thumbDD(uint32_t opcode)
{ {
UPDATE_OLDREG; THUMB_CONDITIONAL_BRANCH(Z_FLAG || (N_FLAG != V_FLAG));
clockTicks = codeTicksAccessSeq16(armNextPC);
if (Z_FLAG || (N_FLAG != V_FLAG)) {
reg[15].I += ((int8_t)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I;
reg[15].I += 2;
THUMB_PREFETCH;
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
busPrefetchCount = 0;
}
} }
// SWI, B, BL ///////////////////////////////////////////////////////////// // SWI, B, BL /////////////////////////////////////////////////////////////