Copper: Exact WAIT Timing

The Copper allows quite fine-grained raster timing for time-critical hardware register changes. This was a great improvement from the so-called "splits" on 8-bit computers and Atari ST where you waited with an interrupt and/or a CPU loop for a certain position.
On Amiga, it's done automatically in the background for you, without wasting cycles waiting.
Such a "split" is most often used to change colors, bitplane pointers or similar things at a certain position. It's easy to do with the Copper:
dc.w $4005,$fffe    ;waits for vertical position $40, first raster stop position outside the left 
                    ;edge of the screen
dc.w $180,$f0f      ;sets the background-color to bright magenta

Each Copper command takes 8 cycles = 8 pixels = 4 increments of the raster position to execute on the OCS chipset.
$05 here is the stop position after horizontal blanking on OCS that results in the MOVE, executed 8 pixels later, modifying the background color visibly on the start of that line. Any lower position*, or a position such as $3fff or $3fdf, results in the background color being changed on the previous line.

Multiple MOVEs

If you need to load more than one register, you must subtract 4 from this virtual position for each MOVE.
For example, if you wanted to load a 15 color palette on each raster line (keeping the background color constant), you would calculate backwards from the horizontal point when the data for the next line has to be ready.

When does the data have to be ready?

For palette colors as in the above example, it's enough that it's ready in time for the left edge of the screen, or $38 for the above standard screen. When this position is reached, DMA will load up to 6 bitplanes in 16 cycles.
The corresponding raster wait position for a MOVE to match up with the left edge is then position $3d.
For modulos, bitplane pointers, and other fixed DMA fetch positions, you would have to set them early to make sure they get picked up at their assigned time slots. Refer to the display timing diagram in Hardware Reference Manual for the exact positions.
In our palette example, for a standard 320px wide screen, you would start from the left edge wait position that included 1 MOVE (1 color), $3d. You have 14 more colors to move, so you would subtract 14*4 from $3d, giving you position $05.
NOTE: It's pure coincidence that this is the same as the first stop position on a new line.
If you wished to set the background color as well, you'd encounter the horizontal blanking. Any position from $e5..$03 would be the same as position $e5. Any position in this span is treated as if it were $e5. You could say "the position 4px before $05" is $e5.
We need 8px to set the extra color though, so our position must be $e3. Here is our 16 color example:
dc.w $3fe3,$fffe
dc.w $180,$000
dc.w $182,$111
dc.w $184,$222
dc.w $186,$333
dc.w $188,$444
dc.w $18a,$555
dc.w $18c,$666
dc.w $18e,$777
dc.w $190,$888
dc.w $192,$999
dc.w $194,$aaa
dc.w $196,$bbb
dc.w $198,$ccc
dc.w $19a,$ddd
dc.w $19c,$eee
dc.w $19e,$fff    ;after this executes, raster should be at position $4038.

MOVE instruction timing

During horizontal blanking and below 5 bitplanes, MOVEs take 8 cycles (pixels) to execute. Between DDFSTRT and DDFSTOP when bitplane DMA has to be read and output to the screen, for 5 bitplanes, MOVEs will align to 16px boundaries with alternate 12 cycle or 8 cycle MOVEs, and for 6 bitplanes, each MOVE takes 16 cycles.


As established, positions $e7...$03 are not usable. If you're writing a simple copperlist with no need for tight timing, positions $df and $07 are conventionally used for the positions on either side of the horizontal blanking, and for compatibility across chipsets use increments of 4 from these, resulting in positions $db, $0b, and so on.