Overview
The blitter is the engine inside Agnus that moves rectangular blocks of memory without the CPU — the single most important reason Amiga games move so much on screen. It has four DMA channels (A, B, C, D) and a logic unit that combines them, but its simplest job is a straight block copy: read source through A, write it to destination through D. You point two registers at the memory, tell it the shape, and one write to BLTSIZE sets it running. The processor is free the moment the blit starts.
Code
; =============================================================================
; BLITTER COPY - AMIGA (Agnus blitter)
; Copy a rectangular block of one bitplane: D = A
; =============================================================================
DMACONR equ $002
BLTCON0 equ $040
BLTCON1 equ $042
BLTAFWM equ $044
BLTALWM equ $046
BLTAPT equ $050
BLTDPT equ $054
BLTSIZE equ $058
BLTAMOD equ $064
BLTDMOD equ $066
W_WORDS equ 2 ; block width = 2 words = 32 px
H_LINES equ 16 ; block height = 16 lines
SCR_WORDS equ 20 ; destination bitplane = 320 px = 20 words wide
; a0 = source, a1 = destination (both in chip RAM)
blit_copy:
lea $dff000,a5
bsr wait_blit ; never touch regs mid-blit
move.w #$09f0,BLTCON0(a5) ; USEA+USED, minterm $F0: D = A
move.w #$0000,BLTCON1(a5) ; no shift, no special mode
move.w #$ffff,BLTAFWM(a5) ; use every bit of the first...
move.w #$ffff,BLTALWM(a5) ; ...and the last word
move.w #0,BLTAMOD(a5) ; source is packed tight
move.w #(SCR_WORDS-W_WORDS)*2,BLTDMOD(a5) ; dest skips the rest of the line
move.l a0,BLTAPT(a5) ; source pointer
move.l a1,BLTDPT(a5) ; destination pointer
move.w #H_LINES*64+W_WORDS,BLTSIZE(a5) ; height*64 + width — STARTS IT
rts
; The classic blitter wait: btst the high byte, bit 6 = BBUSY
wait_blit:
btst #6,DMACONR(a5) ; dummy read (early-Agnus guard)
.wb: btst #6,DMACONR(a5)
bne.s .wb
rts
Trade-offs
| Aspect | Cost |
|---|---|
| CPU | Almost none — the blitter runs the copy; you only set it up |
| Memory | Source and destination both in chip RAM |
| Limitation | One bitplane per blit; the blitter and CPU contend for chip-RAM cycles |
When to use: Clearing the screen, copying backgrounds, restoring what a moving object erased — any bulk pixel move.
When to avoid: A handful of bytes; the setup cost isn’t worth it below a few hundred. And a transparent shape needs the cookie-cut version.
The channels and the minterm
The blitter has four sources — A, B, C, D — and BLTCON0’s low byte is a minterm: a truth table saying, for every combination of the A/B/C bits, whether the output bit is 1. All 256 logic functions are available. For a plain copy you enable just A and D (the $0900 bits) and use minterm $F0, which means “output = A” — so $09F0. Enable more channels and change the minterm and the same hardware masks, merges or cookie-cuts; the copy is the degenerate case with one source.
BLTSIZE starts it — then wait
Writing BLTSIZE is the trigger: the blit begins immediately, so it must be the last register you set. The value packs height and width — height * 64 + width_in_words — with width in the low 6 bits (max 64) and height in the top 10. From then the blitter owns those registers until it’s done, so before the next blit (or any register change) you must wait for it. BBUSY in DMACONR says whether it’s running; the btst #6,$dff002 idiom tests it in the register’s high byte (bit 6 there is bit 14 of the word — see the Blitter vault entry). The leading dummy btst guards a timing quirk on early Agnus revisions.
Modulos: minding the screen width
A 32-pixel-wide block is 2 words, but the screen is 20 words wide — so after each copied line the destination pointer must skip the other 18 words to reach the next line down. That skip is the modulo: (screen_words - blit_words) * 2 bytes, added automatically after every line. The source here is a tightly-packed image, so its modulo is 0. Modulos are what let the blitter carve a small rectangle out of, or into, a much wider bitmap.
Related
Patterns: Cookie-Cut Blit, Copper List Basics
Vault: Blitter | Commodore Amiga