6502 Emulation The Right Way to Implement ADC and SBC

I am working on an emulator for the MOS 6502, but I just can't get the ADC and SBC to work correctly. I am testing my emulator with the program AllSuiteA loaded in 0x4000 in emulated memory, and for test09 my current ADC and SBC implementations are simply not getting the correct flags. I tried changing my algorithms countless times, but each time the carry flag and the overflow flag are large enough to cause matter, and cause branch / non-branch verification.

Both of my features are based on this.

The memory [0x10000] is the Battery. It is stored outside the memory range, so I can have a separate addressing operator.

This is one of my implementations of these functions:

case "ADC":
    var t = memory[0x10000] + memory[address] + getFlag(flag_carry);
    (memory[0x10000] & 0x80) != (t & 0x80) ? setFlag(flag_overflow) : clearFlag(flag_overflow);
    signCalc(memory[0x10000]);
    zeroCalc(t);

    t > 255 ? setFlag(flag_carry) : clearFlag(flag_carry);

    memory[0x10000] = t & 0xFF;
break;

case "SBC":
    var t = memory[0x10000] - memory[address] - (!getFlag(flag_carry));
    (t > 127 || t < -128) ? setFlag(flag_overflow) : clearFlag(flag_overflow);

    t >= 0 ? setFlag(flag_carry) : clearFlag(flag_carry);
    signCalc(t);
    zeroCalc(t);

    memory[0x10000] = t & 0xFF;
break;

, . , , .

+4
3

, , 6502 "" ""! , , . !

, . , SBC - 6502 , , . , , , , "" .

, , . 2008 , , . #, :

case 105: // ADC Immediate
_memTemp = _mem[++_PC.Contents];
_TR.Contents = _AC.Contents + _memTemp + _SR[_BIT0_SR_CARRY];
if (_SR[_BIT3_SR_DECIMAL] == 1)
{
  if (((_AC.Contents ^ _memTemp ^ _TR.Contents) & 0x10) == 0x10)
  {
    _TR.Contents += 0x06;
  }
  if ((_TR.Contents & 0xf0) > 0x90)
  {
    _TR.Contents += 0x60;
  }
}
_SR[_BIT6_SR_OVERFLOW] = ((_AC.Contents ^ _TR.Contents) & (_memTemp ^ _TR.Contents) & 0x80) == 0x80 ? 1 : 0;
_SR[_BIT0_SR_CARRY] = (_TR.Contents & 0x100) == 0x100 ? 1 : 0;
_SR[_BIT1_SR_ZERO] = _TR.Contents == 0 ? 1 : 0;
_SR[_BIT7_SR_NEGATIVE] = _TR[_BIT7_SR_NEGATIVE];
_AC.Contents = _TR.Contents & 0xff;
break;
+7

( , NES 6502, - . , , NES.)

SBC , ADC. , , ADC. , arg -arg - 1 , , carry .

SBC . .

static void sbc(uint8_t arg) { adc(~arg); /* -arg - 1 */ }

ADC - . , "". - , , , :

  • , - .
  • , - .

(1) (2) :

  • , .

XOR overflow ( ADC ):

static void adc(uint8_t arg) {
    unsigned const sum = a + arg + carry;
    carry = sum > 0xFF;
    // The overflow flag is set when the sign of the addends is the same and
    // differs from the sign of the sum
    overflow = ~(a ^ arg) & (a ^ sum) & 0x80;
    zn = a /* (uint8_t) */ = sum;
}

(a ^ arg) 0x80 , a arg . ~ , 0x80, a arg .

overflow = <'a' and 'arg' have the same sign> &  
           <the sign of 'a' and 'sum' differs> &  
           <extract sign bit>

ADC ( ) zero negative.

( NES) . " " ( ).

( NES - ), , ( , , , ).

+10

6502 C64, VIC 20 Atari 2600 (http://www.z64k.com), Lorenzes, bclark asap. , , . , , . , , . ADC, SBC ARR ( ARR).

public ALU ADC=new ALU(9,1,-1);
public ALU SBC=new ALU(15,-1,0);
public ALU ARR=new ALU(5,1,-1){
    protected void setSB(){AC.ror.execute();SB=AC.value;}
    protected void fixlo(){SB=(SB&0xf0)|((SB+c0)&0x0f);}
    protected void setVC(){V.set(((AC.value^(SB>>1))&0x20)==0x20);C.set((SB&0x40)==0x40);if((P&8)==8){Dhi(hb);}}
};
public class ALU{
protected final int base,s,m,c0,c1,c2;
protected int lb,hb;
public ALU(int base,int s,int m){this.base=base;this.s=s;this.m=m;c0=6*s;c1=0x10*s;c2=c0<<4;}
public void execute(int c){// c= P&1 for ADC and ARR, c=(~P)&1 for SBC, P=status register
    lb=(AC.value&0x0f)+(((DL.value&0x0f)+c)*s);
    hb=(AC.value&0xf0)+((DL.value&0xf0)*s);
    setSB();
    if(((P&8)==8)&&(lb&0x1f)>base){fixlo();}//((P&8)==8)=Decimal mode
    N.set((SB&0x80)==0x80);
    setVC();
    AC.value=SB&0xff;
}
protected void setSB(){SB=hb+lb;Z.set((SB&0xff)==0);}
protected void fixlo(){SB=(hb+c1)|((SB+c0)&0x0f);}
protected void Dhi(int a){if((a&0x1f0)>base<<4){SB+=c2;C.set(s==1);}}
protected void setVC(){V.set(((AC.value^SB)&(AC.value^DL.value^m)&0x80)==0x80);C.set(SB>=(0x100&m));if((P&8)==8){Dhi(SB);}}

}

+1

All Articles