Fast Repeat Key

16K Cassette or Disk
by Sammie J. McCaa, Jr.


While working on a rather large machine-language program, I became impatient with the long delay in the Atari keyboard's key repeat function. I found myself pressing the CTRL/arrow keys to move ahead, instead of just holding down the space bar and waiting for the repeat. So I put away what I was doing and pulled out my operating system manuals to figure out a way to get around the problem.

I discovered that ths OS uses a variable called SRTIMR at location 555 decimal ($22B hex) to determine how long to wait before starting the repeat function. It works liks this: Every time you press a key, the keyboard interrupt routine stores a value of 30 (for a 30-jiffy or 1/2 second delay) into SRTIMR. This location is then decremented every 1/60th of a second. If the key is still being pressed when SRTIMR reaches zero, the OS will repeat the key until you let it go. All you have to do to change the repeat delay is to control the value that is stored into SRTIMR when a key is first pressed.

I began by writing a program that copied the OS keyboard interrupt routine from ROM into RAM, changed the value stored into SRTIMR and, of course, altered the interrupt vector to point to the new routine. It worked, but I wasn't too sure if it would work on other versions of the OS (I have an old Atari with the original' 'A" ROMS). I went down to a local department store to try my routine on a 1200XL. The program didn't stand a chance. Talk about incompatibility! Not only is the 1200 interrupt handler in a different ROM location (this wasn't really a problem, since I could check the "reserved" interrupt vector to find out where it was), but it was three, Yes, three times as long as the handler in the 400/800 OS!

After a few more attempts, including one that tried to determine which OS you had by checking the size of the interrupt handler, I finally got it right. The current version continuously checks SRTIMR with a small custom vertical blank interrupt routine. Whenever SRTIMR gets bigger than I want it to be, I just change it. Simple, right?

I got tired of re-initializing the routine every time I hit SYSTEM RESET, so out came the manuals again. I discovered how to trick Atari into believing there has been a cassette boot, thereby enabling me to steal the system long enough to keep my fast repeat-key routine active. The routine is small enough (only 37 bytes) to safely fit at the bottom of the 6502 hardware stack on page 1. This keeps page 6 free for other machine-language routines.

I've included two versions of the program. Listing 1 is the BASIC loader, while Listing 2 is the assembly-language source code. Both versions are set up for use with a disk drive. To use the routine with a cassette, change the third byte in Line 120 of the BASIC listing from 3 to 2, or Line 140 of the assembly listing from LDA #3 to LDA #2.

To execute the BASIC loader, just type it in, CHECK it with D:CHECK1 or C:CHECK and RUN it. The assembly version requires a G1OO from the Editor/Assembler cartridge's DEBUG mode. I selected a new key delay value of 10 (1/6 of a second). By changing the PAUSE variable in the assembly version (Line 270) and reassembling, you can experiment with different time delays.

Listing 1

FASTREP.LST is available in ATASCII format.

10 REM * REPEAT KEY BASIC LOADER
20 REM * BY SAMMIE J. MCCAA, JR.
30 REM 
40 FOR RAM=256 TO 292
50 READ BYTE:POKE RAM,BYTE:NEXT RAM
60 POKE 255,104:REM * PLA FOR BASIC
70 X=USR(255):REM * INIT ROUTINE
80 ? "FAST REPEAT INSTALLED"
90 END 
100 DATA 160,22,162,1,169,6,32,92
110 DATA 228,169,0,133,2,169,1,133
120 DATA 3,169,3,133,9,96,173,43
130 DATA 2,201,11,144,2,169,10,141
140 DATA 43,2,76,95,228
Checksum Data
10 DATA 228,60,255,869,896,390,347,31,
259,683,917,523,923,626,7007
Listing 2

FASTREP.ASM is available in ATASCII format.

0100 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
0110 ;                         ;
0120 ;       REPEAT KEY        ;
0130 ;                         ;
0140 ; BY SAMMIE J. MCCAA, JR. ;
0150 ;                         ;
0160 ;  ANALOG COMPUTING #16   ;
0170 ;                         ;
0180 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
0190 ;
0200 ; ** EQUATES **
0210 ;
0220 BOOT =  $09
0230 CASINI = $02
0240 SRTIMR = $022B
0250 SETVBV = $E45C
0260 SYSVBV = $E45F
0270 PAUSE = 10
0280 ORG =   $0100
0290 ;
0300     *=  ORG
0310 ;
0320 INIT
0330     LDY #WAIT&255 ; CHANGE IMMEDIATE
0340     LDX #WAIT/256 ; VERTICAL BLANK
0350     LDA #6      ; VECTOR
0360     JSR SETVBV
0370     LDA #ORG&255 ; TRICK COMPUTER
0380     STA CASINI  ; INTO THINKING
0390     LDA #ORG/256 ; THERE HAS BEEN
0400     STA CASINI+1 ; A CASSETTE BOOT
0410     LDA #3
0420     STA BOOT
0430     RTS 
0440 ;
0450 WAIT
0460     LDA SRTIMR  ; GET TIMER VALUE
0470     CMP #PAUSE+1 ; IS IT > PAUSE?
0480     BCC STORE
0490     LDA #PAUSE  ; MAKE IT = PAUSE
0500 STORE
0510     STA SRTIMR  ; SAVE NEW RESULT
0520     JMP SYSVBV  ; AND RETURN
0530 ;
0540     .END 

Previous | Contents | Next

Original text copyright 1984 by ANALOG Computing. Reprinted with permission by the Digital ANALOG Archive.