Skip to content
Game 0 Unit 14 of 16 1 hr learning time

Bigger Than a Byte

A byte stops at 255 — too small for an address. The 6510 has no 16-bit registers, so you hold a big number as two bytes and add it by hand, low byte first — and the carry flag becomes the bridge between them.

88% of Meet The Machine

One byte holds 0 to 255. But a screen address runs up to 65535 — far past what a byte can carry. You've been using numbers that big all along: $0400, $D800, $C000 are all sixteen-bit. So how does the machine hold them?

On the Spectrum's Z80 there were sixteen-bit registers — pairs that held a whole address and added in one go. The 6510 has none. A, X and Y are each eight bits, full stop. So a sixteen-bit number is kept as two bytes — a low byte and a high byte — like the units and the "hundreds" of a number, except each digit counts to 255 before it rolls over. $04F0 is high byte $04, low byte $F0.

To add to a sixteen-bit value, you add byte by byte, low first — and here the carry flag from Unit 12 finally shows what it's for. Add the low bytes; if they overflow, the carry comes on. Add the high bytes without clearing it, and that carry flows in — the "carry the one" from school arithmetic, in silicon.

What you'll see by the end

The C64 screen surrounded by a green border.
A 16-bit add by hand: 40 added to $04F0 carries into the high byte, climbing $04 to $05 (green), with nothing added to it directly.

A green border — colour 5. We held the value $04F0, added 40 to it, and showed the high byte. It was $04. It came out $05 — green. The high byte climbed by one, and nothing added directly to it: the carry from the low byte did it.

Adding two bytes, low first

; Meet the Machine - Unit 14: Bigger Than a Byte
; Assemble with: acme -f cbm -o wide.prg wide.asm

*= $0801
!byte $0c,$08,$0a,$00,$9e,$32,$30,$36,$31,$00,$00,$00

*= $080d
        ; hold the 16-bit value $04F0 as two bytes: low, then high
        lda #$f0
        sta $fb         ; low byte
        lda #$04
        sta $fc         ; high byte

        ; add 40 ($28) to it — 16 bits, low byte first
        clc
        lda $fb
        adc #$28        ; low + 40 overflows past 255 -> carry set
        sta $fb
        lda $fc
        adc #$00        ; high + 0 + the carry that just climbed up
        sta $fc

        lda $fc         ; show the high byte ...
        sta $d020       ; ... it was 4, now it's 5 — green
loop    jmp loop

We park $04F0 in two zero-page boxes, $FB (low) and $FC (high). Then: clc, add 40 to the low byte — $F0 + $28 is $118, too big for a byte, so it keeps $18 and sets the carry. Now add the high byte with adc #$00 — zero, plus that carry — and $04 becomes $05. No clc between the two adds: the whole point is to let the carry climb from the low byte to the high one. Show the high byte and the border goes green.

Assemble and run

acme -f cbm -o wide.prg wide.asm

The high byte ticks from 4 to 5 — green — carried up from below.

Try this: a step that doesn't carry

Change the starting low byte to lda #$00 (so the value is $0400). Now $00 + $28 is $28 — no overflow, carry stays clear — and the high byte stays $04 (purple). Adding only moves the high byte when the low byte overflows into it. Same code; this time the carry has nothing to climb.

Try this: show the low byte instead

Change the last two lines to read lda $fb (the low byte) and sta $d020. With the original $04F0 start you'll see $18's colour instead — the other half of the sixteen-bit answer. Two bytes, one number.

A pointer is the next step — but not here

A sixteen-bit value like this is how you hold a screen address — and stepping it (add 40, land one row down) is how a game walks down a wall or scrolls a starfield. But to write through an address you compute, not one baked into the instruction, needs a different addressing mode — the movable pointer we set aside back in Unit 9. That's the first thing the first game teaches, exactly when you need it. Here, the arithmetic; there, the pointer.

If it doesn't work

  • The high byte didn't change. Either the low add didn't overflow (check the start is $F0), or you slipped a clc between the two adds and wiped out the carry before it could climb. The low add gets the clc; the high add must not.
  • The answer is off by 256-ish. You added to the wrong byte, or in the wrong order. Low byte first, then high.
  • acme complains about $fb. Zero-page boxes $FB/$FC are free RAM to borrow; check there's no #lda $fb reads the box, lda #$fb would load the number.

What you've learnt

The 6510 has no 16-bit registers, so a number bigger than a byte is two bytes — low and high — and you add it low-first, letting the carry chain into the high byte. The carry flag is the bridge between them.

What's next

That's the last of the machine's everyday fluency with numbers. One capability is still untouched — the one you hear. Next — The Machine Speaks Back — the SID, the C64's three-voice synthesiser: set a handful of registers and the chip holds a note on its own, while your code does nothing at all.