# Amiga Agnus Copper Co-Processor Agnus's robot friend. ## Links * http://vikke.net/index.php?id=copperbars-1 * Copper timing: http://coppershade.org/articles/AMIGA/Agnus/Copper:_Exact_WAIT_Timing/ ## WAIT ### Horizontal Position * Horizontal WAITs are based on 4 pixel (in low res) blocks * The electron gun X position is represented with a value from $00 to $E2 * Multiply this by 2 to get the X position on the screen * The Copper doesn't use the LSB in comparisons, so in reality you can only WAIT on horizontal positions that are even numbers * $01 is electron gun X position 2, but the Copper can't wait for this position. You can wait for $02, though. * $10 is electron gun X position 64. You can wait for this address. * The way that HBLANK is described in the original docs is not friendly to my brain: * Horizontal Blank goes from $35 on this line -> $0F on the next line * The unused portion where only `COLOR00` is displayed is $47 on this line -> $04 on the next line * http://www.amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node004C.html ## Examples ### Reserving RAM for a new Copperlist ```asm SECTION ChipRAM,Data_c CNOP 0,4 Copperlist DC.L $FFFFFFFE ; impossible condition = end of copperlist DCB.W 1024,0 ; 2048 more bytes for copper data ``` ### Macro to add bitplane to copperlist ```asm AddBitplaneToCopper MACRO MOVE.L \1,D0 MOVE.W #BPL\2PTL,(A5)+ MOVE.W D0,(A5)+ SWAP D0 MOVE.W #BPL\2PTH,(A5)+ MOVE.W D0,(A5)+ ENDM AddBitplaneToCopper #Bitplanes,1 AddBitplaneToCopper #Bitplanes+(320/8)*256,2 AddBitplaneToCopper #Bitplanes+(320/8)*256*2,3 AddBitplaneToCopper #Bitplanes+(320/8)*256*3,4 AddBitplaneToCopper #Bitplanes+(320/8)*256*4,5 ``` ### Building a copperlist dynamically in C ```c void *copperlist = AllocMem(1000, MEMF_CHIP|MEMF_CLEAR); UWORD *copperlist_ptr = (UWORD *)copperlist; // add a bitplane *(copperlist_ptr)++ = BPL1PTH; *(copperlist_ptr)++ = ((ULONG)bitplane >> 16) & 0xffff; *(copperlist_ptr)++ = BPL1PTL; *(copperlist_ptr)++ = (ULONG)bitplane & 0xffff; // add a color *(copperlist_ptr)++ = COLOR00; *(copperlist_ptr)++ = 0x000; // add a WAIT *(copperlist_ptr)++ = ((currentY & 0xff) << 8) | 0x26 | 0x1; *(copperlist_ptr)++ = 0xfffe; // do a PAL workaround if (currentY == 255) { *(copperlist_ptr++) = 0xffdf; *(copperlist_ptr++) = 0xfffe; } // add an END *(copperlist_ptr)++ = 0xffff; *(copperlist_ptr)++ = 0xfffe; ``` ### PAL copperlist workaround ```asm MOVEQ #0,D0 ; current raster line LEA Copperlist,A5 LoopToRenderLines: MOVE.L D0,D1 AND.L #$FF,D1 ROL.W #8,D1 ADDQ #1,D1 MOVE.W D1,(A5)+ MOVE.W $FF00,(A5)+ ; obey only vertical line ADDQ #1,D0 CMP #256,D0 ; this has to happen right before you write copperlist entries to line 256 or above BNE _NoPALFix ; these come straight from http://vikke.net/index.php?id=copperbars-1 MOVE.W #$FFDF, (A5)+ ; %1111111111011111, wait for Y=255, X=111*4=444 MOVE.W #$FFFE, (A5)+ ; %1111111111111110 = blitter-finished-disable =1, all compare bits enabled NoPALFix: CMP #312,D0 BNE LoopToRenderLines ``` ## Code Issues * Writing a copperlist and the display becomes corrupted the longer the list gets? * Ensure you have enough space for the copperlist. You're likely writing into whatever memory was reserved for a bitplane.