[net.micro.atari] Software keyclick suppressor for 800

hitchens@ut-sally.UUCP (Ron Hitchens) (08/28/84)

[I'm so sorry, he's from Barcelona.]

   Here is a nifty little bit of assembly code I wrote to shut off the
keyclick on my Atari 800 so my roommate could sleep whilst I stayed up
all night hacking.  It hasn't been thoroughly tested but works fine
with my Chameleon terminal emulator and with the basic cart.  The only
problem I've found is that it won't coexist with DUP (but what does?),
apparently DUP overwrites part of it and it crashes the system on the
first CR.  If you are using Atari's DOS set it up as an AUTORUN.SYS
and boot with the basic cart in.  If you need to go to DUP, hit the
SYSTEM RESET first, that will reset every thing back to normal (and 
bring back the keyclick).  If using OS/A+, with the Basic cart
you will have to go to dos (DOS), load this, then go back to Basic (CAR),
without the cart just load it from the D1: prompt.
   I have a standard Atari 800 (pre-XL vintage) with one Atari 810 drive,
this is the only configuration this code has been tested on, so if you
have something else you'll just have to give it a shot and see what happens.
This code should work on either Rev. A or B of the OS roms, I copied
the code from the Rev. A OS list and it works on my Rev. B.  I'm not 
familiar with the XL roms but I believe they have an option for turning
keyclick on/off, so this isn't for them anyway.  It should also work on
the early 400s but I can't remember if they had a console speaker or not.
   I'm turning this loose to the world at large with the condition that
my name remain on the source code.  Please send any praise/suggestions/
bug reports to me (hitchens@ut-sally.{UUCP,ARPA,etc})  This code is 
written for OSS's MAC/65, but can easily be converted to just about
any Atari assembler.

Bonadah,
-------------------------------------------------------------------------------
 Ron Hitchens           hitchens@ut-sally
 [Never try to teach a pig to sing, it                 [.UTEXAS, domain of the
 wastes your time and it annoys the pig.]               Mayan SUN worshippers]

