Addition and Subtraction instructions
Simple arithmetic is performed on accumulators with the ADD, SUB, ADC, and SBC instructions. The destination is always the accumulator and the source a memory operand. These instructions are regular across all addressing modes.
To perform addition on the index registers try the LEA instruction.
adda #20 ; A takes the value of A+20 addb #-30 ; add a signed value to B (which likewise is treated as signed) subd #$1000 ; 16-bits available for ADD and SUB, but not ADC and SBC adcb ,y ; indexed addressing sbca <reduction ; direct paged addressing
ADD
Adds a binary memory operand to an accumulator, A, B, or D. Values can be signed twos complement, or unsigned - it's up to the programmer to be consistent in this regard.
For unsigned values test the Carry flag afterwards; it will be set if there was an overflow from bit 7. For signed values an unintentional overflow from bit 6 will set the Overflow flag. The Zero flag and Negative flag are also set as per the result.
DAA
After an addition of two valid unsigned Binary Coded Decimal bytes the Decimal Add Adjust instruction adjusts the value of A to produce a correct BCD result. A valid BCD byte, when read as a hexadecimal value, is a valid two-digit decimal. For example $42 (normally 66) is actually decimal 42 if we chose it to be a BCD value; and $39+$13=$4C, but is transformed to $52 after DAA.
How does it work? For the 8-bit ADD instruction only, the Half-carry flag is set in the result of a carry from bit 3 to bit 4. This is used together with the Carry as part of an intricate adjustment based on the values of each nybble.
What's the point of BCD? In the early days of calculators the conversion from decimal to binary and back again was far more complex than any arithmetic they were likely to perform. Hence this easy to read and display internal format. Nowadays it is pretty well obsolete.
ADC
Adds a memory operand, together with the Carry to an 8-bit accumulator, A, or B. There is no 16-bit version of this instruction. Multi-byte arithmetic can be performed by looping using ADC to add bytes, including the carry from the previous addition, starting with the least significant byte.
SUB
Subtracts a binary memory operand from an accumulator, A, B, or D. Values can be signed twos complement, or unsigned - it's up to the programmer to be consistent in this regard. Flags are set and tested as per ADD.
SBC
Subtracts a binary memory operand, together with the Carry (sometimes called the Borrow in this context) from an 8-bit accumulator, A, or B. There is no 16-bit version of this instruction.
When the Carry flag is clear this is just like SUB. When the Carry is set a value of 1 is subtracted first, so for example, LDA #10; SBCA #3 loads A with 10-1-3, so A becomes 6. Therefore SBC can be used for multi-precision arithmetic just like ADC.
Examples
Convert a list of bytes representing decimal digits ranging from 0 to 9 to equivalent printable ASCII characters.
ldb #numDigits printLoop: lda, x+ adda #$30 ; add ASCII '0' to 0..9 range byte for a printable character jsr printChar decb bne printLoop
Multi-precision binary arithmetic. Add the value addressed by Y to that addressed by X. Values are stored in byte big-endian form, so first the number of bytes in the value has to be added to the index register so we can start the addition with the least significant digit. Any carry caused by an addition is added to the next most significant byte.
ldb #numBytes leax numBytes,x leay numBytes,y andcc #$fe ; clear Carry flag multiByte: lda ,-y adca, -x sta ,x decb ; DEC instruction does not alter the Carry flag bne multiByte
Add a bonus to a score. Both are 8-bit signed; overflow is detected and adjusted for before storing the 16-bit total.
clra ldb score addb bonus bvc standard overflow: bmi corrected ; -$50 + -$32 = $B0 + $CE = $7E+Carry = $FF7E coma ; $50 + $32 = $0082 bra corrected standard: sex ; sign extend B into D, which is A(hi):B(lo) corrected: std total