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

The Screen Is a Bitmap

The picture is a map of bits in memory. Each bit is one pixel — 1 lights it, 0 leaves it dark. Point the display at a stretch of Chip RAM, set some bits, and watch them become a block on the glass.

32% of Meet The Machine

So far the screen has been one flat colour, painted by the Copper. Now we draw on it — and to draw, you need to know what the screen is.

On the Amiga, the screen is a bitmap: a stretch of memory where each bit is one pixel. A 1 bit lights its pixel; a 0 leaves it dark. That stretch of memory is called a bitplane, and it lives in Chip RAM — the memory the custom chips can reach. The display hardware reads the bitplane forty times a second and turns its bits into the picture you see. So to draw, you don't call a routine — you set bits in memory, and the hardware shows them.

This is the C64 and NES parted ways from: those machines drew with tiles, fixed 8×8 shapes you placed in a grid. The Amiga has no grid and no fixed shapes — just a field of bits, one per pixel, entirely yours to set. (If you met the Spectrum's screen, this will feel familiar — a bitmap of pixels — but laid out in plain, linear order, with none of the Spectrum's famous twists.)

What you'll see by the end

A solid yellow rectangle in the top-left corner of an otherwise black Amiga screen.
A yellow block — just bits set to 1 in a bitplane, which the display hardware turned into lit pixels.

A yellow block in the top-left. There's no "draw rectangle" instruction behind it — only bits. We cleared the bitplane to all 0 (a black screen), then set a patch of bits to 1, and the hardware drew them.

Setting bits, getting pixels

The harness has grown: it now sets up a one-bitplane display — 320 pixels across, 256 down — by telling the hardware where the bitplane lives and switching the display DMA on. That set-up is ceremony (display window, data-fetch, the bitplane pointer); treat it as the sealed box, the way you did the Copper. Your job is the YOUR CODE block, where the bits become pixels.

;──────────────────────────────────────────────────────────────
; Meet the Machine (Amiga) - Unit 6: The Screen Is a Bitmap
;
; The picture is a map of bits in memory - a bitplane. Each bit is one pixel:
; 1 lights it, 0 leaves it dark. We point the display hardware at a stretch of
; Chip RAM, clear it, and set some bits - and those bits become a block on the
; glass. (The display set-up is harness; the YOUR CODE block lights the pixels.)
;──────────────────────────────────────────────────────────────

CUSTOM      equ $dff000
DMACON      equ $096
INTENA      equ $09a
INTREQ      equ $09c
COP1LC      equ $080
COPJMP1     equ $088
DIWSTRT     equ $08e
DIWSTOP     equ $090
DDFSTRT     equ $092
DDFSTOP     equ $094
BPLCON0     equ $100
BPL1MOD     equ $108
BPL1PTH     equ $0e0
BPL1PTL     equ $0e2
COLOR00     equ $180
COLOR01     equ $182

ROWBYTES    equ 40                  ; 320 pixels / 8 = 40 bytes per row
BPHEIGHT    equ 256
BPSIZE      equ ROWBYTES*BPHEIGHT   ; the whole bitplane: 10240 bytes

            section code,code_c

start:
            lea     CUSTOM,a5
            move.w  #$7fff,INTENA(a5)
            move.w  #$7fff,INTREQ(a5)
            move.w  #$7fff,DMACON(a5)

            ; --- clear the bitplane to all 0 (a blank screen) ---
            lea     bitplane,a0
            move.w  #(BPSIZE/4)-1,d0
.clr:       clr.l   (a0)+
            dbra    d0,.clr

            ; ----------------------------------------------- YOUR CODE START
            ; light a block of pixels: 32 wide (4 bytes), 24 rows tall
            lea     bitplane,a0
            move.w  #24-1,d1
