Smoother DLI's

Paul Lay shows how to get rid of the keyboard glitch

 

Issue 23

Sep/Oct 86

Next Article >>

<< Prev Article

 

 

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.

AtariLister - requires Java

 

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