Page 1 of 1

SBC #0?

Posted: Mon Oct 06, 2025 1:52 pm
by Maury Markowitz
I'm completely noob to 6502 ASM, so please be gentle...

I'm looking through the source code for Atari BASIC and the Atari base ROMs. I find a number of instances of something like

Code: Select all

ADC #0
or

Code: Select all

SBC #0
.

Am I correct in thinking these are being used as an analog of the non-existing

Code: Select all

CPA #0
?

If so, why do some use ADC and others use SBC? What is the reason to use one or the other?

Re: SBC #0?

Posted: Mon Oct 06, 2025 2:07 pm
by John West
ADC and SBC both add the carry flag to the sum. So ADC #0 will either leave A as it is, or add 1 to it, and SBC #0 will either subtract 1 or leave A unchanged. Without seeing the code you're looking at, my guess would be that these instructions follow other ADC or SBC instructions, and are used to add an 8 bit value to a 16 bit value, like this:

Code: Select all

    lda result
    clc
    adc value
    sta value
    lda result+1
    adc #0
    sta result+1
to add 8 bit value to 16 bit result, or

Code: Select all

    lda result
    sec
    sbc value
    sta value
    lda result+1
    sbc #0
    sta result+1
to subtract 8 bit value to 16 bit result.

The carry flag is used to handle the carry between individual bytes of a larger addition or subtraction. ADC and SBC always use the carry flag: there is no ADD or SUB instruction. So it's normal to start an addition with either CLC (for addition) or SEC (for subtraction) to say that there is no carry into the lowest byte.

The reason that you start with C=1 for subtraction is that it's actually an addition in disguise: rather than implementing another circuit to do the subtraction directly, it uses the addition circuit. To subtract, negate the second operand and then add it. To negate in two's complement you invert every bit and then add one. And rather than having more circuitry to add one, you do that by starting a subtraction with the carry flag set.

If CPA is meant to be "compare A", in line with CPX and CPY, then it does exist: it's called CMP.

Re: SBC #0?

Posted: Mon Oct 06, 2025 3:32 pm
by BigDumbDinosaur
Maury Markowitz wrote:
I'm completely noob to 6502 ASM, so please be gentle...

I'm looking through the source code for Atari BASIC and the Atari base ROMs. I find a number of instances of something like

Code: Select all

ADC #0
or

Code: Select all

SBC #0
...

Also, don’t be surprised if you see something such as ORA #0.  It’s an alternative to CMP #0 to check for zero without affecting the content of the accumulator or the carry flag.

Mentioning checking for zero brings up a useful characteristic of the 6502 family.  Anything that affects the accumulator or index registers performs an automatic compare-to-zero operation.  For example, TAX will set or clear the z flag in the status register according to what has been copied from the accumulator to the X-register (.X).  Similarly, DEX will automatically set z if decrementing .X results in zero.  Taking advantage of this behavior allows for more-succinct and faster-acting code to be written.

Re: SBC #0?

Posted: Mon Oct 06, 2025 3:39 pm
by BigEd
Allow me to offer a very belated welcome here, Maury!

Re: SBC #0?

Posted: Fri Oct 17, 2025 12:49 am
by White Flame
Of course, it is shorter and faster to optionally increment upper bytes instead of `lda/adc#0/sta` chaining on each:

Code: Select all

; Adding an 8-bit unsigned delta to a 32-bit num

lda num+0
adc delta
sta num+0

bcc done  ; if the addition carried, bump the next number
inc num+1

bne done  ; if the increment went to zero, bump the next number
inc num+2

bne done  ; if the increment went to zero, bump the next number
inc num+3

done:
While the initial bcc can be done for subtraction, you can't easily test a `dec num` for underflow to $FF like you can check `inc num` with beq/bne, so you can only do one upper byte decrement this way.

However, it must also be mentioned that the examples you were looking at might not technically be doing upper-byte math, but could be changing values based on flags that ended up in the carry bit.

Re: SBC #0?

Posted: Fri Oct 31, 2025 4:55 pm
by Maury Markowitz
This is all good stuff!

BTW, the background here is for some reason I got interested in whether or not a TZA/TZX/TZY (transfer zero to...) would be useful. In Atari BASIC that would remove 132 #0's, about 1.5% of the total code. I expected to see lots of these, and when paging through them I was surprised to find the ADCs.

John, you mentioned this might be in a 16-bit adder, which may be the case but I can't really tell. It's in some code that searches a table of strings for a given entry, and I suppose that maybe it's calculating an address? But I can't seem to find the code where it does anything with the LSB, but that's entirely possible that it's just my noob.

I wish I could find the code in text form on the 'net, every place I find it is in a ZIP.

Re: SBC #0?

Posted: Fri Oct 31, 2025 6:27 pm
by John West
It would be a lot easier to help if you could post the code you're looking at.

I found a binary of the Atari 400 BASIC cartridge at https://www.atarimania.com/utility-atar ... 13284.html and disassembled that (attached). It's in CART format, which I know nothing about - I just removed the first 16 bytes and hoped that would work.

I can only see four occurrences of ADC #$00 in there, and they all follow the pattern of adding an 8 bit number to a 16 bit number. For example, at $A490 we have

Code: Select all

A490   18         LA490     CLC
A491   98                   TYA
A492   65 95                ADC $95
A494   A8                   TAY
A495   A5 96                LDA $96
A497   69 00                ADC #$00
This takes the 8 bit number in Y, adds it to the contents of $95, and puts the result back in Y. It then adds 0 (and carry) to the contents of $96, leaving the result in A. Later code (at $A468) stores this result back in $95/$96.

Re: SBC #0?

Posted: Fri Oct 31, 2025 6:45 pm
by BigDumbDinosaur
Maury Markowitz wrote:
It's in some code that searches a table of strings for a given entry, and I suppose that maybe it's calculating an address?

ADC #0 is commonly found in code that does pointer arithmetic.  I use that bit of code a lot.