1
0
mirror of https://github.com/rkujawa/rk65c02.git synced 2025-08-08 18:25:10 +00:00

Hopefully fix decimal mode handling. Hopefully.

This commit is contained in:
Radosław Kujawa
2017-02-12 22:56:07 +01:00
parent ce5330dfac
commit 23105b4861

View File

@@ -9,8 +9,8 @@ static void emul_smb(rk65c02emu_t *, void *, instruction_t *, uint8_t);
static void emul_bbr(rk65c02emu_t *, void *, instruction_t *, uint8_t); static void emul_bbr(rk65c02emu_t *, void *, instruction_t *, uint8_t);
static void emul_bbs(rk65c02emu_t *, void *, instruction_t *, uint8_t); static void emul_bbs(rk65c02emu_t *, void *, instruction_t *, uint8_t);
/* Convert 8-bit binary value into binary coded decimal. */ /* Convert 8-bit BCD to binary value. */
static inline uint8_t to_bcd(uint8_t val) static inline uint8_t from_bcd(uint8_t val)
{ {
uint8_t rv; uint8_t rv;
@@ -20,6 +20,24 @@ static inline uint8_t to_bcd(uint8_t val)
return rv; return rv;
} }
/* Convert 8-bit binary to BCD value. */
static inline uint8_t to_bcd(uint8_t val)
{
uint16_t shift, digit;
uint8_t bcd;
shift = 0;
bcd = 0;
while (val > 0) {
digit = val % 10;
bcd += (digit << shift);
shift += 4;
val /= 10;
}
return bcd;
}
/* /*
* Implementation of emulation of instructions follows below. * Implementation of emulation of instructions follows below.
*/ */
@@ -33,7 +51,7 @@ emul_adc(rk65c02emu_t *e, void *id, instruction_t *i)
arg = instruction_data_read_1(e, (instrdef_t *) id, i); arg = instruction_data_read_1(e, (instrdef_t *) id, i);
if (e->regs.P & P_DECIMAL) if (e->regs.P & P_DECIMAL)
res = to_bcd(e->regs.A) + to_bcd(arg); res = from_bcd(e->regs.A) + from_bcd(arg);
else else
res = e->regs.A + arg; res = e->regs.A + arg;
@@ -45,21 +63,25 @@ emul_adc(rk65c02emu_t *e, void *id, instruction_t *i)
else else
e->regs.P &= ~P_SIGN_OVERFLOW; e->regs.P &= ~P_SIGN_OVERFLOW;
if (e->regs.P & P_DECIMAL) if (e->regs.P & P_DECIMAL) {
/* if the result does not fit into two BCD digits then set carry */ /* if the result does not fit into two BCD digits then set carry */
if (res > 99) if (res > 99)
e->regs.P |= P_CARRY; e->regs.P |= P_CARRY;
else else
e->regs.P &= ~P_CARRY; e->regs.P &= ~P_CARRY;
else } else {
/* if the result does not fit into 8 bits then set carry */ /* if the result does not fit into 8 bits then set carry */
if (res > 0xFF) if (res > 0xFF)
e->regs.P |= P_CARRY; e->regs.P |= P_CARRY;
else else
e->regs.P &= ~P_CARRY; e->regs.P &= ~P_CARRY;
}
/* squash the result into accumulator's 8 bits, lol */ /* squash the result into accumulator's 8 bits, lol */
e->regs.A = (uint8_t) res; if (e->regs.P & P_DECIMAL)
e->regs.A = to_bcd(res);
else
e->regs.A = (uint8_t) res;
instruction_status_adjust_zero(e, e->regs.A); instruction_status_adjust_zero(e, e->regs.A);
instruction_status_adjust_negative(e, e->regs.A); instruction_status_adjust_negative(e, e->regs.A);
@@ -820,7 +842,10 @@ emul_sbc(rk65c02emu_t *e, void *id, instruction_t *i)
uint16_t res; /* meh */ uint16_t res; /* meh */
arg = instruction_data_read_1(e, (instrdef_t *) id, i); arg = instruction_data_read_1(e, (instrdef_t *) id, i);
res = e->regs.A - arg; if (e->regs.P & P_DECIMAL)
res = from_bcd(e->regs.A) - from_bcd(arg);
else
res = e->regs.A - arg;
/* if the carry flag is NOT set then "borrow" */ /* if the carry flag is NOT set then "borrow" */
if (!(e->regs.P & P_CARRY)) if (!(e->regs.P & P_CARRY))
@@ -831,14 +856,24 @@ emul_sbc(rk65c02emu_t *e, void *id, instruction_t *i)
else else
e->regs.P &= ~P_SIGN_OVERFLOW; e->regs.P &= ~P_SIGN_OVERFLOW;
/* if the result does not fit into 8 bits then clear carry */ if (e->regs.P & P_DECIMAL)
if (res & 0x8000) if ((res > 99) || (res < 0))
e->regs.P &= ~P_CARRY; e->regs.P |= P_CARRY;
else
e->regs.P &= ~P_CARRY;
else else
e->regs.P |= P_CARRY; /* if the result does not fit into 8 bits then clear carry */
if (res & 0x8000)
e->regs.P &= ~P_CARRY;
else
e->regs.P |= P_CARRY;
/* squash the result into accumulator's 8 bits, lol */ /* squash the result into accumulator's 8 bits, lol */
e->regs.A = (uint8_t) res; if (e->regs.P & P_DECIMAL)
e->regs.A = to_bcd(res);
else
e->regs.A = (uint8_t) res;
instruction_status_adjust_zero(e, e->regs.A); instruction_status_adjust_zero(e, e->regs.A);
instruction_status_adjust_negative(e, e->regs.A); instruction_status_adjust_negative(e, e->regs.A);