"""Build an Amiga Copper list that displays a static 320x200 low-res screen. The Copper runs every frame and re-loads the bitplane pointers + registers, so the picture stays stable. Each instruction is a MOVE (register offset, value); the list ends with WAIT $FFFF,$FFFE. """ from __future__ import annotations import struct DIWSTRT, DIWSTOP, DDFSTRT, DDFSTOP = 0x08E, 0x090, 0x092, 0x094 BPLCON0, BPLCON1, BPLCON2 = 0x100, 0x102, 0x104 BPL1MOD, BPL2MOD = 0x108, 0x10A BPLPT = 0x0E0 # BPL1PTH; +4 per plane COLOR0 = 0x180 def list_len(nplanes, ncolors) -> int: pairs = 9 + nplanes * 2 + ncolors # DIW*2, DDF*2, BPLCON0/1/2, BPLMOD*2 = 9 return pairs * 4 + 4 # + end WAIT def build(nplanes, ham, plane_addrs, colors) -> bytes: bplcon0 = (nplanes << 12) | (0x0800 if ham else 0) | 0x0200 moves = [ (DIWSTRT, 0x2C81), (DIWSTOP, 0xF4C1), (DDFSTRT, 0x0038), (DDFSTOP, 0x00D0), (BPLCON0, bplcon0), (BPLCON1, 0x0000), (BPLCON2, 0x0024), (BPL1MOD, 0x0000), (BPL2MOD, 0x0000), ] for p, addr in enumerate(plane_addrs): moves.append((BPLPT + p * 4, (addr >> 16) & 0xFFFF)) moves.append((BPLPT + p * 4 + 2, addr & 0xFFFF)) for i, c in enumerate(colors): moves.append((COLOR0 + i * 2, c & 0x0FFF)) out = bytearray() for reg, val in moves: out += struct.pack(">HH", reg & 0x1FE, val & 0xFFFF) out += struct.pack(">HH", 0xFFFF, 0xFFFE) # end of copper list return bytes(out)