# Why use an ADC or SBC with immediate zero on a 6502?

I'm perusing the Apple I version of BASIC, later known as Integer BASIC on the II. In several places I see...

``````ADC     #\$00
``````

or

``````SBC     #\$00
``````

Unless I'm mistaken, these mean add/subtract zero. What might the purpose of this be? I thought it might be something to do with carry testing, but none of the instances have obviously related branches or compares.

• LDA does just load, not subtract. Or am I reading something wrong? Commented Feb 26, 2020 at 14:20

Unless I'm mistaken, these mean add/subtract zero.

Almost. It means add/subtract zero plus carry.

So if the Carry flag is set, then `adc #\$00` will increment the accumulator by one. Otherwise, the same instruction will leave the accumulator alone.

Separately, the `adc` instruction may also set or clear the carry flags, if incrementing the accumulator meant that it rolled back round to 0.

What might the purpose of this be?

Adding an 8 bit value and a 16 bit value for example. My answer to this question explains that you can add two-byte values on the 6502 by adding the two values one byte at a time.

To do that, you'd first clear the carry flag, `adc value`, and `sta some_location_low`. Then, the carry flag tells you if a carry needs to be added to or subtracted from the next byte. That's what's happening in the `Se1bc` routine, which subtracts 2 from some value and then stores the pointer somewhere.

What's 2 in hexadecimal? It's 0x0002. Here you can see that one of the bytes is equal to 0. That just needs to be added to the upper 8 bits of the 16 bit value because this will implicitly add the carry from the lower 8 bits.

• I'm missing something: why would A+/-0 change the value of carry? Commented Feb 26, 2020 at 12:56
• @MauryMarkowitz The carry flag is set by a previous `adc` or `sbc`. By adding 0, carry is implicitly added as well. I hope my next edit will make this point clearer Commented Feb 26, 2020 at 13:00
• The carry flag is set by some previous instruction. There are ADC/SBC, but as well all compares (CMP/CPX/CPY) and the shifts (ASL/LSR/ROL/ROR). So an ADC #\$00 will include the carry set bei either of these - oh, and the obvious CLC/SEC of course. Commented Feb 26, 2020 at 14:26
• @Raffzahn In the source code linked ot by OP, that previous instruction happens to be another `sbc` or `adc`, as it's doing basically 16-bit additions and subtractions. Commented Feb 26, 2020 at 14:29
• @Raffzahn, Interesting, it seems that to fully understand all the cases will need more time than I have right now. I invite you to write an answer yourself if you fancy it; your answers are always a delight to read. Commented Feb 26, 2020 at 14:54

`ADC` and `SBC` add/subtract their parameter, plus/minus the value in the carry bit, to the accumulator. This means that you need to know the value in the carry before you start. If you want to add three to the accumulator, a typical sequence might be:

``````        CLC
``````

As mentioned in another answer, you use the carry to "carry through" the, well, carry when adding multibyte numbers:

``````        CLC
LDA xlo
STA resultlo    ; sets carry if xlo+ylo >\$FF, clears otherwise
LDA xhi
STA resulthi
``````

But it gets a bit more sophisticated than that. Since there is no "add/subtract without carry/borrow" instruction, you always need to take into account the state of the carry when you do an addition or subtraction. But rather than blindly putting in `CLC` and `SEC` instructions everywhere, you often can take advantage of what you know about the code before the addition to use the existing state of the carry.

The simplest case is when you are adding and know the carry must be clear:

``````        BCS somewhere   ; if carry set, go somewhere else
LDA someloc     ; does not affect carry flag
;               ; no need to CLC here; carry must be set if we got here!
``````

Even trickier, you might subtract 1 from the constant you add if you know the carry will be set, letting the carry provide that extra 1:

``````        BCC elsewhere   ; if carry clear, go somewhere else
LDA someloc
;               ; carry must be set if we reached this point
ADC #MYCONST-1  ; subtract 1 from MYCONST because set carry adds 1
``````

There are also cases where the carry explicitly contains the data you're trying to add. Say we're repeatedly reading an input value from a device and want to count the number of times the lowest bit was set (rather than clear):

``````        LDA input       ; we want to add contents of bit 0 of this input
ROR             ; rotate bit 0 into carry
LDA count
STA count
``````

All of this applies similarly to `SBC`, except that on the 6502 the carry bit becomes a "borrow bit"; you set it before subtracting and it will still be set if there was no underflow. (Other CPUs, such as the 6800, work the other way around when subtracting.)

I see... `ADC #\$00` or `SBC #\$00`. Unless I'm mistaken, these mean add/subtract zero.

Yes - and taking care of a previous carry.

What might the purpose of this be?

ADC adds the content of the carry flag as well. So an `ADC #\$00` simply adds just the carry flag to A.

The carry flag can be set by several instruction:

• Arithmetic (`ADC`, `SBC`)
• Compares (`CMP`/`CPX`/`CPY`)
• The shifts (`ASL`/`LSR`/`ROL`/`ROR`).

and the obvious

• direct manipulation (`CLC`/`SEC`) (*2)

I thought it might be something to do with carry testing,

It's kind of. It's like adding testing if carry is set and when true adding 1 to A.

Within the source there are several examples where addition/subtraction of immediate zero is used to incooperate carry:

• In line 938-941 Carry comes clearly from previous `ADC`
• Line 360-365 shows the same for use with `SBC`
• In line 520-22 Carry is delivered from a subroutine
• in line 1922-23 Carry comes from a `CMP`

*1 - Technically it should have been called Subtract with Borrow or `SBB`, as carry acts as borrow when subtracting. See as well this Wiki entry about Carry flag vs. borrow flag.

*2 - This is, BTW, a hidden gem. One always sees `CLC`/`SEC` before the start of an addition/subtraction, which lead easy to a hard coded impression it's the only usage. But it works as well the other way. Setting Carry before an addition will works as an implied offset of one. Quite handy in address calculation. Or certain formulas.

As an aside, the PowerPC has dedicated instructions for these operations: `addze` (add to zero extended) and `addme` (add to minus-one extended). They are specifically for propagating the carry out from an extended-width arithmetic operation to the next higher machine word.