The inverse video key on the Atari computer allows messages to be displayed in inverse video for special emphasis or eye-catching effects. Another, sometimes even more dramatic, method of catching the viewer's eye is to have the message flash on and off, or blink. There is no simple command in Atari BASIC to produce this effect, but the key to producing it lies in the register, maintained by the operating system, called CHACT, decimal address 755 ($253). If bit one in this register is set to one, inverse video characters are displayed in inverse video; if it is set to zero, they are displayed normally. However, if bit zero is set to one, these characters are displayed as blank spaces (inverse video or normal blanks depending on bit one).
With this information we can immediately write a program that will produce blinking characters on the screen, as Program 1 does. The trouble with this approach is that our BASIC program is completely preoccupied with timing loops and toggling bit zero of CHACT. If we try to incorporate this routine in a program that does anything else, the timing gets very difficult if not downright impossible. What we really want is a routine that will sit in the background and toggle bit zero of CHACT on a regular basis without interfering with any BASIC program that might be running at the time. Fortunately, the Atari has in it the resources we need to do just this.
The Atari operating system maintains five separate timers that are incremented or decremented during every vertical blank period (the period between successive TV picture frames during which the screen is dark). Actually, most of them are updated only during a "second stage" vertical blank; more about this in a moment. One of these, called CDTMV2 ($21A), is a two-byte down counter that can be set to any value between 1 and 65535. Every sixtieth of a second, during a vertical blank, the operating system reduces this number by one, and when it counts to zero it performs a subroutine jump to the address that it finds in the two-byte vector called CDTMA2 ($228) and returns to the operating system, waiting for the next time the counter counts down to zero.
Program 2 achieves this result by POKEing a machine language program into memory starting at the middle of page 6, location 1664 ($680), and transferring control to it via the USR function. We use the upper half of page 6 because the lower half can be overwritten if an INPUT command recieves 128 or more bytes at one time.
Program 3 is the machine language version of the program that does all the work. After setting up the equates that identify the various registers in lines 20-40 and starting the assembly at location $680 in line 50, we get down to setting ourselves up in business. Lines 80 to 170 pull the three parameters passed by the USR function off the stack and store them in the spaces we reserved for them in lines 260, 270, and 280. We will discuss these parameters further when we reach the points where they are used.
Lines 190 to 220 store the address of our routine that does the actual blinking in the two-byte vector CDRMA2 in the usual low-byte, high-byte order. Lines 230 and 240 take the value of the parameter we have called PERIOD and store it in the actual timer location CDTMV2. Since this is the value that is decremented each sixtieth of a second, it is clear that the parameter PERIOD is just what its name suggests: the period, in sixtieths of a second, of the blink. With this final act the USR function has completed its work, so it returns to BASIC with the RTS at line 250.
Lines 260 to 280 are the storage locations of the three parameters PERIOD, MASK, and FLIP; we already have seen the significance of PERIOD. The actual blink routine is simplicity itself. CHACT is loaded into the A register (line 300), the value is ANDed with the bits in MASK (line 310) to eliminate any bits that we do not want, and the remaining bits are exclusively ORed with the bits in FLIP (line 320) and restored in CHACT (line 330). We can now see the significance of the parameters MASK and FLIP: they define the bits of CHACT that we wish to use and toggle.
The routine ends by resetting the timer for the next period (lines 350, 360) and returning to the operating system vertical blank routines. After this, it is ready to wait for PERIOD more vertical blanks and then do it all over again.
The BASIC program that POKEs the machine language into place does not have to remain in memory once it has done its work. It may be removed with a NEW statement, and a different program that uses the blinking characters may be loaded. In fact, the call to the USR function in line 30 of the BASIC program may be eliminated, and a different program may turn on the blinking. Pressing <SYSTEM RESET> will stop the blinking, but another call to USR(1664, PERIOD, MASK, FLIP) will restore it.
You may experiment with the effect of toggling the various bits of CHACT by using different values of MASK and FLIP. Changing MASK to 23 and leaving FLIP at 1 causes the inverse video to remain on during the blanking. If both MASK and FLIP are changed to 3, inverse video is on while the characters are displayed, but the blanks are normal blanks. Setting both parameters to 2 produces an alternation between regular and inverse video that is quite eye-catching. Finally, setting MASK and FLIP to 4 causes an effect that you will just have to see for yourself; I still haven't figured out what this is used for, but it is spectacular. Of course, PERIOD may be set to any value between 1 and 255 that you may wish to vary the rate with which the characters change.
Since "second stage" vertical blank routines are suspended whenever IO is in progress, you will see that the blinking stops during any disk or cassette activity (or anything that uses the serial IO bus for that matter). You can achieve some unique effects with this short program, and I am sure that many novel programs will use this in ways that I have never thought of.
10 CHACT=755 20 DELAY=200 30 PRINT "HELLO" 40 FOR I=1 TO DELAY:NEXT I 50 POKE CHACT,0 60 FOR I=1 TO DELAY:NEXT I 70 POKE CHACT,1 80 GOTO 40 90 END
10 FOR I=1664 TO 1718 20 READ B:POKE I,B:NEXT I 30 A=USR(1664,30,1,1) 40 END 50 DATA 104,104,104,141,161,6,104,104,141,162,6,104,104,141,163,6,169,164,141,40,2,169,6,141,41 60 DATA 2,173,161,6,141,26,2,96,0,0,0 70 DATA 173,243,2,45,162,6,77,163,6,141,243,2,173,161,6,141,26,2,96
0010 ;CHARACTER BLINK ROUTINE 0020 CHACT = $2F3 0030 CDTMV2 = $21A 0040 CDTMA2 = $228 0050 *=$0680 0060 ;PULL PARAMETERS FROM STACK 0070 ;AND STORE THEM 0080 PLA 0090 PLA 0100 PLA 0110 STA PERIOD 0120 PLA 0130 PLA 0140 STA MASK 0150 PLA 0160 PLA 0170 STA FLIP 0180 ;STORE VECTOR TO BLINK ROUTINE 0190 LDA #BLINK&$00FF 0200 STA CDTMA2 0210 LDA #BLINK/256 0220 STA CDTMA2+1 0230 LDA PERIOD 0240 STA CDTMV2 0250 RTS 0260 PERIOD *=*+1 0270 MASK *=*+1 0280 FLIP *=*+1 0290 ;HERE IS THE BLINK ROUTINE 0300 BLINK LDA CHACT 0310 AND MASK 0320 EOR FLIP 0330 STA CHACT 0340 ;RESET TIMER AND RETURN 0350 LDA PERIOD 0360 STA CDTMV2 0370 RTS
Return to Table of Contents | Previous Section | Next Section