If you have written any programs that use Display
List Interrupts, you may have noticed that you often get 'flashes'
or interference with the DLI when using the keyboard or during other
processing. This is a well-known problem and has come to be known as
'the keyboard glitch'. It seems strange that no one seems to have
figured out a way of programming round this. Consider the following
extract from Mapping The Atari.
"One small problem with using DLI's is that
the keyboard 'click' routine interferes with the DLI by throwing off
the timing, since the click is provided by several calls to the
WSYNC register at 54282. Chris Crawford discusses several solutions
in De Re Atari, but the easiest of them is not to allow input from
the keyboard!"
That's not much use if you want a complex game to
use the keyboard as well as a joystick, so let's have a look to see
what else we can do. Firstly consider why the glitch occurs in the
first place. It is because a STA WSYNC occurs in some other process
which interferes with the DLI timing. During a DLI no other
interrupts can occur so the interfering STA WSYNC must occur outside
the DLI. If therefore we could synchronise directly to the display
during a DLI, the glitch problem would be resolved. We can in fact
do this by starting a DLI early, then waiting for the vertical line
counter (VCOUNT) to reach the required scan line value before
performing the normal DLI processing.
As an example, let's consider the case where a DLI
is to alter the foreground and background colour registers in the
middle of a Graphics 0 display. Firstly we must determine the value
of VCOUNT for the scan line at which we wish our DLI routine to
execute. VCOUNT operates in double line resolution and for every
Graphics 0 mode line we increment VCOUNT by 4. After 12 Graphics 0
mode lines, therefore, VCOUNT will have been incremented by 4*12=48.
The value of VCOUNT just before the first scan line is 15 and
therefore the value of VCOUNT for the mid-point of the screen is 15
+ 48 = 63. The following lines are inserted at the beginning of the
DLI after saving any register values onto the stack.
SCANLINESYNC
LDA VCOUNT
CMP #63
BNE SCANLINESYNC
STA WSYNC
Notice that we have tagged a STA WSYNC onto the
end. This is because VCOUNT operates in double line resolution and
the loop therefore terminates one scan line too early (the STA WSYNC
rectifies this).
All that now remains is to set where the DLI
occurs in the display list. Normally for a DLI to occur in the
middle of a Graphics 0 display we would set bit 7 of DL+ 16. The
interrupt must now, however, occur some time before this so we set
bit 7 of DL+ 15. It could in fact be set at any point prior to DL+
16 but DL+ 15 is the most efficient in terms of processor
utilisation.
The DLI timing problem is now solved, however
there is a further problem with respect to DLI's which isn't often
considered and that is all shadow registers are copied to their
hardware counterparts during the non-critical stage of the Operating
System's immediate VBI (where interrupts are enabled). If an IRQ
occurs during this period, the hardware registers will not be
updated. Thus if a colour register is altered in the middle of the
screen and the hardware registers are not updated because an IRQ
occurs, then that register will remain momentarily in the colour it
was set to by the VBI.
We can overcome this easily by setting up our own
immediate VBI to copy the shadow registers into the hardware
registers, which is called by the operating system during its
immediate VBI critical stage, and hence is always executed. This is
how animation is performed whilst games are loading, for example on
Activision's Decathlon or even Bignose Software's Sprong! In the
example program I have given I have only updated the colour
registers in my immediate VBI as these are all I have changed. If
any other shadow registers are altered in a DLI then they too should
be updated as part of the immediate VBI.
You will find a simple BASIC listing and the
source code with this article. I hope that my explanation is not too
confusing and that you can put the principles into practice in your
own programs. Although it may seem complicated, it is basically only
four machine code instructions added to a normal DLI together with a
very straightforward immediate VBI.
|
|
![](../download.gif) |
source
code
1000
*=$0600
1010 ; ***************
1020 ; * DLI routine *
1030 ; ***************
1040 DLI
1050 PHA
1060 ; synchronise to the scan line
1070 ; counter
1080 SCANLINESYNC
1090 LDA VCOUNT
1100 CMP #$3F
1110 BNE SCANLINESYNC
1120 STA WSYNC
1130 ; and perform normal DLI
1140 ; processing
1150 LDA #$00
1160 STA WSYNC
1170 STA COLPF1
1180 LDA #$DA
1190 STA COLPF2
1200 PLA
1210 RTI
1220 ; ***************
1230 ; * VBI routine *
1240 ; ***************
1250 VBI
1260 LDX #$08
1270 LOOP
1280 LDA SHADOWREGISTERS,X
1290 STA HARDWAREREGISTERS,X
1300 DEX
1310 BPL LOOP
1320 JMP $E45F
1330 ; **************
1340 ; * set up VBI *
1350 ; **************
1360 SETUPVBI
1370 PLA
1380 LDY #VBI&$00FF
1390 LDX #VBI/$0100
1400 LDA #$06
1410 JSR $E45C
1420 RTS
1430 ; equates
1440 COLPF1 = $D017
1450 COLPF2 = $D018
1460 WSYNC = $D40A
1470 VCOUNT = $D40B
1480 SHADOWREGISTERS = $02C0
1490 HARDWAREREGISTERS = $D012
top