CPU fixes - notably ADC/SBC in Decimal mode with invalid BCD values

This commit is contained in:
Jorj Bauer 2018-06-15 23:51:42 -04:00
parent fbb9c85468
commit aa45e49f40
1 changed files with 76 additions and 45 deletions

121
cpu.cpp
View File

@ -741,7 +741,7 @@ uint8_t Cpu::step()
break;
case O_TAX:
x = a;
SETNZA;
SETNZX;
break;
case O_BPL:
if (!(flags & F_N)) {
@ -977,64 +977,95 @@ uint8_t Cpu::step()
break;
case O_SBC:
{
uint8_t memTemp = readmem(param) ^ 0xFF;
uint8_t B = readmem(param) ^ 0xFF;
uint8_t Cin = (flags & F_C);
uint8_t Cout, Vout;
int16_t Aout;
int16_t c;
uint8_t v;
if (flags & F_D) {
cyclesThisStep++;
c = (a & 0x0F) + (memTemp & 0x0F) + (flags & F_C);
if (c < 0x10)
c = (c - 0x06) & 0x0f;
c += (a & 0xf0) + (memTemp & 0xf0);
v = (c >> 1) ^ c;
if (c < 0x100)
c = (c + 0xa0) & 0xff;
if ((flags & F_D) == 0) {
// Binary mode: same as ADC
Aout = a + B + Cin;
Vout = (a ^ Aout) & (B ^ Aout) & 0x80;
Cout = (Aout >= 0x100) ? 1 : 0;
a = Aout & 0xFF;
} else {
c = a + memTemp + (flags & F_C);
v = (c ^ a) & 0x80;
// Decimal mode
cyclesThisStep++;
Aout = (a & 0x0F) + (B & 0x0F) + Cin;
if (Aout < 0x10) {
Aout = (Aout - 0x06) & 0x0F;
}
Aout = Aout + (a & 0xF0) + (B & 0xF0);
Vout = (a ^ Aout) & (B ^ Aout) & 0x80;
if (Aout < 0x100) {
Aout = (Aout + 0xa0) & 0xFF;
}
Cout = (Aout >= 0x100) ? 1 : 0;
B = readmem(param);
int8_t AL = (a & 0x0F) - (B & 0x0F) + (Cin - 1);
Aout = a - B + Cin - 1;
if (Aout < 0) {
Aout = Aout - 0x60;
}
if (AL < 0) {
Aout = Aout - 0x06;
}
a = Aout & 0xFF;
}
if (((a ^ memTemp) & 0x80) != 0) {
v = 0;
}
FLAG(F_C, c > 0xFF);
FLAG(F_V, v);
a = c & 0xFF;
FLAG(F_C, Cout);
FLAG(F_V, Vout);
SETNZA;
}
break;
case O_ADC:
{
uint8_t memTemp = readmem(param);
uint8_t B = readmem(param);
uint8_t Cin = (flags & F_C);
uint8_t Cout, Vout;
uint16_t Aout;
int16_t c;
uint8_t v;
if (flags & F_D) {
cyclesThisStep++;
c = (a & 0x0F) + (memTemp & 0x0F) + (flags & F_C);
if (c > 0x09)
c = (c - 0x0a) | 0x10;
c += (a & 0xf0) + (memTemp & 0xf0);
v = (c >> 1) ^ c;
if (c > 0x99)
c += 0x60;
if ((flags & F_D) == 0x00) {
// Simple binary mode
Aout = a + B + Cin;
Vout = (a ^ Aout) & (B ^ Aout) & 0x80;
Cout = (Aout >= 0x100) ? 1 : 0;
a = Aout & 0xFF;
} else {
c = a + memTemp + (flags & F_C);
v = (c ^ a) & 0x80;
// Decimal mode
cyclesThisStep++;
Aout = (a & 0x0F) + (B & 0x0F) + Cin;
int tmpOverflow = 0;
if (Aout >= 0x0A) {
tmpOverflow = 0x10;
Aout = (Aout + 0x06) & 0x0F;
}
Aout = Aout | (a & 0xF0);
Aout = Aout + (B & 0xF0) + tmpOverflow;
Vout = 0;
if ( ((a ^ B) & 0x80) == 0) {
if (((a ^ Aout) & 0x80)) {
Vout = 1;
}
}
if (Aout >= 0xA0) {
Aout = Aout + 0x60;
Cout = 1;
} else {
Cout = 0;
}
a = Aout & 0xFF;
}
if (((a ^ memTemp) & 0x80) != 0) {
v = 0;
}
FLAG(F_C, c > 0xFF);
FLAG(F_V, v);
a = c & 0xFF;
FLAG(F_C, Cout);
FLAG(F_V, Vout);
SETNZA;
}
break;