;Disassembly of Slogger Challenger 2.00 and variant ;Greg Cook, 1 May 2024 ;Pass this file through a C preprocessor or the attached asm2bin.pl ;to produce a listing that assembles one of the two enclosed ;versions of Challenger. ;Define one of the following symbols during preprocessing to assemble ;its associated target:- ;Symbol: _CHAL200 (default) ;Source: http://regregex.bbcmicro.net/romsearch.zip ;Path: romsearch/slogger/Challenger-3-2.00-1987-Slogger ;Banner version: 2.00 ;Code length: &3FE9 (=&3FDD+&000C) ;Acorn CRC: &AB1B ;PKZIP CRC: &9D9D127C ;XFER CRC: &B0DD5FCB ;Cksum: 338992930 ;Symbol: _PCH200 ;Source: https://github.com/tom-seddon/challenger_disassembly/raw/master/beeb/chaldis/1/R.PCH200 ;Banner version: 200B ;Code length: &3FE9 (=&3FDD+&000C) ;Acorn CRC: &557F ;PKZIP CRC: &8CE0EC81 ;XFER CRC: &D05A8A20 ;Cksum: 3447564607 ;Other interoperability symbols: ;_BUGFIX Fix parsing of file specifications "*" and ".*" ; Fix *INFO, *EX, *VERIFY, and EOF warning flag behaviour ; Preserve stack in *FDCSTAT ; Install empty BASIC program properly after copying ; *RUN, */ enter executables with Acorn DFS-like registers ; Set attribute correctly in OSFILE 4 ; Ignore b5..0 of A on entry to OSFIND ; Preserve RAM disc on OSWORD &7F call &5F (verify data) ; Return special registers &12, &1A in OSWORD &7F ;_EX Add *EX to command table, replacing *HELP CHAL ; (implies _BUGFIX) ;_MASTER Add service call &25 (write filing system information) ; Pass unrecognised *commands to the LIBFS via FSC 11 ;_TURBO Unrolled 'save AXY' routine for shorter debugging traces ;A ROM assembled with symbol _BUGFIX defined allows a simple RISC OS ;program running on an attached SPROW ARM7TDMI coprocessor to read files ;using the ANSI C Library and the built-in ARM Tube OS. ;The Chafix utility must be installed for the program to write files ;using the ANSI C Library. ;http://regregex.bbcmicro.net/#prog.dfsfix ;Note: [D] marks subtle differences from Opus DDOS 3.46. ;Disc transfer level 1 is eliminated in Challenger; L2 calls L0. #if defined _EX # undef _BUGFIX # define _BUGFIX 1 #endif 8000 EQUB &00 ;Language entry 8001 EQUB &00 8002 EQUB &00 #if defined _MASTER 8003 4C 06 89 JMP P906 ;Service entry #else 8003 4C 2F 80 JMP P02F ;Service entry #endif 8006 EQUB &82 ;rom type: service only 8007 EQUB &1A ;Copyright offset pointer 8008 EQUB &20 ;Version No. 8009 EQUS "Challenger 3" ;title 8015 EQUB &00 ;terminator byte #if defined _PCH200 8016 EQUS "200B" ;version string #else 8016 EQUS "2.00" ;version string #endif 801A EQUB &00 ;terminator byte 801B EQUS "(C)1987 Slogger" ;copyright string validated by MOS 802A EQUB &00 ;terminator byte .P02B ;Issue Filing System Call 802B 6C 1E 02 JMP (&021E) ;unreachable code 802E 60 RTS .P02F ;ROM service 802F C9 01 CMP #&01 8031 D0 54 BNE P087 ;Service call &01 = reserve absolute workspace 8033 20 4C A8 JSR R84C ;save AXY 8036 20 1F 82 JSR P21F ;probe Challenger unit RAM size 8039 AA TAX 803A F0 4A BEQ P086 ;if Challenger unit absent then return 803C 20 0C BE JSR SE0C ;else page in main workspace 803F AD 00 FD LDA &FD00 ;validate first workspace sentinel 8042 29 7F AND #&7F ;[D]mask off b7=Challenger is current FS 8044 C9 65 CMP #&65 ;[D]compare remainder with valid value &65/E5 8046 F0 0B BEQ P053 ;if equal then validate second sentinel 8048 A9 65 LDA #&65 ;else initialise sentinel=&65, b7=0 no FS 804A 8D 00 FD STA &FD00 #if defined _PCH200 804D 20 7E AB JSR RB7E ;initialise Challenger and ChADFS mappings #else 804D 20 6A AB JSR RB6A ;initialise current FS's drive mapping #endif 8050 20 00 BA JSR SA00 .P053 8053 A9 E5 LDA #&E5 ;validate second workspace sentinel 8055 CD FD FD CMP &FDFD 8058 F0 13 BEQ P06D ;if not equal to valid value &E5 805A 8D FD FD STA &FDFD ;then initialise second sentinel 805D A9 04 LDA #&04 ;[D]set current drive = 4 805F 85 CF STA &CF 8061 A2 02 LDX #&02 ;x=2 select drive 4 volume size = &3F5 8063 20 F8 AF JSR RFF8 ;initialise RAM disc catalogue 8066 E6 CF INC &CF ;current drive = 5 8068 A2 03 LDX #&03 ;x=3 select drive 5 volume size = &3FF 806A 20 F8 AF JSR RFF8 ;initialise RAM disc catalogue .P06D 806D A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset 806F 20 F2 AD JSR RDF2 ;call OSBYTE with X=0, Y=&FF 8072 8A TXA ;test type of last reset 8073 F0 03 BEQ P078 ;if A=0 then soft break so skip 8075 20 A4 82 JSR P2A4 ;else initialise workspace .P078 8078 20 C8 82 JSR P2C8 807B 2C F4 FD BIT &FDF4 ;[D]test b7=*ENABLE CAT 807E 10 06 BPL P086 ;if enabled 8080 BA TSX ;[D]then return Y=&17 nine pages of workspace 8081 A9 17 LDA #&17 ;[BUG] clobbers higher ROMs that need more 8083 9D 03 01 STA &0103,X .P086 8086 60 RTS .P087 8087 C9 02 CMP #&02 8089 D0 0B BNE P096 ;Service call &02 = reserve private workspace 808B 20 0C BE JSR SE0C ;page in main workspace 808E 2C F4 FD BIT &FDF4 ;[D]test b7=*ENABLE CAT 8091 10 02 BPL P095 ;if enabled 8093 C8 INY ;then reserve two pages of private workspace 8094 C8 INY .P095 8095 60 RTS .P096 8096 C9 03 CMP #&03 8098 D0 1C BNE P0B6 ;Service call &03 = boot 809A 20 0C BE JSR SE0C ;page in main workspace 809D 84 B3 STY &B3 ;save boot flag in scratch space 809F 20 4C A8 JSR R84C ;save AXY 80A2 A9 7A LDA #&7A ;call OSBYTE &7A = scan keyboard from &10+ 80A4 20 F4 FF JSR &FFF4 80A7 8A TXA ;test returned key code 80A8 30 09 BMI P0B3 ;if N=1 no key is pressed, so init and boot 80AA C9 52 CMP #&52 ;[D]else if key pressed is not C 80AC D0 45 BNE P0F3 ;then exit 80AE A9 78 LDA #&78 ;else register keypress for two-key rollover 80B0 20 F4 FF JSR &FFF4 .P0B3 80B3 4C EE 81 JMP P1EE ;initialise Chall. and boot default volume .P0B6 80B6 C9 04 CMP #&04 80B8 D0 20 BNE P0DA ;Service call &04 = unrecognised OSCLI 80BA 20 0C BE JSR SE0C ;page in main workspace 80BD 20 4C A8 JSR R84C ;save AXY 80C0 BA TSX 80C1 86 B8 STX &B8 ;save stack pointer to restore on abort 80C3 98 TYA ;a=offset of *command from GSINIT pointer #if defined _EX 80C4 A2 4D LDX #&4D ;point XY to utility command table at &914D 80C6 A0 91 LDY #&91 #else 80C4 A2 48 LDX #&48 ;point XY to utility command table at &9148 80C6 A0 91 LDY #&91 #endif 80C8 20 A8 91 JSR Q1A8 ;search for command in table 80CB B0 26 BCS P0F3 ;if not found then exit 80CD AD 00 FD LDA &FD00 ;[D]else test b7=Challenger is current FS 80D0 30 05 BMI P0D7 ;if b7=1 then execute *command 80D2 20 AA 00 JSR &00AA ;else get syntax byte from command table 80D5 30 1C BMI P0F3 ;if b7=1 restricted command then return .P0D7 80D7 6C A8 00 JMP (&00A8) ;else execute *command, Y=cmd line tail ptr .P0DA 80DA C9 09 CMP #&09 80DC D0 35 BNE P113 ;Service call &09 = *HELP 80DE 20 0C BE JSR SE0C ;page in main workspace 80E1 20 4C A8 JSR R84C ;save AXY 80E4 B1 F2 LDA (&F2),Y ;test character at start of *HELP string 80E6 C9 0D CMP #&0D ;if not CR then *HELP called with keyword 80E8 D0 0A BNE P0F4 ;so scan keyword #if defined _EX 80EA A2 95 LDX #&95 ;else point XY to *HELP keyword table at &9195 80EC A0 91 LDY #&91 80EE A9 02 LDA #&02 ;2 entries to print #else 80EA A2 90 LDX #&90 ;else point XY to *HELP keyword table at &9190 80EC A0 91 LDY #&91 80EE A9 03 LDA #&03 ;3 entries to print #endif 80F0 20 34 A5 JSR R534 ;print *HELP keywords and pass on the call. .P0F3 80F3 60 RTS .P0F4 ;Scan *HELP keyword 80F4 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 80F7 D0 03 BNE P0FC ;if keyword present then search in table 80F9 4C 69 84 JMP P469 ;else print newline [BUG] should stay quiet .P0FC ;Search for *HELP keyword 80FC 98 TYA ;a=offset of keyword from GSINIT pointer 80FD 48 PHA ;also save on stack #if defined _EX 80FE A2 95 LDX #&95 ;point XY to *HELP keyword table at &9195 8100 A0 91 LDY #&91 #else 80FE A2 90 LDX #&90 ;point XY to *HELP keyword table at &9190 8100 A0 91 LDY #&91 #endif 8102 20 A8 91 JSR Q1A8 ;search for keyword in table 8105 B0 03 BCS P10A ;if keyword found 8107 20 D7 80 JSR P0D7 ;then call its action address; print help .P10A 810A 68 PLA ;restore string offset 810B A8 TAY .P10C 810C 20 C5 FF JSR &FFC5 ;call GSREAD 810F 90 FB BCC P10C ;until end of argument (discarding it) 8111 B0 E1 BCS P0F4 ;then scan next *HELP keyword .P113 8113 C9 12 CMP #&12 8115 D0 0D BNE P124 8117 C0 04 CPY #&04 ;Service call &12 = initialise FS 8119 D0 D8 BNE P0F3 ;if number of FS to initialise = 4 811B 20 0C BE JSR SE0C ;then page in main workspace 811E 20 4C A8 JSR R84C ;save AXY 8121 4C 0E 82 JMP P20E ;and initialise Challenger FS .P124 8124 C9 08 CMP #&08 8126 D0 CB BNE P0F3 ;Service call &08 = unrecognised OSWORD 8128 20 0C BE JSR SE0C ;page in main workspace #if defined _TURBO 812B 20 79 A8 JSR R879 ;save XY (X will be clobbered on return) #else 812B 20 75 A8 JSR R875 ;save XY (X will be clobbered on return) #endif 812E A4 F0 LDY &F0 ;set &B0..1 = pointer to OSWORD control block 8130 84 B0 STY &B0 8132 A4 F1 LDY &F1 8134 84 B1 STY &B1 8136 A0 00 LDY #&00 8138 84 B9 STY &B9 ;=0 disc operation is uninterruptible 813A A4 EF LDY &EF ;set Y = OSWORD call number (in A on entry) 813C C0 7F CPY #&7F 813E D0 78 BNE P1B8 8140 20 88 AD JSR RD88 ;OSWORD A = &7F 8143 A0 01 LDY #&01 ;claim NMI 8145 B1 B0 LDA (&B0),Y ;offset 1 = address LSB 8147 85 A6 STA &A6 ;copy to &A6 8149 C8 INY 814A B1 B0 LDA (&B0),Y ;offset 2 = address 3MSB 814C 85 A7 STA &A7 ;copy to &A7 814E A0 00 LDY #&00 8150 B1 B0 LDA (&B0),Y ;offset 0 = drive number 8152 30 11 BMI P165 ;if b7=1 then use previous drive 8154 48 PHA ;[D]else save requested drive 8155 2A ROL A ;shift bit 3 = force double density 8156 2A ROL A ;to bit 6 8157 2A ROL A 8158 29 40 AND #&40 ;mask bit 6 = hardware double density flag 815A 0D ED FD ORA &FDED ;or with *DENSITY detected/forced DD flag 815D 8D ED FD STA &FDED ;update *DENSITY flag 8160 68 PLA ;restore requested drive 8161 29 07 AND #&07 ;extract drive number 0..7 8163 85 CF STA &CF ;set as current drive .P165 8165 C8 INY ;offset 1 = address 8166 A2 02 LDX #&02 8168 20 C2 89 JSR P9C2 ;copy address to &BE,F,&FDB5,6 816B B1 B0 LDA (&B0),Y ;[D]y = 5 on exit; offset 5 = no. parameters 816D 48 PHA ;save number of parameters 816E C8 INY ;increment offset 816F B1 B0 LDA (&B0),Y ;offset 6 = command 8171 29 3F AND #&3F 8173 85 B2 STA &B2 8175 20 9E A9 JSR R99E ;shift A right 4 places, extract bit 4: 8178 29 01 AND #&01 ;a=0 if writing to disc, A=1 if reading 817A 20 AE 96 JSR Q6AE ;open Tube data transfer channel 817D A0 07 LDY #&07 817F B1 B0 LDA (&B0),Y ;offset 7 = first parameter (usu. track) 8181 C8 INY ;offset 8, Y points to second parameter 8182 85 BA STA &BA 8184 A2 FD LDX #&FD ;x = &FD to start at offset 0: .P186 8186 E8 INX ;add 3 to X 8187 E8 INX 8188 E8 INX 8189 BD AD B8 LDA &B8AD,X ;get command byte from table 818C F0 20 BEQ P1AE ;if the terminator byte then exit 818E C5 B2 CMP &B2 ;else compare with OSWORD &7F command 8190 D0 F4 BNE P186 ;if not the same try next entry 8192 08 PHP ;else save interrupt state 8193 58 CLI ;enable interrupts 8194 A9 81 LDA #&81 ;[D]push return address &81A3 on stack 8196 48 PHA 8197 A9 A2 LDA #&A2 8199 48 PHA 819A BD AF B8 LDA &B8AF,X ;fetch action address high byte 819D 48 PHA ;push on stack 819E BD AE B8 LDA &B8AE,X ;fetch action address low byte 81A1 48 PHA ;push on stack 81A2 60 RTS ;jump to action address. ;Finish OSWORD &7F 81A3 AA TAX ;[D]hold result in X 81A4 28 PLP ;restore interrupt state 81A5 68 PLA ;[D]restore number of parameters 81A6 18 CLC ;add 7; drive, address, no.parms, command 81A7 69 07 ADC #&07 ;=offset of result in O7F control block 81A9 A8 TAY ;transfer to Y for use as offset 81AA 8A TXA 81AB 91 B0 STA (&B0),Y ;[D]store result in user's OSWORD &7F block 81AD 48 PHA ;[D]push dummy byte on stack: .P1AE 81AE 68 PLA ;[D]discard byte from stack 81AF 20 71 AD JSR RD71 ;release NMI 81B2 20 E6 96 JSR Q6E6 ;release Tube 81B5 A9 00 LDA #&00 ;exit A=0 to claim service call 81B7 60 RTS .P1B8 ;OSWORD A <> &7F 81B8 C0 7D CPY #&7D ;if A < &7D 81BA 90 31 BCC P1ED ;then exit #if defined _BUGFIX 81BC 20 15 AA JSR RA15 ;set current vol/dir = default, set up drive #else 81BC 20 1E AA JSR RA1E ;set current vol/dir = default, set up drive #endif 81BF 20 2F 96 JSR Q62F ;load volume catalogue L4 81C2 C0 7E CPY #&7E 81C4 F0 0C BEQ P1D2 ;OSWORD A = &7D (and &80..&DF) 81C6 20 16 BE JSR SE16 ;page in catalogue sector 1 81C9 A0 00 LDY #&00 81CB AD 04 FD LDA &FD04 ;get catalogue cycle number 81CE 91 B0 STA (&B0),Y ;store in OSWORD control block offset 0 81D0 98 TYA ;return A = 0, claiming service call. 81D1 60 RTS .P1D2 ;OSWORD A = &7E get size of volume in bytes 81D2 20 16 BE JSR SE16 ;page in catalogue sector 1 81D5 A9 00 LDA #&00 81D7 A8 TAY 81D8 91 B0 STA (&B0),Y ;store 0 at offset 0: multiple of 256 bytes 81DA C8 INY ;offset 1 81DB AD 07 FD LDA &FD07 ;get LSB volume size from catalogue 81DE 91 B0 STA (&B0),Y ;save as 3MSB volume size 81E0 C8 INY ;offset 2 81E1 AD 06 FD LDA &FD06 ;get boot option/top bits volume size 81E4 29 03 AND #&03 ;extract MSB volume size 81E6 91 B0 STA (&B0),Y ;save as 2MSB volume size 81E8 C8 INY ;offset 3 81E9 A9 00 LDA #&00 ;store 0: volume size less than 16 MiB 81EB 91 B0 STA (&B0),Y .P1ED 81ED 60 RTS .P1EE ;Initialise Chall. and boot default volume 81EE A5 B3 LDA &B3 ;get back boot flag (Y on entry to call &3) 81F0 48 PHA ;save on stack 81F1 38 SEC 81F2 20 5E AE JSR RE5E ;print Challenger banner 81F5 20 69 84 JSR P469 ;print newline 81F8 20 19 82 JSR P219 ;get Challenger unit type 81FB 29 03 AND #&03 ;extract b1,b0 of A 81FD F0 18 BEQ P217 ;if Challenger not installed then exit 81FF 20 C8 82 JSR P2C8 ;else initialise workspace part 2 8202 20 58 82 JSR P258 ;initialise Challenger FS 8205 68 PLA ;if boot flag was >0 8206 D0 03 BNE P20B ;then return A=0 to claim call 8208 4C F7 82 JMP P2F7 ;else examine and boot default volume .P20B ;Return A=0 820B A9 00 LDA #&00 820D 60 RTS .P20E ;*DISC / *DISK 820E 48 PHA 820F 20 36 82 JSR P236 ;probe JIM page &0001 for RAM 8212 D0 03 BNE P217 ;if RAM found then Challenger unit installed 8214 20 58 82 JSR P258 ;so initialise Challenger FS .P217 8217 68 PLA 8218 60 RTS .P219 ;Get Challenger unit type 8219 A6 F4 LDX &F4 ;get our ROM slot number 821B BD F0 0D LDA &0DF0,X ;get type from private page pointer 821E 60 RTS ;ChADFS ROM call 2 .P21F ;Probe Challenger unit RAM size 821F A2 00 LDX #&00 ;set X=0, no RAM found 8221 20 36 82 JSR P236 8224 D0 09 BNE P22F ;if RAM absent return 0 8226 E8 INX ;else X=1, 256 KiB unit 8227 A9 04 LDA #&04 ;probe JIM page &0401 for RAM 8229 20 38 82 JSR P238 ;will hit empty sockets, not alias to bank 0 822C D0 01 BNE P22F ;if RAM absent return 1 822E E8 INX ;else X=2, 512 KiB unit .P22F 822F 8A TXA 8230 A6 F4 LDX &F4 ;get our ROM slot number 8232 9D F0 0D STA &0DF0,X ;store Challenger unit type in private pg ptr 8235 60 RTS .P236 8236 A9 00 LDA #&00 ;Probe JIM page &0001 for RAM .P238 8238 8D FE FC STA &FCFE ;store MSB JIM paging register 823B A9 01 LDA #&01 ;page &0001 (main workspace) or &0401 823D 8D FF FC STA &FCFF ;store LSB JIM paging register 8240 AD 00 FD LDA &FD00 ;read offset 0 of JIM page 8243 49 FF EOR #&FF ;invert it 8245 8D 00 FD STA &FD00 ;write it back 8248 A0 05 LDY #&05 ;wait 13 microseconds .P24A 824A 88 DEY ;allow 1 MHz data bus to discharge 824B D0 FD BNE P24A 824D CD 00 FD CMP &FD00 ;read offset 0, compare with value written 8250 08 PHP ;save result 8251 49 FF EOR #&FF ;restore original value 8253 8D 00 FD STA &FD00 ;write back in case RAM is there 8256 28 PLP ;return Z=1 if location 0 acts like RAM 8257 60 RTS .P258 ;Initialise Challenger FS 8258 A9 00 LDA #&00 825A BA TSX 825B 9D 08 01 STA &0108,X ;have A=0 returned on exit 825E A9 06 LDA #&06 ;FSC &06 = new FS about to change vectors 8260 20 2B 80 JSR P02B ;issue Filing System Call 8263 A2 00 LDX #&00 ;x = 0 offset in MOS vector table .P265 8265 BD F9 AD LDA &ADF9,X ;copy addresses of extended vector handlers 8268 9D 12 02 STA &0212,X ;to FILEV,ARGSV,BGETV,BPUTV,GBPBV,FINDV,FSCV 826B E8 INX ;loop until 7 vectors transferred 826C E0 0E CPX #&0E 826E D0 F5 BNE P265 8270 20 E8 AD JSR RDE8 ;call OSBYTE &A8 = get ext. vector table addr 8273 84 B1 STY &B1 ;set up pointer to vector table 8275 86 B0 STX &B0 8277 A2 00 LDX #&00 ;x = 0 offset in Challenger vector table 8279 A0 1B LDY #&1B ;y = &1B offset of FILEV in extended vec tbl .P27B 827B BD 07 AE LDA &AE07,X ;get LSB action address from table 827E 91 B0 STA (&B0),Y ;store in extended vector table 8280 E8 INX 8281 C8 INY 8282 BD 07 AE LDA &AE07,X ;get MSB action address from table 8285 91 B0 STA (&B0),Y ;store in extended vector table 8287 E8 INX 8288 C8 INY 8289 A5 F4 LDA &F4 ;get our ROM slot number 828B 91 B0 STA (&B0),Y ;store in extended vector table 828D C8 INY 828E E0 0E CPX #&0E ;loop until 7 vectors transferred 8290 D0 E9 BNE P27B 8292 AD 00 FD LDA &FD00 ;[D]get first workspace sentinel 8295 09 80 ORA #&80 ;set b7=1 Challenger is current FS 8297 8D 00 FD STA &FD00 ;update first sentinel 829A A9 00 LDA #&00 829C 8D FF FD STA &FDFF ;b6=0 Challenger is current FS 829F A2 0F LDX #&0F ;service call &0F = vectors claimed 82A1 4C EC AD JMP RDEC ;call OSBYTE &8F = issue service call ;[D]no wksp/private page validation/init .P2A4 ;Initialise workspace part 1 82A4 20 0C BE JSR SE0C ;page in main workspace 82A7 A9 80 LDA #&80 ;a=&80 82A9 8D ED FD STA &FDED ;*OPT 6,0 automatic density 82AC 8D EA FD STA &FDEA ;*OPT 8,255 automatic stepping 82AF A9 0E LDA #&0E ;a=&0E 82B1 8D EE FD STA &FDEE ;*OPT 9,14 page in ROM slot 14 during disc ops 82B4 A9 00 LDA #&00 82B6 8D C7 FD STA &FDC7 ;set default volume = "0A" 82B9 8D C9 FD STA &FDC9 ;set library volume = "0A" 82BC 8D F4 FD STA &FDF4 ;[D]no *ENABLE CAT 82BF A9 24 LDA #&24 82C1 8D C6 FD STA &FDC6 ;set default directory = "$" 82C4 8D C8 FD STA &FDC8 ;set library directory = "$" 82C7 60 RTS .P2C8 ;Initialise workspace part 2 82C8 20 0C BE JSR SE0C ;page in main workspace 82CB 20 E4 AD JSR RDE4 ;call OSBYTE &EA = read Tube presence flag 82CE 8A TXA 82CF 49 FF EOR #&FF ;invert; 0=tube present &FF=Tube absent 82D1 8D CD FD STA &FDCD ;save Tube presence flag 82D4 A0 00 LDY #&00 ;y=&00 [D]no workspace validation 82D6 8C CE FD STY &FDCE ;no files are open 82D9 8C DE FD STY &FDDE ;unused 82DC 8C DD FD STY &FDDD ;NMI resource is not ours 82DF 8C CC FD STY &FDCC ;[D]no Tube data transfer in progress 82E2 8C FF FD STY &FDFF ;b6=0 Challenger is current FS 82E5 88 DEY ;y=&FF 82E6 8C DF FD STY &FDDF ;*commands are not *ENABLEd 82E9 8C D9 FD STY &FDD9 ;*OPT 1,0 quiet operation 82EC 8C DC FD STY &FDDC ;no catalogue in JIM pages 2..3 82EF 20 F0 AD JSR RDF0 ;call OSBYTE &FF = read/write startup options 82F2 86 B4 STX &B4 ;save them in zero page (unused) 82F4 4C F7 B8 JMP S8F7 ;set track stepping rate from startup options .P2F7 #if defined _BUGFIX 82F7 20 15 AA JSR RA15 ;set current volume and directory = default #else 82F7 20 1E AA JSR RA1E ;set current volume and directory = default #endif 82FA 20 32 96 JSR Q632 ;load volume catalogue 82FD A0 00 LDY #&00 82FF A2 00 LDX #&00 8301 20 16 BE JSR SE16 ;page in catalogue sector 1 8304 AD 06 FD LDA &FD06 ;get boot option/top bits volume size 8307 20 9E A9 JSR R99E ;shift A right 4 places 830A F0 25 BEQ P331 ;if boot option = 0 then exit 830C 48 PHA 830D A2 55 LDX #&55 ;point XY to filename "!BOOT" 830F A0 83 LDY #&83 8311 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 8314 20 DC 89 JSR P9DC ;set current file from file spec 8317 20 2E 8C JSR PC2E ;search for file in catalogue 831A 68 PLA ;restore boot option 831B B0 15 BCS P332 ;if !BOOT found then boot from it 831D 20 D3 A8 JSR R8D3 ;else print "File not found" and return 8320 EQUS "File not found" 832E EQUB &0D 832F EQUB &0D 8330 EA NOP .P331 8331 60 RTS .P332 8332 C9 02 CMP #&02 8334 90 0E BCC P344 ;if boot option = 1 then load !BOOT 8336 F0 06 BEQ P33E ;if boot option = 2 then run !BOOT 8338 A2 53 LDX #&53 ;else boot option = 3 (or b7 or b6 set) 833A A0 83 LDY #&83 ;point XY to "E.!BOOT" 833C D0 0A BNE P348 ;call OSCLI .P33E 833E A2 55 LDX #&55 ;point XY to "!BOOT" 8340 A0 83 LDY #&83 8342 D0 04 BNE P348 ;call OSCLI .P344 8344 A2 4B LDX #&4B ;point XY to "L.!BOOT" 8346 A0 83 LDY #&83 .P348 8348 4C F7 FF JMP &FFF7 ;call OSCLI 834B EQUS "L.!BOOT" 8352 EQUB &0D 8353 EQUS "E.!BOOT" 835A EQUB &0D ;*TYPE 835B 20 21 A8 JSR R821 ;claim service call and set up argument ptr 835E A9 00 LDA #&00 ;a = &00 CR does not trigger line no. 8360 F0 05 BEQ P367 ;*LIST 8362 20 21 A8 JSR R821 ;claim service call and set up argument ptr 8365 A9 FF LDA #&FF ;a = &FF CR triggers line number .P367 8367 85 AB STA &AB ;store CR mask 8369 A9 40 LDA #&40 ;OSFIND &40 = open a file for reading 836B 20 CE FF JSR &FFCE ;call OSFIND 836E A8 TAY ;test returned file handle 836F F0 30 BEQ P3A1 ;if file not found then raise error 8371 A9 0D LDA #&0D ;preload CR so *LIST prints line no. 1 8373 D0 1B BNE P390 ;branch to CR test (always) .P375 8375 20 D7 FF JSR &FFD7 ;call OSBGET 8378 B0 1E BCS P398 ;if EOF then finish 837A C9 0A CMP #&0A ;else if character is LF 837C F0 F7 BEQ P375 ;ignore it and get next one 837E 28 PLP ;else restore result of (A & mask) - CR 837F D0 08 BNE P389 ;if no match just print the character 8381 48 PHA ;else save first character of line 8382 20 DA A7 JSR R7DA ;increment and print BCD word 8385 20 18 A8 JSR R818 ;print a space 8388 68 PLA ;restore first character .P389 8389 20 E3 FF JSR &FFE3 ;call OSASCI 838C 24 FF BIT &FF ;if ESCAPE pressed 838E 30 09 BMI P399 ;then finish .P390 8390 25 AB AND &AB ;else apply mask to character just prt'd 8392 C9 0D CMP #&0D ;compare masked character with CR 8394 08 PHP ;save result 8395 4C 75 83 JMP P375 ;and loop to read next character .P398 8398 28 PLP ;discard result of (A & mask) - CR .P399 8399 20 69 84 JSR P469 ;print newline .P39C 839C A9 00 LDA #&00 ;OSFIND &00 = close file 839E 4C CE FF JMP &FFCE ;call OSFIND and exit .P3A1 83A1 4C 46 8B JMP PB46 ;raise "File not found" error ;*DUMP 83A4 20 21 A8 JSR R821 ;claim service call and set up argument ptr 83A7 A9 40 LDA #&40 ;OSFIND &40 = open a file for reading 83A9 20 CE FF JSR &FFCE ;call OSFIND 83AC A8 TAY ;transfer file handle to Y 83AD F0 F2 BEQ P3A1 ;if file not found raise error .P3AF 83AF 24 FF BIT &FF ;if ESCAPE pressed 83B1 30 E9 BMI P39C ;then close file and exit 83B3 A5 A9 LDA &A9 ;else get high byte of file offset 83B5 20 78 A9 JSR R978 ;print hex byte 83B8 A5 A8 LDA &A8 ;get low byte of file offset 83BA 20 78 A9 JSR R978 ;print hex byte 83BD 20 18 A8 JSR R818 ;print a space 83C0 BA TSX 83C1 86 AD STX &AD ;save stack pointer 83C3 A2 08 LDX #&08 ;offset = 8 for indexed indirect load [D]not 0 .P3C5 83C5 20 D7 FF JSR &FFD7 ;call OSBGET 83C8 B0 0A BCS P3D4 ;if EOF then finish 83CA 48 PHA ;[D]else save byte read for ASCII column 83CB 20 78 A9 JSR R978 ;print hex byte 83CE 20 18 A8 JSR R818 ;print a space 83D1 CA DEX ;decrement counter 83D2 D0 F1 BNE P3C5 ;loop until line complete .P3D4 83D4 CA DEX ;test counter 83D5 30 0D BMI P3E4 ;if EOF on incomplete line 83D7 08 PHP ;then save status (N=0, C=1) 83D8 20 D3 A8 JSR R8D3 ;pad hex column with "** " 83DB EQUS "** " 83DE A9 00 LDA #&00 83E0 28 PLP ;restore status 83E1 48 PHA ;push NUL to pad ASCII column 83E2 10 F0 BPL P3D4 ;loop until line complete (always) .P3E4 ;print ASCII column 83E4 08 PHP ;save C=EOF 83E5 BA TSX ;transfer stack pointer to X 83E6 A9 07 LDA #&07 83E8 85 AC STA &AC ;set counter to 7: .P3EA 83EA BD 09 01 LDA &0109,X ;[D]get byte 9..2 down = byte 1..8 of column 83ED C9 7F CMP #&7F ;if DEL or higher 83EF B0 04 BCS P3F5 ;then print a dot 83F1 C9 20 CMP #&20 ;else if a printable character 83F3 B0 02 BCS P3F7 ;then print it .P3F5 83F5 A9 2E LDA #&2E ;else print a dot: .P3F7 83F7 20 E3 FF JSR &FFE3 ;call OSASCI 83FA CA DEX ;decrement pointer, work toward top of stack 83FB C6 AC DEC &AC ;decrement counter 83FD 10 EB BPL P3EA ;loop until line complete 83FF 20 69 84 JSR P469 ;print newline 8402 A9 08 LDA #&08 ;add 8 to file offset 8404 18 CLC 8405 65 A8 ADC &A8 8407 85 A8 STA &A8 8409 90 02 BCC P40D ;carry out to high byte 840B E6 A9 INC &A9 .P40D 840D 28 PLP ;restore carry flag from OSBGET 840E A6 AD LDX &AD ;[D]restore stack pointer to discard column 8410 9A TXS 8411 90 9C BCC P3AF ;if not at end of file then print next row 8413 B0 87 BCS P39C ;else close file and exit ;*BUILD 8415 20 21 A8 JSR R821 ;claim service call and set up argument ptr 8418 A9 80 LDA #&80 ;OSFIND &80 = open a file for writing 841A 20 CE FF JSR &FFCE ;call OSFIND 841D 85 AB STA &AB ;save file handle 841F 20 38 A8 JSR R838 ;[D]set line number = 0 (OSFIND clobbers) .P422 8422 20 DA A7 JSR R7DA ;increment and print BCD word 8425 20 18 A8 JSR R818 ;print a space 8428 A9 FD LDA #&FD ;y = &FD point to JIM page for OSWORD 842A 85 AD STA &AD ;[BUG]writes garbage if no Challenger fitted! 842C A2 AC LDX #&AC ;x = &AC low address for OSWORD 842E A0 FF LDY #&FF ;y = &FF 8430 84 AE STY &AE ;maximum line length = 255 8432 84 B0 STY &B0 ;maximum ASCII value = 255 8434 C8 INY 8435 84 AC STY &AC ;clear low byte of pointer 8437 84 AF STY &AF ;minimum ASCII value = 0 8439 20 1B BE JSR SE1B ;page in line buffer 843C 98 TYA ;OSWORD &00 = read line of input 843D 20 F1 FF JSR &FFF1 ;call OSWORD 8440 08 PHP ;save returned flags 8441 84 AA STY &AA ;save length of line 8443 A4 AB LDY &AB ;y = file handle for OSBPUT 8445 A2 00 LDX #&00 ;offset = 0 for indexed indirect load .P447 8447 8A TXA ;(redundant; do CPX &AA instead) 8448 C5 AA CMP &AA ;compare offset with line length 844A F0 0C BEQ P458 ;if end of line reached then terminate line 844C 20 1B BE JSR SE1B ;else page in line buffer 844F BD 00 FD LDA &FD00,X ;get character of line 8452 20 D4 FF JSR &FFD4 ;call OSBPUT 8455 E8 INX ;increment offset 8456 D0 EF BNE P447 ;and loop to write rest of line (always) .P458 ;terminate line 8458 28 PLP ;restore flags from OSWORD 8459 B0 08 BCS P463 ;if user escaped from input then finish 845B A9 0D LDA #&0D ;else A = carriage return 845D 20 D4 FF JSR &FFD4 ;write to file 8460 4C 22 84 JMP P422 ;and loop to build next line .P463 8463 20 8F A9 JSR R98F ;acknowledge ESCAPE condition 8466 20 9C 83 JSR P39C ;close file: .P469 ;Print newline 8469 48 PHA 846A A9 0D LDA #&0D 846C 20 51 A9 JSR R951 ;print character in A (OSASCI) 846F 68 PLA 8470 60 RTS .P471 ;Select source volume 8471 20 4C A8 JSR R84C ;save AXY 8474 20 0C BE JSR SE0C ;page in main workspace 8477 AE CA FD LDX &FDCA ;set X = source volume 847A A9 00 LDA #&00 ;a=&00 = we want source disc 847C F0 0B BEQ P489 ;branch (always) .P47E ;Select destination volume 847E 20 4C A8 JSR R84C ;save AXY 8481 20 0C BE JSR SE0C ;page in main workspace 8484 AE CB FD LDX &FDCB ;set X = destination volume 8487 A9 80 LDA #&80 ;a=&80 = we want destination disc .P489 8489 48 PHA ;save A (redundant) 848A 86 CF STX &CF ;set wanted volume as current volume ;[D]no 'set up for current drive' 848C 68 PLA ;restore A (redundant) 848D 24 A9 BIT &A9 ;if disc swapping required 848F 30 01 BMI P492 ;then branch to prompt .P491 8491 60 RTS ;else exit .P492 8492 C5 AA CMP &AA ;compare wanted disc with disc in drive 8494 F0 FB BEQ P491 ;if the same then do not prompt 8496 85 AA STA &AA ;else wanted disc is going into drive 8498 20 D3 A8 JSR R8D3 ;print "Insert " 849B EQUS "Insert " 84A2 EA NOP 84A3 24 AA BIT &AA ;if b7=1 84A5 30 0B BMI P4B2 ;then print "destination" 84A7 20 D3 A8 JSR R8D3 ;else print "source" 84AA EQUS "source" 84B0 90 0F BCC P4C1 ;and branch (always) .P4B2 84B2 20 D3 A8 JSR R8D3 ;print " destination" 84B5 EQUS "destination" 84C0 EA NOP .P4C1 84C1 20 D3 A8 JSR R8D3 ;print " disk and hit a key" 84C4 EQUS " disk and hit a key" 84D7 EA NOP 84D8 20 EF 84 JSR P4EF ;poll for ESCAPE (OSRDCH) 84DB 4C 69 84 JMP P469 ;print newline and exit .P4DE ;Ask user yes or no 84DE 20 EF 84 JSR P4EF ;wait for keypress 84E1 29 5F AND #&5F ;convert to uppercase 84E3 C9 59 CMP #&59 ;is it "Y"? 84E5 08 PHP ;save the answer 84E6 F0 02 BEQ P4EA ;if so then print "Y" 84E8 A9 4E LDA #&4E ;else print "N" .P4EA 84EA 20 51 A9 JSR R951 ;print character in A (OSASCI) 84ED 28 PLP ;return Z=1 if "Y" or "y" pressed 84EE 60 RTS .P4EF ;Poll for ESCAPE (OSRDCH) 84EF 20 C2 AD JSR RDC2 ;call *FX 15,1 = clear input buffer 84F2 20 E0 FF JSR &FFE0 ;call OSRDCH, wait for input character 84F5 90 03 BCC P4FA ;if ESCAPE was pressed 84F7 A6 B8 LDX &B8 ;then abort our routine 84F9 9A TXS ;clear our stacked items, return to caller .P4FA 84FA 60 RTS .P4FB ;Restore parameters of source drive 84FB A0 00 LDY #&00 ;offset = 0 84FD F0 02 BEQ P501 ;branch (always) .P4FF ;Restore parameters of destination drive 84FF A0 02 LDY #&02 ;offset = 2: .P501 ;Restore parameters of source/dest drive 8501 20 0C BE JSR SE0C ;page in main workspace 8504 B9 FA FD LDA &FDFA,Y ;[D]get first track of selected volume 8507 8D EC FD STA &FDEC ;set as first track of current volume 850A B9 F9 FD LDA &FDF9,Y ;get packed drive parameters: .P50D ;Restore packed drive parameters 850D 48 PHA ;save packed drive parameters 850E 29 C0 AND #&C0 ;mask b7,b6 8510 8D ED FD STA &FDED ;store *OPT 6 density setting 8513 68 PLA ;restore packed drive parameters 8514 4A LSR A ;shift b1,b0 of A to b7,b6 8515 6A ROR A 8516 6A ROR A 8517 48 PHA ;save other bits 8518 29 C0 AND #&C0 ;mask b7,b6 851A 8D EA FD STA &FDEA ;store *OPT 8 tracks setting 851D 68 PLA ;restore b1,b0 = original b4,b3 851E 29 03 AND #&03 ;mask b1,b0 8520 4C 4C 85 JMP P54C ;unpack and store sectors per track .P523 ;Save parameters of source drive 8523 20 4C A8 JSR R84C ;save AXY 8526 A0 00 LDY #&00 8528 F0 05 BEQ P52F .P52A ;Save parameters of destination drive 852A 20 4C A8 JSR R84C ;save AXY 852D A0 02 LDY #&02 .P52F ;Save parameters of source/dest drive 852F 20 0C BE JSR SE0C ;page in main workspace 8532 AD EC FD LDA &FDEC ;get first track of current volume 8535 99 FA FD STA &FDFA,Y ;set as first track of selected volume 8538 20 3F 85 JSR P53F ;pack drive parameters 853B 99 F9 FD STA &FDF9,Y 853E 60 RTS .P53F ;Pack drive parameters 853F 20 5C 85 JSR P55C ;pack number of sectors per track 8542 0D EA FD ORA &FDEA ;apply *OPT 8 tracks setting in b7,b6 8545 0A ASL A ;shift spt to b4,b3, *OPT 8 to b1,b0 8546 2A ROL A 8547 2A ROL A 8548 0D ED FD ORA &FDED ;apply *OPT 6 density setting in b7,b6 854B 60 RTS ;return packed drive parameters .P54C ;Unpack and store sectors per track 854C C9 00 CMP #&00 ;if A=0 on entry then RAM disc 854E F0 08 BEQ P558 ;so store 0=sectors per track undefined 8550 C9 02 CMP #&02 ;else if A=1 8552 A9 0A LDA #&0A ;then store 10 sectors per track 8554 90 02 BCC P558 8556 A9 12 LDA #&12 ;else A>1, store 18 sectors per track .P558 8558 8D EB FD STA &FDEB ;store number of sectors per track 855B 60 RTS .P55C ;Pack number of sectors per track 855C AD EB FD LDA &FDEB ;get current setting 855F F0 07 BEQ P568 ;if A=0 then RAM disc, return 0 8561 C9 12 CMP #&12 ;else if less than 18 i.e. 10, single dens. 8563 A9 01 LDA #&01 ;then return 1 8565 90 01 BCC P568 8567 0A ASL A ;if 18 or more i.e. double density return 2. .P568 8568 60 RTS ;*BACKUP 8569 20 5F A7 JSR R75F ;ensure *ENABLE active 856C 20 8A A7 JSR R78A ;parse and print source and dest. volumes 856F A9 00 LDA #&00 8571 85 A8 STA &A8 ;no catalogue entry waiting to be created 8573 85 C8 STA &C8 ;set source volume LBA = 0 8575 85 C9 STA &C9 8577 85 CA STA &CA ;set destination volume LBA = 0 8579 85 CB STA &CB 857B 20 5F 86 JSR P65F ;load source volume catalogue 857E A9 00 LDA #&00 8580 8D EC FD STA &FDEC ;data area starts on track 0 8583 20 23 85 JSR P523 ;save parameters of source drive 8586 20 3A 86 JSR P63A ;return volume size in XY/boot option in A 8589 8D E0 FD STA &FDE0 ;save source volume boot option 858C 86 C6 STX &C6 858E 84 C7 STY &C7 8590 20 59 86 JSR P659 ;load destination volume catalogue 8593 A9 00 LDA #&00 8595 8D EC FD STA &FDEC ;data area starts on track 0 8598 20 2A 85 JSR P52A ;save parameters of destination drive 859B AD F9 FD LDA &FDF9 ;get density of source drive 859E 4D FB FD EOR &FDFB ;xor with density flag of destination drive 85A1 29 40 AND #&40 ;extract bit 6 density flag, ignore auto b7 85A3 F0 25 BEQ P5CA ;if the same density then skip 85A5 20 AD A8 JSR R8AD ;else raise density mismatch error. 85A8 EQUB &D5 85A9 EQUS "Both disks MUST be same density" 85C8 EQUB &0D 85C9 EQUB &00 .P5CA 85CA 20 3A 86 JSR P63A ;return volume size in XY/boot option in A 85CD 8A TXA ;save destination volume size on stack 85CE 48 PHA 85CF 98 TYA 85D0 48 PHA 85D1 C5 C7 CMP &C7 ;compare MSBs dest volume size - source 85D3 90 07 BCC P5DC ;if dest < source then raise error 85D5 D0 29 BNE P600 ;if dest > source then proceed 85D7 8A TXA ;else compare LSBs dest - source 85D8 C5 C6 CMP &C6 85DA B0 24 BCS P600 ;if dest >= source then proceed .P5DC 85DC A9 D5 LDA #&D5 ;else error number = &D5 85DE 20 38 A9 JSR R938 ;begin error message, number in A 85E1 AD CA FD LDA &FDCA ;get source drive 85E4 20 AD 8E JSR PEAD ;print " Drive " plus volume spec in A 85E7 20 D3 A8 JSR R8D3 ;print " larger than " 85EA EQUS " larger than " 85F7 AD CB FD LDA &FDCB ;get destination drive 85FA 20 AD 8E JSR PEAD ;print " Drive " plus volume spec in A 85FD 4C F8 A8 JMP R8F8 ;terminate error message, raise error .P600 8600 20 48 89 JSR P948 ;copy source drive/file to destination 8603 20 CA 88 JSR P8CA ;[D]store empty BASIC program at OSHWM (NEW) 8606 20 4C B7 JSR S74C ;[D]set Z=1 iff current drive is a RAM disc 8609 D0 03 BNE P60E ;if so 860B 68 PLA ;then discard destination volume size 860C 68 PLA 860D 60 RTS ;and exit .P60E 860E 2C ED FD BIT &FDED ;else test density flag 8611 70 16 BVS P629 ;if double density then update disc catalogue 8613 20 32 96 JSR Q632 ;else load volume catalogue L4 8616 68 PLA ;pop MSB destination volume size 8617 29 0F AND #&0F ;mask bits 0..3 8619 0D E0 FD ORA &FDE0 ;apply source boot option in bits 4..5 861C 20 16 BE JSR SE16 ;page in catalogue sector 1 861F 8D 06 FD STA &FD06 ;store in catalogue 8622 68 PLA ;pop LSB destination volume size 8623 8D 07 FD STA &FD07 ;store in catalogue 8626 4C 0B 96 JMP Q60B ;write volume catalogue L4 ;[BUG] Copying a 40 track DD disc to an 80 track DD disc preserves ;the destination disc size at &1001..2 = 1440 sectors but copies ;the source track count at &1004 = 40 tracks. EDOS *CATGEN will be ;unable to assign tracks in the second half of the disc. .P629 ;Update disc catalogue 8629 20 BA AC JSR RCBA ;load disc catalogue L3 862C 20 11 BE JSR SE11 ;page in catalogue sector 0 862F 68 PLA ;pop MSB disc size 8630 8D 01 FD STA &FD01 ;store in disc catalogue 8633 68 PLA ;pop LSB disc size 8634 8D 02 FD STA &FD02 ;store in disc catalogue 8637 4C BD AC JMP RCBD ;write disc catalogue L3 .P63A ;Return volume size in XY/boot option in A 863A 20 16 BE JSR SE16 ;page in catalogue sector 1 863D AE 07 FD LDX &FD07 ;get LSB volume size from catalogue 8640 AD 06 FD LDA &FD06 ;get boot option/top bits volume size 8643 48 PHA 8644 29 03 AND #&03 ;extract MSB volume size 8646 A8 TAY ;put volume size in XY 8647 20 0C BE JSR SE0C ;page in main workspace 864A 2C ED FD BIT &FDED ;test density flag 864D 50 06 BVC P655 ;if double density 864F AE F6 FD LDX &FDF6 ;then load disc size from workspace instead 8652 AC F5 FD LDY &FDF5 .P655 8655 68 PLA ;return disc size in XY 8656 29 F0 AND #&F0 ;return boot option in A bits 5 and 4 8658 60 RTS .P659 ;Load destination volume catalogue 8659 20 7E 84 JSR P47E ;select destination volume 865C 4C 32 96 JMP Q632 ;load volume catalogue L4 .P65F ;Load source volume catalogue 865F 20 71 84 JSR P471 ;select source volume 8662 4C 32 96 JMP Q632 ;load volume catalogue L4 ;*COPY 8665 20 2E 8B JSR PB2E ;allow wildcard characters in filename 8668 20 8A A7 JSR R78A ;parse and print source and dest. volumes 866B 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg 866E 20 DC 89 JSR P9DC ;set current file from file spec 8671 20 71 84 JSR P471 ;select source volume 8674 20 41 8B JSR PB41 ;ensure matching file in catalogue 8677 20 23 85 JSR P523 ;save parameters of source drive 867A AD D5 FD LDA &FDD5 ;[D]get start of user memory 867D 85 BD STA &BD ;[D]save in zero page 867F A9 00 LDA #&00 8681 8D F7 FD STA &FDF7 ;point to start of copy buffer file table 8684 85 A8 STA &A8 ;redundant 8686 A9 01 LDA #&01 8688 85 A8 STA &A8 ;one entry in copy buffer file table: ;Copy file .P68A 868A 98 TYA ;[D]save catalogue offset of found file 868B 48 PHA 868C A2 00 LDX #&00 .P68E 868E B5 C7 LDA &C7,X ;save file spec on stack 8690 48 PHA 8691 E8 INX 8692 E0 08 CPX #&08 8694 D0 F8 BNE P68E 8696 20 D3 A8 JSR R8D3 ;print "Reading " 8699 EQUS "Reading " 86A1 EA NOP 86A2 20 A3 8A JSR PAA3 ;print filename from catalogue 86A5 20 69 84 JSR P469 ;print newline 86A8 AE F7 FD LDX &FDF7 ;get pointer to free end of buffer table 86AB A9 08 LDA #&08 ;8 bytes to copy 86AD 85 B0 STA &B0 ;set counter: .P6AF 86AF 20 16 BE JSR SE16 ;page in catalogue sector 1 86B2 B9 08 FD LDA &FD08,Y ;get matching file's catalogue information 86B5 20 07 BE JSR SE07 ;page in auxiliary workspace 86B8 9D 11 FD STA &FD11,X ;store information in copy buffer table 86BB E8 INX ;&FD11..18,X 86BC C8 INY 86BD C6 B0 DEC &B0 ;loop until 8 bytes copied 86BF D0 EE BNE P6AF 86C1 A9 08 LDA #&08 ;8 characters to copy 86C3 85 B0 STA &B0 ;set counter: .P6C5 86C5 20 11 BE JSR SE11 ;page in catalogue sector 0 86C8 B9 00 FD LDA &FD00,Y ;get matching file's name and directory 86CB 20 07 BE JSR SE07 ;page in auxiliary workspace 86CE 9D 12 FD STA &FD12,X ;store filename in copy buffer table 86D1 E8 INX ;&FD1A..21,X 86D2 C8 INY 86D3 C6 B0 DEC &B0 ;loop until 8 characters copied 86D5 D0 EE BNE P6C5 86D7 A9 00 LDA #&00 86D9 9D 09 FD STA &FD09,X ;clear &FD19,X flag byte 86DC BD 05 FD LDA &FD05,X ;get LSB length 86DF C9 01 CMP #&01 ;[D]set C=1 iff file includes partial sector 86E1 BD 06 FD LDA &FD06,X ;get 2MSB length 86E4 69 00 ADC #&00 ;round up to get LSB length in sectors 86E6 9D 12 FD STA &FD12,X ;[D]store LSB length in sectors in table 86E9 08 PHP ;save carry flag 86EA BD 07 FD LDA &FD07,X ;get top bits exec/length/load/start sector 86ED 20 96 A9 JSR R996 ;extract b5,b4 of A 86F0 28 PLP ;restore carry flag 86F1 69 00 ADC #&00 ;carry out to get MSB length in sectors 86F3 9D 13 FD STA &FD13,X ;save length in sectors at &FD22..23,X 86F6 BD 08 FD LDA &FD08,X ;get LSB start LBA 86F9 9D 14 FD STA &FD14,X ;copy to &FD24,X 86FC BD 07 FD LDA &FD07,X ;get top bits exec/length/load/start sector 86FF 29 03 AND #&03 ;extract MSB start sector 8701 9D 15 FD STA &FD15,X ;store MSB start LBA at &FD25,X: ;Read segment of file .P704 8704 20 0C BE JSR SE0C ;page in main workspace 8707 38 SEC ;subtract HIMEM - OSHWM 8708 AD D6 FD LDA &FDD6 870B E5 BD SBC &BD 870D 85 C3 STA &C3 ;= number of pages of user memory 870F AC F7 FD LDY &FDF7 ;get pointer to latest buffer table entry 8712 20 07 BE JSR SE07 ;page in auxiliary workspace 8715 B9 22 FD LDA &FD22,Y ;copy LSB length in sectors 8718 85 C6 STA &C6 ;to zero page 871A B9 23 FD LDA &FD23,Y ;MSB length in sectors 871D 85 C7 STA &C7 871F B9 24 FD LDA &FD24,Y ;LSB start LBA 8722 85 C8 STA &C8 8724 B9 25 FD LDA &FD25,Y ;MSB start LBA 8727 85 C9 STA &C9 8729 20 89 89 JSR P989 ;set start and size of next transfer 872C A5 BD LDA &BD ;set MSB load address = start of user memory 872E 85 BF STA &BF 8730 A9 00 LDA #&00 8732 85 BE STA &BE ;[D]set LSB load address = 0 8734 85 C2 STA &C2 ;set LSB transfer size = 0 8736 A5 C3 LDA &C3 ;get size of transfer 8738 20 07 BE JSR SE07 ;page in auxiliary workspace 873B 99 18 FD STA &FD18,Y ;overwrite LSB start LBA at &FD18,Y 873E 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF 8741 20 0D 97 JSR Q70D ;read ordinary file L5 8744 20 9E 89 JSR P99E ;adjust addresses by amount transferred 8747 18 CLC 8748 A5 BD LDA &BD ;get start of free copy buffer 874A 65 C3 ADC &C3 ;add size of transfer 874C 85 BD STA &BD ;update start of free copy buffer 874E AC F7 FD LDY &FDF7 ;get pointer to latest buffer table entry 8751 20 07 BE JSR SE07 ;page in auxiliary workspace 8754 A5 C6 LDA &C6 ;return LSB length in sectors 8756 99 22 FD STA &FD22,Y ;to copy buffer table 8759 A5 C7 LDA &C7 ;MSB length in sectors 875B 99 23 FD STA &FD23,Y 875E A5 C8 LDA &C8 ;LSB start LBA 8760 99 24 FD STA &FD24,Y 8763 A5 C9 LDA &C9 ;MSB start LBA 8765 99 25 FD STA &FD25,Y 8768 A5 C6 LDA &C6 ;test number of sectors to transfer 876A 05 C7 ORA &C7 876C F0 0B BEQ P779 ;if no more then read next file/write buffer 876E 20 07 BE JSR SE07 ;else page in auxiliary workspace 8771 B9 19 FD LDA &FD19,Y ;get buffer table entry's flag byte 8774 09 80 ORA #&80 ;b7=1 file incomplete in buffer 8776 99 19 FD STA &FD19,Y ;update flag byte: ;Continue filling copy buffer until full, or write it out .P779 8779 20 0C BE JSR SE0C ;page in main workspace 877C A5 BD LDA &BD ;has copy buffer been filled up to HIMEM? 877E CD D6 FD CMP &FDD6 8781 F0 37 BEQ P7BA ;if so then write it out 8783 24 A8 BIT &A8 ;else if b7=1 all files read 8785 30 33 BMI P7BA ;then write out copy buffer 8787 A5 A8 LDA &A8 ;else if copy buffer table is full 8789 29 7F AND #&7F 878B C9 08 CMP #&08 878D F0 2B BEQ P7BA ;then write it out 878F 18 CLC 8790 AD F7 FD LDA &FDF7 ;else point copy buffer table pointer 8793 69 17 ADC #&17 ;to next entry: 8795 8D F7 FD STA &FDF7 ;Copy next matching file .P798 8798 A2 07 LDX #&07 ;8 bytes to restore: .P79A 879A 68 PLA ;restore file spec from stack 879B 95 C7 STA &C7,X 879D CA DEX ;loop until 8 bytes restored 879E 10 FA BPL P79A 87A0 68 PLA ;restore catalogue offset of found file 87A1 8D C2 FD STA &FDC2 87A4 20 35 8C JSR PC35 ;find next matching file 87A7 90 05 BCC P7AE ;if no more files match then finish 87A9 E6 A8 INC &A8 ;else increment no. of files in buffer 87AB 4C 8A 86 JMP P68A ;and copy next file. ;Flush copy buffer .P7AE 87AE AC F7 FD LDY &FDF7 ;more than one table entry in use? 87B1 D0 01 BNE P7B4 ;if so then write out copy buffer 87B3 60 RTS ;else exit .P7B4 87B4 A5 A8 LDA &A8 ;set b7=1 all files read 87B6 09 80 ORA #&80 87B8 85 A8 STA &A8 .P7BA 87BA 20 0C BE JSR SE0C ;page in main workspace 87BD 20 7E 84 JSR P47E ;select destination volume 87C0 AD D5 FD LDA &FDD5 87C3 85 BD STA &BD ;set start of copy buffer to OSHWM 87C5 A5 A8 LDA &A8 ;get no. entries in copy buffer 87C7 29 7F AND #&7F ;extract actual number of entries 87C9 AA TAX 87CA A0 E9 LDY #&E9 ;y=&E9 going to &00: ;Write file from copy buffer .P7CC 87CC 8A TXA 87CD 48 PHA ;save number of buffer table entries 87CE 18 CLC 87CF 98 TYA 87D0 69 17 ADC #&17 ;point to next buffer table entry 87D2 8D F8 FD STA &FDF8 ;set pointer to last entry of buffer table 87D5 48 PHA ;and save it 87D6 A8 TAY 87D7 20 07 BE JSR SE07 ;page in auxiliary workspace 87DA B9 19 FD LDA &FD19,Y ;if b6=1 destination file partly copied 87DD 29 40 AND #&40 ;then skip catalogue entry creation: 87DF D0 57 BNE P838 ;write out rest of file 87E1 B9 19 FD LDA &FD19,Y ;else b6=1 don't create entry twice 87E4 09 40 ORA #&40 87E6 99 19 FD STA &FD19,Y 87E9 A2 00 LDX #&00 .P7EB 87EB B9 11 FD LDA &FD11,Y ;read from buffer table entry &FD11..21,Y 87EE 95 BE STA &BE,X ;restore file catalogue info &BE..&C5 87F0 C8 INY ;and filename and directory &C7..&CE 87F1 E8 INX 87F2 E0 11 CPX #&11 87F4 D0 F5 BNE P7EB 87F6 20 53 97 JSR Q753 ;forget catalogue in JIM pages 2..3 87F9 20 2E 8C JSR PC2E ;search for file in catalogue 87FC 90 03 BCC P801 ;if file found 87FE 20 78 8C JSR PC78 ;then delete catalogue entry .P801 8801 20 2A 85 JSR P52A ;save parameters of destination drive 8804 20 8D 95 JSR Q58D ;expand 18-bit load address to 32-bit 8807 20 AC 95 JSR Q5AC ;expand 18-bit exec address to 32-bit 880A A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 880C 20 96 A9 JSR R996 ;extract b5,b4 of A 880F 85 C6 STA &C6 ;store MSB length of file 8811 20 0B 94 JSR Q40B ;create catalogue entry 8814 20 D3 A8 JSR R8D3 ;print "Writing " 8817 EQUS "Writing " 881F EA NOP 8820 20 A3 8A JSR PAA3 ;print filename from catalogue 8823 20 69 84 JSR P469 ;print newline 8826 AC F8 FD LDY &FDF8 ;point to last entry of buffer table 8829 20 07 BE JSR SE07 ;page in auxiliary workspace 882C A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 882E 29 03 AND #&03 ;extract b1,b0 of A 8830 99 26 FD STA &FD26,Y ;store MSB destination LBA 8833 A5 C5 LDA &C5 ;copy LSB destination LBA 8835 99 27 FD STA &FD27,Y ;Write segment of file .P838 8838 B9 18 FD LDA &FD18,Y ;get no. pages of data in buffer 883B 85 C3 STA &C3 ;set size of transfer 883D 18 CLC 883E B9 27 FD LDA &FD27,Y ;copy LSB destination LBA 8841 85 C5 STA &C5 8843 65 C3 ADC &C3 ;add transfer size 8845 99 27 FD STA &FD27,Y ;update LSB destination LBA of next write 8848 B9 26 FD LDA &FD26,Y ;copy MSB destination LBA 884B 85 C4 STA &C4 884D 69 00 ADC #&00 ;carry out transfer size 884F 99 26 FD STA &FD26,Y ;update MSB destination LBA of next write 8852 A5 BD LDA &BD ;get start of filled copy buffer 8854 85 BF STA &BF ;set MSB of source address 8856 A9 00 LDA #&00 8858 85 BE STA &BE ;clear LSB source address 885A 85 C2 STA &C2 ;clear LSB transfer size 885C 20 FF 84 JSR P4FF ;restore parameters of destination drive 885F 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF 8862 20 13 97 JSR Q713 ;write extended file L5 8865 18 CLC 8866 A5 BD LDA &BD ;get start of filled copy buffer 8868 65 C3 ADC &C3 ;add size of transfer 886A 85 BD STA &BD ;update start of filled copy buffer 886C 68 PLA ;restore pointer to last table entry 886D A8 TAY 886E 68 PLA ;restore no. entries in buffer table 886F AA TAX 8870 CA DEX ;remove one 8871 F0 03 BEQ P876 ;if last entry then check for multi-pass copy 8873 4C CC 87 JMP P7CC ;else write next file in copy buffer ;Wrote last entry of copy buffer. Copy rest of file or refill buffer .P876 8876 20 FB 84 JSR P4FB ;restore parameters of source drive 8879 AC F8 FD LDY &FDF8 ;point to last entry of buffer table 887C 20 07 BE JSR SE07 ;page in auxiliary workspace 887F B9 19 FD LDA &FD19,Y ;test flag byte 8882 29 80 AND #&80 ;if b7=0 file(s) in buffer are complete 8884 F0 2A BEQ P8B0 ;then start refilling copy buffer 8886 A2 00 LDX #&00 ;else start at offset = 0: ;The last entry in the copy buffer table needs another pass ;to fulfil. Move it to the first table slot. .P888 8888 B9 11 FD LDA &FD11,Y ;copy last entry to first position 888B 9D 11 FD STA &FD11,X 888E C8 INY ;increment offsets 888F E8 INX 8890 E0 17 CPX #&17 ;loop until all 23 bytes copied 8892 D0 F4 BNE P888 8894 A9 40 LDA #&40 ;b6=1 destination file partly copied 8896 8D 19 FD STA &FD19 ;set buffer table entry's flag byte 8899 20 71 84 JSR P471 ;select source volume 889C 20 32 96 JSR Q632 ;load volume catalogue L4 889F AD D5 FD LDA &FDD5 88A2 85 BD STA &BD ;set start of copy buffer to OSHWM 88A4 A9 00 LDA #&00 88A6 8D F7 FD STA &FDF7 ;one buffer table entry in use 88A9 85 A8 STA &A8 88AB E6 A8 INC &A8 ;one entry in copy buffer table 88AD 4C 04 87 JMP P704 ;read in the rest of this file. ;Exit if no more files to read; else empty copy buffer and refill it .P8B0 88B0 24 A8 BIT &A8 ;if b7=1 all files read 88B2 30 15 BMI P8C9 ;then exit 88B4 20 71 84 JSR P471 ;else select source volume 88B7 20 32 96 JSR Q632 ;load volume catalogue L4 88BA AD D5 FD LDA &FDD5 88BD 85 BD STA &BD ;set start of copy buffer to OSHWM 88BF A9 00 LDA #&00 88C1 8D F7 FD STA &FDF7 ;no buffer table entries in use 88C4 85 A8 STA &A8 ;no entries in copy buffer table 88C6 4C 98 87 JMP P798 ;copy next matching file. .P8C9 88C9 60 RTS .P8CA ;Store empty BASIC program at OSHWM (NEW) 88CA AD D5 FD LDA &FDD5 ;get start of user memory 88CD 85 BF STA &BF ;store as high byte of pointer #if defined _BUGFIX 88CF A0 00 LDY #&00 ;clear low byte 88D1 84 BE STY &BE ;PAGE is always on a page boundary #else 88CF A9 00 LDA #&00 ;clear low byte 88D1 85 BE STA &BE ;PAGE is always on a page boundary #endif 88D3 A9 0D LDA #&0D ;[BUG] Y uninitialised, store to wrong place 88D5 91 BE STA (&BE),Y ;&0D = first byte of end-of-program marker 88D7 C8 INY ;store at start of user memory 88D8 A9 FF LDA #&FF ;&FF = second byte of end-of-program marker 88DA 91 BE STA (&BE),Y ;store in user memory 88DC 60 RTS #if defined _MASTER .P8DE 88DE 85 B5 STA &B5 ;save call number (<> &0B from FSC 3) 88E0 8C E3 FD STY &FDE3 ;store offset of start of command line 88E3 A9 FF LDA #&FF ;lsb exec address in our OSFILE block = &FF: 88E5 85 C0 STA &C0 ;load executable to load address in catalogue 88E7 A5 F2 LDA &F2 ;copy GSINIT string pointer to zero page 88E9 85 BC STA &BC ;= command line pointer 88EB A5 F3 LDA &F3 88ED 85 BD STA &BD 88EF 60 RTS ;Filing system info table, in reverse 88F0 EQUB &04 ;filing system number 88F1 EQUB &15 ;highest file handle 88F2 EQUB &11 ;lowest file handle 88F3 EQUS " CSID" ;filing system name 88FB EQUB &04 ;filing system number 88FC EQUB &15 ;highest file handle 88FD EQUB &11 ;lowest file handle 88FE EQUS " KSID" ;filing system name .P906 ;ROM service 8906 C9 25 CMP #&25 8908 D0 10 BNE P91A ;Service call &25 = filing system info 890A A2 15 LDX #&15 ;22 bytes to write: .P90C 890C BD F0 88 LDA &88F0,X ;get byte of filing system info 890F 91 F2 STA (&F2),Y ;add to MOS table 8911 C8 INY ;increment table offset 8912 CA DEX ;decrement count 8913 10 F7 BPL P90C ;loop until 22 bytes written 8915 A6 F4 LDX &F4 ;restore AX, pass updated Y 8917 A9 25 LDA #&25 8919 60 RTS .P91A 891A 4C 2F 80 JMP P02F ;service other calls #else /* _MASTER */ ;unreachable code 88DD 20 71 84 JSR P471 88E0 20 32 96 JSR Q632 88E3 20 23 85 JSR P523 88E6 20 16 BE JSR SE16 ;page in catalogue sector 1 88E9 AD 07 FD LDA &FD07 88EC 85 C6 STA &C6 88EE AD 06 FD LDA &FD06 88F1 29 03 AND #&03 88F3 85 C7 STA &C7 88F5 AD 06 FD LDA &FD06 88F8 29 F0 AND #&F0 88FA 20 0C BE JSR SE0C ;page in main workspace 88FD 8D E0 FD STA &FDE0 8900 20 7E 84 JSR P47E 8903 20 32 96 JSR Q632 8906 4C 2A 85 JMP P52A ;unreachable code 8909 20 16 BE JSR SE16 ;page in catalogue sector 1 890C AD 06 FD LDA &FD06 890F 29 03 AND #&03 8911 C5 C7 CMP &C7 8913 90 07 BCC P91C 8915 D0 05 BNE P91C 8917 AD 07 FD LDA &FD07 891A C5 C6 CMP &C6 .P91C 891C 60 RTS #endif /* _MASTER */ .P91D ;Shift data 891D 20 4C A8 JSR R84C ;save AXY 8920 A9 02 LDA #&02 8922 8D D7 FD STA &FDD7 ;2 pages of user memory = catalogue sectors 8925 A9 00 LDA #&00 8927 85 BF STA &BF ;MSB of load address in JIM space = &00 .P929 8929 20 84 89 JSR P984 ;set start and size of first transfer 892C A9 02 LDA #&02 892E 85 BE STA &BE ;LSB of load address in JIM space = &02 8930 20 24 97 JSR Q724 ;read ordinary file to JIM L5 8933 A5 CA LDA &CA ;set LBA = destination volume LBA 8935 85 C5 STA &C5 ;NB always works downwards and shifts upwards 8937 A5 CB LDA &CB ;sector reads and writes will not overlap 8939 85 C4 STA &C4 893B A9 02 LDA #&02 893D 85 BE STA &BE ;LSB of load address in JIM space = &02 893F 20 21 97 JSR Q721 ;write ordinary file from JIM L5 8942 20 9E 89 JSR P99E ;adjust addresses by amount transferred 8945 D0 E2 BNE P929 ;loop until no more sectors to transfer 8947 60 RTS .P948 ;Copy source drive/file to destination 8948 20 0C BE JSR SE0C ;page in main workspace 894B A9 00 LDA #&00 894D 85 BE STA &BE ;clear LSB load address 894F 85 C2 STA &C2 ;clear LSB transfer size in bytes .P951 8951 20 84 89 JSR P984 8954 AD D5 FD LDA &FDD5 ;set MSB load address = start of user memory 8957 85 BF STA &BF 8959 20 FB 84 JSR P4FB ;restore parameters of source drive 895C 20 71 84 JSR P471 ;select source volume 895F 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF 8962 20 0D 97 JSR Q70D ;read extended file L5 8965 A5 CA LDA &CA ;set LBA = destination volume LBA 8967 85 C5 STA &C5 8969 A5 CB LDA &CB 896B 85 C4 STA &C4 896D AD D5 FD LDA &FDD5 ;set MSB save address = start of user memory 8970 85 BF STA &BF 8972 20 FF 84 JSR P4FF ;restore parameters of destination drive 8975 20 7E 84 JSR P47E ;select destination volume 8978 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF 897B 20 13 97 JSR Q713 ;write extended file L5 897E 20 9E 89 JSR P99E ;adjust addresses by amount transferred 8981 D0 CE BNE P951 ;loop until no more sectors to transfer 8983 60 RTS .P984 ;Set start and size of first transfer 8984 AD D7 FD LDA &FDD7 ;get number of pages of user memory 8987 85 C3 STA &C3 ;set number of sectors to transfer: .P989 ;Set start and size of next transfer ;?&C3 contains no. pages free in user memory 8989 A6 C6 LDX &C6 ;compare remaining file size 898B E4 C3 CPX &C3 ;- available memory 898D A5 C7 LDA &C7 898F E9 00 SBC #&00 8991 B0 02 BCS P995 ;[D]if remainder doesn't fit then fill memory 8993 86 C3 STX &C3 ;else transfer size=file size in pages .P995 8995 A5 C8 LDA &C8 ;set LBA = source volume LBA 8997 85 C5 STA &C5 8999 A5 C9 LDA &C9 899B 85 C4 STA &C4 899D 60 RTS .P99E ;Adjust addresses by amount transferred 899E A5 CA LDA &CA ;get LSB destination LBA 89A0 18 CLC 89A1 65 C3 ADC &C3 ;add number of sectors transferred 89A3 85 CA STA &CA ;store LSB destination LBA 89A5 90 02 BCC P9A9 ;carry out to MSB 89A7 E6 CB INC &CB .P9A9 89A9 A5 C3 LDA &C3 ;get number of sectors transferred 89AB 18 CLC 89AC 65 C8 ADC &C8 ;add LSB source LBA 89AE 85 C8 STA &C8 ;store LSB source LBA 89B0 90 02 BCC P9B4 ;carry out to MSB: 89B2 E6 C9 INC &C9 .P9B4 ;Subtract transfer size from remainder 89B4 38 SEC 89B5 A5 C6 LDA &C6 ;get LSB number of sectors in volume 89B7 E5 C3 SBC &C3 ;subtract amount transferred 89B9 85 C6 STA &C6 ;store LSB number of sectors remaining 89BB B0 02 BCS P9BF ;borrow from MSB 89BD C6 C7 DEC &C7 .P9BF 89BF 05 C7 ORA &C7 ;return Z=no more sectors to transfer 89C1 60 RTS .P9C2 ;Copy doubleword into OSFILE field 89C2 20 D2 89 JSR P9D2 ;copy low word into OSFILE field 89C5 CA DEX ;restore offset in X = 4 * field no. 89C6 CA DEX 89C7 20 CA 89 JSR P9CA ;copy 3MSB of dword to workspace: .P9CA ;Copy high byte into OSFILE field 89CA B1 B0 LDA (&B0),Y ;fetch byte from zero page workspace 89CC 9D B3 FD STA &FDB3,X ;store in OSFILE high words table 89CF E8 INX ;increment offsets 89D0 C8 INY 89D1 60 RTS .P9D2 ;Copy low word into OSFILE field 89D2 20 D5 89 JSR P9D5 ;copy LSB of word into workspace: .P9D5 ;Copy low byte into OSFILE field 89D5 B1 B0 LDA (&B0),Y ;fetch byte from zero page workspace 89D7 95 BC STA &BC,X ;store in OSFILE low words table 89D9 E8 INX ;increment offsets 89DA C8 INY 89DB 60 RTS .P9DC #if defined _BUGFIX 89DC 20 15 AA JSR RA15 ;set current volume and dir = default #else 89DC 20 1E AA JSR RA1E ;set current volume and dir = default #endif 89DF 4C F2 89 JMP P9F2 .P9E2 ;Set current file from argument pointer #if defined _BUGFIX 89E2 20 15 AA JSR RA15 ;set current volume and dir = default: #else 89E2 20 1E AA JSR RA1E ;set current volume and dir = default: #endif .P9E5 ;Parse file spec from argument pointer 89E5 A5 BC LDA &BC ;copy argument pointer to GSINIT pointer 89E7 85 F2 STA &F2 89E9 A5 BD LDA &BD 89EB 85 F3 STA &F3 89ED A0 00 LDY #&00 ;set Y = 0 offset for GSINIT 89EF 20 F2 A9 JSR R9F2 ;call GSINIT with C=0: .P9F2 ;Parse file spec 89F2 20 5D 8A JSR PA5D ;set current filename to all spaces 89F5 20 C5 FF JSR &FFC5 ;call GSREAD 89F8 B0 53 BCS PA4D ;if argument empty then "Bad filename" 89FA C9 3A CMP #&3A ;else is first character ":"? 89FC D0 22 BNE PA20 ;if not then skip to dir/filename 89FE 20 C5 FF JSR &FFC5 ;else a drive is specified, call GSREAD 8A01 B0 57 BCS PA5A ;if no drive number then "Bad drive" 8A03 20 F6 A9 JSR R9F6 ;else set current drive from ASCII digit 8A06 20 C5 FF JSR &FFC5 ;call GSREAD 8A09 B0 42 BCS PA4D ;if only drive specified then "Bad filename" 8A0B C9 2E CMP #&2E ;else if next character is "." 8A0D F0 0C BEQ PA1B ;then get first character of filename #if defined _BUGFIX 8A0F 20 FB A9 JSR R9FB ;else set volume from ASCII letter #else 8A0F 20 FC A9 JSR R9FC ;else set volume from ASCII letter #endif 8A12 20 C5 FF JSR &FFC5 ;call GSREAD 8A15 B0 36 BCS PA4D ;if only volume spec'd then "Bad filename" 8A17 C9 2E CMP #&2E ;if separator character "." missing 8A19 D0 32 BNE PA4D ;then raise "Bad filename" error .PA1B 8A1B 20 C5 FF JSR &FFC5 ;call GSREAD, get first character of filename 8A1E B0 2D BCS PA4D ;if filename is empty then "Bad filename" .PA20 8A20 85 C7 STA &C7 ;else save first character of filename 8A22 A2 00 LDX #&00 ;set filename offset = 0 8A24 20 C5 FF JSR &FFC5 ;call GSREAD, get second filename character #if defined _BUGFIX 8A27 B0 3A BCS PA63 ;if absent then process one-character name #else 8A27 B0 44 BCS PA6D ;if absent then process one-character name #endif 8A29 E8 INX ;else offset = 1 8A2A C9 2E CMP #&2E ;is the second character "."? 8A2C D0 0B BNE PA39 ;if not then read in rest of leaf name 8A2E A5 C7 LDA &C7 ;else first character was a directory spec 8A30 20 B0 AA JSR RAB0 ;set directory from ASCII character 8A33 20 C5 FF JSR &FFC5 ;call GSREAD, get first character of leaf name 8A36 B0 15 BCS PA4D ;if leaf name is empty then "Bad filename" 8A38 CA DEX ;else offset = 0, read in leaf name: .PA39 8A39 C9 2A CMP #&2A ;is filename character "*"? 8A3B F0 36 BEQ PA73 ;if so then process "*" in filename 8A3D C9 21 CMP #&21 ;else is it a control character or space? 8A3F 90 0C BCC PA4D ;if so then raise "Bad filename" error 8A41 95 C7 STA &C7,X ;else store character of filename 8A43 E8 INX ;point X to next character of current filename 8A44 20 C5 FF JSR &FFC5 ;call GSREAD, get next character of leaf name #if defined _BUGFIX 8A47 B0 29 BCS PA72 ;if no more then filename complete, return #else 8A47 B0 23 BCS PA6C ;if no more then filename complete, return #endif 8A49 E0 07 CPX #&07 ;else have seven characters been read already? 8A4B D0 EC BNE PA39 ;if not then loop, else: .PA4D ;Raise "Bad filename" error. 8A4D 20 9C A8 JSR R89C 8A50 EQUB &CC 8A51 EQUS "filename" 8A59 EQUB &00 .PA5A #if defined _BUGFIX 8A5A 4C 23 AA JMP RA23 ;raise "Bad drive" error .PA5D ;Set current filename to all spaces 8A5D A9 20 LDA #&20 .PA5F 8A5F A2 00 LDX #&00 8A61 F0 08 BEQ PA6B ;branch (always) .PA63 ;Process one-character filename 8A63 A5 C7 LDA &C7 ;if filename is "*", then: 8A65 C9 2A CMP #&2A 8A67 D0 09 BNE PA72 .PA69 ;Pad current filename with "#"s 8A69 A9 23 LDA #&23 ;x=offset of end of filename .PA6B 8A6B 95 C7 STA &C7,X 8A6D E8 INX 8A6E E0 07 CPX #&07 8A70 D0 F9 BNE PA6B .PA72 8A72 60 RTS .PA73 ;Process "*" in filename 8A73 20 C5 FF JSR &FFC5 ;call GSREAD 8A76 B0 F1 BCS PA69 ;if end of argument pad filename with "#"s 8A78 C9 20 CMP #&20 ;else if next character is space 8A7A F0 ED BEQ PA69 ;then pad filename with "#"s 8A7C D0 CF BNE PA4D ;else raise "Bad filename" error. #else /* _BUGFIX */ 8A5A 4C 34 AA JMP RA34 ;raise "Bad drive" error .PA5D ;Set current filename to all spaces 8A5D A2 00 LDX #&00 8A5F A9 20 LDA #&20 8A61 D0 02 BNE PA65 ;branch (always) .PA63 ;Pad current filename with "#"s 8A63 A9 23 LDA #&23 ;x=offset of end of filename .PA65 8A65 95 C7 STA &C7,X 8A67 E8 INX 8A68 E0 07 CPX #&07 8A6A D0 F9 BNE PA65 .PA6C 8A6C 60 RTS .PA6D ;Process one-character filename 8A6D A5 C7 LDA &C7 ;if filename is "*", then: 8A6F C9 2A CMP #&2A ;([BUG] don't call GSREAD twice on end-of-str 8A71 D0 F9 BNE PA6C ;e.g. *INFO"*" results in "Bad string" error) .PA73 ;Process "*" in filename 8A73 20 C5 FF JSR &FFC5 ;call GSREAD 8A76 B0 EB BCS PA63 ;if end of argument pad filename with "#"s 8A78 C9 20 CMP #&20 ;else if next character is space 8A7A F0 E7 BEQ PA63 ;then pad filename with "#"s 8A7C D0 CF BNE PA4D ;else raise "Bad filename" error. #endif /* _BUGFIX */ .PA7E ;Ensure disc not changed 8A7E 20 4C A8 JSR R84C ;save AXY 8A81 20 16 BE JSR SE16 ;page in catalogue sector 1 8A84 AD 04 FD LDA &FD04 ;get cycle number of last catalogue read 8A87 20 2F 96 JSR Q62F ;load volume catalogue L4 8A8A 20 16 BE JSR SE16 ;page in catalogue sector 1 8A8D CD 04 FD CMP &FD04 ;compare with freshly loaded cycle number #if defined _BUGFIX 8A90 F0 E0 BEQ PA72 ;return if equal, else: #else 8A90 F0 DA BEQ PA6C ;return if equal, else: #endif .PA92 8A92 20 AD A8 JSR R8AD ;Raise "Disk changed" error. 8A95 EQUB &C8 8A96 EQUS "Disk changed" 8AA2 EQUB &00 .PAA3 ;Print filename from catalogue 8AA3 20 4C A8 JSR R84C ;save AXY 8AA6 20 11 BE JSR SE11 ;page in catalogue sector 0 8AA9 B9 0F FD LDA &FD0F,Y ;get directory character 8AAC 08 PHP ;save N = lock attribute 8AAD 29 7F AND #&7F ;extract ASCII character 8AAF D0 05 BNE PAB6 ;if NUL then file is in CSD 8AB1 20 15 A8 JSR R815 ;so print two spaces 8AB4 F0 06 BEQ PABC ;branch (always) .PAB6 8AB6 20 51 A9 JSR R951 ;else print directory character 8AB9 20 4F A9 JSR R94F ;print a dot .PABC 8ABC A2 06 LDX #&06 ;repeat 7 times: .PABE 8ABE B9 08 FD LDA &FD08,Y ;get character of leaf name 8AC1 29 7F AND #&7F ;mask bit 7 8AC3 20 51 A9 JSR R951 ;print character 8AC6 C8 INY 8AC7 CA DEX 8AC8 10 F4 BPL PABE ;and loop 8ACA 20 0C BE JSR SE0C ;page in main workspace 8ACD 20 15 A8 JSR R815 ;print two spaces 8AD0 A9 20 LDA #&20 ;a = space 8AD2 28 PLP ;restore lock attribute in N 8AD3 10 02 BPL PAD7 ;if lock bit set 8AD5 A9 4C LDA #&4C ;then A = capital L .PAD7 8AD7 20 51 A9 JSR R951 ;print attribute character 8ADA 4C 18 A8 JMP R818 ;print a space and exit .PADD ;Print number of spaces in Y 8ADD 20 18 A8 JSR R818 ;print a space 8AE0 88 DEY ;loop until Y = 0 8AE1 D0 FA BNE PADD 8AE3 60 RTS .PAE4 ;Prepare extended file transfer 8AE4 A9 00 LDA #&00 ;set MSB length = 0; transfer less than 64 KiB 8AE6 85 A5 STA &A5 8AE8 A6 C4 LDX &C4 ;x = LSB of relative LBA 8AEA 4C F9 8A JMP PAF9 .PAED ;Prepare ordinary file transfer 8AED A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 8AEF 20 96 A9 JSR R996 ;extract b5,b4 of A 8AF2 85 A5 STA &A5 ;?&A5 = b17..16 (MSB) of length 8AF4 A5 C4 LDA &C4 ;x = b9..8 (MSB) of relative LBA 8AF6 29 03 AND #&03 8AF8 AA TAX .PAF9 8AF9 A5 BE LDA &BE ;copy user data address to NMI area 8AFB 85 A6 STA &A6 8AFD A5 BF LDA &BF 8AFF 85 A7 STA &A7 8B01 A5 C3 LDA &C3 ;copy 2MSB length 8B03 85 A4 STA &A4 8B05 A5 C2 LDA &C2 ;copy LSB length 8B07 85 A3 STA &A3 8B09 86 BA STX &BA ;store LSB/MSB of LBA (clobbered if LSB) 8B0B A5 C5 LDA &C5 ;copy MSB/LSB of LBA 8B0D 85 BB STA &BB 8B0F AD EB FD LDA &FDEB ;get number of sectors per track 8B12 F0 19 BEQ PB2D ;if not defined then just use the LBA 8B14 AD EC FD LDA &FDEC ;else get first track of current volume 8B17 85 BA STA &BA ;set track number for transfer 8B19 C6 BA DEC &BA ;decrement, to increment at start of loop 8B1B A5 C5 LDA &C5 ;get LSB of relative LBA: .PB1D 8B1D 38 SEC ;set C=1 to subtract without borrow: .PB1E 8B1E E6 BA INC &BA ;increment track number 8B20 ED EB FD SBC &FDEB ;subtract sectors-per-track from LBA 8B23 B0 F9 BCS PB1E ;loop until LSB borrows in 8B25 CA DEX ;then decrement MSB of relative LBA 8B26 10 F5 BPL PB1D ;loop until MSB borrows in/underflows 8B28 6D EB FD ADC &FDEB ;add sectors per track to negative remainder 8B2B 85 BB STA &BB ;set sector number. .PB2D 8B2D 60 RTS .PB2E ;Allow wildcard characters in filename 8B2E A9 23 LDA #&23 8B30 D0 02 BNE PB34 .PB32 ;Disallow wildcard characters in filename 8B32 A9 FF LDA #&FF .PB34 8B34 8D D8 FD STA &FDD8 8B37 60 RTS .PB38 ;Ensure file matching spec in catalogue 8B38 20 DC 89 JSR P9DC ;set current file from file spec 8B3B 4C 41 8B JMP PB41 ;ensure matching file in catalogue .PB3E ;Ensure file matching argument in catalogue 8B3E 20 E2 89 JSR P9E2 ;set current file from argument pointer: .PB41 ;Ensure matching file in catalogue 8B41 20 2E 8C JSR PC2E ;search for file in catalogue 8B44 B0 E7 BCS PB2D ;if found then return .PB46 8B46 20 A5 A8 JSR R8A5 ;else raise "File not found" error. 8B49 EQUB &D6 8B4A EQUS "not found" 8B53 EQUB &00 ;*MAP #if defined _BUGFIX 8B54 20 0E AA JSR RA0E ;parse volume spec from argument #else 8B54 20 16 AA JSR RA16 ;parse volume spec from argument #endif 8B57 20 2F 96 JSR Q62F ;load volume catalogue L4 8B5A A9 00 LDA #&00 8B5C 85 C4 STA &C4 ;clear MSB start of data area 8B5E 85 C6 STA &C6 ;clear total free space 8B60 85 C7 STA &C7 8B62 20 F8 A4 JSR R4F8 ;return no. reserved sectors in data area 8B65 85 C5 STA &C5 ;store LSB start of data area 8B67 AD EC FD LDA &FDEC ;if this volume's data area starts >track 0 8B6A F0 1C BEQ PB88 8B6C 20 D3 A8 JSR R8D3 ;then print "Track offset = " 8B6F EQUS " Track offset = " 8B81 EA NOP 8B82 20 78 A9 JSR R978 ;print hex byte 8B85 20 69 84 JSR P469 ;print newline .PB88 8B88 20 16 BE JSR SE16 ;page in catalogue sector 1 8B8B AC 05 FD LDY &FD05 ;y = offset of last catalogue entry: .PB8E 8B8E 20 07 95 JSR Q507 ;calculate slack space after file #if defined _BUGFIX 8B91 F0 2C BEQ PBBF ;if no slack space then only map the file #else 8B91 F0 2F BEQ PBC2 ;if no slack space then only map the file #endif 8B93 18 CLC 8B94 A5 B0 LDA &B0 ;else add LSB slack space 8B96 65 C6 ADC &C6 ;to LSB total free space 8B98 85 C6 STA &C6 8B9A 8A TXA ;add MSB slack space 8B9B 65 C7 ADC &C7 ;and carry out 8B9D 85 C7 STA &C7 ;to MSB total free space 8B9F 20 D3 A8 JSR R8D3 ;print " Free space " 8BA2 EQUS " Free space " 8BAF EA NOP #if defined _BUGFIX 8BB0 20 E3 B7 JSR S7E3 ;print number of sectors #else 8BB0 20 01 8C JSR PC01 ;print number of sectors #endif 8BB3 20 18 A8 JSR R818 ;print a space 8BB6 8A TXA ;a = MSB slack space 8BB7 20 80 A9 JSR R980 ;print hex nibble 8BBA A5 B0 LDA &B0 ;a = LSB slack space #if defined _BUGFIX 8BBC 20 86 B7 JSR S786 ;print hex byte and newline .PBBF 8BBF 98 TYA ;if end of catalogue reached 8BC0 F0 1B BEQ PBDD ;then print total free space 8BC2 20 B2 A9 JSR R9B2 ;else subtract 8 from Y 8BC5 20 A3 8A JSR PAA3 ;print filename from catalogue 8BC8 20 E3 8C JSR PCE3 ;print start sector 8BCB 20 18 A8 JSR R818 ;print a space 8BCE 20 EB 94 JSR Q4EB ;calculate number of sectors used by file 8BD1 20 E3 B7 JSR S7E3 ;print number of sectors 8BD4 20 69 84 JSR P469 ;print newline 8BD7 20 D6 94 JSR Q4D6 ;calculate LBA of end of file 8BDA 4C 8E 8B JMP PB8E ;loop to map next file. .PBDD ;Print total free space 8BDD 20 D3 A8 JSR R8D3 ;print "Free sectors " 8BE0 EQUB &0D 8BE1 EQUS "Free sectors " 8BEE A5 C7 LDA &C7 ;a = MSB total free space 8BF0 20 80 A9 JSR R980 ;print hex nibble 8BF3 A5 C6 LDA &C6 ;a = LSB total free space 8BF5 20 86 B7 JSR S786 ;print hex byte and newline 8BF8 4C 0C BE JMP SE0C ;page in main workspace and exit ;FSC 9 = *EX 8BFC 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 8BFF 20 2E 8B JSR PB2E ;allow wildcard characters in filename 8C02 20 5F 8A JSR PA5F ;a=&23; set current filename = "#######" 8C05 20 15 AA JSR RA15 ;set current volume and directory = default 8C08 20 3B AA JSR RA3B ;call GSINIT and parse directory spec 8C0B 20 41 8B JSR PB41 ;ensure matching file in catalogue 8C0E B0 15 BCS PC25 ;print *INFO lines for all matching files ;FSC 10 = *INFO 8C10 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 # if defined _EX 8C13 A2 19 LDX #&19 ;point XY to *INFO command table entry 8C15 A0 91 LDY #&91 ;fall through: # else 8C13 A2 14 LDX #&14 ;point XY to *INFO command table entry 8C15 A0 91 LDY #&91 ;fall through: # endif 8C17 20 1E 92 JSR Q21E ;set up trampoline to read *INFO entry 8C1A A0 00 LDY #&00 ;set Y = 0 offset for GSINIT #else /* _BUGFIX */ 8BBC 20 78 A9 JSR R978 ;print hex byte 8BBF 20 69 84 JSR P469 ;print newline .PBC2 8BC2 98 TYA ;if end of catalogue reached 8BC3 F0 1B BEQ PBE0 ;then print total free space 8BC5 20 B2 A9 JSR R9B2 ;else subtract 8 from Y 8BC8 20 A3 8A JSR PAA3 ;print filename from catalogue 8BCB 20 E3 8C JSR PCE3 ;print start sector 8BCE 20 18 A8 JSR R818 ;print a space 8BD1 20 EB 94 JSR Q4EB ;calculate number of sectors used by file 8BD4 20 01 8C JSR PC01 ;print number of sectors 8BD7 20 69 84 JSR P469 ;print newline 8BDA 20 D6 94 JSR Q4D6 ;calculate LBA of end of file 8BDD 4C 8E 8B JMP PB8E ;loop to map next file. .PBE0 ;Print total free space 8BE0 20 D3 A8 JSR R8D3 ;print "Free sectors " 8BE3 EQUB &0D 8BE4 EQUS "Free sectors " 8BF1 A5 C7 LDA &C7 ;a = MSB total free space 8BF3 20 80 A9 JSR R980 ;print hex nibble 8BF6 A5 C6 LDA &C6 ;a = LSB total free space 8BF8 20 78 A9 JSR R978 ;print hex byte 8BFB 20 69 84 JSR P469 ;print newline 8BFE 4C 0C BE JMP SE0C ;page in main workspace .PC01 ;Print number of sectors 8C01 A5 C4 LDA &C4 ;get MSB size of file or slack space 8C03 20 80 A9 JSR R980 ;print hex nibble 8C06 A5 C5 LDA &C5 ;get LSB size of file or slack space 8C08 4C 78 A9 JMP R978 ;print hex byte ;FSC 9 = *EX 8C0B 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 8C0E 20 16 AA JSR RA16 ;parse volume spec from argument 8C11 A2 00 LDX #&00 ;set X = 0, whole current filename to #s 8C13 20 63 8A JSR PA63 ;set current filename = "#######" 8C16 4C 1C 8C JMP PC1C ;jump into *INFO ;[BUG]trampoline not initialised ;[BUG]expects , should be *EX () ;[BUG]expects second argument ;use e.g. *EX "" :4.*.* ;FSC 10 = *INFO 8C19 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 ;[BUG]trampoline not initialised .PC1C #endif /* _BUGFIX */ ;*INFO 8C1C 20 2E 8B JSR PB2E ;allow wildcard characters in filename 8C1F 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg 8C22 20 38 8B JSR PB38 ;ensure file matching spec in catalogue .PC25 8C25 20 A5 8C JSR PCA5 ;print *INFO line 8C28 20 35 8C JSR PC35 ;find next matching file 8C2B B0 F8 BCS PC25 ;loop until no more files match. 8C2D 60 RTS .PC2E ;Search for file in catalogue 8C2E 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded 8C31 A0 F8 LDY #&F8 ;y=&F8, start beyond first catalogue entry 8C33 D0 06 BNE PC3B ;and jump into search loop (always) .PC35 ;Find next matching file 8C35 20 0C BE JSR SE0C ;page in main workspace 8C38 AC C2 FD LDY &FDC2 ;set Y = catalogue pointer .PC3B 8C3B 20 16 BE JSR SE16 ;page in catalogue sector 1 8C3E 20 A9 A9 JSR R9A9 ;add 8 to Y 8C41 CC 05 FD CPY &FD05 ;have we reached the end of the catalogue? 8C44 B0 53 BCS PC99 ;if so return C=0 file not found 8C46 20 A9 A9 JSR R9A9 ;else add 8 to Y 8C49 A2 07 LDX #&07 ;x=7 point to directory character: .PC4B 8C4B 20 0C BE JSR SE0C ;page in main workspace 8C4E B5 C7 LDA &C7,X ;get character of current filename 8C50 CD D8 FD CMP &FDD8 ;compare with wildcard mask 8C53 F0 11 BEQ PC66 ;if ='#' and wildcards allowed accept char 8C55 20 D1 A9 JSR R9D1 ;else set C=0 iff character in A is a letter 8C58 20 11 BE JSR SE11 ;page in catalogue sector 0 8C5B 59 07 FD EOR &FD07,Y ;compare with character in catalogue 8C5E B0 02 BCS PC62 ;if character in current filename is letter 8C60 29 DF AND #&DF ;then ignore case .PC62 8C62 29 7F AND #&7F ;ignore bit 7, Z=1 if characters equal 8C64 D0 0C BNE PC72 ;if not equal then test next file .PC66 8C66 88 DEY ;loop to test next (previous) char of name 8C67 CA DEX 8C68 10 E1 BPL PC4B ;if no more chars to test then files match 8C6A 20 0C BE JSR SE0C ;page in main workspace 8C6D 8C C2 FD STY &FDC2 ;save cat. offset of found file in workspace 8C70 38 SEC ;return C=1 file found 8C71 60 RTS .PC72 ;catalogue entry does not match file spec 8C72 88 DEY ;advance catalogue pointer to next file 8C73 CA DEX 8C74 10 FC BPL PC72 8C76 30 C3 BMI PC3B ;loop until file found or not .PC78 ;Delete catalogue entry 8C78 20 A8 A2 JSR R2A8 ;ensure file not locked or open (mutex) .PC7B 8C7B 20 11 BE JSR SE11 ;page in catalogue sector 0 8C7E B9 10 FD LDA &FD10,Y ;copy next file's entry over previous entry 8C81 99 08 FD STA &FD08,Y ;shifting entries up one place 8C84 20 16 BE JSR SE16 ;page in catalogue sector 1 8C87 B9 10 FD LDA &FD10,Y ;(copies title/boot/size if catalogue full) 8C8A 99 08 FD STA &FD08,Y 8C8D C8 INY ;loop until current file count reached 8C8E CC 05 FD CPY &FD05 ;have we reached the end of the catalogue? 8C91 90 E8 BCC PC7B 8C93 98 TYA ;copy Y to A = pointer to last file; C=1 8C94 E9 08 SBC #&08 ;subtract 8, catalogue contains one file less 8C96 8D 05 FD STA &FD05 ;store new file count .PC99 8C99 18 CLC .PC9A 8C9A 4C 0C BE JMP SE0C ;page in main workspace and exit. .PC9D ;Print *INFO line if verbose 8C9D 20 0C BE JSR SE0C ;page in main workspace 8CA0 2C D9 FD BIT &FDD9 ;test *OPT 1 setting 8CA3 30 F5 BMI PC9A ;if b7=1 then *OPT 1,0 do not print, else: .PCA5 ;Print *INFO line 8CA5 20 4C A8 JSR R84C ;save AXY 8CA8 20 A3 8A JSR PAA3 ;print filename from catalogue 8CAB 98 TYA ;save catalogue pointer 8CAC 48 PHA 8CAD A9 A1 LDA #&A1 ;set up pointer to OSFILE block in workspace 8CAF 85 B0 STA &B0 ;at &FDA1 8CB1 A9 FD LDA #&FD 8CB3 85 B1 STA &B1 8CB5 20 F7 8C JSR PCF7 ;return catalogue information to OSFILE block 8CB8 20 0C BE JSR SE0C ;page in main workspace 8CBB A0 02 LDY #&02 ;y = &02 offset of load address in block 8CBD 20 18 A8 JSR R818 ;print a space 8CC0 20 D1 8C JSR PCD1 ;print load address 8CC3 20 D1 8C JSR PCD1 ;print execution address 8CC6 20 D1 8C JSR PCD1 ;print file length 8CC9 68 PLA ;restore catalogue pointer 8CCA A8 TAY 8CCB 20 E3 8C JSR PCE3 ;print start sector 8CCE 4C 69 84 JMP P469 ;print newline .PCD1 ;Print 24-bit field at &FDA1,Y 8CD1 A2 03 LDX #&03 ;start at MSB, offset = 3: .PCD3 8CD3 B9 A3 FD LDA &FDA3,Y ;get byte at &FDA3,Y 8CD6 20 78 A9 JSR R978 ;print hex byte 8CD9 88 DEY ;increment offset 8CDA CA DEX ;decrement counter 8CDB D0 F6 BNE PCD3 ;loop until 3 bytes printed 8CDD 20 AA A9 JSR R9AA ;add 7 to Y to point to MSB of next field 8CE0 4C 18 A8 JMP R818 ;print a space and exit .PCE3 ;Print start sector 8CE3 20 16 BE JSR SE16 ;page in catalogue sector 1 8CE6 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector 8CE9 29 03 AND #&03 ;extract MSB start sector 8CEB 20 80 A9 JSR R980 ;print hex nibble 8CEE B9 0F FD LDA &FD0F,Y ;get LSB start sector 8CF1 20 78 A9 JSR R978 ;print hex byte 8CF4 4C 0C BE JMP SE0C ;page in main workspace [D]not print newline .PCF7 ;Return catalogue information to OSFILE block 8CF7 20 4C A8 JSR R84C ;save AXY 8CFA 98 TYA ;save catalogue pointer on stack 8CFB 48 PHA 8CFC AA TAX ;and copy to X 8CFD 20 0C BE JSR SE0C ;page in main workspace 8D00 A0 02 LDY #&02 ;clear bytes at offsets 2..17 8D02 A9 00 LDA #&00 .PD04 8D04 91 B0 STA (&B0),Y 8D06 C8 INY 8D07 C0 12 CPY #&12 8D09 D0 F9 BNE PD04 8D0B A0 02 LDY #&02 ;offset 2 = LSB load address .PD0D 8D0D 20 55 8D JSR PD55 ;copy two bytes from catalogue to OSFILE block 8D10 C8 INY ;skip high bytes of OSFILE field 8D11 C8 INY 8D12 C0 0E CPY #&0E ;loop until 3 fields half-filled: 8D14 D0 F7 BNE PD0D ;load address, execution address, file length 8D16 68 PLA ;restore catalogue pointer 8D17 AA TAX 8D18 20 11 BE JSR SE11 ;page in catalogue sector 0 8D1B BD 0F FD LDA &FD0F,X ;get directory character 8D1E 10 09 BPL PD29 ;if b7=1 then file is locked 8D20 A9 0A LDA #&0A ;so set attributes to LR/RW (old style) 8D22 A0 0E LDY #&0E ;no delete, owner read only, public read/write ;note: Acorn DFS returns &08 instead 8D24 20 0C BE JSR SE0C ;page in main workspace 8D27 91 B0 STA (&B0),Y ;store in OSFILE block .PD29 8D29 20 16 BE JSR SE16 ;page in catalogue sector 1 8D2C BD 0E FD LDA &FD0E,X ;get top bits exec/length/load/start sector 8D2F 20 0C BE JSR SE0C ;page in main workspace 8D32 A0 04 LDY #&04 ;offset 4 = 2MSB load address 8D34 20 43 8D JSR PD43 ;expand bits 3,2 to top 16 bits of field 8D37 A0 0C LDY #&0C ;offset 12 = 2MSB file length 8D39 4A LSR A ;PD43 returned A = ..eelldd 8D3A 4A LSR A ;shift A right twice to make A = ....eell 8D3B 48 PHA ;save exec address 8D3C 29 03 AND #&03 ;extract bits 1,0 for length (don't expand) 8D3E 91 B0 STA (&B0),Y ;store in OSFILE block 8D40 68 PLA ;restore exec address in bits 3,2 8D41 A0 08 LDY #&08 ;offset 8 = 2MSB execution address: .PD43 8D43 4A LSR A ;shift A right 2 places 8D44 4A LSR A 8D45 48 PHA ;save shifted value for return 8D46 29 03 AND #&03 ;extract bits 3,2 of A on entry 8D48 C9 03 CMP #&03 ;if either one is clear 8D4A D0 05 BNE PD51 ;then save both as b1,0 of 2MSB 8D4C A9 FF LDA #&FF ;else set MSB and 2MSB = &FF. 8D4E 91 B0 STA (&B0),Y 8D50 C8 INY .PD51 8D51 91 B0 STA (&B0),Y 8D53 68 PLA ;discard byte on stack 8D54 60 RTS .PD55 ;Copy two bytes from catalogue to OSFILE block 8D55 20 58 8D JSR PD58 .PD58 8D58 20 16 BE JSR SE16 ;page in catalogue sector 1 8D5B BD 08 FD LDA &FD08,X 8D5E 20 0C BE JSR SE0C ;page in main workspace 8D61 91 B0 STA (&B0),Y 8D63 E8 INX 8D64 C8 INY 8D65 60 RTS ;*STAT 8D66 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 8D69 20 72 AA JSR RA72 ;select specified or default volume 8D6C 8A TXA ;test bit 0 of X 8D6D 29 01 AND #&01 ;if X=3 drive and volume specified 8D6F F0 03 BEQ PD74 8D71 4C B3 8D JMP PDB3 ;then stat specified volume, else: .PD74 ;*STAT eight volumes if double density 8D74 A5 CF LDA &CF ;get current volume 8D76 29 0F AND #&0F ;extract drive number 8D78 85 CF STA &CF ;set current volume letter to A 8D7A A9 80 LDA #&80 ;data transfer call &80 = read data to JIM 8D7C 8D E9 FD STA &FDE9 ;set data transfer call number 8D7F 20 B5 AB JSR RBB5 ;detect disc format/set sector address 8D82 2C ED FD BIT &FDED ;test density flag 8D85 70 03 BVS PD8A ;if double density then *STAT eight volumes 8D87 4C B3 8D JMP PDB3 ;else *STAT the single volume .PD8A ;*STAT eight volumes 8D8A 20 0B 8F JSR PF0B ;print disc type and volume list 8D8D A2 00 LDX #&00 ;for each volume letter A..H: .PD8F 8D8F 20 07 BE JSR SE07 ;page in auxiliary workspace 8D92 BD CD FD LDA &FDCD,X ;test if number of tracks in volume > 0 8D95 F0 0D BEQ PDA4 ;if = 0 then no such volume, skip 8D97 8A TXA ;save volume counter 8D98 48 PHA 8D99 20 69 84 JSR P469 ;print newline 8D9C 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded 8D9F 20 33 90 JSR Q033 ;print volume statistics 8DA2 68 PLA ;restore volume counter 8DA3 AA TAX .PDA4 8DA4 18 CLC 8DA5 A5 CF LDA &CF ;get current volume 8DA7 69 10 ADC #&10 ;increment volume letter 8DA9 85 CF STA &CF ;set as current volume 8DAB E8 INX ;increment counter 8DAC E0 08 CPX #&08 ;loop until 8 volumes catalogued 8DAE D0 DF BNE PD8F 8DB0 4C 0C BE JMP SE0C .PDB3 ;*STAT specified volume 8DB3 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded 8DB6 20 0B 8F JSR PF0B ;print disc type and volume list 8DB9 4C 33 90 JMP Q033 ;print volume statistics .PDBC ;Print "No file" 8DBC 20 D3 A8 JSR R8D3 ;print string immediate [D]not VDU sequence 8DBF EQUB &0D ;newline 8DC0 EQUS "No file" 8DC7 EQUB &0D ;newline 8DC8 EA NOP 8DC9 60 RTS .PDCA ;List files in catalogue 8DCA 20 16 BE JSR SE16 ;page in catalogue sector 1 8DCD AD 05 FD LDA &FD05 ;get number of files in catalogue * 8 8DD0 F0 EA BEQ PDBC ;if catalogue empty then print "No file" 8DD2 85 AC STA &AC ;[D]else copy file count to zero page 8DD4 A0 FF LDY #&FF 8DD6 84 A8 STY &A8 ;print a newline before first entry 8DD8 C8 INY 8DD9 84 AA STY &AA ;CSD printed first, directory char = NUL .PDDB 8DDB 20 11 BE JSR SE11 ;page in catalogue sector 0 8DDE C4 AC CPY &AC ;have we reached the end of the catalogue? 8DE0 B0 1D BCS PDFF ;if so then start sorting entries 8DE2 B9 0F FD LDA &FD0F,Y ;else get directory character of cat entry 8DE5 20 0C BE JSR SE0C ;page in main workspace 8DE8 4D C6 FD EOR &FDC6 ;compare with default (CSD) directory 8DEB 20 11 BE JSR SE11 ;page in catalogue sector 0 8DEE 29 7F AND #&7F ;mask off lock bit 8DF0 D0 08 BNE PDFA ;if directories differ skip to next entry 8DF2 B9 0F FD LDA &FD0F,Y ;else set directory character to NUL 8DF5 29 80 AND #&80 ;and preserve lock bit 8DF7 99 0F FD STA &FD0F,Y .PDFA 8DFA 20 A9 A9 JSR R9A9 ;add 8 to Y 8DFD 90 DC BCC PDDB ;and loop (always) .PDFF 8DFF 20 11 BE JSR SE11 ;page in catalogue sector 0 8E02 A0 00 LDY #&00 ;y=&00, start at first file entry 8E04 20 9E 8E JSR PE9E ;find unlisted catalogue entry 8E07 90 09 BCC PE12 ;[D]if entry found then list it 8E09 20 0C BE JSR SE0C ;[D]else finish catalogue. 8E0C 20 53 97 JSR Q753 ;[D]forget catalogue in JIM pages 2..3 8E0F 4C 69 84 JMP P469 ;[D]print newline and exit .PE12 8E12 84 AB STY &AB ;save catalogue pointer 8E14 A2 00 LDX #&00 ;set filename offset = 0 .PE16 8E16 20 11 BE JSR SE11 8E19 B9 08 FD LDA &FD08,Y ;copy name and directory of first entry 8E1C 29 7F AND #&7F ;with b7 clear 8E1E 20 0C BE JSR SE0C 8E21 9D A1 FD STA &FDA1,X ;to workspace 8E24 C8 INY ;loop until 8 characters copied 8E25 E8 INX 8E26 E0 08 CPX #&08 8E28 D0 EC BNE PE16 .PE2A 8E2A 20 11 BE JSR SE11 8E2D 20 9E 8E JSR PE9E ;find unlisted catalogue entry 8E30 B0 2B BCS PE5D ;if none remaining then print lowest entry 8E32 38 SEC ;else set C=1 for subtraction 8E33 A2 06 LDX #&06 ;start at 6th character (LSB) of leaf name: .PE35 8E35 20 11 BE JSR SE11 ;page in catalogue sector 0 8E38 B9 0E FD LDA &FD0E,Y ;get character of entry 8E3B 20 0C BE JSR SE0C ;page in main workspace 8E3E FD A1 FD SBC &FDA1,X ;subtract character of workspace 8E41 88 DEY ;loop until 7 characters compared 8E42 CA DEX 8E43 10 F0 BPL PE35 8E45 20 AA A9 JSR R9AA ;add 7 to Y 8E48 20 11 BE JSR SE11 ;page in catalogue sector 0 8E4B B9 0F FD LDA &FD0F,Y ;get directory character (MSB) of entry 8E4E 29 7F AND #&7F ;mask off lock bit 8E50 20 0C BE JSR SE0C ;page in main workspace 8E53 ED A8 FD SBC &FDA8 ;subtract directory character in workspace 8E56 90 BA BCC PE12 ;if entry < wksp then copy entry to wksp 8E58 20 A9 A9 JSR R9A9 ;else add 8 to Y 8E5B B0 CD BCS PE2A ;and loop (always) .PE5D 8E5D 20 11 BE JSR SE11 ;page in catalogue sector 0 8E60 A4 AB LDY &AB ;get catalogue pointer 8E62 B9 08 FD LDA &FD08,Y ;set b7 in first character of leaf name 8E65 09 80 ORA #&80 ;marking entry as listed 8E67 99 08 FD STA &FD08,Y 8E6A 20 0C BE JSR SE0C ;page in main workspace 8E6D AD A8 FD LDA &FDA8 ;get directory character from workspace 8E70 C5 AA CMP &AA ;compare with last one printed 8E72 F0 10 BEQ PE84 ;if same then add entry to group 8E74 A6 AA LDX &AA ;else test previous directory 8E76 85 AA STA &AA ;set previous directory = current directory 8E78 D0 0A BNE PE84 ;if prev=NUL we go from CSD to other dirs 8E7A 20 69 84 JSR P469 ;so print double newline: .PE7D 8E7D 20 69 84 JSR P469 ;print newline 8E80 A0 FF LDY #&FF ;set Y = &FF going to 0, start of line 8E82 D0 09 BNE PE8D ;branch (always) .PE84 8E84 A4 A8 LDY &A8 ;have we printed two entries on this line? 8E86 D0 F5 BNE PE7D ;if so then print newline and reset counter 8E88 A0 05 LDY #&05 ;else tab to next field. Y = 5 spaces 8E8A 20 DD 8A JSR PADD ;print number of spaces in Y, set index = 1: .PE8D 8E8D C8 INY 8E8E 84 A8 STY &A8 ;y = index of next entry on this line 8E90 A4 AB LDY &AB ;get catalogue pointer 8E92 20 15 A8 JSR R815 ;print two spaces 8E95 20 A3 8A JSR PAA3 ;print filename from catalogue 8E98 4C FF 8D JMP PDFF ;loop until all files listed .PE9B ;Find next unlisted catalogue entry 8E9B 20 A9 A9 JSR R9A9 ;add 8 to Y .PE9E ;Find unlisted catalogue entry 8E9E C4 AC CPY &AC ;if catalogue pointer beyond last file 8EA0 B0 05 BCS PEA7 ;then return C=1 8EA2 B9 08 FD LDA &FD08,Y ;else test first character of leaf name 8EA5 30 F4 BMI PE9B ;if b7=1 then already listed, skip .PEA7 8EA7 60 RTS ;else return C=0, catalogue pointer in Y .PEA8 ;Print volume spec in A (assuming DD) 8EA8 2C A7 8E BIT &8EA7 ;set V=1 8EAB 70 11 BVS PEBE ;always print volume letter B..H after drive .PEAD ;Print " Drive " plus volume spec in A #if defined _PCH200 8EAD 20 D3 A8 JSR R8D3 8EB0 EQUS "Drive " 8EB6 EA NOP #else 8EAD 20 D3 A8 JSR R8D3 8EB0 EQUS " Drive " #endif 8EB7 EA NOP .PEB8 ;Print volume spec in A 8EB8 20 0C BE JSR SE0C ;test density flag 8EBB 2C ED FD BIT &FDED .PEBE 8EBE 08 PHP ;save density flag on stack 8EBF 48 PHA ;save volume on stack 8EC0 29 07 AND #&07 ;extract bits 2..0, drive 0..7 8EC2 20 80 A9 JSR R980 ;print hex nibble 8EC5 68 PLA ;restore volume 8EC6 28 PLP ;restore density flag 8EC7 50 06 BVC PECF ;if single density then only print drive no. 8EC9 4A LSR A ;else shift volume letter to bits 2..0 8ECA 4A LSR A 8ECB 4A LSR A 8ECC 4A LSR A 8ECD D0 01 BNE PED0 ;if volume letter is not A then print it .PECF 8ECF 60 RTS ;else exit .PED0 8ED0 88 DEY ;decrement Y (no. spaces to print later) 8ED1 18 CLC ;add ASCII value of "A" 8ED2 69 41 ADC #&41 ;to produce volume letter B..H 8ED4 4C 51 A9 JMP R951 ;print character in A (OSASCI) and exit .PED7 ;Print volume title 8ED7 A0 0B LDY #&0B ;set y = &0B print 11 spaces 8ED9 20 DD 8A JSR PADD ;print number of spaces in Y .PEDC 8EDC 20 11 BE JSR SE11 ;page in catalogue sector 0 8EDF B9 00 FD LDA &FD00,Y ;y=0; if Y=0..7 get char from sector 0 8EE2 C0 08 CPY #&08 ;if Y=8..11 8EE4 90 06 BCC PEEC 8EE6 20 16 BE JSR SE16 ;page in catalogue sector 1 8EE9 B9 F8 FC LDA &FCF8,Y ;then get character of title from sector 1 .PEEC 8EEC 20 51 A9 JSR R951 ;print character in A (OSASCI) 8EEF C8 INY ;loop until 12 characters of title printed 8EF0 C0 0C CPY #&0C 8EF2 D0 E8 BNE PEDC #if defined _PCH200 8EF4 20 D3 A8 JSR R8D3 ;print "(" 8EF7 EQUB &0D 8EF8 EQUS "(" 8EF9 EA NOP #else 8EF4 20 D3 A8 JSR R8D3 ;print " (" 8EF7 EQUB &0D 8EF8 EQUS " (" #endif 8EFA EA NOP 8EFB 20 16 BE JSR SE16 ;page in catalogue sector 1 8EFE AD 04 FD LDA &FD04 ;get BCD catalogue cycle number 8F01 20 78 A9 JSR R978 ;print hex byte 8F04 20 D3 A8 JSR R8D3 ;print ")" +newline 8F07 EQUS ")" 8F08 EQUB &0D 8F09 EA NOP 8F0A 60 RTS .PF0B 8F0B 20 0C BE JSR SE0C ;page in main workspace 8F0E 20 4C B7 JSR S74C ;[D]set Z=1 iff current drive is a RAM disc 8F11 F0 66 BEQ PF79 ;[D]if so then print "RAM Disk" 8F13 2C ED FD BIT &FDED ;else test density flag 8F16 70 09 BVS PF21 ;if double density print "Double density" 8F18 20 D3 A8 JSR R8D3 ;else print "Single density" 8F1B EQUS "Sing" 8F1F 90 08 BCC PF29 .PF21 8F21 20 D3 A8 JSR R8D3 8F24 EQUS "Doub" 8F28 EA NOP .PF29 8F29 20 D3 A8 JSR R8D3 8F2C EQUS "le density" 8F36 EA NOP #if defined _PCH200 8F37 A0 0F LDY #&0F ;set Y = 15 spaces for single density 8F39 2C ED FD BIT &FDED ;test density flag 8F3C 50 24 BVC PF62 ;if single density skip list of volumes 8F3E A0 06 LDY #&06 ;else Y = 6 spaces for double density #else 8F37 A0 0E LDY #&0E ;set Y = 14 spaces for single density 8F39 2C ED FD BIT &FDED ;test density flag 8F3C 50 24 BVC PF62 ;if single density skip list of volumes 8F3E A0 05 LDY #&05 ;else Y = 5 spaces for double density #endif 8F40 20 DD 8A JSR PADD ;print number of spaces in Y 8F43 A2 00 LDX #&00 ;set volume index = 0, start at volume A: .PF45 8F45 18 CLC ;clear carry for add 8F46 20 07 BE JSR SE07 ;page in auxiliary workspace 8F49 BD CD FD LDA &FDCD,X ;test if number of tracks in volume > 0 8F4C 08 PHP ;preserve result 8F4D 8A TXA ;copy index to A to make volume letter 8F4E 28 PLP ;restore result 8F4F D0 02 BNE PF53 ;if volume present print its letter 8F51 A9 ED LDA #&ED ;else A=&ED + &41 = &2E, ".": .PF53 8F53 69 41 ADC #&41 ;add ASCII value of "A" 8F55 20 51 A9 JSR R951 ;print character in A (OSASCI) 8F58 E8 INX ;point to next volume 8F59 E0 08 CPX #&08 ;have all 8 volumes been listed? 8F5B D0 E8 BNE PF45 ;if not then loop 8F5D 20 0C BE JSR SE0C ;page in main workspace 8F60 A0 01 LDY #&01 ;else Y=1 space separating volume list: .PF62 8F62 2C EA FD BIT &FDEA ;test double-stepping flag 8F65 10 0F BPL PF76 ;if set manually (*OPT 8,0/1) then end line 8F67 50 0D BVC PF76 ;if 1:1 stepping was detected then end line 8F69 20 DD 8A JSR PADD ;else print 1 or 14 spaces 8F6C 20 D3 A8 JSR R8D3 ;print "40in80" 8F6F EQUS "40in80" 8F75 EA NOP .PF76 8F76 4C 69 84 JMP P469 ;print newline .PF79 ;Print "RAM Disk" 8F79 20 17 A9 JSR R917 ;print VDU sequence immediate 8F7C EQUS "RAM Disk" 8F84 EQUB &FF 8F85 4C 69 84 JMP P469 ;print newline .PF88 ;Print volume spec and boot option 8F88 A0 0D LDY #&0D ;set Y = &0D print 13 spaces 8F8A A5 CF LDA &CF ;get current volume 8F8C 20 AD 8E JSR PEAD ;print " Drive " plus volume spec in A 8F8F 20 DD 8A JSR PADD ;print number of spaces in Y 8F92 20 16 BE JSR SE16 ;page in catalogue sector 1 8F95 20 D3 A8 JSR R8D3 ;print "Option " 8F98 EQUS "Option " 8F9F AD 06 FD LDA &FD06 ;get boot option/top bits volume size 8FA2 20 9E A9 JSR R99E ;shift A right 4 places 8FA5 20 80 A9 JSR R980 ;print hex nibble 8FA8 20 D3 A8 JSR R8D3 ;print " (" 8FAB EQUS " (" 8FAD AA TAX ;transfer to X for use as index 8FAE 20 F7 8F JSR PFF7 ;[D]print boot or Challenger config descriptor 8FB1 20 D3 A8 JSR R8D3 ;print ")"+newline 8FB4 EQUS ")" ;[BUG]prints Challenger config descriptor 8FB5 EQUB &0D ;or garbage if boot option exceeds 3 8FB6 EA NOP ;(i.e. if offset &0106 b7 or b6 set) 8FB7 60 RTS .PFB8 ;Print CSD and library directories #if defined _PCH200 8FB8 20 D3 A8 JSR R8D3 ;print "Directory :" 8FBB EQUS "Directory :" 8FC6 EA NOP #else 8FB8 20 D3 A8 JSR R8D3 ;print " Directory :" 8FBB EQUS " Directory :" #endif 8FC7 A0 06 LDY #&06 ;6 characters in next field 8FC9 20 0C BE JSR SE0C ;page in main workspace 8FCC A2 00 LDX #&00 ;[D]x = 0 point to default (CSD) directory 8FCE 20 E8 8F JSR PFE8 ;[D]print default or library directory 8FD1 20 DD 8A JSR PADD ;print number of spaces in Y 8FD4 20 D3 A8 JSR R8D3 ;print "Library :" 8FD7 EQUS "Library :" 8FE0 A2 02 LDX #&02 ;[D]x = 2 point to library directory 8FE2 20 E8 8F JSR PFE8 ;[D]print default or library directory 8FE5 4C 69 84 JMP P469 ;print newline .PFE8 ;Print default or library directory 8FE8 BD C7 FD LDA &FDC7,X ;get default or library volume 8FEB 20 A8 8E JSR PEA8 ;print volume spec in A (assuming DD) 8FEE 20 4F A9 JSR R94F ;print a dot 8FF1 BD C6 FD LDA &FDC6,X ;get default or library directory 8FF4 4C 51 A9 JMP R951 ;print character in A (OSASCI) .PFF7 ;Print boot or Challenger config descriptor 8FF7 BD 07 90 LDA &9007,X ;look up offset of message selected by X 8FFA AA TAX ;replace X with offset of message: .PFFB 8FFB BD 0E 90 LDA &900E,X ;get character of message 8FFE F0 06 BEQ Q006 ;if NUL terminator reached then exit 9000 20 51 A9 JSR R951 ;else print character in A (OSASCI) 9003 E8 INX ;increment offset 9004 10 F5 BPL PFFB ;and loop (always) .Q006 9006 60 RTS ;Table of offsets of boot descriptors 0..3 9007 EQUB &00,&04,&09,&0D ;Table of offsets of Challenger configuration descriptors 4..6 900B EQUB &12,&1B,&20 ;Table of boot option descriptors 0..3 900E EQUS "off" 9011 EQUB &00 9012 EQUS "LOAD" 9016 EQUB &00 9017 EQUS "RUN" 901A EQUB &00 901B EQUS "EXEC" 901F EQUB &00 ;Table of Challenger configuration descriptors 4..6 9020 EQUS "inactive" 9028 EQUB &00 9029 EQUS "256K" 902D EQUB &00 902E EQUS "512K" 9032 EQUB &00 .Q033 ;Print volume statistics 9033 A0 03 LDY #&03 ;y=3 print 2 spaces/ 1 space 9035 A5 CF LDA &CF ;get current volume 9037 20 AD 8E JSR PEAD ;print " Drive " plus volume spec in A 903A 20 DD 8A JSR PADD ;print number of spaces in Y 903D 20 D3 A8 JSR R8D3 9040 EQUS "Volume size " 904E EA NOP 904F 20 16 BE JSR SE16 ;page in catalogue sector 1 9052 AD 07 FD LDA &FD07 ;copy volume size to sector count 9055 85 A8 STA &A8 ;LSB 9057 AD 06 FD LDA &FD06 ;get boot option/top bits volume size 905A 29 03 AND #&03 ;mask top bits volume size 905C 85 A9 STA &A9 ;store MSB 905E 20 80 B3 JSR S380 ;print sector count as kilobytes 9061 20 69 84 JSR P469 ;print newline #if defined _PCH200 9064 A0 0A LDY #&0A ;set Y = &0A print 10 spaces #else 9064 A0 0B LDY #&0B ;set Y = &0B print 11 spaces #endif 9066 20 DD 8A JSR PADD ;print number of spaces in Y 9069 20 D3 A8 JSR R8D3 ;print "Volume unused" 906C EQUS "Volume unused " 907A EA NOP 907B 20 16 BE JSR SE16 ;[D]calculate used space on volume 907E AC 05 FD LDY &FD05 ;get number of files in catalogue * 8 9081 A9 00 LDA #&00 9083 85 CB STA &CB ;clear MSB number of used sectors on volume 9085 20 F8 A4 JSR R4F8 ;return no. reserved sectors in data area 9088 85 CA STA &CA ;set LSB number of used sectors on volume .Q08A 908A 20 B2 A9 JSR R9B2 ;subtract 8 from Y 908D C0 F8 CPY #&F8 ;if Y=&F8 then was 0, first (last) file done 908F F0 09 BEQ Q09A ;[D]if all files added then continue, else: 9091 20 14 A7 JSR R714 ;calculate number of sectors used by file 9094 20 33 A7 JSR R733 ;add number of sectors to total 9097 4C 8A 90 JMP Q08A ;loop for next file ;[BUG] can exceed vol size due to overlaps .Q09A 909A 20 16 BE JSR SE16 ;page in catalogue sector 1 909D 38 SEC ;c=1 for subtract 909E AD 07 FD LDA &FD07 ;get LSB volume size from catalogue 90A1 E5 CA SBC &CA ;subtract LSB used space 90A3 85 A8 STA &A8 ;store LSB result in zero page 90A5 AD 06 FD LDA &FD06 ;get boot option/top bits volume size 90A8 29 03 AND #&03 ;extract MSB volume size 90AA E5 CB SBC &CB ;subtract MSB used space, store in zp 90AC 85 A9 STA &A9 ;[BUG] can underflow due to overlaps 90AE 20 80 B3 JSR S380 ;print sector count as kilobytes 90B1 4C 69 84 JMP P469 ;print newline ;Challenger command table 90B4 EQUS "ACCESS" 90BA EQUW &93,&6E 90BC EQUB &32 ;syntax &2,&3: (L) 90BD EQUS "BACKUP" 90C3 EQUW &85,&69 90C5 EQUB &54 ;syntax &4,&5: 90C6 EQUS "COMPACT" 90CD EQUW &A6,&36 90CF EQUB &0A ;syntax &A: () 90D0 EQUS "CONFIG" 90D6 EQUW &AA,&F6 90D8 EQUB &0A ;syntax &A: () 90D9 EQUS "COPY" 90DD EQUW &86,&65 90DF EQUB &64 ;syntax &4,&6: 90E0 EQUS "DELETE" 90E6 EQUW &92,&74 90E8 EQUB &01 ;syntax &1: 90E9 EQUS "DESTROY" 90F0 EQUW &92,&83 90F2 EQUB &02 ;syntax &2: 90F3 EQUS "DIR" 90F6 EQUW &93,&13 90F8 EQUB &09 ;syntax &9: () 90F9 EQUS "DRIVE" 90FE EQUW &93,&0A 9100 EQUB &0A ;syntax &A: () 9101 EQUS "ENABLE" 9107 EQUW &95,&5C 9109 EQUB &00 ;syntax &0: no arguments #if defined _EX 910A EQUS "EX" 910C EQUW &8B,&FF 910E EQUB &09 ;syntax &9: () 910F EQUS "FDCSTAT" 9116 EQUW &B7,&6C 9118 EQUB &80 ;syntax &0: no arguments b7=1 9119 EQUS "INFO" 911D EQUW &8C,&1C 911F EQUB &02 ;syntax &2: 9120 EQUS "LIB" 9123 EQUW &93,&16 9125 EQUB &09 ;syntax &9: () 9126 EQUS "MAP" 9129 EQUW &8B,&54 912B EQUB &0A ;syntax &A: () 912C EQUS "RENAME" 9132 EQUW &95,&C6 9134 EQUB &78 ;syntax &8,&7: 9135 EQUS "STAT" 9139 EQUW &8D,&66 913B EQUB &0A ;syntax &A: () 913C EQUS "TITLE" 9141 EQUW &93,&39 9143 EQUB &0B ;syntax &B: 9144 EQUS "WIPE" 9148 EQUW &92,&3F 914A EQUB &02 ;syntax &2: <afsp> # if defined _MASTER 914B EQUW &98,&25 ;unrecognised command, *RUN it &9825 # else 914B EQUW &98,&23 ;unrecognised command, *RUN it &9823 # endif ;Utility command table 914D EQUS "BUILD" 9152 EQUW &84,&15 9154 EQUB &01 ;syntax &1: <fsp> 9155 EQUS "DISC" 9159 EQUW &82,&0E 915B EQUB &00 ;syntax &0: no arguments 915C EQUS "DUMP" 9160 EQUW &83,&A4 9162 EQUB &01 ;syntax &1: <fsp> 9163 EQUS "FORMAT" 9169 EQUW &AE,&88 916B EQUB &8A ;syntax &A: (<drv>) b7=1 916C EQUS "LIST" 9170 EQUW &83,&62 9172 EQUB &01 ;syntax &1: <fsp> 9173 EQUS "TYPE" 9177 EQUW &83,&5B 9179 EQUB &01 ;syntax &1: <fsp> 917A EQUS "VERIFY" 9180 EQUW &B0,&7E 9182 EQUB &8A ;syntax &A: (<drv>) b7=1 9183 EQUS "VOLGEN" 9189 EQUW &B1,&40 918B EQUB &8A ;syntax &A: (<drv>) b7=1 ;entry not printed in *HELP UTILS 918C EQUS "DISK" 9190 EQUW &82,&0E 9192 EQUB &00 ;syntax &0: no arguments 9193 EQUW &91,&A7 ;unrecognised utility, return &91A7 ;*HELP keyword table 9195 EQUS "DFS" 9198 EQUW &A5,&2E 919A EQUB &00 919B EQUS "UTILS" 91A0 EQUW &A5,&26 91A2 EQUB &00 91A3 EQUW &91,&A7 ;unrecognised keyword, return &91A7 #else /* _EX */ 910A EQUS "FDCSTAT" # if defined _BUGFIX 9111 EQUW &B7,&6C # else 9111 EQUW &B7,&66 # endif 9113 EQUB &80 ;syntax &0: no arguments b7=1 9114 EQUS "INFO" 9118 EQUW &8C,&1C 911A EQUB &02 ;syntax &2: <afsp> 911B EQUS "LIB" 911E EQUW &93,&16 9120 EQUB &09 ;syntax &9: (<dir>) 9121 EQUS "MAP" 9124 EQUW &8B,&54 9126 EQUB &0A ;syntax &A: (<drv>) 9127 EQUS "RENAME" 912D EQUW &95,&C6 912F EQUB &78 ;syntax &8,&7: <old fsp> <new fsp> 9130 EQUS "STAT" 9134 EQUW &8D,&66 9136 EQUB &0A ;syntax &A: (<drv>) 9137 EQUS "TITLE" 913C EQUW &93,&39 913E EQUB &0B ;syntax &B: <title> 913F EQUS "WIPE" 9143 EQUW &92,&3F 9145 EQUB &02 ;syntax &2: <afsp> # if defined _MASTER 9146 EQUW &98,&25 ;unrecognised command, *RUN it &9825 # else 9146 EQUW &98,&23 ;unrecognised command, *RUN it &9823 # endif ;Utility command table 9148 EQUS "BUILD" 914D EQUW &84,&15 914F EQUB &01 ;syntax &1: <fsp> 9150 EQUS "DISC" 9154 EQUW &82,&0E 9156 EQUB &00 ;syntax &0: no arguments 9157 EQUS "DUMP" 915B EQUW &83,&A4 915D EQUB &01 ;syntax &1: <fsp> 915E EQUS "FORMAT" 9164 EQUW &AE,&88 9166 EQUB &8A ;syntax &A: (<drv>) b7=1 9167 EQUS "LIST" 916B EQUW &83,&62 916D EQUB &01 ;syntax &1: <fsp> 916E EQUS "TYPE" 9172 EQUW &83,&5B 9174 EQUB &01 ;syntax &1: <fsp> 9175 EQUS "VERIFY" 917B EQUW &B0,&7E 917D EQUB &8A ;syntax &A: (<drv>) b7=1 917E EQUS "VOLGEN" 9184 EQUW &B1,&40 9186 EQUB &8A ;syntax &A: (<drv>) b7=1 ;entry not printed in *HELP UTILS 9187 EQUS "DISK" 918B EQUW &82,&0E 918D EQUB &00 ;syntax &0: no arguments 918E EQUW &91,&A7 ;unrecognised utility, return &91A7 ;*HELP keyword table 9190 EQUS "CHAL" 9194 EQUW &A5,&2E 9196 EQUB &00 9197 EQUS "DFS" 919A EQUW &A5,&2E 919C EQUB &00 919D EQUS "UTILS" 91A2 EQUW &A5,&26 91A4 EQUB &00 91A5 EQUW &91,&A7 ;unrecognised keyword, return &91A7 #endif /* _EX */ ;Return from unrecognised keyword 91A7 60 RTS ;on entry A=string offset (=Y to GSINIT) ;XY=address of table .Q1A8 ;Search for command or keyword in table 91A8 20 1E 92 JSR Q21E ;set up trampoline to read table at XY 91AB A8 TAY 91AC 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 91AF 98 TYA ;save offset of start of command line 91B0 48 PHA 91B1 B1 F2 LDA (&F2),Y ;[D]get first character of command 91B3 29 5F AND #&5F ;make uppercase 91B5 C9 43 CMP #&43 ;is it C? 91B7 D0 0B BNE Q1C4 ;if not then search in table 91B9 C8 INY ;else skip to next character 91BA B1 F2 LDA (&F2),Y ;fetch it 91BC C9 20 CMP #&20 ;is it a space? 91BE D0 04 BNE Q1C4 ;if not then search in table 91C0 68 PLA ;else discard offset of start of command line 91C1 C8 INY ;skip past the space 91C2 98 TYA ;save new offset of start of command: 91C3 48 PHA ;accept *C <command> as alias of *<command>. .Q1C4 91C4 68 PLA ;restore offset of start of command line 91C5 A8 TAY 91C6 48 PHA 91C7 A2 00 LDX #&00 ;start at current trampoline address 91C9 20 AA 00 JSR &00AA ;fetch first byte 91CC 38 SEC ;if terminator,empty keyword matches anything 91CD 30 3B BMI Q20A ;so jump to following action address with C=1 91CF CA DEX ;else decrement X and Y to stay in place: 91D0 88 DEY .Q1D1 91D1 E8 INX ;advance command line and table offsets 91D2 C8 INY 91D3 20 AA 00 JSR &00AA ;get byte from table 91D6 30 22 BMI Q1FA ;if terminator, check command also terminates 91D8 51 F2 EOR (&F2),Y ;else compare with character of command 91DA 29 5F AND #&5F ;make comparison case-insensitive 91DC F0 F3 BEQ Q1D1 ;if equal then compare next characters 91DE B1 F2 LDA (&F2),Y ;else get mismatching character of command 91E0 C9 2E CMP #&2E ;is it a dot? 91E2 08 PHP ;save the result .Q1E3 91E3 E8 INX ;scan keyword in table 91E4 20 AA 00 JSR &00AA 91E7 10 FA BPL Q1E3 ;loop until terminator reached 91E9 E8 INX ;skip action address, 2 bytes 91EA E8 INX 91EB 28 PLP ;is the command an abbreviation or a mismatch? 91EC D0 05 BNE Q1F3 ;if mismatch then skip syntax, scan next kywd 91EE 20 AA 00 JSR &00AA ;else test syntax byte 91F1 10 13 BPL Q206 ;if b7=0 accept cmd, else abbrev. not allowed: .Q1F3 91F3 E8 INX ;skip syntax byte 91F4 20 2D 92 JSR Q22D ;add X to trampoline address 91F7 4C C4 91 JMP Q1C4 ;scan next keyword .Q1FA 91FA B1 F2 LDA (&F2),Y ;get character of command 91FC 20 D1 A9 JSR R9D1 ;set C=0 iff character in A is a letter 91FF B0 08 BCS Q209 ;if C=1 accept command, else longer than kywd 9201 E8 INX ;so skip action address, 2 bytes 9202 E8 INX 9203 4C F3 91 JMP Q1F3 ;skip syntax byte and scan next keyword .Q206 ;Accept abbreviated command 9206 CA DEX ;backtrack to action address, 2 bytes 9207 CA DEX 9208 C8 INY ;advance command line offset past the dot: .Q209 ;Accept command 9209 18 CLC ;set C=0 command valid .Q20A 920A 68 PLA ;discard offset to start of command 920B 20 AA 00 JSR &00AA ;get action address high byte 920E 85 A9 STA &A9 ;store high byte of vector 9210 E8 INX ;advance to next byte of table 9211 20 AA 00 JSR &00AA ;get action address low byte 9214 85 A8 STA &A8 ;store low byte of vector 9216 E8 INX ;return X=offset of syntax byte 9217 60 RTS ;y=offset of command line tail. ;unreachable code 9218 48 PHA ;set up trampoline to write table at XY 9219 A9 9D LDA #&9D 921B 4C 21 92 JMP Q221 .Q21E ;Set up trampoline to read table at XY 921E 48 PHA 921F A9 BD LDA #&BD ;&BD = LDA abs,X .Q221 9221 85 AA STA &AA ;instruction at &00AA = LDA xy,X 9223 86 AB STX &AB 9225 84 AC STY &AC 9227 A9 60 LDA #&60 ;instruction at &00AD = RTS 9229 85 AD STA &AD 922B 68 PLA ;restore A 922C 60 RTS .Q22D ;Add X to trampoline address 922D 18 CLC 922E 8A TXA 922F 65 AB ADC &AB ;add X to low byte of LDA,X address 9231 85 AB STA &AB 9233 90 02 BCC Q237 ;carry out to high byte 9235 E6 AC INC &AC .Q237 9237 60 RTS .Q238 ;Set GSINIT pointer to XY, set Y=0 9238 86 F2 STX &F2 923A 84 F3 STY &F3 923C A0 00 LDY #&00 923E 60 RTS ;*WIPE 923F 20 DD 92 JSR Q2DD ;ensure file matching wildcard argument .Q242 9242 20 A3 8A JSR PAA3 ;print filename from catalogue 9245 20 D3 A8 JSR R8D3 9248 EQUS " : " 924B EA NOP 924C 20 11 BE JSR SE11 ;page in catalogue sector 0 924F B9 0F FD LDA &FD0F,Y ;test lock bit 9252 10 06 BPL Q25A ;if unlocked then ask to delete 9254 20 4B A9 JSR R94B ;else deletion not allowed, print letter N 9257 4C 6B 92 JMP Q26B ;find next matching file .Q25A 925A 20 DE 84 JSR P4DE ;ask user yes or no 925D D0 0C BNE Q26B ;if user replies no then find next match 925F 20 7E 8A JSR PA7E ;else ensure disc not changed 9262 20 78 8C JSR PC78 ;delete catalogue entry 9265 20 0B 96 JSR Q60B ;write volume catalogue 9268 20 00 93 JSR Q300 ;shift cat pointer to follow shifted files .Q26B 926B 20 69 84 JSR P469 ;print newline 926E 20 35 8C JSR PC35 ;find next matching file 9271 B0 CF BCS Q242 ;if found then wipe the file 9273 60 RTS ;else exit ;*DELETE 9274 20 32 8B JSR PB32 ;disallow wildcard characters in filename 9277 20 E0 92 JSR Q2E0 ;ensure file matching argument 927A 20 9D 8C JSR PC9D ;print *INFO line if verbose 927D 20 78 8C JSR PC78 ;delete catalogue entry 9280 4C 0B 96 JMP Q60B ;write volume catalogue ;Note: *DESTROY deletes all matching files, locked or unlocked. ;*DESTROY 9283 20 5F A7 JSR R75F ;ensure *ENABLE active 9286 20 DD 92 JSR Q2DD ;ensure file matching wildcard argument .Q289 9289 20 A3 8A JSR PAA3 ;print filename from catalogue 928C 20 69 84 JSR P469 ;print newline 928F 20 35 8C JSR PC35 ;find next matching file 9292 B0 F5 BCS Q289 ;loop until all matching files listed 9294 20 D3 A8 JSR R8D3 9297 EQUB &0D 9298 EQUS "Delete (Y/N) ? " 92A7 EA NOP 92A8 20 DE 84 JSR P4DE ;ask user yes or no 92AB F0 03 BEQ Q2B0 ;if user replies yes then proceed 92AD 4C 69 84 JMP P469 ;else print newline and exit .Q2B0 92B0 20 7E 8A JSR PA7E ;ensure disc not changed 92B3 20 2E 8C JSR PC2E ;search for file in catalogue .Q2B6 92B6 20 11 BE JSR SE11 ;page in catalogue sector 0 92B9 B9 0F FD LDA &FD0F,Y ;unlock catalogue entry! 92BC 29 7F AND #&7F 92BE 99 0F FD STA &FD0F,Y 92C1 20 78 8C JSR PC78 ;delete catalogue entry 92C4 20 00 93 JSR Q300 ;subtract 8 from catalogue pointer 92C7 20 35 8C JSR PC35 ;find next matching file 92CA B0 EA BCS Q2B6 92CC 20 0B 96 JSR Q60B ;write volume catalogue 92CF 20 D3 A8 JSR R8D3 ;print "Deleted" and exit 92D2 EQUB &0D 92D3 EQUS "Deleted" 92DA EQUB &0D 92DB EA NOP 92DC 60 RTS .Q2DD ;Ensure file matching wildcard argument 92DD 20 2E 8B JSR PB2E ;allow wildcard characters in filename .Q2E0 ;Ensure file matching argument 92E0 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg 92E3 4C 38 8B JMP PB38 ;ensure file matching spec in catalogue .Q2E6 ;Set current file from argument 92E6 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg 92E9 4C DC 89 JMP P9DC ;set current file from file spec .Q2EC ;Pack b17,16 of length into catalogue entry 92EC 20 A4 A9 JSR R9A4 ;shift A left 4 places 92EF 20 16 BE JSR SE16 ;page in catalogue sector 1 92F2 5D 0E FD EOR &FD0E,X ;replace b5,b4 of top bits with b5,b4 from A 92F5 29 30 AND #&30 92F7 5D 0E FD EOR &FD0E,X 92FA 9D 0E FD STA &FD0E,X ;store top bits back in catalogue 92FD 4C 0C BE JMP SE0C ;page in main workspace .Q300 ;Subtract 8 from catalogue pointer 9300 AC C2 FD LDY &FDC2 ;get catalogue pointer 9303 20 B2 A9 JSR R9B2 ;subtract 8 from Y 9306 8C C2 FD STY &FDC2 ;store catalogue pointer 9309 60 RTS ;*DRIVE #if defined _BUGFIX 930A 20 0E AA JSR RA0E ;parse volume spec from argument #else 930A 20 16 AA JSR RA16 ;parse volume spec from argument #endif 930D A5 CF LDA &CF ;get current volume 930F 8D C7 FD STA &FDC7 ;set as default volume 9312 60 RTS ;*DIR 9313 A2 00 LDX #&00 9315 AD A2 02 LDA &02A2 ;*LIB 903A=LDX #&02 9318 BD C6 FD LDA &FDC6,X ;get default/library directory 931B 85 CE STA &CE ;set as current directory 931D BD C7 FD LDA &FDC7,X ;get default/library volume 9320 85 CF STA &CF ;set as current volume 9322 8A TXA ;save offset 9323 48 PHA 9324 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 9327 F0 03 BEQ Q32C 9329 20 3E AA JSR RA3E ;parse directory spec .Q32C 932C 68 PLA ;restore offset 932D AA TAX 932E A5 CE LDA &CE ;get current directory 9330 9D C6 FD STA &FDC6,X ;set as default/library directory 9333 A5 CF LDA &CF ;get current volume 9335 9D C7 FD STA &FDC7,X ;set as default/library volume 9338 60 RTS ;*TITLE 9339 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg #if defined _BUGFIX 933C 20 15 AA JSR RA15 ;set current vol/dir = default, set up drive #else 933C 20 1E AA JSR RA1E ;set current vol/dir = default, set up drive #endif 933F 20 2F 96 JSR Q62F ;load volume catalogue L4 9342 A2 0B LDX #&0B ;first offset to store = 11 9344 A9 00 LDA #&00 ;set title to 12 NULs: .Q346 9346 20 5C 93 JSR Q35C ;store character of title 9349 CA DEX ;loop until 12 characters stored 934A 10 FA BPL Q346 ;finish with X=&FF .Q34C 934C 20 C5 FF JSR &FFC5 ;call GSREAD 934F B0 08 BCS Q359 ;if end of argument write catalogue 9351 E8 INX ;[D]else point X to next character 9352 20 5C 93 JSR Q35C ;store character of title 9355 E0 0B CPX #&0B ;is this the twelfth character written? 9357 D0 F3 BNE Q34C ;if not then loop to write more, else: .Q359 9359 4C 0B 96 JMP Q60B ;write volume catalogue and exit .Q35C ;Store character of title 935C E0 08 CPX #&08 ;if offset is 8 or more 935E 90 07 BCC Q367 9360 20 16 BE JSR SE16 ;page in catalogue sector 1 9363 9D F8 FC STA &FCF8,X ;then store at &0F00..3, X=8..11 9366 60 RTS .Q367 9367 20 11 BE JSR SE11 ;page in catalogue sector 0 936A 9D 00 FD STA &FD00,X ;else store at &0E00..7, X=0..7 936D 60 RTS ;*ACCESS 936E 20 2E 8B JSR PB2E ;allow wildcard characters in filename 9371 20 E6 92 JSR Q2E6 ;set current file from argument 9374 A2 00 LDX #&00 ;preset X=&00 file unlocked 9376 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 9379 D0 21 BNE Q39C ;if argument is empty .Q37B 937B 86 AA STX &AA ;then attribute mask = &00, file unlocked 937D 20 41 8B JSR PB41 ;ensure matching file in catalogue .Q380 9380 20 AB A2 JSR R2AB ;ensure file not open (mutex) 9383 20 11 BE JSR SE11 ;page in catalogue sector 0 9386 B9 0F FD LDA &FD0F,Y ;get directory character from catalogue 9389 29 7F AND #&7F ;mask off old attribute 938B 05 AA ORA &AA ;apply new attribute 938D 99 0F FD STA &FD0F,Y ;put back in catalogue 9390 20 9D 8C JSR PC9D ;print *INFO line if verbose 9393 20 35 8C JSR PC35 ;find next matching file 9396 B0 E8 BCS Q380 ;if found then set its attribute 9398 90 BF BCC Q359 ;else write volume catalogue and exit .Q39A 939A A2 80 LDX #&80 ;found L, set bit 7 to indicate file locked: .Q39C 939C 20 C5 FF JSR &FFC5 ;call GSREAD, get character of attribute 939F B0 DA BCS Q37B ;if end of string then set attribute 93A1 C9 4C CMP #&4C ;else is character capital L? 93A3 F0 F5 BEQ Q39A ;if so then set bit 7 93A5 20 9C A8 JSR R89C ;else raise "Bad attribute" error. 93A8 EQUB &CF 93A9 EQUS "attribute" 93B2 EQUB &00 .Q3B3 ;Create file from OSFILE block 93B3 20 E2 89 JSR P9E2 ;set current file from argument pointer 93B6 20 2E 8C JSR PC2E ;search for file in catalogue 93B9 90 03 BCC Q3BE ;if found 93BB 20 78 8C JSR PC78 ;then delete catalogue entry .Q3BE 93BE A5 C2 LDA &C2 ;save start address low word 93C0 48 PHA 93C1 A5 C3 LDA &C3 93C3 48 PHA 93C4 38 SEC ;subtract end address - start address 93C5 A5 C4 LDA &C4 ;(24 bits) yielding file length 93C7 E5 C2 SBC &C2 93C9 85 C2 STA &C2 93CB A5 C5 LDA &C5 93CD E5 C3 SBC &C3 93CF 85 C3 STA &C3 93D1 AD BB FD LDA &FDBB 93D4 ED B9 FD SBC &FDB9 93D7 85 C6 STA &C6 93D9 20 0B 94 JSR Q40B ;create catalogue entry 93DC AD BA FD LDA &FDBA ;copy start address high word to data pointer 93DF 8D B6 FD STA &FDB6 93E2 AD B9 FD LDA &FDB9 93E5 8D B5 FD STA &FDB5 93E8 68 PLA ;restore low word to data pointer 93E9 85 BF STA &BF 93EB 68 PLA 93EC 85 BE STA &BE 93EE 60 RTS .Q3EF ;Raise "Disk full" error 93EF 20 92 A8 JSR R892 93F2 EQUB &C6 ;number = &C6, "Disk full", cf. &9EDF 93F3 EQUS "full" 93F7 EQUB &00 .Q3F8 ;Raise "Catalogue full" error 93F8 20 AD A8 JSR R8AD 93FB EQUB &BE 93FC EQUS "Catalogue full" 940A EQUB &00 .Q40B ;Create catalogue entry 940B A9 00 LDA #&00 940D 85 C4 STA &C4 ;set MSB of LBA = 0 940F 20 F8 A4 JSR R4F8 ;return no. reserved sectors in data area 9412 85 C5 STA &C5 ;set as LSB of LBA 9414 20 16 BE JSR SE16 ;page in catalogue sector 1 9417 AC 05 FD LDY &FD05 ;get number of files in catalogue * 8 941A C0 F8 CPY #&F8 ;if there are already 31 files 941C B0 DA BCS Q3F8 ;then raise "Catalogue full" error 941E 90 5F BCC Q47F ;else jump into loop .Q420 9420 24 A8 BIT &A8 ;if b6=0 will not accept shorter allocation 9422 50 CB BVC Q3EF ;then raise "Disk full" error 9424 A9 00 LDA #&00 9426 85 C3 STA &C3 ;else zero LSB size of file to be fitted 9428 85 C6 STA &C6 ;and MSB 942A 85 C4 STA &C4 ;set MSB of LBA = 0 942C 20 F8 A4 JSR R4F8 ;return no. reserved sectors in data area 942F 85 C5 STA &C5 ;set as LSB of LBA 9431 20 16 BE JSR SE16 ;page in catalogue sector 1 9434 AC 05 FD LDY &FD05 ;get number of files in catalogue * 8 9437 4C 43 94 JMP Q443 ;jump into loop .Q43A 943A 98 TYA 943B F0 23 BEQ Q460 ;if cat ptr = 0 then test fit 943D 20 B2 A9 JSR R9B2 ;else subtract 8 from Y 9440 20 D6 94 JSR Q4D6 ;[D]calculate LBA of end of file .Q443 9443 20 07 95 JSR Q507 ;calculate slack space after file 9446 F0 F2 BEQ Q43A ;if no slack space then test prev cat entry 9448 38 SEC ;else C=1 for subtraction 9449 20 21 95 JSR Q521 ;test if new file will fit after current file 944C 90 EC BCC Q43A ;if file won't fit then test prev cat entry 944E 86 C6 STX &C6 ;else set MSB file size to MSB slack space 9450 A5 B0 LDA &B0 ;get LSB slack space 9452 85 C3 STA &C3 ;set LSB file size 9454 A5 C4 LDA &C4 ;this finds the largest slack space on volume 9456 85 B1 STA &B1 ;save LSB LBA of slack space 9458 A5 C5 LDA &C5 945A 85 B2 STA &B2 ;save MSB LBA of slack space 945C 84 C2 STY &C2 ;save catalogue offset of insertion point 945E B0 DA BCS Q43A ;and loop (always) .Q460 9460 A5 C3 LDA &C3 ;test slack space found 9462 05 C6 ORA &C6 ;if no slack space available 9464 F0 89 BEQ Q3EF ;then raise "Disk full" error 9466 A5 B1 LDA &B1 ;else get MSB LBA of slack space 9468 85 C4 STA &C4 ;set MSB start LBA of file 946A A5 B2 LDA &B2 ;get LSB LBA of slack space 946C 85 C5 STA &C5 ;set LSB start LBA of file 946E A4 C2 LDY &C2 ;restore catalogue offset of insertion point 9470 A9 00 LDA #&00 9472 85 C2 STA &C2 ;clear LSB length?? (probably redundant) 9474 F0 13 BEQ Q489 ;and branch (always) .Q476 9476 98 TYA 9477 F0 A7 BEQ Q420 ;if cat ptr = 0 then test fit 9479 20 B2 A9 JSR R9B2 ;else subtract 8 from Y 947C 20 D6 94 JSR Q4D6 ;calculate LBA of end of file .Q47F 947F 20 07 95 JSR Q507 ;calculate slack space after file 9482 F0 F2 BEQ Q476 ;if no slack space then test prev cat entry 9484 20 1D 95 JSR Q51D ;test if new file will fit after current file 9487 90 ED BCC Q476 ;if file won't fit then test prev cat entry .Q489 9489 84 B0 STY &B0 ;else insert new catalogue entry here 948B 20 16 BE JSR SE16 ;page in catalogue sector 1 948E AC 05 FD LDY &FD05 ;point Y to last valid catalogue entry: .Q491 9491 C4 B0 CPY &B0 ;compare pointer with insertion point 9493 F0 15 BEQ Q4AA ;stop copying if insertion point reached 9495 20 11 BE JSR SE11 ;page in catalogue sector 0 9498 B9 07 FD LDA &FD07,Y ;else copy current catalogue entry 949B 99 0F FD STA &FD0F,Y ;to next slot 949E 20 16 BE JSR SE16 ;page in catalogue sector 1 94A1 B9 07 FD LDA &FD07,Y ;leaving one slot open 94A4 99 0F FD STA &FD0F,Y ;for new catalogue entry 94A7 88 DEY ;decrease pointer to work back from end 94A8 B0 E7 BCS Q491 ;and loop (always) .Q4AA 94AA 20 0C BE JSR SE0C ;page in main workspace 94AD 20 3A 95 JSR Q53A ;compose top bits exec/length/load/start 94B0 20 29 95 JSR Q529 ;write filename+dir into catalogue at Y=0..&F0 94B3 20 16 BE JSR SE16 ;page in catalogue sector 1 .Q4B6 ;Write load/exec/length/start into catalogue 94B6 B5 BD LDA &BD,X ;x=8..1 copy from &BE..&C5 94B8 88 DEY ;y=catalogue pointer + 7..0 94B9 99 08 FD STA &FD08,Y ;copy to catalogue address fields 94BC CA DEX ;loop until 8 bytes copied 94BD D0 F7 BNE Q4B6 94BF 20 9D 8C JSR PC9D ;print *INFO line if verbose 94C2 98 TYA ;save catalogue pointer 94C3 48 PHA 94C4 20 16 BE JSR SE16 94C7 AC 05 FD LDY &FD05 ;get number of files in catalogue * 8 94CA 20 A9 A9 JSR R9A9 ;add 8 to Y 94CD 8C 05 FD STY &FD05 ;store new file count 94D0 20 0B 96 JSR Q60B ;write volume catalogue 94D3 68 PLA ;restore catalogue pointer 94D4 A8 TAY 94D5 60 RTS .Q4D6 ;Calculate LBA of end of file 94D6 20 EB 94 JSR Q4EB ;calculate number of sectors used by file 94D9 18 CLC 94DA B9 0F FD LDA &FD0F,Y ;get LSB start sector 94DD 65 C5 ADC &C5 ;add LSB file length in sectors 94DF 85 C5 STA &C5 ;replace with new LSB start sector 94E1 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector 94E4 29 03 AND #&03 ;extract MSB start sector 94E6 65 C4 ADC &C4 ;add MSB file length in sectors 94E8 85 C4 STA &C4 ;replace with new MSB start sector 94EA 60 RTS ;Challenger version of routine; DDOS version is at R714. ;Returns to &C5, &C4 and leaves catalogue paged in (vs. &C6, &C7 and main). .Q4EB ;Calculate number of sectors used by file 94EB 20 16 BE JSR SE16 ;page in catalogue sector 1 94EE B9 0C FD LDA &FD0C,Y ;get LSB length 94F1 C9 01 CMP #&01 ;c=1 iff LSB >0 94F3 B9 0D FD LDA &FD0D,Y ;add C to 2MSB length, rounding up 94F6 69 00 ADC #&00 ;(Y points to 8 bytes before file entry) 94F8 85 C5 STA &C5 ;[D]next two instructions swapped vs DDOS 94FA 08 PHP ;save carry flag from addition 94FB B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector 94FE 20 96 A9 JSR R996 ;extract length from b5,4 to b1,0 9501 28 PLP ;restore carry flag 9502 69 00 ADC #&00 ;add C to MSB length, rounding up 9504 85 C4 STA &C4 ;store length in sectors in zero page 9506 60 RTS .Q507 ;Calculate slack space after file 9507 20 16 BE JSR SE16 ;page in catalogue sector 1 950A 38 SEC 950B B9 07 FD LDA &FD07,Y ;get LSB LBA of preceding file in catalogue 950E E5 C5 SBC &C5 ;subtract LSB LBA of end of this file 9510 85 B0 STA &B0 ;store LSB size of slack space 9512 B9 06 FD LDA &FD06,Y ;get top bits exec/length/load/start sector 9515 29 03 AND #&03 ;extract MSB start sector 9517 E5 C4 SBC &C4 ;subtract MSB LBA of end of this file 9519 AA TAX ;return MSB slack size in X, LSB in &B0 951A 05 B0 ORA &B0 ;test result, Z=1 if file follows without gap 951C 60 RTS ;[BUG] can underflow due to overlaps .Q51D ;Test if new file will fit after current file 951D A9 00 LDA #&00 ;if file includes partial sector 951F C5 C2 CMP &C2 ;then C=1 include it in the comparison: .Q521 ;Test if new file will fit after current file 9521 A5 B0 LDA &B0 ;get LSB slack space 9523 E5 C3 SBC &C3 ;subtract LSB file size in sectors 9525 8A TXA ;a=MSB slack space 9526 E5 C6 SBC &C6 ;subtract MSB file size in sectors 9528 60 RTS ;return C=1 if file will fit .Q529 ;Write filename+dir into catalogue at Y=0..&F0 9529 20 11 BE JSR SE11 ;page in catalogue sector 0 952C A2 00 LDX #&00 .Q52E 952E B5 C7 LDA &C7,X ;get character of current filename+dir 9530 99 08 FD STA &FD08,Y ;store in catalogue 9533 C8 INY ;increment both offsets 9534 E8 INX 9535 E0 08 CPX #&08 ;loop until 8 bytes copied. 9537 D0 F5 BNE Q52E 9539 60 RTS .Q53A ;Compose top bits exec/length/load/start 953A AD B7 FD LDA &FDB7 ;get b17,b16 exec address 953D 29 03 AND #&03 ;place in b1,b0 of A, clear b7..b2 953F 0A ASL A ;shift A left 2 places 9540 0A ASL A ;a = ....ee.. 9541 45 C6 EOR &C6 ;place b17,b16 of length in b1,b0 9543 29 FC AND #&FC ;keep b7..b2 of A 9545 45 C6 EOR &C6 ;a = ....eell 9547 0A ASL A ;shift A left 2 places 9548 0A ASL A ;a = ..eell.. 9549 4D B5 FD EOR &FDB5 ;place b17,b16 of load address in b1,b0 954C 29 FC AND #&FC ;keep b7..b2 of A 954E 4D B5 FD EOR &FDB5 ;a = ..eelldd 9551 0A ASL A ;shift A left 2 places 9552 0A ASL A ;a = eelldd.. 9553 45 C4 EOR &C4 ;place b10,b9 of start LBA in b1,b0 9555 29 FC AND #&FC ;keep b7..b2 of A 9557 45 C4 EOR &C4 ;a = eellddss 9559 85 C4 STA &C4 ;set top bits exec/length/load/start sector 955B 60 RTS ;*ENABLE 955C 20 F2 A9 JSR R9F2 ;[D]call GSINIT with C=0 955F F0 1C BEQ Q57D ;if no argument then enable *commands 9561 A2 00 LDX #&00 ;else X=0 offset into "CAT" string: .Q563 9563 20 C5 FF JSR &FFC5 ;call GSREAD 9566 B0 1F BCS Q587 ;if end of argument then "Bad command" 9568 DD 8A 95 CMP &958A,X ;else compare char with char of "CAT" 956B D0 1A BNE Q587 ;if unequal then "Bad command" 956D E8 INX ;else increment offset 956E E0 03 CPX #&03 ;loop until whole "CAT" string compared 9570 D0 F1 BNE Q563 9572 20 C5 FF JSR &FFC5 ;call GSREAD 9575 90 10 BCC Q587 ;if argument continues then "Bad command" 9577 A9 80 LDA #&80 ;else *ENABLE CAT 9579 8D F4 FD STA &FDF4 ;b7=1 emulate Acorn DFS's main memory use 957C 60 RTS .Q57D ;*ENABLE (no argument) 957D A9 80 LDA #&80 957F 85 B9 STA &B9 ;>0 disc operation is interruptible 9581 A9 01 LDA #&01 ;set *ENABLE flag = 1; will be nonnegative 9583 8D DF FD STA &FDDF ;(after FSC 8) for next *command only. 9586 60 RTS .Q587 #if defined _MASTER 9587 4C 56 98 JMP Q856 ;raise "Bad command" error #else 9587 4C 49 98 JMP Q849 ;raise "Bad command" error #endif 958A EQUS "CAT" ;CAT keyword for *ENABLE .Q58D ;Expand 18-bit load address to 32-bit 958D 48 PHA 958E A9 00 LDA #&00 ;set MSB of address = &00 9590 48 PHA 9591 A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 9593 20 98 A9 JSR R998 ;extract b3,b2 of A 9596 C9 03 CMP #&03 ;if either bit clear then a Tube address 9598 D0 06 BNE Q5A0 ;so set high word = high word of tube address 959A 68 PLA ;else discard the high word: 959B 68 PLA .Q59C ;Set high word of OSFILE load address = &FFFF 959C 48 PHA 959D A9 FF LDA #&FF 959F 48 PHA .Q5A0 ;Set high word of OSFILE load address 95A0 20 0C BE JSR SE0C ;page in main workspace 95A3 8D B5 FD STA &FDB5 95A6 68 PLA 95A7 8D B6 FD STA &FDB6 95AA 68 PLA 95AB 60 RTS .Q5AC ;Expand 18-bit exec address to 32-bit 95AC 20 0C BE JSR SE0C ;page in main workspace 95AF A9 00 LDA #&00 ;clear MSB of 32-bit address 95B1 8D B8 FD STA &FDB8 95B4 A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 95B6 20 94 A9 JSR R994 ;extract b7,b6 of A 95B9 C9 03 CMP #&03 ;if b7,b6 both set 95BB D0 05 BNE Q5C2 95BD A9 FF LDA #&FF ;then a host address, set high word = &FFFF 95BF 8D B8 FD STA &FDB8 .Q5C2 95C2 8D B7 FD STA &FDB7 ;else set 2MSB parasite address &0..2FFFF 95C5 60 RTS ;*RENAME 95C6 20 32 8B JSR PB32 ;disallow wildcard characters in filename 95C9 20 E6 92 JSR Q2E6 ;set current file from argument 95CC 20 D9 AA JSR RAD9 ;map current volume to physical volume 95CF 48 PHA ;save source volume 95D0 98 TYA ;save command line offset 95D1 48 PHA 95D2 20 41 8B JSR PB41 ;ensure matching file in catalogue 95D5 20 A8 A2 JSR R2A8 ;ensure file not locked or open (mutex) 95D8 84 B3 STY &B3 ;save pointer to file entry 95DA 68 PLA ;restore command line offset 95DB A8 TAY 95DC 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg 95DF AD C6 FD LDA &FDC6 ;set current directory = default directory 95E2 85 CE STA &CE 95E4 20 F2 89 JSR P9F2 ;parse file spec 95E7 68 PLA ;restore source volume 95E8 8D C0 FD STA &FDC0 ;save in workspace 95EB 20 D9 AA JSR RAD9 ;map current volume to physical volume 95EE CD C0 FD CMP &FDC0 ;compare with source volume 95F1 F0 03 BEQ Q5F6 ;if equal then rename the file #if defined _MASTER 95F3 4C 56 98 JMP Q856 ;else rename across volumes, "Bad command". #else 95F3 4C 49 98 JMP Q849 ;else rename across volumes, "Bad command". #endif .Q5F6 95F6 20 2E 8C JSR PC2E ;search for file in catalogue 95F9 90 0B BCC Q606 ;if not found then update filename+dir 95FB 20 A5 A8 JSR R8A5 ;else raise "File exists" error. 95FE EQUB &C4 95FF EQUS "exists" 9605 EQUB &00 .Q606 ;Update filename+dir in catalogue 9606 A4 B3 LDY &B3 ;get pointer to file entry 9608 20 29 95 JSR Q529 ;write filename+dir into catalogue: .Q60B ;Write volume catalogue L4 960B 20 16 BE JSR SE16 ;page in catalogue sector 1 960E 18 CLC ;add 1 to BCD catalogue cycle number 960F F8 SED 9610 AD 04 FD LDA &FD04 9613 69 01 ADC #&01 9615 8D 04 FD STA &FD04 9618 D8 CLD 9619 20 43 97 JSR Q743 ;set xfer call no. = write, claim NMI 961C 4C 35 96 JMP Q635 ;transfer volume catalogue and exit .Q61F ;Ensure current volume catalogue loaded 961F 20 0C BE JSR SE0C ;page in main workspace 9622 20 D9 AA JSR RAD9 ;map current volume to physical volume 9625 CD DC FD CMP &FDDC ;compare with volume of loaded catalogue 9628 D0 05 BNE Q62F ;if unequal then load volume catalogue 962A 20 06 BD JSR SD06 ;else if motor is on 962D F0 28 BEQ Q657 ;then present cat. and release NMI else: .Q62F 962F 20 4C A8 JSR R84C ;save AXY .Q632 ;Load volume catalogue L4 9632 20 3A 97 JSR Q73A ;set xfer call no. = read, claim NMI: .Q635 ;Transfer volume catalogue 9635 A9 00 LDA #&00 9637 8D CC FD STA &FDCC ;transferring to host, not Tube 963A A9 80 LDA #&80 963C 85 B9 STA &B9 ;>0 disc operation is interruptible 963E AD E9 FD LDA &FDE9 ;get data transfer call number 9641 09 80 ORA #&80 ;b7=1 data address in JIM space 9643 8D E9 FD STA &FDE9 ;update data transfer call number 9646 20 B5 AB JSR RBB5 ;detect disc format/set sector address 9649 20 D9 AA JSR RAD9 ;map current volume to physical volume 964C 8D DC FD STA &FDDC ;set drive and volume of loaded catalogue 964F 20 8B 96 JSR Q68B ;transfer disc/volume catalogue L3 9652 F0 03 BEQ Q657 ;if zero status release NMI and exit 9654 4C AF BC JMP SCAF ;else raise "Disk fault" error. .Q657 ;Present catalogue and release NMI 9657 20 0C BE JSR SE0C ;page in main workspace 965A 2C F4 FD BIT &FDF4 ;[D]test b7=*ENABLE CAT 965D 10 1A BPL Q679 ;if enabled 965F 20 11 BE JSR SE11 ;page in catalogue sector 0 9662 A2 00 LDX #&00 ;then start at offset 0: .Q664 9664 BD 00 FD LDA &FD00,X ;copy catalogue sector 0 9667 9D 00 0E STA &0E00,X ;to main memory page &E, emulating DFS use 966A E8 INX ;loop until entire sector copied 966B D0 F7 BNE Q664 966D 20 16 BE JSR SE16 ;page in catalogue sector 1 .Q670 9670 BD 00 FD LDA &FD00,X ;copy catalogue sector 1 9673 9D 00 0F STA &0F00,X ;to main memory page &F, emulating DFS use 9676 E8 INX ;loop until entire sector copied 9677 D0 F7 BNE Q670 .Q679 9679 20 0C BE JSR SE0C ;page in main workspace 967C 4C 71 AD JMP RD71 ;release NMI ;unreachable code 967F A9 80 LDA #&80 ;data transfer call &80 = read data to JIM 9681 D0 02 BNE Q685 ;branch (always) .Q683 ;Write disc/volume catalogue L3 9683 A9 81 LDA #&81 ;data transfer call &81 = write data from JIM .Q685 ;Transfer disc/volume catalogue L3 9685 20 0C BE JSR SE0C ;page in main workspace 9688 8D E9 FD STA &FDE9 ;set data transfer call number .Q68B ;Transfer disc/volume catalogue L3 #if defined _TURBO 968B 20 79 A8 JSR R879 ;save XY #else 968B 20 75 A8 JSR R875 ;save XY #endif 968E 20 A5 96 JSR Q6A5 ;set data pointer to &0200 9691 A2 03 LDX #&03 ;set X = &03, three possible attempts: .Q693 9693 A9 00 LDA #&00 ;512 bytes to transfer 9695 85 A0 STA &A0 9697 A9 02 LDA #&02 9699 85 A1 STA &A1 969B 20 18 BA JSR SA18 ;transfer data L2 969E F0 04 BEQ Q6A4 ;if zero status then success, return 96A0 CA DEX ;else decrement attempts counter 96A1 D0 F0 BNE Q693 ;if not tried 3 times then try again 96A3 CA DEX ;else return Z=0, failed .Q6A4 96A4 60 RTS .Q6A5 ;Set data pointer to &0200 96A5 A9 02 LDA #&02 ;[D]this addresses catalogue sector 0 in JIM 96A7 85 A6 STA &A6 ;[D]DDOS had &0E00 96A9 A9 00 LDA #&00 96AB 85 A7 STA &A7 96AD 60 RTS .Q6AE ;Open Tube data transfer channel 96AE 20 0C BE JSR SE0C ;page in main workspace 96B1 48 PHA ;a=Tube service call, save in stack[D]no wksp 96B2 A5 BE LDA &BE ;reform address at &FDB3..B6 from &BE,F 96B4 8D B3 FD STA &FDB3 96B7 A5 BF LDA &BF 96B9 8D B4 FD STA &FDB4 96BC AD B5 FD LDA &FDB5 ;and high bytes of address 96BF 2D B6 FD AND &FDB6 ;a=&FF if address is in the host 96C2 0D CD FD ORA &FDCD ;a=&FF if Tube absent (&FDCD=NOT MOS flag!) 96C5 49 FF EOR #&FF ;invert; A>0 if transferring over Tube 96C7 8D CC FD STA &FDCC ;store Tube flag 96CA 38 SEC 96CB F0 0D BEQ Q6DA ;if A=0 then no need for Tube, exit C=1 96CD 20 DC 96 JSR Q6DC ;else claim Tube 96D0 A2 B3 LDX #&B3 ;point XY at address 96D2 A0 FD LDY #&FD 96D4 68 PLA ;restore Tube call number 96D5 48 PHA 96D6 20 06 04 JSR &0406 ;call Tube service 96D9 18 CLC ;exit C=0 as Tube was called .Q6DA 96DA 68 PLA ;preserve Tube call number on exit 96DB 60 RTS .Q6DC ;Claim Tube 96DC 48 PHA .Q6DD 96DD A9 C1 LDA #&C1 ;tube service call = &C0 + ID for DFS (1) 96DF 20 06 04 JSR &0406 ;call Tube service 96E2 90 F9 BCC Q6DD ;loop until C=1, indicating claim granted 96E4 68 PLA 96E5 60 RTS .Q6E6 ;Release Tube 96E6 48 PHA 96E7 AD CC FD LDA &FDCC ;load Tube flag, A>0 if Tube in use 96EA F0 05 BEQ Q6F1 ;if not in use then exit, else: .Q6EC 96EC A9 81 LDA #&81 ;tube service call = &80 + ID for DFS (1) 96EE 20 06 04 JSR &0406 ;call Tube service .Q6F1 96F1 68 PLA 96F2 60 RTS .Q6F3 ;Release Tube if present 96F3 48 PHA 96F4 A9 EA LDA #&EA ;OSBYTE &EA = read Tube presence flag 96F6 20 F2 AD JSR RDF2 ;call OSBYTE with X=0, Y=&FF 96F9 8A TXA ;test X, X=&FF if Tube present 96FA D0 F0 BNE Q6EC ;if Tube present then release Tube 96FC 68 PLA 96FD 60 RTS .Q6FE ;Write ordinary file L5 96FE 20 3E 97 JSR Q73E ;prepare to write from user memory 9701 4C 07 97 JMP Q707 ;transfer ordinary file L5 .Q704 ;Read ordinary file L5 9704 20 35 97 JSR Q735 ;prepare to read to user memory .Q707 ;Transfer ordinary file L5 9707 20 ED 8A JSR PAED ;prepare ordinary file transfer 970A 4C 19 97 JMP Q719 ;transfer data and release Tube .Q70D ;Read extended file L5 970D 20 35 97 JSR Q735 ;prepare to read to user memory 9710 4C 16 97 JMP Q716 ;transfer extended file L5 .Q713 ;Write extended file L5 9713 20 3E 97 JSR Q73E ;prepare to write from user memory .Q716 ;Transfer extended file L5 9716 20 E4 8A JSR PAE4 ;prepare extended file transfer .Q719 9719 A9 01 LDA #&01 ;a=&01, unused 971B 20 E4 AC JSR RCE4 ;transfer data and report errors L4 971E 4C E6 96 JMP Q6E6 ;release Tube and exit .Q721 ;Write ordinary file from JIM L5 9721 A9 81 LDA #&81 ;data transfer call &81 = write data from JIM 9723 AE A9 80 LDX &80A9 ;9724=LDA #&80 .Q724 ;Read ordinary file to JIM L5 9724 A9 80 LDX #&80 ;data transfer call &80 = read data to JIM 9726 8D E9 FD STA &FDE9 ;set data transfer call number 9729 20 88 AD JSR RD88 ;claim NMI 972C 20 ED 8A JSR PAED ;prepare ordinary file transfer 972F 20 E4 AC JSR RCE4 ;transfer data and report errors L4 9732 4C E6 96 JMP Q6E6 ;release Tube .Q735 ;Prepare to read to user memory 9735 A9 01 LDA #&01 ;Tube service 1 = write single bytes to R3 9737 20 AE 96 JSR Q6AE ;open Tube data transfer channel .Q73A 973A A9 00 LDA #&00 ;data transfer call &00 = read data 973C F0 0C BEQ Q74A ;branch (always) .Q73E ;Prepare to write from user memory 973E A9 00 LDA #&00 ;Tube service 0 = read single bytes from R3 9740 20 AE 96 JSR Q6AE ;open Tube data transfer channel .Q743 ;Set xfer call no. = write, claim NMI #if defined _BUGFIX 9743 20 05 B9 JSR S905 ;[D]test write protect state of current drive #else 9743 20 BC AD JSR RDBC ;[D]test write protect state of current drive #endif 9746 D0 14 BNE Q75C ;[D]if not then "Disk read only" 9748 A9 01 LDA #&01 ;else data transfer call &01 = write data .Q74A 974A 20 0C BE JSR SE0C ;page in main workspace 974D 8D E9 FD STA &FDE9 ;set data transfer call number 9750 20 88 AD JSR RD88 ;claim NMI: .Q753 ;Forget catalogue in JIM pages 2..3 9753 20 0C BE JSR SE0C ;page in main workspace 9756 A9 FF LDA #&FF 9758 8D DC FD STA &FDDC ;no catalogue in JIM pages 2..3 975B 60 RTS .Q75C 975C 4C 84 A8 JMP R884 ;raise "Disk read only" error ;FSC 975F 20 0C BE JSR SE0C ;page in main workspace 9762 C9 0C CMP #&0C ;[D]if call outside range 0..11 9764 B0 0E BCS Q774 ;then exit 9766 86 B5 STX &B5 ;else save X 9768 AA TAX ;transfer call number to X as index 9769 BD 21 AE LDA &AE21,X ;get action address high byte 976C 48 PHA ;save on stack 976D BD 15 AE LDA &AE15,X ;get action address low byte 9770 48 PHA ;save on stack 9771 8A TXA ;restore call number to A 9772 A6 B5 LDX &B5 ;restore X on entry .Q774 9774 60 RTS ;jump to action address ;FSC 0 = *OPT 9775 20 4C A8 JSR R84C ;save AXY 9778 E0 0A CPX #&0A ;[D]is option outside range 0..9? 977A B0 0C BCS Q788 ;if so then raise "Bad option" error 977C 8A TXA ;else double option in X for use as offset 977D 0A ASL A 977E AA TAX 977F BD F5 97 LDA &97F5,X ;get action address high byte 9782 48 PHA ;save it on stack 9783 BD F4 97 LDA &97F4,X ;get action address low byte 9786 48 PHA ;save it on stack 9787 60 RTS ;jump to action address .Q788 ;Raise "Bad option" error 9788 20 9C A8 JSR R89C 978B EQUB &CB 978C EQUS "option" 9792 EQUB &00 ;*OPT 0 = restore default FS options ;*OPT 1 = set reporting level 9793 A2 FF LDX #&FF 9795 98 TYA ;is verbosity level =0? 9796 F0 01 BEQ Q799 ;if so then set flag = &FF 9798 E8 INX ;else level >0, set flag = 0. .Q799 9799 8E D9 FD STX &FDD9 979C 60 RTS ;*OPT 4 set boot option 979D 98 TYA ;save requested option 979E 48 PHA #if defined _BUGFIX 979F 20 15 AA JSR RA15 ;set current vol/dir = default, set up drive #else 979F 20 1E AA JSR RA1E ;set current vol/dir = default, set up drive #endif 97A2 20 32 96 JSR Q632 ;load volume catalogue 97A5 68 PLA ;restore option 97A6 20 A4 A9 JSR R9A4 ;shift A left 4 places 97A9 20 16 BE JSR SE16 ;page in catalogue sector 1 97AC 4D 06 FD EOR &FD06 ;xor new option with old 97AF 29 30 AND #&30 ;clear all but option bits 5,4 97B1 4D 06 FD EOR &FD06 ;b5,4 contain new option, others preserved 97B4 8D 06 FD STA &FD06 ;store new option in catalogue 97B7 4C 0B 96 JMP Q60B ;write volume catalogue and exit. ;The structure and syntax of these options derive from those of Opus EDOS ;where they operate natively. Here Challenger translates the parameters ;confirming that EDOS precedes the release of Challenger and may even ;have had an installed base with which compatibility was to be maintained. ;Opus literature confirms that these options replaced the original ;command set still found in DDOS. ;*OPT 6 = set density 97BA A9 40 LDA #&40 ;preset A=&40 force double density 97BC C0 12 CPY #&12 ;if parameter = 18 97BE F0 0A BEQ Q7CA ;then force double density in disc ops 97C0 0A ASL A ;else A=&80 automatic density 97C1 C0 00 CPY #&00 ;if parameter = 0 97C3 F0 05 BEQ Q7CA ;then detect density during FS operations 97C5 0A ASL A ;else A=&00 force single density 97C6 C0 0A CPY #&0A ;if parameter <> 10 97C8 D0 BE BNE Q788 ;then raise "Bad option" error, else: .Q7CA 97CA 8D ED FD STA &FDED ;store *OPT 6 density setting 97CD 60 RTS ;Challenger's *OPT 7 replaces EDOS's high-risk setting of the number ;of volume catalogues on track 0. ;*OPT 7 = set stepping rate 97CE C0 04 CPY #&04 ;if parameter outside range 0..3 97D0 B0 B6 BCS Q788 ;then raise "Bad option" error 97D2 98 TYA ;else 0=slow..3=fast; reverse mapping 97D3 49 03 EOR #&03 ;now in internal format 0=fast..3=slow 97D5 8D F2 FD STA &FDF2 ;store mask to apply to WD 1770 commands 97D8 60 RTS ;*OPT 8 = set double-stepping 97D9 A9 40 LDA #&40 ;preset A=&40 force double-stepping 97DB C8 INY ;map &FF,0,1 to 0..2 97DC C0 02 CPY #&02 ;if parameter = 1 97DE F0 08 BEQ Q7E8 ;then force double-stepping 97E0 B0 A6 BCS Q788 ;if not &FF, 0 or 1 then "Bad option" 97E2 0A ASL A ;else A=&80 automatic stepping 97E3 C0 01 CPY #&01 ;if parameter = &FF 97E5 90 01 BCC Q7E8 ;then detect stepping during FS operations 97E7 0A ASL A ;else A=&00 force 1:1 stepping: .Q7E8 97E8 8D EA FD STA &FDEA ;store *OPT 8 tracks setting 97EB 60 RTS ;*OPT 9 = set save ROM slot no. 97EC C0 10 CPY #&10 ;if parameter not in range &0..F 97EE B0 98 BCS Q788 ;then raise "Bad option" error 97F0 8C EE FD STY &FDEE ;else store *OPT 9 saverom during disc ops 97F3 60 RTS ;Table of action addresses for *OPT commands 0..9 97F4 EQUW &92,&97 ;*OPT 0 = restore default FS opts &9793 97F6 EQUW &92,&97 ;*OPT 1 = set reporting level &9793 97F8 EQUW &87,&97 ;*OPT 2 = (invalid) &9788 97FA EQUW &87,&97 ;*OPT 3 = (invalid) &9788 97FC EQUW &9C,&97 ;*OPT 4 = set boot option &979D 97FE EQUW &87,&97 ;*OPT 5 = (invalid) &9788 9800 EQUW &B9,&97 ;*OPT 6 = set density &97BA 9802 EQUW &CD,&97 ;*OPT 7 = set stepping rate &97CE 9804 EQUW &D8,&97 ;*OPT 8 = set double-stepping &97D9 9806 EQUW &EB,&97 ;*OPT 9 = set save ROM slot no. &97EC ;FSC 1 = read EOF state 9808 48 PHA ;save AY 9809 98 TYA 980A 48 PHA 980B 8A TXA ;transfer file handle to Y 980C A8 TAY 980D 20 9B 9C JSR QC9B ;ensure file handle valid and open 9810 98 TYA ;a=y = channel workspace pointer 9811 20 9F 9E JSR QE9F ;compare PTR - EXT 9814 D0 04 BNE Q81A ;if PTR <> EXT (blech!) then return 0 9816 A2 FF LDX #&FF ;else return &FF, we are at end of file 9818 D0 02 BNE Q81C .Q81A 981A A2 00 LDX #&00 .Q81C 981C 68 PLA ;restore AY and exit 981D A8 TAY 981E 68 PLA 981F 60 RTS ;FSC 2/4/11 = */, *RUN, *RUN from library 9820 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 #if defined _MASTER 9823 F0 01 BEQ Q826 ;always branch ;FSC 3 with *command not in table 9825 0A ASL A ;ensure A is even: .Q826 9826 20 DE 88 JSR P8DE ;save command pointer, offset and call no. 9829 20 E2 89 JSR P9E2 ;set current file from argument pointer 982C 8C E2 FD STY &FDE2 ;store offset of command line tail 982F 20 2E 8C JSR PC2E ;search for file in catalogue 9832 B0 2E BCS Q862 ;if found then execute command binary 9834 AC E3 FD LDY &FDE3 9837 AD C8 FD LDA &FDC8 ;get library directory 983A 85 CE STA &CE ;set as current directory 983C AD C9 FD LDA &FDC9 ;get library drive and volume 983F 85 CF STA &CF ;select volume in A 9841 20 E5 89 JSR P9E5 ;parse file spec from argument pointer 9844 20 2E 8C JSR PC2E ;search for file in catalogue 9847 B0 19 BCS Q862 ;if found then execute it 9849 A9 0B LDA #&0B ;else FSC 11 = *RUN from library 984B C5 B5 CMP &B5 ;if not already serving FSC 11 984D F0 07 BEQ Q856 984F A6 F2 LDX &F2 ;then XY = address of command line 9851 A4 F3 LDY &F3 9853 4C 2B 80 JMP P02B ;issue Filing System Call .Q856 9856 20 9C A8 JSR R89C ;else raise "Bad command" error. 9859 EQUB &FE 985A EQUS "command" 9861 EQUB &00 .Q862 ;Execute command binary 9862 20 F8 A1 JSR R1F8 ;load file into memory 9865 18 CLC 9866 AD E2 FD LDA &FDE2 ;get offset of command line tail 9869 A8 TAY ;and pass to command in Y (if on host) 986A 65 F2 ADC &F2 ;add it to GSINIT pointer in &F2,3 986C 8D E2 FD STA &FDE2 ;giving command line tail pointer 986F A5 F3 LDA &F3 ;[D]save it in &FDE2,3 for OSARGS 1 9871 69 00 ADC #&00 9873 8D E3 FD STA &FDE3 9876 AD B7 FD LDA &FDB7 ;and high bytes of address 9879 2D B8 FD AND &FDB8 ;a=&FF if address is in the host 987C 0D CD FD ORA &FDCD ;a=&FF if Tube absent (&FDCD=NOT MOS flag!) 987F C9 FF CMP #&FF ;if host address or Tube absent 9881 F0 16 BEQ Q899 ;then jump indirect 9883 A5 C0 LDA &C0 ;else copy low word of exec address 9885 8D B5 FD STA &FDB5 ;over high word of load addr in OSFILE block 9888 A5 C1 LDA &C1 988A 8D B6 FD STA &FDB6 988D 20 DC 96 JSR Q6DC ;claim Tube 9890 A2 B5 LDX #&B5 ;point XY to 32-bit execution address 9892 A0 FD LDY #&FD 9894 A9 04 LDA #&04 ;tube service call &04 = *Go 9896 4C 06 04 JMP &0406 ;jump into Tube service .Q899 ;Execute command on host # if defined _BUGFIX 9899 4C D5 BF JMP SFD5 ;emulate Acorn DFS entry conditions # else 9899 6C C0 00 JMP (&00C0) # endif #else /* _MASTER */ ;FSC 3 with *command not in table 9823 20 8F 98 JSR Q88F ;copy argument ptr and load to cat address 9826 8C E3 FD STY &FDE3 ;store offset of start of command line 9829 20 E2 89 JSR P9E2 ;set current file from argument pointer 982C 8C E2 FD STY &FDE2 ;store offset of command line tail 982F 20 2E 8C JSR PC2E ;search for file in catalogue 9832 B0 21 BCS Q855 ;if found then execute command binary 9834 AC E3 FD LDY &FDE3 9837 AD C8 FD LDA &FDC8 ;get library directory 983A 85 CE STA &CE ;set as current directory 983C AD C9 FD LDA &FDC9 ;get library drive and volume 983F 85 CF STA &CF ;select volume in A 9841 20 E5 89 JSR P9E5 ;parse file spec from argument pointer 9844 20 2E 8C JSR PC2E ;search for file in catalogue 9847 B0 0C BCS Q855 ;if found then execute it .Q849 9849 20 9C A8 JSR R89C ;else raise "Bad command" error. 984C EQUB &FE 984D EQUS "command" 9854 EQUB &00 .Q855 ;Execute command binary 9855 20 F8 A1 JSR R1F8 ;load file into memory 9858 18 CLC 9859 AD E2 FD LDA &FDE2 ;get offset of command line tail 985C A8 TAY ;and pass to command in Y (if on host) 985D 65 F2 ADC &F2 ;add it to GSINIT pointer in &F2,3 985F 8D E2 FD STA &FDE2 ;giving command line tail pointer 9862 A5 F3 LDA &F3 ;[D]save it in &FDE2,3 for OSARGS 1 9864 69 00 ADC #&00 9866 8D E3 FD STA &FDE3 9869 AD B7 FD LDA &FDB7 ;and high bytes of address 986C 2D B8 FD AND &FDB8 ;a=&FF if address is in the host 986F 0D CD FD ORA &FDCD ;a=&FF if Tube absent (&FDCD=NOT MOS flag!) 9872 C9 FF CMP #&FF ;if host address or Tube absent 9874 F0 16 BEQ Q88C ;then jump indirect 9876 A5 C0 LDA &C0 ;else copy low word of exec address 9878 8D B5 FD STA &FDB5 ;over high word of load addr in OSFILE block 987B A5 C1 LDA &C1 987D 8D B6 FD STA &FDB6 9880 20 DC 96 JSR Q6DC ;claim Tube 9883 A2 B5 LDX #&B5 ;point XY to 32-bit execution address 9885 A0 FD LDY #&FD 9887 A9 04 LDA #&04 ;tube service call &04 = *Go 9889 4C 06 04 JMP &0406 ;jump into Tube service .Q88C ;Execute command on host # if defined _BUGFIX 988C 4C D5 BF JMP SFD5 ;emulate Acorn DFS entry conditions # else 988C 6C C0 00 JMP (&00C0) # endif .Q88F ;Copy argument ptr and load to cat address 988F A9 FF LDA #&FF ;lsb exec address in our OSFILE block = &FF: 9891 85 C0 STA &C0 ;load executable to load address in catalogue 9893 A5 F2 LDA &F2 ;copy GSINIT string pointer to zero page 9895 85 BC STA &BC ;= command line pointer 9897 A5 F3 LDA &F3 9899 85 BD STA &BD 989B 60 RTS #endif /* _MASTER */ ;FSC 3 = unrecognised *command 989C 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 989F A2 B4 LDX #&B4 ;point XY to command table at &90B4 98A1 A0 90 LDY #&90 98A3 A9 00 LDA #&00 ;command starts at XY with zero offset 98A5 20 A8 91 JSR Q1A8 ;search for command or keyword in table 98A8 BA TSX 98A9 86 B8 STX &B8 ;save stack pointer to restore on abort 98AB 4C D7 80 JMP P0D7 ;execute command ;FSC 5 = *CAT 98AE 20 38 92 JSR Q238 ;set GSINIT pointer to XY, set Y=0 98B1 20 F2 A9 JSR R9F2 ;[D]call GSINIT with C=0 98B4 20 72 AA JSR RA72 ;select specified or default volume 98B7 8A TXA ;[D]test b7 of detected specification type 98B8 10 39 BPL Q8F3 ;if b7=0 then spec specific, *CAT single vol 98BA A9 80 LDA #&80 ;else data transfer call &80 = read to JIM 98BC 8D E9 FD STA &FDE9 98BF 20 B5 AB JSR RBB5 ;detect disc format/set sector address 98C2 2C ED FD BIT &FDED ;test density flag 98C5 50 2C BVC Q8F3 ;if double density then *CAT eight volumes: 98C7 20 0B 8F JSR PF0B ;print disc type and volume list 98CA A2 00 LDX #&00 ;for each volume letter A..H: .Q8CC 98CC 20 07 BE JSR SE07 ;page in auxiliary workspace 98CF BD CD FD LDA &FDCD,X ;test if number of tracks in volume > 0 98D2 F0 10 BEQ Q8E4 ;if = 0 then no such volume, skip 98D4 8A TXA ;save volume counter 98D5 48 PHA 98D6 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded 98D9 20 D7 8E JSR PED7 ;print volume title 98DC 20 88 8F JSR PF88 ;print volume spec and boot option 98DF 20 CA 8D JSR PDCA ;list files in catalogue 98E2 68 PLA ;restore volume counter 98E3 AA TAX .Q8E4 98E4 18 CLC 98E5 A5 CF LDA &CF ;get current volume 98E7 69 10 ADC #&10 ;select next volume letter 98E9 85 CF STA &CF ;set as current volume 98EB E8 INX ;increment counter 98EC E0 08 CPX #&08 ;have 8 volumes A..H been listed? 98EE D0 DC BNE Q8CC ;if not then loop 98F0 4C 0C BE JMP SE0C ;else page in main workspace and exit .Q8F3 ;*CAT single volume 98F3 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded 98F6 20 D7 8E JSR PED7 ;print volume title 98F9 20 0B 8F JSR PF0B ;print disc type and volume list 98FC 20 88 8F JSR PF88 ;print volume spec and boot option 98FF 20 B8 8F JSR PFB8 ;print CSD and library directories 9902 4C CA 8D JMP PDCA ;list files in catalogue ;FSC 6 = new filing system starting up 9905 20 0F 99 JSR Q90F ;close *SPOOL/*EXEC files 9908 0E 00 FD ASL &FD00 ;[D]clear b7=0 Challenger not current FS 990B 4E 00 FD LSR &FD00 990E 60 RTS .Q90F 990F 20 4C A8 JSR R84C ;save AXY 9912 A9 77 LDA #&77 ;call OSBYTE &77 = close *SPOOL/*EXEC files 9914 4C F4 FF JMP &FFF4 ;FSC 7 = range of valid file handles 9917 A2 11 LDX #&11 9919 A0 15 LDY #&15 991B 60 RTS ;FSC 8 = *command has been entered 991C 2C DF FD BIT &FDDF ;if *ENABLEd flag b7=0 (i.e. byte = 0 or 1) 991F 30 03 BMI Q924 9921 CE DF FD DEC &FDDF ;then enable this command, not the ones after .Q924 9924 4C 53 97 JMP Q753 ;[D]forget catalogue in JIM pages 2..3 .Q927 ;Ensure open file still in drive 9927 20 9A AB JSR RB9A ;set current vol/dir from open filename .Q92A ;Ensure open file still on current volume 992A 20 0C BE JSR SE0C 992D A2 07 LDX #&07 ;start at seventh character of leaf name: .Q92F 992F B9 ED FC LDA &FCED,Y ;copy leaf name of file to current leaf name 9932 95 C6 STA &C6,X 9934 88 DEY ;skip odd bytes containing length and addrs 9935 88 DEY ;select previous character of leaf name (Y>0) 9936 CA DEX ;decrement offset in current leaf name 9937 D0 F6 BNE Q92F ;loop until 7 characters copied (X=7..1) 9939 20 2E 8C JSR PC2E ;search for file in catalogue 993C 90 20 BCC Q95E ;if file not found then raise "Disk changed" 993E 8C D2 FD STY &FDD2 ;else save offset in catalogue 9941 20 16 BE JSR SE16 ;page in catalogue sector 1 9944 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector 9947 BE 0F FD LDX &FD0F,Y ;put LSB start sector in X 994A 20 0C BE JSR SE0C ;page in main workspace 994D AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y 9950 59 EE FC EOR &FCEE,Y ;compare start sector with one in workspace 9953 29 03 AND #&03 ;mask off other fields 9955 D0 07 BNE Q95E ;if not equal then raise "Disk changed" error 9957 8A TXA ;else compare low bytes of start sector (LBA) 9958 D9 F0 FC CMP &FCF0,Y 995B D0 01 BNE Q95E ;if not equal then raise "Disk changed" error 995D 60 RTS ;else exit .Q95E 995E 4C 92 8A JMP PA92 ;raise "Disk changed" error ;OSFIND #if defined _BUGFIX 9961 C9 40 CMP #&40 9963 B0 74 BCS Q9D9 ;if A>=&40 then open a file #else 9961 C9 00 CMP #&00 9963 D0 74 BNE Q9D9 ;if A>0 then open a file #endif 9965 20 4C A8 JSR R84C ;else close a file/all files. save AXY .Q968 9968 98 TYA ;if handle = 0 9969 F0 09 BEQ Q974 ;then close all files 996B 48 PHA ;[D]save handle (redundant) 996C 20 AF 9C JSR QCAF ;else convert to pointer 996F A8 TAY 9970 68 PLA ;[D]restore handle (redundant) 9971 4C 88 99 JMP Q988 ;then close file .Q974 ;Close all files 9974 20 0F 99 JSR Q90F ;close *SPOOL/*EXEC files .Q977 9977 A0 04 LDY #&04 ;[D]5 file handles to close: .Q979 9979 98 TYA ;save counter 997A 48 PHA 997B B9 91 9C LDA &9C91,Y ;y=0..4. get workspace pointer from table 997E A8 TAY 997F 20 88 99 JSR Q988 ;close file L7 9982 68 PLA ;restore counter 9983 A8 TAY 9984 88 DEY ;loop until all files closed. 9985 10 F2 BPL Q979 9987 60 RTS .Q988 ;Close file L7 9988 20 0C BE JSR SE0C ;page in main workspace 998B 48 PHA 998C 20 74 9C JSR QC74 ;validate workspace offset 998F B0 46 BCS Q9D7 ;if channel invalid or closed then exit 9991 B9 FC FC LDA &FCFC,Y ;else get bit mask corresponding to channel 9994 49 FF EOR #&FF ;invert it, bit corresponding to channel =0 9996 2D CE FD AND &FDCE ;clear bit of channel open flag byte 9999 8D CE FD STA &FDCE ;update flag byte 999C B9 F8 FC LDA &FCF8,Y ;get channel flags 999F 29 60 AND #&60 ;if either buffer or EXT changed 99A1 F0 34 BEQ Q9D7 99A3 20 27 99 JSR Q927 ;then ensure open file still in drive 99A6 B9 F8 FC LDA &FCF8,Y ;if EXT changed 99A9 29 20 AND #&20 99AB F0 27 BEQ Q9D4 99AD AE D2 FD LDX &FDD2 ;then set X = catalogue pointer 99B0 B9 F5 FC LDA &FCF5,Y ;copy low word of EXT to length in catalogue 99B3 20 16 BE JSR SE16 ;page in catalogue sector 1 99B6 9D 0C FD STA &FD0C,X 99B9 20 0C BE JSR SE0C ;page in main workspace 99BC B9 F6 FC LDA &FCF6,Y 99BF 20 16 BE JSR SE16 ;page in catalogue sector 1 99C2 9D 0D FD STA &FD0D,X 99C5 20 0C BE JSR SE0C ;page in main workspace 99C8 B9 F7 FC LDA &FCF7,Y ;get high byte of EXT 99CB 20 EC 92 JSR Q2EC ;pack b17,16 of length into catalogue entry 99CE 20 0B 96 JSR Q60B ;write volume catalogue 99D1 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y .Q9D4 99D4 20 42 9D JSR QD42 ;ensure buffer up-to-date on disc L6 .Q9D7 99D7 68 PLA ;restore A on entry [D]X not restored here 99D8 60 RTS .Q9D9 ;Open a file #if defined _TURBO 99D9 20 79 A8 JSR R879 ;save XY #else 99D9 20 75 A8 JSR R875 ;save XY #endif 99DC 86 BC STX &BC 99DE 84 BD STY &BD 99E0 85 B4 STA &B4 ;store file open mode in temporary var. 99E2 24 B4 BIT &B4 ;set N and V from temporary variable 99E4 08 PHP 99E5 20 E2 89 JSR P9E2 ;set current file from argument pointer 99E8 20 F7 9A JSR QAF7 ;find unused file handle 99EB 90 18 BCC QA05 ;if all file handles in use 99ED 20 AD A8 JSR R8AD ;then raise "Too many files open" error. 99F0 EQUB &C0 99F1 EQUS "Too many files open" 9A04 EQUB &00 .QA05 9A05 A2 C7 LDX #&C7 ;point XY+A to current filename 9A07 A9 00 LDA #&00 9A09 A8 TAY 9A0A 20 10 9B JSR QB10 ;compare filename at XY+A with open filenames 9A0D 90 1A BCC QA29 ;if file not open then continue .QA0F 9A0F 20 0C BE JSR SE0C ;page in main workspace 9A12 B9 ED FC LDA &FCED,Y ;else test if the channel is open read-write 9A15 10 04 BPL QA1B ;if so, reopening is a conflict; raise error 9A17 28 PLP ;else if reopening a r-o channel read-only 9A18 08 PHP ;(i.e. channel b7=1, OSFIND call no. b7=0) 9A19 10 09 BPL QA24 ;then this is also safe; continue ;NB loop is redundant; can BPL QA29 instead .QA1B 9A1B 20 A5 A8 JSR R8A5 ;else reopening a r-o channel r-w is conflict 9A1E EQUB &C2 ;raise "File open" error. 9A1F EQUS "open" 9A23 EQUB &00 .QA24 9A24 20 2A 9B JSR QB2A ;find any other channels open on this file 9A27 B0 E6 BCS QA0F ;if another channel found then loop .QA29 9A29 20 32 8B JSR PB32 ;disallow wildcard characters in filename 9A2C 20 2E 8C JSR PC2E ;search for file in catalogue 9A2F B0 1D BCS QA4E ;if not found 9A31 A9 00 LDA #&00 ;then preset A=0, no file handle to return 9A33 28 PLP ;if opening for read or update 9A34 50 01 BVC QA37 ;(i.e. OSFIND call no. b6=1) 9A36 60 RTS ;then existing file was expected, return A=0 .QA37 9A37 08 PHP 9A38 20 0C BE JSR SE0C ;page in main workspace 9A3B A2 07 LDX #&07 ;else opening new file for output. .QA3D 9A3D 95 BE STA &BE,X ;clear load, exec, start and length = 0 9A3F 9D B5 FD STA &FDB5,X 9A42 CA DEX 9A43 10 F8 BPL QA3D 9A45 A9 40 LDA #&40 ;initial length = &4000 = 16 KiB 9A47 85 C5 STA &C5 9A49 85 A8 STA &A8 ;b6=1 will accept shorter allocation 9A4B 20 B3 93 JSR Q3B3 ;create file from OSFILE block .QA4E 9A4E 98 TYA ;transfer catalogue pointer to X 9A4F AA TAX 9A50 28 PLP 9A51 08 PHP 9A52 70 03 BVS QA57 ;if opening for output (OSFIND b6=0) 9A54 20 95 A2 JSR R295 ;then ensure file not locked .QA57 9A57 20 0C BE JSR SE0C ;page in main workspace #if defined _BUGFIX 9A5A AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y .QA5D 9A5D 20 11 BE JSR SE11 ;page in catalogue sector 0 9A60 BD 08 FD LDA &FD08,X ;copy name and attributes of file 9A63 20 0C BE JSR SE0C ;page in main workspace 9A66 99 E1 FC STA &FCE1,Y ;to bottom half of channel workspace 9A69 C8 INY 9A6A 20 16 BE JSR SE16 ;page in catalogue sector 1 9A6D BD 08 FD LDA &FD08,X 9A70 20 0C BE JSR SE0C ;page in main workspace 9A73 99 E1 FC STA &FCE1,Y 9A76 C8 INY 9A77 E8 INX 9A78 8A TXA ;loop until 8 byte pairs copied 9A79 29 07 AND #&07 9A7B D0 E0 BNE QA5D 9A7D A2 10 LDX #&10 ;a=0 .QA7F 9A7F 99 E1 FC STA &FCE1,Y ;clear top half of channel workspace 9A82 C8 INY 9A83 CA DEX 9A84 D0 F9 BNE QA7F 9A86 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y ;[D]buffer page no. irrelevant, not set here 9A89 98 TYA 9A8A 99 FE FC STA &FCFE,Y ;set buffer address out of range 9A8D 4C 90 9A JMP QA90 ;(to force a read) .QA90 #else /* _BUGFIX */ 9A5A A9 08 LDA #&08 ;set counter = 8 9A5C 8D D3 FD STA &FDD3 9A5F AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y .QA62 9A62 20 11 BE JSR SE11 ;page in catalogue sector 0 9A65 BD 08 FD LDA &FD08,X ;copy name and attributes of file 9A68 20 0C BE JSR SE0C ;page in main workspace 9A6B 99 E1 FC STA &FCE1,Y ;to bottom half of channel workspace 9A6E C8 INY 9A6F 20 16 BE JSR SE16 ;page in catalogue sector 1 9A72 BD 08 FD LDA &FD08,X 9A75 20 0C BE JSR SE0C ;page in main workspace 9A78 99 E1 FC STA &FCE1,Y 9A7B C8 INY 9A7C E8 INX 9A7D CE D3 FD DEC &FDD3 ;loop until 8 byte pairs copied 9A80 D0 E0 BNE QA62 9A82 A2 10 LDX #&10 9A84 A9 00 LDA #&00 .QA86 9A86 99 E1 FC STA &FCE1,Y ;clear top half of channel workspace 9A89 C8 INY 9A8A CA DEX 9A8B D0 F9 BNE QA86 9A8D AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y ;[D]buffer page no. irrelevant, not set here #endif /* _BUGFIX */ 9A90 AD CF FD LDA &FDCF ;get bit mask corresponding to channel 9A93 99 FC FC STA &FCFC,Y ;store in channel workspace 9A96 0D CE FD ORA &FDCE ;set that bit in channel open flags byte 9A99 8D CE FD STA &FDCE ;marking this channel open 9A9C B9 EA FC LDA &FCEA,Y ;test LSB of file length 9A9F C9 01 CMP #&01 ;[D]set C=1 iff partial sector 9AA1 B9 EC FC LDA &FCEC,Y ;copy 2MSB length to allocation 9AA4 69 00 ADC #&00 ;rounding up to whole sector 9AA6 99 FA FC STA &FCFA,Y 9AA9 B9 EE FC LDA &FCEE,Y ;get top bits exec/length/load/start sector 9AAC 09 0F ORA #&0F ;mask off load/start sector 9AAE 69 00 ADC #&00 ;carry out to length in bits 5 and 4 9AB0 20 96 A9 JSR R996 ;extract b5,b4 of A 9AB3 99 FB FC STA &FCFB,Y ;store MSB allocation 9AB6 28 PLP ;restore OSFIND call number to N and V 9AB7 50 37 BVC QAF0 ;if opening for output then branch 9AB9 30 08 BMI QAC3 ;if opening for update then branch 9ABB A9 80 LDA #&80 ;else opening for input. 9ABD 19 ED FC ORA &FCED,Y ;set b7=1 of seventh char of leaf name 9AC0 99 ED FC STA &FCED,Y ;marking channel read-only. .QAC3 9AC3 B9 EA FC LDA &FCEA,Y ;input or update; set EXT = length of file 9AC6 99 F5 FC STA &FCF5,Y 9AC9 B9 EC FC LDA &FCEC,Y 9ACC 99 F6 FC STA &FCF6,Y 9ACF B9 EE FC LDA &FCEE,Y 9AD2 20 96 A9 JSR R996 ;extract b5,b4 of A 9AD5 99 F7 FC STA &FCF7,Y .QAD8 9AD8 A5 CF LDA &CF ;get current volume 9ADA 99 00 FD STA &FD00,Y ;set as volume of open file 9ADD 20 3F 85 JSR P53F ;[D]pack drive parameters 9AE0 99 F4 FC STA &FCF4,Y ;store in place of buffer page number 9AE3 AD EC FD LDA &FDEC ;get first track of current volume 9AE6 99 FF FC STA &FCFF,Y ;store in spare byte of channel workspace 9AE9 98 TYA ;transfer channel workspace pointer to A 9AEA 20 9D A9 JSR R99D ;shift A right 5 places 9AED 69 10 ADC #&10 ;c=0; add &10 to return file handle &11..15 9AEF 60 RTS .QAF0 ;opening for output 9AF0 A9 20 LDA #&20 ;set channel flag b5=1, "EXT changed" 9AF2 99 F8 FC STA &FCF8,Y ;to truncate file's initial allocation 9AF5 D0 E1 BNE QAD8 ;branch to return file handle (always) .QAF7 ;Find unused file handle 9AF7 AD CE FD LDA &FDCE ;get channel open flags 9AFA A2 FB LDX #&FB ;test up to 5 channel bits:[D]count up here .QAFC 9AFC 0A ASL A ;shift next channel open flag into carry 9AFD 90 04 BCC QB03 ;if C=0 channel unused, calculate ptr+mask 9AFF E8 INX ;else loop until 5 channels tested 9B00 30 FA BMI QAFC 9B02 60 RTS ;if C=1 all channels in use, none free .QB03 ;Calculate workspace pointer and bit mask 9B03 BD 96 9B LDA &9B96,X ;[D]get workspace pointer from &9C91..5 9B06 8D D0 FD STA &FDD0 ;return in workspace pointer variable 9B09 BD 9B 9B LDA &9B9B,X ;[D]get channel open bit mask from &9C96..A 9B0C 8D CF FD STA &FDCF ;return in bit mask variable. 9B0F 60 RTS .QB10 ;Compare filename at XY+A with open filenames 9B10 86 B0 STX &B0 ;save XY as filename pointer 9B12 84 B1 STY &B1 9B14 85 B2 STA &B2 ;save A as offset 9B16 20 0C BE JSR SE0C ;page in main workspace 9B19 AD CE FD LDA &FDCE ;get channel open flags 9B1C 29 F8 AND #&F8 ;extract flags for channels &11..15 9B1E 85 B5 STA &B5 ;save as shift register 9B20 A2 20 LDX #&20 ;start at channel workspace offset &20: .QB22 9B22 86 B4 STX &B4 9B24 06 B5 ASL &B5 ;shift next channel open flag into carry 9B26 B0 0C BCS QB34 ;if C=1 channel open then compare names 9B28 F0 08 BEQ QB32 ;if no more channels open exit C=0, else: .QB2A ;no match 9B2A A5 B4 LDA &B4 ;add &20 to channel workspace pointer 9B2C 18 CLC 9B2D 69 20 ADC #&20 9B2F AA TAX 9B30 90 F0 BCC QB22 ;and loop to test next channel (always) .QB32 9B32 18 CLC 9B33 60 RTS .QB34 9B34 BD 00 FD LDA &FD00,X ;get volume of open file 9B37 20 DB AA JSR RADB ;[D]map volume in A to physical volume 9B3A 85 B3 STA &B3 ;store in temporary variable 9B3C 20 D9 AA JSR RAD9 ;map current volume to physical volume 9B3F 45 B3 EOR &B3 ;compare with volume of open file 9B41 D0 E7 BNE QB2A ;if unequal then no match 9B43 A9 08 LDA #&08 ;else set counter = 8 9B45 85 B3 STA &B3 9B47 A4 B2 LDY &B2 ;put offset in Y: .QB49 9B49 20 11 BE JSR SE11 ;page in catalogue sector 0 9B4C B1 B0 LDA (&B0),Y ;get character of filename to compare 9B4E 20 0C BE JSR SE0C ;page in main workspace 9B51 5D E1 FC EOR &FCE1,X ;compare with char of open filename 9B54 29 7F AND #&7F ;ignore bit 7 9B56 D0 D2 BNE QB2A ;if unequal then no match 9B58 C8 INY ;skip to next character of comparand 9B59 E8 INX ;skip even addresses cont'g file attributes 9B5A E8 INX ;skip to next character of open filename 9B5B C6 B3 DEC &B3 ;decrement counter 9B5D D0 EA BNE QB49 ;loop until 7 leaf name chars + dir tested 9B5F A4 B4 LDY &B4 ;then restore channel workspace offset to Y 9B61 60 RTS ;return C=1 matching filename found. ;OSARGS 9B62 20 0C BE JSR SE0C ;page in main workspace 9B65 C0 00 CPY #&00 ;file handle in Y; if Y = 0 9B67 F0 11 BEQ QB7A ;then perform Y = 0 functions 9B69 20 4C A8 JSR R84C ;else save AXY 9B6C C9 FF CMP #&FF ;if A=&FF 9B6E F0 3C BEQ QBAC ;then ensure file up-to-date on disc 9B70 C9 03 CMP #&03 ;else if A>=3 9B72 B0 17 BCS QB8B ;then return 9B74 4A LSR A ;else place bit 0 of A in carry flag 9B75 90 41 BCC QBB8 ;if A=0 or A=2 then return PTR or EXT 9B77 4C D8 9B JMP QBD8 ;else A=1 set PTR .QB7A ;OSARGS Y=0 #if defined _TURBO 9B7A 20 79 A8 JSR R879 ;save XY #else 9B7A 20 75 A8 JSR R875 ;save XY #endif 9B7D A8 TAY ;A=call number, transfer to Y 9B7E C8 INY ;convert &FF,0,1 to 0..2 9B7F C0 03 CPY #&03 ;if call number was &02..&FE 9B81 B0 08 BCS QB8B ;then return 9B83 B9 30 AE LDA &AE30,Y ;else get action address high byte 9B86 48 PHA ;save on stack 9B87 B9 2D AE LDA &AE2D,Y ;get action address low byte 9B8A 48 PHA ;save on stack .QB8B 9B8B 60 RTS ;jump to action address. ;OSARGS A=0, Y=0 return filing system number 9B8C A9 04 LDA #&04 ;a=4 for Disc Filing System 9B8E 60 RTS ;OSARGS A=1, Y=0 read command line tail 9B8F A9 FF LDA #&FF ;command line is always in I/O processor 9B91 95 02 STA &02,X ;so return a host address, &FFFFxxxx 9B93 95 03 STA &03,X 9B95 AD E2 FD LDA &FDE2 ;copy address of command line arguments 9B98 95 00 STA &00,X ;from workspace where stored by FSC 2..4 9B9A AD E3 FD LDA &FDE3 ;to user's OSARGS block 9B9D 95 01 STA &01,X 9B9F A9 00 LDA #&00 ;return A=0 9BA1 60 RTS ;OSARGS A=&FF, Y=0 9BA2 AD CE FD LDA &FDCE ;Ensure all files up-to-date on disc (flush) 9BA5 48 PHA ;save channel open flags 9BA6 20 77 99 JSR Q977 ;close all files [D](returns N=1) 9BA9 4C B3 9B JMP QBB3 ;branch (always) .QBAC ;OSARGS A=&FF, Y>0 ensure file up-to-date 9BAC AD CE FD LDA &FDCE ;Ensure file up-to-date on disc (flush) 9BAF 48 PHA ;save channel open flags 9BB0 20 68 99 JSR Q968 ;close a file/all files .QBB3 9BB3 68 PLA ;restore channel open flags. 9BB4 8D CE FD STA &FDCE 9BB7 60 RTS .QBB8 ;OSARGS A=0/2, Y>0 return PTR/EXT 9BB8 20 4C A8 JSR R84C ;save AXY 9BBB 20 9B 9C JSR QC9B ;ensure file handle valid and open 9BBE 0A ASL A ;A=0 or 1, multiply by 4 9BBF 0A ASL A ;A=0 offset of PTR, A=4 offset of EXT 9BC0 6D D0 FD ADC &FDD0 ;add offset to channel workspace pointer 9BC3 A8 TAY ;transfer to Y as index 9BC4 B9 F1 FC LDA &FCF1,Y ;copy PTR or EXT 9BC7 95 00 STA &00,X ;to 3 LSBs of user's OSARGS block 9BC9 B9 F2 FC LDA &FCF2,Y 9BCC 95 01 STA &01,X 9BCE B9 F3 FC LDA &FCF3,Y 9BD1 95 02 STA &02,X 9BD3 A9 00 LDA #&00 ;clear MSB of user's OSARGS block 9BD5 95 03 STA &03,X ;PTR <= EXT < 16 MiB 9BD7 60 RTS .QBD8 ;OSARGS A=1, Y>0 set PTR 9BD8 20 4C A8 JSR R84C ;save AXY 9BDB 20 9B 9C JSR QC9B ;ensure file handle valid and open #if defined _BUGFIX 9BDE 20 B7 9E JSR QEB7 ;compare EXT - requested PTR 9BE1 B0 5D BCS QC40 ;if EXT >= request then just set PTR 9BE3 B5 01 LDA &01,X ;else compare 3MSB request - 2MSB EXT 9BE5 D9 F6 FC CMP &FCF6,Y 9BE8 D0 07 BNE 9BF1 ;if unequal then extend file 9BEA B5 02 LDA &02,X ;else compare 2MSB request - MSB EXT 9BEC D9 F7 FC CMP &FCF7,Y 9BEF F0 30 BEQ QC21 ;if equal then within allocation, set PTR,EXT .9BF1 9BF1 B5 00 LDA &00,X ;get LSB requested PTR 9BF3 C9 01 CMP #&01 ;c=1 iff LSB >0 9BF5 B5 01 LDA &01,X ;add C to 3MSB request, rounding up 9BF7 69 00 ADC #&00 9BF9 85 C4 STA &C4 ;store LSB requested length in sectors 9BFB B5 02 LDA &02,X ;carry out to 2MSB request 9BFD 69 00 ADC #&00 9BFF 85 C5 STA &C5 ;store MSB requested length in sectors 9C01 8A TXA ;save OSARGS pointer 9C02 48 PHA 9C03 20 2A 99 JSR Q92A ;ensure open file still on current volume 9C06 20 6E 9E JSR QE6E ;calculate maximum available allocation 9C09 38 SEC 9C0A A5 C4 LDA &C4 ;get LSB requested length in sectors 9C0C E5 C0 SBC &C0 ;subtract LSB maximum available allocation 9C0E 85 C2 STA &C2 ;save LSB excess 9C10 A5 C5 LDA &C5 ;get MSB requested length in sectors 9C12 E5 C1 SBC &C1 ;subtract MSB maximum available allocation 9C14 85 C3 STA &C3 ;save MSB excess, C=0 if negative (headroom) 9C16 90 07 BCC QC1F ;if allocation > request then set PTR 9C18 05 C2 ORA &C2 ;else test excess 9C1A F0 03 BEQ QC1F ;if allocation = request then set PTR 9C1C 20 C7 9E JSR QEC7 ;else move files .QC1F 9C1F 68 PLA ;restore OSARGS pointer 9C20 AA TAX .QC21 9C21 B9 F5 FC LDA &FCF5,Y ;set PTR = EXT 9C24 99 F1 FC STA &FCF1,Y 9C27 B9 F6 FC LDA &FCF6,Y 9C2A 99 F2 FC STA &FCF2,Y 9C2D B9 F7 FC LDA &FCF7,Y 9C30 99 F3 FC STA &FCF3,Y 9C33 20 4F 9C JSR QC4F ;set b7 according to &FCFD..E,Y .QC36 9C36 A9 00 LDA #&00 ;a = &00 filler byte 9C38 20 98 9D JSR QD98 ;write byte to end of file 9C3B 20 B7 9E JSR QEB7 ;compare EXT - request 9C3E 90 F6 BCC QC36 ;loop until last byte is just before new PTR .QC40 9C40 B5 00 LDA &00,X ;copy requested PTR in user's OSARGS block 9C42 99 F1 FC STA &FCF1,Y ;to channel pointer 9C45 B5 01 LDA &01,X 9C47 99 F2 FC STA &FCF2,Y 9C4A B5 02 LDA &02,X ;copy MSB PTR 9C4C 99 F3 FC STA &FCF3,Y .QC4F 9C4F A9 6F LDA #&6F ;b7=0 PTR not in buffer, b4=0 EOF warning clr 9C51 20 37 9D JSR QD37 ;clear channel flag bits 9C54 B9 F2 FC LDA &FCF2,Y 9C57 79 F0 FC ADC &FCF0,Y ;c=0; add LSB start sector to 2MSB PTR 9C5A 85 B0 STA &B0 ;save LSB new buffer address 9C5C B9 F3 FC LDA &FCF3,Y 9C5F 79 EE FC ADC &FCEE,Y ;add top bits exec/length/load/start sector 9C62 29 03 AND #&03 ;mask b1,b0 MSB new buffer address 9C64 D9 FE FC CMP &FCFE,Y ;compare MSB current buffer address 9C67 D0 27 BNE QC90 ;if equal 9C69 A5 B0 LDA &B0 ;get back LSB new buffer address 9C6B D9 FD FC CMP &FCFD,Y ;compare LSB current buffer address 9C6E D0 20 BNE QC90 ;if equal 9C70 4C 2E 9D JMP QD2E ;then set b7=1 buffer contains PTR. #else /* _BUGFIX */ 9BDE 38 SEC 9BDF B9 FD FC LDA &FCFD,Y ;get LSB sector address of buffer 9BE2 F9 F0 FC SBC &FCF0,Y ;subtract LSB start sector of file 9BE5 85 B0 STA &B0 ;=offset of buffer from start of file 9BE7 B9 FE FC LDA &FCFE,Y ;get MSB sector address of buffer 9BEA F9 EE FC SBC &FCEE,Y ;subtract MSB start sector of file 9BED 29 03 AND #&03 ;b7..5 of latter = other top bits, mask off 9BEF D5 02 CMP &02,X ;compare b1..0 with 2MSB requested PTR 9BF1 D0 06 BNE QBF9 ;if equal 9BF3 A5 B0 LDA &B0 ;then compare LSB buffer offset with request 9BF5 D5 01 CMP &01,X 9BF7 F0 0B BEQ QC04 ;if requested PTR not within current buffer .QBF9 9BF9 20 9A AB JSR RB9A ;then set current vol/dir from open filename 9BFC 20 3F 9D JSR QD3F ;ensure buffer up-to-date on disc L6 9BFF A9 6F LDA #&6F ;b7=0 PTR not in buffer, b4=0 EOF warning clr 9C01 20 37 9D JSR QD37 ;clear channel flag bits ;[BUG] EOF warning flag is not cleared if PTR is moved within current buffer! .QC04 9C04 20 B7 9E JSR QEB7 ;compare EXT - requested PTR 9C07 B0 5B BCS QC64 ;if EXT >= request then just set PTR 9C09 B5 01 LDA &01,X ;else compare 3MSB request - 2MSB EXT 9C0B D9 F6 FC CMP &FCF6,Y 9C0E D0 07 BNE QC17 ;if unequal then extend file 9C10 B5 02 LDA &02,X ;else compare 2MSB request - MSB EXT 9C12 D9 F7 FC CMP &FCF7,Y 9C15 F0 31 BEQ QC48 ;if equal then within allocation, set PTR,EXT .QC17 9C17 18 CLC 9C18 B5 00 LDA &00,X ;get LSB requested PTR 9C1A 69 FF ADC #&FF ;c=1 iff LSB >0 9C1C B5 01 LDA &01,X ;add C to 3MSB request, rounding up 9C1E 69 00 ADC #&00 9C20 85 C4 STA &C4 ;store LSB requested length in sectors 9C22 B5 02 LDA &02,X ;carry out to 2MSB request 9C24 69 00 ADC #&00 9C26 85 C5 STA &C5 ;store MSB requested length in sectors 9C28 8A TXA ;save OSARGS pointer 9C29 48 PHA 9C2A 20 2A 99 JSR Q92A ;ensure open file still on current volume 9C2D 20 6E 9E JSR QE6E ;calculate maximum available allocation 9C30 38 SEC 9C31 A5 C4 LDA &C4 ;get LSB requested length in sectors 9C33 E5 C0 SBC &C0 ;subtract LSB maximum available allocation 9C35 85 C2 STA &C2 ;save LSB excess 9C37 A5 C5 LDA &C5 ;get MSB requested length in sectors 9C39 E5 C1 SBC &C1 ;subtract MSB maximum available allocation 9C3B 85 C3 STA &C3 ;save MSB excess, C=0 if negative (headroom) 9C3D 90 07 BCC QC46 ;if allocation > request then set PTR 9C3F 05 C2 ORA &C2 ;else test excess 9C41 F0 03 BEQ QC46 ;if allocation = request then set PTR 9C43 20 C7 9E JSR QEC7 ;else move files .QC46 9C46 68 PLA ;restore OSARGS pointer 9C47 AA TAX .QC48 9C48 B9 F5 FC LDA &FCF5,Y ;set PTR = EXT 9C4B 99 F1 FC STA &FCF1,Y 9C4E B9 F6 FC LDA &FCF6,Y 9C51 99 F2 FC STA &FCF2,Y 9C54 B9 F7 FC LDA &FCF7,Y 9C57 99 F3 FC STA &FCF3,Y .QC5A 9C5A A9 00 LDA #&00 ;a = &00 filler byte 9C5C 20 98 9D JSR QD98 ;write byte to end of file 9C5F 20 B7 9E JSR QEB7 ;compare EXT - request 9C62 90 F6 BCC QC5A ;loop until last byte is just before new PTR .QC64 9C64 B5 00 LDA &00,X ;copy requested PTR in user's OSARGS block 9C66 99 F1 FC STA &FCF1,Y ;to channel pointer 9C69 B5 01 LDA &01,X 9C6B 99 F2 FC STA &FCF2,Y 9C6E B5 02 LDA &02,X 9C70 99 F3 FC STA &FCF3,Y 9C73 60 RTS #endif /* _BUGFIX */ .QC74 ;Validate workspace offset 9C74 48 PHA ;save A [D]not X 9C75 98 TYA ;transfer workspace offset to A 9C76 29 E0 AND #&E0 ;mask bits 7..5, offset = 0..7 * &20 9C78 8D D0 FD STA &FDD0 ;save channel workspace pointer 9C7B F0 11 BEQ QC8E ;if offset = 0 (i.e. channel &10) return C=1 9C7D 4A LSR A ;else shift right five times, divide by 32 9C7E 4A LSR A ;to produce an offset 1..7 9C7F 4A LSR A ;corresponding to channels &11..17 9C80 4A LSR A ;[BUG]accepts &16..17, undefined results! 9C81 4A LSR A 9C82 A8 TAY ;transfer to Y for use as index 9C83 B9 95 9C LDA &9C95,Y ;get channel open bit mask from table 9C86 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y 9C89 2C CE FD BIT &FDCE ;if channel's open bit in flag byte = 0 9C8C D0 01 BNE QC8F .QC8E 9C8E 38 SEC ;then return C=1 .QC8F 9C8F 68 PLA ;else return C=0 #if defined _BUGFIX .QC90 #endif 9C90 60 RTS ;Table of channel workspace pointers for file handles &11..15 9C91 EQUB &20 9C92 EQUB &40 9C93 EQUB &60 9C94 EQUB &80 9C95 EQUB &A0 ;Table of channel open bit masks for file handles &11..15 9C96 EQUB &80 9C97 EQUB &40 9C98 EQUB &20 9C99 EQUB &10 9C9A EQUB &08 .QC9B ;Ensure file handle valid and open 9C9B 48 PHA ;save A on entry, Y = file handle 9C9C 20 AF 9C JSR QCAF ;[D]convert file handle to workspace pointer 9C9F 8D D0 FD STA &FDD0 ;save in temporary location 9CA2 B9 96 9C LDA &9C96,Y ;get channel open bit mask from table 9CA5 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y 9CA8 2C CE FD BIT &FDCE ;if channel's open bit in flag byte = 0 9CAB F0 10 BEQ QCBD ;then raise "Channel" error 9CAD 68 PLA ;else restore A 9CAE 60 RTS .QCAF ;Convert file handle to workspace pointer 9CAF 98 TYA 9CB0 C9 16 CMP #&16 ;if file handle is &16 or more 9CB2 B0 09 BCS QCBD ;then raise "Channel" error 9CB4 E9 10 SBC #&10 ;[D]else C=0; if file handle less than &11 9CB6 90 05 BCC QCBD ;then raise "Channel" error, else: 9CB8 A8 TAY 9CB9 B9 91 9C LDA &9C91,Y ;y=0..4. get workspace pointer from table 9CBC 60 RTS .QCBD ;Raise "Channel" error 9CBD 20 AD A8 JSR R8AD 9CC0 EQUB &DE 9CC1 EQUS "Channel" 9CC8 EQUB &00 .QCC9 ;Raise "EOF" error 9CC9 20 AD A8 JSR R8AD 9CCC EQUB &DF 9CCD EQUS "EOF" 9CD0 EQUB &00 .QCD1 ;OSBGET 9CD1 20 0C BE JSR SE0C ;page in main workspace 9CD4 8E C4 FD STX &FDC4 9CD7 8C C5 FD STY &FDC5 9CDA 20 9B 9C JSR QC9B ;ensure file handle valid and open 9CDD 98 TYA 9CDE 20 9F 9E JSR QE9F ;compare PTR - EXT 9CE1 D0 11 BNE QCF4 ;if at EOF 9CE3 B9 F8 FC LDA &FCF8,Y ;then test EOF warning flag b4 9CE6 29 10 AND #&10 9CE8 D0 DF BNE QCC9 ;if set then raise "EOF" error 9CEA A9 10 LDA #&10 ;else set EOF warning flag b4=1 9CEC 20 30 9D JSR QD30 ;set channel flag bits (A = OR mask) 9CEF A9 FE LDA #&FE ;return A=&FE, "file end" 9CF1 38 SEC ;return C=1 indicating end-of-file 9CF2 B0 18 BCS QD0C ;restore XY and exit .QCF4 9CF4 B9 F8 FC LDA &FCF8,Y ;not at EOF. get channel flags 9CF7 30 0A BMI QD03 ;if PTR not within current buffer 9CF9 20 9A AB JSR RB9A ;then set current vol/dir from open filename 9CFC 20 42 9D JSR QD42 ;ensure buffer up-to-date on disc L6 9CFF 38 SEC ;c=1 read buffer from disc 9D00 20 4A 9D JSR QD4A ;read/write sector buffer L6 (returns C=0) .QD03 9D03 20 59 9E JSR QE59 ;[D]increment PTR and page in channel buffer 9D06 BD 00 FD LDA &FD00,X ;get byte from channel buffer at old PTR 9D09 20 0C BE JSR SE0C ;page in main workspace .QD0C 9D0C AE C4 FD LDX &FDC4 ;restore X and Y on entry 9D0F AC C5 FD LDY &FDC5 9D12 48 PHA ;set N and Z according to A 9D13 68 PLA 9D14 60 RTS ;exit .QD15 ;Set buffer sector address from PTR 9D15 18 CLC 9D16 B9 F0 FC LDA &FCF0,Y ;get LSB start sector of open file 9D19 79 F2 FC ADC &FCF2,Y ;add 2MSB of PTR 9D1C 85 C5 STA &C5 ;store LSB sector address 9D1E 99 FD FC STA &FCFD,Y ;store LSB sector address of buffer 9D21 B9 EE FC LDA &FCEE,Y ;get top bits exec/length/load/start sector 9D24 29 03 AND #&03 ;extract MSB start sector 9D26 79 F3 FC ADC &FCF3,Y ;add MSB of PTR 9D29 85 C4 STA &C4 ;store MSB sector address 9D2B 99 FE FC STA &FCFE,Y ;store MSB sector address of buffer #if defined _BUGFIX .QD2E #endif 9D2E A9 80 LDA #&80 ;b7=1 buffer contains byte at PTR: .QD30 ;Set channel flag bits (A = OR mask) 9D30 19 F8 FC ORA &FCF8,Y 9D33 D0 05 BNE QD3A ;store if >0 else fall through harmlessly: .QD35 ;Clear buffer-contains-PTR channel flag: 9D35 A9 7F LDA #&7F .QD37 ;Clear channel flag bits (A = AND mask) 9D37 39 F8 FC AND &FCF8,Y .QD3A 9D3A 99 F8 FC STA &FCF8,Y 9D3D 18 CLC 9D3E 60 RTS #if !defined _BUGFIX .QD3F #endif 9D3F 20 4C A8 JSR R84C ;save AXY .QD42 ;Ensure buffer up-to-date on disc L6 9D42 B9 F8 FC LDA &FCF8,Y ;test b6 of channel flag 9D45 29 40 AND #&40 9D47 F0 3D BEQ QD86 ;if buffer not changed then return 9D49 18 CLC ;c=0 write buffer to disc: .QD4A ;Read/write sector buffer L6 9D4A 08 PHP 9D4B 20 0C BE JSR SE0C ;get channel workspace pointer 9D4E AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y 9D51 98 TYA ;and A 9D52 4A LSR A ;shift A right 5 places 9D53 4A LSR A 9D54 4A LSR A 9D55 4A LSR A 9D56 4A LSR A 9D57 69 03 ADC #&03 ;c=0; A=4..8 for handles &11..15 9D59 85 BE STA &BE ;[D]set LSB address of buffer in JIM space 9D5B A9 00 LDA #&00 9D5D 85 BF STA &BF ;clear MSB buffer address 9D5F 85 C2 STA &C2 9D61 A9 01 LDA #&01 ;256 bytes to transfer 9D63 85 C3 STA &C3 9D65 28 PLP 9D66 B0 15 BCS QD7D ;if C was 1 on entry then read buffer 9D68 B9 FD FC LDA &FCFD,Y ;else copy channel's sector buffer address 9D6B 85 C5 STA &C5 ;to &C5,4 (big-endian) 9D6D B9 FE FC LDA &FCFE,Y 9D70 85 C4 STA &C4 9D72 20 21 97 JSR Q721 ;write ordinary file from JIM L5 9D75 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y 9D78 A9 BF LDA #&BF ;b6=0 buffer not changed 9D7A 4C 37 9D JMP QD37 ;clear channel flag bits and exit .QD7D ;Read channel buffer from disc L6 9D7D 20 15 9D JSR QD15 ;set buffer sector address from PTR 9D80 20 24 97 JSR Q724 ;read ordinary file to JIM L5 9D83 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y .QD86 9D86 60 RTS .QD87 9D87 4C 9D A2 JMP R29D ;raise "File locked" error. .QD8A ;Raise "File read only" error. 9D8A 20 A5 A8 JSR R8A5 9D8D EQUB &C1 9D8E EQUS "read only" 9D97 EQUB &00 .QD98 9D98 20 4C A8 JSR R84C ;save AXY 9D9B 4C AD 9D JMP QDAD .QD9E ;OSBPUT 9D9E 20 0C BE JSR SE0C ;page in main workspace 9DA1 8D C3 FD STA &FDC3 ;save AXY on entry 9DA4 8E C4 FD STX &FDC4 9DA7 8C C5 FD STY &FDC5 9DAA 20 9B 9C JSR QC9B ;ensure file handle valid and open .QDAD 9DAD 48 PHA ;save byte to write 9DAE B9 ED FC LDA &FCED,Y ;test channel read-only bit 9DB1 30 D7 BMI QD8A ;if b7=1 then raise "File read only" error 9DB3 B9 EF FC LDA &FCEF,Y ;else test file locked bit 9DB6 30 CF BMI QD87 ;if b7=1 then raise "File locked" error 9DB8 20 9A AB JSR RB9A ;else set current vol/dir from open filename 9DBB 98 TYA ;a=y = channel workspace pointer 9DBC 18 CLC ;add 4 to point A to allocated length not EXT 9DBD 69 04 ADC #&04 9DBF 20 9F 9E JSR QE9F ;compare PTR - allocated length 9DC2 D0 43 BNE QE07 ;if within allocation then write 9DC4 20 2A 99 JSR Q92A ;else ensure open file still on current volume .QDC7 9DC7 20 6E 9E JSR QE6E ;calculate maximum available allocation 9DCA A5 C1 LDA &C1 ;get MSB maximum available allocation 9DCC D9 FB FC CMP &FCFB,Y ;compare MSB length of file per workspace 9DCF D0 14 BNE QDE5 ;if not equal then extend file 9DD1 A5 C0 LDA &C0 ;else restore LSB maximum available allocation 9DD3 D9 FA FC CMP &FCFA,Y ;compare 2MSB length of file per workspace 9DD6 D0 1B BNE QDF3 ;if not equal then extend file 9DD8 A9 01 LDA #&01 ;else excess = 1 sector 9DDA 85 C2 STA &C2 9DDC A9 00 LDA #&00 9DDE 85 C3 STA &C3 9DE0 20 C7 9E JSR QEC7 ;move files (to yield one sector) 9DE3 90 E2 BCC QDC7 ;and try again .QDE5 9DE5 18 CLC 9DE6 B9 FB FC LDA &FCFB,Y ;[D]increment MSB of file length in workspace 9DE9 69 01 ADC #&01 ;strictly increasing length to n*64 KiB 9DEB 99 FB FC STA &FCFB,Y 9DEE 20 EC 92 JSR Q2EC ;pack b17,16 of length into catalogue entry 9DF1 A9 00 LDA #&00 ;set 2MSB file length to 0: .QDF3 9DF3 99 FA FC STA &FCFA,Y ;store 2MSB file length in workspace 9DF6 20 16 BE JSR SE16 ;page in catalogue sector 1 9DF9 9D 0D FD STA &FD0D,X ;store 2MSB file length in catalogue 9DFC A9 00 LDA #&00 9DFE 9D 0C FD STA &FD0C,X ;clear LSB file length in catalogue 9E01 20 0B 96 JSR Q60B ;write volume catalogue 9E04 AC D0 FD LDY &FDD0 ;put channel workspace pointer in Y .QE07 ;write byte to file 9E07 B9 F8 FC LDA &FCF8,Y ;test channel flags 9E0A 30 17 BMI QE23 ;if b7=1 buffer-contains-PTR then write byte 9E0C 20 42 9D JSR QD42 ;else ensure buffer up-to-date on disc L6 9E0F B9 F5 FC LDA &FCF5,Y ;does EXT equal a whole number of sectors? 9E12 D0 0B BNE QE1F ;if not then read buffer from disc 9E14 98 TYA ;else a=y = channel workspace pointer 9E15 20 9F 9E JSR QE9F ;compare PTR - EXT 9E18 D0 05 BNE QE1F ;if not at EOF then read buffer from disc 9E1A 20 15 9D JSR QD15 ;else set buffer sector address from PTR 9E1D D0 04 BNE QE23 ;branch (always) .QE1F 9E1F 38 SEC ;c=1 read buffer from disc 9E20 20 4A 9D JSR QD4A ;read/write sector buffer L6 .QE23 9E23 20 59 9E JSR QE59 ;increment PTR and page in channel buffer 9E26 68 PLA ;restore byte to write 9E27 9D 00 FD STA &FD00,X ;put byte in channel buffer at old PTR 9E2A 20 0C BE JSR SE0C ;page in main workspace 9E2D A9 40 LDA #&40 ;b6=1, buffer has changed 9E2F 20 30 9D JSR QD30 ;set channel flag bits (A = OR mask) 9E32 98 TYA ;a=y = channel workspace pointer 9E33 20 9F 9E JSR QE9F ;compare PTR - EXT 9E36 90 17 BCC QE4F ;if at EOF (i.e. pointer >= EXT) 9E38 A9 20 LDA #&20 ;then b5=1, EXT has changed 9E3A 20 30 9D JSR QD30 ;set channel flag bits (A = OR mask) 9E3D B9 F1 FC LDA &FCF1,Y ;copy EXT = PTR 9E40 99 F5 FC STA &FCF5,Y 9E43 B9 F2 FC LDA &FCF2,Y 9E46 99 F6 FC STA &FCF6,Y 9E49 B9 F3 FC LDA &FCF3,Y 9E4C 99 F7 FC STA &FCF7,Y .QE4F 9E4F AD C3 FD LDA &FDC3 ;restore AXY on entry 9E52 AE C4 FD LDX &FDC4 9E55 AC C5 FD LDY &FDC5 9E58 60 RTS ;exit .QE59 ;Increment PTR and page in channel buffer 9E59 B9 F1 FC LDA &FCF1,Y ;get current LSB of PTR to return 9E5C 48 PHA 9E5D 20 8D 9E JSR QE8D ;increment PTR 9E60 98 TYA ;transfer workspace pointer to A 9E61 4A LSR A ;shift A right 5 places 9E62 4A LSR A 9E63 4A LSR A 9E64 4A LSR A 9E65 4A LSR A 9E66 69 03 ADC #&03 ;c=0; A=4..8 for handles &11..15 9E68 20 1D BE JSR SE1D ;page in JIM page in A 9E6B 68 PLA 9E6C AA TAX ;return old LSB of PTR in X as buffer offset 9E6D 60 RTS .QE6E ;Calculate maximum available allocation 9E6E 20 0C BE JSR SE0C ;page in main workspace 9E71 AE D2 FD LDX &FDD2 ;get offset of file in catalogue 9E74 20 16 BE JSR SE16 ;page in catalogue sector 1 9E77 38 SEC 9E78 BD 07 FD LDA &FD07,X ;get LSB start LBA of previous file in cat 9E7B FD 0F FD SBC &FD0F,X ;subtract LSB start LBA of open file 9E7E 85 C0 STA &C0 ;save LSB maximum available allocation 9E80 BD 06 FD LDA &FD06,X ;get MSB start LBA of previous file in cat 9E83 FD 0E FD SBC &FD0E,X ;subtract MSB start LBA of open file 9E86 29 03 AND #&03 ;extract b1,b0 9E88 85 C1 STA &C1 ;store MSB maximum available allocation 9E8A 4C 0C BE JMP SE0C ;page in main workspace .QE8D ;Increment PTR 9E8D 98 TYA ;transfer channel workspace pointer to X 9E8E AA TAX ;[D]no buffer pointer to write back 9E8F FE F1 FC INC &FCF1,X ;increment LSB of PTR 9E92 D0 22 BNE QEB6 ;if within same sector then return 9E94 FE F2 FC INC &FCF2,X ;else sector boundary crossed. 9E97 D0 03 BNE QE9C ;carry out to high bytes of PTR 9E99 FE F3 FC INC &FCF3,X .QE9C 9E9C 4C 35 9D JMP QD35 ;and clear buffer-contains-PTR channel flag. .QE9F ;Compare PTR - EXT (A=Y), - allocation (A=Y+4) 9E9F AA TAX ;return C=1 iff at/past EOF or allocation 9EA0 B9 F3 FC LDA &FCF3,Y ;return Z=1 iff at EOF or equal to allocation 9EA3 DD F7 FC CMP &FCF7,X 9EA6 D0 0E BNE QEB6 9EA8 B9 F2 FC LDA &FCF2,Y 9EAB DD F6 FC CMP &FCF6,X 9EAE D0 06 BNE QEB6 9EB0 B9 F1 FC LDA &FCF1,Y 9EB3 DD F5 FC CMP &FCF5,X .QEB6 9EB6 60 RTS .QEB7 ;Compare EXT - OSARGS parameter 9EB7 B9 F5 FC LDA &FCF5,Y ;return C=1 iff EXT >= parameter 9EBA D5 00 CMP &00,X 9EBC B9 F6 FC LDA &FCF6,Y 9EBF F5 01 SBC &01,X 9EC1 B9 F7 FC LDA &FCF7,Y 9EC4 F5 02 SBC &02,X 9EC6 60 RTS .QEC7 ;Move files 9EC7 20 4C A8 JSR R84C ;save AXY 9ECA 86 A9 STX &A9 ;store catalogue offset of file to extend 9ECC 20 16 BE JSR SE16 ;page in catalogue sector 1 9ECF AD 05 FD LDA &FD05 ;get number of files in catalogue * 8 9ED2 85 AA STA &AA ;save in zero page 9ED4 20 53 A0 JSR R053 ;push file map on stack 9ED7 BA TSX ;x = stack pointer 9ED8 86 B2 STX &B2 ;save pointer to file map 9EDA 20 CE A0 JSR R0CE ;confirm space available 9EDD B0 09 BCS QEE8 ;if space cannot be made 9EDF 20 92 A8 JSR R892 ;then raise "Disk full" error 9EE2 EQUB &BF ;number = &BF, "Can't extend", cf. &93EF 9EE3 EQUS "full" 9EE7 EQUB &00 ;Move files with space confirmed available .QEE8 9EE8 20 C9 A0 JSR R0C9 ;confirm space available after file 9EEB 90 15 BCC QF02 ;if not then shift previous files up 9EED 38 SEC ;redundant 9EEE A5 CA LDA &CA ;else get LSB LBA of end of slack to use 9EF0 E5 C8 SBC &C8 ;subtract LSB headroom 9EF2 85 CA STA &CA ;store LSB LBA of new end of block 9EF4 A5 CB LDA &CB ;get MSB LBA of end of slack to use 9EF6 E5 C9 SBC &C9 ;subtract MSB headroom 9EF8 85 CB STA &CB ;update MSB LBA of new end of block 9EFA A9 00 LDA #&00 9EFC 85 CC STA &CC ;do not move previous files 9EFE 85 CD STA &CD 9F00 F0 0D BEQ QF0F ;and branch (always) ;Shifting later files down is insufficient; must shift earlier files up .QF02 9F02 38 SEC 9F03 A9 00 LDA #&00 9F05 E5 C8 SBC &C8 ;negate LSB negative headroom 9F07 85 CC STA &CC ;store LSB excess to move previous files by 9F09 A9 00 LDA #&00 9F0B E5 C9 SBC &C9 ;negate MSB negative headroom 9F0D 85 CD STA &CD ;store MSB excess ;Shift files after current file down .QF0F 9F0F A5 C6 LDA &C6 ;test total slack space after file 9F11 05 C7 ORA &C7 9F13 F0 30 BEQ QF45 ;if none then all space must come from prev .QF15 9F15 18 CLC 9F16 B9 08 01 LDA &0108,Y ;get LSB length of file in sectors 9F19 85 C6 STA &C6 ;store at C6 9F1B 79 06 01 ADC &0106,Y ;add LSB LBA of file 9F1E 85 C8 STA &C8 ;store LSB source LBA 9F20 B9 07 01 LDA &0107,Y ;get MSB length of file in sectors 9F23 85 C7 STA &C7 ;store at C7 9F25 79 05 01 ADC &0105,Y ;add MSB LBA of file 9F28 85 C9 STA &C9 ;store MSB source LBA 9F2A 20 9E 9F JSR QF9E ;move file data 9F2D AD D0 FD LDA &FDD0 ;get channel workspace pointer for open file 9F30 85 C3 STA &C3 ;store at C3 9F32 20 F1 9F JSR QFF1 ;update LBAs in channel workspaces 9F35 A5 CB LDA &CB ;get LSB destination LBA after transfer 9F37 99 05 01 STA &0105,Y ;replace LSB LBA of file 9F3A A5 CA LDA &CA ;get MSB destination LBA after transfer 9F3C 99 06 01 STA &0106,Y ;replace MSB LBA of file 9F3F 20 AD A9 JSR R9AD ;add 4 to Y 9F42 CA DEX ;loop until all files after current moved 9F43 D0 D0 BNE QF15 ;Shift files before current file up .QF45 9F45 A5 CC LDA &CC ;get LSB excess to move previous files by 9F47 85 C2 STA &C2 ;replace LSB total excess 9F49 A5 CD LDA &CD ;get MSB excess to move previous files by 9F4B 85 C3 STA &C3 ;replace LSB total excess 9F4D 05 C2 ORA &C2 ;test excess to move previous files by 9F4F F0 42 BEQ QF93 ;if none then update catalogue and exit 9F51 20 FC A0 JSR R0FC ;else confirm space available before file 9F54 18 CLC ;(certain to succeed) 9F55 B9 06 01 LDA &0106,Y ;get LSB LBA of previous file 9F58 79 08 01 ADC &0108,Y ;add LSB length of file in sectors 9F5B 85 CA STA &CA ;store LSB LBA of end of previous file 9F5D B9 05 01 LDA &0105,Y ;get MSB LBA of previous file 9F60 79 07 01 ADC &0107,Y ;add MSB length of file in sectors 9F63 85 CB STA &CB ;store MSB LBA of end of previous file: .QF65 9F65 B9 04 01 LDA &0104,Y ;get LSB length of current file in sectors 9F68 85 C6 STA &C6 ;store at C6 9F6A B9 03 01 LDA &0103,Y ;get MSB length of current file in sectors 9F6D 85 C7 STA &C7 ;store at C7 9F6F B9 02 01 LDA &0102,Y ;get LSB LBA of current file 9F72 85 C8 STA &C8 ;store at C8 9F74 B9 01 01 LDA &0101,Y ;get MSB LBA of current file 9F77 85 C9 STA &C9 ;store at C9 9F79 A5 CA LDA &CA ;get LSB LBA of end of previous file 9F7B 99 02 01 STA &0102,Y ;replace LSB LBA of file 9F7E A5 CB LDA &CB ;get MSB LBA of end of previous file 9F80 99 01 01 STA &0101,Y ;replace MSB LBA of file 9F83 A9 00 LDA #&00 ;set workspace pointer out of range: 9F85 85 C3 STA &C3 ;update LBAs even of file being extended 9F87 20 F1 9F JSR QFF1 ;update LBAs in channel workspaces 9F8A 20 1D 89 JSR P91D ;shift data 9F8D 20 B6 A9 JSR R9B6 ;subtract 4 from Y 9F90 CA DEX ;loop until beginning of catalogue reached 9F91 D0 D2 BNE QF65 ;Update catalogue and exit .QF93 9F93 20 32 96 JSR Q632 ;load volume catalogue L4 9F96 20 9A A0 JSR R09A ;update LBAs in catalogue 9F99 20 0B 96 JSR Q60B ;write volume catalogue L4 9F9C 18 CLC ;return C=0 sufficient space was made 9F9D 60 RTS .QF9E ;Move file data 9F9E 20 4C A8 JSR R84C ;save AXY 9FA1 A9 00 LDA #&00 9FA3 85 BF STA &BF ;clear MSB load address in JIM space 9FA5 85 C2 STA &C2 ;clear LSB number of bytes to transfer .QFA7 9FA7 A4 C6 LDY &C6 ;compare size of file in sectors - &0002 9FA9 C0 02 CPY #&02 9FAB A5 C7 LDA &C7 9FAD E9 00 SBC #&00 9FAF 90 02 BCC QFB3 ;if size of file >= 2 sectors 9FB1 A0 02 LDY #&02 ;then transfer size = 2: .QFB3 9FB3 84 C3 STY &C3 ;set number of sectors to transfer 9FB5 38 SEC 9FB6 A5 C8 LDA &C8 ;get LSB source LBA 9FB8 E5 C3 SBC &C3 ;subtract transfer size 9FBA 85 C5 STA &C5 ;store LSB of transfer LBA 9FBC 85 C8 STA &C8 ;update LSB source LBA 9FBE A5 C9 LDA &C9 ;get MSB source LBA 9FC0 E9 00 SBC #&00 ;borrow in from transfer size 9FC2 85 C4 STA &C4 ;store MSB transfer LBA 9FC4 85 C9 STA &C9 ;update MSB source LBA 9FC6 A9 02 LDA #&02 9FC8 85 BE STA &BE ;set load address in JIM space = &0002 9FCA 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF 9FCD 20 24 97 JSR Q724 ;read ordinary file to JIM L5 9FD0 38 SEC 9FD1 A5 CA LDA &CA ;get LSB destination LBA 9FD3 E5 C3 SBC &C3 ;subtract transfer size 9FD5 85 C5 STA &C5 ;store LSB of transfer LBA 9FD7 85 CA STA &CA ;update LSB destination LBA 9FD9 A5 CB LDA &CB ;get MSB destination LBA 9FDB E9 00 SBC #&00 ;borrow in from transfer size 9FDD 85 C4 STA &C4 ;store MSB transfer LBA 9FDF 85 CB STA &CB ;update MSB destination LBA ;NB always works upwards and shifts downwards ;sector reads and writes will not overlap 9FE1 A9 02 LDA #&02 9FE3 85 BE STA &BE ;set load address in JIM space = &0002 9FE5 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF 9FE8 20 21 97 JSR Q721 ;write ordinary file from JIM L5 9FEB 20 B4 89 JSR P9B4 ;subtract transfer size from remainder 9FEE D0 B7 BNE QFA7 ;loop while sectors remaining to transfer 9FF0 60 RTS .QFF1 ;Update LBAs in channel workspaces 9FF1 20 4C A8 JSR R84C ;save AXY 9FF4 A2 00 LDX #&00 ;start at channel &11 9FF6 AD CE FD LDA &FDCE ;get channel open flags: .QFF9 9FF9 0A ASL A ;shift next channel open flag into C 9FFA 48 PHA ;save other flags 9FFB 90 4F BCC R04C ;if C=0 channel closed then skip, else: 9FFD BD 91 9C LDA &9C91,X ;x=0..4. get workspace pointer from table A000 A8 TAY A001 B9 00 FD LDA &FD00,Y ;get volume of open file A004 20 DB AA JSR RADB ;map volume in A to physical volume A007 85 C2 STA &C2 A009 20 D9 AA JSR RAD9 ;map current volume to physical volume A00C C5 C2 CMP &C2 ;compare with current volume A00E D0 3C BNE R04C ;if unequal then no match A010 B9 EE FC LDA &FCEE,Y ;get top bits exec/length/load/start sector A013 29 03 AND #&03 ;extract b1,b0 of A A015 C5 C9 CMP &C9 ;compare MSB LBA of start of open file A017 D0 33 BNE R04C ;with LBA of current file; skip if unequal A019 B9 F0 FC LDA &FCF0,Y ;else get LSB start LBA of open file A01C C5 C8 CMP &C8 ;compare with LSB LBA of current file A01E D0 2C BNE R04C ;if unequal then skip A020 C4 C3 CPY &C3 ;else compare wksp pointer with current file A022 F0 28 BEQ R04C ;skip if equal (don't move it even if empty) A024 A5 CA LDA &CA ;else get LSB new starting LBA A026 99 F0 FC STA &FCF0,Y ;update LSB start LBA of open file A029 E5 C8 SBC &C8 ;subtract LSB old starting LBA A02B 85 C2 STA &C2 ;store LSB difference A02D A5 CB LDA &CB ;get MSB new starting LBA A02F E5 C9 SBC &C9 ;subtract LSB old starting LBA A031 48 PHA ;save MSB difference A032 B9 EE FC LDA &FCEE,Y ;get top bits exec/length/load/start sector A035 29 FC AND #&FC ;mask off MSB start LBA in b1,b0 A037 05 CB ORA &CB ;apply MSB new starting LBA A039 99 EE FC STA &FCEE,Y ;update top bits A03C 18 CLC A03D A5 C2 LDA &C2 ;get LSB difference in LBAs A03F 79 FD FC ADC &FCFD,Y ;add LSB LBA of sector in buffer A042 99 FD FC STA &FCFD,Y ;update LSB LBA of sector in buffer A045 68 PLA ;restore MSB difference A046 79 FE FC ADC &FCFE,Y ;add MSB LBA of sector in buffer A049 99 FE FC STA &FCFE,Y ;update LSB LBA of sector in buffer .R04C A04C 68 PLA ;restore channel open flags A04D E8 INX ;select next channel A04E E0 05 CPX #&05 ;loop until channels &11..15 updated A050 D0 A7 BNE QFF9 A052 60 RTS .R053 ;Push file map on stack A053 68 PLA ;pop caller's address into pointer A054 85 AE STA &AE A056 68 PLA A057 85 AF STA &AF A059 20 16 BE JSR SE16 ;page in catalogue sector 1 A05C AC 05 FD LDY &FD05 ;point Y to last catalogue entry A05F A9 00 LDA #&00 A061 48 PHA ;push word &0000 A062 48 PHA A063 20 F8 A4 JSR R4F8 ;return no. reserved sectors in data area A066 48 PHA ;push as big-endian word A067 A9 00 LDA #&00 A069 48 PHA A06A 20 16 BE JSR SE16 ;page in catalogue sector 1 .R06D A06D B9 04 FD LDA &FD04,Y ;get LSB file length A070 C9 01 CMP #&01 ;c=1 iff LSB >0 A072 B9 05 FD LDA &FD05,Y ;add C to 2MSB file length, rounding up A075 69 00 ADC #&00 A077 48 PHA ;push LSB length in sectors A078 08 PHP ;save carry flag A079 B9 06 FD LDA &FD06,Y ;get top bits exec/length/load/start sector A07C 20 96 A9 JSR R996 ;extract b5,b4 of A A07F 28 PLP ;restore carry flag A080 69 00 ADC #&00 ;carry out to MSB file length A082 48 PHA ;push MSB length in sectors A083 B9 07 FD LDA &FD07,Y ;get LSB start sector A086 48 PHA ;push LSB start sector A087 B9 06 FD LDA &FD06,Y ;get top bits exec/length/load/start sector A08A 29 03 AND #&03 ;extract b1,b0 of A A08C 48 PHA ;push MSB start sector A08D 20 B2 A9 JSR R9B2 ;subtract 8 from Y A090 C0 F8 CPY #&F8 ;loop until all entries +volume size pushed A092 D0 D9 BNE R06D A094 20 0C BE JSR SE0C ;page in main workspace A097 4C 32 A9 JMP R932 ;return to caller ;Returns the following stack frame to the caller: ;0101,S MSB LBA of end of volume ;0102,S LSB LBA of end of volume ;0103,S Undefined ;0104,S Undefined ;0105,S MSB LBA of first file in catalogue (highest LBA) ;0106,S LSB LBA of first file in catalogue (highest LBA) ;0107,S MSB length of first file in sectors ;0108,S LSB length of first file in sectors ;0109,S MSB LBA of second file in catalogue ;010A,S LSB LBA of second file in catalogue ;010B,S MSB length of second file in sectors ;010C,S LSB length of second file in sectors ;... ;nn+1,S MSB volume-relative LBA of data area, =&00 ;nn+2,S LSB volume-relative LBA of data area, =&02 (SD) or =&00 (DD) ;nn+3,S MSB file map terminator, =&00 ;nn+4,S LSB file map terminator, =&00 .R09A ;Update LBAs in catalogue A09A 68 PLA ;pop caller's address into pointer A09B 85 AE STA &AE A09D 68 PLA A09E 85 AF STA &AF A0A0 20 16 BE JSR SE16 ;page in catalogue sector 1 A0A3 A0 F8 LDY #&F8 ;y = catalogue offset &F8 going to &00: .R0A5 A0A5 20 A9 A9 JSR R9A9 ;add 8 to Y A0A8 68 PLA ;pop MSB LBA end of volume/start of file A0A9 59 06 FD EOR &FD06,Y ;XOR top bits exec/length/load/start sector A0AC 29 03 AND #&03 ;mask b1,b0 old XOR new A0AE 59 06 FD EOR &FD06,Y ;preserve b7..b2, replace b1,b0 A0B1 99 06 FD STA &FD06,Y ;update top bits exec/length/load/start A0B4 68 PLA ;pop LSB LBA end of volume/start of file A0B5 99 07 FD STA &FD07,Y ;store LSB LBA end of volume/start of file A0B8 68 PLA ;discard undefined/file length A0B9 68 PLA A0BA CC 05 FD CPY &FD05 ;have all files in catalogue been updated? A0BD D0 E6 BNE R0A5 ;loop until true A0BF 68 PLA ;discard LBA of start of data area A0C0 68 PLA A0C1 68 PLA ;discard file map terminator A0C2 68 PLA A0C3 20 0C BE JSR SE0C ;page in main workspace A0C6 4C 32 A9 JMP R932 ;return to caller .R0C9 ;Confirm space available after file A0C9 A5 A9 LDA &A9 ;get catalogue offset of file to extend A0CB 4C D0 A0 JMP R0D0 ;jump into routine .R0CE ;Confirm space available A0CE A5 AA LDA &AA ;get number of files in catalogue * 8 .R0D0 A0D0 4A LSR A ;divide by two, =no. four-byte records A0D1 48 PHA ;save on stack A0D2 18 CLC A0D3 65 B2 ADC &B2 ;add to file map pointer A0D5 A8 TAY ;terminator located at &0105..08,Y A0D6 68 PLA ;restore A A0D7 4A LSR A ;divide by four, = no. files A0D8 4A LSR A A0D9 85 B0 STA &B0 ;store file count A0DB E6 B0 INC &B0 ;increment it to include end of volume A0DD A2 00 LDX #&00 A0DF 86 C6 STX &C6 ;clear total slack space A0E1 86 C7 STX &C7 A0E3 F0 04 BEQ R0E9 ;jump into loop (always) .R0E5 A0E5 E8 INX A0E6 20 B6 A9 JSR R9B6 ;subtract 4 from Y (toward higher LBAs) .R0E9 A0E9 20 2C A1 JSR R12C ;calculate LBA of end of previous file A0EC 20 3E A1 JSR R13E ;calculate slack space before current file A0EF 20 52 A1 JSR R152 ;add slack space to total A0F2 20 60 A1 JSR R160 ;subtract total slack space - excess A0F5 B0 04 BCS R0FB ;if slack will absorb excess then return C=1 A0F7 C6 B0 DEC &B0 ;else loop A0F9 D0 EA BNE R0E5 ;until all files in map tested .R0FB A0FB 60 RTS ;return C=0 cannot absorb excess .R0FC ;Confirm space available before file A0FC A5 A9 LDA &A9 ;get catalogue offset of file to extend A0FE 4A LSR A ;divide by two, =no. four-byte records A0FF 18 CLC A100 65 B2 ADC &B2 ;add to file map pointer A102 A8 TAY ;file's entry located at &0105..08,Y A103 38 SEC A104 A5 AA LDA &AA ;get number of files in catalogue * 8 A106 E5 A9 SBC &A9 ;subtract offset of file to extend A108 4A LSR A ;divide by 8 A109 4A LSR A A10A 4A LSR A A10B 85 B0 STA &B0 ;=count of files after file to extend, >=0 A10D E6 B0 INC &B0 ;increment it to include file itself A10F A2 00 LDX #&00 A111 86 C6 STX &C6 ;clear total slack space A113 86 C7 STX &C7 .R115 A115 20 AD A9 JSR R9AD ;add 4 to Y (toward lower LBAs) A118 E8 INX A119 20 2C A1 JSR R12C ;calculate LBA of end of previous file A11C 20 3E A1 JSR R13E ;calculate slack space before current file A11F 20 52 A1 JSR R152 ;add slack space to total A122 20 60 A1 JSR R160 ;subtract total slack space - excess A125 B0 04 BCS R12B ;if slack will absorb excess then return C=1 A127 C6 B0 DEC &B0 ;else loop A129 D0 EA BNE R115 ;until all files before subject tested .R12B A12B 60 RTS ;return C=0 cannot absorb excess .R12C ;Calculate LBA of end of previous file A12C 18 CLC A12D B9 06 01 LDA &0106,Y ;get LSB LBA of previous file A130 79 08 01 ADC &0108,Y ;add LSB length of file in sectors A133 85 C4 STA &C4 ;store at C4 A135 B9 05 01 LDA &0105,Y ;get MSB LBA of previous file A138 79 07 01 ADC &0107,Y ;add MSB length of file in sectors A13B 85 C5 STA &C5 ;store at C5 A13D 60 RTS .R13E ;Calculate slack space before current file A13E 38 SEC A13F B9 02 01 LDA &0102,Y ;get LSB LBA of current file A142 85 CA STA &CA ;store at CA A144 E5 C4 SBC &C4 ;subtract LSB LBA of end of previous file A146 85 C4 STA &C4 ;store LSB slack space A148 B9 01 01 LDA &0101,Y ;get MSB LBA of current file A14B 85 CB STA &CB ;store at CB A14D E5 C5 SBC &C5 ;subtract MSB LBA of end of previous file A14F 85 C5 STA &C5 ;store MSB slack space A151 60 RTS .R152 ;Add slack space to total A152 18 CLC A153 A5 C6 LDA &C6 ;get LSB total slack space A155 65 C4 ADC &C4 ;add LSB slack space before current file A157 85 C6 STA &C6 ;update LSB total slack space A159 A5 C7 LDA &C7 ;get MSB total slack space A15B 65 C5 ADC &C5 ;add MSB slack space before current file A15D 85 C7 STA &C7 ;update MSB total slack space A15F 60 RTS .R160 ;Subtract total slack space - excess A160 38 SEC A161 A5 C6 LDA &C6 ;get LSB total slack space A163 E5 C2 SBC &C2 ;subtract LSB excess (i.e. space to be made) A165 85 C8 STA &C8 ;store LSB headroom A167 A5 C7 LDA &C7 ;get MSB total slack space A169 E5 C3 SBC &C3 ;subtract MSB excess A16B 85 C9 STA &C9 ;store MSB headroom A16D 60 RTS ;c=1 if slack space will absorb excess ;OSFILE #if defined _TURBO A16E 20 79 A8 JSR R879 ;save XY #else A16E 20 75 A8 JSR R875 ;save XY #endif A171 20 0C BE JSR SE0C ;page in main workspace A174 48 PHA ;push A A175 20 32 8B JSR PB32 ;disallow wildcard characters in filename A178 86 B0 STX &B0 ;set up pointer from XY A17A 8E E4 FD STX &FDE4 A17D 84 B1 STY &B1 A17F 8C E5 FD STY &FDE5 A182 A2 00 LDX #&00 A184 A0 00 LDY #&00 A186 20 D2 89 JSR P9D2 ;copy word at pointer to &BC,D .R189 A189 20 C2 89 JSR P9C2 ;copy next four dwords to &BE..C5 (low words) A18C C0 12 CPY #&12 ;&FDB5..C (high words) A18E D0 F9 BNE R189 A190 68 PLA ;transfer call number to X A191 AA TAX A192 E8 INX ;increment for use as index A193 E0 08 CPX #&08 ;was call number &FF or 0..6? A195 B0 08 BCS R19F ;if not then exit A197 BD 3B AE LDA &AE3B,X ;else get action address high byte A19A 48 PHA ;save on stack A19B BD 33 AE LDA &AE33,X ;get action address low byte A19E 48 PHA ;save on stack .R19F A19F 60 RTS ;jump to action address ;OSFILE 0 = save file A1A0 A9 00 LDA #&00 A1A2 85 A8 STA &A8 ;b6=0 will not accept shorter allocation A1A4 20 B3 93 JSR Q3B3 ;create file from OSFILE block A1A7 20 D1 A2 JSR R2D1 ;set up pointer to user's OSFILE block A1AA 20 F7 8C JSR PCF7 ;return catalogue information to OSFILE block A1AD 4C FE 96 JMP Q6FE ;write ordinary file L5 ;OSFILE 1 = write catalogue information ;[BUG] can set attributes on open file A1B0 20 90 A2 JSR R290 ;ensure unlocked file exists A1B3 20 2D A2 JSR R22D ;set load address from OSFILE block A1B6 20 4C A2 JSR R24C ;set exec address from OSFILE block A1B9 50 16 BVC R1D1 ;branch to set attributes and write (always) ;OSFILE 2 = write load address A1BB 20 90 A2 JSR R290 ;ensure unlocked file exists A1BE 20 2D A2 JSR R22D ;set load address from OSFILE block A1C1 50 11 BVC R1D4 ;branch to write catalogue (always) ;OSFILE 3 = write execution address A1C3 20 90 A2 JSR R290 ;ensure unlocked file exists A1C6 20 4C A2 JSR R24C ;set exec address from OSFILE block A1C9 50 09 BVC R1D4 ;branch to write catalogue (always) ;OSFILE 4 = write file attributes A1CB 20 BD A2 JSR R2BD ;ensure file exists A1CE 20 AB A2 JSR R2AB ;ensure file not open (mutex) ;[BUG] destroys OSFILE block pointer, &B0..1 .R1D1 A1D1 20 74 A2 JSR R274 ;set file attributes from OSFILE block .R1D4 A1D4 20 59 93 JSR Q359 ;write volume catalogue A1D7 A9 01 LDA #&01 ;return A=1, file found A1D9 60 RTS ;OSFILE 5 = read catalogue information A1DA 20 BD A2 JSR R2BD ;ensure file exists A1DD 20 F7 8C JSR PCF7 ;return catalogue information to OSFILE block A1E0 A9 01 LDA #&01 ;return A=1, file found A1E2 60 RTS ;OSFILE 6 = delete file A1E3 20 90 A2 JSR R290 ;ensure unlocked file exists A1E6 20 F7 8C JSR PCF7 ;return catalogue information to OSFILE block A1E9 20 78 8C JSR PC78 ;delete catalogue entry A1EC 4C D4 A1 JMP R1D4 ;write volume catalogue, return A=1 ;OSFILE &FF = load file A1EF 20 3E 8B JSR PB3E ;ensure file matching argument in catalogue A1F2 20 D1 A2 JSR R2D1 ;set up pointer to user's OSFILE block A1F5 20 F7 8C JSR PCF7 ;return catalogue information to OSFILE block .R1F8 ;Load file into memory A1F8 84 BC STY &BC A1FA A2 00 LDX #&00 A1FC A5 C0 LDA &C0 ;test offset 6, LSB exec from OSFILE block A1FE D0 06 BNE R206 ;if non-zero, use load address in catalogue A200 C8 INY ;else skip first two bytes of catalogue entry A201 C8 INY A202 A2 02 LDX #&02 ;skip over user-supplied load address in zp A204 D0 0E BNE R214 ;branch (always) .R206 A206 20 16 BE JSR SE16 ;page in catalogue sector 1 A209 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector A20C 85 C4 STA &C4 A20E 20 0C BE JSR SE0C ;page in main workspace A211 20 8D 95 JSR Q58D ;expand 18-bit load address to 32-bit .R214 A214 20 16 BE JSR SE16 ;page in catalogue sector 1 .R217 A217 B9 08 FD LDA &FD08,Y ;copy load/exec/length/start from catalogue A21A 95 BE STA &BE,X ;into low words of OSFILE block A21C C8 INY ;(our copy, gave user theirs at &A1F5) A21D E8 INX A21E E0 08 CPX #&08 ;loop until 8 or 6 bytes copied, 0..7/2..7 A220 D0 F5 BNE R217 A222 20 AC 95 JSR Q5AC ;expand 18-bit exec address to 32-bit A225 A4 BC LDY &BC A227 20 9D 8C JSR PC9D ;print *INFO line if verbose A22A 4C 04 97 JMP Q704 ;read ordinary file L5 and exit .R22D ;Set load address from OSFILE block A22D 20 4C A8 JSR R84C ;save AXY A230 A0 02 LDY #&02 ;set offset = 2 A232 B1 B0 LDA (&B0),Y ;get LSB load address from OSFILE block A234 20 16 BE JSR SE16 A237 9D 08 FD STA &FD08,X ;store in catalogue entry A23A C8 INY ;increment offset; Y=3 A23B B1 B0 LDA (&B0),Y ;get 3MSB load address A23D 9D 09 FD STA &FD09,X ;store in catalogue entry A240 C8 INY ;increment offset; Y=4 A241 B1 B0 LDA (&B0),Y ;get 2MSB load address A243 0A ASL A ;extract b17,b16, place in b3,b2 A244 0A ASL A A245 5D 0E FD EOR &FD0E,X ;XOR with existing top bits A248 29 0C AND #&0C ;mask b3,b2; A=....XX.. A24A 10 1E BPL R26A ;branch to update top bits (always) .R24C ;Set exec address from OSFILE block A24C 20 4C A8 JSR R84C ;save AXY A24F A0 06 LDY #&06 ;set offset = 6 A251 B1 B0 LDA (&B0),Y ;get LSB exec address from OSFILE block A253 20 16 BE JSR SE16 ;page in catalogue sector 1 A256 9D 0A FD STA &FD0A,X ;store in catalogue entry A259 C8 INY ;increment offset; Y=7 A25A B1 B0 LDA (&B0),Y ;get 3MSB exec address A25C 9D 0B FD STA &FD0B,X ;store in catalogue entry A25F C8 INY ;increment offset; Y=8 A260 B1 B0 LDA (&B0),Y ;get 2MSB load address A262 6A ROR A ;extract b17,b16, place in b7,b6 A263 6A ROR A A264 6A ROR A A265 5D 0E FD EOR &FD0E,X ;XOR with existing top bits A268 29 C0 AND #&C0 ;mask b7,b6; A=XX...... .R26A A26A 5D 0E FD EOR &FD0E,X ;XOR old top bits with A; 6 bits old, 2 new A26D 9D 0E FD STA &FD0E,X ;set top bits exec/length/load/start sector A270 B8 CLV ;return V=0 A271 4C 0C BE JMP SE0C ;page in main workspace .R274 ;Set file attributes from OSFILE block A274 20 4C A8 JSR R84C ;save AXY #if defined _BUGFIX A277 20 D1 A2 JSR R2D1 ;set up pointer to user's OSFILE block A27A A0 0E LDY #&0E ;set Y=14, offset of file attributes A27C B1 B0 LDA (&B0),Y ;get LSB of file attributes A27E 29 0A AND #&0A ;test b3=file locked, b1=writing denied ;NB b2..b0 are in opposite sense to RISC OS ;where they enable execute, write, read resp. ;this is well-documented in DFS and RISC OS A280 A8 TAY ;hold result, Y>0 iff file is to be locked A281 20 11 BE JSR SE11 ;page in catalogue sector 0 A284 BD 0F FD LDA &FD0F,X ;get directory character A287 2A ROL A ;shift out old bit 7 A288 C0 01 CPY #&01 ;set C=1 iff Y>0 A28A 6A ROR A ;shift in new bit 7, b6..b0 = directory char A28B 9D 0F FD STA &FD0F,X ;save directory char with new lock attribute A28E 60 RTS #else /* _BUGFIX */ A277 A0 0E LDY #&0E ;set Y=14, offset of file attributes A279 B1 B0 LDA (&B0),Y ;get LSB of file attributes A27B 29 0A AND #&0A ;test b3=file locked, b1=writing denied ;NB b2..b0 are in opposite sense to RISC OS ;where they enable execute, write, read resp. ;this is well-documented in DFS and RISC OS A27D F0 02 BEQ R281 ;if either is set A27F A9 80 LDA #&80 ;then b7=1 file locked .R281 A281 20 11 BE JSR SE11 ;page in catalogue sector 0 A284 5D 0F FD EOR &FD0F,X ;else b7=0 file unlocked. get directory char A287 29 80 AND #&80 ;from catalogue entry A289 5D 0F FD EOR &FD0F,X ;preserve b6..0, replace b7 from A A28C 9D 0F FD STA &FD0F,X ;save directory char with new lock attribute A28F 60 RTS #endif /* _BUGFIX */ .R290 ;Ensure unlocked file exists A290 20 C7 A2 JSR R2C7 ;test if file exists A293 90 2D BCC R2C2 ;if not then return A=0 from caller, else: .R295 ;Ensure file not locked A295 20 11 BE JSR SE11 ;page in catalogue sector 0 A298 B9 0F FD LDA &FD0F,Y ;if directory character b7=1 A29B 10 29 BPL R2C6 .R29D A29D 20 A5 A8 JSR R8A5 ;then raise "File locked" error. A2A0 EQUB &C3 A2A1 EQUS "locked" A2A7 EQUB &00 .R2A8 ;Ensure file not locked or open (mutex) A2A8 20 95 A2 JSR R295 ;ensure file not locked .R2AB ;Ensure file not open (mutex) A2AB 20 4C A8 JSR R84C ;save AXY A2AE 98 TYA ;save catalogue pointer A2AF 48 PHA A2B0 A2 08 LDX #&08 ;point XY to filename in catalogue, &FD08 A2B2 A0 FD LDY #&FD A2B4 68 PLA A2B5 20 10 9B JSR QB10 ;compare filename at XY+A with open filenames A2B8 90 0C BCC R2C6 ;if unequal then return A2BA 4C 1B 9A JMP QA1B ;else raise "File open" error. .R2BD ;Ensure file exists A2BD 20 C7 A2 JSR R2C7 ;test if file exists A2C0 B0 04 BCS R2C6 ;if present then return, else: .R2C2 ;Return A=0 from caller A2C2 68 PLA ;discard return address on stack (ew!) A2C3 68 PLA A2C4 A9 00 LDA #&00 ;return A=0 as if from caller. .R2C6 A2C6 60 RTS .R2C7 ;Test if file exists A2C7 20 E2 89 JSR P9E2 ;set current file from argument pointer A2CA 20 2E 8C JSR PC2E ;search for file in catalogue A2CD 90 0C BCC R2DB ;if file not found then exit C=0 A2CF 98 TYA ;else transfer catalogue pointer to X: A2D0 AA TAX .R2D1 ;Set up pointer to user's OSFILE block A2D1 AD E4 FD LDA &FDE4 A2D4 85 B0 STA &B0 A2D6 AD E5 FD LDA &FDE5 A2D9 85 B1 STA &B1 .R2DB A2DB 60 RTS ;OSGBPB A2DC C9 09 CMP #&09 A2DE B0 FB BCS R2DB ;if call number >=9 then return A2E0 20 4C A8 JSR R84C ;else save AXY A2E3 20 0C BE JSR SE0C ;page in main workspace A2E6 20 3F A8 JSR R83F ;have A=0 returned on exit A2E9 8E BE FD STX &FDBE ;save OSGBPB block pointer in workspace A2EC 8C BF FD STY &FDBF A2EF A8 TAY ;transfer call number to Y for use as index A2F0 20 F9 A2 JSR R2F9 ;execute OSGBPB call A2F3 08 PHP A2F4 20 F3 96 JSR Q6F3 ;release Tube if present A2F7 28 PLP A2F8 60 RTS .R2F9 A2F9 B9 43 AE LDA &AE43,Y ;get low byte of action address from table A2FC 8D E0 FD STA &FDE0 A2FF B9 4C AE LDA &AE4C,Y ;get high byte of action address from table A302 8D E1 FD STA &FDE1 A305 B9 55 AE LDA &AE55,Y ;get microcode byte from table A308 4A LSR A ;push bit 0 as C A309 08 PHP A30A 4A LSR A ;push bit 1 as C A30B 08 PHP A30C 8D DA FD STA &FDDA ;store Tube service call number as bits 0..5 A30F 20 D5 A4 JSR R4D5 ;set up pointer to user's OSGBPB block A312 A0 0C LDY #&0C ;13 bytes to copy, &0C..&00: .R314 A314 B1 B4 LDA (&B4),Y ;copy user's OSGBPB block A316 99 A1 FD STA &FDA1,Y ;to workspace A319 88 DEY ;loop until 13 bytes copied A31A 10 F8 BPL R314 A31C AD A4 FD LDA &FDA4 ;and high bytes of address A31F 2D A5 FD AND &FDA5 ;a=&FF if address is in the host A322 0D CD FD ORA &FDCD ;a=&FF if Tube absent (&FDCD=NOT MOS flag!) A325 18 CLC A326 69 01 ADC #&01 ;set A=0, C=1 if transferring to/from host A328 F0 06 BEQ R330 ;if A>0 A32A 20 DC 96 JSR Q6DC ;then claim Tube A32D 18 CLC A32E A9 FF LDA #&FF ;and set A=&FF, C=0, transferring to/from Tube .R330 A330 8D DB FD STA &FDDB ;set Tube transfer flag A333 AD DA FD LDA &FDDA ;set A=0 if writing user mem, A=1 if reading A336 B0 07 BCS R33F ;if transferring to/from Tube A338 A2 A2 LDX #&A2 ;then point XY to OSGBPB data address A33A A0 FD LDY #&FD A33C 20 06 04 JSR &0406 ;call Tube service to open Tube data channel .R33F A33F 28 PLP ;set C=microcode b1 A340 B0 04 BCS R346 ;if reading/writing data then transfer it A342 28 PLP ;else C=microcode b0 (=0), pop off stack .R343 A343 6C E0 FD JMP (&FDE0) ;and jump to action address. .R346 A346 A2 03 LDX #&03 ;4 bytes to copy, 3..0: .R348 A348 BD AA FD LDA &FDAA,X ;copy OSGBPB pointer field A34B 95 B6 STA &B6,X ;to zero page A34D CA DEX A34E 10 F8 BPL R348 A350 A2 B6 LDX #&B6 ;point X to pointer in zero page A352 AC A1 FD LDY &FDA1 ;set Y=channel number A355 A9 00 LDA #&00 ;set A=0, read PTR not EXT A357 28 PLP ;set C=microcode b0 A358 B0 03 BCS R35D ;if C=0 A35A 20 D8 9B JSR QBD8 ;then call OSARGS 1,Y set PTR. .R35D A35D 20 B8 9B JSR QBB8 ;call OSARGS 0,Y return PTR A360 A2 03 LDX #&03 ;4 bytes to copy, 3..0: .R362 A362 B5 B6 LDA &B6,X ;copy pointer in zero page A364 9D AA FD STA &FDAA,X ;to OSGBPB pointer field A367 CA DEX A368 10 F8 BPL R362 .R36A A36A 20 C7 A4 JSR R4C7 ;invert OSGBPB length field A36D 30 0D BMI R37C ;and branch into loop (always) .R36F A36F AC A1 FD LDY &FDA1 ;set Y = channel number A372 20 43 A3 JSR R343 ;transfer byte / element A375 B0 0D BCS R384 ;if attempted read past EOF then finish A377 A2 09 LDX #&09 ;else set X = &09, point to OSGBPB pointer A379 20 BB A4 JSR R4BB ;increment pointer .R37C A37C A2 05 LDX #&05 ;set X = &05, point to OSGBPB length field A37E 20 BB A4 JSR R4BB ;increment OSGBPB length field (inverted) A381 D0 EC BNE R36F ;if not overflowed to zero then loop A383 18 CLC ;else set C = 0, no read past EOF: .R384 A384 08 PHP A385 20 C7 A4 JSR R4C7 ;invert OSGBPB length field A388 A2 05 LDX #&05 ;add one to get two's complement (0 -> 0) A38A 20 BB A4 JSR R4BB ;thus, number of elements not transferred #if defined _BUGFIX A38D 20 C5 BF JSR SFC5 ;set up user pointer and clear EOF warning A390 A0 0C LDY #&0C ;13 bytes to copy, offsets 0..&C: #else A38D A0 0C LDY #&0C ;13 bytes to copy, offsets 0..&C: A38F 20 D5 A4 JSR R4D5 ;set up pointer to user's OSGBPB block #endif .R392 A392 B9 A1 FD LDA &FDA1,Y ;copy OSGBPB block back to user memory A395 91 B4 STA (&B4),Y A397 88 DEY A398 10 F8 BPL R392 A39A 28 PLP .R39B A39B 60 RTS ;OSGBPB 1 = set pointer and write data ;OSGBPB 2 = write data A39C 20 6D A4 JSR R46D ;get byte from user memory A39F 20 9E 9D JSR QD9E ;call OSBPUT; write byte to file A3A2 18 CLC ;return C=0 no end-of-file condition A3A3 60 RTS ;OSGBPB 3 = set pointer and read data ;OSGBPB 4 = read data A3A4 20 D1 9C JSR QCD1 ;call OSBGET; read byte from file A3A7 B0 F2 BCS R39B ;if end-of-file reached return C=1 A3A9 4C A4 A4 JMP R4A4 ;else write data byte to user memory ;OSGBPB 5 = read title, boot option and drive #if defined _BUGFIX A3AC 20 15 AA JSR RA15 ;set current vol/dir = default, set up drive #else A3AC 20 1E AA JSR RA1E ;set current vol/dir = default, set up drive #endif A3AF 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded A3B2 A9 0C LDA #&0C ;write 12 to user memory A3B4 20 A4 A4 JSR R4A4 ;= length of title A3B7 A0 00 LDY #&00 ;set offset to 0 .R3B9 A3B9 20 11 BE JSR SE11 ;page in catalogue sector 0 A3BC B9 00 FD LDA &FD00,Y ;get first eight characters of title A3BF 20 A4 A4 JSR R4A4 ;write to user memory A3C2 C8 INY A3C3 C0 08 CPY #&08 ;loop until 8 characters written A3C5 D0 F2 BNE R3B9 .R3C7 A3C7 20 16 BE JSR SE16 ;page in catalogue sector 1 A3CA B9 F8 FC LDA &FCF8,Y ;get last four characters from &FD00..3 A3CD 20 A4 A4 JSR R4A4 ;write to user memory (Y = 8..11) A3D0 C8 INY A3D1 C0 0C CPY #&0C ;loop until 4 more characters written A3D3 D0 F2 BNE R3C7 A3D5 20 16 BE JSR SE16 A3D8 AD 06 FD LDA &FD06 ;get boot option/top bits volume size A3DB 20 9E A9 JSR R99E ;shift A right 4 places A3DE 4C A4 A4 JMP R4A4 ;write boot option to user memory and exit ;[D]does not return CSD drive number ;OSGBPB 6 = read default (CSD) drive and dir A3E1 AD C7 FD LDA &FDC7 ;get default volume A3E4 20 80 A4 JSR R480 ;write length+drive identifier to user memory A3E7 20 A2 A4 JSR R4A2 ;write binary 1 to user memory A3EA AD C6 FD LDA &FDC6 ;get default directory character A3ED 4C A4 A4 JMP R4A4 ;write it to user memory and exit ;OSGBPB 7 = read library drive and directory A3F0 AD C9 FD LDA &FDC9 ;get library volume A3F3 20 80 A4 JSR R480 ;write length+drive identifier to user memory A3F6 20 A2 A4 JSR R4A2 ;write binary 1 to user memory A3F9 AD C8 FD LDA &FDC8 ;get library directory character A3FC 4C A4 A4 JMP R4A4 ;write it to user memory and exit ;OSGBPB 8 = read filenames in default dir #if defined _BUGFIX A3FF 20 15 AA JSR RA15 ;set current vol/dir = default, set up drive #else A3FF 20 1E AA JSR RA1E ;set current vol/dir = default, set up drive #endif A402 20 1F 96 JSR Q61F ;ensure current volume catalogue loaded A405 A9 12 LDA #&12 ;replace action address with &A412 A407 8D E0 FD STA &FDE0 ;= return one filename A40A A9 A4 LDA #&A4 A40C 8D E1 FD STA &FDE1 A40F 4C 6A A3 JMP R36A ;and return requested number of filenames. ;Return one filename (called during OSGBPB 8) A412 20 0C BE JSR SE0C ;page in main workspace A415 AC AA FD LDY &FDAA ;set Y = catalogue pointer (0 on first call) .R418 A418 20 16 BE JSR SE16 ;page in catalogue sector 1 A41B CC 05 FD CPY &FD05 ;compare with no. files in catalogue A41E B0 2E BCS R44E ;if out of files return C=1, read past EOF A420 20 11 BE JSR SE11 ;else page in catalogue sector 0 A423 B9 0F FD LDA &FD0F,Y ;get directory character of cat entry A426 20 D1 A9 JSR R9D1 ;set C=0 iff character in A is a letter A429 45 CE EOR &CE ;compare with current directory character A42B B0 02 BCS R42F ;if directory character is a letter A42D 29 DF AND #&DF ;then ignore case. .R42F A42F 29 7F AND #&7F ;mask off attribute bit b7 A431 F0 05 BEQ R438 ;if catalogue entry not in current directory A433 20 A9 A9 JSR R9A9 ;then add 8 to Y A436 D0 E0 BNE R418 ;and loop (always) .R438 A438 A9 07 LDA #&07 ;else write 7 to user memory A43A 20 A4 A4 JSR R4A4 ;= length of filename A43D 85 B0 STA &B0 ;set counter to 7 .R43F A43F 20 11 BE JSR SE11 ;page in catalogue sector 0 A442 B9 08 FD LDA &FD08,Y ;get character of leaf name A445 20 A4 A4 JSR R4A4 ;write byte to user memory A448 C8 INY ;increment catalogue pointer A449 C6 B0 DEC &B0 ;loop until 7 characters transferred A44B D0 F2 BNE R43F ;(Y is 7 up, inc at &A379 puts pointer 8 up) A44D 18 CLC ;c=0, did not run out of filenames: .R44E A44E 20 16 BE JSR SE16 ;page in catalogue sector 1 A451 AD 04 FD LDA &FD04 ;get catalogue cycle number A454 20 0C BE JSR SE0C ;page in main workspace A457 8C AA FD STY &FDAA ;put updated cat ptr in OSGBPB pointer field A45A 8D A1 FD STA &FDA1 ;return catalogue cycle no. in channel field A45D 60 RTS .R45E ;Set up pointer to user I/O memory A45E 48 PHA A45F AD A2 FD LDA &FDA2 A462 85 B8 STA &B8 A464 AD A3 FD LDA &FDA3 A467 85 B9 STA &B9 A469 A2 00 LDX #&00 ;offset = 0 for indexed indirect load/store A46B 68 PLA A46C 60 RTS .R46D ;Read data byte from user memory A46D 2C DB FD BIT &FDDB ;test Tube transfer flag A470 10 06 BPL R478 ;if b7=0 then read from I/O memory A472 AD E5 FE LDA &FEE5 ;else read from R3DATA A475 4C B6 A4 JMP R4B6 ;increment OSGBPB address field .R478 A478 20 5E A4 JSR R45E ;set up pointer to user I/O memory A47B A1 B8 LDA (&B8,X) ;read byte from user I/O memory A47D 4C B6 A4 JMP R4B6 ;increment OSGBPB address field .R480 ;Write length+drive identifier to user memory A480 48 PHA A481 A0 01 LDY #&01 ;return Y=1 A483 29 F0 AND #&F0 ;unless volume letter is B..H A485 F0 01 BEQ R488 A487 C8 INY ;in which case return Y=2 .R488 A488 98 TYA A489 20 A4 A4 JSR R4A4 ;write length of drive ID to user memory A48C 68 PLA A48D 48 PHA A48E 29 0F AND #&0F ;extract drive number A490 18 CLC A491 69 30 ADC #&30 ;convert to ASCII digit A493 20 A4 A4 JSR R4A4 ;write data byte to user memory A496 68 PLA A497 20 9E A9 JSR R99E ;shift A right 4 places A49A F0 43 BEQ R4DF ;if volume letter is A then exit A49C 18 CLC A49D 69 41 ADC #&41 ;else convert binary to letter B..H A49F 4C A4 A4 JMP R4A4 ;write it to user memory and exit .R4A2 ;Write binary 1 to user memory A4A2 A9 01 LDA #&01 .R4A4 ;Write data byte to user memory A4A4 20 0C BE JSR SE0C ;page in main workspace A4A7 2C DB FD BIT &FDDB ;test Tube flag A4AA 10 05 BPL R4B1 ;if Tube not in use then write to I/O memory A4AC 8D E5 FE STA &FEE5 ;else put byte in R3DATA A4AF 30 05 BMI R4B6 ;and increment OSGBPB address field (always) .R4B1 A4B1 20 5E A4 JSR R45E ;set up pointer to user I/O memory A4B4 81 B8 STA (&B8,X) ;store byte at pointer: .R4B6 ;Increment OSGBPB address field A4B6 20 4C A8 JSR R84C ;save AXY A4B9 A2 01 LDX #&01 ;set X = &01, point to OSGBPB data address: .R4BB ;Increment OSGBPB field A4BB A0 04 LDY #&04 .R4BD A4BD FE A1 FD INC &FDA1,X A4C0 D0 04 BNE R4C6 A4C2 E8 INX A4C3 88 DEY A4C4 D0 F7 BNE R4BD .R4C6 A4C6 60 RTS ;return Z=1 iff field overflows .R4C7 ;Invert OSGBPB length field A4C7 A2 03 LDX #&03 .R4C9 A4C9 A9 FF LDA #&FF A4CB 5D A6 FD EOR &FDA6,X A4CE 9D A6 FD STA &FDA6,X A4D1 CA DEX A4D2 10 F5 BPL R4C9 A4D4 60 RTS .R4D5 ;Set up pointer to user's OSGBPB block A4D5 AD BE FD LDA &FDBE A4D8 85 B4 STA &B4 A4DA AD BF FD LDA &FDBF A4DD 85 B5 STA &B5 .R4DF A4DF 60 RTS ;[D]The next two routines are in opposite order to DDOS .R4E0 ;Put data byte in user memory A4E0 2C CC FD BIT &FDCC ;test Tube data transfer flag A4E3 30 03 BMI R4E8 ;if transferring to host A4E5 91 A6 STA (&A6),Y ;then write to address in I/O memory A4E7 60 RTS .R4E8 A4E8 8D E5 FE STA &FEE5 ;else write to R3DATA. A4EB 60 RTS .R4EC ;Get data byte from user memory A4EC 2C CC FD BIT &FDCC ;test Tube data transfer flag A4EF 30 03 BMI R4F4 ;if transferring from host A4F1 B1 A6 LDA (&A6),Y ;then read address in I/O memory A4F3 60 RTS .R4F4 A4F4 AD E5 FE LDA &FEE5 ;else read from R3DATA. A4F7 60 RTS .R4F8 ;Return no. reserved sectors in data area A4F8 20 0C BE JSR SE0C ;page in main workspace A4FB 20 4C B7 JSR S74C ;is the physical drive a RAM disc? A4FE F0 07 BEQ R507 ;if so then return A=2 A500 A9 00 LDA #&00 ;else A=0 A502 2C ED FD BIT &FDED ;test density flag A505 70 02 BVS R509 ;if single density .R507 A507 A9 02 LDA #&02 ;then return A=2 .R509 A509 60 RTS ;else return A=0 .R50A ;Get start and size of user memory A50A 20 0C BE JSR SE0C ;page in main workspace A50D A9 83 LDA #&83 ;call OSBYTE &83 = read OSHWM A50F 20 F4 FF JSR &FFF4 A512 8C D5 FD STY &FDD5 ;save MSB A515 A9 84 LDA #&84 ;call OSBYTE &84 = read HIMEM A517 20 F4 FF JSR &FFF4 A51A 98 TYA A51B 8D D6 FD STA &FDD6 ;save MSB A51E 38 SEC A51F ED D5 FD SBC &FDD5 ;subtract MSB of OSHWM A522 8D D7 FD STA &FDD7 ;save result = no. pages of user memory. A525 60 RTS ;*HELP UTILS #if defined _EX A526 A2 4D LDX #&4D ;Print utility command table at &914D A528 A0 91 LDY #&91 #else A526 A2 48 LDX #&48 ;Print utility command table at &9148 A528 A0 91 LDY #&91 #endif A52A A9 08 LDA #&08 ;8 entries to print (not *DISK) A52C D0 06 BNE R534 ;*HELP CHAL / *HELP DFS A52E A2 B4 LDX #&B4 ;Print Challenger command table at &90B4 A530 A0 90 LDY #&90 #if defined _EX A532 A9 13 LDA #&13 ;19 entries to print #else A532 A9 12 LDA #&12 ;18 entries to print #endif .R534 A534 20 1E 92 JSR Q21E ;set up trampoline to read table at XY A537 85 B8 STA &B8 ;store number of printable entries in counter A539 20 69 84 JSR P469 ;print newline A53C 18 CLC ;c=0 print version number in banner A53D 20 5E AE JSR RE5E ;print Challenger banner A540 20 D3 A8 JSR R8D3 ;print copyright message A543 EQUS "(C) SLOGGER 1987" A553 EQUB &0D A554 EA NOP A555 A2 00 LDX #&00 ;set offset in command table = 0 .R557 A557 20 15 A8 JSR R815 ;print two spaces A55A 20 7E A5 JSR R57E ;print command name and syntax A55D 20 69 84 JSR P469 ;print newline A560 C6 B8 DEC &B8 ;decrement count of entries A562 D0 F3 BNE R557 ;loop until none remain A564 60 RTS .R565 ;Call GSINIT with C=0 and reject empty arg A565 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 A568 F0 01 BEQ R56B ;if string empty (and unquoted), syntax error A56A 60 RTS .R56B ;Raise "Syntax: " error A56B 20 AD A8 JSR R8AD A56E EQUB &DC A56F EQUS "Syntax: " A577 EA NOP A578 20 7E A5 JSR R57E ;print command name and syntax A57B 4C F8 A8 JMP R8F8 ;terminate error message, raise error .R57E ;Print command name and syntax A57E 20 4C A8 JSR R84C ;save AXY A581 A2 00 LDX #&00 ;set offset in command table = 0 A583 A0 09 LDY #&09 ;9 characters in command name column .R585 A585 20 AA 00 JSR &00AA ;get byte of command name A588 30 08 BMI R592 ;if terminator reached then print syntax A58A 20 51 A9 JSR R951 ;else print character in A (OSASCI) A58D E8 INX ;increment offset A58E 88 DEY ;decrement number of spaces remaining A58F 4C 85 A5 JMP R585 ;and loop .R592 ;Print syntax A592 88 DEY ;if Y in range 1..128 A593 30 04 BMI R599 ;then command not reached edge of column A595 C8 INY ;so A596 20 DD 8A JSR PADD ;print number of spaces in Y .R599 A599 E8 INX ;skip action address A59A E8 INX A59B 20 AA 00 JSR &00AA ;get syntax byte A59E 48 PHA ;save it A59F E8 INX ;skip over it A5A0 20 2D 92 JSR Q22D ;add X to trampoline address A5A3 68 PLA A5A4 20 AC A5 JSR R5AC ;print syntax element A5A7 20 9E A9 JSR R99E ;shift A right 4 places A5AA 29 07 AND #&07 ;mask b2..0 ignore restricted cmd bit: .R5AC ;Print syntax element A5AC 20 4C A8 JSR R84C ;save AXY A5AF 29 0F AND #&0F ;mask b3..0 current syntax element A5B1 F0 1D BEQ R5D0 ;if null element then return A5B3 A8 TAY ;else transfer to Y for use as counter A5B4 A9 20 LDA #&20 ;print a space A5B6 20 51 A9 JSR R951 ;print character in A (OSASCI) A5B9 A2 FF LDX #&FF ;set offset=&FF going to 0: .R5BB A5BB E8 INX ;increment offset A5BC BD D1 A5 LDA &A5D1,X ;get character of syntax element table A5BF D0 FA BNE R5BB ;loop until NUL reached A5C1 88 DEY ;decrement number of NULs to skip A5C2 D0 F7 BNE R5BB ;when Y=0 we've reached correct element: .R5C4 A5C4 E8 INX ;increment offset A5C5 BD D1 A5 LDA &A5D1,X ;get character of syntax element table A5C8 F0 06 BEQ R5D0 ;if NUL reached then return A5CA 20 51 A9 JSR R951 ;else print character in A (OSASCI) A5CD 4C C4 A5 JMP R5C4 ;and loop until element printed. .R5D0 A5D0 60 RTS ;Table of syntax elements A5D1 EQUB &00 ;element &0, "" A5D2 EQUS "<fsp>" ;element &1, <fsp> A5D7 EQUB &00 A5D8 EQUS "<afsp>" ;element &2, <afsp> A5DE EQUB &00 A5DF EQUS "(L)" ;element &3, (L) A5E2 EQUB &00 A5E3 EQUS "<src drv>" ;element &4, <src drv> A5EC EQUB &00 A5ED EQUS "<dest drv>" ;element &5, <dest drv> A5F7 EQUB &00 A5F8 EQUS "<dest drv> <afsp>" ;element &6, <dest drv> <afsp> A609 EQUB &00 A60A EQUS "<new fsp>" ;element &7, <new fsp> A613 EQUB &00 A614 EQUS "<old fsp>" ;element &8, <old fsp> A61D EQUB &00 A61E EQUS "(<dir>)" ;element &9, (<dir>) A625 EQUB &00 A626 EQUS "(<drv>)" ;element &A, (<drv>) A62D EQUB &00 A62E EQUS "<title>" ;element &B, <title> A635 EQUB &00 ;terminator byte ;*COMPACT #if defined _BUGFIX A636 20 0E AA JSR RA0E ;parse volume spec from argument #else A636 20 16 AA JSR RA16 ;parse volume spec from argument #endif A639 8D CA FD STA &FDCA ;set as source drive A63C 8D CB FD STA &FDCB ;set as destination drive A63F 20 D3 A8 JSR R8D3 A642 EQUS "Compacting" A64C EA NOP A64D 20 AD 8E JSR PEAD ;print " Drive " plus volume spec in A A650 20 69 84 JSR P469 ;print newline A653 20 74 99 JSR Q974 ;[D]close all files A656 20 0A A5 JSR R50A ;get start and size of user memory A659 20 2F 96 JSR Q62F ;load volume catalogue L4 A65C 20 23 85 JSR P523 ;save parameters of source drive A65F 20 2A 85 JSR P52A ;save parameters of destination drive A662 20 16 BE JSR SE16 ;page in catalogue sector 1 A665 AC 05 FD LDY &FD05 ;get number of files in catalogue A668 84 CC STY &CC ;set as catalogue pointer A66A A9 00 LDA #&00 ;initialise LBA to start of data area A66C 85 CB STA &CB A66E 20 F8 A4 JSR R4F8 A671 85 CA STA &CA .R673 A673 A4 CC LDY &CC ;set Y to catalogue pointer A675 20 B2 A9 JSR R9B2 ;subtract 8 from Y A678 C0 F8 CPY #&F8 ;if we've reached end of catalogue A67A F0 5A BEQ R6D6 ;then finish A67C 84 CC STY &CC ;else set new catalogue pointer A67E 20 9D 8C JSR PC9D ;print *INFO line if verbose A681 A4 CC LDY &CC A683 20 03 A7 JSR R703 ;test length of file A686 F0 46 BEQ R6CE ;if empty then only print *INFO line A688 A9 00 LDA #&00 A68A 85 BE STA &BE ;else set LSB load address = 0 A68C 85 C2 STA &C2 ;set LSB transfer size = 0 A68E 20 14 A7 JSR R714 ;calculate number of sectors used by file A691 20 16 BE JSR SE16 ;page in catalogue sector 1 A694 B9 0F FD LDA &FD0F,Y ;get LSB start sector A697 85 C8 STA &C8 ;set LSB source LBA A699 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector A69C 29 03 AND #&03 ;extract b1,b0 of A A69E 85 C9 STA &C9 ;set MSB source LBA A6A0 C5 CB CMP &CB ;compare with destination LBA A6A2 D0 0C BNE R6B0 ;if unequal then compact file A6A4 A5 C8 LDA &C8 ;else compare LSBs source - destination LBA A6A6 C5 CA CMP &CA A6A8 D0 06 BNE R6B0 ;if unequal then compact file A6AA 20 33 A7 JSR R733 ;else add number of sectors to total A6AD 4C CE A6 JMP R6CE ;print *INFO line and loop for next file .R6B0 ;Compact file A6B0 20 16 BE JSR SE16 ;page in catalogue sector 1 A6B3 A5 CA LDA &CA ;set LSB start sector = destination LBA A6B5 99 0F FD STA &FD0F,Y A6B8 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector A6BB 29 FC AND #&FC ;clear b1,b0 MSB start sector A6BD 05 CB ORA &CB ;replace with MSB destination LBA A6BF 99 0E FD STA &FD0E,Y ;set top bits exec/length/load/start sector A6C2 A9 00 LDA #&00 A6C4 85 A8 STA &A8 ;no catalogue entry waiting to be created A6C6 85 A9 STA &A9 ;&00 = source and dest. are different drives ;(no swapping) A6C8 20 48 89 JSR P948 ;copy source drive/file to destination A6CB 20 0B 96 JSR Q60B ;write volume catalogue L4 .R6CE A6CE A4 CC LDY &CC A6D0 20 A5 8C JSR PCA5 ;print *INFO line A6D3 4C 73 A6 JMP R673 ;loop for next file .R6D6 A6D6 20 D3 A8 JSR R8D3 ;print "Disk compacted " A6D9 EQUS "Disk compacted " A6E8 EA NOP A6E9 38 SEC A6EA 20 16 BE JSR SE16 ;page in catalogue sector 1 A6ED AD 07 FD LDA &FD07 ;get LSB volume size A6F0 E5 CA SBC &CA ;subtract LSB sectors used on volume A6F2 85 C6 STA &C6 ;=LSB sectors free. save on stack A6F4 AD 06 FD LDA &FD06 ;get boot option/top bits volume size A6F7 29 03 AND #&03 ;extract volume size in b1,b0 A6F9 E5 CB SBC &CB ;subtract MSB sectors used on volume A6FB 85 C7 STA &C7 #if defined _BUGFIX A6FD 20 DD 8B JSR PBDD ;[D]print number of free sectors #else A6FD 20 E0 8B JSR PBE0 ;[D]print number of free sectors #endif A700 4C CA 88 JMP P8CA ;store empty BASIC program at OSHWM (NEW) .R703 ;Test length of file A703 20 16 BE JSR SE16 ;page in catalogue sector 1 A706 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector A709 29 30 AND #&30 ;extract length in b5,b4 A70B 19 0D FD ORA &FD0D,Y ;OR with 2MSB, LSB of length A70E 19 0C FD ORA &FD0C,Y ;return Z=1 if length=0, empty file. A711 4C 0C BE JMP SE0C ;page in main workspace ;DDOS version of routine; Challenger version is at Q4EB. ;Returns to &C6, &C7 and leaves main workspace paged (vs. &C5, &C4 and cat). .R714 ;Calculate number of sectors used by file A714 20 16 BE JSR SE16 ;page in catalogue sector 1 A717 18 CLC A718 B9 0C FD LDA &FD0C,Y ;get LSB length A71B 69 FF ADC #&FF ;c=1 iff LSB >0 A71D B9 0D FD LDA &FD0D,Y ;add C to 2MSB length, rounding up A720 69 00 ADC #&00 ;(Y points to 8 bytes before file entry) A722 85 C6 STA &C6 A724 B9 0E FD LDA &FD0E,Y ;get top bits exec/length/load/start sector A727 08 PHP ;save carry flag from addition A728 20 96 A9 JSR R996 ;extract length from b5,4 to b1,0 A72B 28 PLP ;restore carry flag A72C 69 00 ADC #&00 ;add C to MSB length, rounding up A72E 85 C7 STA &C7 ;store length in sectors in zero page A730 4C 0C BE JMP SE0C ;page in main workspace .R733 ;Add number of sectors to total A733 18 CLC ;add LSB A734 A5 CA LDA &CA A736 65 C6 ADC &C6 A738 85 CA STA &CA A73A A5 CB LDA &CB ;add MSB A73C 65 C7 ADC &C7 A73E 85 CB STA &CB A740 60 RTS ;Note: Challenger does not give the option to copy between opposite sides of ;different discs with one drive. *BACKUP 0 2 for instance copies one side ;of the disc to the other, without the chance to swap discs. .R741 ;Set swapping and current disc flags A741 AD CB FD LDA &FDCB ;[D]get destination drive A744 20 DB AA JSR RADB ;map volume in A to physical volume A747 85 A9 STA &A9 ;store in temporary variable A749 AD CA FD LDA &FDCA ;get source drive A74C 20 DB AA JSR RADB ;map volume in A to physical volume A74F C5 A9 CMP &A9 ;compare with destination drive A751 D0 07 BNE R75A ;if equal A753 A9 FF LDA #&FF ;then A=&FF A755 85 A9 STA &A9 ;b7=1 source & dest. share drive (swapping) A757 85 AA STA &AA ;b7=1 dest. disc in drive (ask for source) A759 60 RTS .R75A A75A A9 00 LDA #&00 ;&00 = source and dest. are different drives A75C 85 A9 STA &A9 A75E 60 RTS .R75F ;Ensure *ENABLE active A75F 20 4C A8 JSR R84C ;[D]save AXY A762 2C DF FD BIT &FDDF ;test *ENABLE flag A765 10 20 BPL R787 ;if b7=0 then current command is enabled A767 20 D3 A8 JSR R8D3 ;[D]else print "Are you sure ? Y/N " A76A EQUB &0D ;(DDOS raises "Not enabled" error) A76B EQUS "Are you sure ? Y/N " A77E EA NOP A77F 20 DE 84 JSR P4DE ;ask user yes or no A782 F0 03 BEQ R787 ;if user typed Y then return A784 A6 B8 LDX &B8 ;else reset to stack pointer set at &80C0 A786 9A TXS ;and exit from *command. .R787 A787 4C 69 84 JMP P469 ;[D]print newline .R78A ;Parse and print source and dest. volumes A78A 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg A78D 20 7F AA JSR RA7F ;parse volume spec A790 8D CA FD STA &FDCA ;store source volume A793 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg A796 20 7F AA JSR RA7F ;parse volume spec A799 8D CB FD STA &FDCB ;store destination volume A79C 98 TYA ;save GSINIT offset in Y A79D 48 PHA A79E 20 41 A7 JSR R741 ;set swapping and current disc flags A7A1 20 0A A5 JSR R50A ;get start and size of user memory A7A4 20 D3 A8 JSR R8D3 ;print "Copying from drive " A7A7 EQUS "Copying from drive " A7BA AD CA FD LDA &FDCA ;get source volume A7BD 20 B8 8E JSR PEB8 ;print volume spec in A A7C0 20 D3 A8 JSR R8D3 ;print " to drive " A7C3 EQUS " to drive " A7CD AD CB FD LDA &FDCB ;get destination volume A7D0 20 B8 8E JSR PEB8 ;print volume spec in A A7D3 20 69 84 JSR P469 ;print newline A7D6 68 PLA ;restore GSINIT offset to Y A7D7 A8 TAY A7D8 18 CLC A7D9 60 RTS .R7DA ;Increment and print BCD word A7DA F8 SED ;set decimal mode A7DB 18 CLC ;increment low byte A7DC A5 A8 LDA &A8 A7DE 69 01 ADC #&01 ;only ADC and SBC have decimal mode A7E0 85 A8 STA &A8 ;carry out in C, the only valid flag A7E2 A5 A9 LDA &A9 ;carry out to high byte A7E4 69 00 ADC #&00 A7E6 85 A9 STA &A9 A7E8 D8 CLD ;clear decimal mode .R7E9 ;Print space-padded hex word A7E9 18 CLC ;set C=1, pad numeric field with spaces A7EA A5 A9 LDA &A9 ;[D]get high byte of word A7EC 20 00 A8 JSR R800 ;print hex byte, C=0 if space-padded A7EF B0 01 BCS R7F2 ;c=digit printed; preserve over entry point .R7F1 ;Print space-padded hex byte A7F1 18 CLC .R7F2 ;Print hex byte, C=0 if space-padded A7F2 A5 A8 LDA &A8 ;get low byte of word A7F4 D0 0A BNE R800 ;if non-zero then print it A7F6 B0 08 BCS R800 ;else if not space-padded then print zeroes A7F8 20 18 A8 JSR R818 ;else print a space A7FB A9 00 LDA #&00 ;(redundant) A7FD 4C 80 A9 JMP R980 ;and print hex nibble (0). .R800 ;Print hex byte, C=0 if space-padded A800 48 PHA A801 08 PHP ;save space padding flag in C A802 20 9E A9 JSR R99E ;shift A right 4 places A805 28 PLP ;restore C A806 20 0A A8 JSR R80A ;print top nibble of byte A809 68 PLA ;restore bottom nibble: .R80A ;Print space-padded hex nibble A80A 48 PHA ;test accumulator, Z=1 if zero A80B 68 PLA A80C B0 02 BCS R810 ;if digit has been printed print another A80E F0 08 BEQ R818 ;else if nibble is zero print a space .R810 A810 20 80 A9 JSR R980 ;else print hex nibble A813 38 SEC ;set C=1 to suppress space padding A814 60 RTS ;and exit .R815 ;Print two spaces A815 20 18 A8 JSR R818 .R818 ;Print a space A818 48 PHA ;preserve A A819 A9 20 LDA #&20 A81B 20 51 A9 JSR R951 ;print character in A (OSASCI) A81E 68 PLA A81F 18 CLC ;return C=0 A820 60 RTS .R821 ;Claim service call and set up argument ptr A821 BA TSX A822 A9 00 LDA #&00 ;have A=0 returned on exit A824 9D 07 01 STA &0107,X A827 98 TYA ;save string offset A828 48 PHA A829 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg A82C 68 PLA ;restore string offset A82D A8 TAY ;(redundant) A82E 98 TYA ;set XY to GSINIT pointer + Y [D]vestigial ep A82F 18 CLC ;add Y to LSB of GSINIT pointer A830 65 F2 ADC &F2 A832 AA TAX ;hold in X A833 A5 F3 LDA &F3 ;carry out to high byte of GSINIT pointer A835 69 00 ADC #&00 A837 A8 TAY ;hold in Y .R838 ;Clear private pointer A838 A9 00 LDA #&00 ;[D]new entry point A83A 85 A8 STA &A8 A83C 85 A9 STA &A9 A83E 60 RTS .R83F ;Have A=0 returned on exit A83F 48 PHA ;caller called Save AXY, A was at &0105,S A840 8A TXA ;save caller's AX A841 48 PHA ;these two bytes plus return address make 4 A842 BA TSX ;superroutine's A is thus 5+4 = 9 bytes down A843 A9 00 LDA #&00 A845 9D 09 01 STA &0109,X A848 68 PLA ;restore caller's AX A849 AA TAX A84A 68 PLA A84B 60 RTS #if defined _TURBO .R84C ;Save AXY A84C 48 PHA ;stack = &4F,&A8,a,cl,ch,sl,sh A84D 20 56 A8 JSR R856 ;return to caller,RTS jumps to next line .R850 ;Restore AXY and return to superroutine A850 68 PLA ;stack = y,x,a,sl,sh A851 A8 TAY ;cl,ch=caller return address A852 68 PLA ;sl,sh=superroutine return address A853 AA TAX A854 68 PLA A855 60 RTS .R856 ;Poke AXY into stack, return to caller A856 48 PHA A857 48 PHA A858 48 PHA A859 8A TXA A85A 48 PHA A85B BA TSX ;stack = x,a,a,a,&4F,&A8,a,cl,ch,sl,sh A85C BD 09 01 LDA &0109,X ;caller address high byte A85F 9D 04 01 STA &0104,X A862 BD 08 01 LDA &0108,X ;caller address low byte A865 9D 03 01 STA &0103,X A868 BD 07 01 LDA &0107,X ;A on entry A86B 9D 09 01 STA &0109,X A86E 98 TYA ;Y on entry A86F 9D 07 01 STA &0107,X ;stack = x,a,cl,ch,&4F,&A8,y,cl,a,sl,sh A872 68 PLA ;X on entry A873 9D 08 01 STA &0108,X ;stack = a,cl,ch,&4F,&A8,y,x,a,sl,sh A876 AA TAX A877 68 PLA ;restore A on entry A878 60 RTS ;return to caller .R879 ;Save XY A879 48 PHA ;stack = &7C,&A8,a,cl,ch,sl,sh A87A 20 56 A8 JSR R856 ;return to caller,RTS jumps to next line A87D BA TSX A87E 9D 03 01 STA &0103,X ;replace A on entry with A from caller A881 4C 50 A8 JMP R850 ;restore AXY and return to superroutine #else /* _TURBO */ .R84C ;Save AXY A84C 48 PHA ;stack = &6E,&A8,y,x,a,cl,ch,sl,sh A84D 8A TXA ;cl,ch=caller return address A84E 48 PHA ;sl,sh=superroutine return address A84F 98 TYA A850 48 PHA A851 A9 A8 LDA #&A8 A853 48 PHA A854 A9 6E LDA #&6E A856 48 PHA .R857 A857 A0 05 LDY #&05 ;duplicate y,x,a,cl,ch .R859 A859 BA TSX A85A BD 07 01 LDA &0107,X A85D 48 PHA A85E 88 DEY A85F D0 F8 BNE R859 A861 A0 0A LDY #&0A ;copy top 10 bytes down 2 places: .R863 A863 BD 09 01 LDA &0109,X ;overwrite bottom copy of cl,ch A866 9D 0B 01 STA &010B,X A869 CA DEX A86A 88 DEY ;stack now contains: A86B D0 F6 BNE R863 ;y,x,y,x,a,cl,ch,&6E,&A8,y,x,a,sl,sh A86D 68 PLA ;discard y,x: A86E 68 PLA .R86F ;Restore AXY and return A86F 68 PLA A870 A8 TAY A871 68 PLA A872 AA TAX A873 68 PLA A874 60 RTS .R875 ;Save XY A875 48 PHA ;push y,x,a A876 8A TXA A877 48 PHA A878 98 TYA A879 48 PHA A87A 20 57 A8 JSR R857 ;restack then "call" rest of caller's routine! A87D BA TSX ;get stack pointer A87E 9D 03 01 STA &0103,X ;store A on exit from caller in stack: A881 4C 6F A8 JMP R86F ;restore y,x on entry, a on exit. #endif /* _TURBO */ .R884 ;Raise "Disk read only" error A884 20 92 A8 JSR R892 A887 EQUB &C9 A888 EQUS "read only" A891 EQUB &00 .R892 ;Raise "Disk " error A892 20 D0 A8 JSR R8D0 A895 EQUS "Disk " A89A 90 11 BCC R8AD .R89C ;Raise "Bad " error A89C 20 D0 A8 JSR R8D0 A89F EQUS "Bad " A8A3 90 08 BCC R8AD .R8A5 ;Raise "File " error A8A5 20 D0 A8 JSR R8D0 A8A8 EQUS "File " .R8AD ;Append error message immediate A8AD 85 B3 STA &B3 ;save A on entry A8AF 68 PLA ;pop caller's address into pointer A8B0 85 AE STA &AE A8B2 68 PLA A8B3 85 AF STA &AF A8B5 A5 B3 LDA &B3 ;restore A on entry and save on stack A8B7 48 PHA A8B8 98 TYA ;save Y A8B9 48 PHA A8BA A0 00 LDY #&00 ;set Y=0 for indirect indexed load A8BC 20 EB A9 JSR R9EB ;increment &AE,F A8BF B1 AE LDA (&AE),Y ;get error number from byte after JSR A8C1 8D 01 01 STA &0101 ;store at bottom of stack A8C4 20 40 A9 JSR R940 ;[D]if error message already being built A8C7 30 19 BMI R8E2 ;then complete it A8C9 A9 02 LDA #&02 ;else A = &02 A8CB 8D 00 01 STA &0100 ;error message being built from offset 2 A8CE D0 12 BNE R8E2 ;build error message (always) .R8D0 ;Prefix error message immediate A8D0 20 3B A9 JSR R93B ;[D]begin error message .R8D3 ;Print string immediate A8D3 85 B3 STA &B3 ;save A on entry A8D5 68 PLA ;pop caller's address into pointer A8D6 85 AE STA &AE A8D8 68 PLA A8D9 85 AF STA &AF A8DB A5 B3 LDA &B3 ;restore A on entry and save on stack A8DD 48 PHA A8DE 98 TYA ;save Y A8DF 48 PHA A8E0 A0 00 LDY #&00 ;set Y=0 for indirect indexed load: .R8E2 A8E2 20 EB A9 JSR R9EB ;increment &AE,F A8E5 B1 AE LDA (&AE),Y ;get character from after JSR A8E7 30 08 BMI R8F1 ;if b7=1 then opcode terminator, execute it A8E9 F0 0D BEQ R8F8 ;else if NUL then raise error A8EB 20 51 A9 JSR R951 ;else print the character A8EE 4C E2 A8 JMP R8E2 ;and loop .R8F1 A8F1 68 PLA ;restore AY A8F2 A8 TAY A8F3 68 PLA A8F4 18 CLC A8F5 6C AE 00 JMP (&00AE) ;jump to address of end of string .R8F8 ;Terminate error message, raise error A8F8 A9 00 LDA #&00 A8FA AE 00 01 LDX &0100 ;get offset of end of error message A8FD 9D 00 01 STA &0100,X ;set NUL error message terminator A900 8D 00 01 STA &0100 ;instruction at &0100 = BRK A903 20 19 82 JSR P219 ;get Challenger unit type A906 29 7F AND #&7F ;b7=0 A908 9D F0 0D STA &0DF0,X ;no error message being built print to screen A90B 20 53 97 JSR Q753 ;forget catalogue in JIM pages 2..3 A90E 20 F3 96 JSR Q6F3 ;release Tube if present A911 20 71 AD JSR RD71 ;release NMI A914 4C 00 01 JMP &0100 ;jump to BRK to raise error .R917 ;Print VDU sequence immediate A917 68 PLA ;pop caller's address into pointer A918 85 AE STA &AE A91A 68 PLA A91B 85 AF STA &AF A91D 98 TYA ;[D]save Y A91E 48 PHA A91F A0 00 LDY #&00 ;offset = 0 for indirect indexed load .R921 A921 20 EB A9 JSR R9EB ;increment &AE,F A924 B1 AE LDA (&AE),Y ;get character from after JSR A926 C9 FF CMP #&FF ;if &FF terminator byte A928 F0 06 BEQ R930 ;then skip it and return to code after it A92A 20 EE FF JSR &FFEE ;else call OSWRCH A92D 4C 21 A9 JMP R921 ;and loop .R930 A930 68 PLA ;[D]restore Y A931 A8 TAY .R932 A932 20 EB A9 JSR R9EB ;increment &AE,F A935 6C AE 00 JMP (&00AE) ;jump to address at end of string .R938 ;Begin error message, number in A A938 8D 01 01 STA &0101 ;set first byte after BRK to error number .R93B ;Begin error message A93B A9 02 LDA #&02 A93D 8D 00 01 STA &0100 ;error message being built from offset 2 .R940 A940 20 19 82 JSR P219 ;get Challenger unit type A943 08 PHP A944 09 80 ORA #&80 ;b7=1 A946 9D F0 0D STA &0DF0,X ;error message being built, &0100 = offset A949 28 PLP A94A 60 RTS .R94B ;Print letter N A94B A9 4E LDA #&4E A94D D0 02 BNE R951 ;branch (always) .R94F ;Print a dot A94F A9 2E LDA #&2E .R951 ;Print character in A (OSASCI) A951 20 4C A8 JSR R84C ;save AXY A954 48 PHA ;save character A955 20 19 82 JSR P219 ;[D]get Chal. unit type. if error being built A958 30 13 BMI R96D ;then append character to error message else: A95A 20 DC AD JSR RDDC ;call OSBYTE &EC = read/write char dest status A95D 8A TXA ;save current output stream setting A95E 48 PHA A95F 09 10 ORA #&10 ;b4=1 disable *SPOOL output A961 20 D7 AD JSR RDD7 ;call OSBYTE &03 = specify output stream in A A964 68 PLA ;restore previous output stream setting A965 AA TAX A966 68 PLA ;restore character A967 20 E3 FF JSR &FFE3 ;call OSASCI A96A 4C D8 AD JMP RDD8 ;call OSBYTE &03 = specify output stream .R96D ;Append character to error message A96D 68 PLA ;[D]restore character A96E AE 00 01 LDX &0100 ;get pointer to end of error message A971 9D 00 01 STA &0100,X ;store character there A974 EE 00 01 INC &0100 ;and increment pointer A977 60 RTS .R978 ;Print hex byte A978 48 PHA ;save A A979 20 9E A9 JSR R99E ;shift A right 4 places A97C 20 80 A9 JSR R980 ;print top nibble of byte A97F 68 PLA ;restore bottom nibble: .R980 ;Print hex nibble A980 48 PHA ;save A A981 29 0F AND #&0F ;extract b3..0 A983 F8 SED ;set decimal mode for 6502 deep magic A984 18 CLC A985 69 90 ADC #&90 ;a=&90..99, C=0 or A=&00..05, C=1 A987 69 40 ADC #&40 ;a=&30..39 or A=&41..46 A989 D8 CLD ;clear decimal mode A98A 20 51 A9 JSR R951 ;print character in A (OSASCI) A98D 68 PLA ;restore A A98E 60 RTS .R98F ;Acknowledge ESCAPE condition A98F A9 7E LDA #&7E ;OSBYTE &7E = acknowledge ESCAPE condition A991 4C F4 FF JMP &FFF4 ;call OSBYTE and exit .R994 ;Extract b7,b6 of A A994 4A LSR A A995 4A LSR A .R996 ;Extract b5,b4 of A A996 4A LSR A A997 4A LSR A .R998 ;Extract b3,b2 of A A998 4A LSR A A999 4A LSR A A99A 29 03 AND #&03 A99C 60 RTS .R99D ;Shift A right 5 places A99D 4A LSR A .R99E ;Shift A right 4 places A99E 4A LSR A A99F 4A LSR A A9A0 4A LSR A A9A1 4A LSR A A9A2 60 RTS ;unreachable code A9A3 0A ASL A .R9A4 ;Shift A left 4 places A9A4 0A ASL A A9A5 0A ASL A A9A6 0A ASL A A9A7 0A ASL A A9A8 60 RTS .R9A9 ;Add 8 to Y A9A9 C8 INY .R9AA ;Add 7 to Y A9AA C8 INY A9AB C8 INY A9AC C8 INY .R9AD ;Add 4 to Y A9AD C8 INY A9AE C8 INY A9AF C8 INY A9B0 C8 INY A9B1 60 RTS .R9B2 ;Subtract 8 from Y A9B2 88 DEY A9B3 88 DEY A9B4 88 DEY A9B5 88 DEY .R9B6 ;Subtract 4 from Y A9B6 88 DEY A9B7 88 DEY A9B8 88 DEY A9B9 88 DEY A9BA 60 RTS .R9BB ;Uppercase and validate letter in A A9BB C9 41 CMP #&41 ;is character less than capital A? A9BD 90 0C BCC R9CB ;if so then return C=1 A9BF C9 5B CMP #&5B ;else is it more than capital Z? A9C1 90 0A BCC R9CD ;if not then uppercase and return C=0 A9C3 C9 61 CMP #&61 ;else is it less than lowercase a? A9C5 90 04 BCC R9CB ;if so then return C=1 A9C7 C9 7B CMP #&7B ;else is it more than lowercase z? A9C9 90 02 BCC R9CD ;if not then uppercase and return C=0 .R9CB A9CB 38 SEC ;else return C=1 A9CC 60 RTS .R9CD A9CD 29 DF AND #&DF ;mask bit 5, convert letter to uppercase A9CF 18 CLC A9D0 60 RTS .R9D1 ;Set C=0 iff character in A is a letter A9D1 48 PHA A9D2 20 BB A9 JSR R9BB ;uppercase and validate letter in A A9D5 68 PLA A9D6 60 RTS ;This entry point was used only by *SROM, confirming Opus's assertion ;that DDOS's command set was the original from which Challenger deviated. ;[D]unreachable code A9D7 20 E1 A9 JSR R9E1 A9DA 90 03 BCC R9DF A9DC C9 10 CMP #&10 A9DE 60 RTS .R9DF ;[D]unreachable code A9DF 38 SEC A9E0 60 RTS .R9E1 ;Convert ASCII hex digit to binary A9E1 C9 41 CMP #&41 ;if digit is less than A A9E3 90 02 BCC R9E7 ;then convert 0..9 to binary A9E5 E9 07 SBC #&07 ;else convert A..F to binary .R9E7 A9E7 38 SEC A9E8 E9 30 SBC #&30 A9EA 60 RTS .R9EB ;Increment &AE,F A9EB E6 AE INC &AE A9ED D0 02 BNE R9F1 A9EF E6 AF INC &AF .R9F1 A9F1 60 RTS .R9F2 ;Call GSINIT with C=0 A9F2 18 CLC ;c=0 space or CR terminates unquoted strings A9F3 4C C2 FF JMP &FFC2 ;jump to GSINIT .R9F6 ;Set current drive from ASCII digit A9F6 20 BA AA JSR RABA ;convert and validate ASCII drive digit #if defined _BUGFIX A9F9 10 25 BPL RA20 ;set as current drive .R9FB ;Set volume from ASCII letter A9FB 20 BB A9 JSR R9BB ;uppercase and validate letter in A A9FE 38 SEC ;subtract ASCII value of A A9FF E9 41 SBC #&41 ;obtain ordinal 0..25 AA01 90 20 BCC RA23 ;if ordinal negative then "Bad drive" AA03 C9 08 CMP #&08 ;else is ordinal 8 or more? AA05 B0 1C BCS RA23 ;if so then raise "Bad drive" error AA07 20 A4 A9 JSR R9A4 ;else shift A left 4 places AA0A 05 CF ORA &CF ;combine volume letter with current drive AA0C 90 12 BCC RA20 ;set as current volume, return C=0 .RA0E ;Parse volume spec from argument AA0E 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 AA11 F0 0A BEQ RA1D ;if no argument then current vol = default AA13 D0 6A BNE RA7F ;else parse volume spec .RA15 ;Set current volume and directory = default AA15 20 0C BE JSR SE0C ;page in main workspace AA18 AD C6 FD LDA &FDC6 ;get default directory AA1B 85 CE STA &CE ;set as current directory: .RA1D ;Set current volume = default volume AA1D AD C7 FD LDA &FDC7 ;get default volume .RA20 AA20 85 CF STA &CF ;set as current volume AA22 60 RTS .RA23 ;Raise "Bad drive" error AA23 20 9C A8 JSR R89C AA26 EQUB &CD AA27 EQUS "drive" AA2C EQUB &00 ;.RA2D ;OSARGS A=1, Y>0 AA2D 20 D8 9B JSR QBD8 ;set PTR = request AA30 20 4C A8 JSR R84C ;save AXY again .RA33 AA33 20 9B 9C JSR QC9B ;ensure file handle valid and open AA36 A9 EF LDA #&EF ;b4=0 EOF warning flag clear AA38 4C 37 9D JMP QD37 ;clear channel flag bits .RA3B ;Call GSINIT and parse directory spec AA3B 20 F2 A9 JSR R9F2 ;call GSINIT with C=0, fall through: #else /* _BUGFIX */ A9F9 85 CF STA &CF ;set as current drive A9FB 60 RTS .R9FC ;Set volume from ASCII letter A9FC 20 BB A9 JSR R9BB ;uppercase and validate letter in A A9FF 38 SEC ;subtract ASCII value of A AA00 E9 41 SBC #&41 ;obtain ordinal 0..25 AA02 90 30 BCC RA34 ;if ordinal negative then "Bad drive" AA04 C9 08 CMP #&08 ;else is ordinal 8 or more? AA06 B0 2C BCS RA34 ;if so then raise "Bad drive" error AA08 20 A4 A9 JSR R9A4 ;else shift A left 4 places AA0B 05 CF ORA &CF ;combine volume letter with current drive AA0D 85 CF STA &CF ;set as current volume, return C=0 AA0F 60 RTS ;[D]unreachable code ;Call GSINIT and parse mandatory vol spec AA10 20 65 A5 JSR R565 ;call GSINIT with C=0 and reject empty arg AA13 4C 7F AA JMP RA7F ;parse volume spec .RA16 ;Parse volume spec from argument AA16 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 AA19 F0 0B BEQ RA26 ;if no argument then current vol = default AA1B 4C 7F AA JMP RA7F ;else parse volume spec .RA1E ;Set current volume and directory = default AA1E 20 0C BE JSR SE0C ;page in main workspace AA21 AD C6 FD LDA &FDC6 ;get default directory AA24 85 CE STA &CE ;set as current directory: .RA26 ;Set current volume = default volume AA26 AD C7 FD LDA &FDC7 ;get default volume AA29 85 CF STA &CF ;set as current volume .RA2B AA2B 60 RTS ;unreachable code AA2C 20 16 AA JSR RA16 AA2F 20 F2 A9 JSR R9F2 AA32 F0 F7 BEQ RA2B .RA34 ;Raise "Bad drive" error AA34 20 9C A8 JSR R89C AA37 EQUB &CD AA38 EQUS "drive" AA3D EQUB &00 #endif /* _BUGFIX */ .RA3E ;Parse directory spec AA3E 20 C5 FF JSR &FFC5 ;call GSREAD AA41 B0 2E BCS RA71 ;if end of argument then exit C=1 AA43 C9 3A CMP #&3A ;else is character a colon? AA45 D0 22 BNE RA69 ;if not then accept directory character AA47 20 C5 FF JSR &FFC5 ;else call GSREAD #if defined _BUGFIX AA4A B0 D7 BCS RA23 ;if ":" by itself then "Bad drive" error #else AA4A B0 E8 BCS RA34 ;if ":" by itself then "Bad drive" error #endif AA4C 20 F6 A9 JSR R9F6 ;else set current drive from ASCII digit AA4F 20 C5 FF JSR &FFC5 ;call GSREAD AA52 B0 1D BCS RA71 ;if ":<drv>" keep current volume and dir AA54 C9 2E CMP #&2E ;else is character a full stop? AA56 F0 0C BEQ RA64 ;if so then expect a directory character #if defined _BUGFIX AA58 20 FB A9 JSR R9FB ;else set volume from ASCII letter AA5B 20 C5 FF JSR &FFC5 ;call GSREAD AA5E B0 11 BCS RA71 ;if ":<drv><vol>" keep current directory AA60 C9 2E CMP #&2E ;else ".<dir>" must follow AA62 D0 BF BNE RA23 ;if next char not full stop "Bad drive" .RA64 AA64 20 C5 FF JSR &FFC5 ;else call GSREAD AA67 B0 BA BCS RA23 ;directory char expected else "Bad drive" .RA69 AA69 20 B0 AA JSR RAB0 ;set directory from ASCII character AA6C 20 C5 FF JSR &FFC5 ;if not at end of argument AA6F 90 B2 BCC RA23 ;then raise "Bad drive" error. #else /* _BUGFIX */ AA58 20 FC A9 JSR R9FC ;else set volume from ASCII letter AA5B 20 C5 FF JSR &FFC5 ;call GSREAD AA5E B0 11 BCS RA71 ;if ":<drv><vol>" keep current directory AA60 C9 2E CMP #&2E ;else ".<dir>" must follow AA62 D0 D0 BNE RA34 ;if next char not full stop "Bad drive" .RA64 AA64 20 C5 FF JSR &FFC5 ;else call GSREAD AA67 B0 CB BCS RA34 ;directory char expected else "Bad drive" .RA69 AA69 20 B0 AA JSR RAB0 ;set directory from ASCII character AA6C 20 C5 FF JSR &FFC5 ;if not at end of argument AA6F 90 C3 BCC RA34 ;then raise "Bad drive" error. #endif /* _BUGFIX */ .RA71 AA71 60 RTS .RA72 ;Select specified or default volume #if defined _BUGFIX AA72 20 1D AA JSR RA1D ;set current volume = default volume #else AA72 20 26 AA JSR RA26 ;set current volume = default volume #endif AA75 A2 00 LDX #&00 ;x=0, nothing specified AA77 20 C5 FF JSR &FFC5 ;call GSREAD AA7A B0 F5 BCS RA71 ;if end of argument then exit C=1 AA7C 38 SEC ;else C=1, ambiguous vol spec allowed AA7D B0 07 BCS RA86 ;jump into parse volume spec .RA7F ;Parse volume spec AA7F A2 00 LDX #&00 ;x=0, nothing specified AA81 20 C5 FF JSR &FFC5 ;call GSREAD AA84 B0 EB BCS RA71 ;if end of argument then exit C=1 ;The ambiguity flag and this entry point are vestigial in DDOS. ;These features appeared simultaneously in DDOS 3.x5 revision 3.0 and in ;Challenger 1.00. Whereas DDOS retains its original *XCAT command, ;in Challenger the new code enables the *CAT * syntax which was probably ;copied from EDOS along with the extended *OPT settings. .RA86 AA86 08 PHP ;[D]else save ambiguity flag in C AA87 C9 3A CMP #&3A ;is character a colon? AA89 D0 05 BNE RA90 ;if not then set drive from digit AA8B 20 C5 FF JSR &FFC5 ;else call GSREAD #if defined _BUGFIX AA8E B0 93 BCS RA23 ;if ":" by itself then "Bad drive" error #else AA8E B0 A4 BCS RA34 ;if ":" by itself then "Bad drive" error #endif .RA90 AA90 20 F6 A9 JSR R9F6 ;set current drive from ASCII digit AA93 A2 02 LDX #&02 ;x=2, only drive specified AA95 20 C5 FF JSR &FFC5 ;call GSREAD AA98 B0 0F BCS RAA9 ;if no more chars return drive, volume=A AA9A 28 PLP ;[D]else restore ambig. flag, if not allowed AA9B 90 07 BCC RAA4 ;then set volume and return current volume AA9D C9 2A CMP #&2A ;[D]else is character an asterisk? if not AA9F D0 03 BNE RAA4 ;then set volume and return current volume AAA1 A2 83 LDX #&83 ;else X=&83, drive and ambiguous volume spec AAA3 60 RTS .RAA4 #if defined _BUGFIX AAA4 20 FB A9 JSR R9FB ;set volume letter from ASCII letter #else AAA4 20 FC A9 JSR R9FC ;set volume letter from ASCII letter #endif AAA7 E8 INX ;x=3, drive and volume specified AAA8 08 PHP ;push dummy flag .RAA9 AAA9 28 PLP ;discard ambiguity flag AAAA A5 CF LDA &CF ;get current volume and exit AAAC 60 RTS ;unreachable code AAAD 20 C5 FF JSR &FFC5 .RAB0 ;Set directory from ASCII character AAB0 C9 2A CMP #&2A ;make * an alias of # AAB2 D0 02 BNE RAB6 AAB4 A9 23 LDA #&23 .RAB6 AAB6 85 CE STA &CE ;set as current directory AAB8 18 CLC AAB9 60 RTS .RABA ;Convert and validate ASCII drive digit AABA 38 SEC ;convert to binary drive no. 0..3 AABB E9 30 SBC #&30 AABD 90 17 BCC RAD6 ;if invalid then raise "Bad drive" error AABF 48 PHA ;else save result AAC0 C9 08 CMP #&08 ;is it more than 8? AAC2 B0 12 BCS RAD6 ;then invalid as a logical drive, "Bad drive" AAC4 20 DB AA JSR RADB ;else map volume in A to physical volume AAC7 C9 05 CMP #&05 ;if not physical drive 5, the second RAM disc AAC9 D0 09 BNE RAD4 ;then accept digit AACB 20 19 82 JSR P219 ;else get Challenger unit type AACE 29 03 AND #&03 ;mask bits 1,0 AAD0 C9 02 CMP #&02 ;is a 512 KiB unit attached? AAD2 D0 02 BNE RAD6 ;if not then phys. drive 5 is a "Bad drive" .RAD4 AAD4 68 PLA ;else return logical drive number, N=0 AAD5 60 RTS .RAD6 #if defined _BUGFIX AAD6 4C 23 AA JMP RA23 ;raise "Bad drive" error #else AAD6 4C 34 AA JMP RA34 ;raise "Bad drive" error #endif .RAD9 ;Map current volume to physical volume AAD9 A5 CF LDA &CF ;get current volume: .RADB ;Map volume in A to physical volume #if defined _TURBO AADB 20 79 A8 JSR R879 ;save XY #else AADB 20 75 A8 JSR R875 ;save XY #endif AADE AA TAX ;hold volume in X AADF 29 F0 AND #&F0 ;mask volume letter in bits 6..4 AAE1 48 PHA ;save volume letter AAE2 8A TXA ;transfer complete volume to A AAE3 29 07 AND #&07 ;mask logical drive number in bits 2..0 AAE5 AA TAX ;transfer to X for use as index AAE6 20 07 BE JSR SE07 ;page in auxiliary workspace AAE9 BD 00 FD LDA &FD00,X ;look up physical drive for logical drive AAEC BA TSX ;transfer stack pointer to X AAED 1D 01 01 ORA &0101,X ;apply volume letter saved on top of stack AAF0 AA TAX ;hold result = volume on physical drive AAF1 68 PLA ;discard masked volume letter AAF2 8A TXA ;return physical volume in A AAF3 4C 0C BE JMP SE0C ;page in main workspace and exit ;can save 8 bytes by using ORA &FD00,X ;ChADFS ROM call 0 ;*CONFIG AAF6 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 AAF9 D0 36 BNE RB31 ;if argument present then parse it AAFB 20 D3 A8 JSR R8D3 ;else list mapping. Print "L drv:" AAFE EQUS "L drv:" AB04 A2 00 LDX #&00 ;start at logical drive 0: .RB06 AB06 8A TXA ;perform identity mapping to print log.drive AB07 20 90 AB JSR RB90 ;print digit and compare X=8 AB0A D0 FA BNE RB06 ;loop until logical drives 0..7 listed AB0C 20 D3 A8 JSR R8D3 ;print newline + "P drv:" AB0F EQUB &0D AB10 EQUS "P drv:" AB16 A2 00 LDX #&00 ;start at logical drive 0: .RB18 AB18 2C FF FD BIT &FDFF ;test b6=ChADFS is current FS AB1B 20 07 BE JSR SE07 ;page in auxiliary workspace AB1E BD 00 FD LDA &FD00,X ;preload Challenger physical drive mapping AB21 50 03 BVC RB26 ;if ChADFS is current FS AB23 BD 08 FD LDA &FD08,X ;then replace with ChADFS physical drive .RB26 AB26 20 0C BE JSR SE0C ;page in main workspace AB29 20 90 AB JSR RB90 ;print digit and compare X=8 AB2C D0 EA BNE RB18 ;loop until logical drives 0..7 listed AB2E 4C 69 84 JMP P469 ;print newline and exit .RB31 ;Parse *CONFIG argument AB31 C9 52 CMP #&52 ;if first character of argument is capital R AB33 F0 35 BEQ RB6A ;then reset drive mappings .RB35 AB35 20 C5 FF JSR &FFC5 ;else call GSREAD AB38 20 BA AA JSR RABA ;convert and validate ASCII drive digit AB3B 2C FF FD BIT &FDFF ;test b6=ChADFS is current FS AB3E 50 03 BVC RB43 ;if ChADFS is current FS AB40 18 CLC ;then add 8 to A making offset to ChADFS map: AB41 69 08 ADC #&08 .RB43 AB43 85 B0 STA &B0 ;save offset into drive mapping table AB45 20 C5 FF JSR &FFC5 ;call GSREAD AB48 B0 1D BCS RB67 ;if only log. drive given then "Syntax" error AB4A C9 3D CMP #&3D ;else is next character "="? AB4C D0 19 BNE RB67 ;if not then "Syntax" error AB4E 20 C5 FF JSR &FFC5 ;else "<drv>="; call GSREAD AB51 B0 14 BCS RB67 ;if no phys. drive given then "Syntax" error AB53 20 BA AA JSR RABA ;else convert and validate ASCII drive digit AB56 20 07 BE JSR SE07 ;page in auxiliary workspace AB59 A6 B0 LDX &B0 ;restore offset into drive mapping table AB5B 9D 00 FD STA &FD00,X ;save physical drive mapping in table AB5E 20 0C BE JSR SE0C ;page in main workspace AB61 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 AB64 D0 CF BNE RB35 ;if argument present then parse it AB66 60 RTS ;else exit (can string together e.g. 0=42=5) .RB67 AB67 4C 6B A5 JMP R56B ;raise "Syntax: " error .RB6A ;*CONFIG R AB6A 2C FF FD BIT &FDFF ;if b6=1 ChADFS is current FS AB6D 70 12 BVS RB81 ;then only reset ChADFS mapping, else: .RB6F ;Reset *CONFIG mapping AB6F 20 07 BE JSR SE07 ;page in auxiliary workspace AB72 A2 07 LDX #&07 ;loop for X = 7..0: .RB74 AB74 8A TXA AB75 9D 00 FD STA &FD00,X ;configure logical drive X = physical drive X AB78 CA DEX AB79 10 F9 BPL RB74 ;loop until all 8 drive mappings reset AB7B 4C 0C BE JMP SE0C ;page in main workspace and exit #if defined _PCH200 .RB7E #endif ;ChADFS ROM call 3 AB7E 20 6F AB JSR RB6F ;reset *CONFIG mapping .RB81 AB81 20 07 BE JSR SE07 ;page in auxiliary workspace AB84 A2 07 LDX #&07 ;loop for X = 7..0: .RB86 AB86 8A TXA ;configure ChADFS mapping drive X = drive X AB87 9D 08 FD STA &FD08,X AB8A CA DEX AB8B 10 F9 BPL RB86 ;loop until all 8 drive mappings reset AB8D 4C 0C BE JMP SE0C ;page in main workspace and exit .RB90 AB90 20 18 A8 JSR R818 ;print a space AB93 20 80 A9 JSR R980 ;print hex nibble AB96 E8 INX ;increment counter AB97 E0 08 CPX #&08 ;return Z=1 iff counter has reached 8 AB99 60 RTS .RB9A ;Set current vol/dir from open filename AB9A 20 0C BE JSR SE0C AB9D B9 EF FC LDA &FCEF,Y ;get directory character of open file ABA0 29 7F AND #&7F ;mask off b7 =channel file locked bit ABA2 85 CE STA &CE ;set as current directory ABA4 B9 00 FD LDA &FD00,Y ;get volume containing open file ABA7 85 CF STA &CF ;set as current volume ABA9 B9 FF FC LDA &FCFF,Y ;[D]get first track of volume of open file ABAC 8D EC FD STA &FDEC ;set as first track of current volume ABAF B9 F4 FC LDA &FCF4,Y ;get packed drive parameters of open file ABB2 4C 0D 85 JMP P50D ;restore packed drive parameters and exit .RBB5 ;Detect disc format/set sector address ABB5 20 0C BE JSR SE0C ;page in main workspace ABB8 20 88 AD JSR RD88 ;claim NMI ABBB A9 00 LDA #&00 ABBD 85 BA STA &BA ;set track number = 0 ABBF 85 BB STA &BB ;[D]set sector number = 0 ABC1 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc ABC4 F0 5D BEQ RC23 ;[D]if not ABC6 20 16 B9 JSR S916 ;[D]then seek logical track ABC9 AD E9 FD LDA &FDE9 ;if data transfer call is not 0 = read data ABCC 29 7F AND #&7F ABCE D0 67 BNE RC37 ;then set sector number = 2 * volume letter ABD0 A9 00 LDA #&00 ;else data area starts on track 0 ABD2 8D EC FD STA &FDEC ABD5 20 46 AC JSR RC46 ;set number of sectors per track ABD8 2C ED FD BIT &FDED ;test density flag ABDB 70 03 BVS RBE0 ;if disc is single density ABDD 20 1A AC JSR RC1A ;[D]then ensure volume letter is A .RBE0 ABE0 2C EA FD BIT &FDEA ;if double-stepping is automatic ABE3 10 03 BPL RBE8 ABE5 20 5D AC JSR RC5D ;then detect track stepping .RBE8 ABE8 2C ED FD BIT &FDED ;if disc is single density ABEB 50 4A BVC RC37 ;then set sector number = 0 ABED 20 2E B5 JSR S52E ;else copy volume allocations to wksp ABF0 20 11 BE JSR SE11 ;page in catalogue sector 0 ABF3 AD 00 FD LDA &FD00 ;test configuration/version number ABF6 C9 E5 CMP #&E5 ;of disc catalogue ABF8 D0 03 BNE RBFD ;if byte is &E5 formatting fill byte ABFA 4C 9F AC JMP RC9F ;then "Disk not configured by VOLGEN" .RBFD ABFD 20 3C AC JSR RC3C ;set sector number = 2 * volume letter AC00 A8 TAY ;= offset into the track allocation table AC01 B9 08 FD LDA &FD08,Y ;get first track of volume from disc cat. AC04 AC 01 FD LDY &FD01 ;get MSB number of sectors on surface AC07 AE 02 FD LDX &FD02 ;get LSB number of sectors on surface AC0A 20 0C BE JSR SE0C ;page in main workspace AC0D 8E F6 FD STX &FDF6 ;save in workspace AC10 8C F5 FD STY &FDF5 AC13 8D EC FD STA &FDEC ;set as first track of current volume AC16 AA TAX AC17 F0 6B BEQ RC84 ;if =0 raise "Volume . n/a" error .RC19 AC19 60 RTS .RC1A ;Ensure volume letter is A AC1A A5 CF LDA &CF ;get current volume AC1C 29 F0 AND #&F0 ;extract volume letter AC1E F0 F9 BEQ RC19 ;if volume letter is not A #if defined _BUGFIX AC20 4C 23 AA JMP RA23 ;then raise "Bad drive" error #else AC20 4C 34 AA JMP RA34 ;then raise "Bad drive" error #endif .RC23 ;Set up for RAM disc AC23 20 1A AC JSR RC1A ;ensure volume letter is A AC26 AD ED FD LDA &FDED ;set density flag to single density AC29 29 80 AND #&80 ;preserving automatic density setting AC2B 8D ED FD STA &FDED AC2E A9 00 LDA #&00 AC30 8D EB FD STA &FDEB ;number of sectors per track is undefined AC33 8D EC FD STA &FDEC ;data area starts on track 0 AC36 60 RTS .RC37 ;Set sector number = 2 * volume letter AC37 AD ED FD LDA &FDED ;test density flag AC3A F0 07 BEQ RC43 ;if single (and manual!) then start sector =0 .RC3C AC3C A5 CF LDA &CF ;else get current volume AC3E 29 F0 AND #&F0 ;extract volume letter AC40 4A LSR A ;shift right three places AC41 4A LSR A ;to get sector offset of volume catalogue AC42 4A LSR A .RC43 AC43 85 BB STA &BB ;set as sector number AC45 60 RTS .RC46 ;Set number of sectors per track AC46 2C ED FD BIT &FDED ;if density setting is automatic AC49 30 0A BMI RC55 ;then ensure disc is formatted AC4B A9 0A LDA #&0A ;else set 10 sectors per track AC4D 50 02 BVC RC51 ;unless disc is double density AC4F A9 12 LDA #&12 ;in which case set 18 sectors per track .RC51 AC51 8D EB FD STA &FDEB .RC54 AC54 60 RTS .RC55 ;Ensure disc is formatted AC55 20 5F B9 JSR S95F ;read ID and detect density AC58 F0 FA BEQ RC54 ;if record found then exit AC5A 4C E3 BC JMP SCE3 ;else raise "Disk not formatted" error. .RC5D ;Detect track stepping AC5D A9 00 LDA #&00 ;[D]b7=0 manual, b6=0 1:1 stepping AC5F 8D EA FD STA &FDEA ;set stepping flag AC62 A9 02 LDA #&02 ;track number = 2 AC64 85 BA STA &BA AC66 20 B2 B9 JSR S9B2 ;execute Read Address command [D]no seek AC69 AE 0C 0D LDX &0D0C ;get C cylinder number AC6C A9 C0 LDA #&C0 AC6E CA DEX ;is it 1? AC6F F0 0B BEQ RC7C ;then disc is 40 track, set double stepping AC71 0A ASL A AC72 CA DEX ;else is it 2? AC73 F0 07 BEQ RC7C ;then 1:1 stepping is correct AC75 CA DEX ;else the format is wrong, raise an error AC76 CA DEX ;is the head over logical track 4? AC77 F0 34 BEQ RCAD ;[D]if so then raise "80 in 40" error AC79 4C AF BC JMP SCAF ;[D]else raise "Disk fault" error. .RC7C AC7C 8D EA FD STA &FDEA ;set stepping flag AC7F A9 00 LDA #&00 ;[D]track number = 0 AC81 85 BA STA &BA ;[D]no recalibration command here AC83 60 RTS .RC84 ;Raise "Volume . n/a" error AC84 20 AD A8 JSR R8AD ;begin error message "Volume " AC87 EQUB &CD AC88 EQUS "Volume " AC8F A5 BB LDA &BB ;transfer sector offset to A AC91 4A LSR A ;divide by 2; A=0..7, C=0 AC92 69 41 ADC #&41 ;convert to ASCII character "A".."H" AC94 20 51 A9 JSR R951 ;print character in A (to error message) AC97 20 D3 A8 JSR R8D3 ;print " n/a" and raise error AC9A EQUS " n/a" ;[D]short for "not allocated" AC9E EQUB &00 .RC9F AC9F 20 AD A8 JSR R8AD ACA2 EQUB &CD ACA3 EQUS "No config" ACAC EQUB &00 .RCAD ACAD 20 AD A8 JSR R8AD ACB0 EQUB &CD ACB1 EQUS "80 in 40" ACB9 EQUB &00 .RCBA ;Load disc catalogue L3 ACBA A9 80 LDA #&80 ;data transfer call &80 = read data to JIM ACBC AE A9 81 LDX &81A9 ;[D]ACBD=LDA #&81 .RCBD ;Write disc catalogue L3 ACBD A9 81 LDA #&81 ;data transfer call &81 = write data from JIM ACBF 20 0C BE JSR SE0C ;page in main workspace ACC2 8D E9 FD STA &FDE9 ;set data transfer call number ACC5 A2 03 LDX #&03 ;x = 3 number of attempts allowed: .RCC7 ACC7 20 A5 96 JSR Q6A5 ;set data pointer to &0200 ACCA A9 10 LDA #&10 ;set sector number = 16 ACCC 85 BB STA &BB ACCE A9 00 LDA #&00 ;set track number = 0 ACD0 85 BA STA &BA ACD2 85 A0 STA &A0 ;&0100 = 256 bytes to transfer ACD4 A9 01 LDA #&01 ACD6 85 A1 STA &A1 ACD8 20 18 BA JSR SA18 ;transfer data to disc L2 ACDB F0 06 BEQ RCE3 ;[D]if command succeeded then exit ACDD CA DEX ;else decrement attempts remaining ACDE D0 E7 BNE RCC7 ;if not run out then try again #if defined _BUGFIX .RCE0 #endif ACE0 4C AF BC JMP SCAF ;else raise "Disk fault" error .RCE3 ACE3 60 RTS .RCE4 ;Transfer data and report errors L4 ACE4 20 F0 AC JSR RCF0 ;transfer data L3 [D]AXY not saved ACE7 8D F3 FD STA &FDF3 ;store result of transfer #if defined _BUGFIX ACEA D0 F4 BNE RCE0 ;if result >0 then "Disk fault" ACEC A9 01 LDA #&01 ;else return A=&01 from OSFILE ACEE 60 #else ACEA D0 01 BNE RCED ;if result >0 then "Disk fault" else exit ACEC 60 RTS ;[D]no separate write protect error .RCED ACED 4C AF BC JMP SCAF ;raise "Disk fault" error #endif ;[BUG] OSFILE does not load or save files 64 KiB or larger to the RAM ;disc correctly. Only the requested length of data modulo 64 KiB ;(&10000 bytes) is transferred. The rest of the file is unread or ;undefined. Such calls are only relevant to large coprocessors. ;The RAM disc code transfers up to 64 KiB at a time between the RAM disc ;and user memory. Files on the RAM disc are treated specially here and ;moved in a single operation. They can't be split into 'tracks' to ;work around the limit because the RAM code has different variables at ;locations &A0..7 which the floppy-oriented track advance code would ;clobber. This only matters when saving and loading files to a large ;coprocessor (using OSFILE). Just use OSFIND and OSGBPB instead. .RCF0 ;Transfer data L3 #if defined _TURBO ACF0 20 79 A8 JSR R879 ;save XY #else ACF0 20 75 A8 JSR R875 ;save XY #endif ACF3 A9 80 LDA #&80 ACF5 85 B9 STA &B9 ;>0 disc operation is interruptible ACF7 A0 03 LDY #&03 ;set attempt counter to 3 .RCF9 ACF9 AD EB FD LDA &FDEB ;get number of sectors per track ACFC 08 PHP ;save Z flag ACFD A6 A3 LDX &A3 ;set X=LSB byte count ACFF A5 A4 LDA &A4 ;set A=2MSB byte count AD01 28 PLP ;restore Z flag AD02 F0 18 BEQ RD1C ;if 0 sectors per track then RAM disc, branch AD04 38 SEC ;else subtract AD05 AD EB FD LDA &FDEB ;number of sectors per track AD08 E5 BB SBC &BB ;- starting sector AD0A 85 A0 STA &A0 ;= sectors until end, store temp AD0C A5 A5 LDA &A5 ;test MSB byte count AD0E D0 08 BNE RD18 ;if >=64 KiB then transfer rest of track AD10 A6 A3 LDX &A3 ;else X=LSB byte count (redundant to &ACFD) AD12 A5 A4 LDA &A4 ;set A=2MSB byte count AD14 C5 A0 CMP &A0 ;if transfer ends before end of track AD16 90 04 BCC RD1C ;then only transfer byte count, else: .RD18 ;transfer rest of track AD18 A2 00 LDX #&00 ;X=0 byte count is a multiple of 256 AD1A A5 A0 LDA &A0 ;A=number of sectors (not bytes) to transfer: .RD1C AD1C 86 A0 STX &A0 ;store LSB byte count AD1E 85 A1 STA &A1 ;store MSB byte count AD20 05 A0 ORA &A0 ;test if byte count > 0 AD22 F0 47 BEQ RD6B ;if no data to transfer then finish AD24 AD EB FD LDA &FDEB ;[D]else test number of sectors per track AD27 F0 0C BEQ RD35 ;if 0 sectors per track then RAM disc, branch AD29 38 SEC ;else subtract AD2A A5 BA LDA &BA ;track number AD2C E9 50 SBC #&50 ;- 80 AD2E 90 05 BCC RD35 ;if track number in range 0..79 then proceed AD30 85 BA STA &BA ;else set new track number 80 less AD32 20 9B AD JSR RD9B ;select side 2 of current drive. .RD35 AD35 20 18 BA JSR SA18 ;transfer data L2 AD38 D0 32 BNE RD6C ;if non-zero status then try again AD3A E6 BA INC &BA ;else increment track AD3C 85 BB STA &BB ;next transfer starts at sector 0 AD3E A6 A1 LDX &A1 ;x = ?&A1 = MSB number of bytes transferred AD40 A5 A0 LDA &A0 ;a = ?&A0 = LSB number of bytes transferred AD42 2C E9 FD BIT &FDE9 ;test data transfer call number AD45 10 03 BPL RD4A ;if b7=1, transferring to JIM AD47 8A TXA ;then a = ?&A1 = number of pages AD48 A2 00 LDX #&00 ;x = 0, less than 64 KiB transferred .RD4A AD4A 18 CLC ;add expected transfer size to xfer. address AD4B 65 A6 ADC &A6 ;(byte address in CPU space, AD4D 85 A6 STA &A6 ;page address in JIM space) AD4F 8A TXA AD50 65 A7 ADC &A7 AD52 85 A7 STA &A7 AD54 38 SEC ;subtract expected transfer size AD55 A5 A3 LDA &A3 ;from 24-bit byte count AD57 E5 A0 SBC &A0 AD59 85 A3 STA &A3 AD5B A5 A4 LDA &A4 AD5D E5 A1 SBC &A1 AD5F 85 A4 STA &A4 AD61 B0 02 BCS RD65 AD63 C6 A5 DEC &A5 .RD65 AD65 05 A3 ORA &A3 ;test remaining no. bytes to transfer AD67 05 A5 ORA &A5 ;if no more data to transfer then finish AD69 D0 8E BNE RCF9 ;else loop to transfer rest of file. .RD6B AD6B 60 RTS .RD6C AD6C 88 DEY ;decrement attempt counter AD6D D0 8A BNE RCF9 ;if not tried 3 times then try again AD6F A8 TAY ;else Y=A=status>0, return Z=0 AD70 60 RTS .RD71 ;Release NMI AD71 AD DD FD LDA &FDDD ;if NMI is not already ours AD74 10 0C BPL RD82 ;then exit AD76 C9 FF CMP #&FF ;if Y=&FF no previous owner AD78 F0 08 BEQ RD82 ;then skip release call [BUG]improper! AD7A 29 7F AND #&7F ;else Y = ID of previous NMI owner AD7C A8 TAY AD7D A2 0B LDX #&0B ;service call &0B = NMI release AD7F 20 EC AD JSR RDEC ;call OSBYTE &8F = issue service call .RD82 AD82 A9 00 LDA #&00 AD84 8D DD FD STA &FDDD ;&00 = NMI not ours, no previous owner AD87 60 RTS .RD88 ;Claim NMI AD88 2C DD FD BIT &FDDD ;if NMI is already ours AD8B 30 0D BMI RD9A ;then exit AD8D A9 8F LDA #&8F ;else OSBYTE &8F = issue service call AD8F A2 0C LDX #&0C ;service call &0C = claim NMI AD91 20 F4 AD JSR RDF4 ;call OSBYTE with Y=&FF AD94 98 TYA ;save ID of previous NMI owner AD95 09 80 ORA #&80 ;[D]set b7=1 to show we own the NMI AD97 8D DD FD STA &FDDD ;set NMI ownership flag/previous owner .RD9A AD9A 60 RTS ;[BUG]NMI claimant IDs with b7=1 get usurped .RD9B ;Select side 2 of current drive AD9B 20 D9 AA JSR RAD9 ;map current drive to physical drive AD9E AA TAX ;transfer to X for use as index AD9F 20 07 BE JSR SE07 ;page in auxiliary workspace ADA2 BD B7 AD LDA &ADB7,X ;look up side 2 of physical drive ADA5 A2 07 LDX #&07 ;loop for logical drives 7..0: .RDA7 ADA7 DD 00 FD CMP &FD00,X ;does this drive map to the drive we want? ADAA F0 06 BEQ RDB2 ;if so then set current logical drive ADAC CA DEX ;else try next logical drive ADAD 10 F8 BPL RDA7 ;loop until all 8 logical drives tested #if defined _BUGFIX ADAF 4C 23 AA JMP RA23 ;if physical drive not mapped "Bad drive" #else ADAF 4C 34 AA JMP RA34 ;if physical drive not mapped "Bad drive" #endif .RDB2 ADB2 86 CF STX &CF ;else set current drive = logical drive ADB4 4C 0C BE JMP SE0C ;page in main workspace and exit ;Side 2 of physical drives 0..4 ADB7 EQUB &02 ADB8 EQUB &03 ADB9 EQUB &FF ;invalid, raise "Bad drive" error ADBA EQUB &FF ;invalid, raise "Bad drive" error ADBB EQUB &05 ;next three bytes more than 7, invalid physical drives ;[BUG]if auxiliary workspace is not initialised the map bytes can be &FF ;routine redundant to S905 #if !defined _BUGFIX .RDBC ;Test write protect state of current drive #endif ADBC 20 D9 AA JSR RAD9 ;map current drive to physical drive ADBF 4C 05 B9 JMP S905 ;test write protect state of current drive .RDC2 ;Flush input buffer ADC2 20 4C A8 JSR R84C ;save AXY ADC5 A9 0F LDA #&0F ;OSBYTE &0F = flush selected buffer class ADC7 A2 01 LDX #&01 ;x = &01 flush input buffer only ADC9 D0 08 BNE RDD3 ;call OSBYTE with Y=&00 ;unreachable code ADCB A9 81 LDA #&81 ;OSBYTE &81 = read key within time limit ADCD D0 02 BNE RDD1 ;unreachable code ADCF A9 C7 LDA #&C7 ;OSBYTE &C7 = read/write *SPOOL handle .RDD1 ;Call OSBYTE with X=&00, Y=&00 ADD1 A2 00 LDX #&00 .RDD3 ;Call OSBYTE with Y=&00 ADD3 A0 00 LDY #&00 ADD5 F0 1F BEQ RDF6 .RDD7 ADD7 AA TAX ;Call OSBYTE &03 = specify output stream in A .RDD8 ADD8 A9 03 LDA #&03 ;Call OSBYTE &03 = specify output stream ADDA D0 1A BNE RDF6 .RDDC ;Call OSBYTE &EC = read/write char dest status ADDC A9 EC LDA #&EC ADDE D0 12 BNE RDF2 ;unreachable code ADE0 A9 C7 LDA #&C7 ;OSBYTE &C7 = read/write *SPOOL handle ADE2 D0 0E BNE RDF2 .RDE4 ;Call OSBYTE &EA = read Tube presence flag ADE4 A9 EA LDA #&EA ADE6 D0 0A BNE RDF2 .RDE8 ;Call OSBYTE &A8 = get ext. vector table addr ADE8 A9 A8 LDA #&A8 ADEA D0 06 BNE RDF2 .RDEC ;Call OSBYTE &8F = issue service call ADEC A9 8F LDA #&8F ADEE D0 06 BNE RDF6 .RDF0 ;Call OSBYTE &FF = read/write startup options ADF0 A9 FF LDA #&FF .RDF2 ;Call OSBYTE with X=&00, Y=&FF ADF2 A2 00 LDX #&00 .RDF4 ;Call OSBYTE with Y=&FF ADF4 A0 FF LDY #&FF .RDF6 ;Call OSBYTE ADF6 4C F4 FF JMP &FFF4 ;Table of addresses of extended vector handlers ADF9 EQUW &1B,&FF ;FILEV, &0212 = &FF1B ADFB EQUW &1E,&FF ;ARGSV, &0214 = &FF1E ADFD EQUW &21,&FF ;BGETV, &0216 = &FF21 ADFF EQUW &24,&FF ;BPUTV, &0218 = &FF24 AE01 EQUW &27,&FF ;GBPBV, &021A = &FF27 AE03 EQUW &2A,&FF ;FINDV, &021C = &FF2A AE05 EQUW &2D,&FF ;FSCV, &021E = &FF2D ;Table of action addresses for extended vector table AE07 EQUW &6E,&A1 ;E FILEV, evt + &1B = &A16E AE09 EQUW &62,&9B ;E ARGSV, evt + &1E = &9B62 AE0B EQUW &D1,&9C ;E BGETV, evt + &21 = &9CD1 AE0D EQUW &9E,&9D ;E BPUTV, evt + &24 = &9D9E AE0F EQUW &DC,&A2 ;E GBPBV, evt + &27 = &A2DC AE11 EQUW &61,&99 ;E FINDV, evt + &2A = &9961 AE13 EQUW &5F,&97 ;E FSCV, evt + &2D = &975F ;Table of action addresses for FSC calls 0..11, low bytes AE15 EQUB &74 ;FSC 0 = *OPT &9775 AE16 EQUB &07 ;FSC 1 = read EOF state &9808 AE17 EQUB &1F ;FSC 2 = */ &9820 AE18 EQUB &9B ;FSC 3 = unrecognised *cmd &989C AE19 EQUB &1F ;FSC 4 = *RUN &9820 AE1A EQUB &AD ;FSC 5 = *CAT &98AE AE1B EQUB &04 ;FSC 6 = new FS starting up &9905 AE1C EQUB &16 ;FSC 7 = valid file handles &9917 AE1D EQUB &1B ;FSC 8 = *command entered &991C #if defined _BUGFIX AE1E EQUB &FB ;FSC 9 = *EX &8BFC AE1F EQUB &0F ;FSC 10 = *INFO &8C10 #else AE1E EQUB &0A ;FSC 9 = *EX &8C0B AE1F EQUB &18 ;FSC 10 = *INFO &8C19 #endif AE20 EQUB &1F ;FSC 11 = *RUN from library &9820 ;Table of action addresses for FSC calls 0..11, high bytes AE21 EQUB &97 AE22 EQUB &98 AE23 EQUB &98 AE24 EQUB &98 AE25 EQUB &98 AE26 EQUB &98 AE27 EQUB &99 AE28 EQUB &99 AE29 EQUB &99 #if defined _BUGFIX AE2A EQUB &8B AE2B EQUB &8C #else AE2A EQUB &8C AE2B EQUB &8C #endif AE2C EQUB &98 ;Table of action addresses for OSARGS calls A=&FF,0,1, Y=0, low bytes AE2D EQUB &A1 ;OSARGS &FF = ensure all files &9BA2 AE2E EQUB &8B ;OSARGS 0 = return FS number &9B8C AE2F EQUB &8E ;OSARGS 1 = command line tail &9B8F ;Table of action addresses for OSARGS calls A=&FF,0,1, Y=0, high bytes AE30 EQUB &9B AE31 EQUB &9B AE32 EQUB &9B ;Table of action addresses for OSFILE calls &FF,0..6, low bytes AE33 EQUB &EE ;OSFILE &FF = load file &A1EF AE34 EQUB &9F ;OSFILE 0 = save file &A1A0 AE35 EQUB &AF ;OSFILE 1 = wr. catalog info &A1B0 AE36 EQUB &BA ;OSFILE 2 = wr. load address &A1BB AE37 EQUB &C2 ;OSFILE 3 = wr. exec address &A1C3 AE38 EQUB &CA ;OSFILE 4 = wr. attributes &A1CB AE39 EQUB &D9 ;OSFILE 5 = read catalog info &A1DA AE3A EQUB &E2 ;OSFILE 6 = delete file &A1E3 ;Table of action addresses for OSFILE calls &FF,0..6, high bytes AE3B EQUB &A1 AE3C EQUB &A1 AE3D EQUB &A1 AE3E EQUB &A1 AE3F EQUB &A1 AE40 EQUB &A1 AE41 EQUB &A1 AE42 EQUB &A1 ;Table of action addresses for OSGBPB calls 0..8, low bytes AE43 EQUB &9B ;OSGBPB 0 = no operation &A39B AE44 EQUB &9C ;OSGBPB 1 = set PTR and write &A39C AE45 EQUB &9C ;OSGBPB 2 = write data &A39C AE46 EQUB &A4 ;OSGBPB 3 = set PTR and read &A3A4 AE47 EQUB &A4 ;OSGBPB 4 = read data &A3A4 AE48 EQUB &AC ;OSGBPB 5 = read title/opt/drv &A3AC AE49 EQUB &E1 ;OSGBPB 6 = read CSD drv/dir &A3E1 AE4A EQUB &F0 ;OSGBPB 7 = read lib'y drv/dir &A3F0 AE4B EQUB &FF ;OSGBPB 8 = read CSD filenames &A3FF ;Table of action addresses for OSGBPB calls 0..8, high bytes AE4C EQUB &A3 AE4D EQUB &A3 AE4E EQUB &A3 AE4F EQUB &A3 AE50 EQUB &A3 AE51 EQUB &A3 AE52 EQUB &A3 AE53 EQUB &A3 AE54 EQUB &A3 ;Table of microcode bytes for OSGBPB calls 0..8 AE55 EQUB &04 ;%000001 0 . to memory, special handler AE56 EQUB &02 ;%000000 1 0 from memory, xfer data, set PTR AE57 EQUB &03 ;%000000 1 1 from memory, xfer data, leave PTR AE58 EQUB &06 ;%000001 1 0 to memory, xfer data, set PTR AE59 EQUB &07 ;%000001 1 1 to memory, xfer data, leave PTR AE5A EQUB &04 ;%000001 0 . to memory, special handler AE5B EQUB &04 ;%000001 0 . to memory, special handler AE5C EQUB &04 ;%000001 0 . to memory, special handler AE5D EQUB &04 ;%000001 0 . to memory, special handler .RE5E ;Print Challenger banner AE5E 08 PHP ;save C on entry AE5F 20 D3 A8 JSR R8D3 ;print "CHALLENGER " AE62 EQUS "CHALLENGER " AE6D EA NOP AE6E 28 PLP ;restore C AE6F B0 09 BCS RE7A ;if C=0 on entry #if defined _PCH200 AE71 20 D3 A8 JSR R8D3 ;then print version number "200B " AE74 EQUS "200B " #else AE71 20 D3 A8 JSR R8D3 ;then print version number "2.00 " AE74 EQUS "2.00 " #endif AE79 EA NOP .RE7A AE7A 20 19 82 JSR P219 ;get Challenger unit type AE7D 29 03 AND #&03 ;extract bits 1,0 AE7F 09 04 ORA #&04 ;add 4 to make 4..7 AE81 AA TAX ;transfer to X to select message AE82 20 F7 8F JSR PFF7 ;print boot or Challenger config descriptor AE85 4C 69 84 JMP P469 ;print newline and exit ;*FORMAT AE88 20 F2 A9 JSR R9F2 ;call GSINIT with C=0 AE8B F0 17 BEQ REA4 ;if no argument then skip .RE8D AE8D 20 C5 FF JSR &FFC5 ;[D]else call GSREAD AE90 90 04 BCC RE96 ;type character of argument if present AE92 A9 0D LDA #&0D ;else end of argument, type RETURN AE94 A0 00 LDY #&00 ;offset = 0, indicate end of argument .RE96 AE96 84 B7 STY &B7 ;save command line offset AE98 A8 TAY ;transfer character of argument to Y AE99 A2 00 LDX #&00 ;x=&00 insert into keyboard buffer AE9B A9 99 LDA #&99 ;OSBYTE &99 = insert char into buffer ck/ESC AE9D 20 F4 FF JSR &FFF4 ;call OSBYTE AEA0 A4 B7 LDY &B7 ;restore command line offset AEA2 D0 E9 BNE RE8D ;loop until argument inserted in buffer ;e.g. *FORMAT 4|M2|MF auto-formats RAM disc .REA4 AEA4 20 3F A8 JSR R83F ;have A=0 returned on exit AEA7 BA TSX AEA8 86 B7 STX &B7 ;set stack pointer to restore on restart AEAA 86 B8 STX &B8 ;set stack pointer to restore on exit AEAC 20 9C 95 JSR Q59C ;set high word of buffer address = &FFFF ;command restart point set at &AEE5 AEAF 20 1D B0 JSR S01D ;set command restart to exit command AEB2 20 B2 B2 JSR S2B2 ;print "FORMAT" heading .REB5 AEB5 20 DE B2 JSR S2DE ;clear row 23 #if !defined _BUGFIX .REB8 #endif AEB8 20 17 A9 JSR R917 ;print VDU sequence immediate AEBB EQUB &1F ;move cursor to (0,19) AEBC EQUB &00 AEBD EQUB &13 AEBE EQUS "Drive number (0-7) " AED1 EQUB &FF AED2 20 CB B5 JSR S5CB ;get printable input character AED5 38 SEC ;convert to binary drive no. 0..7 AED6 E9 30 SBC #&30 ;is it less than ASCII "0"? #if defined _BUGFIX AED8 C9 08 CMP #&08 ;never; is drive number in range? AEDA 90 07 BCC REE3 ;if so then proceed AEDC 20 3C B7 JSR S73C ;[D]else make a short beep AEDF 4C B5 AE JMP REB5 ;and input new drive number #else AED8 90 DE BCC REB8 ;if so then input new drive number AEDA C9 08 CMP #&08 ;is drive number in range? AEDC 90 05 BCC REE3 ;if so then proceed AEDE 20 3C B7 JSR S73C ;[D]else make a short beep AEE1 D0 D2 BNE REB5 ;and input new drive number [BUG]Z undefined #endif .REE3 AEE3 85 CF STA &CF ;set as current volume .REE5 AEE5 A2 AF LDX #&AF ;point XY at *FORMAT entry point, &AEAF AEE7 A0 AE LDY #&AE AEE9 20 21 B0 JSR S021 ;set command restart action address AEEC 20 17 A9 JSR R917 ;print VDU sequence immediate AEEF EQUB &1F ;move cursor to (0,20) AEF0 EQUB &00 AEF1 EQUB &14 AEF2 EQUS "0=40, 1=80 tracks : " AF07 EQUB &7F AF08 EQUB &7F AF09 EQUB &FF AF0A 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc AF0D D0 03 BNE RF12 ;if so AF0F 4C B7 AF JMP RFB7 ;then format RAM disc .RF12 AF12 20 CB B5 JSR S5CB ;else get printable input character AF15 A2 28 LDX #&28 ;set X = 40 tracks AF17 C9 30 CMP #&30 ;if user typed 0 AF19 F0 06 BEQ RF21 ;then proceed with 40 track format AF1B A2 50 LDX #&50 ;else set X = 80 tracks AF1D C9 31 CMP #&31 ;if user typed 1 then format 80 tracks AF1F D0 C4 BNE REE5 ;else invalid character, prompt again .RF21 AF21 86 C0 STX &C0 ;set number of tracks to format #if defined _BUGFIX AF23 A9 28 LDA #&28 ;40 tracks maximum can be formatted AF25 2C EA FD BIT &FDEA ;test double-stepping flag AF28 50 07 BVC RF31 ;if 1:1 stepping then maximum = 80 tracks AF2A 10 06 BPL RF32 ;if *OPT 8,1 then maximum = 40 tracks AF2C A2 80 LDX #&80 ;else *OPT 8,255; keep automatic on AF2E 8E EA FD STX &FDEA ;force 1:1 stepping .RF31 AF31 0A ASL A ;and format up to 80 tracks. .RF32 AF32 C5 C0 CMP &C0 ;compare max - chosen number of tracks AF34 B0 09 BCS RF3F ;[D]if max >= number chosen then proceed AF36 20 3C B7 JSR S73C ;[D]else make a short beep AF39 4C E5 AE JMP REE5 ;and input new format size #else /* _BUGFIX */ AF23 A2 50 LDX #&50 ;80 tracks maximum can be formatted AF25 AD EA FD LDA &FDEA ;test double-stepping flag AF28 10 05 BPL RF2F ;if double-stepping is automatic AF2A 29 80 AND #&80 ;then discard last detected setting AF2C 8D EA FD STA &FDEA ;and force 1:1 stepping .RF2F AF2F 2C EA FD BIT &FDEA ;(else) test double-stepping flag AF32 50 02 BVC RF36 ;if *OPT 8,1, forced double-stepping AF34 A2 28 LDX #&28 ;then maximum format is 40 tracks. .RF36 AF36 E4 C0 CPX &C0 ;compare max - chosen number of tracks AF38 B0 05 BCS RF3F ;[D]if max >= number chosen then proceed AF3A 20 3C B7 JSR S73C ;[D]else make a short beep AF3D D0 A6 BNE REE5 ;and input new format size [BUG]Z undefined #endif /* _BUGFIX */ .RF3F AF3F 20 DE B2 JSR S2DE ;clear row 23 .RF42 AF42 20 17 A9 JSR R917 ;print VDU sequence immediate AF45 EQUB &1F ;move cursor to (0,21) AF46 EQUB &00 AF47 EQUB &15 AF48 EQUS "Density (S/D) " AF56 EQUB &FF AF57 20 CB B5 JSR S5CB ;get printable input character AF5A C9 53 CMP #&53 ;is it capital S? AF5C F0 38 BEQ RF96 ;if so then format single density AF5E C9 44 CMP #&44 ;else is it capital D? AF60 F0 06 BEQ RF68 ;if so then format double density AF62 20 3C B7 JSR S73C ;[D]else make a short beep AF65 4C 42 AF JMP RF42 ;and re-input; [BUG] old density on screen! .RF68 ;Format double density AF68 AD ED FD LDA &FDED ;set double density AF6B 09 40 ORA #&40 ;preserve automatic setting bit 7 AF6D 8D ED FD STA &FDED ;set double density bit 6 AF70 A9 12 LDA #&12 ;set 18 sectors per track AF72 8D EB FD STA &FDEB AF75 20 5C B6 JSR S65C ;prompt user and start format AF78 B0 14 BCS RF8E ;if failed then prompt to repeat AF7A A6 C0 LDX &C0 ;else get number of tracks on disc AF7C CA DEX ;all but one track available for volumes AF7D 86 B0 STX &B0 ;set multiplicand AF7F 20 52 B5 JSR S552 ;multiply by no. sectors per track AF82 20 12 B4 JSR S412 ;set default volume sizes AF85 20 5E B4 JSR S45E ;write volume catalogues AF88 20 77 B4 JSR S477 ;generate disc catalogue AF8B 20 BD AC JSR RCBD ;write disc catalogue L3 .RF8E AF8E 20 35 B0 JSR S035 ;prompt to repeat AF91 F0 D5 BEQ RF68 ;if user chooses repeat then format another AF93 4C 28 B0 JMP S028 ;else exit command .RF96 ;Format single density AF96 AD ED FD LDA &FDED ;set single density AF99 29 80 AND #&80 ;preserve automatic setting bit 7 AF9B 8D ED FD STA &FDED ;clear double density bit 6 AF9E A9 0A LDA #&0A ;set 10 sectors per track AFA0 8D EB FD STA &FDEB AFA3 20 5C B6 JSR S65C ;prompt user and start format AFA6 B0 07 BCS RFAF ;if failed then prompt to repeat AFA8 A6 C0 LDX &C0 ;else get number of tracks on disc AFAA 86 B0 STX &B0 ;set multiplicand AFAC 20 5B B0 JSR S05B ;initialise volume catalogue by no. tracks .RFAF AFAF 20 35 B0 JSR S035 ;prompt to repeat AFB2 F0 E2 BEQ RF96 ;if user chooses repeat then format another AFB4 4C 28 B0 JMP S028 ;else exit command .RFB7 ;format RAM disc AFB7 20 17 A9 JSR R917 ;print VDU sequence immediate AFBA EQUB &7F ;delete " :" AFBB EQUB &7F AFBC EQUS ", 2=Max RAM disk " AFCD EQUB &FF AFCE 20 CB B5 JSR S5CB ;get printable input character AFD1 38 SEC ;convert to binary option 0..2 AFD2 E9 30 SBC #&30 AFD4 90 1C BCC RFF2 ;if invalid character then prompt again AFD6 C9 03 CMP #&03 ;else is option in range? AFD8 B0 18 BCS RFF2 ;if not 0..2 then prompt again AFDA 48 PHA ;else save option AFDB 20 1B B6 JSR S61B ;prompt to start format AFDE 68 PLA ;restore option AFDF AA TAX AFE0 E0 02 CPX #&02 ;if 40 or 80 track format selected AFE2 D0 08 BNE RFEC ;then format to that size AFE4 20 D9 AA JSR RAD9 ;else map current volume to physical volume AFE7 C9 05 CMP #&05 ;if formatting drive 4 AFE9 D0 01 BNE RFEC ;then use option 2, size = &3F5 sectors AFEB E8 INX ;else use option 3, size = &3FF sectors .RFEC AFEC 20 F8 AF JSR RFF8 ;initialise RAM disc catalogue AFEF 4C 28 B0 JMP S028 ;exit command .RFF2 AFF2 20 3C B7 JSR S73C ;make a short beep AFF5 4C E5 AE JMP REE5 ;and input new volume size option .RFF8 ;Initialise RAM disc catalogue AFF8 BD 15 B0 LDA &B015,X ;look up LSB of selected volume size AFFB 85 C4 STA &C4 AFFD BD 19 B0 LDA &B019,X ;and MSB B000 85 C5 STA &C5 B002 20 88 AD JSR RD88 ;claim NMI B005 A9 00 LDA #&00 B007 8D FE FD STA &FDFE ;b6=0 RAM disc is single density B00A 8D ED FD STA &FDED ;*OPT 6,10 single density [BUG]cancels auto! B00D A0 00 LDY #&00 ;write catalogue to sector 0 B00F 20 62 B0 JSR S062 ;initialise volume catalogue B012 4C 71 AD JMP RD71 ;release NMI ;Table of single density volume sizes, X=0..3, low bytes B015 EQUB &90 ;x=0, 40 track disc, &0190 sectors, 100 KiB B016 EQUB &20 ;x=1, 80 track disc, &0320 sectors, 200 KiB B017 EQUB &F5 ;x=2, RAM disc 4, &03F5 sectors, 253 KiB B018 EQUB &FF ;x=3, RAM disc 5, &03FF sectors, 255 KiB ;Table of single density volume sizes, X=0..3, high bytes B019 EQUB &01 B01A EQUB &03 B01B EQUB &03 B01C EQUB &03 .S01D ;Set command restart to exit command B01D A2 28 LDX #&28 ;point XY at command exit routine, &B028 B01F A0 B0 LDY #&B0 .S021 ;Set command restart action address B021 8E E6 FD STX &FDE6 B024 8C E7 FD STY &FDE7 B027 60 RTS .S028 ;Exit command B028 A6 B8 LDX &B8 ;restore stack pointer from workspace B02A 9A TXS B02B 20 50 B6 JSR S650 ;clear rows 20..22 B02E A2 00 LDX #&00 ;set XY to screen coordinates (0,24) B030 A0 18 LDY #&18 B032 4C D1 B2 JMP S2D1 ;move cursor to (X,Y) .S035 ;Prompt to repeat B035 20 17 A9 JSR R917 ;print VDU sequence immediate B038 EQUB &1F ;move cursor to (8,16) B039 EQUB &08 B03A EQUB &10 B03B EQUS "Format complete" B04A EQUB &0D B04B EQUB &0A B04C EQUS "Repeat? " B054 EQUB &FF B055 20 EE B5 JSR S5EE ;get input character and acknowledge ESCAPE B058 C9 59 CMP #&59 ;return Z=1 iff user typed capital Y B05A 60 RTS .S05B ;Initialise volume catalogue by no. tracks B05B 20 52 B5 JSR S552 ;multiply by no. sectors per track B05E A0 00 LDY #&00 ;sector number = 0 B060 84 BA STY &BA ;set track number = 0 (redundant) .S062 ;Initialise volume catalogue B062 20 4C A8 JSR R84C ;save AXY B065 84 BB STY &BB ;set LSB absolute LBA = 2 * volume letter B067 A9 00 LDA #&00 B069 85 BA STA &BA ;set MSB of absolute LBA = 0 B06B 20 EA B3 JSR S3EA ;clear catalogue sectors B06E 20 16 BE JSR SE16 ;page in catalogue sector 1 B071 A5 C5 LDA &C5 ;set MSB volume size, boot option OFF B073 8D 06 FD STA &FD06 B076 A5 C4 LDA &C4 ;set LSB volume size B078 8D 07 FD STA &FD07 B07B 4C 83 96 JMP Q683 ;write disc/volume catalogue L3 ;*VERIFY B07E 20 41 B7 JSR S741 ;parse floppy volume spec from argument B081 BA TSX B082 86 B8 STX &B8 ;set stack pointer to restore on exit B084 86 B7 STX &B7 ;set stack pointer to restore on restart B086 20 3F A8 JSR R83F ;have A=0 returned on exit B089 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF ;command restart point set at &B0B6 B08C 20 1D B0 JSR S01D ;set command restart to exit command B08F 20 58 B7 JSR S758 ;set display MODE 7 and place heading B092 20 17 A9 JSR R917 ;print VDU sequence immediate B095 EQUS "V E R I F Y" B0A0 EQUB &FF B0A1 20 17 A9 JSR R917 ;print VDU sequence immediate B0A4 EQUB &1F ;move cursor to (0,10) B0A5 EQUB &00 B0A6 EQUB &10 B0A7 EQUS "Insert disk" B0B2 EQUB &FF B0B3 20 06 B7 JSR S706 ;prompt for keypress B0B6 A2 8C LDX #&8C ;point XY at *VERIFY entry point, &B08C B0B8 A0 B0 LDY #&B0 B0BA 20 21 B0 JSR S021 ;set command restart action address B0BD A9 00 LDA #&00 B0BF 8D E9 FD STA &FDE9 ;data transfer call &00 = read data B0C2 A9 80 LDA #&80 B0C4 85 B9 STA &B9 ;>0 disc operation is interruptible B0C6 20 B5 AB JSR RBB5 ;detect disc format/set sector address B0C9 2C ED FD BIT &FDED ;test density flag B0CC 70 26 BVS S0F4 ;if double density then examine disc catalog B0CE 20 32 96 JSR Q632 ;else load volume catalogue B0D1 20 16 BE JSR SE16 ;page in catalogue sector 1 B0D4 AD 06 FD LDA &FD06 ;get boot option/top bits volume size B0D7 29 03 AND #&03 ;extract top bits volume size B0D9 85 B1 STA &B1 ;store MSB of dividend B0DB AD 07 FD LDA &FD07 ;get LSB volume size B0DE 85 B0 STA &B0 ;store LSB of dividend B0E0 20 0C BE JSR SE0C ;page in main workspace B0E3 A9 00 LDA #&00 B0E5 85 B3 STA &B3 ;clear MSB of divisor B0E7 AD EB FD LDA &FDEB ;get number of sectors per track (= 10) B0EA 85 B2 STA &B2 ;store LSB of divisor B0EC 20 5F B3 JSR S35F ;divide word by word B0EF 86 C0 STX &C0 ;store quotient as number of tracks B0F1 4C FF B0 JMP S0FF ;verify disc .S0F4 B0F4 20 BA AC JSR RCBA ;load disc catalogue L3 B0F7 20 11 BE JSR SE11 ;page in catalogue sector 0 B0FA AD 04 FD LDA &FD04 ;get number of tracks on disc B0FD 85 C0 STA &C0 ;store number of tracks to verify .S0FF ;Verify disc B0FF 20 0C BE JSR SE0C ;page in main workspace B102 A9 00 LDA #&00 B104 85 BA STA &BA ;set starting track = 0 B106 18 CLC ;[D]set C=0, no error #if defined _BUGFIX B107 08 PHP .S108 #else .S107 B107 08 PHP #endif B108 20 B3 B6 JSR S6B3 ;print track number in table B10B 20 21 B1 JSR S121 ;verify track with display B10E F0 03 BEQ S113 ;if hard error occurred B110 28 PLP ;[D]then set C=1, verify failed B111 38 SEC B112 08 PHP .S113 B113 E6 BA INC &BA ;increment track number B115 A5 BA LDA &BA ;compare track number - number of tracks B117 C5 C0 CMP &C0 #if defined _BUGFIX B119 90 ED BCC S108 ;if less then verify next track #else B119 90 EC BCC S107 ;if less then verify next track ;[BUG]stack unbalanced, one PHP per track ;[BUG]ignores errors except on last track #endif B11B 28 PLP ;[D]else test return code B11C B0 1C BCS S13A ;if error occurred print "ERROR" B11E 4C 28 B0 JMP S028 ;[D]else exit command. .S121 ;Verify track with display B121 A2 03 LDX #&03 ;[D]make 3 attempts B123 A0 03 LDY #&03 ;[D]erase next 3 characters B125 20 2C B7 JSR S72C ;erase Y characters ahead of cursor .S128 B128 20 EA B2 JSR S2EA ;poll for ESCAPE B12B 20 05 BA JSR SA05 ;verify track B12E F0 09 BEQ S139 ;if verify succeeded then exit B130 A9 2E LDA #&2E ;else print a dot B132 20 EE FF JSR &FFEE ;call OSWRCH B135 CA DEX ;decrement attempt counter B136 D0 F0 BNE S128 ;if attempts remaining then try again B138 CA DEX ;else X=&FF, Z=0 to indicate failure .S139 B139 60 RTS .S13A B13A 20 0B B6 JSR S60B ;print "ERROR" B13D 4C 28 B0 JMP S028 ;and exit command. ;*VOLGEN B140 20 41 B7 JSR S741 ;[D]parse floppy volume spec from argument B143 20 3F A8 JSR R83F ;have A=0 returned on exit B146 BA TSX B147 86 B8 STX &B8 ;set stack pointer to restore on exit B149 20 5F A7 JSR R75F ;ensure *ENABLE active B14C 20 9C 95 JSR Q59C ;set high word of OSFILE load address = &FFFF B14F A9 80 LDA #&80 B151 85 B9 STA &B9 ;>0 disc operation is interruptible B153 A9 00 LDA #&00 B155 8D EC FD STA &FDEC ;data area starts on track 0 B158 85 BA STA &BA ;[D]set track number = 0 B15A 20 16 B9 JSR S916 ;[D]seek logical track B15D 20 79 B2 JSR S279 ;ensure disc is double density B160 A5 CF LDA &CF ;get current volume B162 29 0F AND #&0F ;extract physical drive number, clear b7..4 B164 85 CF STA &CF ;set current volume letter to A B166 20 58 B7 JSR S758 ;[D]set display MODE 7 and place heading B169 20 17 A9 JSR R917 ;print VDU sequence immediate B16C EQUS "V O L G E N" B177 EQUB &FF B178 20 17 A9 JSR R917 ;print VDU sequence immediate B17B EQUB &1F ;move cursor to (0,4) B17C EQUB &00 B17D EQUB &04 B17E EQUB &0D B17F EQUS "Vol Size (K) " B18F EQUB &FF B190 A5 CF LDA &CF ;get current volume B192 20 AD 8E JSR PEAD ;print " Drive " plus volume spec in A B195 20 17 A9 JSR R917 ;print VDU sequence immediate B198 EQUB &1F ;move cursor to (0,15) B199 EQUB &00 B19A EQUB &0F B19B EQUS "Free" B19F EQUB &FF B1A0 20 D2 B4 JSR S4D2 ;read volume sizes and allocations B1A3 A9 07 LDA #&07 ;8 volumes to list B1A5 85 C1 STA &C1 ;set as counter .S1A7 B1A7 20 BC B3 JSR S3BC ;print tabulated volume size B1AA C6 C1 DEC &C1 ;loop until 8 volumes listed B1AC 10 F9 BPL S1A7 .S1AE ;command restart point set at &B255 B1AE 20 1D B0 JSR S01D ;set command restart to exit command .S1B1 B1B1 20 6D B5 JSR S56D ;sum volume sizes B1B4 A2 05 LDX #&05 ;move cursor to (5,15) B1B6 A0 0F LDY #&0F B1B8 20 D1 B2 JSR S2D1 B1BB 20 80 B3 JSR S380 ;print sector count as kilobytes B1BE 4C C4 B1 JMP S1C4 .S1C1 B1C1 20 3C B7 JSR S73C ;make a short beep .S1C4 B1C4 20 17 A9 JSR R917 ;print VDU sequence immediate B1C7 EQUB &1F ;move cursor to (0,23) B1C8 EQUB &00 B1C9 EQUB &17 B1CA EQUS "VOLUME : (W to configure)" B1E8 EQUB &1F ;move cursor to (8,23) B1E9 EQUB &08 B1EA EQUB &17 B1EB EQUB &FF B1EC 20 EE B5 JSR S5EE ;get input character and acknowledge ESCAPE B1EF C9 57 CMP #&57 ;[D]if user typed capital W B1F1 D0 03 BNE S1F6 B1F3 4C 55 B2 JMP S255 ;then generate volumes and exit .S1F6 B1F6 38 SEC ;else convert letter A..H to volume index 0..7 B1F7 E9 41 SBC #&41 B1F9 90 C6 BCC S1C1 ;if out of range then display error B1FB C9 08 CMP #&08 B1FD B0 C2 BCS S1C1 B1FF 85 C1 STA &C1 ;else set volume index B201 69 41 ADC #&41 ;convert back to letter A..H, print it B203 20 EE FF JSR &FFEE ;call OSWRCH B206 A9 20 LDA #&20 ;print a space B208 20 EE FF JSR &FFEE ;call OSWRCH B20B 20 05 B3 JSR S305 ;input number up to 3 digits B20E B0 B4 BCS S1C4 ;[D]if invalid input then prompt again B210 A5 AA LDA &AA ;else test entered volume size B212 05 AB ORA &AB B214 D0 0D BNE S223 ;if >0 then set volume size B216 A5 C1 LDA &C1 ;else RETURN pressed, delete volume B218 F0 A7 BEQ S1C1 ;[D]volume A can't be deleted, prompt again B21A 20 A2 B2 JSR S2A2 ;else clear volume size B21D 20 BC B3 JSR S3BC ;print tabulated volume size B220 4C B1 B1 JMP S1B1 ;update free space and take next command. .S223 ;Fit volume request B223 A5 AB LDA &AB ;test MSB of entered number B225 C9 04 CMP #&04 ;if <256 KiB requested then continue B227 B0 98 BCS S1C1 ;else display error and prompt again B229 20 A2 B2 JSR S2A2 ;clear volume size B22C 20 6D B5 JSR S56D ;sum volume sizes B22F A5 A8 LDA &A8 ;compare free space - request B231 C5 AA CMP &AA B233 A5 A9 LDA &A9 B235 E5 AB SBC &AB B237 B0 08 BCS S241 ;if request fits then assign request B239 A5 A8 LDA &A8 ;else set request = free space on disc B23B 85 AA STA &AA B23D A5 A9 LDA &A9 B23F 85 AB STA &AB .S241 B241 A5 C1 LDA &C1 ;get volume index B243 0A ASL A ;double it B244 A8 TAY ;transfer to Y as index B245 A5 AB LDA &AB ;set assigned volume size B247 99 D5 FD STA &FDD5,Y ;= min(request, free_space) B24A A5 AA LDA &AA B24C 99 D6 FD STA &FDD6,Y B24F 20 BC B3 JSR S3BC ;print tabulated volume size B252 4C B1 B1 JMP S1B1 ;update free space display and take input. .S255 ;Generate volumes B255 A2 AE LDX #&AE ;point XY at *VOLGEN entry point, &B1AE B257 A0 B1 LDY #&B1 B259 20 21 B0 JSR S021 ;set command restart action address B25C 20 06 B7 JSR S706 ;prompt for keypress B25F 20 79 B2 JSR S279 ;ensure disc is double density B262 20 D3 B6 JSR S6D3 ;ensure disc is write enabled B265 F0 03 BEQ S26A ;if write enabled then proceed B267 4C AE B1 JMP S1AE ;if write protected then try again .S26A B26A 20 EA B3 JSR S3EA ;clear catalogue sectors B26D 20 5E B4 JSR S45E ;write volume catalogues B270 20 77 B4 JSR S477 ;generate disc catalogue B273 20 BD AC JSR RCBD ;write disc catalogue L3 B276 4C 28 B0 JMP S028 ;exit command .S279 B279 20 55 AC JSR RC55 ;ensure disc is formatted B27C 2C ED FD BIT &FDED ;test density flag B27F 70 20 BVS S2A1 ;if single density B281 20 AD A8 JSR R8AD ;then raise "must be double density" error. B284 EQUB &C9 B285 EQUS "Disk must be double density" B2A0 EQUB &00 .S2A1 B2A1 60 RTS .S2A2 ;Clear volume size B2A2 A5 C1 LDA &C1 ;get volume index B2A4 0A ASL A ;double to get offset B2A5 A8 TAY B2A6 20 07 BE JSR SE07 ;page in auxiliary workspace B2A9 A9 00 LDA #&00 B2AB 99 D5 FD STA &FDD5,Y ;set size of selected volume = 0 B2AE 99 D6 FD STA &FDD6,Y B2B1 60 RTS .S2B2 ;Print "FORMAT" heading B2B2 20 58 B7 JSR S758 ;set display MODE 7 and place heading B2B5 20 17 A9 JSR R917 ;print VDU sequence immediate B2B8 EQUS "F O R M A T" B2C3 EQUB &FF .S2C4 B2C4 60 RTS .S2C5 ;Set display MODE 7 B2C5 A9 07 LDA #&07 B2C7 48 PHA B2C8 A9 16 LDA #&16 B2CA 20 EE FF JSR &FFEE B2CD 68 PLA B2CE 4C EE FF JMP &FFEE .S2D1 ;Move cursor to (X,Y) B2D1 A9 1F LDA #&1F ;issue VDU 31 = PRINT TAB(X,Y) B2D3 20 EE FF JSR &FFEE B2D6 8A TXA ;send X coordinate to OSWRCH, 0=leftmost col B2D7 20 EE FF JSR &FFEE B2DA 98 TYA ;send Y coordinate to OSWRCH, 0=top row B2DB 4C EE FF JMP &FFEE .S2DE ;Clear row 23 B2DE A2 00 LDX #&00 ;move cursor to (0,23) B2E0 A0 17 LDY #&17 B2E2 20 D1 B2 JSR S2D1 ;move cursor to (X,Y) B2E5 A0 28 LDY #&28 ;[D]set Y = 40, width of one MODE 7 row: B2E7 4C DD 8A JMP PADD ;[D]print number of spaces in Y .S2EA ;Poll for ESCAPE B2EA 24 FF BIT &FF ;[D]if ESCAPE was pressed B2EC 10 D6 BPL S2C4 B2EE 20 8F A9 JSR R98F ;then acknowledge ESCAPE condition B2F1 20 71 AD JSR RD71 ;release NMI B2F4 A6 B7 LDX &B7 ;restore stack pointer from &B7 B2F6 9A TXS B2F7 6C E6 FD JMP (&FDE6) ;and restart command .S2FA ;Move cursor to table row in &C1 B2FA A2 01 LDX #&01 ;[D](1,6+?&C1) vs (6,9+?&C1) in DDOS B2FC 18 CLC B2FD A5 C1 LDA &C1 B2FF 69 06 ADC #&06 B301 A8 TAY B302 4C D1 B2 JMP S2D1 .S305 ;Input hex number up to 3 digits B305 A0 00 LDY #&00 ;start with no characters in line buffer B307 84 AA STY &AA ;clear accumulator B309 84 AB STY &AB ;[D]accepted decimals up to 5 digits in DDOS .S30B B30B 20 EE B5 JSR S5EE ;get input character and acknowledge ESCAPE B30E C9 0D CMP #&0D ;if user pressed RETURN B310 D0 02 BNE S314 B312 18 CLC ;then return C=0 B313 60 RTS .S314 B314 C9 7F CMP #&7F ;else if user pressed DELETE B316 D0 15 BNE S32D B318 98 TYA ;then test number of characters entered B319 D0 02 BNE S31D ;if no characters on line B31B 38 SEC ;then return C=1 B31C 60 RTS .S31D B31D 20 48 B3 JSR S348 ;else backspace and erase last character B320 88 DEY ;decrement number of characters entered B321 A2 04 LDX #&04 ;[D]else 4 places to shift by: .S323 B323 46 AB LSR &AB ;[D]shift MSB of accumulator right B325 66 AA ROR &AA ;shift old b0 into LSB of accumulator B327 CA DEX ;loop until 4 bits shifted B328 D0 F9 BNE S323 ;removing last digit entered B32A 4C 0B B3 JMP S30B ;and loop .S32D B32D C0 03 CPY #&03 ;[D]if 3 characters already entered B32F F0 DA BEQ S30B ;then ignore latest, loop to read DEL/CR B331 20 E1 A9 JSR R9E1 ;[D]else convert ASCII hex digit to binary B334 20 80 A9 JSR R980 ;print hex nibble [BUG]no validation! B337 A2 04 LDX #&04 ;4 places to shift by: .S339 B339 06 AA ASL &AA ;shift LSB of accumulator left B33B 26 AB ROL &AB ;shift old b7 into MSB of accumulator B33D CA DEX ;loop until 4 bits shifted B33E D0 F9 BNE S339 ;now b3..0 of &AA = &0 B340 05 AA ORA &AA ;apply LSB to nibble typed by user B342 85 AA STA &AA ;update LSB of accumulator B344 C8 INY ;increment number of digits typed B345 4C 0B B3 JMP S30B ;loop to input more digits ;[BUG]can type e.g. AvF (A = 255K) in *VOLGEN .S348 ;Backspace and erase characters B348 20 50 B3 JSR S350 ;print DEL B34B A9 20 LDA #&20 ;print space: B34D 20 EE FF JSR &FFEE .S350 ;Print DEL B350 A9 7F LDA #&7F ;set A = ASCII value of DEL character B352 4C EE FF JMP &FFEE ;call OSWRCH to print it and exit. ;[D]unreachable code B355 38 SEC ;Convert ASCII digit to binary and validate B356 E9 30 SBC #&30 ;C=1 iff invalid B358 90 03 BCC S35D ;(redundant) B35A C9 0A CMP #&0A B35C 60 RTS .S35D ;unreachable code B35D 38 SEC B35E 60 RTS .S35F ;Divide word by word B35F A2 00 LDX #&00 ;initialise quotient = 0: .S361 B361 A5 B1 LDA &B1 ;Compare dividend - divisor B363 C5 B3 CMP &B3 B365 90 18 BCC S37F B367 D0 06 BNE S36F B369 A5 B0 LDA &B0 B36B C5 B2 CMP &B2 B36D 90 10 BCC S37F ;if dividend >= divisor .S36F B36F A5 B0 LDA &B0 ;then subtract dividend - divisor B371 E5 B2 SBC &B2 B373 85 B0 STA &B0 ;ultimately leaving remainder B375 A5 B1 LDA &B1 B377 E5 B3 SBC &B3 B379 85 B1 STA &B1 B37B E8 INX ;increment quotient in X B37C 4C 61 B3 JMP S361 ;and loop as remainder >= 0 .S37F B37F 60 RTS .S380 ;Print sector count as kilobytes B380 20 E9 A7 JSR R7E9 ;[D]print sector count B383 A0 02 LDY #&02 ;print 2 spaces B385 20 DD 8A JSR PADD B388 46 A9 LSR &A9 ;divide sector count by 4 to get kilobytes B38A 66 A8 ROR &A8 B38C 46 A9 LSR &A9 B38E 66 A8 ROR &A8 B390 A5 A8 LDA &A8 B392 20 9D B3 JSR S39D ;convert byte to three decimal digits B395 20 E9 A7 JSR R7E9 ;print space-padded hex word B398 A9 4B LDA #&4B ;print "K" B39A 4C EE FF JMP &FFEE .S39D ;Convert byte to three decimal digits B39D 38 SEC ;[D]versus word to four in DDOS B39E A2 FF LDX #&FF B3A0 86 A9 STX &A9 .S3A2 B3A2 E6 A9 INC &A9 B3A4 E9 64 SBC #&64 B3A6 B0 FA BCS S3A2 B3A8 69 64 ADC #&64 .S3AA B3AA E8 INX B3AB E9 0A SBC #&0A B3AD B0 FB BCS S3AA B3AF 69 0A ADC #&0A B3B1 85 A8 STA &A8 B3B3 8A TXA B3B4 20 A4 A9 JSR R9A4 B3B7 05 A8 ORA &A8 B3B9 85 A8 STA &A8 B3BB 60 RTS .S3BC ;Print tabulated volume size B3BC 20 FA B2 JSR S2FA ;move cursor to table row in &C1 B3BF 18 CLC B3C0 A5 C1 LDA &C1 ;get volume letter B3C2 69 41 ADC #&41 ;convert to ASCII letter A..H B3C4 20 EE FF JSR &FFEE ;call OSWRCH B3C7 A0 0D LDY #&0D ;erase next 13 characters B3C9 20 2C B7 JSR S72C ;erase Y characters ahead of cursor B3CC A5 C1 LDA &C1 ;get volume index B3CE 0A ASL A ;double it B3CF A8 TAY ;transfer to Y as index B3D0 20 07 BE JSR SE07 ;page in auxiliary workspace B3D3 B9 D5 FD LDA &FDD5,Y ;get MSB volume size B3D6 85 A9 STA &A9 ;store it in zero page B3D8 B9 D6 FD LDA &FDD6,Y ;get LSB volume size B3DB 85 A8 STA &A8 ;store it in zero page B3DD 05 A9 ORA &A9 ;test volume size B3DF F0 06 BEQ S3E7 ;if =0 then leave row blank B3E1 20 15 A8 JSR R815 ;else print two spaces B3E4 20 80 B3 JSR S380 ;print sector count as kilobytes .S3E7 B3E7 4C 0C BE JMP SE0C ;page in main workspace .S3EA ;Clear catalogue sectors B3EA A9 00 LDA #&00 B3EC A8 TAY B3ED 20 11 BE JSR SE11 ;page in catalogue sector 0 .S3F0 B3F0 99 00 FD STA &FD00,Y B3F3 C8 INY B3F4 D0 FA BNE S3F0 B3F6 20 16 BE JSR SE16 ;page in catalogue sector 1 .S3F9 B3F9 99 00 FD STA &FD00,Y B3FC C8 INY B3FD D0 FA BNE S3F9 B3FF 4C 0C BE JMP SE0C ;page in main workspace .S402 ;Clear volume sizes B402 20 07 BE JSR SE07 ;page in auxiliary workspace B405 A9 00 LDA #&00 B407 A0 0F LDY #&0F ;8 words to clear for volumes A..H .S409 B409 99 D5 FD STA &FDD5,Y ;set assigned size of volume to &0000 B40C 88 DEY B40D 10 FA BPL S409 ;loop until all words cleared B40F 4C 0C BE JMP SE0C ;page in main workspace .S412 ;Set default volume sizes B412 20 0C BE JSR SE0C ;page in main workspace B415 A5 C4 LDA &C4 ;set free space = sectors avail. for volumes B417 85 B2 STA &B2 B419 A5 C5 LDA &C5 B41B 85 B3 STA &B3 B41D AD EB FD LDA &FDEB ;get number of sectors per track B420 85 B0 STA &B0 B422 A9 00 LDA #&00 ;clear MSB of word B424 A2 04 LDX #&04 ;4 places to shift, multiply by 16: .S426 B426 06 B0 ASL &B0 ;shift word one place left B428 2A ROL A B429 CA DEX ;repeat 4 times B42A D0 FA BNE S426 ;max. 16 tracks = 72 KiB per volume B42C 85 B1 STA &B1 B42E 20 07 BE JSR SE07 ;page in auxiliary workspace B431 A0 00 LDY #&00 .S433 B433 20 47 B5 JSR S547 ;compare requested allocation with free space B436 90 08 BCC S440 ;if it fits then set allocation = request B438 A5 B3 LDA &B3 ;[D]else set request = free space B43A 85 B1 STA &B1 B43C A5 B2 LDA &B2 B43E 85 B0 STA &B0 .S440 B440 A5 B1 LDA &B1 ;set allocation = request B442 99 D5 FD STA &FDD5,Y B445 A5 B0 LDA &B0 B447 99 D6 FD STA &FDD6,Y B44A 38 SEC ;subtract LSB request from free space B44B A5 B2 LDA &B2 B44D E5 B0 SBC &B0 B44F 85 B2 STA &B2 B451 A5 B3 LDA &B3 ;subtract MSB request from free space B453 E5 B1 SBC &B1 B455 85 B3 STA &B3 ;[D]no disc full test, last volumes = 0 B457 C8 INY ;add 2 to offset, point to next volume B458 C8 INY B459 C0 10 CPY #&10 ;loop until volumes A..H set. B45B D0 D6 BNE S433 B45D 60 RTS .S45E ;Write volume catalogues B45E A0 00 LDY #&00 ;start at volume A .S460 B460 20 07 BE JSR SE07 ;page in auxiliary workspace B463 B9 D5 FD LDA &FDD5,Y ;copy MSB sector count B466 85 C5 STA &C5 ;[D]to size of volume to be created B468 B9 D6 FD LDA &FDD6,Y ;and copy LSB B46B 85 C4 STA &C4 B46D 20 62 B0 JSR S062 ;[D]initialise volume catalogue B470 C8 INY ;advance volume letter by 1/sector by 2 B471 C8 INY B472 C0 10 CPY #&10 ;have we initialised 8 volumes/16 sectors? B474 D0 EA BNE S460 ;if not then loop to init all volumes B476 60 RTS .S477 ;Generate disc catalogue B477 20 11 BE JSR SE11 ;page in catalogue sector 0 B47A A9 20 LDA #&20 ;set version/configuration number = &20 B47C 8D 00 FD STA &FD00 ;indicating that sector count is big-endian B47F A9 12 LDA #&12 ;18 sectors per track B481 8D 03 FD STA &FD03 B484 A4 C0 LDY &C0 ;set number of tracks on disc B486 8C 04 FD STY &FD04 B489 A9 00 LDA #&00 ;mystery field (MSB no. tracks?), always 0 B48B 8D 05 FD STA &FD05 B48E 20 AE B5 JSR S5AE B491 A5 A8 LDA &A8 B493 8D 02 FD STA &FD02 ;store LSB number of sectors on disc B496 A5 A9 LDA &A9 B498 8D 01 FD STA &FD01 ;[D]store MSB B49B A0 01 LDY #&01 B49D 84 BB STY &BB ;data area starts on track 1 B49F 88 DEY .S4A0 B4A0 20 07 BE JSR SE07 ;page in auxiliary workspace B4A3 98 TYA ;save 2 * volume letter B4A4 48 PHA B4A5 B9 D5 FD LDA &FDD5,Y ;get MSB no. sectors in volume's data area B4A8 85 B1 STA &B1 ;store MSB dividend B4AA B9 D6 FD LDA &FDD6,Y ;get LSB no. sectors in volume's data area B4AD 85 B0 STA &B0 ;store LSB dividend B4AF 05 B1 ORA &B1 ;test number of requested sectors B4B1 F0 16 BEQ S4C9 ;if zero then volume absent, assign no tracks B4B3 20 11 BE JSR SE11 B4B6 A5 BB LDA &BB ;else set starting track of volume data area B4B8 99 08 FD STA &FD08,Y B4BB A9 00 LDA #&00 ;clear next byte (MSB track number?) B4BD 99 09 FD STA &FD09,Y B4C0 20 97 B5 JSR S597 ;[D]generate track multiple of at least req. B4C3 18 CLC B4C4 98 TYA B4C5 65 BB ADC &BB ;add number of tracks in Y to starting track B4C7 85 BB STA &BB .S4C9 B4C9 68 PLA ;skip to next volume entry B4CA A8 TAY B4CB C8 INY B4CC C8 INY B4CD C0 10 CPY #&10 ;loop until tracks assigned to 8 volumes B4CF D0 CF BNE S4A0 B4D1 60 RTS .S4D2 ;Read volume sizes and allocations B4D2 20 2E B5 JSR S52E ;copy volume allocations to workspace B4D5 20 11 BE JSR SE11 ;page in catalogue sector 0 B4D8 38 SEC B4D9 AD 02 FD LDA &FD02 ;get LSB number of sectors on disc B4DC E9 12 SBC #&12 ;subtract 18 sectors of catalogue track B4DE 85 C4 STA &C4 ;set LSB total sectors allocated to volumes B4E0 AD 01 FD LDA &FD01 ;borrow from MSB B4E3 E9 00 SBC #&00 B4E5 85 C5 STA &C5 B4E7 AD 04 FD LDA &FD04 ;get number of tracks on disc B4EA 85 C0 STA &C0 B4EC 20 02 B4 JSR S402 ;clear volume sizes B4EF A0 0E LDY #&0E ;start at volume H, cat. sector 14: ;Read volume sizes from the catalogue of each volume. ;This allows the size of each volume to be less than its allocation, ;in particular an allocation of 57 or more tracks may contain a volume ;of the maximum size, 1023 sectors (&3FF). .S4F1 B4F1 20 07 BE JSR SE07 ;page in auxiliary workspace B4F4 98 TYA ;y=2*volume B4F5 4A LSR A ;A=volume B4F6 AA TAX ;transfer to X for use as index B4F7 BD CD FD LDA &FDCD,X ;look up number of tracks in volume B4FA F0 2D BEQ S529 ;if volume absent then skip B4FC 84 BB STY &BB ;else set sector number = 2*volume B4FE E6 BB INC &BB ;add 1, point to 2nd sector of cat. B500 20 A5 96 JSR Q6A5 ;[D]set data pointer to &0200 B503 A9 01 LDA #&01 ;256 bytes to transfer B505 85 A1 STA &A1 B507 A9 00 LDA #&00 B509 85 A0 STA &A0 B50B A9 80 LDA #&80 ;data transfer call &80 = read data to JIM B50D 8D E9 FD STA &FDE9 ;[D]set data transfer call number B510 20 18 BA JSR SA18 ;transfer data L2 B513 20 11 BE JSR SE11 ;page in catalogue sector 0 B516 AD 06 FD LDA &FD06 ;get boot option/top bits volume size B519 29 03 AND #&03 ;extract MSB volume size B51B 48 PHA B51C AD 07 FD LDA &FD07 ;get LSB volume size from catalogue B51F 20 07 BE JSR SE07 ;page in auxiliary workspace B522 99 D6 FD STA &FDD6,Y ;set as LSB size of this volume B525 68 PLA B526 99 D5 FD STA &FDD5,Y ;set as MSB size of this volume .S529 B529 88 DEY ;proceed to previous volume B52A 88 DEY ;whose catalogue sector no. is two less B52B 10 C4 BPL S4F1 ;loop until all eight volumes read B52D 60 RTS .S52E ;Copy volume allocations to workspace B52E 20 BA AC JSR RCBA ;load disc catalogue L3 B531 A0 0E LDY #&0E ;start at sector offset 14, volume H B533 A2 07 LDX #&07 ;start at workspace offset 7, volume H .S535 B535 20 11 BE JSR SE11 ;page in catalogue sector 0 B538 B9 08 FD LDA &FD08,Y ;get first track of data area of volume B53B 20 07 BE JSR SE07 ;page in auxiliary workspace B53E 9D CD FD STA &FDCD,X ;store in workspace B541 88 DEY ;skip mystery field in sector B542 88 DEY ;decrement offset, work back from H to A B543 CA DEX ;decrement workspace offset B544 10 EF BPL S535 ;loop until 8 track numbers copied B546 60 RTS .S547 ;Compare requested allocation with limit B547 A5 B1 LDA &B1 B549 C5 B3 CMP &B3 B54B D0 04 BNE S551 B54D A5 B0 LDA &B0 B54F C5 B2 CMP &B2 .S551 B551 60 RTS .S552 ;Multiply by no. sectors per track B552 20 0C BE JSR SE0C ;page in main workspace B555 AC EB FD LDY &FDEB ;get number of sectors per track B558 A9 00 LDA #&00 ;clear product B55A 85 C4 STA &C4 B55C 85 C5 STA &C5 .S55E B55E 18 CLC ;add number of tracks to product B55F A5 B0 LDA &B0 B561 65 C4 ADC &C4 B563 85 C4 STA &C4 B565 90 02 BCC S569 ;carry out to high byte B567 E6 C5 INC &C5 .S569 B569 88 DEY ;loop until all sectors per track added B56A D0 F2 BNE S55E B56C 60 RTS .S56D ;Sum volume sizes B56D A2 00 LDX #&00 ;clear offset = 0, point to volume A B56F 86 B2 STX &B2 ;clear total .S571 B571 20 07 BE JSR SE07 ;page in auxiliary workspace B574 BD D6 FD LDA &FDD6,X ;get LSB requested size of volume at X B577 85 B0 STA &B0 ;set LSB current request B579 BD D5 FD LDA &FDD5,X ;get MSB requested size of volume at X B57C 85 B1 STA &B1 ;get MSB current request B57E 20 97 B5 JSR S597 ;generate track multiple of at least req. B581 18 CLC B582 98 TYA ;a = track count for this volume B583 65 B2 ADC &B2 ;add to total allocations B585 85 B2 STA &B2 B587 E8 INX ;add 2 to offset B588 E8 INX B589 E0 10 CPX #&10 ;loop until 8 allocations added B58B D0 E4 BNE S571 B58D 38 SEC ;subtract disc size - total allocations B58E A5 C0 LDA &C0 B590 E5 B2 SBC &B2 B592 A8 TAY ;=disc space free B593 88 DEY ;subtract 1 for catalogue track B594 4C AE B5 JMP S5AE ;multiply track count by 18 .S597 ;Generate track multiple of at least req. B597 A0 00 LDY #&00 B599 84 A8 STY &A8 ;clear LSB sector count B59B 84 A9 STY &A9 ;clear MSB sector count .S59D B59D A5 A8 LDA &A8 ;compare sector count - request B59F C5 B0 CMP &B0 B5A1 A5 A9 LDA &A9 B5A3 E5 B1 SBC &B1 B5A5 B0 06 BCS S5AD ;if sector count >= request then return it B5A7 C8 INY ;else add one track to track count B5A8 20 BE B5 JSR S5BE ;add 18 sectors to sector count B5AB 90 F0 BCC S59D ;and loop (always) .S5AD B5AD 60 RTS .S5AE ;Multiply track count by 18 B5AE A9 00 LDA #&00 B5B0 85 A8 STA &A8 ;clear LSB sector count B5B2 85 A9 STA &A9 ;clear MSB sector count B5B4 C8 INY ;pre-increment track count to exit on 0: .S5B5 B5B5 88 DEY ;have we added all tracks? B5B6 F0 05 BEQ S5BD ;if so then return sector count B5B8 20 BE B5 JSR S5BE ;else add 18 sectors to sector count B5BB 90 F8 BCC S5B5 ;and loop (always) .S5BD B5BD 60 RTS .S5BE ;Add 18 sectors to sector count B5BE 18 CLC B5BF A5 A8 LDA &A8 B5C1 69 12 ADC #&12 B5C3 85 A8 STA &A8 B5C5 90 02 BCC S5C9 ;carry out to MSB B5C7 E6 A9 INC &A9 .S5C9 B5C9 18 CLC B5CA 60 RTS .S5CB ;Get printable input character B5CB 20 EE B5 JSR S5EE ;get input character and acknowledge ESCAPE B5CE C9 30 CMP #&30 ;is ASCII value less than that of "0"? B5D0 90 F9 BCC S5CB ;if so then discard, get another character B5D2 C9 5B CMP #&5B ;else is ASCII value higher than "Z"? B5D4 B0 F5 BCS S5CB ;if so then discard, get another character B5D6 48 PHA ;else save input character B5D7 20 EE FF JSR &FFEE ;call OSWRCH to print it: .S5DA B5DA 20 EE B5 JSR S5EE ;get input character and acknowledge ESCAPE B5DD C9 0D CMP #&0D ;is it CR? B5DF D0 02 BNE S5E3 ;if not then test for DEL B5E1 68 PLA ;else restore first character and exit B5E2 60 RTS .S5E3 B5E3 C9 7F CMP #&7F ;was DELETE key pressed? B5E5 D0 F3 BNE S5DA ;if neither CR or DEL then get another B5E7 68 PLA ;else discard first character B5E8 20 48 B3 JSR S348 ;backspace and erase characters B5EB 4C CB B5 JMP S5CB ;and loop to get another character. .S5EE ;Get input character and acknowledge ESCAPE B5EE 20 E0 FF JSR &FFE0 ;call OSRDCH B5F1 B0 01 BCS S5F4 ;if C=1 then error occurred, test err. code B5F3 60 RTS ;else return character in A .S5F4 B5F4 C9 1B CMP #&1B ;test if error code from OSRDCH is &1B B5F6 F0 01 BEQ S5F9 ;if so then ESCAPE was pressed B5F8 60 RTS ;else return .S5F9 B5F9 20 0C BE JSR SE0C ;page in main workspace B5FC 20 8F A9 JSR R98F ;acknowledge ESCAPE condition B5FF 20 71 AD JSR RD71 ;release NMI B602 20 50 B6 JSR S650 ;[D]clear rows 20..22 B605 A6 B7 LDX &B7 ;[D]restore stack pointer from &B7 B607 9A TXS B608 6C E6 FD JMP (&FDE6) ;jump to action address .S60B ;Print "ERROR" B60B 20 50 B6 JSR S650 ;clear rows 20..22 B60E 20 17 A9 JSR R917 ;print VDU sequence immediate B611 EQUB &1F ;move cursor to (21,23) B612 EQUB &15 B613 EQUB &17 B614 EQUS "ERROR" ;[D]common routine shared by *FORMAT,*VERIFY B619 EQUB &FF B61A 60 RTS .S61B ;Prompt to start format B61B 20 17 A9 JSR R917 ;print VDU sequence immediate B61E EQUB &1C ;define text window (0,13)..(39,4) B61F EQUB &00 B620 EQUB &0D B621 EQUB &27 B622 EQUB &04 B623 EQUB &0C ;clear text window B624 EQUB &1A ;restore default windows B625 EQUB &FF B626 20 50 B6 JSR S650 ;clear rows 20..22 B629 20 17 A9 JSR R917 ;print VDU sequence immediate B62C EQUB &1F ;move cursor to (0,16) B62D EQUB &00 B62E EQUB &10 B62F EQUS "Press F(ret) to start " B646 EQUB &7F ;backspace and erase character B647 EQUB &FF B648 20 CB B5 JSR S5CB ;get printable input character B64B C9 46 CMP #&46 ;is it capital F? B64D D0 CC BNE S61B ;if not then reprint heading and try again B64F 60 RTS .S650 ;Clear rows 20..22 B650 A2 00 LDX #&00 ;move cursor to (0,20) B652 A0 10 LDY #&10 B654 20 D1 B2 JSR S2D1 ;move cursor to (X,Y) B657 A0 78 LDY #&78 ;print 120 spaces and exit B659 4C DD 8A JMP PADD ;print X spaces .S65C ;Prompt user and start format B65C 20 1B B6 JSR S61B ;prompt to start format B65F 20 D3 B6 JSR S6D3 ;ensure disc is write enabled B662 D0 F8 BNE S65C ;if write protected then try again B664 20 50 B6 JSR S650 ;else clear rows 20..22 B667 A9 80 LDA #&80 B669 85 B9 STA &B9 ;>0 disc operation is interruptible B66B A9 00 LDA #&00 B66D 85 BA STA &BA ;set track number = 0 B66F 85 BB STA &BB ;set running track skew counter = 0 B671 20 18 BB JSR SB18 ;create ID table and format track .S674 B674 A9 03 LDA #&03 ;make three attempts (outer) B676 85 BF STA &BF ;set attempt counter .S678 B678 20 EA B2 JSR S2EA ;poll for ESCAPE B67B 20 B3 B6 JSR S6B3 ;print track number in table B67E A0 03 LDY #&03 ;erase next 3 characters B680 20 2C B7 JSR S72C ;erase Y characters ahead of cursor B683 20 18 BB JSR SB18 ;create ID table and format track B686 20 21 B1 JSR S121 ;verify track with display B689 F0 09 BEQ S694 ;if succeeded then format next track B68B C6 BF DEC &BF ;else decrement attempt counter B68D D0 E9 BNE S678 ;if attempts remaining then try again B68F 20 0B B6 JSR S60B ;else print "ERROR" B692 38 SEC ;[D]set C=1, format failed B693 60 RTS .S694 B694 A9 FE LDA #&FE ;implement track skew B696 2C ED FD BIT &FDED ;a=-2 (in two's complement) B699 50 01 BVC S69C ;[D]if double density B69B 0A ASL A ;then A=-4: .S69C B69C 18 CLC ;subtract 2 or 4 from first R of track B69D 65 BB ADC &BB B69F B0 03 BCS S6A4 ;if it underflows B6A1 6D EB FD ADC &FDEB ;then add number of sectors per track .S6A4 B6A4 85 BB STA &BB ;set first sector number of track B6A6 E6 BA INC &BA ;increment track number B6A8 A5 BA LDA &BA B6AA C5 C0 CMP &C0 ;compare with total tracks B6AC B0 03 BCS S6B1 ;if >= total tracks then format complete B6AE 4C 74 B6 JMP S674 ;else loop to format next track .S6B1 B6B1 18 CLC ;[D]set C=0, format succeeded. B6B2 60 RTS .S6B3 ;Print track number in table B6B3 A2 00 LDX #&00 ;set column to 0 B6B5 A4 BA LDY &BA ;copy track number as row number .S6B7 B6B7 38 SEC B6B8 98 TYA B6B9 E9 0A SBC #&0A ;[D]subtract 10 from row number B6BB 90 08 BCC S6C5 ;if underflow then keep current row B6BD A8 TAY ;else set as new row number B6BE 18 CLC ;add 10 to column B6BF 8A TXA B6C0 69 05 ADC #&05 B6C2 AA TAX B6C3 90 F2 BCC S6B7 ;and loop until row < 0 .S6C5 B6C5 69 0E ADC #&0E ;[D]c=0, add 14 to negative remainder B6C7 A8 TAY ;set Y = row 4..13 B6C8 20 D1 B2 JSR S2D1 ;move cursor to (X,Y) B6CB A5 BA LDA &BA ;get track number B6CD 20 9D B3 JSR S39D ;[D]convert byte to three decimal digits B6D0 4C F1 A7 JMP R7F1 ;[D]print space-padded hex byte .S6D3 ;Ensure disc is write enabled #if defined _BUGFIX B6D3 20 05 B9 JSR S905 ;test write protect state of current drive #else B6D3 20 BC AD JSR RDBC ;test write protect state of current drive #endif B6D6 F0 2D BEQ S705 ;if write enabled then return B6D8 20 17 A9 JSR R917 ;else print VDU sequence immediate B6DB EQUB &1F ;[D]move cursor to (0,16) B6DC EQUB &00 B6DD EQUB &10 B6DE EQUS "Disk R/O...remove write protect" B6FD EQUB &0D B6FE EQUB &0A B6FF EQUB &FF B700 20 06 B7 JSR S706 ;prompt for keypress B703 A9 FF LDA #&FF ;return Z=0 [D]omit redundant row erase .S705 B705 60 RTS .S706 ;Prompt for keypress B706 20 17 A9 JSR R917 ;print VDU sequence immediate B709 EQUB &1F ;[D]move cursor to (4,17) B70A EQUB &04 B70B EQUB &11 B70C EQUS "Press any key to continue" B725 EQUB &FF B726 20 EE B5 JSR S5EE ;get input character and acknowledge ESCAPE B729 4C 50 B6 JMP S650 ;clear rows 20..22 and exit .S72C ;Erase Y characters ahead of cursor B72C 98 TYA B72D 48 PHA B72E 20 DD 8A JSR PADD ;print number of spaces in Y B731 68 PLA B732 A8 TAY .S733 B733 A9 7F LDA #&7F ;print number of DELs in Y B735 20 EE FF JSR &FFEE B738 88 DEY B739 D0 F8 BNE S733 B73B 60 RTS .S73C ;Make a short beep B73C A9 07 LDA #&07 ;BEL = make a short beep B73E 4C EE FF JMP &FFEE ;call OSWRCH .S741 ;Parse floppy volume spec from argument #if defined _BUGFIX B741 20 0E AA JSR RA0E ;parse volume spec from argument #else B741 20 16 AA JSR RA16 ;parse volume spec from argument #endif B744 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B747 D0 0E BNE S757 ;if so B749 4C D6 AA JMP RAD6 ;then raise "Bad drive" error. .S74C ;Set Z=1 iff current drive is a RAM disc B74C 20 D9 AA JSR RAD9 ;map current volume to physical volume B74F 29 07 AND #&07 ;mask drive no in b2..0 mask off volume letter B751 C9 04 CMP #&04 ;if physical drive = 4 B753 F0 02 BEQ S757 ;then return Z=1 B755 C9 05 CMP #&05 ;else return Z=1 if physical drive = 5. .S757 B757 60 RTS .S758 ;set display MODE 7 and place heading B758 20 C5 B2 JSR S2C5 ;set display MODE 7 B75B A0 00 LDY #&00 B75D C8 INY ;redundant B75E A2 0D LDX #&0D ;set X=13, Y=1 B760 20 D1 B2 JSR S2D1 ;move cursor to (X,Y) B763 C0 03 CPY #&03 ;redundant B765 60 RTS ;*FDCSTAT B766 BA TSX ;have A=0 returned on exit B767 A9 00 LDA #&00 B769 9D 05 01 STA &0105,X B76C 20 17 A9 JSR R917 ;print VDU sequence immediate B76F EQUB &0D B770 EQUB &0A B771 EQUS "WD 1770 status : " B782 EQUB &FF B783 AD F3 FD LDA &FDF3 ;get status of last command #if defined _BUGFIX .S786 #endif B786 20 78 A9 JSR R978 ;print hex byte B789 4C 69 84 JMP P469 ;print newline B78C A2 00 LDX #&00 ;&13 Read data / &17 Read data & deleted data B78E AD A2 01 LDA &01A2 ;&0B Write data B78F=LDX #&01 B791 AD A2 02 LDA &02A2 ; B792=LDX #&02 B794 AD A2 03 LDA &03A2 ;&0F Write deleted data B795=LDX #&03 B797 AD A2 04 LDA &04A2 ;&1F Verify data B798=LDX #&04 B79A 8E E9 FD STX &FDE9 ;set data transfer call number B79D B1 B0 LDA (&B0),Y ;get 2nd parameter = starting sector number B79F 85 BB STA &BB ;set starting sector B7A1 20 4C B7 JSR S74C ;[D]set Z=1 iff current drive is a RAM disc B7A4 D0 13 BNE S7B9 ;if so B7A6 A2 0A LDX #&0A ;then convert CS address per Acorn DFS to LBA B7A8 A0 00 LDY #&00 ;x = 10 sectors per track, Y = 0 MSB of LBA B7AA A5 BB LDA &BB ;begin with LSB of LBA = starting sector: .S7AC B7AC 18 CLC ;add one sector for each track skipped B7AD 65 BA ADC &BA B7AF 90 01 BCC S7B2 ;carry out to MSB B7B1 C8 INY .S7B2 B7B2 CA DEX ;loop until 10 sectors per track added B7B3 D0 F7 BNE S7AC ;thereby adding product = no. sectors skipped B7B5 85 BB STA &BB ;store LSB of LBA B7B7 84 BA STY &BA ;store MSB of LBA (big-endian) .S7B9 B7B9 A0 09 LDY #&09 B7BB B1 B0 LDA (&B0),Y ;get number of sectors + size code B7BD 20 9D A9 JSR R99D ;shift A right 5 places B7C0 AA TAX ;save size code in X B7C1 A9 00 LDA #&00 ;set LSB of byte count = 0 B7C3 85 A0 STA &A0 B7C5 B1 B0 LDA (&B0),Y ;get number of sectors + size code B7C7 C8 INY ;increment offset; Y = 10, points to status B7C8 29 1F AND #&1F ;extract number of sectors B7CA 4A LSR A ;A,&A0 = 256 x sector count; divide by two B7CB 66 A0 ROR &A0 ;= byte count if X=0, 128-byte sectors B7CD 90 03 BCC S7D2 ;jump into doubling loop (always) .S7CF B7CF 06 A0 ASL &A0 ;multiply byte count by two B7D1 2A ROL A .S7D2 B7D2 CA DEX ;subtract 1 from X B7D3 10 FA BPL S7CF ;if X was >0 then double byte count B7D5 85 A1 STA &A1 ;else store high byte of byte count B7D7 4C 18 BA JMP SA18 ;[D]transfer data L2 and exit ;&29 Seek #if defined _BUGFIX B7DA 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B7DD F0 5C BEQ S83B ;if a RAM disc then nothing to do, exit B7DF 20 16 B9 JSR S916 ;else seek logical track #else B7DA 20 E3 B7 JSR S7E3 ;set A=0, C=1 if RAM else A=physical drive B7DD B0 03 BCS S7E2 ;if a RAM disc then nothing to do, exit B7DF 20 16 B9 JSR S916 ;else seek logical track .S7E2 #endif B7E2 60 RTS #if defined _BUGFIX .S7E3 ;Print number of sectors B7E3 A5 C4 LDA &C4 ;get MSB size of file or slack space B7E5 20 80 A9 JSR R980 ;print hex nibble B7E8 A5 C5 LDA &C5 ;get LSB size of file or slack space B7EA 4C 78 A9 JMP R978 ;print hex byte #else ;routine redundant to S74C .S7E3 ;Set A=0, C=1 if RAM else A=physical drive B7E3 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B7E6 18 CLC ;if a floppy drive B7E7 D0 03 BNE S7EC ;then return C=0, A=physical drive, Z=0 B7E9 A9 00 LDA #&00 B7EB 38 SEC ;else return C=1, A=0, Z=1 .S7EC B7EC 60 RTS #endif ;&1B Read ID B7ED A0 09 LDY #&09 ;offset 9 = third parameter B7EF B1 B0 LDA (&B0),Y ;get number of IDs to return B7F1 D0 02 BNE S7F5 ;zero is reserved for internal use B7F3 A9 01 LDA #&01 ;in which case return one ID .S7F5 B7F5 85 BB STA &BB ;set number of IDs to return B7F7 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B7FA F0 1C BEQ S818 ;if so then emulate IDs B7FC 20 16 B9 JSR S916 ;seek logical track B7FF 20 5F B9 JSR S95F ;read ID and detect density B802 D0 13 BNE S817 ;if command failed then exit B804 48 PHA ;else save command result = 0 B805 A5 BB LDA &BB ;get number of IDs to return B807 0A ASL A ;multiply by 4 = number of ID bytes B808 0A ASL A B809 AA TAX ;transfer to X to use as counter B80A A0 00 LDY #&00 ;start at offset 0: .S80C B80C B9 0C 0D LDA &0D0C,Y ;get byte of ID read from workspace B80F 20 E0 A4 JSR R4E0 ;put data byte in user memory B812 C8 INY ;increment offset B813 CA DEX ;loop until X bytes returned to user B814 D0 F6 BNE S80C B816 68 PLA ;restore command result .S817 B817 60 RTS #if defined _BUGFIX .S818 ;emulate RAM disc sector IDs B818 A0 00 LDY #&00 ;start at beginning of user memory B81A A2 00 LDX #&00 ;first sector number = 0 .S81C ;Create ID table B81C A5 BA LDA &BA ;get track number C B81E 20 E0 A4 JSR R4E0 ;put data byte in user memory B821 C8 INY B822 A9 00 LDA #&00 ;head number = 0 H B824 20 E0 A4 JSR R4E0 ;put data byte in user memory B827 C8 INY B828 8A TXA ;transfer sector number R B829 20 E0 A4 JSR R4E0 ;put data byte in user memory B82C C8 INY B82D A9 01 LDA #&01 ;size code = 1, 256 b N B82F 20 E0 A4 JSR R4E0 ;put data byte in user memory B832 C8 INY B833 E8 INX ;increment sector number B834 C6 BB DEC &BB ;loop until required no. sector IDs created B836 D0 E4 BNE S81C B838 20 96 B9 JSR S996 ;set up drive for single density .S83B #else /* _BUGFIX */ .S818 ;emulate RAM disc sector IDs B818 68 PLA ;[BUG] destroys return address, crashes B819 A0 00 LDY #&00 ;start at beginning of user memory B81B A2 00 LDX #&00 ;first sector number = 0 .S81D ;Create ID table B81D A5 BA LDA &BA ;get track number C B81F 20 E0 A4 JSR R4E0 ;put data byte in user memory B822 C8 INY B823 A9 00 LDA #&00 ;head number = 0 H B825 20 E0 A4 JSR R4E0 ;put data byte in user memory B828 C8 INY B829 8A TXA ;transfer sector number R B82A 20 E0 A4 JSR R4E0 ;put data byte in user memory B82D C8 INY B82E A9 01 LDA #&01 ;size code = 1, 256 b N B830 20 E0 A4 JSR R4E0 ;put data byte in user memory B833 E8 INX ;increment sector number [BUG] no INY B834 C6 BB DEC &BB ;loop until required no. sector IDs created B836 D0 E5 BNE S81D B838 20 96 B9 JSR S996 ;set up drive for single density #endif /* _BUGFIX */ B83B A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. B83D 60 RTS ;&23 Format track #if defined _BUGFIX B83E 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B841 F0 0B BEQ S84E ;if RAM then set density of RAM disc #else B83E 20 E3 B7 JSR S7E3 ;Set A=0, C=1 if RAM else A=physical drive B841 B0 0B BCS S84E ;if RAM then set density of RAM disc #endif B843 C8 INY ;else offset 9 = no. sectors + size code B844 B1 B0 LDA (&B0),Y B846 29 1F AND #&1F ;extract number of sectors B848 8D EB FD STA &FDEB ;store number of sectors per track B84B 4C 58 BB JMP SB58 ;format track .S84E B84E AD ED FD LDA &FDED ;get density flag B851 29 40 AND #&40 ;mask bit 6 = double density B853 8D FE FD STA &FDFE ;store RAM disc density flag B856 A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. B858 60 RTS ;&2C Read drive status B859 88 DEY ;y = 8 going to 7, offset of result B85A 20 05 B9 JSR S905 ;test write protect state B85D 4A LSR A ;returned in bit 6 B85E 4A LSR A ;move to bit 3 = WR PROT B85F 4A LSR A B860 09 44 ORA #&44 ;set b6 = RDY 1, b2 = RDY 0 .S862 B862 60 RTS ;return result to user's OSWORD &7F block ;&35 Specify B863 A5 BA LDA &BA ;get first parameter B865 C9 0D CMP #&0D ;is it &0D = Specify Initialization? B867 D0 F9 BNE S862 ;if not then exit B869 B1 B0 LDA (&B0),Y ;else get second parameter = step rate B86B AA TAX ;(WD1770 format; 0=fast..3=slow; b7..2=0) B86C 4C 01 B9 JMP S901 ;save as track stepping rate ;returns stepping rate as result ;NB 8271 command result undefined ;&3A Write special registers B86F B1 B0 LDA (&B0),Y ;get second parameter = value to write B871 A6 BA LDX &BA ;get first parameter = register address B873 E0 05 CPX #&05 ;[D]if address in range 0..4 B875 B0 04 BCS S87B B877 9D EA FD STA &FDEA,X ;then set parameter of current drive B87A 60 RTS ;returns it as result ;NB 8271 command result undefined .S87B B87B A0 00 LDY #&00 ;[D]else point to unit 0 track position B87D E0 12 CPX #&12 ;if address = 18 B87F F0 05 BEQ S886 ;then set unit 0 position B881 C8 INY ;else point to unit 1 track position B882 E0 1A CPX #&1A ;if address <> 26 B884 D0 24 BNE S8AA ;then exit with result = 0 .S886 B886 99 EF FD STA &FDEF,Y ;else store physical position of head B889 A9 00 LDA #&00 ;return result = 0, succeeded. B88B 60 RTS ;NB 8271 command result undefined ;&3D Read special registers B88C A6 BA LDX &BA ;get first parameter = register address B88E E0 05 CPX #&05 ;if address in range 0..3 B890 B0 06 BCS S898 B892 BD EA FD LDA &FDEA,X ;then return parameter of current drive B895 91 B0 STA (&B0),Y ;return to offset 8 of OSWORD control block B897 60 RTS .S898 B898 A9 00 LDA #&00 ;[D]else point to unit 0 track position B89A E0 12 CPX #&12 ;if address = 18 B89C F0 06 BEQ S8A4 ;then return unit 0 position B89E A9 01 LDA #&01 ;else point to unit 1 track position B8A0 E0 1A CPX #&1A ;if address <> 26 B8A2 D0 06 BNE S8AA ;then exit with result = 0 .S8A4 B8A4 AA TAX ;else transfer offset to X B8A5 BD EF FD LDA &FDEF,X ;get physical track number for drive #if defined _BUGFIX B8A8 60 RTS ;return result byte to OSWORD &7F block #else B8A8 91 B0 STA (&B0),Y ;store result byte (immediately clobbered): #endif .S8AA B8AA A9 00 LDA #&00 ;[BUG]returns 0 instead of register value B8AC 60 RTS ;Table of 8271 floppy drive controller commands with action addresses B8AD EQUB &13 ;&13 Read data &B78C B8AE EQUW &8B,&B7 B8B0 EQUB &0B ;&0B Write data &B78F B8B1 EQUW &8E,&B7 B8B3 EQUB &29 ;&29 Seek &B7DA B8B4 EQUW &D9,&B7 B8B6 EQUB &1F ;&1F Verify data &B798 B8B7 EQUW &97,&B7 B8B9 EQUB &17 ;&17 Read data & deleted data &B78C B8BA EQUW &8B,&B7 B8BC EQUB &0F ;&0F Write deleted data &B795 B8BD EQUW &94,&B7 B8BF EQUB &1B ;&1B Read ID &B7ED B8C0 EQUW &EC,&B7 B8C2 EQUB &23 ;&23 Format track &B83E B8C3 EQUW &3D,&B8 B8C5 EQUB &2C ;&2C Read drive status &B859 B8C6 EQUW &58,&B8 B8C8 EQUB &35 ;&35 Specify &B863 B8C9 EQUW &62,&B8 B8CB EQUB &3A ;&3A Write special registers &B86F B8CC EQUW &6E,&B8 B8CE EQUB &3D ;&3D Read special registers &B88C B8CF EQUW &8B,&B8 B8D1 EQUB &00 ;terminator byte .S8D2 ;Set control latch for drive B8D2 20 4C A8 JSR R84C ;[D]save AXY B8D5 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B8D8 F0 14 BEQ S8EE ;if so then nothing to do, return B8DA 20 D9 AA JSR RAD9 ;else map current volume to physical volume B8DD 29 07 AND #&07 ;extract physical drive number, clear b7..3 B8DF AA TAX ;put drive number in X B8E0 AD ED FD LDA &FDED ;get density flag B8E3 29 7F AND #&7F ;mask off b7=automatic density B8E5 49 40 EOR #&40 ;invert b6, now 0=double density 1=single B8E7 4A LSR A ;move to bit 5 B8E8 1D EF B8 ORA &B8EF,X ;apply flags for drive 0..7 in X B8EB 8D FC FC STA &FCFC ;store in control latch .S8EE B8EE 60 RTS ;+---+---+---+---+---+---+---+---+--------+ ;|b 7|b 6|b 5|b 4|b 3|b 2|b 1|b 0| | ;+---+---+---+---+---+---+---+---+--------+ ;|CLK|DEN| - | - | - | - |SEL|DS | 2791HD | ;| - | - |RES|INT|DEN|SEL|DS1|DS0| B+ | ;| - | - |DEN|SEL|DS2|RES|DS1|DS0| Master | ;| - | - |DEN|RES|DS2|DS1|DS0|SEL|Chal'ger| ;+---+---+---+---+---+---+---+---+--------+ ;| 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | X = 00 | ;+---+---+---+---+---+---+---+---+--------+ ;| 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | X = 01 | ;+---+---+---+---+---+---+---+---+--------+ ;| 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | X = 02 | ;+---+---+---+---+---+---+---+---+--------+ ;| 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | X = 03 | ;+---+---+---+---+---+---+---+---+--------+ ;| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | X = 04 | ;+---+---+---+---+---+---+---+---+--------+ ;| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | X = 05 | ;+---+---+---+---+---+---+---+---+--------+ ;| 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | X = 06 | ;+---+---+---+---+---+---+---+---+--------+ ;| 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | X = 07 | ;+---+---+---+---+---+---+---+---+--------+ ;Table of drive control latch values for drives 0..7 B8EF EQUB &12,&14,&13,&15 B8F3 EQUB &FF,&FF,&18,&19 ;drives 4 and 5 are RAM discs .S8F7 ;Set track stepping rate from startup options B8F7 20 4C A8 JSR R84C ;save AXY B8FA 20 F0 AD JSR RDF0 ;call OSBYTE &FF = read/write startup options B8FD 8A TXA ;transfer keyboard links to A B8FE 20 96 A9 JSR R996 ;extract b5,b4 of A .S901 B901 8D F2 FD STA &FDF2 ;save as track stepping rate B904 60 RTS ;1770 doesn't need Force Interrupt?? .S905 ;Test write protect state of current drive B905 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc B908 F0 09 BEQ S913 ;if so then return A=&00, Z=1 write enabled B90A 20 F3 B9 JSR S9F3 ;else issue Seek and Force Interrupt B90D 20 16 BD JSR SD16 ;wait for command completion B910 29 40 AND #&40 ;z=0 if WD1770 S6 = write protect. B912 60 RTS .S913 B913 A9 00 LDA #&00 B915 60 RTS ;The Challenger unit does not connect the WD 1770's INTRQ pin. ;No NMI occurs as a result of the Seek command and the contents of the ;NMI service area at &0D00 may safely be left undefined. .S916 ;Seek logical track B916 20 0C BE JSR SE0C ;page in main workspace B919 A5 BA LDA &BA ;get logical track number B91B 2C EA FD BIT &FDEA ;test double-stepping flag B91E 50 01 BVC S921 ;if b6=1 then double stepping is enabled B920 0A ASL A ;so double track number: .S921 ;Seek physical track B921 20 D2 B8 JSR S8D2 ;[D]set control latch for drive #if defined _TURBO B924 20 79 A8 JSR R879 ;[D]save XY #else B924 20 75 A8 JSR R875 ;[D]save XY #endif B927 48 PHA ;save target physical track B928 20 A0 BC JSR SCA0 ;set X=physical floppy unit for current drive B92B BD EF FD LDA &FDEF,X ;get physical track number for drive B92E 20 9C BC JSR SC9C ;write to FDC track register B931 68 PLA ;get back A B932 9D EF FD STA &FDEF,X ;store physical track number for drive B935 20 02 BD JSR SD02 ;write to FDC data register B938 C9 00 CMP #&00 ;if track number = 0 B93A F0 02 BEQ S93E ;then issue WD1770 FDC command &00 = Restore B93C A9 10 LDA #&10 ;else issue WD1770 FDC command &10 = Seek: .S93E ;Execute Restore/Seek command B93E 2C F8 FC BIT &FCF8 ;[D]test FDC status register B941 08 PHP ;[D]save WD1770 S7 = motor on in N B942 0D F2 FD ORA &FDF2 ;apply track stepping rate B945 20 FA BC JSR SCFA ;write to FDC command register B948 20 16 BD JSR SD16 ;wait for command completion B94B 28 PLP ;[D]restore previous status B94C 30 10 BMI S95E ;if motor was on then exit B94E AD E9 FD LDA &FDE9 ;else get data transfer call number B951 4A LSR A ;test bit 0 B952 90 0A BCC S95E ;if reading or verifying data then exit B954 A0 00 LDY #&00 ;else wait 295 milliseconds then exit: .S956 B956 EA NOP ;allow extra head settling time B957 EA NOP ;before writing B958 CA DEX B959 D0 FB BNE S956 B95B 88 DEY ;this point reached every 1.1 milliseconds B95C D0 F8 BNE S956 .S95E B95E 60 RTS .S95F ;Read ID and detect density #if defined _TURBO B95F 20 79 A8 JSR R879 ;save XY #else B95F 20 75 A8 JSR R875 ;save XY #endif B962 20 0C BE JSR SE0C ;page in main workspace B965 20 F3 B9 JSR S9F3 ;issue Seek and Force Interrupt B968 A2 05 LDX #&05 ;[D]5 attempts to make, 3 in SD + 2 in DD B96A 2C ED FD BIT &FDED ;if current density is single B96D 50 13 BVC S982 ;then attempt in single density first B96F CA DEX ;[D]else only 2 attempts in DD + 2 in SD: .S970 B970 AD ED FD LDA &FDED ;get density flag B973 09 40 ORA #&40 ;set b6=1, double density B975 A0 12 LDY #&12 ;18 sectors per track B977 20 AC B9 JSR S9AC ;execute Read Address at specified density B97A F0 2D BEQ S9A9 ;if record found then return success B97C 2C ED FD BIT &FDED ;[D]else test density flag B97F 10 15 BPL S996 ;if b7=0 manual density then return failure B981 CA DEX ;else decrement number of attempts remaining ;[D]not testing it here. [BUG] when SD ;selected, detection takes longer to fail .S982 B982 AD ED FD LDA &FDED ;get density flag B985 29 BF AND #&BF ;set b6=0, single density B987 A0 0A LDY #&0A ;10 sectors per track B989 20 AC B9 JSR S9AC ;execute Read Address at specified density B98C F0 1B BEQ S9A9 ;if record found then return success B98E 2C ED FD BIT &FDED ;[D]else test density flag B991 10 03 BPL S996 ;if b7=0 manual density then return failure B993 CA DEX ;else decrement number of attempts remaining B994 D0 DA BNE S970 ;if attempts remaining try double density .S996 B996 AD ED FD LDA &FDED ;else set b6=0, single density B999 29 BF AND #&BF B99B 8D ED FD STA &FDED B99E 20 D2 B8 JSR S8D2 ;set control latch for drive B9A1 A9 0A LDA #&0A ;set 10 sectors per track B9A3 8D EB FD STA &FDEB B9A6 A9 18 LDA #&18 ;fake WD1770 S4 = record not found B9A8 60 RTS ;fake WD1770 S3 = CRC error. .S9A9 B9A9 A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. B9AB 60 RTS .S9AC ;Execute Read Address at specified density B9AC 8D ED FD STA &FDED ;store density flag B9AF 8C EB FD STY &FDEB ;store number of sectors per track: .S9B2 ;Execute Read Address command #if defined _TURBO B9B2 20 79 A8 JSR R879 ;save XY #else B9B2 20 75 A8 JSR R875 ;save XY #endif B9B5 20 16 B9 JSR S916 ;[D]seek logical track B9B8 A0 0B LDY #&0B ;[D]12 bytes to copy, &0D00..0B: .S9BA B9BA B9 BA BD LDA &BDBA,Y ;get byte of NMI read ID B9BD 99 00 0D STA &0D00,Y ;store in NMI area B9C0 88 DEY ;loop until all bytes copied B9C1 10 F7 BPL S9BA B9C3 08 PHP ;save interrupt state B9C4 A6 BB LDX &BB ;[D]test no. IDs to read B9C6 F0 08 BEQ S9D0 ;0 = internal use, skip wait for index B9C8 78 SEI ;else disable interrupts .S9C9 B9C9 AD F8 FC LDA &FCF8 ;load FDC status register B9CC 29 02 AND #&02 ;test WD1770 S1 = index B9CE F0 F9 BEQ S9C9 ;loop until index pulse from drive .S9D0 B9D0 A0 00 LDY #&00 ;then wait 640.5 microseconds .S9D2 B9D2 88 DEY B9D3 D0 FD BNE S9D2 B9D5 A9 C0 LDA #&C0 ;WD1770 command &C0 = Read address B9D7 8D F8 FC STA &FCF8 ;write to FDC command register B9DA 20 16 BD JSR SD16 ;wait for command completion B9DD D0 0B BNE S9EA ;[D]if command succeeded B9DF CE 05 0D DEC &0D05 ;then backspace over CRC bytes B9E2 CE 05 0D DEC &0D05 B9E5 CA DEX ;decrement number of IDs to read B9E6 30 02 BMI S9EA ;if an internal call then finish B9E8 D0 E6 BNE S9D0 ;else loop until all IDs read, then: .S9EA B9EA 28 PLP ;restore interrupt state B9EB AD F8 FC LDA &FCF8 ;WD1770 S4 = record not found B9EE 29 18 AND #&18 ;WD1770 S3 = CRC error B9F0 4C 0C BE JMP SE0C ;mask off other bits, page in main workspace. .S9F3 ;Issue Seek and Force Interrupt B9F3 20 D2 B8 JSR S8D2 ;set control latch for drive B9F6 A9 18 LDA #&18 ;WD1770 command &18 = Seek w/spin up B9F8 20 FA BC JSR SCFA ;write to FDC command register B9FB A2 0F LDX #&0F ;wait 38 microseconds .S9FD B9FD CA DEX B9FE D0 FD BNE S9FD .SA00 BA00 A9 D0 LDA #&D0 ;WD1770 command &D0 = Force interrupt BA02 4C FA BC JMP SCFA ;write to FDC command register and exit .SA05 ;Verify track #if defined _TURBO BA05 20 79 A8 JSR R879 ;save XY #else BA05 20 75 A8 JSR R875 ;save XY #endif BA08 A9 00 LDA #&00 BA0A 85 BB STA &BB ;sector number = 0 BA0C 85 A0 STA &A0 ;whole number of sectors to transfer BA0E AD EB FD LDA &FDEB ;get number of sectors per track BA11 85 A1 STA &A1 ;set number of sectors to transfer BA13 A9 04 LDA #&04 ;set call number to &04, verify data BA15 8D E9 FD STA &FDE9 ;set data transfer call number .SA18 ;Transfer data L2 #if defined _TURBO BA18 20 79 A8 JSR R879 ;save XY (inner) #else BA18 20 75 A8 JSR R875 ;save XY (inner) #endif BA1B 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc BA1E D0 03 BNE SA23 ;if floppy then transfer data to disc L2 BA20 4C 67 BE JMP SE67 ;else transfer data to paged RAM .SA23 ;Transfer data to disc L2 BA23 A5 A0 LDA &A0 ;save ?&A0, ?&A1 on stack BA25 48 PHA BA26 A5 A1 LDA &A1 BA28 48 PHA BA29 20 D2 B8 JSR S8D2 ;set control latch for drive BA2C 20 16 B9 JSR S916 ;seek logical track BA2F A5 BA LDA &BA ;get logical track number BA31 20 94 BC JSR SC94 ;store physical position of head ;This sets the FDC's track register to the logical track number so that ;sectors on 40-in-80 discs can be recognised. The track register and the ;drive's current track number in the workspace are re-set to the physical ;track number after the operation at &BA93. BA34 20 FB BA JSR SAFB ;copy NMI read from disc/polling loop to NMI BA37 AD EE FD LDA &FDEE ;get *OPT 9 saverom slot number BA3A 8D 2D 0D STA &0D2D ;store in polling loop to page in on entry BA3D AD E9 FD LDA &FDE9 ;get data transfer call number BA40 48 PHA ;[D]save on stack BA41 29 05 AND #&05 ;if call=0 or 2, read (deleted) data BA43 F0 09 BEQ SA4E ;then branch BA45 6A ROR A ;else if b2..0 = 1x0, A=&04 verify data BA46 B0 10 BCS SA58 BA48 20 EF BA JSR SAEF ;[D]then instruction at &0D06 = JMP &0D11 BA4B 4C 6A BA JMP SA6A ;discard byte from FDC data register .SA4E BA4E A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 BA50 F0 02 BEQ SA54 ;not rounding up, converting number format; BA52 E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .SA54 BA54 A0 07 LDY #&07 ;if call=0 or 2, read (deleted) data BA56 D0 0F BNE SA67 ;then data address is located at &0D07. .SA58 BA58 A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 BA5A F0 02 BEQ SA5E ;not rounding up, converting number format; BA5C E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .SA5E BA5E A9 00 LDA #&00 ;if b0=1, A=1 or 3 write (deleted) data BA60 85 A0 STA &A0 ;then clear ?&A0, write whole sectors BA62 20 07 BB JSR SB07 ;copy NMI write to disc to NMI area BA65 A0 04 LDY #&04 ;data address is located at &0D04 .SA67 BA67 20 A0 BA JSR SAA0 ;set data address in NMI ISR .SA6A BA6A A5 F4 LDA &F4 ;get Challenger ROM slot number BA6C 8D 38 0D STA &0D38 ;save in NMI area BA6F A5 BB LDA &BB ;get start sector number BA71 20 FE BC JSR SCFE ;write to FDC sector register BA74 68 PLA ;restore data transfer call number BA75 29 07 AND #&07 ;[D]mask bits 2..0 BA77 48 PHA ;save it again BA78 A8 TAY ;transfer to Y BA79 B9 52 BD LDA &BD52,Y ;get FDC command for call BA7C 20 FA BC JSR SCFA ;write to FDC command register BA7F A2 1E LDX #&1E ;wait 76 microseconds .SA81 BA81 CA DEX BA82 D0 FD BNE SA81 BA84 20 2C 0D JSR &0D2C ;page SROM in and wait until finished L0 BA87 20 0C BE JSR SE0C ;page in main workspace (redundant) BA8A 68 PLA BA8B A8 TAY BA8C 20 27 BD JSR SD27 ;load FDC status register and store b6..0 BA8F 39 57 BD AND &BD57,Y ;apply status mask from table to set Z BA92 A8 TAY ;present FDC status register in A BA93 20 8C BC JSR SC8C ;store head position for this drive .SA96 BA96 68 PLA ;restore ?&A0, ?&A1 from stack BA97 85 A1 STA &A1 BA99 68 PLA BA9A 85 A0 STA &A0 BA9C 98 TYA BA9D 4C 0C BE JMP SE0C ;page in main workspace .SAA0 ;Set data address in NMI ISR BAA0 AD E9 FD LDA &FDE9 ;[D]test data transfer call number BAA3 30 2A BMI SACF ;if b7=1 then transferring to JIM, branch BAA5 AD CC FD LDA &FDCC ;else test Tube data transfer flag BAA8 F0 1A BEQ SAC4 ;if transferring data to Tube BAAA A9 E5 LDA #&E5 ;then paste address of R3DATA at &0D00+Y BAAC 99 00 0D STA &0D00,Y BAAF A9 FE LDA #&FE BAB1 99 01 0D STA &0D01,Y BAB4 A9 4C LDA #&4C ;instruction at &0D09 = JMP &0D11 BAB6 8D 09 0D STA &0D09 ;do not increment R3DATA address BAB9 A9 11 LDA #&11 BABB 8D 0A 0D STA &0D0A BABE A9 0D LDA #&0D BAC0 8D 0B 0D STA &0D0B BAC3 60 RTS .SAC4 BAC4 A5 A6 LDA &A6 ;else copy data pointer to NMI ISR at &0D00+Y BAC6 99 00 0D STA &0D00,Y BAC9 A5 A7 LDA &A7 BACB 99 01 0D STA &0D01,Y BACE 60 RTS .SACF ;Enable JIM select in NMI read from disc BACF A9 20 LDA #&20 ;&0D0E = JSR &0D3D BAD1 8D 0E 0D STA &0D0E BAD4 A9 3D LDA #&3D BAD6 8D 0F 0D STA &0D0F BAD9 A9 0D LDA #&0D BADB 8D 10 0D STA &0D10 BADE A5 A6 LDA &A6 ;insert 2MSB of JIM address = LSB page no. BAE0 8D 41 0D STA &0D41 BAE3 8D FF FC STA &FCFF ;and page it in BAE6 A5 A7 LDA &A7 ;insert MSB of JIM address = MSB page no. BAE8 8D 4B 0D STA &0D4B BAEB 8D FE FC STA &FCFE ;and page it in BAEE 60 RTS .SAEF ;Copy NMI verify to NMI area BAEF A0 02 LDY #&02 ;3 bytes to copy, &0D06..8: .SAF1 BAF1 B9 C6 BD LDA &BDC6,Y ;get byte of NMI verify BAF4 99 06 0D STA &0D06,Y ;store in NMI area BAF7 88 DEY ;loop until all bytes copied BAF8 10 F7 BPL SAF1 BAFA 60 RTS .SAFB ;Copy NMI read from disc/polling loop to NMI BAFB A0 4F LDY #&4F ;80 bytes to copy, &0D00..4F: .SAFD BAFD B9 5C BD LDA &BD5C,Y ;get byte of NMI read from disc/polling loop BB00 99 00 0D STA &0D00,Y ;store in NMI area BB03 88 DEY ;loop until all bytes copied BB04 10 F7 BPL SAFD BB06 60 RTS .SB07 ;Copy NMI write to disc to NMI area BB07 A0 0D LDY #&0D ;14 bytes to copy, &0D03..10: .SB09 BB09 B9 AC BD LDA &BDAC,Y ;get byte of NMI write to disc BB0C 99 03 0D STA &0D03,Y ;patch NMI read to disc routine with it BB0F 88 DEY ;loop until all bytes copied BB10 10 F7 BPL SB09 BB12 A9 FC LDA #&FC ;enable 123 microsecond delay BB14 8D 23 0D STA &0D23 ;before interrupting write operation BB17 60 RTS ;so that FDC will write CRC of sector .SB18 ;Create ID table and format track BB18 A9 0A LDA #&0A ;set A = 10 sectors per track BB1A 2C ED FD BIT &FDED ;if double density format BB1D 50 02 BVC SB21 BB1F A9 12 LDA #&12 ;then set A = 18 sectors per track .SB21 BB21 85 A6 STA &A6 ;store as limit to sector count BB23 8D EB FD STA &FDEB ;store as no. sectors per track of disc BB26 0A ASL A ;multiply by 4 BB27 0A ASL A BB28 85 A7 STA &A7 ;store as size of CHRN table BB2A A6 BB LDX &BB ;set X = number of first sector BB2C A0 00 LDY #&00 ;(inverse track skew) Y=0 CHRN tbl index .SB2E BB2E A5 BA LDA &BA ;Get logical track number BB30 99 61 FD STA &FD61,Y ;store cylinder number C BB33 C8 INY BB34 A9 00 LDA #&00 ;head number = 0 BB36 99 61 FD STA &FD61,Y ;store head humber H BB39 C8 INY BB3A 8A TXA ;transfer sector number to A BB3B 99 61 FD STA &FD61,Y ;store record number R BB3E C8 INY BB3F A9 01 LDA #&01 ;size code = 1, 256-byte sector BB41 99 61 FD STA &FD61,Y ;store size code N BB44 C8 INY BB45 E8 INX ;increment sector number BB46 E4 A6 CPX &A6 ;has it reached no. sectors per track? BB48 90 02 BCC SB4C BB4A A2 00 LDX #&00 ;if so then wrap around to 0 .SB4C BB4C C4 A7 CPY &A7 ;has table offset reached 4x s.p.t? BB4E 90 DE BCC SB2E ;if not then loop BB50 A9 61 LDA #&61 ;else set pointer to start of CHRN table: BB52 85 A6 STA &A6 BB54 A9 FD LDA #&FD BB56 85 A7 STA &A7 .SB58 ;Format track BB58 A9 12 LDA #&12 ;set run table pointer to &000612 in JIM BB5A 85 A4 STA &A4 ;(page breaks occur 5/8 through fifth, BB5C A9 06 LDA #&06 ;1/8 through eleventh and in gap2 of BB5E 48 PHA ;seventeenth sector of track.) BB5F 85 A5 STA &A5 BB61 A2 00 LDX #&00 ;point to single density table, X = &00 BB63 2C ED FD BIT &FDED ;if double density format BB66 50 02 BVC SB6A BB68 A2 23 LDX #&23 ;then point to double density table, X = &23 .SB6A BB6A AD EB FD LDA &FDEB ;[D]get number of sectors per track BB6D 85 A2 STA &A2 ;set as counter BB6F 20 3A BC JSR SC3A ;page in JIM page 6..9 BB72 A0 05 LDY #&05 ;set Y = 5 as counter: .SB74 BB74 20 BB BB JSR SBBB ;add entry to track format RLE table BB77 88 DEY ;loop until 5 entries added BB78 D0 FA BNE SB74 ;this copies gap 5, IDAM and start of gap 1 BB7A 86 A3 STX &A3 ;X points to repeating sector block .SB7C BB7C A6 A3 LDX &A3 ;[D]reset X to start of sector block .SB7E BB7E 20 BB BB JSR SBBB ;add entry to track format RLE table BB81 90 FB BCC SB7E ;loop until terminator byte reached BB83 C6 A2 DEC &A2 ;decrement number of sectors remaining BB85 D0 F5 BNE SB7C ;loop until all sectors added to track BB87 A9 00 LDA #&00 ;data byte = &00 (run length = &10 or &16) BB89 20 14 BC JSR SC14 ;add gap 4 to table BB8C 20 0C BE JSR SE0C ;page in main workspace BB8F 20 16 B9 JSR S916 ;seek logical track BB92 A2 FF LDX #&FF BB94 A0 10 LDY #&10 ;A = &10 BB96 2C ED FD BIT &FDED ;if double density format BB99 50 04 BVC SB9F BB9B A0 28 LDY #&28 ;then A = &28 BB9D A2 4E LDX #&4E .SB9F BB9F 84 A0 STY &A0 ;set number of filler bytes in gap 5 BBA1 68 PLA BBA2 20 1D BE JSR SE1D ;page in JIM page in A BBA5 8E 92 FD STX &FD92 ;set filler byte in gap 5 (redundant) BBA8 A0 3C LDY #&3C ;[D]61 bytes to copy, &0D00..3D: .SBAA BBAA B9 C9 BD LDA &BDC9,Y ;get byte of NMI format code BBAD 99 00 0D STA &0D00,Y ;store in NMI handler area BBB0 88 DEY ;loop until all bytes transferred BBB1 10 F7 BPL SBAA BBB3 A9 F4 LDA #&F4 ;&F4=Write track, settling delay BBB5 20 FA BC JSR SCFA ;write to FDC command register BBB8 4C 16 BD JMP SD16 ;wait for command completion and exit. .SBBB ;Add entry to track format RLE table BBBB 8A TXA ;save ROM table offset BBBC 48 PHA BBBD 98 TYA ;save number of sectors remaining BBBE 48 PHA BBBF A0 00 LDY #&00 ;y=&00, unused BBC1 38 SEC BBC2 BD 42 BC LDA &BC42,X ;get run length from ROM table BBC5 30 12 BMI SBD9 ;if b7=1 then process special entry BBC7 F0 09 BEQ SBD2 ;if the terminator byte then finish C=1 BBC9 85 A0 STA &A0 ;else store run length in zero page BBCB BD 43 BC LDA &BC43,X ;get data byte from ROM table BBCE 20 14 BC JSR SC14 ;store run in table .SBD1 BBD1 18 CLC ;c=0, sector not completed .SBD2 BBD2 68 PLA ;restore number of sectors remaining BBD3 A8 TAY BBD4 68 PLA ;restore ROM table offset BBD5 AA TAX BBD6 E8 INX ;add 2 to ROM table offset BBD7 E8 INX BBD8 60 RTS .SBD9 ;Process special table entry (length=&FF) BBD9 BD 43 BC LDA &BC43,X ;get data byte from ROM format table BBDC D0 22 BNE SC00 ;if non-zero then add sector data area BBDE A9 01 LDA #&01 ;else add ID bytes. run length of bytes = 1 BBE0 85 A0 STA &A0 ;store run length in zero page BBE2 A2 04 LDX #&04 ;4 bytes in sector ID: .SBE4 BBE4 20 0C BE JSR SE0C BBE7 A0 00 LDY #&00 ;y=0 for user memory load BBE9 20 EC A4 JSR R4EC ;get data byte from user memory BBEC 20 3A BC JSR SC3A ;page in JIM page 6..9 BBEF 20 14 BC JSR SC14 ;store run in table BBF2 E6 A6 INC &A6 ;increment CHRN table pointer BBF4 D0 02 BNE SBF8 ;carry out to high byte BBF6 E6 A7 INC &A7 .SBF8 BBF8 CA DEX ;loop until 4 ID bytes stored BBF9 D0 E9 BNE SBE4 BBFB 85 A1 STA &A1 ;store last byte read = N = size code BBFD 4C D1 BB JMP SBD1 ;restore XY and return .SC00 ;Add sector data area BC00 A6 A1 LDX &A1 ;load sector size code BC02 BD 88 BC LDA &BC88,X ;get run length from table BC05 85 A0 STA &A0 ;store in zero page BC07 A2 08 LDX #&08 ;repeat prescribed run 8 times: BC09 A9 E5 LDA #&E5 ;A=&E5 = sector filler byte .SC0B BC0B 20 14 BC JSR SC14 ;store run in table BC0E CA DEX ;loop until 8 copies of run stored BC0F D0 FA BNE SC0B BC11 4C D1 BB JMP SBD1 ;restore XY and return .SC14 ;Store run in table BC14 48 PHA ;save data byte BC15 A4 A4 LDY &A4 ;get offset into data/run tables BC17 99 80 FD STA &FD80,Y ;store data byte in data table BC1A A5 A0 LDA &A0 ;get run length BC1C 99 00 FD STA &FD00,Y ;store run length in run table BC1F A5 A4 LDA &A4 ;can save 1 byte using TYA BC21 D0 08 BNE SC2B ;if pointers are on a page boundary BC23 AD 00 FD LDA &FD00 ;then set b7=1 of run length BC26 09 80 ORA #&80 BC28 8D 00 FD STA &FD00 .SC2B BC2B E6 A4 INC &A4 ;increment data table pointer BC2D 10 09 BPL SC38 ;if LSB of pointer reaches &80 BC2F A9 00 LDA #&00 ;then the tables fill each half page BC31 85 A4 STA &A4 ;so reset LSB of pointer = &00 BC33 E6 A5 INC &A5 ;and carry out to high byte BC35 20 3A BC JSR SC3A .SC38 BC38 68 PLA ;restore data byte and return BC39 60 RTS .SC3A ;page in JIM page 6..9 BC3A 48 PHA ;save A BC3B A5 A5 LDA &A5 ;get MSB of data table pointer BC3D 20 1D BE JSR SE1D ;page in JIM page in A BC40 68 PLA BC41 60 RTS ;RLE tables of formatting bytes ;Single density BC42 EQUB &10,&FF ; 16x &FF filler bytes } Gap 5 BC44 EQUB &03,&00 ; 6x &00 synchronization bytes } BC46 EQUB &03,&00 BC48 EQUB &01,&FC ; 1x &FC index address mark (clock &D7) BC4A EQUB &0B,&FF ; 11x &FF filler bytes } Gap 1 ;block repeated for each sector BC4C EQUB &03,&00 ; 6x &00 synchronization bytes } BC4E EQUB &03,&00 BC50 EQUB &01,&FE ; 1x &FE ID address mark (clock &C7) BC52 EQUB &FF,&00 ;id bytes are inserted here BC54 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) BC56 EQUB &0B,&FF ; 11x &FF filler bytes } Gap 2 BC58 EQUB &03,&00 ; 6x &00 synchronization bytes } BC5A EQUB &03,&00 BC5C EQUB &01,&FB ; 1x &FB data address mark (clock &C7) BC5E EQUB &FF,&01 ;data bytes are inserted here BC60 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) BC62 EQUB &10,&FF ; 16x &FF filler bytes } Gap 3... ;end of repeated block BC64 EQUB &00 ;terminator byte (not part of format) ;Double density BC65 EQUB &28,&4E ; 40x &4E filler bytes } BC67 EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 5 BC69 EQUB &03,&F6 ; 3x &F6 synchronization bytes } BC6B EQUB &01,&FC ; 1x &FC index address mark BC6D EQUB &19,&4E ; 25x &4E filler bytes } Gap 1 ;block repeated for each sector BC6F EQUB &0C,&00 ; 12x &00 preamble bytes } BC71 EQUB &03,&F5 ; 3x &F5 synchronization bytes } BC73 EQUB &01,&FE ; 1x &FE ID address mark BC75 EQUB &FF,&00 ;id bytes are inserted here BC77 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) BC79 EQUB &16,&4E ; 22x &4E filler bytes } BC7B EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 2 BC7D EQUB &03,&F5 ; 3x &F5 synchronization bytes } BC7F EQUB &01,&FB ; 1x &FB data address mark BC81 EQUB &FF,&01 ;data bytes are inserted here BC83 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) BC85 EQUB &16,&4E ; 22x &4E filler bytes } Gap 3... ;end of repeated block BC87 EQUB &00 ;terminator byte (not part of format) BC88 EQUB &10 ;8x runs of 16 bytes for 128-byte sectors BC89 EQUB &20 ;8x runs of 32 bytes for 256-byte sectors BC8A EQUB &40 ;8x runs of 64 bytes for 512-byte sectors BC8B EQUB &80 ;8x runs of 128 bytes for 1024-byte sectors .SC8C ;Store per-drive head position BC8C A5 BA LDA &BA ;get logical track number of disc operation BC8E 2C EA FD BIT &FDEA ;test double-stepping flag BC91 50 01 BVC SC94 ;if b6=1 then double stepping is enabled BC93 0A ASL A ;so double track number: .SC94 ;Store physical position of head BC94 48 PHA ;save physical track BC95 20 A0 BC JSR SCA0 ;set X=physical floppy unit for current drive BC98 68 PLA ;restore physical track BC99 9D EF FD STA &FDEF,X ;store physical track number for drive: .SC9C ;Write to FDC track register BC9C 8D F9 FC STA &FCF9 BC9F 60 RTS .SCA0 ;Set X=physical floppy unit for current drive BCA0 20 D9 AA JSR RAD9 ;map current volume to physical volume BCA3 29 07 AND #&07 ;mask drive no in b2..0 mask off volume letter BCA5 A2 02 LDX #&02 ;preset X=2 to select third floppy drive BCA7 C9 06 CMP #&06 ;if physical drive number = 6 or 7 BCA9 B0 03 BCS SCAE ;then return X=2 BCAB 29 01 AND #&01 ;else return X=0 drv 0 or 2, X=1 drv 1 or 3 BCAD AA TAX .SCAE BCAE 60 RTS .SCAF ;Raise "Disk fault" error BCAF 20 92 A8 JSR R892 ;begin error message with "Disk fault " BCB2 EQUB &C5 BCB3 EQUS "fault " BCB9 EQUB &EA BCBA AD F3 FD LDA &FDF3 BCBD 20 78 A9 JSR R978 ;print hex byte BCC0 20 D3 A8 JSR R8D3 ;print " at Trk " BCC3 EQUS " at Trk " BCCB EA NOP BCCC A5 BA LDA &BA ;get track number BCCE 20 78 A9 JSR R978 ;print hex byte BCD1 20 D3 A8 JSR R8D3 ;print ", Sct " BCD4 EQUS ", Sct " BCDA EA NOP BCDB A5 BB LDA &BB ;get sector number BCDD 20 78 A9 JSR R978 ;print hex byte BCE0 4C F8 A8 JMP R8F8 ;terminate error message, raise error .SCE3 ;Raise "Disk not formatted" error BCE3 20 AD A8 JSR R8AD BCE6 EQUB &C5 BCE7 EQUS "Disk not formatted" BCF9 EQUB &00 .SCFA ;Write to FDC command register BCFA 8D F8 FC STA &FCF8 BCFD 60 RTS .SCFE ;Write to FDC sector register BCFE 8D FA FC STA &FCFA BD01 60 RTS .SD02 ;Write to FDC data register BD02 8D FB FC STA &FCFB BD05 60 RTS .SD06 ;Set Z=1 iff drive motor is on BD06 20 4C B7 JSR S74C ;set Z=1 iff current drive is a RAM disc BD09 F0 08 BEQ SD13 ;if RAM disc then treat as motor on BD0B AD F8 FC LDA &FCF8 ;else load FDC status register BD0E 49 80 EOR #&80 ;return A=0, Z=1 iff motor is on [D]swapped BD10 29 80 AND #&80 ;mask b7 extract WD1770 S7 = motor on BD12 60 RTS .SD13 BD13 A9 00 LDA #&00 ;return A=0, Z=1 indicating motor on. BD15 60 RTS .SD16 ;Wait for command completion #if defined _TURBO BD16 20 79 A8 JSR R879 ;save XY #else BD16 20 75 A8 JSR R875 ;save XY #endif BD19 A2 FF LDX #&FF ;wait 638 microseconds .SD1B BD1B CA DEX BD1C D0 FD BNE SD1B .SD1E BD1E 20 33 BD JSR SD33 ;[D]poll for ESCAPE BD21 AD F8 FC LDA &FCF8 ;load FDC status register BD24 6A ROR A ;place bit 0 in carry flag BD25 B0 F7 BCS SD1E ;loop until b0=0 WD1770 S0 = busy .SD27 BD27 AD F8 FC LDA &FCF8 ;load FDC status register BD2A 29 7F AND #&7F ;mask bits 6..0 ignore WD1770 S7 = motor on BD2C 20 0C BE JSR SE0C BD2F 8D F3 FD STA &FDF3 ;save final status BD32 60 RTS .SD33 ;Poll for ESCAPE BD33 A5 B9 LDA &B9 ;if >0 disc operation is uninterruptible BD35 F0 1A BEQ SD51 ;then return BD37 24 FF BIT &FF ;else if ESCAPE pressed BD39 10 16 BPL SD51 BD3B 20 00 BA JSR SA00 ;then send Force Interrupt BD3E A9 00 LDA #&00 ;RES b4=0, reset WD 1770 floppy controller BD40 8D FC FC STA &FCFC ;store in control latch BD43 20 8F A9 JSR R98F ;acknowledge ESCAPE condition BD46 20 AD A8 JSR R8AD ;raise "Escape" error. BD49 EQUB &11 BD4A EQUS "Escape" BD50 EQUB &00 .SD51 BD51 60 RTS ;Table of WD1770 FDC commands for data transfer call numbers 0..4 BD52 EQUB &90 ;&00 = Read data BD53 EQUB &B4 ;&01 = Write data BD54 EQUB &90 BD55 EQUB &B5 ;&03 = Write deleted data BD56 EQUB &90 ;&04 = Verify data ;Table of status mask bytes for data transfer call numbers 0..4 ;{RecordNotFound CRCError LostData} (&1C) plus: BD57 EQUB &3C ;&00 = Read data: {RecordType} BD58 EQUB &7C ;&01 = Write data: {WriteProtect RecordType} BD59 EQUB &1C ;{} BD5A EQUB &5C ;&03 = Write deleted data: {WriteProtect} BD5B EQUB &3C ;&04 = Verify data: {RecordType} ;NMI read from disc, &0D00..2B ;opcode read 4+e..8 microseconds after NMI ;(up to 13.5 us if code running in 1 MHz mem) BD5C 8D 2A 0D STA &0D2A ;save accumulator to restore on exit BD5F AD FB FC LDA &FCFB ;read FDC data register BD62 8D 00 FD STA &FD00 ;store in user memory or R3DATA BD65 EE 07 0D INC &0D07 ;increment user memory address BD68 D0 03 BNE SD6D ;carry out to high byte BD6A EE 08 0D INC &0D08 .SD6D BD6D C6 A0 DEC &A0 ;decrement count of bytes to transfer BD6F D0 14 BNE SD85 ;(&0101 = 1; &0000 = 0) BD71 C6 A1 DEC &A1 ;if count has not reached zero BD73 D0 10 BNE SD85 ;then restore A and return from interrupt BD75 A9 40 LDA #&40 ;else set 0D00=RTI; ignore further NMIs BD77 8D 00 0D STA &0D00 ;ISR safe by 23+e..30.5 us after NMI BD7A A9 CE LDA #&CE ;write complete by 25.5+e..33 us BD7C 69 01 ADC #&01 ;wait 123 microseconds (if loop enabled) BD7E 90 00 BCC SD80 ;0D23=&FC loops back to &0D20 .SD80 BD80 A9 D0 LDA #&D0 ;FDC command &D0 = Force Interrupt BD82 8D F8 FC STA &FCF8 ;write to FDC command register .SD85 BD85 A9 00 LDA #&00 ;restore value of A on entry BD87 40 RTI ;return from interrupt ;NMI polling loop, &0D2C..3C BD88 A9 0E LDA #&0E ;page *OPT 9 saverom slot in BD8A 8D 30 FE STA &FE30 .SD8D BD8D AD F8 FC LDA &FCF8 ;load FDC status register BD90 6A ROR A ;place bit 0 in carry flag BD91 B0 FA BCS SD8D ;loop until b0=0 WD1770 S0 = busy BD93 A9 00 LDA #&00 ;page Challenger ROM back in BD95 8D 30 FE STA &FE30 BD98 60 RTS ;return ;JIM page select routine, &0D3D..4F ;made reachable by JSR installed at &BACF BD99 EE 41 0D INC &0D41 ;increment LSB of JIM page address BD9C A9 00 LDA #&00 ;set LSB of JIM page address BD9E 8D FF FC STA &FCFF BDA1 D0 08 BNE SDAB ;if carry out BDA3 EE 4B 0D INC &0D4B ;then increment MSB of JIM page address BDA6 A9 00 LDA #&00 ;set MSB of JIM page address BDA8 8D FE FC STA &FCFE .SDAB BDAB 60 RTS ;NMI write to disc, &0D03..10 BDAC AD 00 FD LDA &FD00 BDAF 8D FB FC STA &FCFB BDB2 EE 04 0D INC &0D04 BDB5 D0 03 BNE SDBA BDB7 EE 05 0D INC &0D05 .SDBA ;NMI read ID, &0D00..0B BDBA 48 PHA BDBB AD FB FC LDA &FCFB ;load FDC data register BDBE 8D 0C 0D STA &0D0C ;store ID byte in buffer BDC1 EE 05 0D INC &0D05 ;increment offset BDC4 68 PLA BDC5 40 RTI ;NMI verify, &0D06..08 BDC6 4C 11 0D JMP &0D11 ;discard byte from FDC data register ;A run-length encoded table of formatting bytes is stored in two ;interleaved arrays in JIM space starting at &000612 and &000692. ;Data bytes occupy the top half of each page. Valid range of counts is ;&01..&80, but bit 7 is then toggled on the first count of the page. ;When the byte source address crosses a page, the next JIM page is selected ;in the same interrupt and the count source address is reset to the start ;of the page in the next interrupt. One byte from the next page is sent to ;the controller in the meantime, and so the first byte of the page cannot ;be a singleton. The page crossings occur 5/8 of the way through the data ;area of the fifth sector after the index pulse, 1/8th through the eleventh ;sector and during gap2 of the seventeenth sector. ;The table alignment shows that the RLE code was ported from Challenger ;into DDOS 3.46. ;NMI format, &0D00..3C BDC9 48 PHA ;save A on entry BDCA AD 92 FD LDA &FD92 ;fetch current data byte BDCD 8D FB FC STA &FCFB ;write to FDC data register BDD0 C6 A0 DEC &A0 ;decrement run counter BDD2 D0 16 BNE SDEA ;if all bytes in run written BDD4 EE 02 0D INC &0D02 ;then increment data byte address low BDD7 D0 23 BNE SDFC ;if no carry then fetch next run length BDD9 A9 80 LDA #&80 ;[D]else reset data address low = &80 BDDB 8D 02 0D STA &0D02 BDDE A9 07 LDA #&07 ;page in next JIM page BDE0 8D FF FC STA &FCFF BDE3 AD 00 FD LDA &FD00 ;fetch next run length [D]marked b7=1 BDE6 85 A0 STA &A0 ;set run counter .SDE8 BDE8 68 PLA ;restore A on entry BDE9 40 RTI ;exit .SDEA BDEA 10 FC BPL SDE8 ;if run still in progress then exit BDEC A5 A0 LDA &A0 ;else page was crossed last time: BDEE 29 7F AND #&7F ;[D]mask off page marker in b7 BDF0 85 A0 STA &A0 ;update run counter BDF2 A9 00 LDA #&00 ;reset run length address low = &00 BDF4 8D 37 0D STA &0D37 BDF7 EE 16 0D INC &0D16 ;increment data byte address high BDFA 68 PLA ;restore A on entry BDFB 40 RTI ;exit .SDFC BDFC EE 37 0D INC &0D37 ;increment run length address BDFF AD 12 FD LDA &FD12 ;fetch next run length BE02 85 A0 STA &A0 ;set run counter BE04 68 PLA ;restore A on entry BE05 40 RTI ;exit ;unreachable code BE06 EA NOP .SE07 ;Page in auxiliary workspace BE07 48 PHA BE08 A9 00 LDA #&00 BE0A F0 12 BEQ SE1E .SE0C ;Page in main workspace BE0C 48 PHA BE0D A9 01 LDA #&01 BE0F D0 0D BNE SE1E .SE11 ;Page in catalogue sector 0 BE11 48 PHA BE12 A9 02 LDA #&02 BE14 D0 08 BNE SE1E .SE16 ;Page in catalogue sector 1 BE16 48 PHA BE17 A9 03 LDA #&03 BE19 D0 03 BNE SE1E .SE1B ;Page in line buffer BE1B A9 09 LDA #&09 .SE1D ;Page in JIM page in A BE1D 48 PHA .SE1E BE1E 8D FF FC STA &FCFF ;store LSB JIM paging register BE21 A9 00 LDA #&00 BE23 8D FE FC STA &FCFE ;set MSB JIM paging register = &00 BE26 68 PLA ;restore A on entry BE27 60 RTS ;ChADFS ROM call 4 BE28 20 88 AD JSR RD88 ;claim NMI BE2B 20 0C BE JSR SE0C ;page in main workspace BE2E A9 01 LDA #&01 ;data transfer call &01 = write data BE30 8D E9 FD STA &FDE9 BE33 A9 00 LDA #&00 ;transfer size = 512 bytes BE35 85 A0 STA &A0 BE37 A9 02 LDA #&02 BE39 85 A1 STA &A1 BE3B A9 00 LDA #&00 ;source address = HAZEL, &C000 BE3D 85 A6 STA &A6 BE3F A9 C0 LDA #&C0 BE41 85 A7 STA &A7 BE43 A9 00 LDA #&00 ;b7=0 transfer from host BE45 8D CC FD STA &FDCC BE48 A9 00 LDA #&00 ;starting sector/LBA = &0000 BE4A 85 BA STA &BA BE4C 85 BB STA &BB BE4E A9 04 LDA #&04 ;destination physical drive = 4 #if defined _BUGFIX BE50 20 80 BE JSR SE80 ;transfer data to paged RAM #else BE50 20 7C BE JSR SE7C ;transfer data to paged RAM #endif BE53 A9 C9 LDA #&C9 ;source address = HAZEL, &C900 BE55 85 A7 STA &A7 BE57 A9 02 LDA #&02 ;starting sector/LBA = &0002 BE59 85 BB STA &BB BE5B A9 05 LDA #&05 ;transfer size = 1280 bytes BE5D 85 A1 STA &A1 BE5F A9 04 LDA #&04 ;destination physical drive = 4 #if defined _BUGFIX BE61 20 80 BE JSR SE80 ;transfer data to paged RAM .SE64 #else BE61 20 7C BE JSR SE7C ;transfer data to paged RAM #endif BE64 A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. BE66 60 RTS #if defined _BUGFIX .SE67 ;Transfer data to paged RAM BE67 20 0C BE JSR SE0C ;page in main workspace BE6A AD ED FD LDA &FDED ;get density flag BE6D 4D FE FD EOR &FDFE ;compare with RAM disc density flag BE70 0A ASL A ;move result into N BE71 10 03 BPL SE76 ;if densities do not match BE73 A9 10 LDA #&10 ;then WD1770 S4 = record not found BE75 60 RTS .SE76 BE76 AD E9 FD LDA &FDE9 ;else get data transfer call number BE79 29 7C AND #&7C ;mask off b7=JIM, b1,b0=calls 0..3 BE7B D0 E7 BNE SE64 ;if call=4 verify, return status &00 BE7D 20 D9 AA JSR RAD9 ;map current volume to physical volume .SE80 BE80 A0 0A LDY #&0A ;volume 4 starts at JIM address &000A00 BE82 A2 00 LDX #&00 BE84 C9 04 CMP #&04 ;if physical drive is not 4 BE86 F0 04 BEQ SE8C BE88 A0 00 LDY #&00 ;then volume starts at JIM address &040000 BE8A A2 04 LDX #&04 .SE8C BE8C A5 A0 LDA &A0 ;save ?&A0, ?&A1 on stack BE8E 48 PHA BE8F A5 A1 LDA &A1 BE91 48 PHA BE92 8A TXA ;save volume start address in YX on stack BE93 48 PHA ;MSB first BE94 98 TYA BE95 48 PHA BE96 A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 BE98 F0 02 BEQ SE9C ;not rounding up, converting number format; BE9A E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .SE9C BE9C A0 46 LDY #&46 ;71 bytes to copy, &0D00..46 [D]: .SE9E BE9E B9 2F BF LDA &BF2F,Y ;get byte of RAM disc transfer code BEA1 99 00 0D STA &0D00,Y ;store in NMI handler area BEA4 88 DEY ;loop until all bytes transferred BEA5 10 F7 BPL SE9E BEA7 AD E9 FD LDA &FDE9 ;get data transfer call number BEAA 30 4A BMI SEF6 ;if data address in JIM space then branch BEAC 4A LSR A ;else put b0 = write data in C BEAD A5 A6 LDA &A6 ;set AY = user memory address BEAF A4 A7 LDY &A7 BEB1 B0 11 BCS SEC4 ;if call number = 0 read data BEB3 8D 22 0D STA &0D22 ;then paste user memory address at &0D22,3 BEB6 8C 23 0D STY &0D23 BEB9 AD CC FD LDA &FDCC ;test Tube transfer flag BEBC F0 58 BEQ SF16 ;if b7=0 then an I/O transfer, branch BEBE A9 8D LDA #&8D ;else instruction at &0D21 = STA &FEE5 BEC0 A0 03 LDY #&03 BEC2 D0 14 BNE SED8 ;modify RAM transfer code for Tube. .SEC4 ;Modify RAM transfer code for write BEC4 8D 1F 0D STA &0D1F ;paste user memory address at &0D1F,20 BEC7 8C 20 0D STY &0D20 #else /* _BUGFIX */ .SE67 ;Transfer data to paged RAM BE67 20 0C BE JSR SE0C ;page in main workspace BE6A A0 10 LDY #&10 ;redundant BE6C AD ED FD LDA &FDED ;get density flag BE6F 4D FE FD EOR &FDFE ;compare with RAM disc density flag BE72 29 40 AND #&40 ;mask bit 6 = double density BE74 F0 03 BEQ SE79 ;if not matched BE76 A9 10 LDA #&10 ;WD1770 S4 = record not found BE78 60 RTS .SE79 BE79 20 D9 AA JSR RAD9 ;map current volume to physical volume .SE7C BE7C A0 0A LDY #&0A ;volume 4 starts at JIM address &000A00 BE7E A2 00 LDX #&00 BE80 C9 04 CMP #&04 ;if physical drive is not 4 BE82 F0 04 BEQ SE88 BE84 A0 00 LDY #&00 ;then volume starts at JIM address &040000 BE86 A2 04 LDX #&04 .SE88 BE88 A5 A0 LDA &A0 ;save ?&A0, ?&A1 on stack BE8A 48 PHA BE8B A5 A1 LDA &A1 BE8D 48 PHA BE8E 8A TXA ;save volume start address in YX on stack BE8F 48 PHA ;MSB first BE90 98 TYA BE91 48 PHA BE92 A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 BE94 F0 02 BEQ SE98 ;not rounding up, converting number format; BE96 E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .SE98 BE98 A0 46 LDY #&46 ;71 bytes to copy, &0D00..46 [D]: .SE9A BE9A B9 2F BF LDA &BF2F,Y ;get byte of RAM disc transfer code BE9D 99 00 0D STA &0D00,Y ;store in NMI handler area BEA0 88 DEY ;loop until all bytes transferred BEA1 10 F7 BPL SE9A BEA3 AD E9 FD LDA &FDE9 ;get data transfer call number BEA6 30 4E BMI SEF6 ;if data address in JIM space then branch BEA8 D0 16 BNE SEC0 ;else if =0 read data BEAA A5 A6 LDA &A6 ;then paste user memory address at &0D22,3 BEAC 8D 22 0D STA &0D22 BEAF A5 A7 LDA &A7 BEB1 8D 23 0D STA &0D23 BEB4 AD CC FD LDA &FDCC ;test Tube transfer flag BEB7 F0 5D BEQ SF16 ;if b7=0 then an I/O transfer, branch BEB9 A9 8D LDA #&8D ;else instruction at &0D21 = STA &FEE5 BEBB A0 03 LDY #&03 BEBD 4C D8 BE JMP SED8 ;modify RAM transfer code for Tube. ;Verify data command (&1F/&04) also comes here. [BUG] Overwrites RAM disc! .SEC0 ;Modify RAM transfer code for write BEC0 A5 A6 LDA &A6 ;paste user memory address at &0D1F,20 BEC2 8D 1F 0D STA &0D1F BEC5 A5 A7 LDA &A7 BEC7 8D 20 0D STA &0D20 #endif /* _BUGFIX */ BECA A9 20 LDA #&20 ;0D27=INC &0D20 BECC 8D 28 0D STA &0D28 ;increment user memory address BECF AD CC FD LDA &FDCC ;test Tube transfer flag BED2 F0 42 BEQ SF16 ;if b7=0 then an I/O transfer, branch BED4 A9 AD LDA #&AD ;else instruction at &0D1E = LDA &FEE5 BED6 A0 00 LDY #&00 .SED8 ;Modify RAM transfer code for Tube BED8 99 1E 0D STA &0D1E,Y ;store opcode LDA abs at &D1E/STA abs at &D21 BEDB A9 E5 LDA #&E5 ;store address of R3DATA, &FEE5 BEDD 99 1F 0D STA &0D1F,Y ;at &0D1F,20 or &0D22,3 BEE0 A9 FE LDA #&FE BEE2 99 20 0D STA &0D20,Y BEE5 A9 F4 LDA #&F4 ;0D25=BNE &0D1B BEE7 8D 26 0D STA &0D26 ;enable 25 microsecond interval per byte BEEA A9 E1 LDA #&E1 ;0D38=BNE &0D1B BEEC 8D 39 0D STA &0D39 ;enable 38.5 microsecond delay to next page BEEF A9 AD LDA #&AD ;0D27=LDA &0D23 BEF1 8D 27 0D STA &0D27 ;do not increment R3DATA address BEF4 D0 20 BNE SF16 ;branch (always) .SEF6 ;Copy data between JIM pages BEF6 A0 31 LDY #&31 ;50 bytes to copy, &0D00..31 [D]: .SEF8 BEF8 B9 76 BF LDA &BF76,Y ;get byte of RAM disc copy code BEFB 99 00 0D STA &0D00,Y ;store in NMI handler area BEFE 88 DEY ;loop until all bytes transferred BEFF 10 F7 BPL SEF8 BF01 A0 00 LDY #&00 ;LBA goes to &0D06,01 BF03 A2 12 LDX #&12 ;JIM page number goes to &0D13 BF05 AD E9 FD LDA &FDE9 ;get data transfer call number BF08 29 7F AND #&7F ;mask bits 0..6 BF0A F0 04 BEQ SF10 ;if not =0, read data BF0C A0 0D LDY #&0D ;then LBA goes to &0D13,0E BF0E A2 05 LDX #&05 ;JIM page number goes to &0D06 .SF10 BF10 A5 A6 LDA &A6 BF12 9D 01 0D STA &0D01,X ;paste JIM page number at &0D06/13 BF15 AD A0 11 LDA &11A0 ;BF16=LDY #&11 .SF16 BF16 A0 11 LDY #&11 ;LBA goes to &0D17,12 BF18 18 CLC BF19 68 PLA ;restore LSB volume start address BF1A 65 BB ADC &BB ;add LSB relative LBA BF1C 99 06 0D STA &0D06,Y ;paste LSB absolute LBA at &0D06/13/17 BF1F 68 PLA ;restore MSB volume start address BF20 65 BA ADC &BA ;add MSB relative LBA BF22 99 01 0D STA &0D01,Y ;paste MSB absolute LBA at &0D01/0E/12 BF25 A0 00 LDY #&00 ;starting offset = &00 BF27 20 00 0D JSR &0D00 ;do transfer to/from paged RAM BF2A A0 00 LDY #&00 ;fake WD1770 status = 0, succeeded BF2C 4C 96 BA JMP SA96 ;restore &A0,1 and page in main workspace. ;Transfer code copied to &0D00..46 BF2F AD EE FD LDA &FDEE ;get *OPT 9 saverom setting BF32 8D 30 FE STA &FE30 ;set ROM bank to *OPT 9 saverom .SF35 BF35 A5 A1 LDA &A1 ;if 256 bytes or less remaining BF37 C9 01 CMP #&01 BF39 D0 05 BNE SF40 BF3B A9 0F LDA #&0F ;then 0D25=BNE &0D36 BF3D 8D 26 0D STA &0D26 ;transfer bytes of last page .SF40 BF40 A2 00 LDX #&00 ;0D11 BF42 8E FE FC STX &FCFE ;set MSB of JIM page number BF45 A2 00 LDX #&00 ;0D16 BF47 8E FF FC STX &FCFF ;set LSB of JIM page number BF4A 20 40 0D JSR &0D40 ;wait 18 microseconds (only needed for Tube) .SF4D BF4D B9 00 FD LDA &FD00,Y ;0D1E read byte from JIM page BF50 99 00 FD STA &FD00,Y ;0D21 write byte to JIM page BF53 C8 INY ;increment offset BF54 D0 F7 BNE SF4D ;0D25 loop until page boundary reached BF56 EE 23 0D INC &0D23 ;0D27 increment MSB write address BF59 EE 17 0D INC &0D17 ;increment LSB of JIM page number BF5C D0 03 BNE SF61 ;carry out to MSB of JIM page number BF5E EE 12 0D INC &0D12 .SF61 BF61 C6 A1 DEC &A1 ;decrement MSB transfer byte count BF63 D0 D0 BNE SF35 ;loop to transfer next page (always) BF65 C6 A0 DEC &A0 ;0D36 decrement LSB transfer byte count BF67 D0 E4 BNE SF4D ;loop until last bytes transferred BF69 A5 F4 LDA &F4 ;page Challenger ROM back in BF6B 8D 30 FE STA &FE30 BF6E 60 RTS ;return BF6F 20 46 0D JSR &0D46 ;0D40 wait 18 microseconds BF72 20 46 0D JSR &0D46 BF75 60 RTS .SF76 ;RAM disc copy code copied to &0D00..31 BF76 A2 00 LDX #&00 BF78 8E FE FC STX &FCFE ;set MSB JIM paging register to source BF7B A2 00 LDX #&00 BF7D 8E FF FC STX &FCFF ;set LSB JIM paging register to source BF80 B9 00 FD LDA &FD00,Y ;get byte from source page BF83 A2 00 LDX #&00 ;0D0D BF85 8E FE FC STX &FCFE ;set MSB JIM paging register to destination BF88 A2 00 LDX #&00 ;0D12 BF8A 8E FF FC STX &FCFF ;set LSB JIM paging register to destination BF8D 99 00 FD STA &FD00,Y ;store byte in destination page BF90 C8 INY ;loop to copy whole page BF91 D0 E3 BNE SF76 BF93 EE 06 0D INC &0D06 ;increment LSB source page BF96 D0 03 BNE SF9B ;carry out to MSB source page BF98 EE 01 0D INC &0D01 .SF9B BF9B EE 13 0D INC &0D13 ;increment LSB destination page BF9E D0 03 BNE SFA3 ;carry out to MSB destination page BFA0 EE 0E 0D INC &0D0E .SFA3 BFA3 C6 A1 DEC &A1 ;loop until required number of pages copied BFA5 D0 CF BNE SF76 BFA7 60 RTS ;ChADFS ROM call 1 BFA8 A9 00 LDA #&00 BFAA 8D EC FD STA &FDEC ;first track of volume = 0, no track offset BFAD AD ED FD LDA &FDED ;get *OPT 6 density setting BFB0 09 40 ORA #&40 ;set b6=1, double density BFB2 8D ED FD STA &FDED ;update *OPT 6 density setting (preserve auto) BFB5 20 E4 8A JSR PAE4 ;prepare extended file transfer BFB8 4C F0 AC JMP RCF0 ;transfer data L3 and exit ;Table of action addresses for ChADFS ROM calls 0..4, low bytes BFBB EQUB &F5 ;ChADFS 0 = *CONFIG &AAF6 BFBC EQUB &A7 ;ChADFS 1 = transfer data &BFA8 BFBD EQUB &1E ;ChADFS 2 = probe unit RAM size &821F BFBE EQUB &7D ;ChADFS 3 = reset drv mappings &AB7E BFBF EQUB &27 ;ChADFS 4 = format RAM disc &BE28 ;Table of action addresses for ChADFS ROM calls 0..4, high bytes BFC0 EQUB &AA BFC1 EQUB &BF BFC2 EQUB &82 BFC3 EQUB &AB BFC4 EQUB &BE #if defined _BUGFIX .SFC5 ;Clear EOF warning flag in OSGBPB BFC5 AC E0 FD LDY &FDE0 ;get LSB of OSGBPB action address BFC8 C0 12 CPY #&12 ;does it match 'return one filename'? BFCA F0 06 BEQ SFD2 ;if not BFCC AC A1 FD LDY &FDA1 ;set Y = file handle from OSGBPB block BFCF 20 33 AA JSR RA33 ;clear EOF warning flag .SFD2 BFD2 4C D5 A4 JMP R4D5 ;set up pointer to user's OSGBPB block .SFD5 ;Execute command on host BFD5 AA TAX ;on entry A=&FF, C=1 BFD6 A9 01 LDA #&01 ;emulate Acorn DFS: A=1, C=1, BFD8 6C C0 00 JMP (&00C0) ;X=&FF filename cmp complete .SFDB ;ChADFS ROM call dispatcher BFDB AA TAX ;transfer call number to X as index BFDC 20 0C BE JSR SE0C ;page in main workspace BFDF A9 FF LDA #&FF BFE1 8D FF FD STA &FDFF ;b6=1 ChADFS is current FS BFE4 A9 BF LDA #&BF ;push address of ChADFS return, &BFF4 BFE6 48 PHA ;high byte BFE7 A9 F3 LDA #&F3 ;low byte BFE9 48 PHA BFEA BD C0 BF LDA &BFC0,X ;get action address high byte BFED 48 PHA ;save on stack BFEE BD BB BF LDA &BFBB,X ;get action address low byte BFF1 48 PHA ;save on stack BFF2 60 RTS ;jump to action address #else /* _BUGFIX */ .SFC5 ;ChADFS ROM call dispatcher BFC5 AA TAX ;transfer call number to X as index BFC6 20 0C BE JSR SE0C ;page in main workspace BFC9 A9 FF LDA #&FF BFCB 8D FF FD STA &FDFF ;b6=1 ChADFS is current FS BFCE A9 BF LDA #&BF ;push address of ChADFS return, &BFF4 BFD0 48 PHA ;high byte BFD1 A9 F3 LDA #&F3 ;low byte BFD3 48 PHA BFD4 BD C0 BF LDA &BFC0,X ;get action address high byte BFD7 48 PHA ;save on stack BFD8 BD BB BF LDA &BFBB,X ;get action address low byte BFDB 48 PHA ;save on stack BFDC 60 RTS ;jump to action address #endif ;'Revolving bookcase' routine to perform bank switching from code executing ;in that same bank. ChADFS 300M contains a near-identical routine at the ;same location. The thread comes to the routine on either 'side', sets the ;latch and vanishes, to appear on the opposite 'side'. ;In this instance, Challenger and ChADFS are hard-coded to reside in ;neighbouring paged ROM slots, with ChADFS higher. Challenger never ;initiates the crossing; the thread always enters from ChADFS and returns ;after Challenger has serviced the call. ;Return to ChADFS ROM BFF4 A6 F4 LDX &F4 ;get our ROM slot number BFF6 E8 INX ;ChADFS is in the slot above BFF7 86 F4 STX &F4 ;set MOS copy of ROMSEL to new slot number ;At this point MOS may service an interrupt then switch 'back' to ChADFS. ;Likewise an interrupt service in ChADFS may cause premature entry here. ;In either case the next instruction has no effect. BFF9 8E 30 FE STX &FE30 ;switch to ChADFS ROM and continue there ;Absent an interrupt, the thread leaves or enters here. ;entry point from ChADFS ROM BFFC EA NOP ;allow address bus to stabilise #if defined _BUGFIX BFFD 4C DB BF JMP SFDB ;jump to dispatcher #else BFFD 4C C5 BF JMP SFC5 ;jump to dispatcher #endif ;Code fragments with no known references: ;802E = &01 = 1 byte ;88DD..1C = &40 = 64 bytes used by _MASTER ;9218..1D = &06 = 6 bytes ;967F..82 = &04 = 4 bytes ;A9A3 = &01 = 1 byte ;A9D7..E0 = &0A = 10 bytes ;AA10..15 = &06 = 6 bytes used by _BUGFIX ;AA2C..33 = &08 = 8 bytes used by _BUGFIX ;AAAD..AF = &03 = 3 bytes ;ADBC..C1 = &06 = 6 bytes (vacated by _BUGFIX) ;ADCB..D0 = &06 = 6 bytes ;ADE0..E3 = &04 = 4 bytes ;B355..5E = &0A = 10 bytes ;BE06 = &01 = 1 byte ;Total = &7C = 124 bytes ;Variables ;00A0 Temporary number of sectors until end of track ;00A0 Number of bytes in current run while preparing/executing format ;00A0..A1 Number of bytes to transfer to RAM disc or current track ;00A1 Sector size code while preparing format ;00A2 Number of sectors remaining while preparing format ;00A3 Temporary pointer to repeating sector block in ROM format table ;00A3..A5 Total number of bytes to transfer to floppy disc ;00A4..A5 Run length table pointer while preparing format ;00A6 Number of sectors per track while preparing format ;00A6..A7 User data address during transfer ;00A7 Size of CHRN table while preparing format ;00A8 Number of files in copy buffer b7=no more files match, all read ;00A8 b7=catalogue entry is waiting to be created in *COPY, *COMPACT ;00A8 Flag for printing newlines in *CAT ;00A8 b6=Caller will accept shorter allocation than requested while creating catalogue entry (OSFILE=0, OSFIND=1) ;00A8..A9 Line number in *BUILD, *LIST or file offset in *DUMP ;00A8..A9 Number of unused sectors while displaying volume statistics ;00A8..A9 Action address of *command ;00A8..A9 Free space in sectors during *VOLGEN ;00A9 b7=Copying between different discs in same drive (swapping) ;00A9 Catalogue offset of file to extend while moving files ;00AA Length of input line in *BUILD ;00AA &00=Source disc in drive &80=Destination disc in drive ;00AA =0 listing current directory during *CAT >0 listing other dirs ;00AA File attribute mask in *ACCESS &00=unlocked &80=locked ;00AA Number of files in catalogue while moving files ;00AA..AB Requested volume size during *VOLGEN ;00AA..AD Trampoline to read byte of *command and keyword table ;00AB Mask to enable line number printing &00=*TYPE &FF=*LIST ;00AB Handle of output file in *BUILD ;00AB Offset of catalogue entry of file being listed in *CAT ;00AC ASCII column counter in *DUMP ;00AC..B0 OSWORD 0 control block in *BUILD ;00AD Stack pointer in *DUMP ;00AE..AF Pointer to error message source string, VDU sequence or caller's address while producing/consuming file map ;00B0 Counter for copying catalogue entry to copy buffer ;00B0 LSB number of free sectors after file (MSB in X) ;00B0 Offset of insertion point while creating catalogue entry ;00B0 Count of file map entries to test while testing available space ;00B0 Counter for copying filename in OSGBPB 8 ;00B0 Offset into drive mapping table during *CONFIG ;00B0..B1 Pointer to private page, extended vector table, OSFILE or ; OSWORD &7F control block or filename to be compared with open ; filenames ;00B0..B1 Offset of current sector buffer from start of file in OSARGS 1,Y ;00B0..B1 Integer workspace: multiplicand or dividend ;00B1..B2 LBA of largest slack space on volume ;00B2 b5..0=OSWORD &7F command to compare with commands in table ;00B2 Offset of filename to compare with names of open handles ;00B2 Pointer to file map in stack page ;00B2..B3 Integer workspace: multiplier or divisor ;00B3 Boot option in Y on entry to service call &03 ;00B3 Counter to compare filename with names of open handles ;00B3 Saved A register on entry to print string/append error message ;00B4 Startup options while initialising private page (unused) ;00B4 Temporary copy of file open mode in A on entry to OSFIND ;00B4 Channel workspace offset while comparing names of open handles ;00B4..B5 Pointer to user's OSGBPB control block ;00B5 Saved X register on entry to FSC ;00B5 Shift register containing channel open flags ;00B6..B9 Temporary copy of pointer from OSGBPB control block ;00B7 Command line argument offset in *FORMAT ;00B7 Stack pointer to restore on command restart ;00B8 Stack pointer to restore on abort or command exit ;00B8 Counter of *HELP entries to print ;00B8..B9 Pointer to user memory in OSGBPB ;00B9 =0 disc operation is uninterruptible >0 interruptible ;00BA Logical track number of disc operation ;00BB Starting sector number of disc operation ;00BB Lowest free track in data area while assigning volumes to disc ;00BB Running track skew counter while formatting ;00BB Number of IDs/bytes to return in Read ID ;00BC Offset of catalogue entry in OSFILE &FF ;00BC..BD Pointer to argument string: OSCLI command tail or passed to FSC ;00BC..BD Pointer to filename in OSFILE ;00BD Address of lowest free/used page in copy buffer ;00BE..C5 Low words of load, exec, start, end addresses in OSFILE ;00BE..C5 Load/exec/length/start sector in catalogue format ;00BF Retry counter at data transfer level 3 ;00C0 Number of tracks on disc in *FORMAT, *VERIFY ;00C0..C1 Maximum allocation of sectors available to file ;00C1 Volume index in *VOLGEN ;00C2 Offset while testing for space to create catalogue entry ;00C2..C3 Sector excess: requested file allocation minus space available; headroom when negative ;00C3 (1, copied to &A4, then &A1, causes file buffer transfers to =256) ;00C3 Channel workspace offset of open file being extended ; (to avoid moving it while shifting following files down) ; =0 while shifting up to ensure open file is included ;00C4..C5 Length of file in sectors (big- or little-endian) ;00C4..C5 Integer workspace: product ;00C6 MSB length of file while creating catalogue entry ;00C6..C7 Total number of free sectors in volume ;00C6..C7 Source volume size in *BACKUP, *COPY ;00C6..C7 Length in sectors of file being copied ;00C7..CD Current filename ;00C8..C9 Sector headroom: total free sectors minus sector excess ;00C8..C9 LBA of next sector to copy from source volume ;00CA..CB LBA of next sector to copy to destination volume ;00CA..CB Total number of used sectors in volume ;00CC Offset of catalogue entry in *COMPACT ;00CC..CD Sector excess to be absorbed by shifting previous files up ;00CE Current directory ;00CF b2..0=current drive b6..4=current volume ;0DF0,X b1..0=Challenger unit type 0=inactive 1=256 KiB 2=512 KiB ; <&80 print to screen >=&80 "print" to error message (X=?&F4) ; (if >=&80, ?&0100 = offset of next error character in page &01) ;Auxiliary workspace, &000000..FF ;FD00..07 *CONFIG mapping, logical drives 0..7 to physical drive (b2..0) ;FD08..0F ChADFS mapping, logical drives 0..7 to physical drive (b2..0) ;FD11..C8 Copy buffer table, 8 entries * 23 bytes ;FD11..8,Y cf. BE..C5 Load/exec/length/start sector of file in copy buffer ;FD18,Y Number of pages of data in copy buffer ;FD19,Y Flag byte b7=source read incomplete b6=dest. file part written ;FD1A..1,Y cf. C7..CE Name and directory of file in copy buffer ;FD22..3,Y Length in sectors of file being copied ;FD24..5,Y LBA of next sector to copy from source volume, little-endian ;FD26..7,Y LBA of next sector to copy to destination volume, big-endian ;FDCD..D4 First track of data area of volumes A..H ;FDD5..E4 Sizes assigned to volumes A..H in *VOLGEN ;FDD5..4,Y Number of sectors in data area of volumes A..H, big-endian ;Main workspace, &000100..FF ;FD00 First workspace sentinel &65,&E5=workspace valid ; b7=Challenger is current FS ;FD01..D,Y FCE1,Y Name of open file (odd addresses) ;FD02..0,Y FCE2,Y Load/exec/length/start sector in catalogue format (evens) ;FD0D,Y FCED,Y Seventh character of open filename; b7=read-only channel ;FD0F,Y FCEF,Y Directory of open filename; b7=file locked ;FD11..3,Y FCF1,Y PTR file pointer ;FD14,Y FCF4,Y Packed drive parameters b7=auto density b6=double density b4,b3=sectors per track b1=auto stepping b0=double stepping ;FD15..7,Y FCF5,Y EXT file length ;FD18,Y FCF8,Y Channel flags b7=buffer contains byte at PTR ; b6=buffer changed b5=EXT changed (not cleared on ensure) ; b4=EOF warning given ;FD19,Y Always 0 (&FD19..B,Y = length in bytes, rounded up) ;FD1A..B,Y FCFA,Y Length of file in sectors, according to catalogue ;FD1C,Y FCFC,Y Bit mask corresponding to channel in flag byte &FDCE ;FD1D..E,Y FCFD,Y LBA of sector buffer relative to start of volume ;FD1F,Y FCFF,Y First track of volume of open file ;FD20,Y FD00,Y Drive (b3..0) and volume (b6..4) of open file ;FDA1..B2 Copy of OSFILE/OSGBPB control block ;FDB3..B6 Address of Tube data transfer ;FDB5..BC High words of load, exec, start, end addresses in OSFILE ;FDBE..BF Pointer to user's OSGBPB control block ;FDC0 Source physical volume in *RENAME ;FDC2 Offset of catalogue entry, 0..&F0, multiple of 8 ;FDC3..C5 Saved A,X,Y registers on entry to OSBPUT ;FDC4..C5 Saved X,Y registers on entry to OSBGET ;FDC6 Default (CSD) directory character ;FDC7 Default (CSD) drive (b3..0) and volume (b6..4) ;FDC8 Library directory character ;FDC9 Library drive (b3..0) and volume (b6..4) ;FDCA Source volume in *BACKUP, *COPY ;FDCB Destination volume in *BACKUP, *COPY ;FDCC b7=Tube data transfer ;FDCD &00=Tube coprocessor present &FF=Tube absent (inverted MOS flag) ;FDCE Channel open flags ;FDCF Channel open bit mask for current open file ;FDD0 Channel workspace pointer for current open file ;FDD2 Offset of catalogue entry of current open file ;FDD3 Counter for copying catalogue entry while opening file ;FDD5 MSB of OSHWM; lowest page number of user memory ;FDD6 MSB of HIMEM; 1 + highest page number of user memory ;FDD7 Number of pages of user memory; = ?&FDD6 - ?&FDD5 ;FDD8 &23=wildcard characters allowed in filename &FF=no wildcards ;FDD9 *OPT 1 monitor 0=verbose &FF=quiet ;FDDA Transfer direction 0=writing from memory 1=reading to memory ;FDDB &00=transferring to/from host &FF=transferring to/from Tube ;FDDC Drive and volume of catalogue in pages 2..3; &FF=catalogue invalid ;FDDD NMI ownership flag b7=we own NMI b6..0=previous owner (if b7=1) ;FDDE Cleared at &82D9, otherwise unused ;FDDF *ENABLE counter 1=*ENABLE just called 0=current command enabled ; &FF=current command not enabled ;FDE0 b7..4=boot option of source volume in *BACKUP ;FDE0..E1 Action address in OSGBPB ;FDE2 Offset of command line tail from GSINIT pointer ;FDE3 Offset of start of command line from GSINIT pointer ;FDE2..E3 Pointer to arguments of *RUN, */ command ;FDE4..E5 Pointer to user's OSFILE control block ;FDE6..E7 Command restart action address ;FDE9 Data transfer call number 0=read data 1=write data ; 3=write deleted data 4=verify data b7=data address in JIM space ;FDEA..EE Special registers 0..4 ;FDEA &00=single stepping b6=double stepping b7=automatic stepping ;FDEB Number of sectors per track &0A=single density &12=double density ;FDEC First track of current volume (=0 unless set from disc catalogue) ;FDED &00=single density b6=double density b7=automatic density ;FDEE *OPT 9 number of paged ROM slot to page in during disc operations ;FDEF..F1 Physical track number under heads on drive 0/2, 1/3, 6/7 ;FDF2 Track stepping rate in WD 1770 format 0=fast..3=slow ;FDF3 Status of last FDC command, reported by *FDCSTAT ;FDF4 b7=*ENABLE CAT emulate Acorn DFS's main memory use ;FDF7 Offset of last entry of copy buffer file table, n*&17 (&00..A1) ;FDF9,Y Packed drive parameters of source, destination volume (Y=0 or 2) ;FDFA,Y First track of source, destination volume (Y=0 or 2) ;FDFD Second workspace sentinel &E5=workspace valid ;FDFE RAM disc density flag b6=double density ;FDFF b6=ChADFS is current filing system ;Catalogue of current drive, &000200..3FF ;Sector buffer of file handle &11, &000400..FF ;Sector buffer of file handle &12, &000500..FF ;Sector buffer of file handle &13, &000600..FF ;Sector buffer of file handle &14, &000700..FF ;Sector buffer of file handle &15, &000800..FF ;Buffer for current line of input to *BUILD, &000900..FF ;RAM disc :4 in DFS format, &000A00..03FEFF ;Unused, &03FF00..FF ;RAM disc :5 in DFS format (512 KiB units only), &040000..07FEFF ;Unused, &07FF00..FF ;Note: The maximum size of RAM disc :4 can be increased by poking ;a value of &3F6 sectors into the volume size field at &000B06..7. ;This Perl script recreates the binary from this listing. ;Copy the text between the cut lines. ;Paste it into a new file, asm2bin.pl, and remove the column of ; ;Then call it with ; perl asm2bin.pl -D_CHAL200 -b 8000 -o chal200 chal200.asm.txt ; perl asm2bin.pl -D_PCH200 -b 8000 -o pch200 chal200.asm.txt ;-------->8--- ;#!/usr/bin/perl ; ;#Usage: perl asm2bin.pl ;# {-D SYMBOL[=VALUE]} [-E|-d] [-l] [-v] [-b BASE] ;# -o OUTFILE [FILE...] ; ;use Getopt::Std; ;use IO::Seekable qw(SEEK_SET SEEK_CUR SEEK_END); ; ;@x=(2); @t[6,7]=(2,4); ; ;for($i=0;$i<@ARGV && ($arg = $ARGV[$i]) ne '--'; ++$i) { ; if(substr($arg,0,2) eq '-D') { ; if(($dfn=substr($arg,2)) eq '') { ; $dfn = $ARGV[++$i]; ; } ; if(($x=index($dfn,'=')) > 0) { ; $symbol{substr($dfn,0,$x)} = substr($dfn,$x+1); ; } elsif($dfn ne '') { ; $symbol{$dfn} = 1; ; } ; } ;} ; ;getopts("D:Eb:dlo:v"); ;die "No output file specified" if $opt_o eq ''; ;$opt_b = hex($opt_b);$l=$opt_l ? "\n" : ''; ; ;open(BIN,"+>$opt_o") or die; ;binmode(BIN) unless $opt_E; ;while(<>) { ; y/\n\r//d; ; if($opt_v && !/^\s*#/) { ; while(($key, $value) = each %symbol) { ; $x=0; ; while(($x = index($_,$key,$x)) >= 0) { ; substr($_,$x,length($key),$value); ; $x+=length($value); ; } ; } ; } ; if(/^\s*#\s*()ifdef\s+(\S+)\s*$/ ; || /^\s*#\s*((?:el)?)if\s+defined\s*\(\s*(\S*)\s*\)/ ; || /^\s*#\s*((?:el)?)if\s+defined\s+(\S+)/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|!exists($symbol{$2})];$_=$l; ; }elsif(/^\s*#\s*()ifndef\s+(\S+)\s*$/ ; || /^\s*#\s*((?:el)?)if\s+\!\s*defined\s*\(\s*(\S*)\s*\)/ ; || /^\s*#\s*((?:el)?)if\s+\!\s*defined\s+(\S+)/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|exists($symbol{$2})];$_=$l; ; }elsif(/^\s*#\s*((?:el)?)if\s+\(\s*\!\s*(\S*)\s*\)\s*$/ ; || /^\s*#\s*((?:el)?)if\s+\!\s*\(\s*(\S*)\s*\)\s*$/ ; || /^\s*#\s*((?:el)?)if\s+\!\s*(\S*)\s*$/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|($symbol{$2}!=0)];$_=$l; ; }elsif(/^\s*#\s*((?:el)?)if\s+\(\s*(\S*)\s*\)\s*$/ ; || /^\s*#\s*((?:el)?)if\s+(\S*)\s*$/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|($symbol{$2}==0)];$_=$l; ; }elsif(/^\s*#\s*else(?!\S)/) { ; $x[0]=$t[$x[0]|$x[1]&2];$_=$l; ; }elsif(/^\s*#\s*endif(?!\S)/) { ; shift@x;@x=(2)unless@x;$_=$l; ; }elsif($x[0] & 2 && /^\s*#\s*define\s+(\S+)\s*(.*)$/) { ; $symbol{$1}=$2;$_=$l; ; }elsif($x[0] & 2 && /^\s*#\s*undef\s+(\S+)/) { ; delete $symbol{$1};$_=$l; ; }else{ ; $_.="\n"; ; } ; if($opt_E) { ; print BIN ($x[0] & 2 ? $_ : $l); next; ; }elsif(($x[0] & 2)==0) { ; next; ; } ; if(/^ {0,2}([0-9A-F]{4})/) { ; print STDERR "seek $1\n" if $opt_d; ; seek(BIN,hex($1)-$opt_b,SEEK_SET); ; } ; if(/^ {0,2}[^;\\]{4}((?: {0,2}[0-9A-F]{2}){1,3})/) { ; ($a=$1)=~y/ //d; ; print STDERR " write $a\n" if $opt_d; ; print BIN pack("H*",$a); ; } ; if(/^ {0,2}[^;\\]{4} {0,2}EQUS ((?:"[^"]*")*)/) { ; ($a=substr($1,1,length($1)-2))=~s/""/"/g; ; print STDERR " write $a\n" if $opt_d; ; print BIN $a; ; } ; if(/^ {0,2}[^;\\]{4} {0,2}EQU[^S] (&[0-9A-F]{2}(?:,&[0-9A-F]{2})*)/){ ; ($a=$1)=~y/,&//d; ; print STDERR " write $a\n" if $opt_d; ; print BIN pack("H*",$a); ; } ;} ;close(BIN); ;-------->8--- ;End of chal200.asm.txt