.row:       move.l  #$ffffffff,(a0)     ; 32 bits = 32 lit pixels in this row
            lea     ROWBYTES(a0),a0     ; step to the next row down
            dbra    d1,.row
            ; ------------------------------------------------- YOUR CODE END

            ; --- tell the display where the bitplane lives (patch the Copper) ---
            lea     bitplane,a0
            move.l  a0,d0
            swap    d0
            move.w  d0,bplhi            ; high word of the address
            swap    d0
            move.w  d0,bpllo            ; low word of the address

            lea     copperlist,a0
            move.l  a0,COP1LC(a5)
            move.w  d0,COPJMP1(a5)
            move.w  #$8380,DMACON(a5)   ; DMA on: master + bitplane + Copper

forever:
            bra.s   forever

;──────────────────────────────────────────────────────────────
; Copper list: set up a 320x256, one-bitplane display.
;──────────────────────────────────────────────────────────────
copperlist:
            dc.w    DIWSTRT,$2c81       ; display window start
            dc.w    DIWSTOP,$2cc1       ; display window stop
            dc.w    DDFSTRT,$0038       ; data fetch start
            dc.w    DDFSTOP,$00d0       ; data fetch stop
            dc.w    BPLCON0,$1200       ; one bitplane, colour on
            dc.w    BPL1MOD,$0000       ; no gap between rows
            dc.w    BPL1PTH
bplhi:      dc.w    $0000               ; bitplane address, high word (patched)
            dc.w    BPL1PTL
bpllo:      dc.w    $0000               ; bitplane address, low word (patched)
            dc.w    COLOR00,$0000       ; colour 0 (a 0 bit) = black
            dc.w    COLOR01,$0ff0       ; colour 1 (a 1 bit) = yellow
            dc.w    $ffff,$fffe

            section bss,bss_c           ; Chip RAM, zero-filled
bitplane:   ds.b    BPSIZE

The bitplane is 320 / 8 = 40 bytes per row. We first clear all 10,240 bytes to 0, then light a block:

lea     bitplane,a0
move.w  #24-1,d1
.row:   move.l  #$ffffffff,(a0)     ; 32 bits = 32 lit pixels in this row
        lea     ROWBYTES(a0),a0     ; step down to the next row
        dbra    d1,.row

Each move.l #$ffffffff,(a0) sets 32 bits — 32 pixels — to 1. Stepping a0 on by 40 bytes (ROWBYTES) moves to the row below, and 24 rows make the block. A 1 bit shows colour 1 (yellow, set in the Copper list); a 0 bit shows colour 0 (black). Bit, pixel — that's the whole relationship. (dbra is the 68000's count-and-loop instruction; it's Unit 12's job, used early here.)

Assemble, master, and run

make

A yellow block in the corner — drawn one bit at a time.

Try this: a wider, taller block

Change #24-1 to #48-1 for twice the height, or write two longs per row (move.l #$ffffffff,(a0) then move.l #$ffffffff,4(a0)) for 64 pixels wide. More bits set, more pixels lit. The block is only ever as big as the run of 1s you write.

Try this: a different colour

The block's colour isn't in the bitplane — the bitplane only says which pixels are lit (1) or dark (0). The colour comes from the palette, exactly as before. Find COLOR01,$0ff0 in the Copper list and change $0ff0 to another $0RGB. The same block appears in the new colour, because you changed the palette, not a single pixel.

If it doesn't work

  • The screen is all black. The bits were set but the display can't see them — most often the bitplane pointer wasn't patched into the Copper, or the DMA enable ($8380) is missing. Leave the harness exactly as shown.
  • The block is in the wrong place or smeared. Check ROWBYTES is 40 and the step is lea ROWBYTES(a0),a0 — a wrong stride lands each row in the wrong column.
  • Garbage fills the screen. The bitplane wasn't cleared first, so old memory shows as random pixels. The clear loop runs before you draw.

What you've learnt

The Amiga screen is a bitmap — a bitplane in Chip RAM where each bit is a pixel, 1 lit and 0 dark. You draw by setting bits in memory; the display hardware turns them into the picture. No tiles, no grid — just pixels, all yours.

What's next

We've leaned on the Copper twice now — it set the flat colour, and just now it set up the whole display — without ever explaining it. Next — Colour and the Copper — we open that box: the little co-processor that runs alongside the CPU, changing the hardware in step with the beam, and paints a band of colours down the screen.