65816: fix decimal mode ADC/SBC behavior [blargg, byuu, R. Belmont]

This commit is contained in:
R. Belmont 2010-03-14 00:53:08 +00:00
parent 0c96738a1e
commit 707f597134

View File

@ -658,94 +658,61 @@ INLINE uint EA_SIY(g65816i_cpu_struct *cpustate) {return MAKE_UINT_16(read_16_
SRC = OPER_8_##MODE(cpustate); \ SRC = OPER_8_##MODE(cpustate); \
if(FLAG_D) \ if(FLAG_D) \
{ \ { \
unsigned tmp1, tmp2, tmpA, tmpB; \ INT32 result, r0, r1, carry; \
tmp1 = REGISTER_A & 0x0F; \ r0 = REGISTER_A; \
tmp2 = (REGISTER_A >> 4) & 0x0F; \ r1 = SRC; \
tmpA = SRC&0x0F; \ carry = CFLAG_AS_1(); \
tmpB = (SRC >> 4) & 0x0F; \ result = (r0 & 0x0f) + (r1 & 0x0f) + (carry << 0); \
tmp1 = tmp1 + tmpA + CFLAG_AS_1(); \ if (result > 0x09) result += 0x06; \
tmp2 = tmp2 + tmpB; \ carry = result > 0x0f; \
FLAG_C = CFLAG_CLEAR; \ result = (r0 & 0xf0) + (r1 & 0xf0) + (carry << 4) + (result & 0x0f); \
if(tmp1 > 0x09) \ FLAG_V = ~(r0 ^ SRC) & (r0 ^ result) & 0x80; \
{ \ if (result > 0x9f) result += 0x60; \
tmp2++; \ FLAG_C = (result > 0xff) ? 0x100 : 0; \
tmp1 = ((tmp1 + 6) & 0x0F); \ FLAG_N = (result & 0x80); \
} \ FLAG_Z = REGISTER_A = MAKE_UINT_8(result); \
if(tmp2 > 0x09) \
{ \
tmp2=((tmp2 + 6) & 0x0F); \
FLAG_C = CFLAG_SET; \
} \
tmp16 = tmp1 | (tmp2 << 4); \
FLAG_V = VFLAG_ADD_8(SRC, REGISTER_A, tmp16); \
} \ } \
else \ else \
{ \ { \
FLAG_C = tmp16 = REGISTER_A + SRC + CFLAG_AS_1(); \ FLAG_C = tmp16 = REGISTER_A + SRC + CFLAG_AS_1(); \
FLAG_V = VFLAG_ADD_8(SRC, REGISTER_A, FLAG_C); \ FLAG_V = VFLAG_ADD_8(SRC, REGISTER_A, FLAG_C); \
} \
FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(tmp16); \ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(tmp16); \
} \
} }
#else #else
#define OP_ADC(MODE) \ #define OP_ADC(MODE) \
CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
SRC = OPER_16_##MODE(cpustate); \ SRC = OPER_16_##MODE(cpustate); \
if(!FLAG_D) \ INT32 result, r0, r1, carry; \
r0 = REGISTER_A; \
r1 = SRC; \
carry = CFLAG_AS_1(); \
if (!FLAG_D) \
{ \ { \
FLAG_C = REGISTER_A + SRC + CFLAG_AS_1(); \ result = r0 + r1 + carry; \
FLAG_V = VFLAG_ADD_16(SRC, REGISTER_A, FLAG_C); \
FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \
FLAG_N = NFLAG_16(REGISTER_A); \
FLAG_C = CFLAG_16(FLAG_C); \
BREAKOUT; \
} \ } \
else \ else \
{ \ { \
unsigned tmp16; \ result = (r0 & 0x000f) + (r1 & 0x000f) + (carry << 0); \
unsigned tmp1,tmp2,tmp3, tmp4, tmpA, tmpB, tmpC, tmpD; \ if(result > 0x0009) result += 0x0006; \
tmp1 = REGISTER_A & 0x0F; \ carry = result > 0x000f; \
tmp2 = (REGISTER_A >> 4) & 0x0F; \ result = (r0 & 0x00f0) + (r1 & 0x00f0) + (carry << 4) + (result & 0x000f); \
tmp3 = (REGISTER_A >> 8) & 0x0F; \ if(result > 0x009f) result += 0x0060; \
tmp4 = (REGISTER_A >> 12) & 0x0F; \ carry = result > 0x00ff; \
tmpA = SRC & 0x0F; \ result = (r0 & 0x0f00) + (r1 & 0x0f00) + (carry << 8) + (result & 0x00ff); \
tmpB = (SRC >> 4) & 0x0F; \ if(result > 0x09ff) result += 0x0600; \
tmpC = (SRC >> 8) & 0x0F; \ carry = result > 0x0fff; \
tmpD = (SRC >> 12) & 0x0F; \ result = (r0 & 0xf000) + (r1 & 0xf000) + (carry << 12) + (result & 0x0fff); \
tmp1 = tmp1 + tmpA + CFLAG_AS_1(); \
tmp2 = tmp2 + tmpB; \
tmp3 = tmp3 + tmpC; \
tmp4 = tmp4 + tmpD; \
FLAG_C = CFLAG_CLEAR; \
if(tmp1 > 9) \
{ \
tmp2++; \
tmp1 = ((tmp1 + 6) & 0x0F); \
} \ } \
if(tmp2 > 9) \ FLAG_V = ~(r0 ^ r1) & (r0 ^ result) & 0x8000; \
{ \ FLAG_V >>= 8; \
tmp3++; \ if (FLAG_D && result > 0x9fff) result += 0x6000; \
tmp2 = ((tmp2 + 6) & 0x0F); \ FLAG_C = (result > 0xffff) ? 0x100 : 0; \
} \ FLAG_Z = REGISTER_A = MAKE_UINT_16(result); \
if(tmp3 > 9) \ FLAG_N = NFLAG_16(REGISTER_A);
{ \
tmp4++; \
tmp3 = ((tmp3 + 6) & 0x0F); \
} \
if(tmp4 > 9) \
{ \
FLAG_C = CFLAG_SET; \
tmp4 = ((tmp4 + 6) & 0x0F); \
} \
tmp16 = tmp1 | (tmp2 << 4) | (tmp3 << 8) | (tmp4 << 12); \
FLAG_V = VFLAG_ADD_16(SRC, REGISTER_A, tmp16); \
FLAG_Z = REGISTER_A = MAKE_UINT_16(tmp16); \
FLAG_N = NFLAG_16(REGISTER_A); \
}
#endif #endif
/* M6502 Logical AND with accumulator */ /* M6502 Logical AND with accumulator */
#undef OP_AND #undef OP_AND
#if FLAG_SET_M #if FLAG_SET_M
@ -1546,9 +1513,9 @@ INLINE uint EA_SIY(g65816i_cpu_struct *cpustate) {return MAKE_UINT_16(read_16_
#define OP_SBC(MODE) \ #define OP_SBC(MODE) \
CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ CLK(CLK_OP + CLK_R8 + CLK_##MODE); \
SRC = OPER_8_##MODE(cpustate); \ SRC = OPER_8_##MODE(cpustate); \
FLAG_C = ~FLAG_C; \
if(!FLAG_D) \ if(!FLAG_D) \
{ \ { \
FLAG_C = ~FLAG_C; \
FLAG_C = REGISTER_A - SRC - CFLAG_AS_1(); \ FLAG_C = REGISTER_A - SRC - CFLAG_AS_1(); \
FLAG_V = VFLAG_SUB_8(SRC, REGISTER_A, FLAG_C); \ FLAG_V = VFLAG_SUB_8(SRC, REGISTER_A, FLAG_C); \
FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C); \ FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C); \
@ -1557,93 +1524,53 @@ INLINE uint EA_SIY(g65816i_cpu_struct *cpustate) {return MAKE_UINT_16(read_16_
} \ } \
else \ else \
{ \ { \
unsigned tmp16; \ INT32 result, r0, r1, carry; \
signed tmp1, tmp2, tmpA, tmpB; \ r0 = REGISTER_A; \
DST = CFLAG_AS_1(); \ r1 = SRC; \
tmp1 = REGISTER_A & 0x0F; \ r1 ^= 0xff; \
tmp2 = (REGISTER_A >> 4) & 0x0F; \ carry = CFLAG_AS_1(); \
tmpA = SRC&0x0F; \ result = (r0 & 0x0f) + (r1 & 0x0f) + (carry << 0); \
tmpB = (SRC >> 4) & 0x0F; \ if (result <= 0x0f) result -= 0x06; \
tmp1 = tmp1 - tmpA - DST; \ carry = result > 0x0f; \
tmp2 = tmp2 - tmpB; \ result = (r0 & 0xf0) + (r1 & 0xf0) + (carry << 4) + (result & 0x0f); \
FLAG_C = CFLAG_CLEAR; \ FLAG_V = ~(r0 ^ r1) & (r0 ^ result) & 0x80; \
if(tmp1 < 0) \ if (result <= 0xff) result -= 0x60; \
tmp2--; \ FLAG_C = (result > 0xff) ? 0x100 : 0; \
if((tmp1 > 0x09) || (tmp1 < 0 )) \ FLAG_N = (result & 0x80); \
{ \ FLAG_Z = REGISTER_A = MAKE_UINT_8(result); \
tmp1 = ((tmp1 + 10) & 0x0F); \
} \
if(!(tmp2 < 0)) \
FLAG_C = CFLAG_SET; \
if((tmp2 > 0x09) || (tmp2 < 0)) \
{ \
tmp2=((tmp2 + 10) & 0x0F); \
} \
tmp16 = tmp1 | (tmp2 << 4); \
FLAG_V = VFLAG_SUB_8(SRC, REGISTER_A, tmp16); \
FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(tmp16); \
} }
#else #else
#define OP_SBC(MODE) \ #define OP_SBC(MODE) \
CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ CLK(CLK_OP + CLK_R16 + CLK_##MODE); \
SRC = OPER_16_##MODE(cpustate); \ SRC = OPER_16_##MODE(cpustate); \
FLAG_C = ~FLAG_C; \ INT32 result, r0, r1, carry; \
if(!FLAG_D) \ r0 = REGISTER_A; \
r1 = SRC; \
r1 ^= 0xffff; \
carry = CFLAG_AS_1(); \
if (!FLAG_D) \
{ \ { \
FLAG_C = REGISTER_A - SRC - CFLAG_AS_1(); \ result = r0 + r1 + carry; \
FLAG_V = VFLAG_SUB_16(SRC, REGISTER_A, FLAG_C); \
FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \
FLAG_N = NFLAG_16(REGISTER_A); \
FLAG_C = ~CFLAG_16(FLAG_C); \
BREAKOUT; \
} \ } \
else \ else \
{ \ { \
unsigned tmp16; \ result = (r0 & 0x000f) + (r1 & 0x000f) + (carry << 0); \
signed tmp1,tmp2,tmp3, tmp4, tmpA, tmpB, tmpC, tmpD; \ if(result <= 0x000f) result -= 0x0006; \
DST = CFLAG_AS_1(); \ carry = result > 0x000f; \
tmp1 = REGISTER_A & 0x0F; \ result = (r0 & 0x00f0) + (r1 & 0x00f0) + (carry << 4) + (result & 0x000f); \
tmp2 = (REGISTER_A >> 4) & 0x0F; \ if(result <= 0x00ff) result -= 0x0060; \
tmp3 = (REGISTER_A >> 8) & 0x0F; \ carry = result > 0x00ff; \
tmp4 = (REGISTER_A >> 12) & 0x0F; \ result = (r0 & 0x0f00) + (r1 & 0x0f00) + (carry << 8) + (result & 0x00ff); \
tmpA = SRC & 0x0F; \ if(result <= 0x0fff) result -= 0x0600; \
tmpB = (SRC >> 4) & 0x0F; \ carry = result > 0x0fff; \
tmpC = (SRC >> 8) & 0x0F; \ result = (r0 & 0xf000) + (r1 & 0xf000) + (carry << 12) + (result & 0x0fff); \
tmpD = (SRC >> 12) & 0x0F; \
tmp1 = tmp1 - tmpA - CFLAG_AS_1(); \
tmp2 = tmp2 - tmpB; \
tmp3 = tmp3 - tmpC; \
tmp4 = tmp4 - tmpD; \
FLAG_C = CFLAG_CLEAR; \
if(tmp1 < 0) \
tmp2--; \
if((tmp1 > 0x09) || (tmp1 < 0 )) \
{ \
tmp1 = ((tmp1 + 10) & 0x0F); \
} \ } \
if(tmp2 < 0) \ FLAG_V = ~(r0 ^ r1) & (r0 ^ result) & 0x8000; \
tmp3--; \ FLAG_V >>= 8; \
if((tmp2 > 0x09) || (tmp2 < 0)) \ if (FLAG_D && result <= 0xffff) result -= 0x6000; \
{ \ FLAG_C = (result > 0xffff) ? 0x100 : 0; \
tmp2=((tmp2 + 10) & 0x0F); \ FLAG_Z = REGISTER_A = MAKE_UINT_16(result); \
} \ FLAG_N = NFLAG_16(REGISTER_A);
if(tmp3 < 0) \
tmp4--; \
if((tmp3 > 0x09) || (tmp3 < 0 )) \
{ \
tmp3 = ((tmp3 + 10) & 0x0F); \
} \
if(!(tmp4 < 0)) \
FLAG_C = CFLAG_SET; \
if((tmp4 > 0x09) || (tmp4 < 0)) \
{ \
tmp4=((tmp4 + 10) & 0x0F); \
} \
tmp16 = tmp1 | (tmp2 << 4) | (tmp3 << 8) | (tmp4 << 12); \
FLAG_V = VFLAG_SUB_16(SRC, REGISTER_A, tmp16); \
FLAG_Z = REGISTER_A = MAKE_UINT_16(tmp16); \
FLAG_N = NFLAG_16(REGISTER_A); \
}
#endif #endif