Adding and Taking Away
The most ordinary thing of all, finally: maths. adc and sbc on a value — and the carry flag the 6510 makes you mind: clear it before you add, set it before you subtract.
You can move values, compare them, loop, branch, index and call — and yet you've never done the most ordinary thing a program does: arithmetic. Before you build a game, the last pieces of plain fluency. This one is the simplest: LET X = X + 1.
And here the 6510 has a quirk you'll meet on day one and never forget. There's no "add 1 to A" instruction — no inc a at all. Adding to the accumulator goes through one instruction, adc — ADd with Carry — and the name is a warning: it always adds the carry flag in too. So before the first add you clear the carry yourself:
clc— CLear the Carry. Do this before you start adding.adc #1— add 1 (plus the carry, which you just made sure is 0).sec/sbc #1— to subtract, SEt the Carry first, then SuBtract with Carry.
Forget the clc and your sum comes out one too high; forget the sec and your difference comes out one too low. It catches everyone once. (The index registers have their own steps — inx / dex / iny / dey — and those don't touch carry at all. It's the accumulator that makes you mind it.)
What you'll see by the end
A green border — colour 5. But we never loaded 5; we computed it: start at 2, clear the carry, add one three times. In a real game the numbers are a score or a position you don't know ahead of time. Here they're constants so you can check the sum yourself.
Computing a value
; Meet the Machine - Unit 12: Adding and Taking Away
; Assemble with: acme -f cbm -o maths.prg maths.asm
*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00
*= $080d
lda #2 ; start at 2
clc ; clear the carry BEFORE adding
adc #1 ; 2 + 1 = 3
adc #1 ; 3 + 1 = 4
adc #1 ; 4 + 1 = 5
sta $d020 ; show it — green
loop jmp loop
2, clc, then adc #1 three times — 3, 4, 5 — and show it. We clear the carry once, up front; after that no add overflows, so the carry stays clear and each adc #1 adds exactly one. Same shape as loading the border, but the value is worked out, not written down. That's the whole difference between a constant and a calculation.
Assemble and run
acme -f cbm -o maths.prg maths.asm
A green border, arrived at by adding.
Try this: past the edge of a byte
Replace the body with lda #255 then clc / adc #1, and watch A in the register view: it reads 0, not 256. A byte can't hold 256, so it wraps to 0 — and the carry flag is set, the machine flagging "that overflowed." A bcs would fire on it. This is how you'd catch a score rolling over — and, next unit but one, how numbers bigger than a byte are built.
Try this: taking away
Subtract with sec / sbc: lda #6, sec, sbc #2 leaves 4 (purple). Forget the sec and you'd get 3 instead — one short, because the missing carry counts as a borrow. And subtracting past zero wraps the other way: lda #0, sec, sbc #1 gives 255, this time clearing the carry (a borrow happened). Predict each before you run it.
If it doesn't work
- Your sum is one too high. You forgot the
clcbefore the firstadc— the leftover carry added an extra 1. - Your difference is one too low. You forgot the
secbefore the firstsbc. Subtraction needs the carry set to mean "no borrow." - The border colour looks "wrong". It isn't — the border shows only the low four bits, so any result is shown mod 16. Check the register view for the true answer.
What you've learnt
You add with clc / adc and subtract with sec / sbc — the 6510 folds the carry into every one, so you set it up first — and a result past 255 (or below 0) wraps and flips the carry, the machine's overflow signal.
What's next
Sometimes you don't want to change a whole number — just one bit of it. Next — Working With Bits — and, ora and eor let you clear, set and flip individual bits, the everyday way to throw one switch in a byte and leave the other seven alone.