NEW 0 GOTO 1000 1 REM * CFFA Utility by David A. Lyons 900 : 900 REM * Memory use: 905 REM * $0300 = EEPROM writing, EPROM/EEPROM detection 906 REM * $03C0 = COUT filter, 910 REM * $0800 = scratch space 920 REM * $1000..1FFF = 4K firmware image, loaded from disk 930 REM * $2000 = this BASIC code 999 : 1000 REM * Relocate us to $2000 1002 IF PEEK (104) < > 32 THEN POKE 103,1: POKE 104,32: POKE 32 * 256,0: PRINT CHR$ (4);"RUN CFFA.UTIL" 1010 VN$ = "2.0":DT$ = "3-May-2008" 1020 GOSUB 50000 1030 GOSUB 20000 1040 CC% = 1 : SLOT = CF%(CC%) 1090 M = 1 1100 REM * Main Menu 1105 M9 = 5 1110 M$(1) = "Settings" 1120 M$(2) = "Show CFFA Details" 1140 M$(3) = "Upgrade EEPROM" 1150 M$(4) = "Change Slot" REM If there is no CFFA card present, all you can do is Quit. 1160 IF SLOT=0 THEN M9=1 1190 M$(M9) = "Quit" 1200 IF SLOT = 0 THEN CC$ = "No CFFA card found in any slot." 1210 IF SLOT < > 0 THEN CC$ = "Using CFFA card in slot " + STR$ (SLOT) + "." 1300 HOME : PRINT CC$ 1305 PRINT : PRINT 1310 GOSUB 40000 1315 IF M=M9 THEN 19000 1320 HOME : ON M GOSUB 12000,11000,30000,14000,19000 1390 GOTO 1100 9999 : 10999 : 11000 REM * CFFA details 11010 IF SLOT = 0 THEN C$ = "No CFFA card found": GOSUB 60600: RETURN 11015 PRINT 11020 PRINT "Details for CFFA in slot ";SLOT;":" 11030 BASE = C000 + 256 * SLOT REM IF $CnFA vers is 255 then it's 2.0 or greater -> get the "real" version from $C822. 11040 V = PEEK (BASE + 250) : IF V=255 THEN POKE MSLOT,192+SLOT: Z=PEEK(CFFF): Z=PEEK(BASE): V=PEEK(C800+34) 11050 PRINT : PRINT "Firmware version "; INT (V / 16);".";V - 16 * INT (V / 16) REM If $CnF5 is FF, then the real GS/OS driver level is at $C823 REM 11060 L=PEEK(BASE+245): IF L=255 THEN POKE MSLOT,192+SLOT: Z=PEEK(CFFF): Z=PEEK(BASE): L=PEEK(C800+35) REM 11070 PRINT "GS/OS Driver level "; L REM 300: jsr $Cnxx to SmartPort entry REM 303: 0 = status REM 304: $310 = parameter list REM 306: sta 00 REM 308: php REM 309: pla REM 30A: and #1 REM 30B: sta 01 REM 30C: rts 11100 S = 768: POKE S,32: POKE S + 1, PEEK (BASE + 255) + 3: POKE S + 2,192 + SLOT 11110 POKE S + 3,0: REM * SP status 11120 POKE S + 4,16: POKE S + 5,3 11130 POKE S + 6,133: POKE S + 7,0: POKE S + 8,8: POKE S + 9,104: POKE S + 10,41: POKE S + 11,1: POKE S + 12,133: POKE S + 13,1: POKE S + 14,96 11140 POKE S + 16,3: POKE S + 17,0: POKE S + 18,0: POKE S + 19,8: POKE S + 20, ASC ("I") 11150 CALL S 11160 PRINT : IF PEEK(0) THEN 11300 : REM error REM display results of the first Identify call 11170 PRINT: PRINT "Dev0 Identify results:" 11200 FOR X = 2102 TO 2141: PRINT CHR$ ( PEEK (X));: NEXT : PRINT 11210 FOR X = 2068 TO 2087: PRINT CHR$ ( PEEK (X));: NEXT : PRINT 11220 FOR X = 2094 TO 2101: PRINT CHR$ ( PEEK (X));: NEXT REM try Dev1 -- status code is one less than "I" 11300 POKE S+20, ASC("H"): CALL S 11310 IF PEEK(0) THEN 11980 : REM error 11320 ?:?:?"Dev1 Identify results:" 11330 FOR X = 2102 TO 2141: PRINT CHR$ ( PEEK (X));: NEXT : PRINT 11340 FOR X = 2068 TO 2087: PRINT CHR$ ( PEEK (X));: NEXT : PRINT 11350 FOR X = 2094 TO 2101: PRINT CHR$ ( PEEK (X));: NEXT 11980 GOSUB 61500 11990 RETURN 11999 : REM ============================================================================================ REM C800 Max32MBPartitionsDev0: range 0 to 13 REM C801 Max32MBPartitionsDev1: range 0 to 13 REM C802 DefaultBootDevice: range 0 to 1 REM C803 DefaultBootPartition: range 1 to 13 REM C809 MenuSnagMask: ($DF) allow "m" or "M" to activate the boot-time menu REM C80A MenuSnagKey: ('M'+$80) REM C80B BootTimeDelayTenths: number of tenths of a second to wait on boot before kbd check REM C80C BusResetSeconds: number of seconds to wait for ready after bus reset REM C80D CheckDeviceTenths: (100) number of tenths of a second to wait for device to be ready REM C80E ConfigOptionBits: set bit $80 to skip bus reset REM C80F BlockOffsetDev0: range 0 to 2^24 blocks (8 GB) REM C812 BlockOffsetDev1: range 0 to 2^24 blocks (8 GB) REM REM C820_Signature: 'CF' REM C822_VersionByte: REM C824_FeatureBits - $80=65C02, $40=EEPROM, $20=WriteProtect, $10=RawBlocks REM ============================================================================================ 12000 REM * Settings 12010 BASE=C000+256*SLOT: V=PEEK(BASE+250): IF V=255 THEN POKE MSLOT,192+SLOT: Z=PEEK(CFFF): Z=PEEK(BASE): V=PEEK(C800+34) 12020 IF V < 32 THEN C$="Requires firmware 2.0 or later.": GOSUB 60600: RETURN 12090 M=1 REM set up V() and V$() with current settings 12100 POKE MSLOT,192+SLOT: Z=PEEK(CFFF): Z=PEEK(BASE) 12110 V(1)=PEEK(C800+0): MN(1)=0: MX(1)=13: OFF(1)=0 12115 V(2)=PEEK(C800+1): MN(2)=0: MX(2)=13: OFF(2)=1 12120 V(3)=PEEK(C800+2): MN(3)=0: MX(3)=1: OFF(3)=2 12125 V(4)=PEEK(C800+3): MN(4)=1: MX(4)=13: OFF(4)=3 12130 V(5)=PEEK(C800+10): KM=PEEK(C800+9): OFF(5)=10: V$(5)="none": IF V(5)>127 THEN V(5)=V(5)-128 12131 IF V(5)>31 THEN V$(5)=CHR$(V(5)) 12132 IF V(5)<32 THEN V$(5)="^"+CHR$(V(5)+64) 12133 IF V(5)=0 AND KM=0 THEN V$(5)="always" 12135 V(6)=PEEK(C800+11): V$(6)=STR$(INT(V(6)/10))+"."+STR$(V(6)-10*INT(V(6)/10)): MN(6)=0: MX(6)=25.5: OFF(6)=11 12140 V(7)=PEEK(C800+12): MN(7)=0: MX(7)=255: OFF(7)=12 12145 V(8)=PEEK(C800+13): V$(8)=STR$(INT(V(8)/10))+"."+STR$(V(8)-10*INT(V(8)/10)): MN(8)=0: MX(8)=25.5: OFF(8)=13 12150 V(9)=PEEK(C800+15) + 256*PEEK(C800+16) + 65536*PEEK(C800+17): V$(9)=STR$(V(9)): MN(9)=0: MX(9)=16777215: OFF(9)=15 12155 V(10)=PEEK(C800+18) + 256*PEEK(C800+19) + 65536*PEEK(C800+20): V$(10)=STR$(V(10)): MN(10)=0: MX(10)=16777215: OFF(10)=18 12200 M9=1: M$(M9)="Partitions Dev0 (" + STR$(V(1)) + ")" 12210 M9=M9+1: M$(M9)="Partitions Dev1 (" + STR$(V(2)) + ")" 12220 M9=M9+1: M$(M9)="Boot Dev (" + STR$(V(3)) + ")" 12230 M9=M9+1: M$(M9)="Boot Partition (" + STR$(V(4)) + ")" 12240 M9=M9+1: M$(M9)="Menu key (" + V$(5) + ")" 12250 M9=M9+1: M$(M9)="Menu check delay (" + V$(6) + ")" 12260 M9=M9+1: M$(M9)="Bus reset timeout (" + STR$(V(7)) + ")" 12270 M9=M9+1: M$(M9)="Device timeout (" + V$(8) + ")" 12280 M9=M9+1: M$(M9)="Block offset Dev0 (" + V$(9) + ")" 12290 M9=M9+1: M$(M9)="Block offset Dev1 (" + V$(10) + ")" 12390 M9=M9+1: M$(M9)="Main Menu" 12400 HOME:?:?: M0$="Select a setting to modify:": GOSUB 40002: IF M=M9 THEN M=1: RETURN 12410 HOME: PRINT "New value for:" : ? : ?M$(M) : ? 12450 IF M<>5 THEN 12500 12460 ?"-> ";: GET V$(5): ?: V(5)=ASC(V$(5)): IF V(5)=27 THEN HOME:?"Set menu key to Esc";:GOSUB 57000: IF NOT Y THEN 12900 12470 IF V$(5)>="a" AND V$(5)<="z" THEN V(5)=V(5)-32 12475 IF KM>127 THEN V(5)=V(5)+128 12480 GOTO 12600 12500 ?"("; MN(M); " to "; MX(M); ") "; 12510 INPUT "";V$(M) 12520 IF V$(M)="" THEN 12900 12530 V(M)=VAL(V$(M)) 12540 IF V(M)MX(M) THEN C$="Out of range": GOSUB 60600: GOTO 12900 12550 IF M=6 OR M=8 THEN V(M)=INT(V(M)*10 + 0.5) : REM these are tenths of seconds 12600 REM * write new value for setting M to EEPROM 12610 POKE MSLOT,192+SLOT: Z=PEEK(CFFF): Z=PEEK(BASE) 12620 Z=PEEK(C000+128+16*SLOT+3) : REM enable writes to EEPROM 12630 V=V(M) 12640 IF M<>9 AND M<>10 THEN 12700 REM take care of the 3-byte offset parameters 12650 V2=INT(V/65536): V=V-65536*V2 12655 V1=INT(V/256): V=V-256*V1 12660 POKE C800+OFF(M)+2,V2 12665 FOR Z=1 TO 10: IF PEEK(C800+OFF(M)+2)=V2 THEN OK=1: Z=100: NEXT: GOTO 12675 12670 NEXT: OK=0: GOTO 12800 12675 POKE C800+OFF(M)+1,V1 12680 FOR Z=1 TO 10: IF PEEK(C800+OFF(M)+1)=V1 THEN OK=1: Z=100: NEXT: GOTO 12700 12685 NEXT: OK=0: GOTO 12800 REM stash a single-byte value in EEPROM and wait for it to stick 12700 POKE C800+OFF(M),V 12720 FOR Z=1 TO 10: IF PEEK(C800+OFF(M))=V THEN OK=1: Z=100: NEXT: GOTO 12800 12730 NEXT: OK=0 12800 Z=PEEK(C000+128+16*SLOT+4) : REM disable writes to EEPROM 12810 IF NOT OK THEN C$="Couldn't set value: check WP jumper": GOSUB 60600 12900 GOTO 12100 13999 : 14000 REM * Change cards 14010 IF CF% < 2 THEN C$ = "No other CFFA card found": GOSUB 60600: RETURN 14020 CC% = CC% + 1 14030 IF CC% > CF% THEN CC% = 1 14040 SLOT = CF%(CC%) 14050 RETURN 14090 : 19000 REM * Quit 19010 TEXT : HOME : PRINT "Bye!": END 19999 : 20000 REM * Locate all CFFA cards 20010 REM CF% = number of cards, CF%(1) = first card 20020 CF% = 0 20030 FOR S = 1 TO 7 20040 BASE = C000 + S * 256 20050 IF PEEK (BASE + 246) = ASC ("C") AND PEEK (BASE + 247) = ASC ("F") AND PEEK (BASE + 248) = ASC ("F") AND PEEK (BASE + 249) = ASC ("A") THEN CF% = CF% + 1:CF%(CF%) = S 20060 NEXT 20090 RETURN 28999: 29000 REM * Select firmware image file 29010 ?D$;"BLOAD CFFA.FIRMWARE,TDIR,A$1000,L$1000" 29050 M9=0 29060 P=4096 REM beginning of directory block 29100 O=4: N=13 REM try next dir entry 29110 O=O+39: N=N-1: IF N>0 THEN 29200 REM try next block, if any 29120 IF PEEK(P+2)=0 AND PEEK(P+3)=0 THEN 29500 29130 P=P+512: N=13: O=4 REM directory entry is at P+O REM look for seedling files (storage type = 2) 29200 IF INT(PEEK(P+O)/16)<>2 THEN 29110 REM look for filetype $00 or BIN 29210 T=PEEK(P+O+16): IF T<>0 AND T<>6 THEN 29110 REM look for length = 4096 29220 L = PEEK(P+O+21) + 256*PEEK(P+O+22) + 65536*PEEK(P+O+23): IF L <> 4096 THEN 29110 29230 N$="": FOR I=1 TO PEEK(P+O)-32: N$=N$+CHR$(PEEK(P+O+I)): NEXT 29240 M9=M9+1: M$(M9)=N$: T%(M9)=T 29250 GOTO 29110 REM hit end of directory 29500 IF M9=0 THEN C$="No firmware images available.": GOSUB 60600: OK=0: M=1: RETURN 29510 M9=M9+1: M$(M9)="Main Menu": M=1 29550 M0$="Choose a firmware file:" : GOSUB 40002 29560 IF M=M9 THEN OK=0: M=1: RETURN 29600 ?D$;"BLOAD CFFA.FIRMWARE/";M$(M);",T";T%(M);",A$1000,L$1000" 29610 OK=1: RETURN 29999 : 30000 REM * Upgrade EEPROM REM choose firmware 30100 GOSUB 29000: IF NOT OK THEN RETURN REM Hard-code your firmware choice here, if you want. REM 30100 ?D$;"BLOAD CFFA.FIRMWARE/CFFA20EEC02.BIN,T$00,A$1000,L$1000" 30200 CC$="" 30210 GOSUB 39000: IF E=0 THEN CC$="Boot ROM matches.": GOTO 30300 30220 CC$="Boot ROM does not match."+CHR$(13)+" Diffs=" + STR$(E) + " (1st at " + STR$(E1) + ")" 30300 CC$=CC$+CHR$(13) 30305 GOSUB 39100: EE=0 30310 FOR P=7 TO 0 STEP -1 30320 GOSUB 39110: EE=EE+E 30330 IF E THEN E0=E1 + 256*P 30340 NEXT P 30350 IF EE=0 THEN CC$=CC$+"Aux ROM matches.": GOTO 30400 30360 CC$=CC$+"Aux ROM does not match."+CHR$(13)+" Diffs=" + STR$(EE) + " (1st at " + STR$(E0) + ")" 30400 BASE = C000 + 256 * SLOT REM IF $CnFA vers is 255 then it's 2.0 or greater -> get the "real" version from $C822. 30410 V = PEEK (BASE + 250) : IF V=255 THEN POKE MSLOT,SLOT: Z=PEEK(CFFF): Z=PEEK(BASE): V=PEEK(C800+34) 30420 CC$=CC$+CHR$(13)+"CFFA in slot "+STR$(SLOT)+": v"+STR$(INT(V/16))+"."+STR$(V-16*(INT(V/16))) REM Show version from loaded firmware image 30430 V = PEEK(4096+256*SLOT+250): IF V=255 THEN V=PEEK(4096+2048+34) 30440 CC$=CC$+CHR$(13)+"Firmware file: v" + STR$(INT(V/16))+"."+STR$(V-16*(INT(V/16))) 30500 M = 1: M9=3 30520 M$(1) = "Program boot ROM ($C" + STR$(SLOT) + "xx)" 30530 M$(2) = "Program Aux ROM ($C800, 2K) 30590 M$(M9) = "Main Menu" 30700 HOME : PRINT CC$ 30710 PRINT : PRINT 30720 GOSUB 40000 30730 IF M=M9 THEN M=1:RETURN 30750 HOME : ON M GOSUB 31000,32000 REM Clear out the screen hole so the card automatically re-initializes itself REM (set $478+SLOT to anything other than $A5) 30760 POKE 1144+SLOT,0 30770 GOTO 30200 30999 : 31000 REM * Program boot ROM ($Cnxx, 256 bytes) 31050 IF SLOT = 3 THEN POKE 49163,0: REM HIT SOFTSWITCH TO TURN OFF SLOT 3 80 COL. ROM 31100 GOSUB 32500: GOSUB 32600 31110 IF E=0 THEN PRINT "Successful.":GOTO 31200 31120 ?"Failed at offset ";E1: ?" (working down from 255)": ?"Check write-protect jumper." 31200 GOSUB 61500 31210 RETURN 31999 : 32000 REM * Program Aux ROM ($C800, 2048 bytes) 32010 GOSUB 32500 32100 FOR P=7 TO 0 STEP -1 32110 GOSUB 32700 32120 IF E>0 THEN PF=P: P=-1:NEXT P:GOTO 32150 32130 NEXT P 32140 ?"Successful.": GOTO 32200 32150 ?"Failed on page ";PF;", offset ";E1 32160 ?"Check write-protect jumper." 32200 GOSUB 61500 32210 RETURN 32500 REM * Skeleton to Program one page of EEPROM. REM 0 php REM 1 sei REM 2 lda $cfff REM 5 lda $Cn00 -- +7 = 192+SLOT REM 8 ldy #0 -- or ldy #$ff (+9 = START) REM 10 dey REM 11 cpy #$EF -- need to skip $CFEF (on page 7) REM 13 beq @dey -- only branch for page $CF (+14 = SKIP) REM 15 lda $1z00,y REM 18 ldx #0 REM 20 sta $Cz00,Y REM 23 cmp $Cz00,Y REM 26 beq @tya REM 28 dex REM 29 bne @cmp REM 31 inc 0 REM 33 sty 1 REM 35 bne @plp REM 37 tya REM 38 bne @dey REM 40 plp REM 41 rts 32510 S=768: POKE S,8: POKE S+1,120: POKE S+2,173: POKE S+3,255: POKE S+4,207: POKE S+5,173: POKE S+6,0: POKE S+7,192+SLOT 32520 POKE S+8,160: POKE S+10,136: POKE S+11,192: POKE S+12,239: POKE S+13,240: POKE S+15,185: POKE S+16,0 32530 POKE S+18,162: POKE S+19,0: POKE S+20,153: POKE S+21,0: POKE S+23,217: POKE S+24,0: POKE S+26,240: POKE S+27,9 32540 POKE S+28,202: POKE S+29,208: POKE S+30,248: POKE S+31,230: POKE S+32,0: POKE S+33,132: POKE S+34,1 32550 POKE S+35,208: POKE S+36,3: POKE S+37,152: POKE S+38,208: POKE S+39,226: POKE S+40,40: POKE S+41,96 32560 RETURN 32600 REM * Write boot ROM for SLOT - return E=1 if error, E1=index of failure (working backwards from end) 32610 SKIP=0: START=0 32620 POKE S+9,START: POKE S+14,SKIP: POKE S+17,16+SLOT: POKE S+22,192+SLOT: POKE S+25,192+SLOT 32630 POKE 0,0: POKE 1,1: CALL S 32640 E=PEEK(0): E1=PEEK(1): IF E=0 AND E1=0 THEN E=256 32650 RETURN 32700 REM * Write page P of Aux ROM - return E=1 if error, E1=index of failure (working backwards from end) 32710 SKIP=0: START=0: IF P=7 THEN SKIP=251: START=255: REM branch offset after CPY #$EF, countdown to skip $CFFF 32720 POKE S+9,START: POKE S+14,SKIP: POKE S+17,16+8+P: POKE S+22,192+8+P: POKE S+25,192+8+P 32730 POKE 0,0: POKE 1,1: CALL S 32740 E=PEEK(0): E1=PEEK(1): IF E=0 AND E1=0 THEN E=256 32750 RETURN 39000 REM * Verify Boot ROM -- compare $Cnxx to $1nxx, returning E=error count, E1=offset of lowest difference. REM ldy #0 REM dey REM lda $Cn00,y REM cmp $1n00,y REM beq +4 REM inc 0 REM sty 1 REM tya REM bne @dey REM rts 39010 S=768: POKE S,160: POKE S+1,0: POKE S+2,136: POKE S+3,185: POKE S+4,0: POKE S+5,192+SLOT: POKE S+6,217: POKE S+7,0: POKE S+8,16+SLOT 39020 POKE S+9,240: POKE S+10,4:POKE S+11,230:POKE S+12,0:POKE S+13,132:POKE S+14,1:POKE S+15,152:POKE S+16,208:POKE S+17,240:POKE S+18,96 39030 POKE 0,0: POKE 1,1: CALL S 39040 E=PEEK(0): E1=PEEK(1): IF E=0 AND E1=0 THEN E=256 39090 RETURN 39100 REM * Set up verify-page (P=0 to 7) of Aux ROM -- compare $Czxx to $1zxx, returning E=error count, E1=offset of lowest difference. REM 0 php REM 1 sei REM 2 lda $cfff REM 5 lda $Cn00 -- +7 = 192+SLOT REM 8 ldy #0 -- or ldy #$ff (+9 = START) REM 10 dey REM 11 cpy #$EF -- need to skip $CFEF REM 13 beq @dey -- only branch for page $CF ($F0 FB, or $F0 00 to fall thru) (+14 = SKIP) REM 15 lda $Cz00,y REM 18 cmp $1z00,y REM 21 beq @tya REM 23 inc 0 REM 25 sty 1 REM 27 tya REM 28 bne @dey REM 30 plp REM 31 rts 39101 S=768: POKE S,8: POKE S+1,120: POKE S+2,173: POKE S+3,255: POKE S+4,207: POKE S+5,173: POKE S+6,0: POKE S+7,192+SLOT 39102 POKE S+8,160: POKE S+10,136: POKE S+11,192: POKE S+12,239: POKE S+13,240: POKE S+15,185: POKE S+16,0 39103 POKE S+18,217: POKE S+19,0: POKE S+21,240: POKE S+22,4: POKE S+23,230: POKE S+24,0 39104 POKE S+25,132: POKE S+26,1: POKE S+27,152: POKE S+28,208: POKE S+29,236: POKE S+30,40: POKE S+31,96 39105 RETURN 39110 REM * Verify page P of Aux ROM 39120 SKIP=0: START=0: IF P=7 THEN SKIP=251: START=255: REM branch offset after CPY #$EF, countdown to skip $CFFF 39130 POKE S+9,START: POKE S+14,SKIP: POKE S+17,192+8+P: POKE S+20,16+8+P 39170 POKE 0,0: POKE 1,1: CALL S 39180 E=PEEK(0): E1=PEEK(1): IF E=0 AND E1=0 THEN E=256 39190 RETURN 39199 : 39999 : 40000 REM * MENU (M$(), M9, M) REM M$()=choices, M9=number of choices, M=current choice 40001 M0$ = "Select one of the following:" 40002 REM * Menu w/ msg M0$ 40005 HTAB 1 40010 PRINT M0$: PRINT 40020 V = PEEK (37) + 1 40021 IF M9 > 10 THEN 40030 40022 VTAB 22:C$ = "Use arrows, numbers, or letters to": GOSUB 60000:C$ = "select; then press RETURN": GOSUB 60000: VTAB V 40030 FOR I9 = 1 TO M9: PRINT SPC( 1 + (I9 < 10));I9;". ";M$(I9): NEXT 40050 REM * MAIN LOOP FOR MENU 40052 IF M = 0 THEN M = M9 40053 IF M = M9 + 1 THEN M = 1 40055 HTAB 6: INVERSE : VTAB V - 1 + M: PRINT " ";M$(M);" ";: NORMAL 40060 GOSUB 41000: HTAB 6: VTAB V - 1 + M: PRINT " ";M$(M);" "; 40070 IF A$ = CHR$ (27) THEN M = M9: GOTO 40050 40080 IF A$ = CHR$ (13) THEN VTAB V - 1 + M: HTAB 1: RETURN 40090 IF A$ = CHR$ (8) OR A$ = CHR$ (11) THEN M = M - 1: GOTO 40050 40100 IF A$ = CHR$ (21) OR A$ = CHR$ (10) THEN M = M + 1: GOTO 40050 40102 IF VAL (A$) AND ( VAL (A$) > M9) THEN 40110 40105 IF VAL (A$) THEN M = VAL (A$): GOTO 40050 40107 GOSUB 42000: IF OK THEN 40050 40110 GOSUB 57900: GOTO 40050 40120 : 41000 WAIT - 16384,128: GET A$: RETURN 41080 : 42000 REM * ADVANCE TO ENTRY STARTING WITH A$, IF PRESENT 42010 OK = 0 42020 IF A$ > = "a" AND A$ < = "z" THEN A$ = CHR$ ( ASC (A$) - 32) 42025 M0 = M 42030 FOR CNT = 1 TO M9 42040 M0 = M0 + 1: IF M0 > M9 THEN M0 = 1 42050 IF A$ = LEFT$ (M$(M0),1) THEN CNT = 999: NEXT :M = M0:OK = 1: RETURN 42060 NEXT CNT: RETURN 42070 : 49999 : 50000 REM * Initialize 50010 DIM M$(20),T%(20),V(20),V$(20),MN(20),MX(20),OFF(20) 50015 GOSUB 59900 50030 D$ = CHR$ (4) 50040 MSLOT=2040: C000=49152: C800=51200: CFFF=53247 50900 RETURN 50910 : 57000 REM * Yes/No question; return Y=0/1 57010 PRINT "? (Y/N) "; 57020 GET A$: IF A$>="a" THEN A$=CHR$(ASC(A$)-32) 57030 IF A$ = "Y" THEN PRINT "yes":Y = 1: RETURN 57040 IF A$ = "N" THEN PRINT "no":Y = 0: RETURN 57050 GOSUB 57900: GOTO 57020 57060 : 57900 REM * ERROR TONE 57910 PRINT CHR$ (7); 57920 RETURN 57930 : 59900 REM * INIT SCREEN 59910 TEXT : HOME : NORMAL : SPEED= 255: NOTRACE 59920 REM * Install lowercase-filter REM $3C0: uppercaseInverseLetters: (for Apple IIe and later has $FBB3 = 6, PEEK(-1101)=6) REM cld REM bit $32 REM bmi @out REM $3C5: uppercaseAllLetters: (for Apple II+) REM cld REM cmp #$E0 REM bcc @out REM and #$DF REM out: REM jmp $fdf0 REM 59930 POKE 960,216: POKE 961,36: POKE 962,50: POKE 963,48: POKE 964,7: POKE 965,216: POKE 966,201: POKE 967,224: POKE 968,144 59931 POKE 969,2: POKE 970,41: POKE 971,223: POKE 972,76: POKE 973,240: POKE 974,253 59940 ?CHR$(4);"PR# A";960 + 5 * (PEEK(-1101) <> 6) REM used to use this on GS *** PRINT CHR$ (4);"PR#3": PRINT CHR$ (17);: REM * 80-col firmware, but 40-column mode (want inverse lowercase) 59950 H$ = "---------------------------------------" 59960 PRINT H$: PRINT "CFFA Utility v";VN$;: HTAB 40-LEN(DT$):?DT$ 59970 PRINT H$ 59980 POKE 34,4: VTAB 5 59990 RETURN 59999 : 60000 REM * CENTER C$ 60010 HTAB 21 - LEN (C$) / 2: PRINT C$: RETURN 60500 REM * CENTER C$ IN BOX 60510 TEXT : HOME 60520 A$ = "****************************************":B$ = "* *" 60530 PRINT A$;B$;B$;B$;A$: VTAB PEEK (37) - 3: GOSUB 60000: PRINT : PRINT : PRINT : RETURN 60598 : 60599 REM *Error C$ 60600 VTAB 9: GOSUB 60520: PRINT CHR$ (7); 60610 GOSUB 61500 60620 RETURN 60630 : 61498 : 61499 REM * Press RETURN to continue 61500 VTAB 24: HTAB 1: PRINT "Press RETURN to continue: "; 61510 GET KK$: IF KK$ < > CHR$ (13) THEN 61500 61520 RETURN 61999 : 62000 REM * Print A$ w/o breaking words 62005 IF LEFT$ (A$,1) = " " THEN A$ = MID$ (A$,2): GOTO 62005 62010 IF LEN (A$) < 40 THEN PRINT A$: GOTO 62100 62020 FOR P9 = 40 TO 1 STEP - 1: IF MID$ (A$,P9,1) = " " THEN PRINT LEFT$ (A$,P9 - 1):A$ = MID$ (A$,P9 + 1): GOSUB 62100: GOTO 62000 62030 NEXT : PRINT A$: GOSUB 62100: RETURN 62040 : 62050 REM * NEW LINE 62100 L9 = L9 + 1: IF L9 = 18 THEN L9 = 1: GOSUB 61500: HOME 62110 RETURN 63999 PRINT CHR$ (4);"SAVE CFFA.UTIL" SAVE CFFA.UTIL PRINT "Saved as CFFA.UTIL"