Исправление кода эмуляции fake6502.c

 Вернулся к незавершенному проекту эмуляции 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);
}

На форуме предложено другое решение:

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);
}

Исправил код и тест завершен. Осталось добавить некоторые функции и закончить эмуляцию прерываний.

Комментарии