amiga-bootcamp/08_graphics/blitter_programming.md
Ilia Sharin fca930d0db docs(amiga): make cross-references clickable markdown links
Convert bare .md path references in 29 files to proper [name](relative/path)
markdown links for GitHub navigation.
2026-04-23 12:24:21 -04:00

257 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[← Home](../README.md) · [Graphics](README.md)
# Blitter Programming — Deep Dive
## Overview
The **Blitter** (Block Image Transfer) is a DMA engine that performs raster operations on rectangular blocks of memory. It operates on up to **4 channels** (A, B, C → D) using programmable **minterm logic** and can work independently of the CPU. The Blitter is the workhorse for screen clearing, scrolling, cookie-cut sprites, line drawing, and area fill.
---
## Channel Architecture
```
Channel A ──→ ┐
Channel B ──→ ├──→ Minterm Logic ──→ Channel D (output)
Channel C ──→ ┘
A = mask/pattern (e.g., cookie shape, font glyph)
B = source image data
C = background / destination read-back
D = output destination
```
Each channel reads (or writes, for D) from a different memory pointer with independent modulo.
---
## Minterm Logic
The minterm is an **8-bit truth table** encoding the logical function of A, B, C:
```
Bit 7: ABC = 111 → bit value
Bit 6: ABC = 110 → bit value
Bit 5: ABC = 101 → bit value
Bit 4: ABC = 100 → bit value
Bit 3: ABC = 011 → bit value
Bit 2: ABC = 010 → bit value
Bit 1: ABC = 001 → bit value
Bit 0: ABC = 000 → bit value
```
### Common Minterms
| Minterm | Hex | Operation | Use Case |
|---|---|---|---|
| `D = A` | `$F0` | Copy A to D | Simple block copy |
| `D = B` | `$CC` | Copy B to D | Simple block copy |
| `D = C` | `$AA` | Copy C to D | Read-back |
| `D = A·B + (¬A)·C` | `$CA` | Cookie-cut | Masked sprite blit (B through A mask onto C) |
| `D = 0` | `$00` | Clear | Clear a memory region |
| `D = $FFFF` | `$FF` | Set all | Fill with 1s |
| `D = A XOR C` | `$5A` | XOR | Cursor blink, highlight |
| `D = A OR C` | `$FA` | OR | Overlay |
| `D = ¬A AND C` | `$0A` | Mask out | Erase through mask |
| `D = A·B` | `$C0` | AND (A,B) | Masked pattern |
### Cookie-Cut Explained
```
A = mask (1 = sprite pixel, 0 = transparent)
B = sprite image data
C = background
D = result
Minterm $CA:
Where A=1: D = B (show sprite)
Where A=0: D = C (show background)
```
---
## Register Reference
| Reg | Offset | Description |
|---|---|---|
| `BLTCON0` | `$040` | Control: channels enabled (bits 118), ASH (bits 1512), minterm (bits 70) |
| `BLTCON1` | `$042` | Control: BSH (bits 1512), line mode (bit 0), fill mode (bits 32) |
| `BLTAFWM` | `$044` | First word mask for channel A |
| `BLTALWM` | `$046` | Last word mask for channel A |
| `BLTAPT` | `$050` | Channel A pointer (high+low) |
| `BLTBPT` | `$04C` | Channel B pointer |
| `BLTCPT` | `$048` | Channel C pointer |
| `BLTDPT` | `$054` | Channel D pointer |
| `BLTAMOD` | `$064` | Channel A modulo |
| `BLTBMOD` | `$062` | Channel B modulo |
| `BLTCMOD` | `$060` | Channel C modulo |
| `BLTDMOD` | `$066` | Channel D modulo |
| `BLTSIZE` | `$058` | Blit size + START (write triggers blit) |
### BLTCON0 Encoding
```
Bits 1512: ASH (A shift, 015 pixels)
Bit 11: USEA (enable channel A)
Bit 10: USEB (enable channel B)
Bit 9: USEC (enable channel C)
Bit 8: USED (enable channel D, almost always 1)
Bits 70: Minterm
```
### BLTSIZE Encoding (OCS/ECS)
```
Bits 156: Height in lines (11024, 0 means 1024)
Bits 50: Width in words (164, 0 means 64)
```
**Writing BLTSIZE starts the blit!**
---
## Complete Examples
### Example 1: Clear Screen (320×256, 1 bitplane)
```asm
lea $DFF000,a5
; Wait for blitter idle:
.bwait:
btst #14,$002(a5) ; DMACONR bit 14 = BBUSY
bne.s .bwait
; D channel only, minterm $00 (clear):
move.l #$01000000,$040(a5) ; BLTCON0: USED=1, minterm=$00
clr.w $042(a5) ; BLTCON1: 0
move.l #ScreenMem,$054(a5) ; BLTDPT
clr.w $066(a5) ; BLTDMOD: 0 (contiguous)
move.w #(256<<6)|20,$058(a5) ; BLTSIZE: 256 lines × 20 words (320/16)
; Blit is now running!
```
### Example 2: Block Copy (No Shift)
```asm
; Copy 64×64 pixel block from source to dest (1 bitplane)
; Source and dest are in contiguous bitmap, 320 pixels wide
; Width = 64 pixels = 4 words
; Modulo = (320 - 64) / 16 = 16 words = 32 bytes
lea $DFF000,a5
.bwait:
btst #14,$002(a5)
bne.s .bwait
move.l #$09F00000,$040(a5) ; BLTCON0: USEA+USED, minterm=$F0 (A→D)
clr.w $042(a5) ; BLTCON1
move.w #$FFFF,$044(a5) ; BLTAFWM = all bits
move.w #$FFFF,$046(a5) ; BLTALWM = all bits
move.l #SourceAddr,$050(a5) ; BLTAPT
move.l #DestAddr,$054(a5) ; BLTDPT
move.w #32,$064(a5) ; BLTAMOD = 32 bytes
move.w #32,$066(a5) ; BLTDMOD = 32 bytes
move.w #(64<<6)|4,$058(a5) ; BLTSIZE: 64 lines × 4 words → GO!
```
### Example 3: Cookie-Cut Blit (Masked Sprite)
```asm
; Blit a 16×16 masked sprite onto background
; A = mask, B = sprite data, C = background, D = destination
lea $DFF000,a5
.bwait:
btst #14,$002(a5)
bne.s .bwait
move.l #$0FCA0000,$040(a5) ; BLTCON0: A+B+C+D, minterm=$CA
clr.w $042(a5) ; BLTCON1
move.w #$FFFF,$044(a5) ; BLTAFWM
move.w #$FFFF,$046(a5) ; BLTALWM
move.l #MaskData,$050(a5) ; BLTAPT = mask
move.l #SpriteData,$04C(a5) ; BLTBPT = sprite imagery
move.l #ScreenPos,$048(a5) ; BLTCPT = background (read-back)
move.l #ScreenPos,$054(a5) ; BLTDPT = same as C (overwrite)
clr.w $064(a5) ; BLTAMOD = 0 (mask is 16px = 1 word wide)
clr.w $062(a5) ; BLTBMOD = 0
move.w #38,$060(a5) ; BLTCMOD = (320-16)/8 = 38 bytes
move.w #38,$066(a5) ; BLTDMOD = 38
move.w #(16<<6)|1,$058(a5) ; BLTSIZE: 16 lines × 1 word → GO!
```
### Example 4: Line Drawing
```asm
; Draw a line from (x1,y1) to (x2,y2) using blitter line mode
; This is complex — blitter line mode uses a Bresenham-style algorithm
; implemented in hardware
; BLTCON1 bit 0 = LINE mode
; Channel A = single word (texture pattern)
; Channel C/D = destination bitmap
; See HRM for the full algorithm; here's the concept:
move.l #$0B4A0000,$040(a5) ; BLTCON0: A+C+D, minterm=$4A (XOR), ASH=dx
move.w #$0001,$042(a5) ; BLTCON1: LINE=1, octant bits set per slope
move.w #$8000,$074(a5) ; BLTADAT: single pixel pattern
move.w #$FFFF,$044(a5) ; BLTAFWM
move.l #StartPos,$048(a5) ; BLTCPT: line start position in bitmap
move.l #StartPos,$054(a5) ; BLTDPT: same
move.w #Modulo,$060(a5) ; BLTCMOD
move.w #Modulo,$066(a5) ; BLTDMOD
move.w #(len<<6)|2,$058(a5) ; BLTSIZE: length × 2 → GO!
```
---
## System-Friendly Blitter (via graphics.library)
```c
/* BltBitMap — the safe, OS-friendly way: */
BltBitMap(srcBitmap, srcX, srcY,
dstBitmap, dstX, dstY,
width, height,
0xC0, /* minterm: A AND B */
0xFF, /* all planes */
NULL); /* temp buffer */
/* BltMaskBitMapRastPort — cookie-cut with mask: */
BltMaskBitMapRastPort(srcBM, srcX, srcY,
rp, dstX, dstY,
width, height,
(ABC | ABNC | ANBC), /* minterm for cookie */
maskPlane);
/* BltClear — fast memory clear: */
BltClear(memory, byteCount, 0);
/* OwnBlitter / DisownBlitter — exclusive access: */
OwnBlitter(); /* wait for and lock blitter */
/* ... direct register programming ... */
DisownBlitter(); /* release */
```
---
## Performance Notes
| Operation | Speed |
|---|---|
| Word copy | 4 DMA cycles per word (1 µs at 3.58 MHz) |
| Full 320×256 clear | ~1280 µs (~1.3 ms) |
| Cookie-cut blit | 4 channels = 4 cycles/word (same as copy) |
| CPU vs blitter | Blitter wins for moves > ~40 words |
| Nasty mode | `BLTPRI` in DMACON: blitter gets priority, CPU stalls |
---
## References
- HRM: *Blitter* chapter — complete register descriptions
- [blitter.md](../01_hardware/ocs_a500/blitter.md) — hardware reference
- [blitter.md](blitter.md) — graphics.library BltBitMap API