P.S.  This is not an archive, just chop out everything up to here.
---------------------------- cut here ------------------
0100 ;
0110 ;Keyboard click suppressor for Atari 800, OS roms A or B (not XL)
0120     .OPT NO LIST
0130 ;
0140 ;(c) Copyright August 1984 Ron Hitchens@ut-sally
0145 ;     (512)-928-4654  Reachable at University of Texas Computer Science
0147 ;                     Dept.  PAI 1.50  Austin, Tx  78714
0150 ;
0160 ;Relocates to MEMLO, doesn't take any page 6 or any other fixed space.
0170 ;This code will turn off the keyclick produced by accesses to the
0180 ;E: or K: devices.  But not the snarfing bell thru the console speaker.
0190 ;It does this by changing the pointers in the handler tables for the
0200 ;K: and E: devices to point to new code which is a copy of the ROM
0210 ;code without the calls to the keyclick routine.  This code follows
0220 ;the protocol for installing device handlers, except that it doesn't
0230 ;hook itself into the reset chain.  This means it will not survive
0240 ;a SYSTEM RESET, but it may be loaded again with no problem.
0250 ;Loading it again (once it is already installed) will not hurt
0260 ;anything, it just loads another copy above the current one,
0270 ;wasting a little space.
0280 ;The action of this handler should be transparent to all applications
0290 ;providing they do legal accesses to the keyboard.
0300 ;Written for MAC/65, should be compatible with assm/edit cart
0310 ;excepting maybe .OPT and .IF statements.  .IF can be removed.
0320 ;
0330 ;Copyright August 1984 Ron Hitchens
0340 ;I retain the copyright to this code, permission is given to
0350 ;reproduce and distribute it freely provided this notice is included.
0360 ;
0370 ;
0380 START = $3400   ;load point
0390 MEMLO = $02E7   ;
0400 HATABS = $031A
0410 PTR1 =  $64
0420 PTR2 =  $68
0430 CH  =   $02FC
0440 HOLDCH = $7C
0450 INVFLG = $02B6
0460 ATACHR = $02FB
0470 ICAX1Z = $2A
0480 BRKKEY = $11
0490 BRKABT = $80
0500 SHFLOK = $02BE
0510 EOFERR = $88
0520 DSTAT = $4C
0530 CR  =   $9B
0540 ATASCI = $FEFE
0550 ;
0560     *=  START   ;begin code
0570     RTS 
0580 ;
0590 ;-------------------
0600 ; K: HANDLER
0610 ;
0620 READK2 LDA #$FF
0630     STA CH
0640 READK
0650 KVEC =  READK-START-1 ;offset from MEMLO of new table entry
0660 ;modified code executed by the handler
0670 ;see OS listing (keyboard handler)
0680 ;
0690     LDA ICAX1Z
0700     LSR A
0710     BCS GETOUT
0720     LDA #BRKABT
0730     LDX BRKKEY
0740     BEQ K7
0750     LDA CH
0760     CMP #$FF
0770     BEQ READK
0780     STA HOLDCH
0790     LDX #$FF
0800     STX CH
0810 ;   this is where CLICK call was
0820 ;   have do copy following code to cover all the branches back here
0830 KGETC3 TAX 
0840     CPX #$C0
0850     BCC ASCC01
0860     LDX #3
0870 ASCC01 LDA ATASCI,X
0880     STA ATACHR
0890     CMP #$80
0900     BEQ READK2
0910     CMP #$81
0920     BNE KGETC1
0930     LDA INVFLG
0940     EOR #$80
0950     STA INVFLG
0960     BNE READK2
0970     BEQ READK2  ;uncond rel jump
0980 KGETC1 CMP #$82
0990     BNE K1
1000     LDA #0
1010     STA SHFLOK
1020     BEQ READK2
1030 K1  CMP #$83
1040     BNE K2
1050     LDA #$40
1060     STA SHFLOK
1070     BNE READK2
1080 K2  CMP #$84
1090     BNE K3
1100     LDA #$80
1110     STA SHFLOK
1120     BNE READK2
1130 K3  CMP #$85
1140     BNE K6
1150     LDA #EOFERR
1160 K7  STA DSTAT
1170     STA BRKKEY
1180 GETOUT LDA #CR
1190     BNE K8
1200 K6  LDA HOLDCH
1210     CMP #$40
1220     BCS K5
1230     LDA ATACHR
1240     CMP #$61
1250     BCC K5
1260     CMP #$7B
1270     BCS K5
1280     LDA SHFLOK
1290     BEQ K5
1300     ORA HOLDCH
1310     BNE KGETC3
1320     BEQ KGETC3  ;unconditional
1330 K5  JSR $FC8D
1340     BEQ K4
1350     LDA ATACHR
1360     EOR INVFLG
1370 K8  STA ATACHR
1380 K4  JMP $F634
1390 ;
1400 MYKTAB *= *+16  ;reserve handler table space
1410 KADDR = MYKTAB-START ;rel offset of new table
1420 ;-------------------
1430 ;
1440 ; E: HANDLER
1450 ;
1460 READE
1470 EVEC =  READE-START-1 ; offset for E: getch entry
1480     JSR $FCB3
1490     JSR $FA88
1500     LDA $6B
1510     BNE EGETC3
1520     LDA $54
1530     STA $6C
1540     LDA $55
1550     STA $6D
1560 EPATCH = *+1
1570 EGETC1 JSR READK-START ;will be patched
1580     STY DSTAT
1590     LDA ATACHR
1600     CMP #CR
1610     BEQ EGETC2
1620     JSR $F6AD
1630     JSR $FCB3
1640     LDA $63
1650     CMP #113
1660     BNE EGETC6
1670     JSR $F90A
1680 EGETC6 BNE EGETC1
1690     BEQ EGETC1  ;uncond
1700 EGETC2 JMP $F66E
1710     JMP $F653
1720 EGETC3 JMP $F67C ;CAVEAT
1730 ;
1740 ;all references to $Fxxx addresses are unauthorized entries.
1750 ;
1760 MYETAB *= *+16
1770 EADDR = MYETAB-START
1780 ;-----------------------
1790 ;
1800 FENCE
1810 SIZE =  FENCE-START
1820     .IF SIZE>255
1830       .ERROR "RESIDENT > 255"
1840       .ENDIF 
1850 ; end of resident code
1860 ;
1870 ; Init code, runs once
1880 ;
1890 INIT
1900 ;lookup and move handler tables
1910     LDA #MYKTAB&$FF
1920     STA PTR2
1930     LDA #MYKTAB/256
1940     STA PTR2+1
1950     LDA #'K
1960     JSR MOVTAB
1970     STY TEMPK
1980     LDA #MYETAB&$FF
1990     STA PTR2
2000     LDA #MYETAB/256
2010     STA PTR2+1
2020     LDA #'E
2030     JSR MOVTAB
2040     STY TEMPE
2050 ;
2060 ;put new vectors in tables
2070     LDX #KVEC&$FF
2080     LDY #KVEC/256
2090     LDA #MYKTAB&$FF
2100     STA PTR2
2110     LDA #MYKTAB/256
2120     STA PTR2+1
2130     JSR INSVEC
2140     LDX #EVEC&$FF
2150     LDY #EVEC/256
2160     LDA #MYETAB&$FF
2170     STA PTR2
2180     LDA #MYETAB/256
2190     STA PTR2+1
2200     JSR INSVEC
2210 ;
2220 ;patch JSR in E: handler code
2230     CLC 
2240     LDA EPATCH
2250     ADC MEMLO
2260     STA EPATCH
2270     LDA EPATCH+1
2280     ADC MEMLO+1
2290     STA EPATCH+1
2300 ;
2310 ;move the resident code
2320     LDA MEMLO
2330     STA PTR1    ;load a pointer (dest)
2340     LDA MEMLO+1
2350     STA PTR1+1
2360     LDA #START&$FF ;source pointer
2370     STA PTR2
2380     LDA #START/256
2390     STA PTR2+1
2400     LDY #SIZE
2410 L2  LDA (PTR2),Y ;OK if SIZE < 256
2420     STA (PTR1),Y
2430     DEY 
2440     BNE L2
2450     LDA (PTR2),Y ;get 0th byte
2460     STA (PTR1),Y
2470 ;
2480 ;patch the pointers in HATABS to new tables
2490     LDX #KADDR&$FF
2500     LDY #KADDR/256
2510     LDA TEMPK
2520     STA TEMP
2530     JSR PCHVEC
2540     LDX #EADDR&$FF
2550     LDY #EADDR/256
2560     LDA TEMPE
2570     STA TEMP
2580     JSR PCHVEC
2590     JMP END     ;skip over subroutines and finish
2600 ;
2610 MOVTAB LDY #$21 ;run backwards
2620 SRCH CMP HATABS,Y
2630     BEQ GOTIT
2640     DEY 
2650     DEY 
2660     DEY 
2670     BPL SRCH
2680     PLA 
2690     PLA 
2700     RTS         ;it isn't there !?!
2710 GOTIT STY TEMP  ;we'll need this later
2720     LDA HATABS+1,Y ;low byte
2730     STA PTR1
2740     LDA HATABS+2,Y ;high byte
2750     STA PTR1+1
2760     LDY #15
2770 LOOP LDA (PTR1),Y
2780     STA (PTR2),Y ;copy old table to mine
2790     DEY 
2800     BPL LOOP
2810     LDY TEMP
2820     RTS 
2830 ;
2840 INSVEC
2850     TYA 
2860     PHA 
2870     TXA 
2880     LDY #4      ;doing 3rd entry (getch)
2890     CLC 
2900     ADC MEMLO
2910     STA (PTR2),Y
2920     PLA 
2930     ADC MEMLO+1
2940     INY 
2950     STA (PTR2),Y
2960     RTS 
2970 ;
2980 ;
2990 ; set pointer to patched handler table
3000 PCHVEC
3010     TYA 
3020     PHA 
3030     TXA 
3040     LDY TEMP
3050     CLC 
3060     ADC MEMLO
3070     STA HATABS+1,Y
3080     PLA 
3090     ADC MEMLO+1
3100     STA HATABS+2,Y
3110     RTS 
3120 ;------------
3130 ;
3140 ;continue mainline INIT code
3150 END CLC 
3160     LDA MEMLO
3170     ADC #SIZE&$FF
3180     STA MEMLO   ;move MEMLO up past our new code
3190     LDA MEMLO+1
3200     ADC #SIZE/256
3210     STA MEMLO+1
3220 ;
3230 ; print out a msg
3240     LDA #9
3250     STA $0342
3260     LDA #MSG&$FF
3270     STA $0344
3280     LDA #MSG/256
3290     STA $0345
3300     LDA #$FF
3310     STA $0349
3320     LDX #0
3330     JSR $E456
3340 ;
3350 RTS RTS         ;all finished, no keyclick, and I didn't need a screwdriver
3360 ;
3370 TEMP .BYTE 0
3380 TEMPK .BYTE 0
3390 TEMPE .BYTE 0
3400 MSG .BYTE "Keyclick disabled",$9B
3410 ;----------------
3420 ;
3430     *=  $02E0
3440     .WORD RTS   ;DUMMY VECTOR
3450     .WORD INIT
3460 ; set start vector to run init code
3470 ; this allows concating with other autoruns
3480     .OPT NO LIST
3490 ;suppress xref if list on
3500 ;
3510 ;---- this is the last line ----