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

Adding and Taking Away

Arithmetic is two instructions: ADD and SUB. They work on a size you choose, and they leave the flags set for a branch to read. Master the size suffix and the carry between sizes and you've got the maths every program runs on.

74% of Meet The Machine

You've used numbers since Unit 1 — colours, counts, addresses. This unit looks straight at the arithmetic underneath: how the 68000 adds and subtracts, and the two things that catch people out.

The instructions themselves are short. ADD adds; SUB subtracts. Both take a size — .b, .w, .l — that says how wide the sum is, exactly like MOVE back in Unit 3. And both leave the flags set behind them, the same flags Unit 8's branches read: a sum that comes out zero sets the zero flag, a result that won't fit sets the carry. So arithmetic and decisions are joined at the hip — you add, then you branch on how the add turned out.

This unit keeps the sums visible by doing them to a colour: add a channel, take one away, and watch where the value lands.

What you'll see by the end

The Amiga screen filled with solid blue.
Blue — what's left after adding red and blue together, then subtracting the red back out.

A blue screen. The code starts with red, adds blue to it, then takes the red away again — and blue is what remains. Every step is a real add or sub, and the final number is what the channel arithmetic left behind.

Add, then take away

;──────────────────────────────────────────────────────────────
; Meet the Machine (Amiga) - Unit 14: Adding and Taking Away
;
; ADD and SUB are the whole of arithmetic. They work on a chosen size (.b/.w/.l)
; and leave the flags set for a branch to read. Here a colour is built by adding
; one channel and taking away another.
;──────────────────────────────────────────────────────────────

CUSTOM      equ $dff000
DMACON      equ $096
INTENA      equ $09a
INTREQ      equ $09c
COP1LC      equ $080
COPJMP1     equ $088
BPLCON0     equ $100
COLOR00     equ $180

            section code,code_c

start:
            lea     CUSTOM,a5
            move.w  #$7fff,INTENA(a5)
            move.w  #$7fff,INTREQ(a5)
            move.w  #$7fff,DMACON(a5)
            lea     copperlist,a0
            move.l  a0,COP1LC(a5)
            move.w  d0,COPJMP1(a5)
            move.w  #$8280,DMACON(a5)

            ; ----------------------------------------------- YOUR CODE START
            move.w  #$0f00,d0           ; start with red
            add.w   #$000f,d0           ; add blue  -> $0f0f (magenta)
            sub.w   #$0f00,d0           ; take the red back -> $000f (blue)
            move.w  d0,colourval        ; show the result
            ; ------------------------------------------------- YOUR CODE END

forever:
            bra.s   forever

copperlist:
            dc.w    BPLCON0,$0200
            dc.w    COLOR00
colourval:
            dc.w    $0000
            dc.w    $ffff,$fffe

Three sums build the answer:

move.w  #$0f00,d0           ; start with red
add.w   #$000f,d0           ; add blue  -> $0f0f (magenta)
sub.w   #$0f00,d0           ; take the red back -> $000f (blue)
move.w  d0,colourval        ; show the result

Because the colour's three channels sit in separate groups of bits, adding $000f only touches the blue channel and adding $0f00 only the red. So $0f00 + $000f is $0f0f — red and blue together, which is magenta — and subtracting $0f00 removes the red and leaves $000f, blue. The .w on each instruction says "work sixteen bits wide," which is the size a colour needs.

The flags moved with every line, even though nothing branched on them here. After the last sub the result is non-zero, so the zero flag is clear — and if you followed it with a beq, it wouldn't branch. That's the join from Unit 8: the sum sets the flags, the branch reads them.

Assemble, master, and run

make

A blue screen — red and blue added, then the red taken back.

Try this: change the sums

Swap the sub.w #$0f00 for sub.w #$000f. Now you remove the blue instead and land on $0f00 — red. Or drop the sub line entirely and keep the magenta. The screen is a readout of the arithmetic; change the numbers and you can predict the colour before you run it.

Try this: watch a carry happen

Carry is what spills out of one size into the next. Try move.w #$ffff,d0 then add.w #1,d0: the word wraps to $0000 and the carry flag is set, because the answer needed a seventeenth bit the word couldn't hold. This is how the machine adds numbers bigger than one register — add the low halves, then add the high halves with the carry, using ADDX. You won't need it for colours, but it's why .b, .w and .l exist.

If it doesn't work

  • A neighbouring channel changes too. A sum carried out of one channel into the next — $0f00 + $0100 overflows the red nibble. Keep each addend inside the channel you mean to change.
  • The colour is far from what you predicted. A size suffix slipped — .b only touches the low eight bits (green and blue), so a .b add never reaches the red channel.
  • It won't assemble. add and sub both need a size and two operands, like add.w #$000f,d0. A missing size or operand is the usual cause.

What you've learnt

Arithmetic is ADD and SUB, each working on a size you choose — .b, .w, .l — and each leaving the flags set for a branch to read. A sum that overflows its size sets the carry, which is how the machine chains sizes together for bigger numbers. Add and branch are two halves of one move: compute, then decide on the result.

What's next

Addition treats a value as a number. Sometimes you want to treat it as a row of independent switches instead. Next — Working With BitsAND, OR and EOR set, clear and flip individual bits, the tool for packing flags and reading hardware registers.