4.4 KiB
Copper Coprocessor
Overview
The Copper (co-processor) is built into Agnus. It executes a simple instruction list (the copperlist) in sync with the video beam, allowing precise per-scanline changes to any writable custom register — without CPU intervention.
The Copper can only write to custom registers (it cannot access Chip RAM directly), but it can change bitplane pointers, colors, BPLCON0, sprite pointers, and any other $DFF0xx register on a cycle-accurate basis.
Copper Instruction Set
The Copper has exactly three instructions, each exactly 32 bits (two 16-bit words):
1. MOVE — Write a Register
Word 1: [RRR RRRR RRR0] Destination register address (must be even, bit 0 = 0)
Word 2: [DDDD DDDD DDDD] Data to write
Example — set COLOR00 to red at scanline 100:
DC.W $0180, $0F00 ; MOVE COLOR00, $0F00 (red)
2. WAIT — Wait for Beam Position
Word 1: [VVVV VVVH HHHH HH1] Vertical pos[8:1], Horizontal pos[8:3], bit0=1
Word 2: [EVVV VVVH HHHH HHx0] Enable, VP mask, HP mask, bit0=0
The Copper stalls until the beam reaches (V,H) AND (Vmask,Hmask).
Standard full-precision WAIT:
DC.W $6401, $FF00 ; WAIT for line $64 (100), any H — full V mask
WAIT for end of frame (copper stop):
DC.W $FFFF, $FFFE ; WAIT $FF,$FF — impossible position → stop copper
3. SKIP — Conditional Skip
Word 1: [VVVV VVVH HHHH HH1] Same format as WAIT
Word 2: [EVVV VVVH HHHH HHx1] Same as WAIT but bit 0 = 1 (SKIP flag)
If beam has passed the position, skip the next instruction. Used for double-buffered copper switching.
Copperlist Format
A copperlist is an array of 32-bit instruction pairs in Chip RAM, terminated by:
DC.W $FFFF, $FFFE
Example — color cycle on vertical blank:
Copperlist:
DC.W $0180, $0000 ; COLOR00 = black
DC.W $4401, $FF00 ; WAIT line 68 (display area start)
DC.W $0180, $0F00 ; COLOR00 = red
DC.W $6401, $FF00 ; WAIT line 100
DC.W $0180, $00F0 ; COLOR00 = green
DC.W $FFFF, $FFFE ; END
Copper Pointers and Control
| Register | Offset | Description |
|---|---|---|
| COP1LCH | $080 | Copper list 1 pointer high word |
| COP1LCL | $082 | Copper list 1 pointer low word |
| COP2LCH | $084 | Copper list 2 pointer high word |
| COP2LCL | $086 | Copper list 2 pointer low word |
| COPJMP1 | $088 | Strobe: restart copper from list 1 (any write) |
| COPJMP2 | $08A | Strobe: restart copper from list 2 |
| COPCON | $02E | Copper danger bit (CDANG) |
COPCON bit 1 (CDANG): When set, Copper is allowed to write to registers $40–$7F (blitter registers). Should be 0 in normal use to prevent runaway copperlists from corrupting the blitter.
Activating the Copper
; Load copperlist address into copper list 1
move.l #Copperlist, d0
move.w d0, COP1LCL+custom ; low word
swap d0
move.w d0, COP1LCH+custom ; high word
; Restart copper (triggers on next VBlank)
move.w d0, COPJMP1+custom ; value irrelevant, strobe only
; Enable copper DMA
move.w #$8280, DMACON+custom ; SET + MASTER + COPEN
Dual-Playfield and HAM via Copper
Common copper techniques:
Split-screen different palettes: Change COLOR00–COLOR31 registers mid-screen via a WAIT at the split scanline.
Mid-screen bitplane pointer change: Redirect BPL1PTH/BPL1PTL to a different bitmap half-way through the display — used for large vertical scrolling without double-buffering the full screen.
BPLCON0 mid-screen: Switch between HIRES and LORES, or between 6-plane and 4-plane modes, on different lines.
Raster bars: Write a different color to COLOR00 on every scanline using sequential WAIT+MOVE pairs.
Graphics Library vs Direct Copper
AmigaOS's graphics.library manages the Copper list internally:
MrgCop()merges system and user copper listsLoadView()installs a View structure's copper listWaitTOF()waits for the top-of-frame (VBlank) before the copper restarts
Direct copper access should be done via GetColorMap(), SetRGB4() and official graphics calls, or through a custom View/ViewPort/ColorMap structure passed to LoadView().
References
- ADCD 2.1 Hardware Manual — Copper chapter
- NDK39:
hardware/custom.h,graphics/copper.h - Amiga Hardware Reference Manual 3rd ed., Chapter 6