Date : Thu, 11 May 1995 13:44:55 +0100
From : lamcw <lamcw@...>
Subject: ADC, SBC and BCD
Hello all,
I had some problems with emulating the SBC opcode recently. SBC performs
A-M-!C where !C is the complement of C or 1-C
i.e.
A-M-(1-C) or A-(M+1-C).
This is just textbook stuff. So I went ahead and coded
byte = M + 1 - C;
result = rega - byte;
if (rega>=byte) set C; else reset C;
Looks okay, the correct values were being churned out. Only when I came
across a game for another 6502 machine I'm emulating, did I notice that
either adds/subtractions were screwing up. Many hours of frustration later,
I realised I could not use the above strategy to evaluate the C flag.
Instead I needed
wu = rega - M - 1 - C; /* wu is unsigned int */
if (wu&256) reset C; else set C;
The first method fails when M=255 and C=0. Then byte=0 (if byte is an
unsigned char) and if rega=255 (say) the following 'if' statement will
set C when in fact it should reset C. The second method allows for this
and produces the correct C flag.
The bug in the first method is a little tricky to detect since it is
correct 255 out 256 times.
As for BCD arithmetic, I believe only the C flag functions as expected
both for ADC and SBC (in 64doc, it is claimed the C flag is incorrectly
set... but this is clearly unthinkable since multi-byte BCD subtractions
would not be possible). The N,V and Z flags are set according to the
BINARY result. i.e.
LDA#&99
SED
CLC
ADC#1
will leave a result of zero in A but Z will NOT be set. The BINARY result
is &9A and hence Z is reset. Same for N and V flags.
Hope this is of some help,
Regards,
Chris Lam,
Aston University,
U.K.