Вернулся к незавершенному проекту эмуляции MOS6502 и стал лепить симулятор+отладчик. На сладкое остался functional test, который выполняется очень долго и иногда вылетает с ошибкой. Вчера тест споткнулся на тесте BCD при сложении/вычитании ADC/SBC. Стал разбираться, в чем причина. Оригинальный код:
static void adc() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
if ((a & 0xF0) > 0x90) {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
static void sbc() {
penaltyop = 1;
value = getvalue() ^ 0x00FF;
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
a -= 0x66;
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
if ((a & 0xF0) > 0x90) {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
penaltyop = 1;
value = getvalue();
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
if ((a & 0xF0) > 0x90) {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
static void sbc() {
penaltyop = 1;
value = getvalue() ^ 0x00FF;
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
a -= 0x66;
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
if ((a & 0xF0) > 0x90) {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
На форуме предложено другое решение:
static void adc() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) /* detect and apply BCD nybble carries */
result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
#endif
carrycalc(result);
saveaccum(result);
}
static void sbc() {
penaltyop = 1;
value = getvalue() ^ 0x00FF; /* ones complement */
#ifndef NES_CPU
if (status & FLAG_DECIMAL) /* use nines complement for BCD */
value -= 0x0066;
#endif
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) /* detect and apply BCD nybble carries */
result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
#endif
carrycalc(result);
saveaccum(result);
}
penaltyop = 1;
value = getvalue();
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) /* detect and apply BCD nybble carries */
result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
#endif
carrycalc(result);
saveaccum(result);
}
static void sbc() {
penaltyop = 1;
value = getvalue() ^ 0x00FF; /* ones complement */
#ifndef NES_CPU
if (status & FLAG_DECIMAL) /* use nines complement for BCD */
value -= 0x0066;
#endif
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) /* detect and apply BCD nybble carries */
result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
#endif
carrycalc(result);
saveaccum(result);
}
Исправил код и тест завершен. Осталось добавить некоторые функции и закончить эмуляцию прерываний.
Комментарии
Отправить комментарий