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

Adding and Taking Away

The most ordinary thing of all, finally: maths. inc, dec, add and sub on a value — and the carry flag, the machine's way of telling you a byte just overflowed.

75% of Meet The Machine

You can move values, compare them, loop, branch, point 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 most everyday of all: LET x = x + 1.

On the Z80 that's a single instruction:

  • inc a — add 1 to A. dec a takes 1 away.
  • add a, n — add n to A. sub n takes n away.
  • add a, b — add register B to A (add two values together).

There's a catch you already half-know: A holds eight bits, 0–255. Add past 255 and it can't hold the answer — it wraps round to 0 and sets the carry flag. That's the carry we borrowed in Test, Then Jump; here's where it comes from. (More in the Try this.)

What you'll see by the end

The screen surrounded by a cyan border.
A cyan border — colour 5, never loaded but computed: start at 2, inc twice to 4, add 1 to 5, then show it.

A cyan border — colour 5. But we never loaded 5; we computed it: start at 2, count up twice, add one. 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

; ============================================================================
; PRIMER — Beat 12: Adding and Taking Away
; ============================================================================
; You've moved values, compared them, looped and branched -- but never done
; the most ordinary thing of all: maths. BASIC's `LET x = x + 1` becomes one
; instruction here.
;
;   inc a       -- add 1 to A          (dec a takes 1 away)
;   add a, n    -- add n to A          (sub n takes n away)
;   add a, b    -- add register B to A
;
; A holds 8 bits, 0-255. Add past 255 and it wraps round to 0 and sets the
; CARRY flag -- the machine's "it overflowed" signal (the carry we borrowed
; back in Test, Then Jump). We meet it properly in the Try this.
;
; Here we COMPUTE the border colour rather than just loading it: start at 2,
; count up twice, add one -- 5, cyan. In a game the numbers are a score or a
; position you don't know in advance; here they're constants so you can check.
; ============================================================================

            org     32768

start:
            ld      a, 2             ; start at 2
            inc     a                ; + 1 -> 3
            inc     a                ; + 1 -> 4
            add     a, 1             ; + 1 -> 5   (cyan)
            out     ($FE), a         ; show the computed result

.loop:
            halt
            jr      .loop

            end     start

2, inc to 3, inc to 4, add a, 1 to 5 — then show it. Same shape as loading the border, but the value is worked out instead of written down. That's the whole difference between a constant and a calculation.

Assemble and run

pasmonext --sna arithmetic.asm primer.sna

A cyan border, arrived at by adding.

Try this: past the edge of a byte

Replace the body with ld a, 255 then add a, 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 jr c would fire on it. This is how you'd catch a score rolling over, and how numbers bigger than a byte are built (next unit but one).

Try this: taking away

Swap in sub: ld a, 6 then sub 2 leaves 4 (green). sub past zero wraps the other way — ld a, 0 then sub 1 gives 255, and sets carry again (this time as a "borrow"). Predict each before you run it.

When it's wrong, see why

  • pasmonext errors on add 1. The 8-bit add names its target: it's add a, 1, not add 1. (sub, oddly, is just sub 1A is assumed.)
  • The border colour is "wrong". It isn't — the border shows only the low 3 bits, so any result is shown mod 8. Check the value in the register view for the true answer.
  • You expected 256 and got 0. That's the lesson, not a bug: a byte stops at 255.

What you've learnt

inc/add add and dec/sub take away — and a result past 255 (or below 0) wraps and sets the carry flag, 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 Bitsand, or and xor let you set, clear and flip individual bits, like switching a single attribute's BRIGHT on without touching its colour.