This example will instruct the Copper to issue an interrupt every 16 scan lines. It might seem that the way to do this would be to use a mask of $0F and then compare the result with $0F. This should compare "true" for $1F, $2F, $3F, etc. Since the test is for greater than or equal to, this would seem to allow checking for every 16th scan line. However, the highest order bit cannot be masked, so it will always appear in the comparisons. When the Copper is waiting for $0F and the vertical position is past 128 (hex $80), this test will always be true. In this case, the minimum value in the comparison will be $80, which is always greater than $0F, and the interrupt will happen on every scan line. Remember, the Copper only checks for greater than or equal to. In the following example, the Copper lists have been made to loop. The COP1LC and COP2LC values are either set via the CPU or in the Copper list before this section of Copper code. Also, it is assumed that you have correctly installed an interrupt server for the Copper interrupt that will be generated every 16 lines. Note that these are non-interlaced scan lines. Here's how it works. Both loops are, for the most part, exactly the same. In each, the Copper waits until the vertical position register has $xF (where x is any hex digit) in it, at which point we issue a Copper interrupt to the Amiga hardware. To make sure that the Copper does not loop back before the vertical position has changed and cause another interrupt on the same scan line, wait for the horizontal position to be $E2 after each interrupt. Position $E2 is horizontal position 113 for the Copper and the last real horizontal position available. This will force the Copper to the next line before the next WAIT . The loop is executed by writing to the COPJMP1 register. This causes the Copper to jump to the address that was initialized in COP1LC . The masking problem described above makes this code fail after vertical position 127. A separate loop must be executed when vertical position is greater than or equal 127. When the vertical position becomes greater than or equal to 127, the the first loop instruction is skipped, dropping the Copper into the second loop. The second loop is much the same as the first, except that it waits for $xF with the high bit set (binary 1xxx1111). This is true for both the vertical and the horizontal WAIT instructions. To cause the second loop, write to the COPJMP2 register. The list is put into an infinite wait when VP >= 255 so that it will end before the vertical blank. At the end of the vertical blanking period COP1LC is written to by the operating system, causing the first loop to start up again. COP1LC is written at the end of vertical blanking . ------------------------------------------------------ The COP1LC register is written at the end of the vertical blanking period by a graphics interrupt handler which is in the vertical blank interrupt server chain. As long as this server is intact, COP1LC will be correctly strobed at the end of each vertical blank. ; ; This is the data for the Copper list. ; ; It is assumed that COPPERL1 is loaded into COP1LC and ; that COPPERL2 is loaded into COP2LC by some other code. ; COPPERL1: DC.W $0F01,$8F00 ; Wait for VP=0xxx1111 DC.W INTREQ,$8010 ; Set the copper interrupt bit... DC.W $00E3,$80FE ; Wait for Horizontal $E2 ; This is so the line gets finished before ; we check if we are there (The wait above) DC.W $7F01,$7F01 ; Skip if VP>=127 DC.W COPJMP1,$0 ; Force a jump to COP1LC COPPERL2: DC.W $8F01,$8F00 ; Wait for VP=1xxx1111 DC.W INTREQ,$8010 ; Set the copper interrupt bit... DC.W $80E3,$80FE ; Wait for Horizontal $E2 ; This is so the line gets finished before ; we check if we are there (The wait above) DC.W $FF01,$FE01 ; Skip if VP>=255 DC.W COPJMP2,$0 ; Force a jump to COP2LC ; Whatever cleanup copper code that might be needed here... ; Since there are 262 lines in NTSC, and we stopped at 255, there is a ; bit of time available DC.W $FFFF,$FFFE ; End of Copper list ;