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 ----