;Disassembly of Opus DDOS 3.46 and variants ;Greg Cook, 16 April 2024 ;Hints on Tube host code (all attributed): ;(NAUG) M. Holmes and A. Dickens, The new advanced user guide for ; the BBC Microcomputer (Cambridge: Adder, 1987) ;(SB) Steven Bass's comments on Opus EDOS 0.4, ; http://regregex.bbcmicro.net/edos04.asm.txt ;(JGH) J. G. Harston's disassembly of the Tube host code, ; https://mdfs.net/Software/Tube/BBC/Host100.lst ;Pass this file through a C preprocessor or the attached asm2bin.pl ;to produce a listing that assembles one of the six enclosed ;versions of DDOS. ;Define one of the following symbols during preprocessing to assemble ;its associated target, listed in estimated date order:- ;Symbol: _DDOS346PRE (default) ;Source: https://mdfs.net/Mirror/Image/Challenger/DISS.ZIP ;Path: DDOS346 ;Compatibility: Opus DDOS interface for Model B, WD 1770 ;Banner version: 3.46 ;*ROMID string: 3.45 01-03-86 ;Code length: &3F3F ;Acorn CRC: &3C3A ;PKZIP CRC: &C146F266 ;XFER CRC: &A22A48A5 ;Cksum: 2457132685 ;Symbol: _DDOS316 ;Source: http://regregex.bbcmicro.net/romsearch.zip ;Path: romsearch/slogger/Slogger-DDOS-3.16-Copyright-c-1984-Slogger-Software-alt1 ;Compatibility: Opus DDOS interface for Model B, WD 2791 ;Banner version: 3.16 ;*ROMID string: 3.16 01-03-86 ;Code length: &3F30 ;Acorn CRC: &07FD ;PKZIP CRC: &268EBC0D ;XFER CRC: &9E06A31E ;Cksum: 2106235609 ;Symbol: _DDOS336 ;Source: http://regregex.bbcmicro.net/romsearch.zip ;Path: romsearch/slogger/Slogger-DDOS-3.36-Copyright-c-1984-Slogger-Software ;Compatibility: Opus DDOS interface for Model B, WD 2793 ;Banner version: 3.36 ;*ROMID string: 3.36 01-03-86 ;Code length: &3F1E ;Acorn CRC: &7196 ;PKZIP CRC: &2F400F69 ;XFER CRC: &0C4CD447 ;Cksum: 1809122509 ;Symbol: _DDOS346 ;Source: http://wouter.bbcmicro.net/bbc/bestanden/roms-2009.01.28.zip ;Path: roms/kopie_van_disk/Opus/Opus__Slogger_DDOS__3.46 ;Compatibility: Opus DDOS interface for Model B, WD 1770 ;Banner version: 3.46 ;*ROMID string: 3.46 01-03-86 ;Code length: &3F40 ;Acorn CRC: &9C48 ;PKZIP CRC: &BF9C35CF ;XFER CRC: &927A0EC3 ;Cksum: 3431659878 ;Symbol: _DDOS356 ;Source: https://mdfs.net/Mirror/Image/Challenger/DISS.ZIP ;Path: DDOS356 (edited) ;Compatibility: Built-in interface on Master 128, WD 1770 ;Banner version: 3.56 ;*ROMID string: 3.45 01-03-86 ;Code length: &3F59 ;Acorn CRC: &5DEC ;PKZIP CRC: &1571DAE6 ;XFER CRC: &94C83A73 ;Cksum: 1522787914 ;Symbol: _DDOS357 ;Source: https://mdfs.net/Mirror/Image/Challenger/DISS.ZIP ;Path: DDOS357 (edited) ;Compatibility: Built-in interface on Master 128, WD 1770 ;Banner version: 3.58 ;*ROMID string: 3.45 01-03-86 ;Code length: &3F6C (=&3F59-&0004+&0017) ;Acorn CRC: &EB49 ;PKZIP CRC: &22AB01AB ;XFER CRC: &926623EF ;Cksum: 2692941395 ;Symbol: _DDOS326 ;Source: https://mdfs.net/Mirror/Image/Challenger/DISS.ZIP ;Path: DDOS346 (edited) ;Compatibility: Acorn interface on Model B/B+, WD 1770 ;Banner version: 3.26 ;*ROMID string: 3.26 16-12-22 ;Code length: &3F46 (=&3F52-&000C) ;Acorn CRC: &AA23 ;PKZIP CRC: &85B39BC2 ;XFER CRC: &C280D9A3 ;Cksum: 1495495777 ;Symbols to enable RAM disc use. ;Maximum paged RAM supported (some boards fitted with less): ;_DDOSRAM Model B, 256 KiB on DDOS RAM pack ;_BMEM Model B, 128 KiB paged RAM to Greg Cook's BMem recipe ;_IFEL Model B, 128 KiB on IFEL RAM/ROM board ;_WILLIAMS Model B, 128 KiB on Alan Williams' SWRAM/Flash board ;_TWOMEG Model B, 128 KiB on Solidisk Twomeg board ;_PLUGIN Model B, 128 KiB on 4x RAM/ROM modules from BooBip.com ;_PLUGIN2 Model B, 128 KiB on 4x RAM/ROM modules, alternate layout ;_PLUGIN3 Model B, 128 KiB on 4x RAM/ROM modules, alternate layout ;_BPLUS Model B+, 76 KiB internal paged RAM ;_MASTER Master, 128 KiB; 64 KiB internal + 2x 32 KiB cartridges ;_RAMINIT64K *RAMINIT creates 64 KiB RAM disc catalogue ;_RAMINIT76K *RAMINIT creates 76 KiB RAM disc catalogue ;_RAMINIT256K *RAMINIT creates 256 KiB RAM disc catalogue ;Other interoperability symbols: ;_BUGFIX Fix parsing of file specifications "*" and ".*" ; Ignore NMIs during track seek operations ; Preserve stack in *FDCSTAT, *RAMINIT and *ROMID ; *RUN, */ enter executables with Acorn DFS-like registers ; Set attribute correctly in OSFILE 4 ;_DFSFIX Provide OSARGS 3,Y (EXT#=), OSFILE 7/9/10/11 ; (create/stamp file) and minimal RISC OS semantics ;_MOS350 (DDOS 3.57 only) Enable all *commands under MOS 3.50 ;_TURBO Unrolled 'save AXY' routine for shorter debugging traces ;An accompanying module to speed up OSGBPB calls is available. ;http://regregex.bbcmicro.net/#prog.dfsfix #undef _RAMBUGFIX #if defined _DDOSRAM # define _RAMBUGFIX 1 #elif defined _BMEM # define _RAMBUGFIX 1 #elif defined _IFEL # define _RAMBUGFIX 1 #elif defined _WILLIAMS # define _RAMBUGFIX 1 #elif defined _TWOMEG # define _RAMBUGFIX 1 #elif defined _PLUGIN # define _RAMBUGFIX 1 #elif defined _PLUGIN2 # define _RAMBUGFIX 1 #elif defined _PLUGIN3 # define _RAMBUGFIX 1 #elif defined _BPLUS # define _RAMBUGFIX 1 #elif defined _MASTER # define _RAMBUGFIX 1 #endif #if defined _DDOS316 # undef _BEEBEM #elif defined _DDOS336 # undef _BEEBEM #elif defined _DDOS346 # undef _BEEBEM #endif 8000 EQUB &00 ;Language entry 8001 EQUB &00 8002 EQUB &00 #if defined _DDOS357 8003 4C E8 BF JMP SFE8 ;Service entry #else 8003 4C 47 80 JMP P047 ;Service entry #endif 8006 EQUB &82 ;rom type: service only 8007 EQUB &1A ;Copyright offset pointer 8008 EQUB &35 ;Version No. #if defined _DDOS356 8009 EQUS "Master DDOS " ;title 8015 EQUB &00 ;terminator byte 8016 EQUS "3.56" ;version string 801A EQUB &00 ;terminator byte 801B EQUS "(C)Copyright (c) 1990 F.T.C." ;copyright pointer validated by MOS prior to accepting ROM 8037 EQUB &00 ;terminator byte 8038 EQUS "Software " 8041 EQUB &00 ;terminator byte #elif defined _DDOS357 8009 EQUS "Master DDOS " ;title 8015 EQUB &00 ;terminator byte 8016 EQUS "3.57" ;version string 801A EQUB &00 ;terminator byte 801B EQUS "(C)Copyright (c) 1990 F.T.C." ;copyright pointer validated by MOS prior to accepting ROM 8037 EQUB &00 ;terminator byte 8038 EQUS "Software " 8041 EQUB &00 ;terminator byte #elif defined _DDOS326 8009 EQUS "Otus DDOS B+" ;title 8015 EQUB &00 ;terminator byte 8016 EQUS "3.26" ;version string 801A EQUB &00 ;terminator byte 801B EQUS "(C)Copyright (c) 2022 Otus" ;copyright pointer validated by MOS prior to accepting ROM 8035 EQUB &00,&00,&00,&00 ;terminator byte 8039 EQUB &00,&00,&00,&00 803D EQUB &00,&00,&00,&00 8041 EQUB &00 #else /* COMMON */ 8009 EQUS "Slogger DDOS" ;title 8015 EQUB &00 ;terminator byte 8016 EQUS "3.x5" ;version string 801A EQUB &00 ;terminator byte 801B EQUS "(C)Copyright (c) 1984 Slogger Software" ;copyright pointer validated by MOS prior to accepting ROM 8041 EQUB &00 ;terminator byte #endif /* _DDOS356 */ .P042 ;Issue Filing System Call 8042 6C 1E 02 JMP (&021E) #if defined _DDOS357 ;////////////////////////////////////////////// DDOS 3.57 .P045 ;ROM service 8045 20 A9 BA JSR SAA9 ;service calls &FE, &FF 8048 C9 01 CMP #&01 804A D0 06 BNE P052 804C C0 17 CPY #&17 ;Service call &01 = reserve absolute workspace 804E B0 02 BCS P052 ;if workspace < 9 pages (+&0E = &17) 8050 A0 17 LDY #&17 ;then reserve 9 pages abs workspace. .P052 8052 C9 02 CMP #&02 8054 90 19 BCC P06F 8056 D0 18 BNE P070 8058 98 TYA ;Service call &02 = reserve private workspace 8059 85 B1 STA &B1 ;y=lowest free page, store in pointer 805B 9D F0 0D STA &0DF0,X ;and in the MOS workspace for this purpose 805E A9 00 LDA #&00 ;clear LSB of pointer 8060 85 B0 STA &B0 8062 A0 C0 LDY #&C0 ;clear offset &C0 of page 8064 91 B0 STA (&B0),Y ;b7=1 iff private page initialised 8066 C8 INY ;and offset &C1 8067 91 B0 STA (&B0),Y ;b7=1 iff we own the shared workspace 8069 A4 B1 LDY &B1 ;y = 2 + address of private page 806B C8 INY ;thus reserving two private pages 806C C8 INY 806D A9 02 LDA #&02 ;restore call number and pass to next ROM. .P06F 806F 60 RTS .P070 8070 C9 04 CMP #&04 8072 F0 1B BEQ P08F 8074 B0 5E BCS P0D4 8076 84 B3 STY &B3 ;Service call &03 = boot 8078 20 00 A3 JSR R300 ;save boot flag in scratch space 807B A9 7A LDA #&7A ;call OSBYTE &7A = scan keyboard from &10+ 807D 20 F4 FF JSR &FFF4 8080 8A TXA ;test returned key code 8081 30 09 BMI P08C ;if N=1 no key is pressed, so init and boot 8083 C9 32 CMP #&32 ;else if key pressed is not D 8085 D0 E8 BNE P06F ;then exit 8087 A9 78 LDA #&78 ;else register keypress for two-key rollover 8089 20 F4 FF JSR &FFF4 .P08C 808C 4C DB 81 JMP P1DB ;initialise DDOS and boot default volume .P08F 808F 20 00 A3 JSR R300 ;Service call &04 = unrecognised OSCLI 8092 BA TSX 8093 86 B8 STX &B8 ;save stack pointer to restore on abort 8095 98 TYA ;a=offset of *command from GSINIT pointer 8096 A2 5F LDX #&5F ;point XY to utility command table at &8E5F 8098 A0 8E LDY #&8E 809A 20 C7 8E JSR PEC7 ;search for command in table 809D B0 63 BCS P102 ;if not found then exit 809F 86 AF STX &AF ;else save pointer to syntax byte in workspace 80A1 5A PHY ;save offset of command line tail on stack 80A2 AD 1E 02 LDA &021E ;test address in FSCV # if defined _MOS350 80A5 C9 A5 CMP #&A5 ;if it does not point to MOS ROM at &F8A5 # else 80A5 C9 69 CMP #&69 ;if it does not point to MOS ROM at &FB69 # endif 80A7 D0 21 BNE P0CA ;then only execute *command if syntax b7=0 80A9 AD 1F 02 LDA &021F # if defined _MOS350 80AC C9 F8 CMP #&F8 # else 80AC C9 FB CMP #&FB # endif 80AE D0 1A BNE P0CA 80B0 20 14 A8 JSR R814 ;else FSCV not intercepted. 80B3 86 B0 STX &B0 ;call OSBYTE &A8 = get extended vector table 80B5 84 B1 STY &B1 ;address in XY. store XY as pointer 80B7 A0 2D LDY #&2D ;test sixteenth entry in table = FSCV 80B9 B1 B0 LDA (&B0),Y ;if FSCV vector address is not &BF40 80BB C9 40 CMP #&40 80BD D0 0B BNE P0CA ;then only execute *command if syntax b7=0 80BF C8 INY 80C0 B1 B0 LDA (&B0),Y 80C2 C9 BF CMP #&BF 80C4 D0 04 BNE P0CA .P0C6 80C6 7A PLY ;else restore offset of command line tail .P0C7 80C7 6C A8 00 JMP (&00A8) ;and execute *command. .P0CA ;*command while FSCV does not point to us 80CA A6 AF LDX &AF ;get syntax byte from command table 80CC 20 AA 00 JSR &00AA 80CF 10 F5 BPL P0C6 ;if b7=0 then execute *command 80D1 4C F2 84 JMP P4F2 ;else restore stack pointer and exit .P0D4 80D4 C9 09 CMP #&09 80D6 D0 2B BNE P103 80D8 20 00 A3 JSR R300 ;Service call &09 = *HELP 80DB 20 BB A4 JSR R4BB ;save AXY, test for keyword 80DE D0 09 BNE P0E9 ;if present then scan keyword 80E0 A2 A7 LDX #&A7 ;else point XY to *HELP keyword table at &8EA7 80E2 A0 8E LDY #&8E 80E4 A9 04 LDA #&04 ;4 entries to print 80E6 4C F6 9F JMP QFF6 ;print *HELP keywords and pass on the call. .P0E9 ;Scan *HELP keyword 80E9 5A PHY ;y=offset of keyword from GSINIT pointer 80EA 98 TYA ;save on stack and transfer to A 80EB A2 A7 LDX #&A7 ;point XY to *HELP keyword table at &8EA7 80ED A0 8E LDY #&8E 80EF 20 C7 8E JSR PEC7 ;search for keyword in table 80F2 B0 03 BCS P0F7 ;if keyword found 80F4 20 C7 80 JSR P0C7 ;then call its action address; print help .P0F7 80F7 7A PLY ;restore string offset .P0F8 80F8 20 C5 FF JSR &FFC5 ;call GSREAD 80FB 90 FB BCC P0F8 ;until end of argument (discarding it) 80FD 20 BB A4 JSR R4BB ;then test for next keyword 8100 D0 E7 BNE P0E9 ;if present then scan next *HELP keyword .P102 8102 60 RTS ;else exit .P103 8103 C9 12 CMP #&12 8105 D0 0A BNE P111 8107 C0 04 CPY #&04 ;Service call &12 = initialise FS 8109 D0 F7 BNE P102 ;if number of FS to initialise = 4 810B 20 00 A3 JSR R300 ;then save AXY 810E 4C 0F 82 JMP P20F ;and initialise DDOS .P111 8111 C9 0A CMP #&0A 8113 D0 25 BNE P13A 8115 20 00 A3 JSR R300 ;Service call &0A = workspace claimed 8118 20 D4 9F JSR QFD4 ;set up pointer to private page 811B A0 C1 LDY #&C1 ;y = offset = &C1 shared workspace ownership 811D B1 B0 LDA (&B0),Y ;fetch byte at offset &C1 of private page 811F 10 18 BPL P139 ;if b7 clear then we already vacated, exit 8121 A9 00 LDA #&00 ;clear flag at offset &C1 of private page 8123 F0 03 BEQ P128 ;b7=1 iff we own the shared workspace. .P125 8125 B9 00 11 LDA &1100,Y ;store bytes &10C0..&11BF in private page .P128 8128 91 B0 STA (&B0),Y ;(wrapped around so that private page 812A C8 INY ;contains: &1100..BF, &10C0..FF) 812B B9 00 10 LDA &1000,Y 812E C0 C0 CPY #&C0 8130 90 F3 BCC P125 8132 D0 F4 BNE P128 8134 91 B0 STA (&B0),Y ;store &10C0 in private page at offset &C0 8136 4C D1 97 JMP Q7D1 ;ensure all files up-to-date on disc (flush) .P139 8139 60 RTS #else /* _DDOS357 */ ;////////////////////////////////////////////// COMMON 8045 EQUW &99,&A8 ;pointer to DDOS version information &A899 .P047 ;ROM service # if defined _DDOS316 8047 20 9A BA JSR SA9A ;service calls &FE, &FF # elif defined _DDOS336 8047 20 88 BA JSR SA88 ;service calls &FE, &FF # elif defined _DDOS346 8047 20 AA BA JSR SAAA ;service calls &FE, &FF # else 8047 20 A9 BA JSR SAA9 ;service calls &FE, &FF # endif 804A C9 01 CMP #&01 804C D0 07 BNE P055 804E C0 17 CPY #&17 ;Service call &01 = reserve absolute workspace 8050 B0 02 BCS P054 ;if workspace < 9 pages (+&0E = &17) 8052 A0 17 LDY #&17 ;then reserve 9 pages abs workspace. .P054 8054 60 RTS .P055 8055 C9 02 CMP #&02 8057 D0 18 BNE P071 8059 98 TYA ;Service call &02 = reserve private workspace 805A 85 B1 STA &B1 ;y=lowest free page, store in pointer 805C 9D F0 0D STA &0DF0,X ;and in the MOS workspace for this purpose 805F A9 00 LDA #&00 ;clear LSB of pointer 8061 85 B0 STA &B0 8063 A0 C0 LDY #&C0 ;clear offset &C0 of page 8065 91 B0 STA (&B0),Y ;b7=1 iff private page initialised 8067 C8 INY ;and offset &C1 8068 91 B0 STA (&B0),Y ;b7=1 iff we own the shared workspace 806A A4 B1 LDY &B1 ;y = 2 + address of private page 806C C8 INY ;thus reserving two private pages 806D C8 INY 806E A9 02 LDA #&02 ;restore call number and pass to next ROM. .P070 8070 60 RTS .P071 8071 C9 03 CMP #&03 8073 D0 19 BNE P08E 8075 84 B3 STY &B3 ;Service call &03 = boot 8077 20 00 A3 JSR R300 ;save boot flag in scratch space 807A A9 7A LDA #&7A ;call OSBYTE &7A = scan keyboard from &10+ 807C 20 F4 FF JSR &FFF4 807F 8A TXA ;test returned key code 8080 30 09 BMI P08B ;if N=1 no key is pressed, so init and boot 8082 C9 32 CMP #&32 ;else if key pressed is not D 8084 D0 EA BNE P070 ;then exit 8086 A9 78 LDA #&78 ;else register keypress for two-key rollover 8088 20 F4 FF JSR &FFF4 .P08B 808B 4C DB 81 JMP P1DB ;initialise DDOS and boot default volume .P08E 808E C9 04 CMP #&04 8090 D0 47 BNE P0D9 8092 20 00 A3 JSR R300 ;Service call &04 = unrecognised OSCLI 8095 BA TSX 8096 86 B8 STX &B8 ;save stack pointer to restore on abort 8098 98 TYA ;a=offset of *command from GSINIT pointer 8099 A2 5F LDX #&5F ;point XY to utility command table at &8E5F 809B A0 8E LDY #&8E 809D 20 C7 8E JSR PEC7 ;search for command in table 80A0 B0 4D BCS P0EF ;if not found then exit 80A2 86 AF STX &AF ;else save pointer to syntax byte in workspace 80A4 98 TYA ;save offset of command line tail on stack 80A5 48 PHA 80A6 AD 1E 02 LDA &021E ;test address in FSCV 80A9 C9 2D CMP #&2D ;if it does not point to MOS ROM at &FB69 80AB D0 22 BNE P0CF ;then only execute *command if syntax b7=0 80AD AD 1F 02 LDA &021F 80B0 C9 FF CMP #&FF 80B2 D0 1B BNE P0CF 80B4 20 14 A8 JSR R814 ;else FSCV not intercepted. 80B7 86 B0 STX &B0 ;call OSBYTE &A8 = get extended vector table 80B9 84 B1 STY &B1 ;address in XY. store XY as pointer 80BB A0 2D LDY #&2D ;test sixteenth entry in table = FSCV 80BD B1 B0 LDA (&B0),Y ;if FSCV vector address is not &9468 80BF C9 68 CMP #&68 80C1 D0 0C BNE P0CF ;then only execute *command if syntax b7=0 80C3 C8 INY 80C4 B1 B0 LDA (&B0),Y 80C6 C9 94 CMP #&94 80C8 D0 05 BNE P0CF .P0CA 80CA 68 PLA ;else restore offset of command line tail 80CB A8 TAY .P0CC 80CC 6C A8 00 JMP (&00A8) ;and execute *command. .P0CF ;*command while FSCV does not point to us 80CF A6 AF LDX &AF ;get syntax byte from command table 80D1 20 AA 00 JSR &00AA 80D4 10 F4 BPL P0CA ;if b7=0 then execute *command 80D6 4C F2 84 JMP P4F2 ;else restore stack pointer and exit .P0D9 80D9 C9 09 CMP #&09 80DB D0 30 BNE P10D 80DD 20 00 A3 JSR R300 ;Service call &09 = *HELP 80E0 B1 F2 LDA (&F2),Y ;save AXY, test char at start of *HELP string 80E2 C9 0D CMP #&0D ;if not CR then *HELP called with keyword 80E4 D0 0A BNE P0F0 ;so scan keyword 80E6 A2 A7 LDX #&A7 ;else point XY to *HELP keyword table at &8EA7 80E8 A0 8E LDY #&8E 80EA A9 04 LDA #&04 ;4 entries to print 80EC 20 F6 9F JSR QFF6 ;print *HELP keywords and pass on the call. .P0EF 80EF 60 RTS .P0F0 ;Scan *HELP keyword 80F0 20 BB A4 JSR R4BB ;call GSINIT with C=0 80F3 F0 FA BEQ P0EF ;if string is empty then pass call on 80F5 98 TYA ;else a=offset of keyword from GSINIT pointer 80F6 48 PHA ;also save on stack 80F7 A2 A7 LDX #&A7 ;point XY to *HELP keyword table at &8EA7 80F9 A0 8E LDY #&8E 80FB 20 C7 8E JSR PEC7 ;search for keyword in table 80FE B0 03 BCS P103 ;if keyword found 8100 20 CC 80 JSR P0CC ;then call its action address; print help .P103 8103 68 PLA ;restore string offset 8104 A8 TAY .P105 8105 20 C5 FF JSR &FFC5 ;call GSREAD 8108 90 FB BCC P105 ;until end of argument (discarding it) 810A 4C F0 80 JMP P0F0 ;then scan next *HELP keyword .P10D 810D C9 0A CMP #&0A 810F D0 29 BNE P13A 8111 20 00 A3 JSR R300 ;Service call &0A = workspace claimed 8114 20 D4 9F JSR QFD4 ;set up pointer to private page 8117 A0 C1 LDY #&C1 ;y = offset = &C1 shared workspace ownership 8119 B1 B0 LDA (&B0),Y ;fetch byte at offset &C1 of private page 811B 10 1C BPL P139 ;if b7 clear then we already vacated, exit 811D A0 00 LDY #&00 ;else set offset = 0: .P11F 811F C0 C0 CPY #&C0 ;store bytes &10C0..&11BF in private page 8121 90 05 BCC P128 ;(wrapped around so that private page 8123 B9 00 10 LDA &1000,Y ;contains: &1100..BF, &10C0..FF) 8126 B0 03 BCS P12B .P128 8128 B9 00 11 LDA &1100,Y .P12B 812B 91 B0 STA (&B0),Y 812D C8 INY 812E D0 EF BNE P11F 8130 20 D1 97 JSR Q7D1 ;ensure all files up-to-date on disc (flush) 8133 A0 C1 LDY #&C1 ;clear flag at offset &C1 of private page 8135 A9 00 LDA #&00 ;b7=1 iff we own the shared workspace. 8137 91 B0 STA (&B0),Y .P139 8139 60 RTS #endif /* _DDOS357 */ .P13A 813A C9 08 CMP #&08 ;if call not &1,2,3,4,8,9,A,FE,FF then return 813C D0 FB BNE P139 #if defined _TURBO 813E 20 2D A3 JSR R32D ;Service call &08 = unrecognised OSWORD #else 813E 20 29 A3 JSR R329 ;Service call &08 = unrecognised OSWORD #endif 8141 A4 F0 LDY &F0 ;save XY (X will be clobbered on return) 8143 84 B0 STY &B0 ;set &B0..1 = pointer to OSWORD control block 8145 A4 F1 LDY &F1 8147 84 B1 STY &B1 8149 A4 EF LDY &EF ;set Y = OSWORD call number (in A on entry) 814B C0 7F CPY #&7F 814D D0 5C BNE P1AB 814F 20 C1 A7 JSR R7C1 ;OSWORD A = &7F 8152 A0 01 LDY #&01 ;claim NMI 8154 B1 B0 LDA (&B0),Y ;offset 1 = address LSB 8156 85 A6 STA &A6 ;copy to &A6 8158 C8 INY 8159 B1 B0 LDA (&B0),Y ;offset 2 = address 3MSB 815B 85 A7 STA &A7 ;copy to &A7 815D A0 00 LDY #&00 815F B1 B0 LDA (&B0),Y ;offset 0 = drive number 8161 30 03 BMI P166 ;if b7=1 then use previous drive 8163 20 03 A5 JSR R503 ;else select drive in A .P166 8166 C8 INY ;offset 1 = address 8167 A2 02 LDX #&02 8169 20 CB 87 JSR P7CB ;copy address to &BE,F,&106F,70 816C C8 INY ;y = 5 on exit; increment 816D B1 B0 LDA (&B0),Y ;offset 6 = command 816F 29 3F AND #&3F 8171 85 B2 STA &B2 8173 20 67 A4 JSR R467 ;shift A right 4 places, extract bit 4: 8176 29 01 AND #&01 ;a=0 if writing to disc, A=1 if reading 8178 20 00 93 JSR Q300 ;open Tube data transfer channel 817B A0 07 LDY #&07 817D B1 B0 LDA (&B0),Y ;offset 7 = first parameter (usu. track) 817F C8 INY ;offset 8, Y points to second parameter 8180 85 BA STA &BA 8182 A2 FD LDX #&FD ;x = &FD to start at offset 0: .P184 8184 E8 INX ;add 3 to X 8185 E8 INX 8186 E8 INX 8187 BD 11 B6 LDA &B611,X ;get command byte from table 818A F0 16 BEQ P1A2 ;if the terminator byte then exit 818C C5 B2 CMP &B2 ;else compare with OSWORD &7F command 818E D0 F4 BNE P184 ;if not the same try next entry 8190 08 PHP ;else save interrupt state 8191 58 CLI ;enable interrupts 8192 A9 81 LDA #&81 ;push return address &81A1 on stack 8194 48 PHA 8195 A9 A0 LDA #&A0 8197 48 PHA 8198 BD 13 B6 LDA &B613,X ;fetch action address high byte 819B 48 PHA ;push on stack 819C BD 12 B6 LDA &B612,X ;fetch action address low byte 819F 48 PHA ;push on stack 81A0 60 RTS ;jump to action address. ;Finish OSWORD &7F 81A1 28 PLP .P1A2 81A2 20 A7 A7 JSR R7A7 ;release NMI 81A5 20 38 93 JSR Q338 ;release Tube 81A8 A9 00 LDA #&00 ;exit A=0 to claim service call 81AA 60 RTS .P1AB ;OSWORD A <> &7F 81AB C0 7D CPY #&7D ;if A < &7D 81AD 90 2B BCC P1DA ;then exit 81AF 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive 81B2 20 9E 92 JSR Q29E ;load volume catalogue L4 81B5 C0 7E CPY #&7E 81B7 F0 09 BEQ P1C2 81B9 A0 00 LDY #&00 ;OSWORD A = &7D (and &80..&DF) 81BB AD 04 0F LDA &0F04 ;get catalogue cycle number 81BE 91 B0 STA (&B0),Y ;store in OSWORD control block offset 0 81C0 98 TYA ;return A = 0, claiming service call. 81C1 60 RTS .P1C2 ;OSWORD A = &7E get size of volume in bytes 81C2 A9 00 LDA #&00 81C4 A8 TAY 81C5 91 B0 STA (&B0),Y ;store 0 at offset 0: multiple of 256 bytes 81C7 C8 INY ;offset 1 81C8 AD 07 0F LDA &0F07 ;get LSB volume size from catalogue 81CB 91 B0 STA (&B0),Y ;save as 3MSB volume size 81CD C8 INY ;offset 2 81CE AD 06 0F LDA &0F06 ;get boot option/top bits volume size 81D1 29 03 AND #&03 ;extract MSB volume size 81D3 91 B0 STA (&B0),Y ;save as 2MSB volume size 81D5 C8 INY ;offset 3 81D6 A9 00 LDA #&00 ;store 0: volume size less than 16 MiB 81D8 91 B0 STA (&B0),Y .P1DA 81DA 60 RTS .P1DB 81DB A5 B3 LDA &B3 ;get back boot flag (Y on entry to call &3) 81DD 48 PHA ;save on stack 81DE A2 FF LDX #&FF 81E0 8E DD 10 STX &10DD ;no error message being built print to screen 81E3 A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset 81E5 20 1E A8 JSR R81E ;call OSBYTE with X=0, Y=&FF 81E8 20 02 82 JSR P202 ;validate shared workspace 81EB D0 03 BNE P1F0 ;if invalid then initialise shared workspace 81ED 8A TXA ;else test type of last reset 81EE F0 03 BEQ P1F3 ;if A=0 then soft break so skip .P1F0 81F0 20 D2 82 JSR P2D2 ;else initialise shared workspace .P1F3 81F3 20 84 A8 JSR R884 ;print DDOS banner 81F6 20 15 82 JSR P215 ;initialise DDOS 81F9 68 PLA ;if boot flag was >0 81FA D0 03 BNE P1FF ;then return A=0 to claim call 81FC 4C F5 82 JMP P2F5 ;else examine and boot default volume .P1FF ;Return A=0 81FF A9 00 LDA #&00 8201 60 RTS .P202 ;Validate shared workspace 8202 AD C2 10 LDA &10C2 ;compare first sentinel with "A" 8205 C9 41 CMP #&41 8207 D0 05 BNE P20E ;return Z=0 if unequal 8209 AD DE 10 LDA &10DE ;else compare second sentinel with "H" 820C C9 48 CMP #&48 ;return Z=0 if unequal, Z=0 if both equal .P20E 820E 60 RTS #if defined _DDOS357 .P20F #endif /* _DDOS357 */ ;*DISC / *DISK 820F 48 PHA 8210 20 15 82 JSR P215 ;initialise DDOS 8213 68 PLA 8214 60 RTS .P215 ;Initialise DDOS 8215 A9 00 LDA #&00 8217 BA TSX 8218 9D 08 01 STA &0108,X ;have A=0 returned on exit 821B A9 06 LDA #&06 ;FSC &06 = new FS about to change vectors 821D 20 42 80 JSR P042 ;issue Filing System Call 8220 A2 00 LDX #&00 ;x = 0 offset in MOS vector table .P222 8222 BD 25 A8 LDA &A825,X ;copy addresses of extended vector handlers 8225 9D 12 02 STA &0212,X ;to FILEV,ARGSV,BGETV,BPUTV,GBPBV,FINDV,FSCV 8228 E8 INX ;loop until 7 vectors transferred 8229 E0 0E CPX #&0E 822B D0 F5 BNE P222 822D 20 14 A8 JSR R814 ;call OSBYTE &A8 = get ext. vector table addr 8230 84 B1 STY &B1 ;set up pointer to vector table 8232 86 B0 STX &B0 8234 A2 00 LDX #&00 ;x = 0 offset in DDOS vector table 8236 A0 1B LDY #&1B ;y = &1B offset of FILEV in extended vec tbl .P238 8238 BD 33 A8 LDA &A833,X ;get LSB action address from table 823B 91 B0 STA (&B0),Y ;store in extended vector table 823D E8 INX 823E C8 INY 823F BD 33 A8 LDA &A833,X ;get MSB action address from table 8242 91 B0 STA (&B0),Y ;store in extended vector table 8244 E8 INX 8245 C8 INY 8246 A5 F4 LDA &F4 ;get our ROM slot number 8248 91 B0 STA (&B0),Y ;store in extended vector table 824A C8 INY 824B E0 0E CPX #&0E ;loop until 7 vectors transferred 824D D0 E9 BNE P238 824F A2 0F LDX #&0F ;service call &0F = vectors claimed 8251 20 18 A8 JSR R818 ;call OSBYTE &8F = issue service call 8254 A9 FF LDA #&FF 8256 8D 84 10 STA &1084 ;no catalogue in pages &0E..F 8259 20 D4 9F JSR QFD4 ;set up pointer to private page 825C A0 C0 LDY #&C0 ;test offset &C0 of private page 825E B1 B0 LDA (&B0),Y ;b7=1 if private page initialised 8260 10 35 BPL P297 ;if b7=0 then initialise private page 8262 C8 INY ;else test offset &C1 of private page 8263 B1 B0 LDA (&B0),Y ;b7=1 iff we own the shared workspace 8265 30 27 BMI P28E ;if we already own it then ensure wksp valid 8267 20 C5 9F JSR QFC5 ;else claim shared workspace 826A A0 00 LDY #&00 .P26C 826C B1 B0 LDA (&B0),Y ;restore bytes &10C0..&11BF from private page 826E C0 C0 CPY #&C0 8270 90 05 BCC P277 8272 99 00 10 STA &1000,Y 8275 B0 03 BCS P27A .P277 8277 99 00 11 STA &1100,Y .P27A 827A 88 DEY 827B D0 EF BNE P26C 827D A9 A0 LDA #&A0 ;set channel workspace pointer = &A0: .P27F 827F A8 TAY ;transfer channel workspace pointer to Y 8280 48 PHA 8281 A9 3F LDA #&3F ;b7=0 PTR not in buffer; b6=0 buf unchanged 8283 20 46 99 JSR Q946 ;clear channel flag bits 8286 68 PLA 8287 99 1D 11 STA &111D,Y ;set MSB buffer address out of range 828A E9 1F SBC #&1F ;(to force a read) C=0 subtract &20 828C D0 F1 BNE P27F ;loop until all buffers discarded .P28E 828E 20 02 82 JSR P202 ;validate shared workspace 8291 F0 03 BEQ P296 ;if invalid 8293 20 D2 82 JSR P2D2 ;then initialise shared workspace .P296 8296 60 RTS .P297 ;Initialise private page 8297 A9 FF LDA #&FF ;set offset &C0 of private page = &FF 8299 91 B0 STA (&B0),Y ;b7=1 iff private page initialised 829B 8D C0 10 STA &10C0 ;set same flag in shared workspace 829E 20 C5 9F JSR QFC5 ;claim shared workspace 82A1 20 10 A8 JSR R810 ;call OSBYTE &EA = read Tube presence flag 82A4 8A TXA 82A5 49 FF EOR #&FF ;invert; 0=tube present &FF=Tube absent 82A7 8D D6 10 STA &10D6 ;save Tube presence flag 82AA 20 8E 82 JSR P28E ;ensure shared workspace is valid 82AD A9 0E LDA #&0E ;a=&0E 82AF 8D 01 10 STA &1001 ;*SROM E page in ROM slot 14 during disc ops 82B2 A0 00 LDY #&00 ;y=&00 82B4 8C C3 10 STY &10C3 ;no files are open 82B7 8C CE 10 STY &10CE ;unused 82BA 8C 87 10 STY &1087 ;NMI resource is not ours 82BD 88 DEY ;y=&FF 82BE 8C D2 10 STY &10D2 ;*commands are not *ENABLEd 82C1 8C D1 10 STY &10D1 ;*OPT 1,0 quiet operation 82C4 8C DD 10 STY &10DD ;no error message being built print to screen 82C7 8C 84 10 STY &1084 ;no catalogue in pages &0E..F 82CA 20 1C A8 JSR R81C ;call OSBYTE &FF = read/write startup options 82CD 86 B4 STX &B4 ;save them in zero page (unused) 82CF 4C 65 B6 JMP S665 ;re-read options and set drive stepping rate .P2D2 ;Initialise shared workspace 82D2 A9 00 LDA #&00 82D4 8D E0 10 STA &10E0 ;*4080 OFF no double-stepping 82D7 8D CB 10 STA &10CB ;set default volume = "0A" 82DA 8D CD 10 STA &10CD ;set library volume = "0A" 82DD A9 24 LDA #&24 82DF 8D CA 10 STA &10CA ;set default directory = "$" 82E2 8D CC 10 STA &10CC ;set library directory = "$" 82E5 A9 80 LDA #&80 82E7 8D E3 10 STA &10E3 ;*DENSITY AUTO 82EA A9 41 LDA #&41 ;set &10C2 first sentinel = "A" 82EC 8D C2 10 STA &10C2 82EF A9 48 LDA #&48 ;set &10DE second sentinel = "H" 82F1 8D DE 10 STA &10DE 82F4 60 RTS .P2F5 82F5 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive 82F8 20 A1 92 JSR Q2A1 ;load volume catalogue 82FB A0 00 LDY #&00 82FD A2 00 LDX #&00 82FF AD 06 0F LDA &0F06 ;get boot option/top bits volume size 8302 20 67 A4 JSR R467 ;shift A right 4 places 8305 F0 25 BEQ P32C ;if boot option = 0 then exit 8307 48 PHA 8308 A2 50 LDX #&50 ;point XY to filename "!BOOT" 830A A0 83 LDY #&83 830C 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 830F 20 E5 87 JSR P7E5 ;set current file from file spec 8312 20 63 89 JSR P963 ;search for file in catalogue 8315 68 PLA ;restore boot option 8316 B0 15 BCS P32D ;if !BOOT found then boot from it 8318 20 94 A3 JSR R394 ;else print "File not found" and return 831B EQUS "File not found" 8329 EQUB &0D 832A EQUB &0D 832B EA NOP .P32C 832C 60 RTS .P32D 832D C9 02 CMP #&02 832F 90 0E BCC P33F ;if boot option = 1 then load !BOOT 8331 F0 06 BEQ P339 ;if boot option = 2 then run !BOOT 8333 A2 4E LDX #&4E ;else boot option = 3 (or b7 or b6 set) 8335 A0 83 LDY #&83 ;point XY to "E.!BOOT" 8337 D0 0A BNE P343 ;call OSCLI .P339 8339 A2 50 LDX #&50 ;point XY to "!BOOT" 833B A0 83 LDY #&83 833D D0 04 BNE P343 ;call OSCLI .P33F 833F A2 46 LDX #&46 ;point XY to "L.!BOOT" 8341 A0 83 LDY #&83 .P343 8343 4C F7 FF JMP &FFF7 ;call OSCLI 8346 EQUS "L.!BOOT" 834D EQUB &0D 834E EQUS "E.!BOOT" 8355 EQUB &0D ;*TYPE 8356 20 D5 A2 JSR R2D5 ;claim service call and set up argument ptr 8359 A9 00 LDA #&00 ;a = &00 CR does not trigger line no. 835B F0 05 BEQ P362 ;*LIST 835D 20 D5 A2 JSR R2D5 ;claim service call and set up argument ptr 8360 A9 FF LDA #&FF ;a = &FF CR triggers line number .P362 8362 85 AB STA &AB ;store CR mask 8364 A9 40 LDA #&40 ;OSFIND &40 = open a file for reading 8366 20 CE FF JSR &FFCE ;call OSFIND 8369 A8 TAY ;test returned file handle 836A F0 30 BEQ P39C ;if file not found then raise error 836C A9 0D LDA #&0D ;preload CR so *LIST prints line no. 1 836E D0 1B BNE P38B ;branch to CR test (always) .P370 8370 20 D7 FF JSR &FFD7 ;call OSBGET 8373 B0 1E BCS P393 ;if EOF then finish 8375 C9 0A CMP #&0A ;else if character is LF 8377 F0 F7 BEQ P370 ;ignore it and get next one 8379 28 PLP ;else restore result of (A & mask) - CR 837A D0 08 BNE P384 ;if no match just print the character 837C 48 PHA ;else save first character of line 837D 20 9F A2 JSR R29F ;increment and print BCD word 8380 20 CC A2 JSR R2CC ;print a space 8383 68 PLA ;restore first character .P384 8384 20 E3 FF JSR &FFE3 ;call OSASCI 8387 24 FF BIT &FF ;if ESCAPE pressed 8389 30 09 BMI P394 ;then finish .P38B 838B 25 AB AND &AB ;else apply mask to character just prt'd 838D C9 0D CMP #&0D ;compare masked character with CR 838F 08 PHP ;save result 8390 4C 70 83 JMP P370 ;and loop to read next character .P393 8393 28 PLP ;discard result of (A & mask) - CR .P394 8394 20 67 84 JSR P467 ;print newline .P397 8397 A9 00 LDA #&00 ;OSFIND &00 = close file 8399 4C CE FF JMP &FFCE ;call OSFIND and exit .P39C 839C 4C 43 89 JMP P943 ;raise "File not found" error ;*DUMP 839F 20 D5 A2 JSR R2D5 ;claim service call and set up argument ptr 83A2 A9 40 LDA #&40 ;OSFIND &40 = open a file for reading 83A4 20 CE FF JSR &FFCE ;call OSFIND 83A7 A8 TAY ;transfer file handle to Y 83A8 F0 F2 BEQ P39C ;if file not found raise error 83AA A6 F4 LDX &F4 ;else get our ROM slot number 83AC BD F0 0D LDA &0DF0,X ;get address of our private page 83AF 85 AD STA &AD ;set up pointer 83B1 E6 AD INC &AD ;point to second private page .P3B3 83B3 24 FF BIT &FF ;if ESCAPE pressed 83B5 30 E0 BMI P397 ;then close file and exit 83B7 A5 A9 LDA &A9 ;else get high byte of file offset 83B9 20 29 A4 JSR R429 ;print hex byte 83BC A5 A8 LDA &A8 ;get low byte of file offset 83BE 20 29 A4 JSR R429 ;print hex byte 83C1 20 CC A2 JSR R2CC ;print a space 83C4 A9 07 LDA #&07 ;set counter, 8 bytes to print 83C6 85 AC STA &AC ;set up pointer 83C8 A2 00 LDX #&00 ;offset = 0 for indexed indirect load .P3CA 83CA 20 D7 FF JSR &FFD7 ;call OSBGET 83CD B0 0D BCS P3DC ;if EOF then finish 83CF 81 AC STA (&AC,X) ;else store byte in 2nd private page 83D1 20 29 A4 JSR R429 ;print hex byte 83D4 20 CC A2 JSR R2CC ;print a space 83D7 C6 AC DEC &AC ;decrement counter 83D9 10 EF BPL P3CA ;loop until line complete 83DB 18 CLC ;c=0, end of file not reached .P3DC 83DC 08 PHP ;save carry flag 83DD 90 0E BCC P3ED ;if not EOF then print full ASCII column .P3DF 83DF 20 94 A3 JSR R394 ;else print "** " 83E2 EQUS "** " 83E5 A9 00 LDA #&00 ;clear rest of row with NULs 83E7 81 AC STA (&AC,X) ;to print dots in ASCII column 83E9 C6 AC DEC &AC ;decrement counter 83EB 10 F2 BPL P3DF ;loop until hex column complete .P3ED 83ED A9 07 LDA #&07 ;set counter, 8 bytes to print 83EF 85 AC STA &AC ;set up pointer .P3F1 83F1 A1 AC LDA (&AC,X) ;get saved byte from file 83F3 C9 7F CMP #&7F ;if DEL or higher 83F5 B0 04 BCS P3FB ;then print a dot 83F7 C9 20 CMP #&20 ;else if a printable character 83F9 B0 02 BCS P3FD ;then print it .P3FB 83FB A9 2E LDA #&2E ;else print a dot: .P3FD 83FD 20 E3 FF JSR &FFE3 ;call OSASCI 8400 C6 AC DEC &AC ;decrement counter 8402 10 ED BPL P3F1 ;loop until line complete 8404 20 67 84 JSR P467 ;print newline 8407 A9 08 LDA #&08 ;add 8 to file offset 8409 18 CLC 840A 65 A8 ADC &A8 840C 85 A8 STA &A8 840E 90 02 BCC P412 8410 E6 A9 INC &A9 .P412 8412 28 PLP ;restore carry flag from OSBGET 8413 90 9E BCC P3B3 ;if not at end of file then print next row 8415 B0 80 BCS P397 ;else close file and exit ;*BUILD 8417 20 D5 A2 JSR R2D5 ;claim service call and set up argument ptr 841A A9 80 LDA #&80 ;OSFIND &80 = open a file for writing 841C 20 CE FF JSR &FFCE ;call OSFIND 841F 85 AB STA &AB ;save file handle .P421 8421 20 9F A2 JSR R29F ;increment and print BCD word 8424 20 CC A2 JSR R2CC ;print a space 8427 A6 F4 LDX &F4 ;get our ROM slot number 8429 BC F0 0D LDY &0DF0,X ;get address of our private page 842C C8 INY ;point to second private page 842D 84 AD STY &AD 842F A2 AC LDX #&AC ;x = &AC low address for OSWORD 8431 A0 FF LDY #&FF ;y = &FF 8433 84 AE STY &AE ;maximum line length = 255 8435 84 B0 STY &B0 ;maximum ASCII value = 255 8437 C8 INY 8438 84 AC STY &AC ;clear low byte of pointer 843A 84 AF STY &AF ;minimum ASCII value = 0 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 8447 F0 07 BEQ P450 .P449 8449 A1 AC LDA (&AC,X) ;get character of line 844B 20 D4 FF JSR &FFD4 ;call OSBPUT 844E E6 AC INC &AC ;increment low byte of pointer .P450 8450 A5 AC LDA &AC ;get low byte of pointer 8452 C5 AA CMP &AA ;compare with length of line 8454 D0 F3 BNE P449 ;if not at end of line then loop 8456 28 PLP ;else restore flags from OSWORD 8457 B0 08 BCS P461 ;if user escaped from input then finish 8459 A9 0D LDA #&0D ;else A = carriage return 845B 20 D4 FF JSR &FFD4 ;write to file 845E 4C 21 84 JMP P421 ;and loop to build next line .P461 8461 20 58 A4 JSR R458 ;acknowledge ESCAPE condition 8464 20 97 83 JSR P397 ;close file: .P467 ;Print newline 8467 48 PHA 8468 A9 0D LDA #&0D 846A 20 03 A4 JSR R403 ;print character in A (OSASCI) 846D 68 PLA 846E 60 RTS .P46F ;Select source volume 846F 20 00 A3 JSR R300 ;save AXY 8472 AE D3 10 LDX &10D3 ;set X = source volume 8475 A9 00 LDA #&00 ;a=&00 = we want source disc 8477 F0 08 BEQ P481 ;branch (always) .P479 ;Select destination volume 8479 20 00 A3 JSR R300 ;save AXY 847C AE D4 10 LDX &10D4 ;set X = destination volume 847F A9 80 LDA #&80 ;a=&80 = we want destination disc .P481 8481 48 PHA ;save A 8482 86 CF STX &CF ;set wanted volume as current volume 8484 20 D6 A7 JSR R7D6 ;set up for current drive 8487 68 PLA ;restore A 8488 24 A9 BIT &A9 ;if disc swapping required 848A 30 01 BMI P48D ;then branch to prompt .P48C 848C 60 RTS ;else exit .P48D 848D C5 AA CMP &AA ;compare wanted disc with disc in drive 848F F0 FB BEQ P48C ;if the same then do not prompt 8491 85 AA STA &AA ;else wanted disc is going into drive 8493 20 94 A3 JSR R394 ;print "Insert " 8496 EQUS "Insert " 849D EA NOP 849E 24 AA BIT &AA ;if b7=1 84A0 30 0B BMI P4AD ;then print "destination" 84A2 20 94 A3 JSR R394 ;else print "source" 84A5 EQUS "source" 84AB 90 0F BCC P4BC ;and branch (always) .P4AD 84AD 20 94 A3 JSR R394 ;print " destination" 84B0 EQUS "destination" 84BB EA NOP .P4BC 84BC 20 94 A3 JSR R394 ;print " disk and hit a key" 84BF EQUS " disk and hit a key" 84D2 EA NOP 84D3 20 EA 84 JSR P4EA ;poll for ESCAPE (OSRDCH) 84D6 4C 67 84 JMP P467 ;print newline and exit .P4D9 ;Ask user yes or no 84D9 20 EA 84 JSR P4EA ;wait for keypress 84DC 29 5F AND #&5F ;convert to uppercase 84DE C9 59 CMP #&59 ;is it "Y"? 84E0 08 PHP ;save the answer 84E1 F0 02 BEQ P4E5 ;if so then print "Y" 84E3 A9 4E LDA #&4E ;else print "N" .P4E5 84E5 20 03 A4 JSR R403 ;print character in A (OSASCI) 84E8 28 PLP ;return Z=1 if "Y" or "y" pressed 84E9 60 RTS .P4EA ;Poll for ESCAPE (OSRDCH) 84EA 20 EE A7 JSR R7EE ;call *FX 15,1 = clear input buffer 84ED 20 E0 FF JSR &FFE0 ;call OSRDCH, wait for input character 84F0 90 03 BCC P4F5 ;if ESCAPE was pressed .P4F2 84F2 A6 B8 LDX &B8 ;then abort our routine 84F4 9A TXS ;clear our stacked items, return to caller .P4F5 84F5 60 RTS .P4F6 ;Restore parameters of source drive 84F6 A0 05 LDY #&05 ;use slot of invalid channel &16 84F8 D0 02 BNE P4FC ;restore drive parameters of open file .P4FA ;Restore parameters of destination drive 84FA A0 06 LDY #&06 ;use slot of invalid channel &17: .P4FC ;Restore drive parameters of open file 84FC 20 2C 85 JSR P52C ;multiply Y by 6 84FF A2 00 LDX #&00 .P501 8501 B9 E6 10 LDA &10E6,Y ;copy from parameter set &10E6..B,Y 8504 9D E0 10 STA &10E0,X ;to current drive parameters &10E0..5 8507 C8 INY 8508 E8 INX 8509 E0 06 CPX #&06 ;loop until 6 bytes copied 850B D0 F4 BNE P501 850D 60 RTS .P50E ;Save parameters of source drive 850E 20 00 A3 JSR R300 ;save AXY 8511 A0 05 LDY #&05 ;use slot of invalid channel &16 8513 D0 05 BNE P51A ;save drive parameters of open file .P515 ;Save parameters of destination drive 8515 20 00 A3 JSR R300 ;save AXY 8518 A0 06 LDY #&06 ;use slot of invalid channel &17: .P51A ;Save drive parameters of open file 851A 20 2C 85 JSR P52C ;multiply Y by 6 851D A2 00 LDX #&00 .P51F 851F BD E0 10 LDA &10E0,X ;copy from current drive parameters &10E0..5 8522 99 E6 10 STA &10E6,Y ;to parameter set &10E6..B,Y 8525 C8 INY 8526 E8 INX 8527 E0 06 CPX #&06 ;loop until 6 bytes copied 8529 D0 F4 BNE P51F 852B 60 RTS .P52C ;Multiply Y by 6 852C A5 A8 LDA &A8 ;save content of &A8 852E 48 PHA 852F 98 TYA ;a=y 8530 85 A8 STA &A8 ;save in temp 8532 0A ASL A ;multiply A by two 8533 65 A8 ADC &A8 ;add starting value making 3x 8535 0A ASL A ;double the result making 6x 8536 A8 TAY ;put back in Y 8537 68 PLA ;restore content of &A8 8538 85 A8 STA &A8 853A 60 RTS ;*BACKUP 853B 20 3A A2 JSR R23A ;ensure *ENABLE active 853E 20 4F A2 JSR R24F ;parse and print source and dest. volumes 8541 A9 00 LDA #&00 8543 85 A8 STA &A8 ;no catalogue entry waiting to be created 8545 85 C8 STA &C8 ;set source volume LBA = 0 8547 85 C9 STA &C9 8549 85 CA STA &CA ;set destination volume LBA = 0 854B 85 CB STA &CB 854D 20 38 86 JSR P638 ;load source volume catalogue 8550 A9 00 LDA #&00 8552 8D E2 10 STA &10E2 ;data area starts on track 0 8555 20 0E 85 JSR P50E ;save parameters of source drive 8558 20 19 86 JSR P619 ;return volume size in XY/boot option in A 855B 8D D7 10 STA &10D7 ;save source volume boot option 855E 86 C6 STX &C6 8560 84 C7 STY &C7 8562 20 32 86 JSR P632 ;load destination volume catalogue 8565 A9 00 LDA #&00 8567 8D E2 10 STA &10E2 ;data area starts on track 0 856A 20 15 85 JSR P515 ;save parameters of destination drive 856D AD 07 11 LDA &1107 ;get density of source drive 8570 4D 0D 11 EOR &110D ;xor with density flag of destination drive 8573 29 40 AND #&40 ;extract bit 6 density flag, ignore auto b7 8575 F0 3A BEQ P5B1 ;if the same density then skip 8577 A9 D5 LDA #&D5 ;else error number = &D5 8579 20 EF A3 JSR R3EF ;begin error message, number in A 857C 20 8A A3 JSR R38A ;print error message 857F EQUS "Both disks MUST be same density" 859E EQUB &0D 859F EQUB &0A 85A0 EQUS "Hint...use MCOPY" 85B0 EQUB &00 ;terminator byte &00 raises error .P5B1 85B1 20 19 86 JSR P619 ;return volume size in XY/boot option in A 85B4 8A TXA ;save destination volume size on stack 85B5 48 PHA 85B6 98 TYA 85B7 48 PHA 85B8 C5 C7 CMP &C7 ;compare MSBs dest volume size - source 85BA 90 07 BCC P5C3 ;if dest < source then raise error 85BC D0 29 BNE P5E7 ;if dest > source then proceed 85BE 8A TXA ;else compare LSBs dest - source 85BF C5 C6 CMP &C6 85C1 B0 24 BCS P5E7 ;if dest >= source then proceed .P5C3 85C3 A9 D5 LDA #&D5 ;else error number = &D5 85C5 20 EF A3 JSR R3EF ;begin error message, number in A 85C8 AD D3 10 LDA &10D3 ;get source drive 85CB 20 08 8D JSR PD08 ;print " Drive " plus volume spec in A 85CE 20 94 A3 JSR R394 ;print " larger than " 85D1 EQUS " larger than " 85DE AD D4 10 LDA &10D4 ;get destination drive 85E1 20 08 8D JSR PD08 ;print " Drive " plus volume spec in A 85E4 4C B9 A3 JMP R3B9 ;terminate error message, raise error .P5E7 85E7 20 51 87 JSR P751 ;copy source drive/file to destination 85EA 2C E3 10 BIT &10E3 ;test density flag 85ED 70 19 BVS P608 ;if double density then update disc catalogue 85EF 20 79 84 JSR P479 ;else select destination volume 85F2 20 A1 92 JSR Q2A1 ;load volume catalogue 85F5 68 PLA ;pop MSB destination volume size 85F6 29 0F AND #&0F ;mask bits 0..3 85F8 0D D7 10 ORA &10D7 ;apply source boot option in bits 4..5 85FB 8D 06 0F STA &0F06 ;store in catalogue 85FE 68 PLA ;pop LSB destination volume size 85FF 8D 07 0F STA &0F07 ;store in catalogue 8602 20 81 92 JSR Q281 ;write volume catalogue 8605 4C BA 86 JMP P6BA ;and do a NEW for BASIC ;[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. .P608 ;Update disc catalogue 8608 20 D9 A6 JSR R6D9 ;load disc catalogue L3 860B 68 PLA ;pop MSB disc size 860C 8D 01 0E STA &0E01 ;store in disc catalogue 860F 68 PLA ;pop LSB disc size 8610 8D 02 0E STA &0E02 ;store in disc catalogue 8613 20 DD A6 JSR R6DD ;write disc catalogue L3 8616 4C BA 86 JMP P6BA ;and do a NEW for BASIC .P619 ;Return volume size in XY/boot option in A 8619 AE 07 0F LDX &0F07 ;get LSB volume size from catalogue 861C AD 06 0F LDA &0F06 ;get boot option/top bits volume size 861F 48 PHA 8620 29 03 AND #&03 ;extract MSB volume size 8622 A8 TAY ;put volume size in XY 8623 2C E3 10 BIT &10E3 ;test density flag 8626 50 06 BVC P62E ;if double density 8628 AE 0F 10 LDX &100F ;then load disc size from workspace instead 862B AC 0E 10 LDY &100E .P62E 862E 68 PLA ;return disc size in XY 862F 29 F0 AND #&F0 ;return boot option in A bits 5 and 4 8631 60 RTS .P632 ;Load destination volume catalogue 8632 20 79 84 JSR P479 ;select destination volume 8635 4C A1 92 JMP Q2A1 ;load volume catalogue L4 .P638 ;Load source volume catalogue 8638 20 6F 84 JSR P46F ;select source volume 863B 4C A1 92 JMP Q2A1 ;load volume catalogue L4 ;*COPY 863E 20 2B 89 JSR P92B ;allow wildcard characters in filename 8641 20 4F A2 JSR R24F ;parse and print source and dest. volumes 8644 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg 8647 20 E5 87 JSR P7E5 ;set current file from file spec 864A 20 6F 84 JSR P46F ;select source volume 864D 20 3E 89 JSR P93E ;ensure matching file in catalogue 8650 20 0E 85 JSR P50E ;save parameters of source drive .P653 8653 84 AB STY &AB ;save cat. offset of found file in zero page 8655 20 C0 89 JSR P9C0 ;print *INFO line 8658 A2 00 LDX #&00 .P65A 865A B5 C7 LDA &C7,X ;save file spec in workspace 865C 9D 58 10 STA &1058,X 865F B9 08 0E LDA &0E08,Y ;copy matching filename+dir to current file 8662 95 C7 STA &C7,X 8664 9D 50 10 STA &1050,X ;and to workspace 8667 B9 08 0F LDA &0F08,Y ;copy matching file's catalogue information 866A 95 BD STA &BD,X ;to OSFILE block? 866C 9D 47 10 STA &1047,X ;and to workspace 866F E8 INX 8670 C8 INY 8671 E0 08 CPX #&08 ;loop until 8 bytes of each field copied 8673 D0 E5 BNE P65A 8675 A5 C3 LDA &C3 ;get top bits exec/length/load/start sector 8677 20 5F A4 JSR R45F ;extract b5,b4 of A 867A 85 C5 STA &C5 ;set MSB length 867C A5 C1 LDA &C1 ;get LSB length 867E 18 CLC 867F 69 FF ADC #&FF ;set C=1 iff file includes partial sector 8681 A5 C2 LDA &C2 ;get 2MSB length 8683 69 00 ADC #&00 ;round up to get LSB length in sectors 8685 85 C6 STA &C6 8687 A5 C5 LDA &C5 ;get extracted MSB length 8689 69 00 ADC #&00 ;carry out to get MSB length in sectors 868B 85 C7 STA &C7 868D AD 4E 10 LDA &104E ;get LSB start LBA (also at &C4) 8690 85 C8 STA &C8 8692 AD 4D 10 LDA &104D ;get top bits exec/length/load/start sector 8695 29 03 AND #&03 ;extract b1,b0 of A 8697 85 C9 STA &C9 ;store MSB start LBA 8699 A9 FF LDA #&FF 869B 85 A8 STA &A8 ;catalogue entry is waiting to be created 869D 20 51 87 JSR P751 ;copy source drive/file to destination 86A0 20 6F 84 JSR P46F ;select source volume 86A3 20 9E 92 JSR Q29E ;load volume catalogue L4 86A6 A2 07 LDX #&07 .P6A8 86A8 BD 58 10 LDA &1058,X ;restore file spec to current file 86AB 95 C7 STA &C7,X 86AD CA DEX 86AE 10 F8 BPL P6A8 ;loop until 8 characters copied 86B0 A4 AB LDY &AB ;restore cat. offset of found file 86B2 8C CF 10 STY &10CF ;to workspace 86B5 20 6A 89 JSR P96A ;find next matching file 86B8 B0 99 BCS P653 ;loop while match found, else: .P6BA ;Store empty BASIC program at OSHWM (NEW) 86BA AD 89 10 LDA &1089 ;get start of user memory 86BD 85 BF STA &BF ;store as high byte of pointer #if defined _BUGFIX 86BF A0 00 LDY #&00 ;clear low byte 86C1 84 BE STY &BE ;PAGE is always on a page boundary #else 86BF A9 00 LDA #&00 ;clear low byte 86C1 85 BE STA &BE ;PAGE is always on a page boundary ;[BUG] Y uninitialised, store to wrong place #endif 86C3 A9 0D LDA #&0D ;&0D = first byte of end-of-program marker 86C5 91 BE STA (&BE),Y ;store at start of user memory 86C7 C8 INY ;&FF = second byte of end-of-program marker 86C8 A9 FF LDA #&FF ;store in user memory 86CA 91 BE STA (&BE),Y 86CC 60 RTS .P6CD ;Create destination catalogue entry 86CD 20 09 87 JSR P709 ;swap &BC..CD with &1045..56 86D0 20 79 84 JSR P479 ;select destination volume 86D3 A5 CE LDA &CE ;save current directory 86D5 48 PHA 86D6 20 9E 92 JSR Q29E ;load volume catalogue L4 86D9 20 63 89 JSR P963 ;search for file in catalogue 86DC 90 03 BCC P6E1 ;if found 86DE 20 9E 89 JSR P99E ;then delete catalogue entry .P6E1 86E1 68 PLA ;restore current directory 86E2 85 CE STA &CE ;set as current directory 86E4 20 15 85 JSR P515 ;save parameters of destination drive 86E7 20 19 92 JSR Q219 ;expand 18-bit load address to 32-bit 86EA 20 35 92 JSR Q235 ;expand 18-bit exec address to 32-bit 86ED A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 86EF 20 5F A4 JSR R45F ;extract b5,b4 of A 86F2 85 C6 STA &C6 ;store MSB length 86F4 20 2C 91 JSR Q12C ;create catalogue entry 86F7 A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 86F9 29 03 AND #&03 ;extract b1,b0 of A 86FB 48 PHA ;save MSB start sector 86FC A5 C5 LDA &C5 ;get LSB start sector 86FE 48 PHA ;save LSB start sector 86FF 20 09 87 JSR P709 ;swap &BC..CD with &1045..56 8702 68 PLA 8703 85 CA STA &CA ;store LSB start sector 8705 68 PLA 8706 85 CB STA &CB ;store MSB start sector 8708 60 RTS .P709 ;Swap &BC..CD with &1045..56 8709 A2 11 LDX #&11 .P70B #if defined _DDOS357 870B BC 45 10 LDY &1045,X 870E B5 BC LDA &BC,X 8710 94 BC STY &BC,X 8712 9D 45 10 STA &1045,X 8715 CA DEX 8716 10 F3 BPL P70B 8718 60 RTS ;Filing system info table, in reverse 8719 EQUB &04 ;filing system number 871A EQUB &15 ;highest file handle 871B EQUB &11 ;lowest file handle 871C EQUS " CSID" ;filing system name 8724 EQUB &04 ;filing system number 8725 EQUB &15 ;highest file handle 8726 EQUB &11 ;lowest file handle 8727 EQUS " KSID" ;filing system name .P72F 872F C9 09 CMP #&09 8731 D0 1B BNE P74E 8733 20 00 A3 JSR R300 ;FSC 9 = *EX. save AXY 8736 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 8739 20 BB A4 JSR R4BB ;call GSINIT with C=0 873C 20 2B 89 JSR P92B ;allow wildcard characters in filename 873F 20 68 88 JSR P868 ;a=&23; set current filename = "#######" 8742 20 F0 A4 JSR R4F0 ;set current volume and dir = default 8745 20 1B A5 JSR R51B ;parse directory spec (Y presv'd from GSINIT) 8748 20 3E 89 JSR P93E ;ensure matching file in catalogue 874B 4C 5A 89 JMP P95A ;print *INFO lines for all matching files .P74E 874E 4C CE 94 JMP Q4CE ;serve other FSC calls #else /* _DDOS357 */ 870B BD 45 10 LDA &1045,X 870E B4 BC LDY &BC,X 8710 95 BC STA &BC,X 8712 98 TYA 8713 9D 45 10 STA &1045,X 8716 CA DEX 8717 10 F2 BPL P70B 8719 60 RTS ;unreachable code 871A 20 6F 84 JSR P46F ;select source volume 871D 20 A1 92 JSR Q2A1 ;load volume catalogue 8720 20 0E 85 JSR P50E ;save parameters of source drive 8723 AD 07 0F LDA &0F07 ;get LSB volume size 8726 85 C6 STA &C6 ;store in zero page 8728 AD 06 0F LDA &0F06 ;get boot option/top bits volume size 872B 29 03 AND #&03 ;extract MSB volume size 872D 85 C7 STA &C7 ;store in zero page 872F AD 06 0F LDA &0F06 ;get boot option/top bits volume size 8732 29 F0 AND #&F0 ;extract boot option to b7..4 8734 8D D7 10 STA &10D7 ;store in workspace 8737 20 79 84 JSR P479 ;select destination volume 873A 20 A1 92 JSR Q2A1 ;load volume catalogue 873D 4C 15 85 JMP P515 ;save parameters of destination drive ;unreachable code ;compare new volume size - old volume size 8740 AD 06 0F LDA &0F06 ;get boot option/top bits volume size 8743 29 03 AND #&03 ;extract MSB volume size 8745 C5 C7 CMP &C7 ;compare with stored MSB volume size 8747 90 07 BCC P750 ;return C=0, Z=0 if new size < old size 8749 D0 05 BNE P750 ;return C=1, Z=0 if new size > old size 874B AD 07 0F LDA &0F07 ;if MSBs equal, load LSB old size 874E C5 C6 CMP &C6 ;return C=1, Z=1 if sizes equal, or as above .P750 8750 60 RTS #endif /* _DDOS357 */ .P751 ;Copy source drive/file to destination 8751 A9 00 LDA #&00 8753 85 BE STA &BE ;set LSB load address = 0 8755 85 C2 STA &C2 ;set LSB transfer size = 0 .P757 8757 A5 C6 LDA &C6 ;compare remaining file size 8759 A8 TAY ;- available memory 875A CD 8B 10 CMP &108B 875D A5 C7 LDA &C7 875F E9 00 SBC #&00 8761 90 03 BCC P766 ;if remainder fits then Y=file size in pages 8763 AC 8B 10 LDY &108B ;else Y=size of available memory in pages .P766 8766 84 C3 STY &C3 ;set MSB transfer size = no. pages in Y 8768 A5 C8 LDA &C8 ;set LBA = source volume LBA 876A 85 C5 STA &C5 876C A5 C9 LDA &C9 876E 85 C4 STA &C4 8770 AD 89 10 LDA &1089 ;set MSB load address = start of user memory 8773 85 BF STA &BF 8775 20 F6 84 JSR P4F6 ;restore parameters of source drive 8778 20 6F 84 JSR P46F ;select source volume 877B 20 28 92 JSR Q228 ;set high word of OSFILE load address = &FFFF 877E 20 1D 90 JSR Q01D ;read extended file L5 8781 24 A8 BIT &A8 ;if catalogue entry is waiting to be created 8783 10 07 BPL P78C 8785 20 CD 86 JSR P6CD ;then create destination catalogue entry 8788 A9 00 LDA #&00 878A 85 A8 STA &A8 ;no catalogue entry waiting to be created .P78C 878C A5 CA LDA &CA ;set LBA = destination volume LBA 878E 85 C5 STA &C5 8790 A5 CB LDA &CB 8792 85 C4 STA &C4 8794 AD 89 10 LDA &1089 ;set MSB save address = start of user memory 8797 85 BF STA &BF 8799 20 FA 84 JSR P4FA ;restore parameters of destination drive 879C 20 79 84 JSR P479 ;select destination volume 879F 20 28 92 JSR Q228 ;set high word of OSFILE load address = &FFFF 87A2 20 23 90 JSR Q023 ;write extended file L5 87A5 A5 C3 LDA &C3 ;add transfer size to destination volume LBA 87A7 18 CLC 87A8 65 CA ADC &CA 87AA 85 CA STA &CA 87AC 90 02 BCC P7B0 ;carry out to high byte 87AE E6 CB INC &CB .P7B0 87B0 A5 C3 LDA &C3 ;add transfer size to source volume LBA 87B2 18 CLC 87B3 65 C8 ADC &C8 87B5 85 C8 STA &C8 87B7 90 02 BCC P7BB ;carry out to high byte 87B9 E6 C9 INC &C9 .P7BB 87BB 38 SEC 87BC A5 C6 LDA &C6 ;get LSB remaining size of file in sectors 87BE E5 C3 SBC &C3 ;subtract number of pages transferred 87C0 85 C6 STA &C6 ;update LSB remaining size 87C2 B0 02 BCS P7C6 87C4 C6 C7 DEC &C7 ;borrow in from MSB remaining size if req'd .P7C6 87C6 05 C7 ORA &C7 ;or MSB with LSB, Z=0 if pages remain 87C8 D0 8D BNE P757 ;if file transfer is incomplete then loop 87CA 60 RTS .P7CB ;Copy address to (&BC,D,&106D,E)+X 87CB 20 DB 87 JSR P7DB ;copy low word to zero page 87CE CA DEX ;backtrack destination offset 87CF CA DEX 87D0 20 D3 87 JSR P7D3 ;copy high word to workspace: .P7D3 ;copy byte of high word to workspace 87D3 B1 B0 LDA (&B0),Y 87D5 9D 6D 10 STA &106D,X 87D8 E8 INX ;increment source and destination offsets 87D9 C8 INY 87DA 60 RTS .P7DB ;copy low word to zero page: 87DB 20 DE 87 JSR P7DE .P7DE ;copy byte of low word to zero page 87DE B1 B0 LDA (&B0),Y 87E0 95 BC STA &BC,X 87E2 E8 INX ;increment source and destination offsets 87E3 C8 INY 87E4 60 RTS .P7E5 ;Set current file from file spec 87E5 20 F0 A4 JSR R4F0 ;set current volume and dir = default 87E8 4C FB 87 JMP P7FB ;parse file spec .P7EB ;Set current file from argument pointer 87EB 20 F0 A4 JSR R4F0 ;set current volume and dir = default: .P7EE ;Parse file spec from argument pointer 87EE A5 BC LDA &BC ;copy argument pointer to GSINIT pointer 87F0 85 F2 STA &F2 87F2 A5 BD LDA &BD 87F4 85 F3 STA &F3 87F6 A0 00 LDY #&00 ;set Y = 0 offset for GSINIT 87F8 20 BB A4 JSR R4BB ;call GSINIT with C=0: .P7FB ;Parse file spec 87FB 20 66 88 JSR P866 ;set current filename to all spaces 87FE 20 C5 FF JSR &FFC5 ;call GSREAD 8801 B0 53 BCS P856 ;if argument empty then "Bad filename" 8803 C9 3A CMP #&3A ;else is first character ":"? 8805 D0 22 BNE P829 ;if not then skip to dir/filename 8807 20 C5 FF JSR &FFC5 ;else a drive is specified, call GSREAD 880A B0 57 BCS P863 ;if no drive number then "Bad drive" 880C 20 BF A4 JSR R4BF ;else set current drive from ASCII digit 880F 20 C5 FF JSR &FFC5 ;call GSREAD 8812 B0 42 BCS P856 ;if only drive specified then "Bad filename" 8814 C9 2E CMP #&2E ;else if next character is "." 8816 F0 0C BEQ P824 ;then get first character of filename 8818 20 CB A4 JSR R4CB ;else set volume from ASCII letter 881B 20 C5 FF JSR &FFC5 ;call GSREAD 881E B0 36 BCS P856 ;if only volume spec'd then "Bad filename" 8820 C9 2E CMP #&2E ;if separator character "." missing 8822 D0 32 BNE P856 ;then raise "Bad filename" error .P824 8824 20 C5 FF JSR &FFC5 ;call GSREAD, get first character of filename 8827 B0 2D BCS P856 ;if filename is empty then "Bad filename" .P829 8829 85 C7 STA &C7 ;else save first character of filename 882B A2 00 LDX #&00 ;set filename offset = 0 882D 20 C5 FF JSR &FFC5 ;call GSREAD, get second filename character #if defined _BUGFIX 8830 B0 3A BCS P86C ;if absent then process one-character name #else 8830 B0 44 BCS P876 ;if absent then process one-character name #endif 8832 E8 INX ;else offset = 1 8833 C9 2E CMP #&2E ;is the second character "."? 8835 D0 0B BNE P842 ;if not then read in rest of leaf name 8837 A5 C7 LDA &C7 ;else first character was a directory spec 8839 20 80 A5 JSR R580 ;set directory from ASCII character 883C 20 C5 FF JSR &FFC5 ;call GSREAD, get first character of leaf name 883F B0 15 BCS P856 ;if leaf name is empty then "Bad filename" 8841 CA DEX ;else offset = 0, read in leaf name: .P842 8842 C9 2A CMP #&2A ;is filename character "*"? 8844 F0 36 BEQ P87C ;if so then process "*" in filename 8846 C9 21 CMP #&21 ;else is it a control character or space? 8848 90 0C BCC P856 ;if so then raise "Bad filename" error 884A 95 C7 STA &C7,X ;else store character of filename 884C E8 INX ;point X to next character of current filename 884D 20 C5 FF JSR &FFC5 ;call GSREAD, get next character of leaf name #if defined _BUGFIX 8850 B0 29 BCS P87B ;if no more then filename complete, return #else 8850 B0 23 BCS P875 ;if no more then filename complete, return #endif 8852 E0 07 CPX #&07 ;else have seven characters been read already? 8854 D0 EC BNE P842 ;if not then loop, else: .P856 ;Raise "Bad filename" error. 8856 20 51 A3 JSR R351 8859 EQUB &CC 885A EQUS "filename" 8862 EQUB &00 .P863 8863 4C 11 A5 JMP R511 ;raise "Bad drive" error. #if defined _DDOS357 .P866 ;Set current filename to all spaces 8866 A9 20 LDA #&20 .P868 8868 A2 00 LDX #&00 # if defined _BUGFIX 886A F0 08 BEQ P874 ;branch (always) # else 886A F0 02 BEQ P86E ;branch (always) # endif #else /* _DDOS357 */ .P866 ;Set current filename to all spaces 8866 A2 00 LDX #&00 8868 A9 20 LDA #&20 # if defined _BUGFIX 886A D0 08 BNE P874 ;branch (always) # else 886A D0 02 BNE P86E ;branch (always) # endif #endif /* _DDOS357 */ #if defined _BUGFIX .P86C ;Process one-character filename 886C A5 C7 LDA &C7 ;if filename is "*", then: 886E C9 2A CMP #&2A 8870 D0 09 BNE P87B .P872 ;Pad current filename with "#"s 8872 A9 23 LDA #&23 ;x=offset of end of filename .P874 8874 95 C7 STA &C7,X 8876 E8 INX 8877 E0 07 CPX #&07 8879 D0 F9 BNE P874 .P87B 887B 60 RTS .P87C ;Process "*" in filename 887C 20 C5 FF JSR &FFC5 ;call GSREAD 887F B0 F1 BCS P872 ;if end of argument pad filename with "#"s 8881 C9 20 CMP #&20 ;else if next character is space 8883 F0 ED BEQ P872 ;then pad filename with "#"s 8885 D0 CF BNE P856 ;else raise "Bad filename" error. #else /* _BUGFIX */ .P86C ;Pad current filename with "#"s 886C A9 23 LDA #&23 ;x=offset of end of filename .P86E 886E 95 C7 STA &C7,X 8870 E8 INX 8871 E0 07 CPX #&07 8873 D0 F9 BNE P86E .P875 8875 60 RTS .P876 ;Process one-character filename 8876 A5 C7 LDA &C7 ;if filename is "*", then: 8878 C9 2A CMP #&2A ;([BUG] don't call GSREAD twice on end-of-str 887A D0 F9 BNE P875 ;e.g. *INFO"*" results in "Bad string" error) .P87C ;Process "*" in filename 887C 20 C5 FF JSR &FFC5 ;call GSREAD 887F B0 EB BCS P86C ;if end of argument pad filename with "#"s 8881 C9 20 CMP #&20 ;else if next character is space 8883 F0 E7 BEQ P86C ;then pad filename with "#"s 8885 D0 CF BNE P856 ;else raise "Bad filename" error. #endif /* _BUGFIX */ .P887 ;Ensure disc not changed 8887 20 00 A3 JSR R300 ;save AXY 888A AD 04 0F LDA &0F04 ;get cycle number of last catalogue read 888D 20 9E 92 JSR Q29E ;load volume catalogue L4 8890 CD 04 0F CMP &0F04 ;compare with freshly loaded cycle number #if defined _BUGFIX 8893 F0 E6 BEQ P87B ;return if equal, else: #else 8893 F0 E0 BEQ P875 ;return if equal, else: #endif .P895 ;Raise "Disk changed" error. 8895 20 62 A3 JSR R362 8898 EQUB &C8 8899 EQUS "Disk changed" 88A5 EQUB &00 .P8A6 ;Print filename from catalogue 88A6 20 00 A3 JSR R300 ;save AXY 88A9 B9 0F 0E LDA &0E0F,Y ;get directory character 88AC 08 PHP ;save N = lock attribute 88AD 29 7F AND #&7F ;extract ASCII character 88AF D0 05 BNE P8B6 ;if NUL then file is in CSD 88B1 20 C9 A2 JSR R2C9 ;so print two spaces 88B4 F0 06 BEQ P8BC ;branch (always) .P8B6 88B6 20 03 A4 JSR R403 ;else print directory character 88B9 20 01 A4 JSR R401 ;print a dot .P8BC 88BC A2 06 LDX #&06 ;repeat 7 times: .P8BE 88BE B9 08 0E LDA &0E08,Y ;get character of leaf name 88C1 29 7F AND #&7F ;mask bit 7 88C3 20 03 A4 JSR R403 ;print character 88C6 C8 INY 88C7 CA DEX 88C8 10 F4 BPL P8BE ;and loop 88CA 20 C9 A2 JSR R2C9 ;print two spaces 88CD A9 20 LDA #&20 ;a = space 88CF 28 PLP ;restore lock attribute in N 88D0 10 02 BPL P8D4 ;if lock bit set 88D2 A9 4C LDA #&4C ;then A = capital L .P8D4 88D4 20 03 A4 JSR R403 ;print attribute character 88D7 4C CC A2 JMP R2CC ;print a space and exit .P8DA ;Print number of spaces in Y 88DA 20 CC A2 JSR R2CC ;print a space 88DD 88 DEY ;loop until Y = 0 88DE D0 FA BNE P8DA 88E0 60 RTS .P8E1 ;Prepare extended file transfer 88E1 A9 00 LDA #&00 ;set MSB length = 0; transfer less than 64 KiB 88E3 85 A5 STA &A5 88E5 A6 C4 LDX &C4 ;x = LSB of relative LBA 88E7 4C F6 88 JMP P8F6 .P8EA ;Prepare ordinary file transfer 88EA A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 88EC 20 5F A4 JSR R45F ;extract b5,b4 of A 88EF 85 A5 STA &A5 ;?&A5 = b17..16 (MSB) of length 88F1 A5 C4 LDA &C4 ;x = b9..8 (MSB) of relative LBA 88F3 29 03 AND #&03 88F5 AA TAX .P8F6 88F6 A5 BE LDA &BE ;copy user data address to NMI area 88F8 85 A6 STA &A6 88FA A5 BF LDA &BF 88FC 85 A7 STA &A7 88FE A5 C3 LDA &C3 ;copy 2MSB length 8900 85 A4 STA &A4 8902 A5 C2 LDA &C2 ;copy LSB length 8904 85 A3 STA &A3 8906 86 BA STX &BA ;store LSB/MSB of LBA (clobbered if LSB) 8908 A5 C5 LDA &C5 ;copy MSB/LSB of LBA 890A 85 BB STA &BB 890C AD E1 10 LDA &10E1 ;get number of sectors per track 890F F0 19 BEQ P92A ;if not defined then just use the LBA 8911 AD E2 10 LDA &10E2 ;else get first track of current volume 8914 85 BA STA &BA ;set track number for transfer 8916 C6 BA DEC &BA ;decrement, to increment at start of loop 8918 A5 C5 LDA &C5 ;get LSB of relative LBA: .P91A 891A 38 SEC ;set C=1 to subtract without borrow: .P91B 891B E6 BA INC &BA ;increment track number 891D ED E1 10 SBC &10E1 ;subtract sectors-per-track from LBA 8920 B0 F9 BCS P91B ;loop until LSB borrows in 8922 CA DEX ;then decrement MSB of relative LBA 8923 10 F5 BPL P91A ;loop until MSB borrows in/underflows 8925 6D E1 10 ADC &10E1 ;add sectors per track to negative remainder 8928 85 BB STA &BB ;set sector number. .P92A 892A 60 RTS .P92B ;Allow wildcard characters in filename 892B A9 23 LDA #&23 892D D0 02 BNE P931 .P92F ;Disallow wildcard characters in filename 892F A9 FF LDA #&FF .P931 8931 8D D0 10 STA &10D0 8934 60 RTS .P935 ;Ensure file matching spec in catalogue 8935 20 E5 87 JSR P7E5 ;set current file from file spec 8938 4C 3E 89 JMP P93E ;ensure matching file in catalogue .P93B ;Ensure file matching argument in catalogue 893B 20 EB 87 JSR P7EB ;set current file from argument pointer: .P93E ;Ensure matching file in catalogue 893E 20 63 89 JSR P963 ;search for file in catalogue 8941 B0 E7 BCS P92A ;if found then return .P943 8943 20 5A A3 JSR R35A ;else raise "File not found" error. 8946 EQUB &D6 8947 EQUS "not found" 8950 EQUB &00 #if defined _DDOS357 .P951 #endif ;*INFO 8951 20 2B 89 JSR P92B ;allow wildcard characters in filename 8954 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg 8957 20 35 89 JSR P935 ;ensure file matching spec in catalogue .P95A 895A 20 C0 89 JSR P9C0 ;print *INFO line 895D 20 6A 89 JSR P96A ;find next matching file 8960 B0 F8 BCS P95A ;loop until no more files match. 8962 60 RTS .P963 ;Search for file in catalogue 8963 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 8966 A0 F8 LDY #&F8 ;y=&F8, start beyond first catalogue entry 8968 D0 03 BNE P96D ;and jump into search loop (always) .P96A ;Find next matching file 896A AC CF 10 LDY &10CF ;set Y = catalogue pointer .P96D 896D 20 72 A4 JSR R472 ;add 8 to Y 8970 CC 05 0F CPY &0F05 ;have we reached the end of the catalogue? 8973 B0 44 BCS P9B9 ;if so return C=0 file not found 8975 20 72 A4 JSR R472 ;else add 8 to Y 8978 A2 07 LDX #&07 ;x=7 point to directory character: .P97A 897A B5 C7 LDA &C7,X ;get character of current filename 897C CD D0 10 CMP &10D0 ;compare with wildcard mask 897F F0 0E BEQ P98F ;if ='#' and wildcards allowed accept char 8981 20 9A A4 JSR R49A ;else set C=0 iff character in A is a letter 8984 59 07 0E EOR &0E07,Y ;compare with character in catalogue 8987 B0 02 BCS P98B ;if character in current filename is letter 8989 29 DF AND #&DF ;then ignore case .P98B 898B 29 7F AND #&7F ;ignore bit 7, Z=1 if characters equal 898D D0 09 BNE P998 ;if not equal then test next file .P98F 898F 88 DEY ;loop to test next (previous) char of name 8990 CA DEX 8991 10 E7 BPL P97A ;if no more chars to test then files match 8993 8C CF 10 STY &10CF ;save cat. offset of found file in workspace 8996 38 SEC ;return C=1 file found 8997 60 RTS .P998 ;catalogue entry does not match file spec 8998 88 DEY ;advance catalogue pointer to next file 8999 CA DEX 899A 10 FC BPL P998 899C 30 CF BMI P96D ;loop until file found or not .P99E ;Delete catalogue entry 899E 20 F8 9B JSR QBF8 ;ensure file not locked or open (mutex) .P9A1 89A1 B9 10 0E LDA &0E10,Y ;copy next file's entry over previous entry 89A4 99 08 0E STA &0E08,Y ;shifting entries up one place 89A7 B9 10 0F LDA &0F10,Y ;(copies title/boot/size if catalogue full) 89AA 99 08 0F STA &0F08,Y 89AD C8 INY ;loop until current file count reached 89AE CC 05 0F CPY &0F05 ;have we reached the end of the catalogue? 89B1 90 EE BCC P9A1 89B3 98 TYA ;copy Y to A = pointer to last file; C=1 89B4 E9 08 SBC #&08 ;subtract 8, catalogue contains one file less 89B6 8D 05 0F STA &0F05 ;store new file count .P9B9 89B9 18 CLC .P9BA 89BA 60 RTS .P9BB ;Print *INFO line if verbose 89BB 2C D1 10 BIT &10D1 ;test *OPT 1 setting 89BE 30 FA BMI P9BA ;if b7=1 then *OPT 1,0 do not print, else: .P9C0 ;Print *INFO line 89C0 20 00 A3 JSR R300 ;save AXY 89C3 20 A6 88 JSR P8A6 ;print filename from catalogue 89C6 98 TYA ;save catalogue pointer 89C7 48 PHA 89C8 A9 60 LDA #&60 ;set up pointer to OSFILE block in workspace 89CA 85 B0 STA &B0 ;at &1060 89CC A9 10 LDA #&10 89CE 85 B1 STA &B1 89D0 20 06 8A JSR PA06 ;return catalogue information to OSFILE block 89D3 A0 02 LDY #&02 ;y = &02 offset of load address in block 89D5 20 CC A2 JSR R2CC ;print a space 89D8 20 F4 89 JSR P9F4 ;print load address 89DB 20 F4 89 JSR P9F4 ;print execution address 89DE 20 F4 89 JSR P9F4 ;print file length 89E1 68 PLA ;restore catalogue pointer 89E2 A8 TAY 89E3 B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector 89E6 29 03 AND #&03 ;extract MSB start sector 89E8 20 31 A4 JSR R431 ;print hex nibble 89EB B9 0F 0F LDA &0F0F,Y ;get LSB start sector 89EE 20 29 A4 JSR R429 ;print hex byte 89F1 4C 67 84 JMP P467 ;print newline .P9F4 ;Print 24-bit field at &1060,Y 89F4 A2 03 LDX #&03 ;start at MSB, offset = 3: .P9F6 89F6 B9 62 10 LDA &1062,Y ;get byte at &1062,Y 89F9 20 29 A4 JSR R429 ;print hex byte 89FC 88 DEY ;increment offset 89FD CA DEX ;decrement counter 89FE D0 F6 BNE P9F6 ;loop until 3 bytes printed 8A00 20 73 A4 JSR R473 ;add 7 to Y to point to MSB of next field 8A03 4C CC A2 JMP R2CC ;print a space and exit .PA06 ;Return catalogue information to OSFILE block #if defined _DFSFIX 8A06 A9 01 LDA #&01 ;return A=&01 from OSFILE 7/11 8A08 20 00 A3 JSR R300 ;save AXY 8A0B 98 TYA ;save catalogue pointer on stack 8A0C 48 PHA 8A0D AA TAX ;and copy to X 8A0E A0 12 LDY #&12 ;clear bytes at offsets 2..17 8A10 A9 00 LDA #&00 .PA12 8A12 88 DEY 8A13 91 B0 STA (&B0),Y 8A15 C0 02 CPY #&02 ;end with Y = offset 2 = LSB load address 8A17 D0 F9 BNE PA12 #else /* _DFSFIX */ 8A06 20 00 A3 JSR R300 ;save AXY 8A09 98 TYA ;save catalogue pointer on stack 8A0A 48 PHA 8A0B AA TAX ;and copy to X 8A0C A0 02 LDY #&02 ;clear bytes at offsets 2..17 8A0E A9 00 LDA #&00 .PA10 8A10 91 B0 STA (&B0),Y 8A12 C8 INY 8A13 C0 12 CPY #&12 8A15 D0 F9 BNE PA10 8A17 A0 02 LDY #&02 ;offset 2 = LSB load address #endif /* _DFSFIX */ .PA19 8A19 20 55 8A JSR PA55 ;copy two bytes from catalogue to OSFILE block 8A1C C8 INY ;skip high bytes of OSFILE field 8A1D C8 INY 8A1E C0 0E CPY #&0E ;loop until 3 fields half-filled: 8A20 D0 F7 BNE PA19 ;load address, execution address, file length 8A22 68 PLA ;restore catalogue pointer 8A23 AA TAX 8A24 BD 0F 0E LDA &0E0F,X ;get directory character 8A27 10 06 BPL PA2F ;if b7=1 then file is locked 8A29 A9 0A LDA #&0A ;so set attributes to LR/RW (old style) 8A2B A0 0E LDY #&0E ;no delete, owner read only, public read/write ;note: Acorn DFS returns &08 instead 8A2D 91 B0 STA (&B0),Y ;store in OSFILE block .PA2F 8A2F BD 0E 0F LDA &0F0E,X ;get top bits exec/length/load/start sector 8A32 A0 04 LDY #&04 ;offset 4 = 2MSB load address 8A34 20 43 8A JSR PA43 ;expand bits 3,2 to top 16 bits of field 8A37 A0 0C LDY #&0C ;offset 12 = 2MSB file length 8A39 4A LSR A ;PA43 returned A = ..eelldd 8A3A 4A LSR A ;shift A right twice to make A = ....eell 8A3B 48 PHA ;save exec address 8A3C 29 03 AND #&03 ;extract bits 1,0 for length (don't expand) 8A3E 91 B0 STA (&B0),Y ;store in OSFILE block 8A40 68 PLA ;restore exec address in bits 3,2 8A41 A0 08 LDY #&08 ;offset 8 = 2MSB execution address: .PA43 8A43 4A LSR A ;shift A right 2 places 8A44 4A LSR A 8A45 48 PHA ;save shifted value for return 8A46 29 03 AND #&03 ;extract bits 3,2 of A on entry 8A48 C9 03 CMP #&03 ;if either one is clear 8A4A D0 05 BNE PA51 ;then save both as b1,0 of 2MSB 8A4C A9 FF LDA #&FF ;else set MSB and 2MSB = &FF. 8A4E 91 B0 STA (&B0),Y 8A50 C8 INY .PA51 8A51 91 B0 STA (&B0),Y 8A53 68 PLA ;discard byte on stack 8A54 60 RTS .PA55 ;Copy two bytes from catalogue to OSFILE block 8A55 20 58 8A JSR PA58 .PA58 8A58 BD 08 0F LDA &0F08,X 8A5B 91 B0 STA (&B0),Y 8A5D E8 INX 8A5E C8 INY 8A5F 60 RTS ;*STAT 8A60 A2 00 LDX #&00 ;x=0, nothing specified 8A62 20 E5 A4 JSR R4E5 ;select specified or default volume 8A65 8A TXA ;test bit 0 of X 8A66 29 01 AND #&01 ;if X=3 drive and volume specified 8A68 F0 03 BEQ PA6D 8A6A 4C A7 8A JMP PAA7 ;then stat specified volume, else: .PA6D ;*STAT eight volumes if double density 8A6D A5 CF LDA &CF ;get current volume 8A6F 29 0F AND #&0F ;extract drive number 8A71 85 CF STA &CF ;set current volume letter to A 8A73 A9 00 LDA #&00 ;data transfer call &00 = read data 8A75 8D 00 10 STA &1000 ;set data transfer call number 8A78 20 A4 A5 JSR R5A4 ;detect disc format/set sector address ;[BUG]NMI area use before claim ;[BUG]*STAT 4 prints stats 0..8 times ;if last disc double density 8A7B 2C E3 10 BIT &10E3 ;test density flag 8A7E 70 03 BVS PA83 ;if double density then *STAT eight volumes 8A80 4C A7 8A JMP PAA7 ;else *STAT the single volume .PA83 ;*STAT eight volumes 8A83 20 00 8C JSR PC00 ;print disc type and volume list 8A86 A2 00 LDX #&00 ;for each volume letter A..H: .PA88 8A88 BD 06 10 LDA &1006,X ;test if number of tracks in volume > 0 8A8B F0 0D BEQ PA9A ;if = 0 then no such volume, skip 8A8D 8A TXA ;save volume counter 8A8E 48 PHA 8A8F 20 67 84 JSR P467 ;print newline 8A92 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 8A95 20 16 8D JSR PD16 ;print volume statistics 8A98 68 PLA ;restore volume counter 8A99 AA TAX .PA9A 8A9A 18 CLC 8A9B A5 CF LDA &CF ;get current volume 8A9D 69 10 ADC #&10 ;increment volume letter 8A9F 85 CF STA &CF ;set as current volume 8AA1 E8 INX ;increment counter 8AA2 E0 08 CPX #&08 ;loop until 8 volumes catalogued 8AA4 D0 E2 BNE PA88 8AA6 60 RTS .PAA7 ;*STAT specified volume 8AA7 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 8AAA 20 00 8C JSR PC00 ;print disc type and volume list 8AAD 4C 16 8D JMP PD16 ;print volume statistics ;*XCAT 8AB0 A2 00 LDX #&00 ;x=0, nothing specified (unused) 8AB2 20 E5 A4 JSR R4E5 ;select specified or default volume 8AB5 A5 CF LDA &CF ;get current volume 8AB7 29 0F AND #&0F ;extract drive number 8AB9 85 CF STA &CF ;set current volume letter to A 8ABB A9 00 LDA #&00 ;data transfer call &00 = read data 8ABD 8D 00 10 STA &1000 ;set data transfer call number 8AC0 20 A4 A5 JSR R5A4 ;detect disc format/set sector address ;[BUG]NMI area use before claim ;[BUG]*XCAT 4 prints catalogue 0..8 times ;if last disc double density 8AC3 2C E3 10 BIT &10E3 ;test density flag 8AC6 70 03 BVS PACB ;if double density then *CAT eight volumes 8AC8 4C 63 95 JMP Q563 ;else *CAT the single volume .PACB ;*CAT eight volumes 8ACB 20 00 8C JSR PC00 ;print disc type and volume list 8ACE A2 00 LDX #&00 ;for each volume letter A..H: .PAD0 8AD0 BD 06 10 LDA &1006,X ;test if number of tracks in volume > 0 8AD3 F0 10 BEQ PAE5 ;if = 0 then no such volume, skip 8AD5 8A TXA ;save volume counter 8AD6 48 PHA 8AD7 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 8ADA 20 D6 8B JSR PBD6 ;print volume title 8ADD 20 7F 8C JSR PC7F ;print volume spec and boot option 8AE0 20 02 8B JSR PB02 ;list files in catalogue 8AE3 68 PLA ;restore volume counter 8AE4 AA TAX .PAE5 8AE5 18 CLC 8AE6 A5 CF LDA &CF ;get current volume 8AE8 69 10 ADC #&10 ;select next volume letter 8AEA 85 CF STA &CF ;set as current volume 8AEC E8 INX ;increment counter 8AED E0 08 CPX #&08 ;have 8 volumes A..H been listed? 8AEF D0 DF BNE PAD0 ;if not then loop 8AF1 60 RTS .PAF2 ;Print "No file" 8AF2 20 D2 A3 JSR R3D2 ;print VDU sequence immediate 8AF5 EQUB &0D ;newline 8AF6 EQUB &0A 8AF7 EQUS "No file" 8AFE EQUB &0D ;newline 8AFF EQUB &0A 8B00 EQUB &FF 8B01 60 RTS .PB02 ;List files in catalogue 8B02 AD 05 0F LDA &0F05 ;get number of files in catalogue * 8 8B05 F0 EB BEQ PAF2 ;if catalogue empty then print "No file" 8B07 A0 FF LDY #&FF 8B09 84 A8 STY &A8 ;else print a newline before first entry 8B0B C8 INY 8B0C 84 AA STY &AA ;CSD printed first, directory char = NUL .PB0E 8B0E CC 05 0F CPY &0F05 ;have we reached the end of the catalogue? 8B11 B0 17 BCS PB2A ;if so then start sorting entries 8B13 B9 0F 0E LDA &0E0F,Y ;else get directory character of cat entry 8B16 4D CA 10 EOR &10CA ;compare with default (CSD) directory 8B19 29 7F AND #&7F ;mask off lock bit 8B1B D0 08 BNE PB25 ;if directories differ skip to next entry 8B1D B9 0F 0E LDA &0E0F,Y ;else set directory character to NUL 8B20 29 80 AND #&80 ;and preserve lock bit 8B22 99 0F 0E STA &0E0F,Y .PB25 8B25 20 72 A4 JSR R472 ;add 8 to Y 8B28 90 E4 BCC PB0E ;and loop (always) .PB2A 8B2A A0 00 LDY #&00 ;y=&00, start at first file entry 8B2C 20 AA 8B JSR PBAA ;find unlisted catalogue entry 8B2F B0 6E BCS PB9F ;if none remaining then finish catalogue .PB31 8B31 84 AB STY &AB ;save catalogue pointer 8B33 A2 00 LDX #&00 ;set filename offset = 0 .PB35 8B35 B9 08 0E LDA &0E08,Y ;copy name and directory of first entry 8B38 29 7F AND #&7F ;with b7 clear 8B3A 9D 60 10 STA &1060,X ;to workspace 8B3D C8 INY 8B3E E8 INX 8B3F E0 08 CPX #&08 ;loop until 8 characters copied 8B41 D0 F2 BNE PB35 .PB43 8B43 20 AA 8B JSR PBAA ;find unlisted catalogue entry 8B46 B0 1F BCS PB67 ;if none remaining then print lowest entry 8B48 38 SEC ;else set C=1 for subtraction 8B49 A2 06 LDX #&06 ;start at 6th character (LSB) of leaf name: .PB4B 8B4B B9 0E 0E LDA &0E0E,Y ;get character of entry 8B4E FD 60 10 SBC &1060,X ;subtract character of workspace 8B51 88 DEY ;loop until 7 characters compared 8B52 CA DEX 8B53 10 F6 BPL PB4B 8B55 20 73 A4 JSR R473 ;add 7 to Y 8B58 B9 0F 0E LDA &0E0F,Y ;get directory character (MSB) of entry 8B5B 29 7F AND #&7F ;mask off lock bit 8B5D ED 67 10 SBC &1067 ;subtract directory character in workspace 8B60 90 CF BCC PB31 ;if entry < wksp then copy entry to wksp 8B62 20 72 A4 JSR R472 ;else add 8 to Y 8B65 B0 DC BCS PB43 ;and loop (always) .PB67 8B67 A4 AB LDY &AB ;get catalogue pointer 8B69 B9 08 0E LDA &0E08,Y ;set b7 in first character of leaf name 8B6C 09 80 ORA #&80 ;marking entry as listed 8B6E 99 08 0E STA &0E08,Y 8B71 AD 67 10 LDA &1067 ;get directory character from workspace 8B74 C5 AA CMP &AA ;compare with last one printed 8B76 F0 10 BEQ PB88 ;if same then add entry to group 8B78 A6 AA LDX &AA ;else test previous directory 8B7A 85 AA STA &AA ;set previous directory = current directory 8B7C D0 0A BNE PB88 ;if prev=NUL we go from CSD to other dirs 8B7E 20 67 84 JSR P467 ;so print double newline: .PB81 8B81 20 67 84 JSR P467 ;print newline 8B84 A0 FF LDY #&FF ;set Y = &FF going to 0, start of line 8B86 D0 09 BNE PB91 ;branch (always) .PB88 8B88 A4 A8 LDY &A8 ;have we printed two entries on this line? 8B8A D0 F5 BNE PB81 ;if so then print newline and reset counter 8B8C A0 05 LDY #&05 ;else tab to next field. Y = 5 spaces 8B8E 20 DA 88 JSR P8DA ;print number of spaces in Y, set index = 1: .PB91 8B91 C8 INY 8B92 84 A8 STY &A8 ;y = index of next entry on this line 8B94 A4 AB LDY &AB ;get catalogue pointer 8B96 20 C9 A2 JSR R2C9 ;print two spaces 8B99 20 A6 88 JSR P8A6 ;print filename from catalogue 8B9C 4C 2A 8B JMP PB2A ;loop until all files listed .PB9F 8B9F A9 FF LDA #&FF 8BA1 8D 84 10 STA &1084 ;forget catalogue in pages &0E..F 8BA4 4C 67 84 JMP P467 ;print newline .PBA7 ;Find next unlisted catalogue entry 8BA7 20 72 A4 JSR R472 ;add 8 to Y .PBAA ;Find unlisted catalogue entry 8BAA CC 05 0F CPY &0F05 ;if catalogue pointer beyond last file 8BAD B0 05 BCS PBB4 ;then return C=1 8BAF B9 08 0E LDA &0E08,Y ;else test first character of leaf name 8BB2 30 F3 BMI PBA7 ;if b7=1 then already listed, skip .PBB4 8BB4 60 RTS ;else return C=0, catalogue pointer in Y .PBB5 ;Print volume spec in A (assuming DD) 8BB5 2C B4 8B BIT &8BB4 ;set V=1 8BB8 70 03 BVS PBBD ;always print volume letter B..H after drive .PBBA ;Print volume spec in A 8BBA 2C E3 10 BIT &10E3 ;test density flag .PBBD 8BBD 08 PHP ;save density flag on stack 8BBE 48 PHA ;save volume on stack 8BBF 29 07 AND #&07 ;extract bits 2..0, drive 0..7 8BC1 20 31 A4 JSR R431 ;print hex nibble 8BC4 68 PLA ;restore volume 8BC5 28 PLP ;restore density flag 8BC6 50 06 BVC PBCE ;if single density then only print drive no. 8BC8 4A LSR A ;else shift volume letter to bits 2..0 8BC9 4A LSR A 8BCA 4A LSR A 8BCB 4A LSR A 8BCC D0 01 BNE PBCF ;if volume letter is not A then print it .PBCE 8BCE 60 RTS ;else exit .PBCF 8BCF 88 DEY ;decrement Y (no. spaces to print later) 8BD0 18 CLC ;add ASCII value of "A" 8BD1 69 41 ADC #&41 ;to produce volume letter B..H 8BD3 4C 03 A4 JMP R403 ;print character in A (OSASCI) and exit .PBD6 ;Print volume title 8BD6 A0 0B LDY #&0B ;set y = &0B print 11 spaces 8BD8 20 DA 88 JSR P8DA ;print number of spaces in Y .PBDB 8BDB B9 00 0E LDA &0E00,Y ;y=0; if Y=0..7 get char from sector 0 8BDE C0 08 CPY #&08 ;if Y=8..11 8BE0 90 03 BCC PBE5 8BE2 B9 F8 0E LDA &0EF8,Y ;then get character of title from sector 1 .PBE5 8BE5 20 03 A4 JSR R403 ;print character in A (OSASCI) 8BE8 C8 INY ;loop until 12 characters of title printed 8BE9 C0 0C CPY #&0C 8BEB D0 EE BNE PBDB 8BED 20 94 A3 JSR R394 ;print " (" 8BF0 EQUB &0D 8BF1 EQUS " (" 8BF3 AD 04 0F LDA &0F04 ;get BCD catalogue cycle number 8BF6 20 29 A4 JSR R429 ;print hex byte 8BF9 20 94 A3 JSR R394 ;print ")" +newline 8BFC EQUS ")" 8BFD EQUB &0D 8BFE EA NOP 8BFF 60 RTS .PC00 ;Print disc type and volume list 8C00 A9 83 LDA #&83 ;teletext char &83 = yellow alphanumerics 8C02 20 03 A4 JSR R403 ;print character in A (OSASCI) 8C05 A5 CF LDA &CF ;get current volume 8C07 29 0C AND #&0C ;extract bits 2,3 of drive number 8C09 D0 65 BNE PC70 ;if drive number more than 3 print "RAM Disk" 8C0B 2C E3 10 BIT &10E3 ;else test density flag 8C0E 70 09 BVS PC19 ;if double density print "Double density" 8C10 20 94 A3 JSR R394 ;else print "Single density" 8C13 EQUS "Sing" 8C17 90 08 BCC PC21 .PC19 8C19 20 94 A3 JSR R394 8C1C EQUS "Doub" 8C20 EA NOP .PC21 8C21 20 94 A3 JSR R394 8C24 EQUS "le density" 8C2E EA NOP 8C2F A9 87 LDA #&87 ;teletext char &87 = white alphanumerics 8C31 20 03 A4 JSR R403 ;print character in A (OSASCI) 8C34 A0 0E LDY #&0E ;set Y = 14 spaces for single density 8C36 2C E3 10 BIT &10E3 ;test density flag 8C39 50 1E BVC PC59 ;if single density skip list of volumes 8C3B A0 05 LDY #&05 ;else Y = 5 spaces for double density 8C3D 20 DA 88 JSR P8DA ;print number of spaces in Y 8C40 A2 00 LDX #&00 ;set volume index = 0, start at volume A: .PC42 8C42 18 CLC ;clear carry for add 8C43 BD 06 10 LDA &1006,X ;test if number of tracks in volume > 0 8C46 08 PHP ;preserve result 8C47 8A TXA ;copy index to A to make volume letter 8C48 28 PLP ;restore result 8C49 D0 02 BNE PC4D ;if volume present print its letter 8C4B A9 ED LDA #&ED ;else A=&ED + &41 = &2E, ".": .PC4D 8C4D 69 41 ADC #&41 ;add ASCII value of "A" 8C4F 20 03 A4 JSR R403 ;print character in A (OSASCI) 8C52 E8 INX ;point to next volume 8C53 E0 08 CPX #&08 ;have all 8 volumes been listed? 8C55 D0 EB BNE PC42 ;if not then loop 8C57 A0 01 LDY #&01 ;else Y=1 space separating volume list: .PC59 8C59 2C E0 10 BIT &10E0 ;test double-stepping flag 8C5C 10 0F BPL PC6D ;if set manually (*4080 ON/OFF) then end line 8C5E 50 0D BVC PC6D ;if 1:1 stepping was detected then end line 8C60 20 DA 88 JSR P8DA ;else print 1 or 14 spaces 8C63 20 94 A3 JSR R394 ;print "40in80" 8C66 EQUS "40in80" 8C6C EA NOP .PC6D 8C6D 4C 67 84 JMP P467 ;print newline .PC70 ;Print "RAM Disk" 8C70 20 D2 A3 JSR R3D2 ;print VDU sequence immediate 8C73 EQUS "RAM Disk" 8C7B EQUB &FF 8C7C 4C 67 84 JMP P467 ;print newline .PC7F ;Print volume spec and boot option 8C7F A0 0D LDY #&0D ;set Y = &0D print 13 spaces 8C81 A5 CF LDA &CF ;get current volume 8C83 20 08 8D JSR PD08 ;print " Drive " plus volume spec in A 8C86 20 DA 88 JSR P8DA ;print number of spaces in Y 8C89 20 94 A3 JSR R394 ;print "Option " 8C8C EQUS "Option " 8C93 AD 06 0F LDA &0F06 ;get boot option/top bits volume size 8C96 20 67 A4 JSR R467 ;shift A right 4 places 8C99 20 31 A4 JSR R431 ;print hex nibble 8C9C 20 94 A3 JSR R394 ;print " (" 8C9F EQUS " (" 8CA1 A0 03 LDY #&03 ;4 characters to print 8CA3 0A ASL A ;multiply boot option by 4 8CA4 0A ASL A 8CA5 AA TAX ;transfer to X for use as offset .PCA6 8CA6 BD F8 8C LDA &8CF8,X ;get character of boot option descriptor 8CA9 20 03 A4 JSR R403 ;print character in A (OSASCI) 8CAC E8 INX ;increment offset 8CAD 88 DEY ;decrement count 8CAE 10 F6 BPL PCA6 ;loop until 4 characters printed 8CB0 20 94 A3 JSR R394 ;print ")" + newline 8CB3 EQUS ")" 8CB4 EQUB &0D 8CB5 EA NOP 8CB6 60 RTS .PCB7 ;Print CSD and library directories 8CB7 20 94 A3 JSR R394 ;print "Directory :" 8CBA EQUS " Directory :" 8CC6 A0 06 LDY #&06 ;6 characters in next field 8CC8 AD CB 10 LDA &10CB ;get default volume 8CCB 20 B5 8B JSR PBB5 ;print volume spec in A (assuming DD) 8CCE 20 01 A4 JSR R401 ;print a dot 8CD1 AD CA 10 LDA &10CA ;get default directory 8CD4 20 03 A4 JSR R403 ;print character in A (OSASCI) 8CD7 20 DA 88 JSR P8DA ;print number of spaces in Y 8CDA 20 94 A3 JSR R394 ;print "Library :" 8CDD EQUS "Library :" 8CE6 AD CD 10 LDA &10CD ;get library volume 8CE9 20 B5 8B JSR PBB5 ;print volume spec in A (assuming DD) 8CEC 20 01 A4 JSR R401 ;print a dot 8CEF AD CC 10 LDA &10CC ;get library directory #if defined _BEEBEM .PCF2 #endif 8CF2 20 03 A4 JSR R403 ;print character in A (OSASCI) 8CF5 4C 67 84 JMP P467 ;print newline ;Table of boot option descriptors 0..3 8CF8 EQUS "off" 8CFB EQUB &00 8CFC EQUS "LOAD" 8D00 EQUS "RUN" 8D03 EQUB &00 8D04 EQUS "EXEC" .PD08 ;Print " Drive " plus volume spec in A 8D08 20 94 A3 JSR R394 8D0B EQUS " Drive " 8D12 EA NOP 8D13 4C BA 8B JMP PBBA ;print volume spec in A .PD16 ;Print volume statistics 8D16 A0 03 LDY #&03 ;y=3 print 2 spaces/ 1 space 8D18 A5 CF LDA &CF ;get current volume 8D1A 20 08 8D JSR PD08 ;print " Drive " plus volume spec in A 8D1D 20 DA 88 JSR P8DA ;print number of spaces in Y 8D20 20 94 A3 JSR R394 8D23 EQUS "Volume size " 8D31 EA NOP 8D32 AD 07 0F LDA &0F07 ;copy volume size to sector count 8D35 85 B0 STA &B0 ;LSB 8D37 AD 06 0F LDA &0F06 ;get boot option/top bits volume size 8D3A 29 03 AND #&03 ;mask top bits volume size 8D3C 85 B1 STA &B1 ;store MSB 8D3E 20 72 8D JSR PD72 ;print sector count as kilobytes 8D41 20 7B 8D JSR PD7B ;print "K" 8D44 20 67 84 JSR P467 ;print newline 8D47 A0 0B LDY #&0B ;set Y = &0B print 11 spaces 8D49 20 DA 88 JSR P8DA ;print number of spaces in Y 8D4C 20 94 A3 JSR R394 ;print "Volume unused" 8D4F EQUS "Volume unused " 8D5D EA NOP 8D5E 20 EA A1 JSR R1EA ;calculate free space on volume 8D61 A5 C0 LDA &C0 ;copy result to sector count 8D63 85 B0 STA &B0 8D65 A5 C1 LDA &C1 8D67 85 B1 STA &B1 8D69 20 72 8D JSR PD72 ;print sector count as kilobytes 8D6C 20 7B 8D JSR PD7B ;print "K" 8D6F 4C 67 84 JMP P467 ;print newline .PD72 ;Print sector count as kilobytes 8D72 20 81 8D JSR PD81 ;divide sector count by 4 8D75 20 5D AE JSR RE5D ;convert binary word to four decimal digits 8D78 4C 66 B0 JMP S066 ;print four decimal digits, space-padded .PD7B ;Print "K" 8D7B 20 94 A3 JSR R394 8D7E EQUS "K" 8D7F EA NOP 8D80 60 RTS .PD81 ;Divide word by 4 8D81 46 B1 LSR &B1 8D83 66 B0 ROR &B0 8D85 46 B1 LSR &B1 8D87 66 B0 ROR &B0 8D89 60 RTS ;DFS command table 8D8A EQUS "4080" 8D8E EQUW &B4,&01 8D90 EQUB &8D ;syntax &D: b7=1 8D91 EQUS "ACCESS" 8D97 EQUW &90,&A5 8D99 EQUB &32 ;syntax &2,&3: (L) 8D9A EQUS "BACKUP" 8DA0 EQUW &85,&3B 8DA2 EQUB &54 ;syntax &4,&5: 8DA3 EQUS "COMPACT" 8DAA EQUW &A0,&F4 8DAC EQUB &0A ;syntax &A: () 8DAD EQUS "COPY" 8DB1 EQUW &86,&3E 8DB3 EQUB &64 ;syntax &4,&6: 8DB4 EQUS "DELETE" 8DBA EQUW &8F,&7B 8DBC EQUB &01 ;syntax &1: 8DBD EQUS "DENSITY" 8DC4 EQUW &B3,&D7 8DC6 EQUB &8D ;syntax &D: b7=1 8DC7 EQUS "DESTROY" 8DCE EQUW &8F,&8A 8DD0 EQUB &02 ;syntax &2: 8DD1 EQUS "DIR" 8DD4 EQUW &90,&37 8DD6 EQUB &09 ;syntax &9: () 8DD7 EQUS "DRIVE" 8DDC EQUW &90,&2E 8DDE EQUB &0A ;syntax &A: () 8DDF EQUS "ENABLE" 8DE5 EQUW &92,&13 8DE7 EQUB &00 ;syntax &0: no arguments 8DE8 EQUS "INFO" 8DEC EQUW &89,&51 8DEE EQUB &02 ;syntax &2: 8DEF EQUS "LIB" 8DF2 EQUW &90,&3A 8DF4 EQUB &09 ;syntax &9: () 8DF5 EQUS "MCOPY" 8DFA EQUW &9E,&2D 8DFC EQUB &D4 ;syntax &4,&5: b7=1 8DFD EQUS "RENAME" 8E03 EQUW &92,&4C 8E05 EQUB &78 ;syntax &8,&7: 8E06 EQUS "SROM" 8E0A EQUW &90,&5D 8E0C EQUB &8C ;syntax &C: b7=1 8E0D EQUS "STAT" 8E11 EQUW &8A,&60 8E13 EQUB &0A ;syntax &A: () 8E14 EQUS "TAPEDISK" 8E1C EQUW &93,&6C 8E1E EQUB &81 ;syntax &1: b7=1 8E1F EQUS "TITLE" 8E24 EQUW &90,&76 8E26 EQUB &0B ;syntax &B: 8E27 EQUS "WIPE" 8E2B EQUW &8F,&49 8E2D EQUB &02 ;syntax &2: <afsp> 8E2E EQUS "XCAT" 8E32 EQUW &8A,&B0 8E34 EQUB &0A ;syntax &A: (<drv>) ;DDOSX command table 8E35 EQUS "COPYRIGHT" #if defined _DDOS316 8E3E EQUW &BE,&33 #elif defined _DDOS336 8E3E EQUW &BE,&21 #elif defined _DDOS346 8E3E EQUW &BE,&43 #else 8E3E EQUW &BE,&42 #endif 8E40 EQUB &80 ;syntax &0: no arguments b7=1 #if defined _BUGFIX 8E41 EQUS "FDCSTAT" 8E48 EQUW &B5,&6C 8E4A EQUB &80 ;syntax &0: no arguments b7=1 8E4B EQUS "RAMINIT" 8E52 EQUW &B4,&37 8E54 EQUB &80 ;syntax &0: no arguments b7=1 8E55 EQUS "ROMID" 8E5A EQUW &94,&2D 8E5C EQUB &80 ;syntax &0: no arguments b7=1 #else 8E41 EQUS "FDCSTAT" 8E48 EQUW &B5,&66 8E4A EQUB &80 ;syntax &0: no arguments b7=1 8E4B EQUS "RAMINIT" 8E52 EQUW &B4,&31 8E54 EQUB &80 ;syntax &0: no arguments b7=1 8E55 EQUS "ROMID" 8E5A EQUW &94,&2A 8E5C EQUB &80 ;syntax &0: no arguments b7=1 #endif #if defined _DDOS357 8E5D EQUW &94,&D7 ;unrecognised command, *RUN it &94D7 #else 8E5D EQUW &94,&D1 ;unrecognised command, *RUN it &94D1 #endif ;Utility command table 8E5F EQUS "BUILD" 8E64 EQUW &84,&17 8E66 EQUB &01 ;syntax &1: <fsp> 8E67 EQUS "DISC" 8E6B EQUW &82,&0F 8E6D EQUB &00 ;syntax &0: no arguments 8E6E EQUS "DUMP" 8E72 EQUW &83,&9F 8E74 EQUB &01 ;syntax &1: <fsp> 8E75 EQUS "FORMAT" 8E7B EQUW &A8,&A1 8E7D EQUB &8D ;syntax &D: <argument> b7=1 8E7E EQUS "LIST" 8E82 EQUW &83,&5D 8E84 EQUB &01 ;syntax &1: <fsp> 8E85 EQUS "TYPE" 8E89 EQUW &83,&56 8E8B EQUB &01 ;syntax &1: <fsp> 8E8C EQUS "VERIFY" 8E92 EQUW &AA,&55 8E94 EQUB &8A ;syntax &A: (<drv>) b7=1 8E95 EQUS "VOLGEN" 8E9B EQUW &AB,&47 8E9D EQUB &8A ;syntax &A: (<drv>) b7=1 ;entry not printed in *HELP UTILS 8E9E EQUS "DISK" 8EA2 EQUW &82,&0F 8EA4 EQUB &00 ;syntax &0: no arguments 8EA5 EQUW &8E,&C6 ;unrecognised utility, return &8EC6 ;*HELP keyword table 8EA7 EQUS "DDOS" 8EAB EQUW &9F,&E8 8EAD EQUB &00 8EAE EQUS "DFS" 8EB1 EQUW &9F,&E8 8EB3 EQUB &00 8EB4 EQUS "UTILS" 8EB9 EQUW &9F,&E0 8EBB EQUB &00 8EBC EQUS "DDOSX" 8EC1 EQUW &9F,&F0 8EC3 EQUB &00 8EC4 EQUW &8E,&C6 ;unrecognised keyword, return &8EC6 ;Return from unrecognised keyword 8EC6 60 RTS ;on entry A=string offset (=Y to GSINIT) ;XY=address of table .PEC7 ;Search for command or keyword in table 8EC7 20 28 8F JSR PF28 ;set up trampoline to read table at XY 8ECA 48 PHA ;save string offset .PECB 8ECB 68 PLA ;restore offset of start of command line 8ECC A8 TAY 8ECD 48 PHA 8ECE 20 BB A4 JSR R4BB ;call GSINIT with C=0 8ED1 A2 00 LDX #&00 ;start at current trampoline address 8ED3 20 AA 00 JSR &00AA ;fetch first byte 8ED6 38 SEC ;if terminator,empty keyword matches anything 8ED7 30 3B BMI PF14 ;so jump to following action address with C=1 8ED9 CA DEX ;else decrement X and Y to stay in place: 8EDA 88 DEY .PEDB 8EDB E8 INX ;advance command line and table offsets 8EDC C8 INY 8EDD 20 AA 00 JSR &00AA ;get byte from table 8EE0 30 22 BMI PF04 ;if terminator, check command also terminates 8EE2 51 F2 EOR (&F2),Y ;else compare with character of command 8EE4 29 5F AND #&5F ;make comparison case-insensitive 8EE6 F0 F3 BEQ PEDB ;if equal then compare next characters 8EE8 B1 F2 LDA (&F2),Y ;else get mismatching character of command 8EEA C9 2E CMP #&2E ;is it a dot? 8EEC 08 PHP ;save the result .PEED 8EED E8 INX ;scan keyword in table 8EEE 20 AA 00 JSR &00AA 8EF1 10 FA BPL PEED ;loop until terminator reached 8EF3 E8 INX ;skip action address, 2 bytes 8EF4 E8 INX 8EF5 28 PLP ;is the command an abbreviation or a mismatch? 8EF6 D0 05 BNE PEFD ;if mismatch then skip syntax, scan next kywd 8EF8 20 AA 00 JSR &00AA ;else test syntax byte 8EFB 10 13 BPL PF10 ;if b7=0 accept cmd, else abbrev. not allowed: .PEFD 8EFD E8 INX ;skip syntax byte 8EFE 20 37 8F JSR PF37 ;add X to trampoline address 8F01 4C CB 8E JMP PECB ;scan next keyword .PF04 8F04 B1 F2 LDA (&F2),Y ;get character of command 8F06 20 9A A4 JSR R49A ;set C=0 iff character in A is a letter 8F09 B0 08 BCS PF13 ;if C=1 accept command, else longer than kywd 8F0B E8 INX ;so skip action address, 2 bytes 8F0C E8 INX 8F0D 4C FD 8E JMP PEFD ;skip syntax byte and scan next keyword .PF10 ;Accept abbreviated command 8F10 CA DEX ;backtrack to action address, 2 bytes 8F11 CA DEX 8F12 C8 INY ;advance command line offset past the dot: .PF13 ;Accept command 8F13 18 CLC ;set C=0 command valid .PF14 8F14 68 PLA ;discard offset to start of command 8F15 20 AA 00 JSR &00AA ;get action address high byte 8F18 85 A9 STA &A9 ;store high byte of vector 8F1A E8 INX ;advance to next byte of table 8F1B 20 AA 00 JSR &00AA ;get action address low byte 8F1E 85 A8 STA &A8 ;store low byte of vector 8F20 E8 INX ;return X=offset of syntax byte 8F21 60 RTS ;y=offset of command line tail. ;unreachable code 8F22 48 PHA ;set up trampoline to write table at XY 8F23 A9 9D LDA #&9D 8F25 4C 2B 8F JMP PF2B .PF28 ;Set up trampoline to read table at XY 8F28 48 PHA 8F29 A9 BD LDA #&BD ;&BD = LDA abs,X .PF2B 8F2B 85 AA STA &AA ;instruction at &00AA = LDA xy,X 8F2D 86 AB STX &AB 8F2F 84 AC STY &AC 8F31 A9 60 LDA #&60 ;instruction at &00AD = RTS 8F33 85 AD STA &AD 8F35 68 PLA ;restore A 8F36 60 RTS .PF37 ;Add X to trampoline address 8F37 18 CLC 8F38 8A TXA 8F39 65 AB ADC &AB ;add X to low byte of LDA,X address 8F3B 85 AB STA &AB 8F3D 90 02 BCC PF41 ;carry out to high byte 8F3F E6 AC INC &AC .PF41 8F41 60 RTS .PF42 ;Set GSINIT pointer to XY, set Y=0 8F42 86 F2 STX &F2 8F44 84 F3 STY &F3 8F46 A0 00 LDY #&00 8F48 60 RTS ;*WIPE 8F49 20 E1 8F JSR PFE1 ;ensure file matching wildcard argument .PF4C 8F4C 20 A6 88 JSR P8A6 ;print filename from catalogue 8F4F 20 94 A3 JSR R394 8F52 EQUS " : " 8F55 EA NOP 8F56 B9 0F 0E LDA &0E0F,Y ;test lock bit 8F59 10 06 BPL PF61 ;if unlocked then ask to delete 8F5B 20 FD A3 JSR R3FD ;else deletion not allowed, print letter N 8F5E 4C 72 8F JMP PF72 ;find next matching file .PF61 8F61 20 D9 84 JSR P4D9 ;ask user yes or no 8F64 D0 0C BNE PF72 ;if user replies no then find next match 8F66 20 87 88 JSR P887 ;else ensure disc not changed 8F69 20 9E 89 JSR P99E ;delete catalogue entry 8F6C 20 81 92 JSR Q281 ;write volume catalogue 8F6F 20 FF 8F JSR PFFF ;shift cat pointer to follow shifted files .PF72 8F72 20 67 84 JSR P467 ;print newline 8F75 20 6A 89 JSR P96A ;find next matching file 8F78 B0 D2 BCS PF4C ;if found then wipe the file 8F7A 60 RTS ;else exit ;*DELETE 8F7B 20 2F 89 JSR P92F ;disallow wildcard characters in filename 8F7E 20 E4 8F JSR PFE4 ;ensure file matching argument 8F81 20 BB 89 JSR P9BB ;print *INFO line if verbose 8F84 20 9E 89 JSR P99E ;delete catalogue entry 8F87 4C 81 92 JMP Q281 ;write volume catalogue ;Note: *DESTROY deletes all matching files, locked or unlocked. ;*DESTROY 8F8A 20 3A A2 JSR R23A ;ensure *ENABLE active 8F8D 20 E1 8F JSR PFE1 ;ensure file matching wildcard argument .PF90 8F90 20 A6 88 JSR P8A6 ;print filename from catalogue 8F93 20 67 84 JSR P467 ;print newline 8F96 20 6A 89 JSR P96A ;find next matching file 8F99 B0 F5 BCS PF90 ;loop until all matching files listed 8F9B 20 94 A3 JSR R394 8F9E EQUB &0D 8F9F EQUS "Delete (Y/N) ? " 8FAE EA NOP 8FAF 20 D9 84 JSR P4D9 ;ask user yes or no 8FB2 F0 03 BEQ PFB7 ;if user replies yes then proceed 8FB4 4C 67 84 JMP P467 ;else print newline and exit .PFB7 8FB7 20 87 88 JSR P887 ;ensure disc not changed 8FBA 20 63 89 JSR P963 ;search for file in catalogue .PFBD 8FBD B9 0F 0E LDA &0E0F,Y ;unlock catalogue entry! 8FC0 29 7F AND #&7F 8FC2 99 0F 0E STA &0E0F,Y 8FC5 20 9E 89 JSR P99E ;delete catalogue entry 8FC8 20 FF 8F JSR PFFF ;subtract 8 from catalogue pointer 8FCB 20 6A 89 JSR P96A ;find next matching file 8FCE B0 ED BCS PFBD 8FD0 20 81 92 JSR Q281 ;write volume catalogue 8FD3 20 94 A3 JSR R394 ;print "Deleted" and exit 8FD6 EQUB &0D 8FD7 EQUS "Deleted" 8FDE EQUB &0D 8FDF EA NOP 8FE0 60 RTS .PFE1 ;Ensure file matching wildcard argument 8FE1 20 2B 89 JSR P92B ;allow wildcard characters in filename .PFE4 ;Ensure file matching argument 8FE4 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg 8FE7 4C 35 89 JMP P935 ;ensure file matching spec in catalogue .PFEA ;Set current file from argument 8FEA 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg 8FED 4C E5 87 JMP P7E5 ;set current file from file spec .PFF0 ;Pack b17,16 of length into catalogue entry 8FF0 20 6D A4 JSR R46D ;shift A left 4 places 8FF3 5D 0E 0F EOR &0F0E,X ;replace b5,b4 of top bits with b5,b4 from A 8FF6 29 30 AND #&30 8FF8 5D 0E 0F EOR &0F0E,X 8FFB 9D 0E 0F STA &0F0E,X ;store top bits back in catalogue 8FFE 60 RTS .PFFF ;Subtract 8 from catalogue pointer 8FFF AC CF 10 LDY &10CF ;get catalogue pointer 9002 20 7B A4 JSR R47B ;subtract 8 from Y 9005 8C CF 10 STY &10CF ;store catalogue pointer 9008 60 RTS .Q009 ;Write ordinary file L5 9009 20 59 93 JSR Q359 ;prepare to write from user memory 900C 4C 12 90 JMP Q012 ;transfer ordinary file L5 .Q00F ;Read ordinary file L5 900F 20 50 93 JSR Q350 ;prepare to read to user memory .Q012 ;Transfer ordinary file L5 9012 20 EA 88 JSR P8EA ;prepare ordinary file transfer 9015 A9 01 LDA #&01 ;a=&01, unused ;(appears in A on exit from OSFILE 0/&FF ;but these calls define no return value) 9017 20 02 A7 JSR R702 ;transfer data and report errors L4 901A 4C 38 93 JMP Q338 ;release Tube and exit ;called only from &877E .Q01D ;Read extended file L5 901D 20 50 93 JSR Q350 ;prepare to read to user memory 9020 4C 26 90 JMP Q026 ;transfer extended file L5 ;called only from &87A2 .Q023 ;Write extended file L5 9023 20 59 93 JSR Q359 ;prepare to write from user memory .Q026 ;Transfer extended file L5 9026 20 E1 88 JSR P8E1 ;prepare extended file transfer 9029 A9 01 LDA #&01 ;a=&01, unused 902B 4C 02 A7 JMP R702 ;transfer data and report errors L4 ;*DRIVE 902E 20 E5 A4 JSR R4E5 ;select specified or default volume 9031 A5 CF LDA &CF ;get current volume 9033 8D CB 10 STA &10CB ;set as default volume 9036 60 RTS ;*DIR 9037 A2 00 LDX #&00 9039 AD A2 02 LDA &02A2 ;*LIB 903A=LDX #&02 903C BD CA 10 LDA &10CA,X ;get default/library directory 903F 85 CE STA &CE ;set as current directory 9041 BD CB 10 LDA &10CB,X ;get default/library volume 9044 85 CF STA &CF ;set as current volume 9046 8A TXA ;save offset 9047 48 PHA 9048 20 BB A4 JSR R4BB ;call GSINIT with C=0 904B F0 03 BEQ Q050 904D 20 1B A5 JSR R51B ;parse directory spec .Q050 9050 68 PLA ;restore offset 9051 AA TAX 9052 A5 CE LDA &CE ;get current directory 9054 9D CA 10 STA &10CA,X ;set as default/library directory 9057 A5 CF LDA &CF ;get current volume 9059 9D CB 10 STA &10CB,X ;set as default/library volume 905C 60 RTS ;*SROM 905D 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg 9060 20 C5 FF JSR &FFC5 ;call GSREAD, get first argument character 9063 20 A0 A4 JSR R4A0 ;convert ASCII hex digit to binary 9066 B0 0B BCS Q073 ;if invalid then raise "Bad command" error 9068 48 PHA ;else save digit 9069 20 C5 FF JSR &FFC5 ;call GSREAD; if more characters in argument 906C 90 05 BCC Q073 ;then raise "Bad command" error 906E 68 PLA ;else get back digit 906F 8D 01 10 STA &1001 ;set *SROM slot number and exit. 9072 60 RTS .Q073 #if defined _DDOS357 9073 4C CC B9 JMP S9CC ;raise "Bad command" error #else 9073 4C F8 94 JMP Q4F8 ;raise "Bad command" error #endif ;*TITLE 9076 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg 9079 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive 907C 20 9E 92 JSR Q29E ;load volume catalogue L4 907F A2 0B LDX #&0B ;first offset to store = 11 9081 A9 00 LDA #&00 ;set title to 12 NULs: .Q083 9083 20 99 90 JSR Q099 ;store character of title 9086 CA DEX ;loop until 12 characters stored 9087 10 FA BPL Q083 .Q089 9089 E8 INX ;x=&FF, set X=0 offset of first character 908A 20 C5 FF JSR &FFC5 ;call GSREAD 908D B0 07 BCS Q096 ;if end of argument write catalogue 908F 20 99 90 JSR Q099 ;else store character of title 9092 E0 0B CPX #&0B ;is this the twelfth character written? 9094 90 F3 BCC Q089 ;if not then loop to write more, else: .Q096 9096 4C 81 92 JMP Q281 ;write volume catalogue and exit .Q099 ;Store character of title 9099 E0 08 CPX #&08 ;if offset is 8 or more 909B 90 04 BCC Q0A1 909D 9D F8 0E STA &0EF8,X ;then store at &0F00..3, X=8..11 90A0 60 RTS .Q0A1 90A1 9D 00 0E STA &0E00,X ;else store at &0E00..7, X=0..7 90A4 60 RTS ;*ACCESS 90A5 20 2B 89 JSR P92B ;allow wildcard characters in filename 90A8 20 EA 8F JSR PFEA ;set current file from argument 90AB A2 00 LDX #&00 ;preset X=&00 file unlocked 90AD 20 BB A4 JSR R4BB ;call GSINIT with C=0 90B0 D0 1E BNE Q0D0 ;if argument is empty .Q0B2 90B2 86 AA STX &AA ;then attribute mask = &00, file unlocked 90B4 20 3E 89 JSR P93E ;ensure matching file in catalogue .Q0B7 90B7 20 FB 9B JSR QBFB ;ensure file not open (mutex) 90BA B9 0F 0E LDA &0E0F,Y ;get directory character from catalogue 90BD 29 7F AND #&7F ;mask off old attribute 90BF 05 AA ORA &AA ;apply new attribute 90C1 99 0F 0E STA &0E0F,Y ;put back in catalogue 90C4 20 BB 89 JSR P9BB ;print *INFO line if verbose 90C7 20 6A 89 JSR P96A ;find next matching file 90CA B0 EB BCS Q0B7 ;if found then set its attribute 90CC 90 C8 BCC Q096 ;else write volume catalogue and exit .Q0CE 90CE A2 80 LDX #&80 ;found L, set bit 7 to indicate file locked: .Q0D0 90D0 20 C5 FF JSR &FFC5 ;call GSREAD, get character of attribute 90D3 B0 DD BCS Q0B2 ;if end of string then set attribute 90D5 C9 4C CMP #&4C ;else is character capital L? 90D7 F0 F5 BEQ Q0CE ;if so then set bit 7 90D9 20 51 A3 JSR R351 ;else raise "Bad attribute" error. 90DC EQUB &CF 90DD EQUS "attribute" 90E6 EQUB &00 .Q0E7 ;Raise "Disk full" error. 90E7 20 47 A3 JSR R347 90EA EQUB &C6 90EB EQUS "full" 90EF EQUB &00 .Q0F0 ;Create file from OSFILE block 90F0 20 EB 87 JSR P7EB ;set current file from argument pointer 90F3 20 63 89 JSR P963 ;search for file in catalogue 90F6 90 03 BCC Q0FB ;if found 90F8 20 9E 89 JSR P99E ;then delete catalogue entry .Q0FB 90FB A5 C2 LDA &C2 ;save start address low word 90FD 48 PHA 90FE A5 C3 LDA &C3 9100 48 PHA 9101 38 SEC ;subtract end address - start address 9102 A5 C4 LDA &C4 ;(24 bits) yielding file length 9104 E5 C2 SBC &C2 9106 85 C2 STA &C2 9108 A5 C5 LDA &C5 910A E5 C3 SBC &C3 910C 85 C3 STA &C3 910E AD 75 10 LDA &1075 9111 ED 73 10 SBC &1073 9114 85 C6 STA &C6 9116 20 2C 91 JSR Q12C ;create catalogue entry 9119 AD 74 10 LDA &1074 ;copy start address high word to data pointer 911C 8D 70 10 STA &1070 911F AD 73 10 LDA &1073 9122 8D 6F 10 STA &106F 9125 68 PLA ;restore low word to data pointer 9126 85 BF STA &BF 9128 68 PLA 9129 85 BE STA &BE 912B 60 RTS .Q12C ;Create catalogue entry 912C A9 00 LDA #&00 912E 85 C4 STA &C4 ;set MSB of LBA = 0 9130 20 8E 9F JSR QF8E ;return no. reserved sectors in data area 9133 85 C5 STA &C5 ;set as LSB of LBA 9135 AC 05 0F LDY &0F05 ;get number of files in catalogue * 8 9138 C0 F8 CPY #&F8 ;if there are already 31 files 913A B0 4C BCS Q188 ;then raise "Catalogue full" error, else: 913C 20 BA 91 JSR Q1BA ;test if new file will fit at current LBA 913F 4C 4A 91 JMP Q14A ;jump into loop .Q142 9142 F0 A3 BEQ Q0E7 ;if cat ptr = 0 then raise "Disk full" error 9144 20 7B A4 JSR R47B ;else subtract 8 from Y 9147 20 9B 91 JSR Q19B ;test if new file will fit after current file .Q14A 914A 98 TYA ;test if catalogue pointer > 0 914B 90 F5 BCC Q142 ;if file won't fit then test prev cat entry 914D 84 B0 STY &B0 ;else insert new catalogue entry here 914F AC 05 0F LDY &0F05 ;point Y to last valid catalogue entry: .Q152 9152 C4 B0 CPY &B0 ;compare pointer with insertion point 9154 F0 0F BEQ Q165 ;stop copying if insertion point reached 9156 B9 07 0E LDA &0E07,Y ;else copy current catalogue entry 9159 99 0F 0E STA &0E0F,Y ;to next slot 915C B9 07 0F LDA &0F07,Y ;leaving one slot open 915F 99 0F 0F STA &0F0F,Y ;for new catalogue entry 9162 88 DEY ;decrease pointer to work back from end 9163 B0 ED BCS Q152 ;and loop (always) .Q165 9165 20 F1 91 JSR Q1F1 ;compose top bits exec/length/load/start 9168 20 E3 91 JSR Q1E3 ;write filename+dir into catalogue at Y=0..&F0 .Q16B ;Write load/exec/length/start into catalogue 916B B5 BD LDA &BD,X ;x=8..1 copy from &BE..&C5 916D 88 DEY ;y=catalogue pointer + 7..0 916E 99 08 0F STA &0F08,Y ;copy to catalogue address fields 9171 CA DEX ;loop until 8 bytes copied 9172 D0 F7 BNE Q16B 9174 20 BB 89 JSR P9BB ;print *INFO line if verbose 9177 98 TYA ;save catalogue pointer 9178 48 PHA 9179 AC 05 0F LDY &0F05 ;get number of files in catalogue * 8 917C 20 72 A4 JSR R472 ;add 8 to Y 917F 8C 05 0F STY &0F05 ;store new file count 9182 20 81 92 JSR Q281 ;write volume catalogue 9185 68 PLA ;restore catalogue pointer 9186 A8 TAY 9187 60 RTS .Q188 ;Raise "Catalogue full" error. 9188 20 62 A3 JSR R362 918B EQUB &BE 918C EQUS "Catalogue full" 919A EQUB &00 .Q19B ;Test if new file will fit after current file 919B B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector 919E 20 5F A4 JSR R45F ;extract b5,b4 of A = MSB length 91A1 85 C4 STA &C4 ;save length in zero page (big-endian) 91A3 18 CLC 91A4 A9 FF LDA #&FF ;subtract 1 from LSB length 91A6 79 0C 0F ADC &0F0C,Y ;setting C=1 if file includes partial sector 91A9 B9 0F 0F LDA &0F0F,Y ;add LSB start LBA + 2MSB length + C 91AC 79 0D 0F ADC &0F0D,Y ;=LSB LBA after last sector of file 91AF 85 C5 STA &C5 ;save LBA in zero page (big-endian) 91B1 B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector 91B4 29 03 AND #&03 ;extract MSB start LBA 91B6 65 C4 ADC &C4 ;add MSB start LBA + MSB length + C 91B8 85 C4 STA &C4 ;=MSB LBA after last sector of file: .Q1BA ;Test if new file will fit at current LBA 91BA A5 C5 LDA &C5 ;save LSB current LBA 91BC 48 PHA 91BD 38 SEC ;subtract LSBs LBA of file - current LBA 91BE B9 07 0F LDA &0F07,Y 91C1 E5 C5 SBC &C5 91C3 85 C5 STA &C5 ;=LSB no. free sectors after file 91C5 B9 06 0F LDA &0F06,Y ;get top bits exec/length/load/start sector 91C8 29 03 AND #&03 ;extract MSB start LBA 91CA E5 C4 SBC &C4 ;subtract MSB current LBA 91CC AA TAX ;=MSB no. free sectors after file 91CD 05 C5 ORA &C5 ;are there any free sectors? 91CF D0 03 BNE Q1D4 ;if so compare with file sector size 91D1 18 CLC ;else return C=0 file won't fit. 91D2 90 0B BCC Q1DF ;[BUG] empty files don't fit on a full disc .Q1D4 91D4 A9 00 LDA #&00 ;set C=1 if LSB length = 0, no borrow: 91D6 C5 C2 CMP &C2 91D8 A5 C5 LDA &C5 ;subtract LSB free sectors - 2MSB length 91DA E5 C3 SBC &C3 91DC 8A TXA ;subtract MSB free sectors - MSB length 91DD E5 C6 SBC &C6 ;return C = 1 if file fits in free space .Q1DF 91DF 68 PLA ;restore LSB current LBA 91E0 85 C5 STA &C5 91E2 60 RTS .Q1E3 ;Write filename+dir into catalogue at Y=0..&F0 91E3 A2 00 LDX #&00 .Q1E5 91E5 B5 C7 LDA &C7,X ;get character of current filename+dir 91E7 99 08 0E STA &0E08,Y ;store in catalogue 91EA C8 INY ;increment both offsets 91EB E8 INX 91EC E0 08 CPX #&08 ;loop until 8 bytes copied. 91EE D0 F5 BNE Q1E5 91F0 60 RTS .Q1F1 ;Compose top bits exec/length/load/start 91F1 AD 71 10 LDA &1071 ;get b17,b16 exec address 91F4 29 03 AND #&03 ;place in b1,b0 of A, clear b7..b2 91F6 0A ASL A ;shift A left 2 places 91F7 0A ASL A ;a = ....ee.. 91F8 45 C6 EOR &C6 ;place b17,b16 of length in b1,b0 91FA 29 FC AND #&FC ;keep b7..b2 of A 91FC 45 C6 EOR &C6 ;a = ....eell 91FE 0A ASL A ;shift A left 2 places 91FF 0A ASL A ;a = ..eell.. 9200 4D 6F 10 EOR &106F ;place b17,b16 of load address in b1,b0 9203 29 FC AND #&FC ;keep b7..b2 of A 9205 4D 6F 10 EOR &106F ;a = ..eelldd 9208 0A ASL A ;shift A left 2 places 9209 0A ASL A ;a = eelldd.. 920A 45 C4 EOR &C4 ;place b10,b9 of start LBA in b1,b0 920C 29 FC AND #&FC ;keep b7..b2 of A 920E 45 C4 EOR &C4 ;a = eellddss 9210 85 C4 STA &C4 ;set top bits exec/length/load/start sector 9212 60 RTS ;*ENABLE 9213 A9 01 LDA #&01 ;set *ENABLE flag = 1; will be nonnegative 9215 8D D2 10 STA &10D2 ;(after FSC 8) for next *command only. 9218 60 RTS .Q219 ;Expand 18-bit load address to 32-bit 9219 48 PHA 921A A9 00 LDA #&00 ;set MSB of address = &00 921C 48 PHA 921D A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 921F 20 61 A4 JSR R461 ;extract b3,b2 of A 9222 C9 03 CMP #&03 ;if either bit clear then a Tube address 9224 D0 06 BNE Q22C ;so set high word = high word of tube address 9226 68 PLA ;else discard the high word: 9227 68 PLA .Q228 ;Set high word of OSFILE load address = &FFFF 9228 48 PHA 9229 A9 FF LDA #&FF 922B 48 PHA .Q22C ;Set high word of OSFILE load address 922C 8D 6F 10 STA &106F 922F 68 PLA 9230 8D 70 10 STA &1070 9233 68 PLA 9234 60 RTS .Q235 ;Expand 18-bit exec address to 32-bit 9235 A9 00 LDA #&00 ;clear MSB of 32-bit address 9237 8D 72 10 STA &1072 923A A5 C4 LDA &C4 ;get top bits exec/length/load/start sector 923C 20 5D A4 JSR R45D ;extract b7,b6 of A 923F C9 03 CMP #&03 ;if b7,b6 both set 9241 D0 05 BNE Q248 9243 A9 FF LDA #&FF ;then a host address, set high word = &FFFF 9245 8D 72 10 STA &1072 .Q248 9248 8D 71 10 STA &1071 ;else set 2MSB parasite address &0..2FFFF 924B 60 RTS ;*RENAME 924C 20 2F 89 JSR P92F ;disallow wildcard characters in filename 924F 20 EA 8F JSR PFEA ;set current file from argument 9252 A5 CF LDA &CF ;get current volume 9254 48 PHA 9255 98 TYA ;save command line offset 9256 48 PHA 9257 20 3E 89 JSR P93E ;ensure matching file in catalogue 925A 20 F8 9B JSR QBF8 ;ensure file not locked or open (mutex) 925D 84 B3 STY &B3 ;save pointer to file entry 925F 68 PLA ;restore command line offset 9260 A8 TAY 9261 20 EA 8F JSR PFEA ;set current file from argument 9264 68 PLA ;restore current volume 9265 C5 CF CMP &CF ;compare with destination volume 9267 F0 03 BEQ Q26C ;if equal then rename the file #if defined _DDOS357 9269 4C CC B9 JMP S9CC ;else rename across volumes, "Bad command". #else 9269 4C F8 94 JMP Q4F8 ;else rename across volumes, "Bad command". #endif .Q26C 926C 20 63 89 JSR P963 ;search for file in catalogue 926F 90 0B BCC Q27C ;if not found then update filename+dir 9271 20 5A A3 JSR R35A ;else raise "File exists" error. 9274 EQUB &C4 9275 EQUS "exists" 927B EQUB &00 .Q27C ;Update filename+dir in catalogue 927C A4 B3 LDY &B3 ;get pointer to file entry 927E 20 E3 91 JSR Q1E3 ;write filename+dir into catalogue: .Q281 ;Write volume catalogue L4 9281 18 CLC ;add 1 to BCD catalogue cycle number 9282 F8 SED 9283 AD 04 0F LDA &0F04 9286 69 01 ADC #&01 9288 8D 04 0F STA &0F04 928B D8 CLD 928C 20 5E 93 JSR Q35E ;set &1000 = write, claim NMI 928F 4C A4 92 JMP Q2A4 ;transfer volume catalogue and exit .Q292 ;Ensure current volume catalogue loaded 9292 AD 84 10 LDA &1084 ;get drive and volume of loaded catalogue 9295 C5 CF CMP &CF ;compare with current drive and volume 9297 D0 05 BNE Q29E ;if unequal then load volume catalogue #if defined _DDOS316 9299 20 E0 B9 JSR S9E0 ;load FDC status register #elif defined _DDOS336 9299 20 D8 B9 JSR S9D8 ;load FDC status register #else 9299 20 FB B9 JSR S9FB ;load FDC status register #endif 929C F0 25 BEQ Q2C3 ;if motor is on then finish .Q29E 929E 20 00 A3 JSR R300 ;else save AXY .Q2A1 ;Load volume catalogue L4 92A1 20 55 93 JSR Q355 ;set &1000 = read, claim NMI: .Q2A4 ;Transfer volume catalogue 92A4 A9 00 LDA #&00 92A6 8D D5 10 STA &10D5 ;transferring to host, not Tube 92A9 20 D6 A7 JSR R7D6 ;set up for current drive 92AC 20 A4 A5 JSR R5A4 ;detect disc format/set sector address 92AF A5 CF LDA &CF ;get current volume 92B1 8D 84 10 STA &1084 ;set drive and volume of loaded catalogue 92B4 20 D3 92 JSR Q2D3 ;transfer disc/volume catalogue L3 92B7 F0 0A BEQ Q2C3 ;if zero status release NMI and exit 92B9 29 40 AND #&40 92BB D0 03 BNE Q2C0 ;else if b6=0 WD1770 S6 = write protect #if defined _DDOS316 92BD 4C 95 B9 JMP S995 ;then raise "Disk fault" error #elif defined _DDOS336 92BD 4C 93 B9 JMP S993 ;then raise "Disk fault" error #elif defined _DDOS357 92BD 4C B2 B9 JMP S9B2 ;then raise "Disk fault" error #else 92BD 4C B6 B9 JMP S9B6 ;then raise "Disk fault" error #endif .Q2C0 92C0 4C 38 A3 JMP R338 ;else raise "Disk read only" error. .Q2C3 92C3 4C A7 A7 JMP R7A7 ;release NMI and exit. ;unreachable code 92C6 A9 00 LDA #&00 ;data transfer call &00 = read data 92C8 8D 00 10 STA &1000 ;set data transfer call number 92CB 4C D3 92 JMP Q2D3 ;transfer disc/volume catalogue L3 .Q2CE ;Write disc/volume catalogue L3 92CE A9 01 LDA #&01 ;data transfer call &01 = write data 92D0 8D 00 10 STA &1000 ;set data transfer call number .Q2D3 ;Transfer disc/volume catalogue L3 #if defined _TURBO 92D3 20 2D A3 JSR R32D ;save XY #else 92D3 20 29 A3 JSR R329 ;save XY #endif 92D6 20 ED 92 JSR Q2ED ;set data pointer to &0E00 92D9 A2 03 LDX #&03 ;set X = &03, three possible attempts: .Q2DB 92DB A9 00 LDA #&00 ;512 bytes to transfer 92DD 85 A0 STA &A0 92DF A9 02 LDA #&02 92E1 85 A1 STA &A1 92E3 20 67 B4 JSR S467 ;transfer data L2 92E6 F0 04 BEQ Q2EC ;if zero status then success, return 92E8 CA DEX ;else decrement attempts counter 92E9 D0 F0 BNE Q2DB ;if not tried 3 times then try again 92EB CA DEX ;else return Z=0, failed .Q2EC 92EC 60 RTS .Q2ED ;Set data pointer to &0E00 92ED A9 00 LDA #&00 92EF 85 A6 STA &A6 92F1 A9 0E LDA #&0E 92F3 85 A7 STA &A7 92F5 60 RTS #if defined _BUGFIX .Q2F6 92F6 48 PHA ;save FDC command 92F7 A9 40 LDA #&40 ;instruction at &0D00 = RTI 92F9 8D 00 0D STA &0D00 92FC 68 PLA ;restore FDC command # if defined _DDOS316 92FD 4C BB B6 JMP S6BB ;and write it to command register # elif defined _DDOS336 92FD 4C BB B6 JMP S6BB ;and write it to command register # else 92FD 4C B9 B6 JMP S6B9 ;and write it to command register # endif #else ;unreachable code 92F6 AD 82 10 LDA &1082 ;load Tube call number 92F9 48 PHA 92FA AD D5 10 LDA &10D5 ;load Tube flag, A>0 if Tube in use 92FD 4C 1C 93 JMP Q31C ;call Tube service #endif .Q300 ;Open Tube data transfer channel 9300 48 PHA 9301 8D 82 10 STA &1082 ;a=Tube service call, save in stack and wksp 9304 A5 BE LDA &BE ;reform address at &106D..70 from &BE,F 9306 8D 6D 10 STA &106D 9309 A5 BF LDA &BF 930B 8D 6E 10 STA &106E 930E AD 6F 10 LDA &106F ;and high bytes of address 9311 2D 70 10 AND &1070 ;a=&FF if address is in the host 9314 0D D6 10 ORA &10D6 ;a=&FF if Tube absent (&10D6=NOT MOS flag!) 9317 49 FF EOR #&FF ;invert; A>0 if transferring over Tube 9319 8D D5 10 STA &10D5 ;store Tube flag #if !defined _BUGFIX .Q31C ;Call Tube service, Z=1 if Tube unused #endif 931C 38 SEC 931D F0 0D BEQ Q32C ;if A=0 then no need for Tube, exit C=1 931F 20 2E 93 JSR Q32E ;else claim Tube 9322 A2 6D LDX #&6D ;point XY at address 9324 A0 10 LDY #&10 9326 68 PLA ;restore Tube call number 9327 48 PHA 9328 20 06 04 JSR &0406 ;call Tube service 932B 18 CLC ;exit C=0 as Tube was called .Q32C 932C 68 PLA ;preserve Tube call number on exit 932D 60 RTS .Q32E ;Claim Tube 932E 48 PHA .Q32F 932F A9 C1 LDA #&C1 ;tube service call = &C0 + ID for DFS (1) 9331 20 06 04 JSR &0406 ;call Tube service 9334 90 F9 BCC Q32F ;loop until C=1, indicating claim granted 9336 68 PLA 9337 60 RTS .Q338 ;Release Tube 9338 48 PHA 9339 AD D5 10 LDA &10D5 ;load Tube flag, A>0 if Tube in use 933C F0 05 BEQ Q343 ;if not in use then exit, else: .Q33E 933E A9 81 LDA #&81 ;tube service call = &80 + ID for DFS (1) 9340 20 06 04 JSR &0406 ;call Tube service .Q343 9343 68 PLA 9344 60 RTS .Q345 ;Release Tube if present 9345 48 PHA 9346 A9 EA LDA #&EA ;OSBYTE &EA = read Tube presence flag 9348 20 1E A8 JSR R81E ;call OSBYTE with X=0, Y=&FF 934B 8A TXA ;test X, X=&FF if Tube present 934C D0 F0 BNE Q33E ;if Tube present then release Tube 934E 68 PLA 934F 60 RTS .Q350 ;Prepare to read to user memory 9350 A9 01 LDA #&01 ;Tube service 1 = write single bytes to R3 9352 20 00 93 JSR Q300 ;open Tube data transfer channel .Q355 9355 A9 00 LDA #&00 ;data transfer call &00 = read data 9357 F0 07 BEQ Q360 ;branch (always) .Q359 ;Prepare to write from user memory 9359 A9 00 LDA #&00 ;Tube service 0 = read single bytes from R3 935B 20 00 93 JSR Q300 ;open Tube data transfer channel .Q35E 935E A9 01 LDA #&01 ;data transfer call &01 = write data .Q360 9360 8D 00 10 STA &1000 ;set data transfer call number 9363 20 C1 A7 JSR R7C1 ;claim NMI 9366 A9 FF LDA #&FF 9368 8D 84 10 STA &1084 ;no catalogue in pages &0E..F 936B 60 RTS #if defined _DDOS357 ;*TAPEDISK 936C 20 E2 A2 JSR R2E2 ;save XY 936F 8E ED 02 STX &02ED ;store filename address in MOS OSFILE block 9372 8C EE 02 STY &02EE 9375 20 AC 9F JSR QFAC ;get start and size of user memory 9378 AD 89 10 LDA &1089 ;get start of user memory 937B 8D F0 02 STA &02F0 ;set as load address of OSFILE block 937E A9 00 LDA #&00 ;loading starts on page boundary 9380 8D EF 02 STA &02EF ;[BUG] loads to coprocessor memory! 9383 20 09 94 JSR Q409 ;clear top of MOS OSFILE block 9386 A2 0C LDX #&0C ;x = &0C 1200 baud 9388 A9 8C LDA #&8C ;OSBYTE &8C = *TAPE 938A 20 F4 FF JSR &FFF4 ;call OSBYTE 938D A9 FF LDA #&FF ;a=&FF load file 938F 20 02 94 JSR Q402 ;call OSFILE using MOS OSFILE block 9392 A2 16 LDX #&16 ;point XY to *DISC command 9394 A0 94 LDY #&94 9396 20 F7 FF JSR &FFF7 ;call OSCLI 9399 A9 B2 LDA #&B2 ;point filename field to last read CFS block 939B 8D ED 02 STA &02ED ;&03B2 begins with NUL-terminated filename 939E A9 03 LDA #&03 93A0 8D EE 02 STA &02EE 93A3 A2 00 LDX #&00 .Q3A5 93A5 BD B2 03 LDA &03B2,X ;scan filename of last CFS block read 93A8 F0 05 BEQ Q3AF ;until NUL found 93AA E8 INX 93AB E0 07 CPX #&07 ;or 7 characters scanned 93AD D0 F6 BNE Q3A5 ;(no allowance for directory specifiers) .Q3AF 93AF A9 0D LDA #&0D ;terminate filename with CR 93B1 9D B2 03 STA &03B2,X 93B4 20 1B 94 JSR Q41B ;calculate CFS file length 93B7 A5 B0 LDA &B0 ;round up to whole number of pages in &B1 93B9 F0 02 BEQ Q3BD 93BB E6 B1 INC &B1 .Q3BD 93BD AD 8B 10 LDA &108B ;compare available memory - file size 93C0 C5 B1 CMP &B1 93C2 B0 13 BCS Q3D7 ;if file fit in memory then continue 93C4 20 5A A3 JSR R35A ;else "File size too large" error (too late!) 93C7 EQUB &D4 93C8 EQUS "size too large" 93D6 EQUB &00 .Q3D7 93D7 20 1B 94 JSR Q41B ;calculate CFS file length 93DA A9 00 LDA #&00 ;set OSFILE start address = start of user mem 93DC 8D F7 02 STA &02F7 93DF AD 89 10 LDA &1089 93E2 8D F8 02 STA &02F8 93E5 18 CLC ;set end address = start addr + length of file 93E6 65 B1 ADC &B1 93E8 8D FC 02 STA &02FC 93EB A5 B0 LDA &B0 93ED 8D FB 02 STA &02FB 93F0 A9 00 LDA #&00 ;a=&00 save file 93F2 20 02 94 JSR Q402 ;call OSFILE using MOS OSFILE block 93F5 A2 07 LDX #&07 ;8 bytes to copy, 7..0: .Q3F7 93F7 BD BE 03 LDA &03BE,X ;copy load and exec addresses from CFS block 93FA 9D EF 02 STA &02EF,X ;to OSFILE block 93FD CA DEX 93FE 10 F7 BPL Q3F7 9400 A9 01 LDA #&01 ;a=&01 write catalogue information: .Q402 ;Call OSFILE using MOS OSFILE block 9402 A2 ED LDX #&ED 9404 A0 02 LDY #&02 9406 4C DD FF JMP &FFDD ;call OSFILE and exit .Q409 ;Clear top of MOS OSFILE block 9409 A2 04 LDX #&04 ;start at top half of load address field 940B A9 00 LDA #&00 ;a=&00 write zeroes .Q40D 940D 9D ED 02 STA &02ED,X ;clear load, exec, length, attribute fields 9410 E8 INX 9411 E0 11 CPX #&11 9413 90 F8 BCC Q40D 9415 60 RTS #else /* _DDOS357 */ ;*TAPEDISK 936C 20 E2 A2 JSR R2E2 ;save XY 936F 8E EE 02 STX &02EE ;store filename address in MOS OSFILE block 9372 8C EF 02 STY &02EF 9375 20 AC 9F JSR QFAC ;get start and size of user memory 9378 AD 89 10 LDA &1089 ;get start of user memory 937B 8D F1 02 STA &02F1 ;set as load address of OSFILE block 937E A9 00 LDA #&00 ;loading starts on page boundary 9380 8D F0 02 STA &02F0 ;[BUG] loads to coprocessor memory! 9383 20 09 94 JSR Q409 ;clear top of MOS OSFILE block 9386 A2 0C LDX #&0C ;x = &0C 1200 baud 9388 A9 8C LDA #&8C ;OSBYTE &8C = *TAPE 938A 20 F4 FF JSR &FFF4 ;call OSBYTE 938D A9 FF LDA #&FF ;a=&FF load file 938F 20 02 94 JSR Q402 ;call OSFILE using MOS OSFILE block 9392 A2 16 LDX #&16 ;point XY to *DISC command 9394 A0 94 LDY #&94 9396 20 F7 FF JSR &FFF7 ;call OSCLI 9399 A9 B2 LDA #&B2 ;point filename field to last read CFS block 939B 8D EE 02 STA &02EE ;&03B2 begins with NUL-terminated filename 939E A9 03 LDA #&03 93A0 8D EF 02 STA &02EF 93A3 A2 00 LDX #&00 .Q3A5 93A5 BD B2 03 LDA &03B2,X ;scan filename of last CFS block read 93A8 F0 05 BEQ Q3AF ;until NUL found 93AA E8 INX 93AB E0 07 CPX #&07 ;or 7 characters scanned 93AD D0 F6 BNE Q3A5 ;(no allowance for directory specifiers) .Q3AF 93AF A9 0D LDA #&0D ;terminate filename with CR 93B1 9D B2 03 STA &03B2,X 93B4 20 1B 94 JSR Q41B ;calculate CFS file length 93B7 A5 B0 LDA &B0 ;round up to whole number of pages in &B1 93B9 F0 02 BEQ Q3BD 93BB E6 B1 INC &B1 .Q3BD 93BD AD 8B 10 LDA &108B ;compare available memory - file size 93C0 C5 B1 CMP &B1 93C2 B0 13 BCS Q3D7 ;if file fit in memory then continue 93C4 20 5A A3 JSR R35A ;else "File size too large" error (too late!) 93C7 EQUB &D4 93C8 EQUS "size too large" 93D6 EQUB &00 .Q3D7 93D7 20 1B 94 JSR Q41B ;calculate CFS file length 93DA A9 00 LDA #&00 ;set OSFILE start address = start of user mem 93DC 8D F8 02 STA &02F8 93DF AD 89 10 LDA &1089 93E2 8D F9 02 STA &02F9 93E5 18 CLC ;set end address = start addr + length of file 93E6 65 B1 ADC &B1 93E8 8D FD 02 STA &02FD 93EB A5 B0 LDA &B0 93ED 8D FC 02 STA &02FC 93F0 A9 00 LDA #&00 ;a=&00 save file 93F2 20 02 94 JSR Q402 ;call OSFILE using MOS OSFILE block 93F5 A2 07 LDX #&07 ;8 bytes to copy, 7..0: .Q3F7 93F7 BD BE 03 LDA &03BE,X ;copy load and exec addresses from CFS block 93FA 9D F0 02 STA &02F0,X ;to OSFILE block 93FD CA DEX 93FE 10 F7 BPL Q3F7 9400 A9 01 LDA #&01 ;a=&01 write catalogue information: .Q402 ;Call OSFILE using MOS OSFILE block 9402 A2 EE LDX #&EE 9404 A0 02 LDY #&02 9406 4C DD FF JMP &FFDD ;call OSFILE and exit .Q409 ;Clear top of MOS OSFILE block 9409 A2 04 LDX #&04 ;start at top half of load address field 940B A9 00 LDA #&00 ;a=&00 write zeroes .Q40D 940D 9D EE 02 STA &02EE,X ;clear load, exec, length, attribute fields 9410 E8 INX 9411 E0 11 CPX #&11 9413 90 F8 BCC Q40D 9415 60 RTS #endif /* _DDOS357 */ 9416 EQUS "DISC" ;*DISC command string 941A EQUB &0D .Q41B ;Calculate CFS file length 941B AD C8 03 LDA &03C8 ;get LSB length of last block of file 941E 85 B0 STA &B0 ;store LSB length of file 9420 18 CLC ;set c=0 9421 AD C6 03 LDA &03C6 ;get LSB number of last block 9424 6D C9 03 ADC &03C9 ;add MSB length of file (0 or 1) 9427 85 B1 STA &B1 ;store MSB length of file 9429 60 RTS ;*ROMID 942A 20 F3 A2 JSR R2F3 ;have A=0 returned on exit 942D AD 99 A8 LDA &A899 ;get version number integer part 9430 18 CLC ;c=0 to enable space padding 9431 20 B4 A2 JSR R2B4 ;print hex byte, C=0 if space-padded 9434 20 01 A4 JSR R401 ;print a dot 9437 AD 9A A8 LDA &A89A ;get version number decimal part 943A 20 29 A4 JSR R429 ;print hex byte 943D 20 C9 A2 JSR R2C9 ;print two spaces 9440 A0 02 LDY #&02 ;repeat with offset 2..4: .Q442 9442 B9 99 A8 LDA &A899,Y ;get byte of release date dd/mm/yy 9445 20 29 A4 JSR R429 ;print hex byte 9448 C8 INY 9449 C0 05 CPY #&05 ;move on at offset 5 944B F0 08 BEQ Q455 944D A9 2D LDA #&2D ;else print a dash 944F 20 03 A4 JSR R403 ;print character in A (OSASCI) 9452 4C 42 94 JMP Q442 ;and loop .Q455 9455 20 CC A2 JSR R2CC ;print a space 9458 18 CLC ;c=0 to enable space padding 9459 A2 03 LDX #&03 ;repeat with offsets 5..7: .Q45B 945B B9 99 A8 LDA &A899,Y ;get byte of release number 945E 20 B4 A2 JSR R2B4 ;print hex byte, C=0 if space-padded 9461 C8 INY ;increment offset 9462 CA DEX ;decrement counter 9463 D0 F6 BNE Q45B ;loop until 3 bytes printed 9465 4C 67 84 JMP P467 ;print newline and exit #if defined _DDOS357 .Q468 #endif ;FSC 9468 C9 09 CMP #&09 ;if call outside range 0..8 946A B0 0E BCS Q47A ;then exit 946C 86 B5 STX &B5 ;else save X 946E AA TAX ;transfer call number to X as index 946F BD 4A A8 LDA &A84A,X ;get action address high byte 9472 48 PHA ;save on stack 9473 BD 41 A8 LDA &A841,X ;get action address low byte 9476 48 PHA ;save on stack 9477 8A TXA ;restore call number to A 9478 A6 B5 LDX &B5 ;restore X on entry .Q47A 947A 60 RTS ;jump to action address ;FSC 0 = *OPT 947B 20 00 A3 JSR R300 ;save AXY 947E 8A TXA 947F C9 04 CMP #&04 ;is it *OPT 4? 9481 F0 19 BEQ Q49C ;if so go and set boot option 9483 C9 02 CMP #&02 ;else is it *OPT 0 or *OPT 1? 9485 90 0B BCC Q492 ;if so go and set monitoring option 9487 20 51 A3 JSR R351 ;else raise "Bad option" error. 948A EQUB &CB 948B EQUS "option" 9491 EQUB &00 .Q492 ;*OPT 0 / *OPT 1 monitor 9492 A2 FF LDX #&FF 9494 98 TYA ;is verbosity level =0? 9495 F0 01 BEQ Q498 ;if so then set flag = &FF 9497 E8 INX ;else level >0, set flag = 0. .Q498 9498 8E D1 10 STX &10D1 949B 60 RTS .Q49C ;*OPT 4 set boot option 949C 98 TYA ;save requested option 949D 48 PHA 949E 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive 94A1 20 A1 92 JSR Q2A1 ;load volume catalogue 94A4 68 PLA ;restore option 94A5 20 6D A4 JSR R46D ;shift A left 4 places 94A8 4D 06 0F EOR &0F06 ;xor new option with old 94AB 29 30 AND #&30 ;clear all but option bits 5,4 94AD 4D 06 0F EOR &0F06 ;b5,4 contain new option, others preserved 94B0 8D 06 0F STA &0F06 ;store new option in catalogue 94B3 4C 81 92 JMP Q281 ;write volume catalogue and exit. #if defined _DFSFIX .Q4B6 #endif ;FSC 1 = read EOF state 94B6 48 PHA ;save AY 94B7 98 TYA 94B8 48 PHA 94B9 8A TXA ;transfer file handle to Y 94BA A8 TAY 94BB 20 A7 98 JSR Q8A7 ;ensure file handle valid and open 94BE 98 TYA ;a=y = channel workspace pointer 94BF 20 B4 9A JSR QAB4 ;compare PTR - EXT 94C2 D0 04 BNE Q4C8 ;if PTR <> EXT (blech!) then return 0 94C4 A2 FF LDX #&FF ;else return &FF, we are at end of file 94C6 D0 02 BNE Q4CA .Q4C8 94C8 A2 00 LDX #&00 .Q4CA 94CA 68 PLA ;restore AY and exit 94CB A8 TAY 94CC 68 PLA 94CD 60 RTS #if defined _DDOS357 .Q4CE 94CE C9 0B CMP #&0B ;if call number is not 11 94D0 D0 96 BNE Q468 ;then serve other FSC calls, else: ;FSC 2/4/11 = */, *RUN, *RUN from library 94D2 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 94D5 F0 01 BEQ Q4D8 ;always branch ;FSC 3 with *command not in table 94D7 0A ASL A ;ensure A is even: .Q4D8 94D8 85 B5 STA &B5 ;save call number (<> &0B from FSC 3) 94DA 20 3E 95 JSR Q53E ;copy argument ptr and load to cat address 94DD 8C DA 10 STY &10DA ;store offset of start of command line 94E0 20 EB 87 JSR P7EB ;set current file from argument pointer 94E3 8C D9 10 STY &10D9 ;store offset of command line tail 94E6 20 63 89 JSR P963 ;search for file in catalogue 94E9 B0 19 BCS Q504 ;if found then execute command binary 94EB AC DA 10 LDY &10DA 94EE AD CC 10 LDA &10CC ;get library directory 94F1 85 CE STA &CE ;set as current directory 94F3 AD CD 10 LDA &10CD ;get library drive and volume 94F6 20 03 A5 JSR R503 ;select volume in A 94F9 20 EE 87 JSR P7EE ;parse file spec from argument pointer 94FC 20 63 89 JSR P963 ;search for file in catalogue 94FF B0 03 BCS Q504 ;if found then execute it 9501 4C BF B9 JMP S9BF ;else issue FSC 11 or raise "Bad command" #else /* _DDOS357 */ ;FSC 2 = */; FSC 4 = *RUN 94CE 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 ;FSC 3 with *command not in table 94D1 20 3E 95 JSR Q53E ;copy argument ptr and load to cat address 94D4 8C DA 10 STY &10DA ;store offset of start of command line 94D7 20 EB 87 JSR P7EB ;set current file from argument pointer 94DA 8C D9 10 STY &10D9 ;store offset of command line tail 94DD 20 63 89 JSR P963 ;search for file in catalogue 94E0 B0 22 BCS Q504 ;if found then execute command binary 94E2 AC DA 10 LDY &10DA 94E5 AD CC 10 LDA &10CC ;get library directory 94E8 85 CE STA &CE ;set as current directory 94EA AD CD 10 LDA &10CD ;get library drive and volume 94ED 20 03 A5 JSR R503 ;select volume in A 94F0 20 EE 87 JSR P7EE ;parse file spec from argument pointer 94F3 20 63 89 JSR P963 ;search for file in catalogue 94F6 B0 0C BCS Q504 ;if found then execute it .Q4F8 94F8 20 51 A3 JSR R351 ;else raise "Bad command" error. 94FB EQUB &FE 94FC EQUS "command" 9503 EQUB &00 #endif /* _DDOS357 */ .Q504 ;Execute command binary 9504 20 5F 9B JSR QB5F ;load file into memory 9507 18 CLC 9508 AD D9 10 LDA &10D9 ;get offset of command line tail 950B A8 TAY ;and pass to command in Y (if on host) 950C 65 F2 ADC &F2 ;add it to GSINIT pointer in &F2,3 950E 8D D9 10 STA &10D9 ;giving command line tail pointer 9511 A5 F3 LDA &F3 ;save it in &10D9,A for OSARGS 1 9513 69 00 ADC #&00 9515 8D DA 10 STA &10DA 9518 AD 71 10 LDA &1071 ;and high bytes of address 951B 2D 72 10 AND &1072 ;a=&FF if address is in the host 951E 0D D6 10 ORA &10D6 ;a=&FF if Tube absent (&10D6=NOT MOS flag!) 9521 C9 FF CMP #&FF ;if host address or Tube absent 9523 F0 16 BEQ Q53B ;then jump indirect 9525 A5 C0 LDA &C0 ;else copy low word of exec address 9527 8D 6F 10 STA &106F ;over high word of load addr in OSFILE block 952A A5 C1 LDA &C1 952C 8D 70 10 STA &1070 952F 20 2E 93 JSR Q32E ;claim Tube 9532 A2 6F LDX #&6F ;point XY to 32-bit execution address 9534 A0 10 LDY #&10 9536 A9 04 LDA #&04 ;tube service call &04 = *Go 9538 4C 06 04 JMP &0406 ;jump into Tube service .Q53B ;Execute command on host #if defined _BUGFIX 953B 4C 2B A9 JMP R92B ;emulate Acorn DFS entry conditions #else 953B 6C C0 00 JMP (&00C0) #endif .Q53E ;Copy argument ptr and load to cat address 953E A9 FF LDA #&FF ;lsb exec address in our OSFILE block = &FF: 9540 85 C0 STA &C0 ;load executable to load address in catalogue 9542 A5 F2 LDA &F2 ;copy GSINIT string pointer to zero page 9544 85 BC STA &BC ;= command line pointer 9546 A5 F3 LDA &F3 9548 85 BD STA &BD 954A 60 RTS ;FSC 3 = unrecognised *command 954B 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 954E A2 8A LDX #&8A ;point XY to command table at &8D8A 9550 A0 8D LDY #&8D 9552 A9 00 LDA #&00 ;zero offset, *command starts at XY 9554 20 C7 8E JSR PEC7 ;search for command or keyword in table 9557 BA TSX 9558 86 B8 STX &B8 ;save stack pointer to restore on abort #if defined _DDOS357 955A 4C C7 80 JMP P0C7 ;execute command #else 955A 4C CC 80 JMP P0CC ;execute command #endif ;FSC 5 = *CAT 955D 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 9560 20 E5 A4 JSR R4E5 ;select specified or default volume .Q563 9563 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 9566 20 D6 8B JSR PBD6 ;print volume title 9569 20 00 8C JSR PC00 ;print disc type and volume list 956C 20 7F 8C JSR PC7F ;print volume spec and boot option 956F 20 B7 8C JSR PCB7 ;print CSD and library directories 9572 4C 02 8B JMP PB02 ;list files in catalogue .Q575 ;FSC 6 = new filing system starting up 9575 20 00 A3 JSR R300 ;save AXY 9578 A9 77 LDA #&77 ;call OSBYTE &77 = close *SPOOL/*EXEC files 957A 4C F4 FF JMP &FFF4 ;FSC 7 = return range of valid file handles 957D A2 11 LDX #&11 957F A0 15 LDY #&15 9581 60 RTS ;FSC 8 = *command has been entered 9582 2C D2 10 BIT &10D2 ;if *ENABLEd flag b7=0 (i.e. byte = 0 or 1) 9585 30 03 BMI Q58A 9587 CE D2 10 DEC &10D2 ;then enable this command, not the ones after .Q58A 958A A9 FF LDA #&FF 958C 8D 84 10 STA &1084 ;no catalogue in pages &0E..F 958F 60 RTS .Q590 ;Ensure open file still in drive 9590 20 97 A5 JSR R597 ;set current vol/dir from open filename .Q593 ;Ensure open file still on current volume 9593 A2 07 LDX #&07 ;start at seventh character of leaf name: .Q595 9595 B9 0C 11 LDA &110C,Y ;copy leaf name of file to current leaf name 9598 95 C6 STA &C6,X 959A 88 DEY ;skip odd bytes containing length and addrs 959B 88 DEY ;select previous character of leaf name (Y>0) 959C CA DEX ;decrement offset in current leaf name 959D D0 F6 BNE Q595 ;loop until 7 characters copied (X=7..1) 959F 20 63 89 JSR P963 ;search for file in catalogue 95A2 90 1A BCC Q5BE ;if file not found then raise "Disk changed" 95A4 8C C7 10 STY &10C7 ;else save offset in catalogue 95A7 B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector 95AA BE 0F 0F LDX &0F0F,Y ;put LSB start sector in X 95AD AC C5 10 LDY &10C5 ;put channel workspace pointer in Y 95B0 59 0D 11 EOR &110D,Y ;compare start sector with one in workspace 95B3 29 03 AND #&03 ;mask off other fields 95B5 D0 07 BNE Q5BE ;if not equal then raise "Disk changed" error 95B7 8A TXA ;else compare low bytes of start sector (LBA) 95B8 D9 0F 11 CMP &110F,Y 95BB D0 01 BNE Q5BE ;if not equal then raise "Disk changed" error 95BD 60 RTS ;else exit .Q5BE 95BE 4C 95 88 JMP P895 ;raise "Disk changed" error #if defined _DFSFIX .Q5C1 #endif ;OSFIND 95C1 C9 00 CMP #&00 95C3 D0 62 BNE Q627 ;if A>0 then open a file 95C5 20 00 A3 JSR R300 ;else close a file/all files. save AXY .Q5C8 95C8 98 TYA ;if handle = 0 95C9 F0 08 BEQ Q5D3 ;then close all files 95CB 20 93 98 JSR Q893 ;else convert to pointer, if valid (&11..17) 95CE 90 12 BCC Q5E2 ;then close file 95D0 4C C6 98 JMP Q8C6 ;else raise "Channel" error. .Q5D3 ;Close all files 95D3 20 75 95 JSR Q575 ;close *SPOOL/*EXEC files .Q5D6 95D6 A9 A0 LDA #&A0 ;set channel workspace pointer = &A0: .Q5D8 95D8 A8 TAY ;transfer channel workspace pointer to Y 95D9 20 E2 95 JSR Q5E2 ;close file 95DC 38 SEC ;subtract &20 to point to next channel 95DD E9 20 SBC #&20 95DF D0 F7 BNE Q5D8 ;if >0 then loop (close 5 files &A0..20). 95E1 60 RTS .Q5E2 ;Close file L7 95E2 48 PHA 95E3 20 63 98 JSR Q863 ;validate workspace offset 95E6 B0 3A BCS Q622 ;if channel invalid or closed then exit 95E8 B9 1B 11 LDA &111B,Y ;else get bit mask corresponding to channel 95EB 49 FF EOR #&FF ;invert it, bit corresponding to channel =0 95ED 2D C3 10 AND &10C3 ;clear bit of channel open flag byte 95F0 8D C3 10 STA &10C3 ;update flag byte 95F3 B9 17 11 LDA &1117,Y ;get channel flags 95F6 29 60 AND #&60 ;if either buffer or EXT changed 95F8 F0 28 BEQ Q622 95FA 20 90 95 JSR Q590 ;then ensure open file still in drive 95FD B9 17 11 LDA &1117,Y ;if EXT changed 9600 29 20 AND #&20 9602 F0 1B BEQ Q61F 9604 AE C7 10 LDX &10C7 ;then set X = catalogue pointer 9607 B9 14 11 LDA &1114,Y ;copy low word of EXT to length in catalogue 960A 9D 0C 0F STA &0F0C,X 960D B9 15 11 LDA &1115,Y 9610 9D 0D 0F STA &0F0D,X 9613 B9 16 11 LDA &1116,Y ;get high byte of EXT 9616 20 F0 8F JSR PFF0 ;pack b17,16 of length into catalogue entry 9619 20 81 92 JSR Q281 ;write volume catalogue 961C AC C5 10 LDY &10C5 ;put channel workspace pointer in Y .Q61F 961F 20 51 99 JSR Q951 ;ensure buffer up-to-date on disc L6 .Q622 9622 AE C9 10 LDX &10C9 ;restore X on entry 9625 68 PLA ;restore A on entry 9626 60 RTS .Q627 ;Open a file #if defined _TURBO 9627 20 2D A3 JSR R32D ;save XY #else 9627 20 29 A3 JSR R329 ;save XY #endif 962A 86 BC STX &BC 962C 84 BD STY &BD 962E 85 B4 STA &B4 ;store file open mode in temporary var. 9630 24 B4 BIT &B4 ;set N and V from temporary variable 9632 08 PHP 9633 20 EB 87 JSR P7EB ;set current file from argument pointer 9636 20 32 97 JSR Q732 ;find unused file handle 9639 90 18 BCC Q653 ;if all file handles in use 963B 20 62 A3 JSR R362 ;then raise "Too many files open" error. 963E EQUB &C0 963F EQUS "Too many files open" 9652 EQUB &00 .Q653 9653 A2 C7 LDX #&C7 ;point XY+A to current filename 9655 A9 00 LDA #&00 9657 A8 TAY 9658 20 53 97 JSR Q753 ;compare filename at XY+A with open filenames 965B 90 17 BCC Q674 ;if file not open then continue .Q65D 965D B9 0C 11 LDA &110C,Y ;else test if the channel is open read-write 9660 10 04 BPL Q666 ;if so, reopening is a conflict; raise error 9662 28 PLP ;else if reopening a r-o channel read-only 9663 08 PHP ;(i.e. channel b7=1, OSFIND call no. b7=0) 9664 10 09 BPL Q66F ;then this is also safe; continue ;NB loop is redundant; can BPL Q674 instead .Q666 9666 20 5A A3 JSR R35A ;else reopening a r-o channel r-w is conflict 9669 EQUB &C2 ;raise "File open" error. 966A EQUS "open" 966E EQUB &00 .Q66F 966F 20 6A 97 JSR Q76A ;find any other channels open on this file 9672 B0 E9 BCS Q65D ;if another channel found then loop .Q674 9674 20 2F 89 JSR P92F ;disallow wildcard characters in filename 9677 20 63 89 JSR P963 ;search for file in catalogue 967A B0 18 BCS Q694 ;if not found 967C A9 00 LDA #&00 ;then preset A=0, no file handle to return 967E 28 PLP ;if opening for read or update 967F 50 01 BVC Q682 ;(i.e. OSFIND call no. b6=1) 9681 60 RTS ;then existing file was expected, return A=0 .Q682 9682 08 PHP 9683 A2 07 LDX #&07 ;else opening new file for output. .Q685 9685 95 BE STA &BE,X ;clear load, exec, start and length = 0 9687 9D 6F 10 STA &106F,X 968A CA DEX 968B 10 F8 BPL Q685 968D A9 40 LDA #&40 ;initial length = &4000 = 16 KiB 968F 85 C5 STA &C5 9691 20 F0 90 JSR Q0F0 ;create file from OSFILE block .Q694 9694 98 TYA ;transfer catalogue pointer to X 9695 AA TAX 9696 28 PLP 9697 08 PHP 9698 70 03 BVS Q69D ;if opening for output (OSFIND b6=0) 969A 20 E8 9B JSR QBE8 ;then ensure file not locked .Q69D 969D A9 08 LDA #&08 ;set counter = 8 969F 8D C8 10 STA &10C8 96A2 AC C5 10 LDY &10C5 ;put channel workspace pointer in Y .Q6A5 96A5 BD 08 0E LDA &0E08,X ;copy name and attributes of file 96A8 99 00 11 STA &1100,Y ;to bottom half of channel workspace 96AB C8 INY 96AC BD 08 0F LDA &0F08,X 96AF 99 00 11 STA &1100,Y 96B2 C8 INY 96B3 E8 INX 96B4 CE C8 10 DEC &10C8 ;loop until 8 byte pairs copied 96B7 D0 EC BNE Q6A5 96B9 A2 10 LDX #&10 96BB A9 00 LDA #&00 .Q6BD 96BD 99 00 11 STA &1100,Y ;clear top half of channel workspace 96C0 C8 INY 96C1 CA DEX 96C2 D0 F9 BNE Q6BD 96C4 AC C5 10 LDY &10C5 ;put channel workspace pointer in Y 96C7 98 TYA 96C8 20 66 A4 JSR R466 ;shift A right 5 places, A=1..5, C=0 96CB 69 11 ADC #&11 ;add 17; A=&12..16 96CD 99 13 11 STA &1113,Y ;store page number of channel buffer 96D0 AD C4 10 LDA &10C4 ;get bit mask corresponding to channel 96D3 99 1B 11 STA &111B,Y ;store in channel workspace 96D6 0D C3 10 ORA &10C3 ;set that bit in channel open flags byte 96D9 8D C3 10 STA &10C3 ;marking this channel open 96DC B9 09 11 LDA &1109,Y ;test LSB of file length 96DF 69 FF ADC #&FF ;c=0 from &96CB; c=1 if partial sector 96E1 B9 0B 11 LDA &110B,Y ;copy 2MSB length to allocation 96E4 69 00 ADC #&00 ;rounding up to whole sector 96E6 99 19 11 STA &1119,Y 96E9 B9 0D 11 LDA &110D,Y ;get top bits exec/length/load/start sector 96EC 09 0F ORA #&0F ;mask off load/start sector 96EE 69 00 ADC #&00 ;carry out to length in bits 5 and 4 96F0 20 5F A4 JSR R45F ;extract b5,b4 of A 96F3 99 1A 11 STA &111A,Y ;store MSB allocation 96F6 28 PLP ;restore OSFIND call number to N and V 96F7 50 32 BVC Q72B ;if opening for output then branch 96F9 30 08 BMI Q703 ;if opening for update then branch 96FB A9 80 LDA #&80 ;else opening for input. 96FD 19 0C 11 ORA &110C,Y ;set b7=1 of seventh char of leaf name 9700 99 0C 11 STA &110C,Y ;marking channel read-only. .Q703 9703 B9 09 11 LDA &1109,Y ;input or update; set EXT = length of file 9706 99 14 11 STA &1114,Y 9709 B9 0B 11 LDA &110B,Y 970C 99 15 11 STA &1115,Y 970F B9 0D 11 LDA &110D,Y 9712 20 5F A4 JSR R45F ;extract b5,b4 of A 9715 99 16 11 STA &1116,Y .Q718 9718 A5 CF LDA &CF ;get current volume 971A 99 1F 11 STA &111F,Y ;set as volume of open file 971D 98 TYA ;set A=workspace pointer 971E 20 66 A4 JSR R466 ;shift A right 5 places 9721 48 PHA ;save A=1..5 9722 A8 TAY 9723 88 DEY ;select parameter slot 0..4 9724 20 1A 85 JSR P51A ;save drive parameters of open file 9727 68 PLA 9728 09 10 ORA #&10 ;return A=file handle &11..15. 972A 60 RTS .Q72B ;opening for output 972B A9 20 LDA #&20 ;set channel flag b5=1, "EXT changed" 972D 99 17 11 STA &1117,Y ;to truncate file's initial allocation 9730 D0 E6 BNE Q718 ;branch to return file handle (always) .Q732 ;Find unused file handle 9732 AD C3 10 LDA &10C3 ;get channel open flags 9735 A2 04 LDX #&04 ;test up to 5 channel bits: .Q737 9737 0A ASL A ;shift next channel open flag into carry 9738 90 04 BCC Q73E ;if C=0 channel unused, calculate ptr+mask 973A CA DEX ;else loop until 5 channels tested 973B 10 FA BPL Q737 973D 60 RTS ;if C=1 all channels in use, none free .Q73E ;Calculate workspace pointer and bit mask 973E BD 4E 97 LDA &974E,X ;x=0..4. get workspace pointer from table 9741 8D C5 10 STA &10C5 ;return in workspace pointer variable 9744 A9 04 LDA #&04 ;set b2=1, becoming b3..7=1: .Q746 9746 0A ASL A ;shift bit mask left by X+1 places 9747 CA DEX 9748 10 FC BPL Q746 974A 8D C4 10 STA &10C4 ;return in bit mask variable. 974D 60 RTS ;Table of channel workspace pointers for file handles &15..11 974E EQUB &A0 974F EQUB &80 9750 EQUB &60 9751 EQUB &40 9752 EQUB &20 .Q753 ;Compare filename at XY+A with open filenames 9753 86 B0 STX &B0 ;save XY as filename pointer 9755 84 B1 STY &B1 9757 85 B2 STA &B2 ;save A as offset 9759 AD C3 10 LDA &10C3 ;get channel open flags 975C 29 F8 AND #&F8 ;extract flags for channels &11..15 975E 85 B5 STA &B5 ;save as shift register 9760 A2 20 LDX #&20 ;start at channel workspace offset &20: .Q762 9762 86 B4 STX &B4 9764 06 B5 ASL &B5 ;shift next channel open flag into carry 9766 B0 0C BCS Q774 ;if C=1 channel open then compare names 9768 F0 08 BEQ Q772 ;if no more channels open exit C=0, else: .Q76A ;no match 976A A5 B4 LDA &B4 ;add &20 to channel workspace pointer 976C 18 CLC 976D 69 20 ADC #&20 976F AA TAX 9770 90 F0 BCC Q762 ;and loop to test next channel (always) .Q772 9772 18 CLC 9773 60 RTS .Q774 9774 BD 1F 11 LDA &111F,X ;get volume of open file 9777 45 CF EOR &CF ;compare with current volume 9779 D0 EF BNE Q76A ;if unequal then no match 977B A9 08 LDA #&08 ;else set counter = 8 977D 85 B3 STA &B3 977F A4 B2 LDY &B2 ;put offset in Y: .Q781 9781 B1 B0 LDA (&B0),Y ;get character of filename to compare 9783 5D 00 11 EOR &1100,X ;compare with char of open filename 9786 29 7F AND #&7F ;ignore bit 7 9788 D0 E0 BNE Q76A ;if unequal then no match 978A C8 INY ;skip to next character of comparand 978B E8 INX ;skip even addresses cont'g file attributes 978C E8 INX ;skip to next character of open filename 978D C6 B3 DEC &B3 ;decrement counter 978F D0 F0 BNE Q781 ;loop until 7 leaf name chars + dir tested 9791 A4 B4 LDY &B4 ;then restore channel workspace offset to Y 9793 60 RTS ;return C=1 matching filename found. ;OSARGS 9794 C0 00 CPY #&00 ;file handle in Y; if Y = 0 9796 F0 11 BEQ Q7A9 ;then perform Y = 0 functions 9798 20 00 A3 JSR R300 ;else save AXY 979B C9 FF CMP #&FF ;if A=&FF 979D F0 3B BEQ Q7DA ;then ensure file up-to-date on disc #if defined _DFSFIX 979F C9 04 CMP #&04 ;else if A>=4 97A1 B0 17 BCS Q7BA ;then return 97A3 4A LSR A ;else place bit 0 of A in carry flag .Q7A4 97A4 90 40 BCC Q7E6 ;if A=0 or A=2 then return PTR or EXT 97A6 4C 7C BF JMP SF7C ;else A=1 set PTR or A=3 set EXT #else 979F C9 03 CMP #&03 ;else if A>=3 97A1 B0 17 BCS Q7BA ;then return 97A3 4A LSR A ;else place bit 0 of A in carry flag 97A4 90 40 BCC Q7E6 ;if A=0 or A=2 then return PTR or EXT 97A6 4C 06 98 JMP Q806 ;else A=1 set PTR #endif .Q7A9 ;OSARGS Y=0 #if defined _TURBO 97A9 20 2D A3 JSR R32D ;save XY #else 97A9 20 29 A3 JSR R329 ;save XY #endif 97AC A8 TAY ;A=call number, transfer to Y 97AD C8 INY ;convert &FF,0,1 to 0..2 97AE C0 03 CPY #&03 ;if call number was &02..&FE 97B0 B0 08 BCS Q7BA ;then return 97B2 B9 56 A8 LDA &A856,Y ;else get action address high byte 97B5 48 PHA ;save on stack 97B6 B9 53 A8 LDA &A853,Y ;get action address low byte 97B9 48 PHA ;save on stack .Q7BA 97BA 60 RTS ;jump to action address. ;OSARGS A=0, Y=0 return filing system number 97BB A9 04 LDA #&04 ;a=4 for Disc Filing System 97BD 60 RTS ;OSARGS A=1, Y=0 read command line tail 97BE A9 FF LDA #&FF ;command line is always in I/O processor 97C0 95 02 STA &02,X ;so return a host address, &FFFFxxxx 97C2 95 03 STA &03,X 97C4 AD D9 10 LDA &10D9 ;copy address of command line arguments 97C7 95 00 STA &00,X ;from workspace where stored by FSC 2..4 97C9 AD DA 10 LDA &10DA ;to user's OSARGS block 97CC 95 01 STA &01,X 97CE A9 00 LDA #&00 ;return A=0 97D0 60 RTS .Q7D1 ;OSARGS A=&FF, Y=0 97D1 AD C3 10 LDA &10C3 ;Ensure all files up-to-date on disc (flush) 97D4 48 PHA ;save channel open flags 97D5 20 D6 95 JSR Q5D6 ;close all files (returns Z=1) 97D8 F0 07 BEQ Q7E1 ;branch (always) .Q7DA ;OSARGS A=&FF, Y>0 ensure file up-to-date 97DA AD C3 10 LDA &10C3 ;Ensure file up-to-date on disc (flush) 97DD 48 PHA ;save channel open flags 97DE 20 C8 95 JSR Q5C8 ;close a file/all files .Q7E1 97E1 68 PLA ;restore channel open flags. 97E2 8D C3 10 STA &10C3 97E5 60 RTS .Q7E6 ;OSARGS A=0/2, Y>0 return PTR/EXT 97E6 20 00 A3 JSR R300 ;save AXY 97E9 20 A7 98 JSR Q8A7 ;ensure file handle valid and open 97EC 0A ASL A ;A=0 or 1, multiply by 4 97ED 0A ASL A ;A=0 offset of PTR, A=4 offset of EXT 97EE 6D C5 10 ADC &10C5 ;add offset to channel workspace pointer 97F1 A8 TAY ;transfer to Y as index 97F2 B9 10 11 LDA &1110,Y ;copy PTR or EXT 97F5 95 00 STA &00,X ;to 3 LSBs of user's OSARGS block 97F7 B9 11 11 LDA &1111,Y 97FA 95 01 STA &01,X 97FC B9 12 11 LDA &1112,Y 97FF 95 02 STA &02,X 9801 A9 00 LDA #&00 ;clear MSB of user's OSARGS block 9803 95 03 STA &03,X ;PTR <= EXT < 16 MiB 9805 60 RTS .Q806 ;OSARGS A=1, Y>0 set PTR 9806 20 00 A3 JSR R300 ;save AXY 9809 20 A7 98 JSR Q8A7 ;ensure file handle valid and open 980C 38 SEC 980D B9 1C 11 LDA &111C,Y ;get LSB sector address of buffer 9810 F9 0F 11 SBC &110F,Y ;subtract LSB start sector of file 9813 85 B0 STA &B0 ;=offset of buffer from start of file 9815 B9 1D 11 LDA &111D,Y ;get MSB sector address of buffer 9818 F9 0D 11 SBC &110D,Y ;subtract MSB start sector of file 981B 29 03 AND #&03 ;b7..2 of latter = other top bits, mask off 981D D5 02 CMP &02,X ;compare b1..0 with 2MSB requested PTR 981F D0 06 BNE Q827 ;if equal 9821 A5 B0 LDA &B0 ;then compare LSB buffer offset with request 9823 D5 01 CMP &01,X 9825 F0 0B BEQ Q832 ;if requested PTR not within current buffer .Q827 9827 20 97 A5 JSR R597 ;then set current vol/dir from open filename 982A 20 4E 99 JSR Q94E ;ensure buffer up-to-date on disc L6 982D A9 6F LDA #&6F ;b7=0 PTR not in buffer, b4=0 EOF warning clr 982F 20 46 99 JSR Q946 ;clear channel flag bits ;[BUG] EOF warning flag is not cleared if PTR is moved within current buffer! .Q832 9832 20 CC 9A JSR QACC ;compare EXT - requested PTR 9835 B0 1C BCS Q853 ;if EXT >= request then just set PTR 9837 B9 14 11 LDA &1114,Y ;else set PTR = EXT 983A 99 10 11 STA &1110,Y 983D B9 15 11 LDA &1115,Y 9840 99 11 11 STA &1111,Y 9843 B9 16 11 LDA &1116,Y 9846 99 12 11 STA &1112,Y .Q849 9849 A9 00 LDA #&00 ;a = &00 filler byte 984B 20 B0 99 JSR Q9B0 ;write byte to end of file 984E 20 CC 9A JSR QACC ;compare EXT - request 9851 90 F6 BCC Q849 ;loop until last byte is just before new PTR .Q853 9853 B5 00 LDA &00,X ;copy requested PTR in user's OSARGS block 9855 99 10 11 STA &1110,Y ;to channel pointer 9858 B5 01 LDA &01,X 985A 99 11 11 STA &1111,Y 985D B5 02 LDA &02,X 985F 99 12 11 STA &1112,Y 9862 60 RTS .Q863 ;Validate workspace offset 9863 48 PHA ;save A 9864 8E C9 10 STX &10C9 ;save X in workspace 9867 98 TYA ;transfer workspace offset to A 9868 29 E0 AND #&E0 ;mask bits 7..5, offset = 0..7 * &20 986A 8D C5 10 STA &10C5 ;save channel workspace pointer 986D F0 11 BEQ Q880 ;if offset = 0 (i.e. channel &10) return C=1 986F 4A LSR A ;else shift right five times, divide by 32 9870 4A LSR A ;to produce an offset 1..7 9871 4A LSR A ;corresponding to channels &11..17 9872 4A LSR A 9873 4A LSR A 9874 A8 TAY ;transfer to Y for use as index 9875 B9 8A 98 LDA &988A,Y ;get channel open bit mask from table 9878 AC C5 10 LDY &10C5 ;put channel workspace pointer in Y 987B 2C C3 10 BIT &10C3 ;if channel's open bit in flag byte = 1 987E D0 03 BNE Q883 ;then return C=0 .Q880 9880 68 PLA ;else return C=1 9881 38 SEC 9882 60 RTS .Q883 9883 68 PLA 9884 18 CLC 9885 60 RTS ;Table of channel workspace pointers for file handles &11..15 9886 EQUB &20 9887 EQUB &40 9888 EQUB &60 9889 EQUB &80 988A EQUB &A0 ;Table of channel open bit masks for file handles &11..18 988B EQUB &80 988C EQUB &40 988D EQUB &20 988E EQUB &10 988F EQUB &08 9890 EQUB &04 9891 EQUB &02 9892 EQUB &01 .Q893 ;Convert file handle to channel pointer 9893 48 PHA ;save A 9894 98 TYA ;if Y outside range &10..17 9895 C9 10 CMP #&10 9897 90 04 BCC Q89D 9899 C9 18 CMP #&18 989B 90 02 BCC Q89F .Q89D 989D A9 08 LDA #&08 ;then return Y=0, C=1 .Q89F 989F 0A ASL A ;else multiply Y by 32 98A0 0A ASL A ;yielding &00..E0 98A1 0A ASL A 98A2 0A ASL A 98A3 0A ASL A 98A4 A8 TAY ;transfer to Y as index 98A5 68 PLA ;restore A on entry 98A6 60 RTS .Q8A7 ;Ensure file handle valid and open 98A7 48 PHA 98A8 98 TYA 98A9 38 SEC 98AA E9 11 SBC #&11 ;subtract lowest valid handle; if result <0 98AC 90 18 BCC Q8C6 ;then raise "Channel" error 98AE C9 05 CMP #&05 ;else if result >= 5 98B0 B0 14 BCS Q8C6 ;then raise "Channel" error 98B2 A8 TAY ;else transfer to Y as offset 0..4 98B3 B9 86 98 LDA &9886,Y ;get channel workspace pointer from table 98B6 8D C5 10 STA &10C5 ;save in temporary location 98B9 B9 8B 98 LDA &988B,Y ;get channel open bit mask from table 98BC AC C5 10 LDY &10C5 ;put channel workspace pointer in Y 98BF 2C C3 10 BIT &10C3 ;if channel's open bit in flag byte = 0 98C2 F0 02 BEQ Q8C6 ;then raise "Channel" error 98C4 68 PLA 98C5 60 RTS .Q8C6 ;Raise "Channel" error 98C6 20 62 A3 JSR R362 98C9 EQUB &DE 98CA EQUS "Channel" 98D1 EQUB &00 .Q8D2 ;Raise "EOF" error 98D2 20 62 A3 JSR R362 98D5 EQUB &DF 98D6 EQUS "EOF" 98D9 EQUB &00 .Q8DA ;OSBGET 98DA 8E 28 10 STX &1028 98DD 8C 29 10 STY &1029 98E0 20 A7 98 JSR Q8A7 ;ensure file handle valid and open 98E3 98 TYA 98E4 20 B4 9A JSR QAB4 ;compare PTR - EXT 98E7 D0 11 BNE Q8FA ;if at EOF 98E9 B9 17 11 LDA &1117,Y ;then test EOF warning flag b4 98EC 29 10 AND #&10 98EE D0 E2 BNE Q8D2 ;if set then raise "EOF" error 98F0 A9 10 LDA #&10 ;else set EOF warning flag b4=1 98F2 20 3F 99 JSR Q93F ;set channel flag bits (A = OR mask) 98F5 A9 FE LDA #&FE ;return A=&FE, "file end" 98F7 38 SEC ;return C=1 indicating end-of-file 98F8 B0 21 BCS Q91B ;restore XY and exit .Q8FA 98FA B9 17 11 LDA &1117,Y ;not at EOF. get channel flags 98FD 30 0A BMI Q909 ;if PTR not within current buffer 98FF 20 97 A5 JSR R597 ;then set current vol/dir from open filename 9902 20 51 99 JSR Q951 ;ensure buffer up-to-date on disc L6 9905 38 SEC ;c=1 read buffer from disc 9906 20 59 99 JSR Q959 ;read/write sector buffer L6 .Q909 9909 B9 10 11 LDA &1110,Y ;get LSB of PTR 990C 85 BC STA &BC ;set LSB of buffer pointer 990E B9 13 11 LDA &1113,Y ;get MSB buffer pointer from channel workspace 9911 85 BD STA &BD ;set MSB of buffer pointer 9913 20 9D 9A JSR QA9D ;increment PTR 9916 A0 00 LDY #&00 ;set Y=0 for indirect indexed load 9918 B1 BC LDA (&BC),Y ;get byte from channel buffer at old PTR 991A 18 CLC ;c=0, not at EOF: .Q91B 991B AE 28 10 LDX &1028 ;restore X and Y on entry 991E AC 29 10 LDY &1029 9921 48 PHA ;set N and Z according to A 9922 68 PLA 9923 60 RTS ;exit .Q924 ;Set buffer sector address from PTR 9924 18 CLC 9925 B9 0F 11 LDA &110F,Y ;get LSB start sector of open file 9928 79 11 11 ADC &1111,Y ;add 2MSB of PTR 992B 85 C5 STA &C5 ;store LSB sector address 992D 99 1C 11 STA &111C,Y ;store LSB sector address of buffer 9930 B9 0D 11 LDA &110D,Y ;get top bits exec/length/load/start sector 9933 29 03 AND #&03 ;extract MSB start sector 9935 79 12 11 ADC &1112,Y ;add MSB of PTR 9938 85 C4 STA &C4 ;store MSB sector address 993A 99 1D 11 STA &111D,Y ;store MSB sector address of buffer 993D A9 80 LDA #&80 ;b7=1 buffer contains byte at PTR: .Q93F ;Set channel flag bits (A = OR mask) 993F 19 17 11 ORA &1117,Y 9942 D0 05 BNE Q949 ;store if >0 else fall through harmlessly: .Q944 ;Clear buffer-contains-PTR channel flag: 9944 A9 7F LDA #&7F .Q946 ;Clear channel flag bits (A = AND mask) 9946 39 17 11 AND &1117,Y .Q949 9949 99 17 11 STA &1117,Y 994C 18 CLC 994D 60 RTS .Q94E 994E 20 00 A3 JSR R300 ;save AXY .Q951 ;Ensure buffer up-to-date on disc L6 9951 B9 17 11 LDA &1117,Y ;test b6 of channel flag 9954 29 40 AND #&40 9956 F0 46 BEQ Q99E ;if buffer not changed then return 9958 18 CLC ;c=0 write buffer to disc: .Q959 ;Read/write sector buffer L6 9959 08 PHP 995A AD C5 10 LDA &10C5 ;get channel workspace pointer 995D 20 66 A4 JSR R466 ;shift A right 5 places 9960 A8 TAY 9961 88 DEY ;y=0..4 for handles &11..15 9962 20 FC 84 JSR P4FC ;copy channel's drive parameters to &10E0..5 9965 20 D6 A7 JSR R7D6 ;set up for current drive 9968 AC C5 10 LDY &10C5 ;put channel workspace pointer in Y 996B B9 13 11 LDA &1113,Y ;get MSB address of buffer in shared wksp 996E 85 BF STA &BF 9970 20 28 92 JSR Q228 ;set high word of buffer address = &FFFF 9973 A9 00 LDA #&00 9975 85 BE STA &BE ;clear LSB buffer address 9977 85 C2 STA &C2 9979 A9 01 LDA #&01 ;256 bytes to transfer 997B 85 C3 STA &C3 997D 28 PLP 997E B0 15 BCS Q995 ;if C was 1 on entry then read buffer 9980 B9 1C 11 LDA &111C,Y ;else copy channel's sector buffer address 9983 85 C5 STA &C5 ;to &C5,4 (big-endian) 9985 B9 1D 11 LDA &111D,Y 9988 85 C4 STA &C4 998A 20 09 90 JSR Q009 ;write ordinary file L5 998D AC C5 10 LDY &10C5 ;put channel workspace pointer in Y 9990 A9 BF LDA #&BF ;b6=0 buffer not changed 9992 4C 46 99 JMP Q946 ;clear channel flag bits and exit .Q995 ;Read channel buffer from disc L6 9995 20 24 99 JSR Q924 ;set buffer sector address from PTR 9998 20 0F 90 JSR Q00F ;read ordinary file L5 999B AC C5 10 LDY &10C5 ;put channel workspace pointer in Y .Q99E 999E 60 RTS .Q99F 999F 4C ED 9B JMP QBED ;raise "File locked" error. .Q9A2 ;Raise "File read only" error. 99A2 20 5A A3 JSR R35A 99A5 EQUB &C1 99A6 EQUS "read only" 99AF EQUB &00 .Q9B0 ;Write byte 99B0 20 00 A3 JSR R300 ;save AXY 99B3 4C C2 99 JMP Q9C2 .Q9B6 ;OSBPUT 99B6 8D 27 10 STA &1027 ;save AXY on entry 99B9 8E 28 10 STX &1028 99BC 8C 29 10 STY &1029 99BF 20 A7 98 JSR Q8A7 ;ensure file handle valid and open .Q9C2 99C2 48 PHA ;save byte to write 99C3 B9 0C 11 LDA &110C,Y ;test channel read-only bit 99C6 30 DA BMI Q9A2 ;if b7=1 then raise "File read only" error 99C8 B9 0E 11 LDA &110E,Y ;else test file locked bit 99CB 30 D2 BMI Q99F ;if b7=1 then raise "File locked" error 99CD 20 97 A5 JSR R597 ;else set current vol/dir from open filename 99D0 98 TYA ;a=y = channel workspace pointer 99D1 18 CLC ;add 4 to point A to allocated length not EXT 99D2 69 04 ADC #&04 99D4 20 B4 9A JSR QAB4 ;compare PTR - allocated length 99D7 D0 6A BNE QA43 ;if within allocation then write 99D9 20 93 95 JSR Q593 ;else ensure open file still on current volume 99DC AE C7 10 LDX &10C7 ;get offset of file in catalogue 99DF 38 SEC 99E0 BD 07 0F LDA &0F07,X ;get LSB start LBA of previous file in cat 99E3 FD 0F 0F SBC &0F0F,X ;subtract LSB start LBA of open file 99E6 48 PHA ;save LSB maximum available allocation 99E7 BD 06 0F LDA &0F06,X ;get MSB start LBA of previous file in cat 99EA FD 0E 0F SBC &0F0E,X ;subtract MSB start LBA of open file 99ED 29 03 AND #&03 ;extract b1,b0 99EF 8D C6 10 STA &10C6 ;store MSB maximum available allocation 99F2 20 F0 8F JSR PFF0 ;pack b17,16 of length into catalogue entry 99F5 AD C6 10 LDA &10C6 ;get MSB maximum available allocation 99F8 D9 1A 11 CMP &111A,Y ;compare MSB length of file per workspace 99FB D0 2E BNE QA2B ;if not equal then extend file 99FD 68 PLA ;else restore LSB maximum available allocation 99FE D9 19 11 CMP &1119,Y ;compare 2MSB length of file per workspace 9A01 D0 29 BNE QA2C ;if not equal then extend file 9A03 84 B4 STY &B4 ;else save workspace pointer 9A05 20 0C A8 JSR R80C ;call OSBYTE &C7 = read/write *SPOOL handle 9A08 8A TXA ;if *SPOOL not in use 9A09 F0 0A BEQ QA15 ;then close file and raise "Can't extend" 9A0B BD 75 98 LDA &9875,X ;else get workspace pointer to *SPOOL file 9A0E C5 B4 CMP &B4 ;compare with workspace pointer to this file 9A10 D0 03 BNE QA15 ;if equal 9A12 20 FB A7 JSR R7FB ;then disable *SPOOL output. .QA15 9A15 A4 B4 LDY &B4 ;get workspace pointer 9A17 20 E2 95 JSR Q5E2 ;close file 9A1A 20 62 A3 JSR R362 ;raise "Can't extend" error. 9A1D EQUB &BF 9A1E EQUS "Can't extend" 9A2A EQUB &00 ;extend file .QA2B 9A2B 68 PLA ;restore LSB maximum allocation .QA2C 9A2C 9D 0D 0F STA &0F0D,X ;store 2MSB file length in catalogue 9A2F 99 19 11 STA &1119,Y ;store 2MSB file length in workspace 9A32 AD C6 10 LDA &10C6 ;get MSB maximum allocation 9A35 99 1A 11 STA &111A,Y ;store MSB file length in workspace 9A38 A9 00 LDA #&00 ;clear LSB file length in catalogue 9A3A 9D 0C 0F STA &0F0C,X 9A3D 20 81 92 JSR Q281 ;write volume catalogue 9A40 AC C5 10 LDY &10C5 ;put channel workspace pointer in Y .QA43 ;write byte to file 9A43 B9 17 11 LDA &1117,Y ;test channel flags 9A46 30 17 BMI QA5F ;if b7=1 buffer-contains-PTR then write byte 9A48 20 51 99 JSR Q951 ;else ensure buffer up-to-date on disc L6 9A4B B9 14 11 LDA &1114,Y ;does EXT equal a whole number of sectors? 9A4E D0 0B BNE QA5B ;if not then read buffer from disc 9A50 98 TYA ;else a=y = channel workspace pointer 9A51 20 B4 9A JSR QAB4 ;compare PTR - EXT 9A54 D0 05 BNE QA5B ;if not at EOF then read buffer from disc 9A56 20 24 99 JSR Q924 ;else set buffer sector address from PTR 9A59 D0 04 BNE QA5F ;branch (always) .QA5B 9A5B 38 SEC ;c=1 read buffer from disc 9A5C 20 59 99 JSR Q959 ;read/write sector buffer L6 .QA5F 9A5F B9 10 11 LDA &1110,Y ;get LSB of PTR 9A62 85 BC STA &BC ;set LSB of buffer pointer 9A64 B9 13 11 LDA &1113,Y ;get MSB buffer pointer from channel workspace 9A67 85 BD STA &BD ;set MSB of buffer pointer 9A69 20 9D 9A JSR QA9D ;increment PTR 9A6C 68 PLA ;restore byte to write 9A6D A2 00 LDX #&00 ;set Y=0 for indirect indexed store 9A6F 81 BC STA (&BC,X) ;put byte in channel buffer at old PTR 9A71 A9 40 LDA #&40 ;b6=1, buffer has changed 9A73 20 3F 99 JSR Q93F ;set channel flag bits (A = OR mask) 9A76 98 TYA ;a=y = channel workspace pointer 9A77 20 B4 9A JSR QAB4 ;compare PTR - EXT 9A7A 90 17 BCC QA93 ;if at EOF (i.e. pointer >= EXT) 9A7C A9 20 LDA #&20 ;then b5=1, EXT has changed 9A7E 20 3F 99 JSR Q93F ;set channel flag bits (A = OR mask) 9A81 B9 10 11 LDA &1110,Y ;copy EXT = PTR 9A84 99 14 11 STA &1114,Y 9A87 B9 11 11 LDA &1111,Y 9A8A 99 15 11 STA &1115,Y 9A8D B9 12 11 LDA &1112,Y 9A90 99 16 11 STA &1116,Y .QA93 9A93 AD 27 10 LDA &1027 ;restore AXY on entry 9A96 AE 28 10 LDX &1028 9A99 AC 29 10 LDY &1029 9A9C 60 RTS ;exit .QA9D ;Increment PTR 9A9D 98 TYA ;transfer channel workspace pointer to X 9A9E AA TAX 9A9F A5 BC LDA &BC ;copy LSB of buffer pointer to LSB of PTR 9AA1 9D 10 11 STA &1110,X 9AA4 FE 10 11 INC &1110,X ;increment LSB of PTR 9AA7 D0 22 BNE QACB ;if within same sector then return 9AA9 FE 11 11 INC &1111,X ;else sector boundary crossed. 9AAC D0 03 BNE QAB1 ;carry out to high bytes of PTR 9AAE FE 12 11 INC &1112,X .QAB1 9AB1 4C 44 99 JMP Q944 ;and clear buffer-contains-PTR channel flag. .QAB4 ;Compare PTR - EXT (A=Y), - allocation (A=Y+4) 9AB4 AA TAX ;return C=1 iff at/past EOF or allocation 9AB5 B9 12 11 LDA &1112,Y ;return Z=1 iff at EOF or equal to allocation 9AB8 DD 16 11 CMP &1116,X 9ABB D0 0E BNE QACB 9ABD B9 11 11 LDA &1111,Y 9AC0 DD 15 11 CMP &1115,X 9AC3 D0 06 BNE QACB 9AC5 B9 10 11 LDA &1110,Y 9AC8 DD 14 11 CMP &1114,X .QACB 9ACB 60 RTS .QACC ;Compare EXT - OSARGS parameter 9ACC B9 14 11 LDA &1114,Y ;return C=1 iff EXT >= parameter 9ACF D5 00 CMP &00,X 9AD1 B9 15 11 LDA &1115,Y 9AD4 F5 01 SBC &01,X 9AD6 B9 16 11 LDA &1116,Y 9AD9 F5 02 SBC &02,X 9ADB 60 RTS ;OSFILE #if defined _TURBO 9ADC 20 2D A3 JSR R32D ;save XY #else 9ADC 20 29 A3 JSR R329 ;save XY #endif 9ADF 48 PHA ;push A 9AE0 20 2F 89 JSR P92F ;disallow wildcard characters in filename 9AE3 86 B0 STX &B0 ;set up pointer from XY 9AE5 8E DB 10 STX &10DB 9AE8 84 B1 STY &B1 9AEA 8C DC 10 STY &10DC 9AED A2 00 LDX #&00 9AEF A0 00 LDY #&00 9AF1 20 DB 87 JSR P7DB ;copy word at pointer to &BC,D .QAF4 9AF4 20 CB 87 JSR P7CB ;copy next four dwords to &BE..C5 (low words) 9AF7 C0 12 CPY #&12 ;&106F..76 (high words) 9AF9 D0 F9 BNE QAF4 9AFB 68 PLA ;transfer call number to X 9AFC AA TAX #if defined _DFSFIX 9AFD 20 5D BF JSR SF5D ;handle OSFILE calls 7,9-11 or validate index #else 9AFD E8 INX ;increment for use as index 9AFE E0 08 CPX #&08 ;was call number &FF or 0..6? #endif 9B00 B0 08 BCS QB0A ;if not then exit 9B02 BD 61 A8 LDA &A861,X ;else get action address high byte 9B05 48 PHA ;save on stack 9B06 BD 59 A8 LDA &A859,X ;get action address low byte 9B09 48 PHA ;save on stack .QB0A 9B0A 60 RTS ;jump to action address ;OSFILE 0 = save file 9B0B 20 F0 90 JSR Q0F0 ;create file from OSFILE block 9B0E 20 22 9C JSR QC22 ;set up pointer to user's OSFILE block 9B11 20 06 8A JSR PA06 ;return catalogue information to OSFILE block 9B14 4C 09 90 JMP Q009 ;write ordinary file L5 ;OSFILE 1 = write catalogue information ;[BUG] can set attributes on open file 9B17 20 E3 9B JSR QBE3 ;ensure unlocked file exists 9B1A 20 8B 9B JSR QB8B ;set load address from OSFILE block 9B1D 20 A7 9B JSR QBA7 ;set exec address from OSFILE block 9B20 50 16 BVC QB38 ;branch to set attributes and write (always) ;OSFILE 2 = write load address 9B22 20 E3 9B JSR QBE3 ;ensure unlocked file exists 9B25 20 8B 9B JSR QB8B ;set load address from OSFILE block 9B28 50 11 BVC QB3B ;branch to write catalogue (always) ;OSFILE 3 = write execution address 9B2A 20 E3 9B JSR QBE3 ;ensure unlocked file exists 9B2D 20 A7 9B JSR QBA7 ;set exec address from OSFILE block 9B30 50 09 BVC QB3B ;branch to write catalogue (always) ;OSFILE 4 = write file attributes 9B32 20 0E 9C JSR QC0E ;ensure file exists 9B35 20 FB 9B JSR QBFB ;ensure file not open (mutex) ;[BUG] destroys OSFILE block pointer, &B0..1 .QB38 9B38 20 CA 9B JSR QBCA ;set file attributes from OSFILE block .QB3B 9B3B 20 96 90 JSR Q096 ;write volume catalogue 9B3E A9 01 LDA #&01 ;return A=1, file found 9B40 60 RTS ;OSFILE 5 = read catalogue information 9B41 20 0E 9C JSR QC0E ;ensure file exists 9B44 20 06 8A JSR PA06 ;return catalogue information to OSFILE block 9B47 A9 01 LDA #&01 ;return A=1, file found 9B49 60 RTS ;OSFILE 6 = delete file 9B4A 20 E3 9B JSR QBE3 ;ensure unlocked file exists 9B4D 20 06 8A JSR PA06 ;return catalogue information to OSFILE block 9B50 20 9E 89 JSR P99E ;delete catalogue entry 9B53 4C 3B 9B JMP QB3B ;write volume catalogue, return A=1 ;OSFILE &FF = load file 9B56 20 3B 89 JSR P93B ;ensure file matching argument in catalogue 9B59 20 22 9C JSR QC22 ;set up pointer to user's OSFILE block 9B5C 20 06 8A JSR PA06 ;return catalogue information to OSFILE block .QB5F ;Load file into memory 9B5F 84 BC STY &BC 9B61 A2 00 LDX #&00 9B63 A5 C0 LDA &C0 ;test offset 6, LSB exec from OSFILE block 9B65 D0 06 BNE QB6D ;if non-zero, use load address in catalogue 9B67 C8 INY ;else skip first two bytes of catalogue entry 9B68 C8 INY 9B69 A2 02 LDX #&02 ;skip over user-supplied load address in zp 9B6B D0 08 BNE QB75 ;branch (always) .QB6D 9B6D B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector 9B70 85 C4 STA &C4 9B72 20 19 92 JSR Q219 ;expand 18-bit load address to 32-bit .QB75 9B75 B9 08 0F LDA &0F08,Y ;copy load/exec/length/start from catalogue 9B78 95 BE STA &BE,X ;into low words of OSFILE block 9B7A C8 INY ;(our copy, gave user theirs at &9B5C) 9B7B E8 INX 9B7C E0 08 CPX #&08 ;loop until 8 or 6 bytes copied, 0..7/2..7 9B7E D0 F5 BNE QB75 9B80 20 35 92 JSR Q235 ;expand 18-bit exec address to 32-bit 9B83 A4 BC LDY &BC 9B85 20 BB 89 JSR P9BB ;print *INFO line if verbose 9B88 4C 0F 90 JMP Q00F ;read ordinary file L5 and exit .QB8B ;Set load address from OSFILE block 9B8B 20 00 A3 JSR R300 ;save AXY 9B8E A0 02 LDY #&02 ;set offset = 2 9B90 B1 B0 LDA (&B0),Y ;get LSB load address from OSFILE block 9B92 9D 08 0F STA &0F08,X ;store in catalogue entry 9B95 C8 INY ;increment offset; Y=3 9B96 B1 B0 LDA (&B0),Y ;get 3MSB load address 9B98 9D 09 0F STA &0F09,X ;store in catalogue entry 9B9B C8 INY ;increment offset; Y=4 9B9C B1 B0 LDA (&B0),Y ;get 2MSB load address 9B9E 0A ASL A ;extract b17,b16, place in b3,b2 9B9F 0A ASL A 9BA0 5D 0E 0F EOR &0F0E,X ;XOR with existing top bits 9BA3 29 0C AND #&0C ;mask b3,b2; A=....XX.. 9BA5 10 1B BPL QBC2 ;branch to update top bits (always) .QBA7 ;Set exec address from OSFILE block 9BA7 20 00 A3 JSR R300 ;save AXY 9BAA A0 06 LDY #&06 ;set offset = 6 9BAC B1 B0 LDA (&B0),Y ;get LSB exec address from OSFILE block 9BAE 9D 0A 0F STA &0F0A,X ;store in catalogue entry 9BB1 C8 INY ;increment offset; Y=7 9BB2 B1 B0 LDA (&B0),Y ;get 3MSB exec address 9BB4 9D 0B 0F STA &0F0B,X ;store in catalogue entry 9BB7 C8 INY ;increment offset; Y=8 9BB8 B1 B0 LDA (&B0),Y ;get 2MSB load address 9BBA 6A ROR A ;extract b17,b16, place in b7,b6 9BBB 6A ROR A 9BBC 6A ROR A 9BBD 5D 0E 0F EOR &0F0E,X ;XOR with existing top bits 9BC0 29 C0 AND #&C0 ;mask b7,b6; A=XX...... .QBC2 9BC2 5D 0E 0F EOR &0F0E,X ;XOR old top bits with A; 6 bits old, 2 new 9BC5 9D 0E 0F STA &0F0E,X ;set top bits exec/length/load/start sector 9BC8 B8 CLV ;return V=0 9BC9 60 RTS .QBCA ;Set file attributes from OSFILE block 9BCA 20 00 A3 JSR R300 ;save AXY #if defined _BUGFIX 9BCD 20 22 9C JSR QC22 ;set up pointer to user's OSFILE block 9BD0 A0 0E LDY #&0E ;set Y=14, offset of file attributes 9BD2 B1 B0 LDA (&B0),Y ;get LSB of file attributes 9BD4 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 9BD6 A8 TAY ;hold result, Y>0 iff file is to be locked 9BD7 BD 0F 0E LDA &0E0F,X ;get directory character 9BDA 2A ROL A ;shift out old bit 7 9BDB C0 01 CPY #&01 ;set C=1 iff Y>0 9BDD 6A ROR A ;shift in new bit 7, b6..b0 = directory char 9BDE 9D 0F 0E STA &0E0F,X ;save directory char with new lock attribute 9BE1 60 RTS #else 9BCD A0 0E LDY #&0E ;set Y=14, offset of file attributes 9BCF B1 B0 LDA (&B0),Y ;get LSB of file attributes 9BD1 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 9BD3 F0 02 BEQ QBD7 ;if either is set 9BD5 A9 80 LDA #&80 ;then b7=1 file locked .QBD7 9BD7 5D 0F 0E EOR &0E0F,X ;else b7=0 file unlocked. get directory char 9BDA 29 80 AND #&80 ;from catalogue entry 9BDC 5D 0F 0E EOR &0E0F,X ;preserve b6..0, replace b7 from A 9BDF 9D 0F 0E STA &0E0F,X ;save directory char with new lock attribute 9BE2 60 RTS #endif .QBE3 ;Ensure unlocked file exists 9BE3 20 18 9C JSR QC18 ;test if file exists 9BE6 90 2B BCC QC13 ;if not then return A=0 from caller, else: .QBE8 ;Ensure file not locked 9BE8 B9 0F 0E LDA &0E0F,Y ;if directory character b7=1 9BEB 10 2A BPL QC17 .QBED 9BED 20 5A A3 JSR R35A ;then raise "File locked" error. 9BF0 EQUB &C3 9BF1 EQUS "locked" 9BF7 EQUB &00 .QBF8 ;Ensure file not locked or open (mutex) 9BF8 20 E8 9B JSR QBE8 ;ensure file not locked .QBFB ;Ensure file not open (mutex) 9BFB 20 00 A3 JSR R300 ;save AXY 9BFE 98 TYA ;save catalogue pointer 9BFF 48 PHA 9C00 A2 08 LDX #&08 ;point XY to filename in catalogue, &0E08 9C02 A0 0E LDY #&0E 9C04 68 PLA 9C05 20 53 97 JSR Q753 ;compare filename at XY+A with open filenames 9C08 90 03 BCC QC0D ;if unequal then return 9C0A 4C 66 96 JMP Q666 ;else raise "File open" error. .QC0D 9C0D 60 RTS .QC0E ;Ensure file exists 9C0E 20 18 9C JSR QC18 ;test if file exists 9C11 B0 04 BCS QC17 ;if present then return, else: .QC13 ;Return A=0 from caller 9C13 68 PLA ;discard return address on stack (ew!) 9C14 68 PLA 9C15 A9 00 LDA #&00 ;return A=0 as if from caller. .QC17 9C17 60 RTS .QC18 ;Test if file exists 9C18 20 EB 87 JSR P7EB ;set current file from argument pointer 9C1B 20 63 89 JSR P963 ;search for file in catalogue 9C1E 90 0C BCC QC2C ;if file not found then exit C=0 9C20 98 TYA ;else transfer catalogue pointer to X: 9C21 AA TAX .QC22 ;Set up pointer to user's OSFILE block 9C22 AD DB 10 LDA &10DB 9C25 85 B0 STA &B0 9C27 AD DC 10 LDA &10DC 9C2A 85 B1 STA &B1 .QC2C 9C2C 60 RTS ;OSGBPB 9C2D C9 09 CMP #&09 9C2F B0 FB BCS QC2C ;if call number >=9 then return 9C31 20 00 A3 JSR R300 ;else save AXY 9C34 20 F3 A2 JSR R2F3 ;have A=0 returned on exit 9C37 8E 7F 10 STX &107F ;save OSGBPB block pointer in workspace 9C3A 8C 80 10 STY &1080 9C3D A8 TAY ;transfer call number to Y for use as index 9C3E 20 47 9C JSR QC47 ;execute OSGBPB call 9C41 08 PHP 9C42 20 45 93 JSR Q345 ;release Tube if present 9C45 28 PLP 9C46 60 RTS .QC47 9C47 B9 69 A8 LDA &A869,Y ;get low byte of action address from table 9C4A 8D D7 10 STA &10D7 9C4D B9 72 A8 LDA &A872,Y ;get high byte of action address from table 9C50 8D D8 10 STA &10D8 9C53 B9 7B A8 LDA &A87B,Y ;get microcode byte from table 9C56 4A LSR A ;push bit 0 as C 9C57 08 PHP 9C58 4A LSR A ;push bit 1 as C 9C59 08 PHP 9C5A 8D 81 10 STA &1081 ;store Tube service call number as bits 0..5 9C5D 20 0A 9E JSR QE0A ;set up pointer to user's OSGBPB block 9C60 A0 0C LDY #&0C ;13 bytes to copy, &0C..&00: .QC62 9C62 B1 B4 LDA (&B4),Y ;copy user's OSGBPB block 9C64 99 60 10 STA &1060,Y ;to workspace 9C67 88 DEY ;loop until 13 bytes copied 9C68 10 F8 BPL QC62 9C6A AD 63 10 LDA &1063 ;and high bytes of address 9C6D 2D 64 10 AND &1064 ;a=&FF if address is in the host 9C70 0D D6 10 ORA &10D6 ;a=&FF if Tube absent (&10D6=NOT MOS flag!) 9C73 18 CLC 9C74 69 01 ADC #&01 ;set A=0, C=1 if transferring to/from host 9C76 F0 06 BEQ QC7E ;if A>0 9C78 20 2E 93 JSR Q32E ;then claim Tube 9C7B 18 CLC 9C7C A9 FF LDA #&FF ;and set A=&FF, C=0, transferring to/from Tube .QC7E 9C7E 8D 83 10 STA &1083 ;set Tube transfer flag 9C81 AD 81 10 LDA &1081 ;set A=0 if writing user mem, A=1 if reading 9C84 B0 07 BCS QC8D ;if transferring to/from Tube 9C86 A2 61 LDX #&61 ;then point XY to OSGBPB data address 9C88 A0 10 LDY #&10 9C8A 20 06 04 JSR &0406 ;call Tube service to open Tube data channel .QC8D 9C8D 28 PLP ;set C=microcode b1 9C8E B0 04 BCS QC94 ;if reading/writing data then transfer it 9C90 28 PLP ;else C=microcode b0 (=0), pop off stack .QC91 9C91 6C D7 10 JMP (&10D7) ;and jump to action address. .QC94 9C94 A2 03 LDX #&03 ;4 bytes to copy, 3..0: .QC96 9C96 BD 69 10 LDA &1069,X ;copy OSGBPB pointer field 9C99 95 B6 STA &B6,X ;to zero page 9C9B CA DEX 9C9C 10 F8 BPL QC96 9C9E A2 B6 LDX #&B6 ;point X to pointer in zero page 9CA0 AC 60 10 LDY &1060 ;set Y=channel number 9CA3 A9 00 LDA #&00 ;set A=0, read PTR not EXT 9CA5 28 PLP ;set C=microcode b0 9CA6 B0 03 BCS QCAB ;if C=0 #if defined _DFSFIX 9CA8 20 B4 BF JSR SFB4 ;then call OSARGS 1,Y set PTR. #else 9CA8 20 06 98 JSR Q806 ;then call OSARGS 1,Y set PTR. #endif .QCAB 9CAB 20 E6 97 JSR Q7E6 ;call OSARGS 0,Y return PTR 9CAE A2 03 LDX #&03 ;4 bytes to copy, 3..0: .QCB0 9CB0 B5 B6 LDA &B6,X ;copy pointer in zero page 9CB2 9D 69 10 STA &1069,X ;to OSGBPB pointer field 9CB5 CA DEX 9CB6 10 F8 BPL QCB0 .QCB8 9CB8 20 FC 9D JSR QDFC ;invert OSGBPB length field 9CBB 30 0D BMI QCCA ;and branch into loop (always) .QCBD 9CBD AC 60 10 LDY &1060 ;set Y = channel number 9CC0 20 91 9C JSR QC91 ;transfer byte / element 9CC3 B0 0D BCS QCD2 ;if attempted read past EOF then finish 9CC5 A2 09 LDX #&09 ;else set X = &09, point to OSGBPB pointer 9CC7 20 F0 9D JSR QDF0 ;increment pointer .QCCA 9CCA A2 05 LDX #&05 ;set X = &05, point to OSGBPB length field 9CCC 20 F0 9D JSR QDF0 ;increment OSGBPB length field (inverted) 9CCF D0 EC BNE QCBD ;if not overflowed to zero then loop 9CD1 18 CLC ;else set C = 0, no read past EOF: .QCD2 9CD2 08 PHP 9CD3 20 FC 9D JSR QDFC ;invert OSGBPB length field 9CD6 A2 05 LDX #&05 ;add one to get two's complement (0 -> 0) 9CD8 20 F0 9D JSR QDF0 ;thus, number of elements not transferred #if defined _DFSFIX 9CDB 20 C2 BF JSR SFC2 ;set up user pointer and clear EOF warning 9CDE A0 0C LDY #&0C ;13 bytes to copy, offsets 0..&C: #else 9CDB A0 0C LDY #&0C ;13 bytes to copy, offsets 0..&C: 9CDD 20 0A 9E JSR QE0A ;set up pointer to user's OSGBPB block #endif .QCE0 9CE0 B9 60 10 LDA &1060,Y ;copy OSGBPB block back to user memory 9CE3 91 B4 STA (&B4),Y 9CE5 88 DEY 9CE6 10 F8 BPL QCE0 9CE8 28 PLP .QCE9 ;OSGBPB 0 = no operation 9CE9 60 RTS ;OSGBPB 1 = set pointer and write data ;OSGBPB 2 = write data 9CEA 20 A5 9D JSR QDA5 ;get byte from user memory 9CED 20 B6 99 JSR Q9B6 ;call OSBPUT; write byte to file 9CF0 18 CLC ;return C=0 no end-of-file condition 9CF1 60 RTS ;OSGBPB 3 = set pointer and read data ;OSGBPB 4 = read data 9CF2 20 DA 98 JSR Q8DA ;call OSBGET; read byte from file 9CF5 B0 F2 BCS QCE9 ;if end-of-file reached return C=1 9CF7 4C DC 9D JMP QDDC ;else write data byte to user memory ;OSGBPB 5 = read title, boot option and drive 9CFA 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive 9CFD 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 9D00 A9 0C LDA #&0C ;write 12 to user memory 9D02 20 DC 9D JSR QDDC ;= length of title 9D05 A0 00 LDY #&00 ;set offset to 0 .QD07 9D07 B9 00 0E LDA &0E00,Y ;get first eight characters of title 9D0A 20 DC 9D JSR QDDC ;write to user memory 9D0D C8 INY 9D0E C0 08 CPY #&08 ;loop until 8 characters written 9D10 D0 F5 BNE QD07 .QD12 9D12 B9 F8 0E LDA &0EF8,Y ;get last four characters from &0F00..3 9D15 20 DC 9D JSR QDDC ;write to user memory (Y = 8..11) 9D18 C8 INY 9D19 C0 0C CPY #&0C ;loop until 4 more characters written 9D1B D0 F5 BNE QD12 9D1D AD 06 0F LDA &0F06 ;get boot option/top bits volume size 9D20 20 67 A4 JSR R467 ;shift A right 4 places 9D23 20 DC 9D JSR QDDC ;write boot option to user memory 9D26 A5 CF LDA &CF ;get current volume (incl. vol letter b6..4) 9D28 4C DC 9D JMP QDDC ;write to user memory and exit ;OSGBPB 6 = read default (CSD) drive and dir 9D2B AD CB 10 LDA &10CB ;get default volume 9D2E 20 B8 9D JSR QDB8 ;write length+drive identifier to user memory 9D31 20 DA 9D JSR QDDA ;write binary 1 to user memory 9D34 AD CA 10 LDA &10CA ;get default directory character 9D37 4C DC 9D JMP QDDC ;write it to user memory and exit ;OSGBPB 7 = read library drive and directory 9D3A AD CD 10 LDA &10CD ;get library volume 9D3D 20 B8 9D JSR QDB8 ;write length+drive identifier to user memory 9D40 20 DA 9D JSR QDDA ;write binary 1 to user memory 9D43 AD CC 10 LDA &10CC ;get library directory character 9D46 4C DC 9D JMP QDDC ;write it to user memory and exit ;OSGBPB 8 = read filenames in default dir 9D49 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive 9D4C 20 92 92 JSR Q292 ;ensure current volume catalogue loaded 9D4F A9 5C LDA #&5C ;replace action address with &9D5C 9D51 8D D7 10 STA &10D7 ;= return one filename 9D54 A9 9D LDA #&9D 9D56 8D D8 10 STA &10D8 9D59 4C B8 9C JMP QCB8 ;and return requested number of filenames. ;Return one filename (called during OSGBPB 8) 9D5C AC 69 10 LDY &1069 ;set Y = catalogue pointer (0 on first call) .QD5F 9D5F CC 05 0F CPY &0F05 ;compare with no. files in catalogue 9D62 B0 28 BCS QD8C ;if out of files return C=1, read past EOF 9D64 B9 0F 0E LDA &0E0F,Y ;else get directory character of cat entry 9D67 20 9A A4 JSR R49A ;set C=0 iff character in A is a letter 9D6A 45 CE EOR &CE ;compare with current directory character 9D6C B0 02 BCS QD70 ;if directory character is a letter 9D6E 29 DF AND #&DF ;then ignore case. .QD70 9D70 29 7F AND #&7F ;mask off attribute bit b7 9D72 F0 05 BEQ QD79 ;if catalogue entry not in current directory 9D74 20 72 A4 JSR R472 ;then add 8 to Y 9D77 D0 E6 BNE QD5F ;and loop (always) .QD79 9D79 A9 07 LDA #&07 ;else write 7 to user memory 9D7B 20 DC 9D JSR QDDC ;= length of filename 9D7E 85 B0 STA &B0 ;set counter to 7 .QD80 9D80 B9 08 0E LDA &0E08,Y ;get character of leaf name 9D83 20 DC 9D JSR QDDC ;write byte to user memory 9D86 C8 INY ;increment catalogue pointer 9D87 C6 B0 DEC &B0 ;loop until 7 characters transferred 9D89 D0 F5 BNE QD80 ;(Y is 7 up, inc at &9CC7 puts pointer 8 up) 9D8B 18 CLC ;c=0, did not run out of filenames: .QD8C 9D8C 8C 69 10 STY &1069 ;put updated cat ptr in OSGBPB pointer field 9D8F AD 04 0F LDA &0F04 ;return catalogue cycle no. in channel field 9D92 8D 60 10 STA &1060 9D95 60 RTS .QD96 ;Set up pointer to user I/O memory 9D96 48 PHA 9D97 AD 61 10 LDA &1061 9D9A 85 B8 STA &B8 9D9C AD 62 10 LDA &1062 9D9F 85 B9 STA &B9 9DA1 A2 00 LDX #&00 ;offset = 0 for indexed indirect load/store 9DA3 68 PLA 9DA4 60 RTS .QDA5 ;Read data byte from user memory 9DA5 2C 83 10 BIT &1083 ;test Tube transfer flag 9DA8 10 06 BPL QDB0 ;if b7=0 then read from I/O memory 9DAA AD E5 FE LDA &FEE5 ;else read from R3DATA 9DAD 4C EB 9D JMP QDEB ;increment OSGBPB address field .QDB0 9DB0 20 96 9D JSR QD96 ;set up pointer to user I/O memory 9DB3 A1 B8 LDA (&B8,X) ;read byte from user I/O memory 9DB5 4C EB 9D JMP QDEB ;increment OSGBPB address field .QDB8 ;Write length+drive identifier to user memory 9DB8 48 PHA 9DB9 A0 01 LDY #&01 ;return Y=1 9DBB 29 F0 AND #&F0 ;unless volume letter is B..H 9DBD F0 01 BEQ QDC0 9DBF C8 INY ;in which case return Y=2 .QDC0 9DC0 98 TYA 9DC1 20 DC 9D JSR QDDC ;write length of drive ID to user memory 9DC4 68 PLA 9DC5 48 PHA 9DC6 29 0F AND #&0F ;extract drive number 9DC8 18 CLC 9DC9 69 30 ADC #&30 ;convert to ASCII digit 9DCB 20 DC 9D JSR QDDC ;write data byte to user memory 9DCE 68 PLA 9DCF 20 67 A4 JSR R467 ;shift A right 4 places 9DD2 F0 40 BEQ QE14 ;if volume letter is A then exit 9DD4 18 CLC 9DD5 69 41 ADC #&41 ;else convert binary to letter B..H 9DD7 4C DC 9D JMP QDDC ;write it to user memory and exit .QDDA ;Write binary 1 to user memory 9DDA A9 01 LDA #&01 .QDDC ;Write data byte to user memory 9DDC 2C 83 10 BIT &1083 ;test Tube flag 9DDF 10 05 BPL QDE6 ;if Tube not in use then write to I/O memory 9DE1 8D E5 FE STA &FEE5 ;else put byte in R3DATA 9DE4 30 05 BMI QDEB ;and increment OSGBPB address field (always) .QDE6 9DE6 20 96 9D JSR QD96 ;set up pointer to user I/O memory 9DE9 81 B8 STA (&B8,X) ;store byte at pointer: .QDEB ;Increment OSGBPB address field 9DEB 20 00 A3 JSR R300 ;save AXY 9DEE A2 01 LDX #&01 ;set X = &01, point to OSGBPB data address: .QDF0 ;Increment OSGBPB field 9DF0 A0 04 LDY #&04 .QDF2 9DF2 FE 60 10 INC &1060,X 9DF5 D0 04 BNE QDFB 9DF7 E8 INX 9DF8 88 DEY 9DF9 D0 F7 BNE QDF2 .QDFB 9DFB 60 RTS ;return Z=1 iff field overflows .QDFC ;Invert OSGBPB length field 9DFC A2 03 LDX #&03 .QDFE 9DFE A9 FF LDA #&FF 9E00 5D 65 10 EOR &1065,X 9E03 9D 65 10 STA &1065,X 9E06 CA DEX 9E07 10 F5 BPL QDFE 9E09 60 RTS .QE0A ;Set up pointer to user's OSGBPB block 9E0A AD 7F 10 LDA &107F 9E0D 85 B4 STA &B4 9E0F AD 80 10 LDA &1080 9E12 85 B5 STA &B5 .QE14 9E14 60 RTS .QE15 ;Get data byte from user memory 9E15 2C D5 10 BIT &10D5 ;test Tube data transfer flag 9E18 30 03 BMI QE1D ;if transferring from host 9E1A B1 A6 LDA (&A6),Y ;then read address in I/O memory 9E1C 60 RTS .QE1D 9E1D AD E5 FE LDA &FEE5 ;else read from R3DATA. 9E20 60 RTS .QE21 ;Put data byte in user memory 9E21 2C D5 10 BIT &10D5 ;test Tube data transfer flag 9E24 30 03 BMI QE29 ;if transferring to host 9E26 91 A6 STA (&A6),Y ;then write to address in I/O memory 9E28 60 RTS .QE29 9E29 8D E5 FE STA &FEE5 ;else write to R3DATA. 9E2C 60 RTS ;The use of location &CC as a catalogue pointer is a red herring; it occurs ;in Acorn DFS 0.9 as well as in EDOS. ;*MCOPY 9E2D 20 3A A2 JSR R23A ;ensure *ENABLE active 9E30 20 DF A4 JSR R4DF ;call GSINIT and parse mandatory vol spec 9E33 8D D3 10 STA &10D3 ;set as source volume 9E36 20 DF A4 JSR R4DF ;call GSINIT and parse mandatory vol spec 9E39 8D D4 10 STA &10D4 ;set as destination volume 9E3C 20 27 A2 JSR R227 ;set swapping and current disc flags 9E3F 20 AC 9F JSR QFAC ;get start and size of user memory 9E42 20 32 86 JSR P632 ;load destination volume catalogue 9E45 20 15 85 JSR P515 ;save parameters of destination drive 9E48 AD 06 0F LDA &0F06 ;save destination volume size on stack 9E4B 48 PHA 9E4C AD 07 0F LDA &0F07 9E4F 48 PHA 9E50 20 84 9F JSR QF84 ;initialise LBA to start of data area 9E53 20 38 86 JSR P638 ;load source volume catalogue 9E56 20 0E 85 JSR P50E ;save parameters of source drive 9E59 AD 05 0F LDA &0F05 ;get number of files in catalogue * 8 9E5C 85 CC STA &CC ;store in catalogue pointer 9E5E F0 4F BEQ QEAF ;if no files then raise "File not found" 9E60 20 6D 9F JSR QF6D ;calculate number of sectors used in volume 9E63 68 PLA ;restore destination volume size 9E64 85 C6 STA &C6 9E66 68 PLA 9E67 85 C7 STA &C7 9E69 29 0F AND #&0F ;extract b3..0 9E6B C5 CB CMP &CB ;compare MSBs destination - src sectors used 9E6D 90 08 BCC QE77 ;if destination < source raise error 9E6F D0 09 BNE QE7A ;if destination > source then continue 9E71 A5 C6 LDA &C6 ;else compare LSBs destination - source 9E73 C5 CA CMP &CA 9E75 B0 03 BCS QE7A ;if destination >= source then continue .QE77 9E77 4C C3 85 JMP P5C3 ;else raise "Drive .. larger than Drive .." .QE7A 9E7A A5 C7 LDA &C7 ;save destination volume size on stack 9E7C 48 PHA 9E7D A5 C6 LDA &C6 9E7F 48 PHA 9E80 20 FA 84 JSR P4FA ;restore parameters of destination drive 9E83 20 84 9F JSR QF84 ;initialise LBA to start of data area 9E86 20 38 86 JSR P638 ;load source volume catalogue 9E89 20 B2 9E JSR QEB2 ;copy files 9E8C 20 FA 84 JSR P4FA ;restore parameters of destination drive 9E8F 20 84 9F JSR QF84 ;initialise LBA to start of data area 9E92 20 6D 9F JSR QF6D ;calculate number of sectors used in volume 9E95 68 PLA ;restore destination volume size to catalogue 9E96 8D 07 0F STA &0F07 9E99 68 PLA 9E9A 8D 06 0F STA &0F06 9E9D 20 FA 84 JSR P4FA ;restore parameters of destination drive 9EA0 20 79 84 JSR P479 ;select destination volume 9EA3 20 81 92 JSR Q281 ;write volume catalogue 9EA6 20 BA 86 JSR P6BA ;do a NEW for BASIC 9EA9 A9 FF LDA #&FF 9EAB 8D 84 10 STA &1084 ;forget catalogue in pages &0E..F 9EAE 60 RTS .QEAF 9EAF 4C 43 89 JMP P943 ;raise "File not found" error .QEB2 ;Copy files 9EB2 20 28 92 JSR Q228 ;set high word of OSFILE load address = &FFFF 9EB5 A9 00 LDA #&00 9EB7 85 BE STA &BE ;clear LSB of load address 9EB9 85 C2 STA &C2 9EBB AD 89 10 LDA &1089 ;get start of user memory 9EBE 85 BF STA &BF ;set OSFILE load address = OSHWM on I/O proc. .QEC0 9EC0 A4 CC LDY &CC 9EC2 20 7B A4 JSR R47B ;subtract 8 from Y 9EC5 84 CC STY &CC 9EC7 20 C0 89 JSR P9C0 ;print *INFO line 9ECA A4 CC LDY &CC 9ECC 20 C4 A1 JSR R1C4 ;test length of file 9ECF F0 57 BEQ QF28 ;if empty then skip to next file 9ED1 B9 0F 0F LDA &0F0F,Y ;else get LSB start sector 9ED4 85 C8 STA &C8 9ED6 B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector 9ED9 29 03 AND #&03 ;extract b1,b0 of A 9EDB 85 C9 STA &C9 ;set MSB start sector 9EDD 20 D0 A1 JSR R1D0 ;calculate number of sectors used by file .QEE0 9EE0 38 SEC ;subtract HIMEM - OSHWM 9EE1 AD 8A 10 LDA &108A 9EE4 E5 BF SBC &BF 9EE6 A8 TAY ;= number of pages of user memory 9EE7 A5 C7 LDA &C7 ;test MSB file size in sectors 9EE9 D0 06 BNE QEF1 ;if >= 64 KiB then fill user memory 9EEB C4 C6 CPY &C6 ;else compare available pages - LSB sectors 9EED 90 02 BCC QEF1 ;if file won't fit then fill user memory 9EEF A4 C6 LDY &C6 ;else transfer number of sectors in file .QEF1 9EF1 84 C3 STY &C3 ;save transfer size 9EF3 A5 C8 LDA &C8 ;set LBA = source volume LBA 9EF5 85 C5 STA &C5 9EF7 A5 C9 LDA &C9 9EF9 85 C4 STA &C4 9EFB 20 F6 84 JSR P4F6 ;restore parameters of source drive 9EFE 20 6F 84 JSR P46F ;select source volume 9F01 20 0F 90 JSR Q00F ;read ordinary file L5 9F04 18 CLC ;add transfer size to source volume LBA 9F05 A5 C8 LDA &C8 9F07 65 C3 ADC &C3 9F09 85 C8 STA &C8 9F0B 90 02 BCC QF0F ;carry out to high byte 9F0D E6 C9 INC &C9 .QF0F 9F0F 38 SEC 9F10 A5 C6 LDA &C6 ;get LSB remaining size of file in sectors 9F12 E5 C3 SBC &C3 ;subtract number of pages transferred 9F14 85 C6 STA &C6 ;update LSB remaining size 9F16 B0 02 BCS QF1A 9F18 C6 C7 DEC &C7 ;borrow in from MSB remaining size if req'd .QF1A 9F1A 18 CLC ;add transfer size to load address 9F1B A5 BF LDA &BF 9F1D 65 C3 ADC &C3 9F1F 85 BF STA &BF 9F21 A5 BF LDA &BF ;compare new load address - HIMEM 9F23 CD 8A 10 CMP &108A 9F26 F0 04 BEQ QF2C ;if user memory not full .QF28 9F28 A4 CC LDY &CC ;then test catalogue pointer 9F2A D0 94 BNE QEC0 ;if all files not copied then copy next file. .QF2C 9F2C AD 89 10 LDA &1089 ;compare start of user memory - load address 9F2F C5 BF CMP &BF 9F31 F0 32 BEQ QF65 ;if memory empty then loop until files done 9F33 A5 CA LDA &CA ;else set LBA = destination volume LBA 9F35 85 C5 STA &C5 9F37 A5 CB LDA &CB 9F39 85 C4 STA &C4 9F3B 38 SEC ;subtract load address - start of user memory 9F3C A5 BF LDA &BF 9F3E ED 89 10 SBC &1089 9F41 85 C3 STA &C3 ;= number of pages used -> MSB transfer size 9F43 AD 89 10 LDA &1089 ;set MSB load address = start of user memory 9F46 85 BF STA &BF 9F48 20 FA 84 JSR P4FA ;restore parameters of destination drive 9F4B 20 79 84 JSR P479 ;select destination volume 9F4E 20 09 90 JSR Q009 ;write ordinary file L5 9F51 18 CLC ;add transfer size to destination volume LBA 9F52 A5 CA LDA &CA 9F54 65 C3 ADC &C3 9F56 85 CA STA &CA 9F58 90 02 BCC QF5C ;carry out to high byte 9F5A E6 CB INC &CB .QF5C 9F5C A5 C6 LDA &C6 ;test no. sectors remaining to transfer 9F5E 05 C7 ORA &C7 9F60 F0 03 BEQ QF65 ;if none then copy next file 9F62 4C E0 9E JMP QEE0 ;else loop to transfer remaining sectors .QF65 9F65 A5 CC LDA &CC ;test catalogue pointer 9F67 F0 03 BEQ QF6C ;if at start of catalogue then exit 9F69 4C C0 9E JMP QEC0 ;else loop to copy next file .QF6C 9F6C 60 RTS .QF6D ;Calculate number of sectors used in volume 9F6D AC 05 0F LDY &0F05 ;get number of files in catalogue * 8 .QF70 9F70 20 7B A4 JSR R47B ;subtract 8 from Y 9F73 C0 F8 CPY #&F8 ;loop until entire catalogue done 9F75 D0 01 BNE QF78 9F77 60 RTS .QF78 9F78 20 9C 9F JSR QF9C ;set LBA of catalogue entry 9F7B 20 D0 A1 JSR R1D0 ;calculate number of sectors used by file 9F7E 20 19 A2 JSR R219 ;add number of sectors to total 9F81 4C 70 9F JMP QF70 ;loop to add next file .QF84 ;Initialise LBA to start of data area 9F84 A9 00 LDA #&00 9F86 85 CB STA &CB ;set MSB volume-relative LBA = 0 9F88 20 8E 9F JSR QF8E ;return no. reserved sectors in data area 9F8B 85 CA STA &CA ;set as LSB volume-relative LBA 9F8D 60 RTS .QF8E ;Return no. reserved sectors in data area 9F8E A5 CF LDA &CF ;get current volume 9F90 29 0C AND #&0C ;is the physical drive a RAM disc? 9F92 D0 05 BNE QF99 ;if so then return A=2 9F94 2C E3 10 BIT &10E3 ;else A=0; test density flag 9F97 70 02 BVS QF9B ;if single density .QF99 9F99 A9 02 LDA #&02 ;then return A=2 .QF9B 9F9B 60 RTS ;else return A=0 .QF9C ;Set LBA of catalogue entry 9F9C A5 CA LDA &CA ;replace start sector of catalogue entry 9F9E 99 0F 0F STA &0F0F,Y ;with value in &CA..B 9FA1 B9 0E 0F LDA &0F0E,Y 9FA4 29 FC AND #&FC 9FA6 05 CB ORA &CB 9FA8 99 0E 0F STA &0F0E,Y 9FAB 60 RTS .QFAC ;Get start and size of user memory 9FAC A9 83 LDA #&83 ;call OSBYTE &83 = read OSHWM 9FAE 20 F4 FF JSR &FFF4 9FB1 8C 89 10 STY &1089 ;save MSB 9FB4 A9 84 LDA #&84 ;call OSBYTE &84 = read HIMEM 9FB6 20 F4 FF JSR &FFF4 9FB9 98 TYA 9FBA 8D 8A 10 STA &108A ;save MSB 9FBD 38 SEC 9FBE ED 89 10 SBC &1089 ;subtract MSB of OSHWM 9FC1 8D 8B 10 STA &108B ;save result = no. pages of user memory. 9FC4 60 RTS .QFC5 ;Claim shared workspace 9FC5 A2 0A LDX #&0A ;service call &0A = workspace claimed 9FC7 20 18 A8 JSR R818 ;call OSBYTE &8F = issue service call 9FCA 20 D4 9F JSR QFD4 ;set up pointer to private page 9FCD A0 C1 LDY #&C1 ;set b7 of offset &C1 in private page 9FCF A9 FF LDA #&FF ;b7=1 iff we own the shared workspace 9FD1 91 B0 STA (&B0),Y 9FD3 60 RTS .QFD4 ;Set up pointer to private page 9FD4 A6 F4 LDX &F4 9FD6 A9 00 LDA #&00 9FD8 85 B0 STA &B0 9FDA BD F0 0D LDA &0DF0,X 9FDD 85 B1 STA &B1 9FDF 60 RTS ;*HELP UTILS 9FE0 A2 5F LDX #&5F ;Print utility command table at &8E5F 9FE2 A0 8E LDY #&8E 9FE4 A9 08 LDA #&08 ;8 entries to print (not *DISK) 9FE6 D0 0E BNE QFF6 ;*HELP DDOS / *HELP DFS 9FE8 A2 8A LDX #&8A ;Print DFS command table at &8D8A 9FEA A0 8D LDY #&8D 9FEC A9 15 LDA #&15 ;21 entries to print 9FEE D0 06 BNE QFF6 ;*HELP DDOSX 9FF0 A2 35 LDX #&35 ;Print DDOSX command table at &8E35 9FF2 A0 8E LDY #&8E 9FF4 A9 04 LDA #&04 ;4 entries to print .QFF6 9FF6 20 28 8F JSR PF28 ;set up trampoline to read table at XY 9FF9 85 B8 STA &B8 ;store number of printable entries in counter 9FFB 20 84 A8 JSR R884 ;print DDOS banner 9FFE A2 00 LDX #&00 ;set offset in command table = 0 .R000 A000 20 C9 A2 JSR R2C9 ;print two spaces A003 20 27 A0 JSR R027 ;print command name and syntax A006 20 67 84 JSR P467 ;print newline A009 C6 B8 DEC &B8 ;decrement count of entries A00B D0 F3 BNE R000 ;loop until none remain A00D 60 RTS .R00E ;Call GSINIT with C=0 and reject empty arg A00E 20 BB A4 JSR R4BB ;call GSINIT with C=0 A011 F0 01 BEQ R014 ;if string empty (and unquoted), syntax error A013 60 RTS .R014 ;Raise "Syntax: " error A014 20 62 A3 JSR R362 A017 EQUB &DC A018 EQUS "Syntax: " A020 EQUB &EA A021 20 27 A0 JSR R027 ;print command name and syntax A024 4C B9 A3 JMP R3B9 ;terminate error message, raise error .R027 ;Print command name and syntax A027 20 00 A3 JSR R300 ;save AXY A02A A2 00 LDX #&00 ;set offset in command table = 0 A02C A0 09 LDY #&09 ;9 characters in command name column .R02E A02E 20 AA 00 JSR &00AA ;get byte of command name A031 30 08 BMI R03B ;if terminator reached then print syntax A033 20 03 A4 JSR R403 ;else print character in A (OSASCI) A036 E8 INX ;increment offset A037 88 DEY ;decrement number of spaces remaining A038 4C 2E A0 JMP R02E ;and loop .R03B ;Print syntax A03B 88 DEY ;if Y in range 1..128 A03C 30 04 BMI R042 ;then command not reached edge of column A03E C8 INY ;so A03F 20 DA 88 JSR P8DA ;print number of spaces in Y .R042 A042 E8 INX ;skip action address A043 E8 INX A044 20 AA 00 JSR &00AA ;get syntax byte A047 48 PHA ;save it A048 E8 INX ;skip over it A049 20 37 8F JSR PF37 ;add X to trampoline address A04C 68 PLA A04D 20 55 A0 JSR R055 ;print syntax element A050 20 67 A4 JSR R467 ;shift A right 4 places A053 29 07 AND #&07 ;mask b2..0 ignore restricted cmd bit: .R055 ;Print syntax element A055 20 00 A3 JSR R300 ;save AXY A058 29 0F AND #&0F ;mask b3..0 current syntax element A05A F0 1D BEQ R079 ;if null element then return A05C A8 TAY ;else transfer to Y for use as counter A05D A9 20 LDA #&20 ;print a space A05F 20 03 A4 JSR R403 ;print character in A (OSASCI) A062 A2 FF LDX #&FF ;set offset=&FF going to 0: .R064 A064 E8 INX ;increment offset A065 BD 7A A0 LDA &A07A,X ;get character of syntax element table A068 D0 FA BNE R064 ;loop until NUL reached A06A 88 DEY ;decrement number of NULs to skip A06B D0 F7 BNE R064 ;when Y=0 we've reached correct element: .R06D A06D E8 INX ;increment offset A06E BD 7A A0 LDA &A07A,X ;get character of syntax element table A071 F0 06 BEQ R079 ;if NUL reached then return A073 20 03 A4 JSR R403 ;else print character in A (OSASCI) A076 4C 6D A0 JMP R06D ;and loop until element printed. .R079 A079 60 RTS ;Table of syntax elements A07A EQUB &00 ;element &0, "" A07B EQUS "<fsp>" ;element &1, <fsp> A080 EQUB &00 A081 EQUS "<afsp>" ;element &2, <afsp> A087 EQUB &00 A088 EQUS "(L)" ;element &3, (L) A08B EQUB &00 A08C EQUS "<src drv>" ;element &4, <src drv> A095 EQUB &00 A096 EQUS "<dest drv>" ;element &5, <dest drv> A0A0 EQUB &00 A0A1 EQUS "<dest drv> <afsp>" ;element &6, <dest drv> <afsp> A0B2 EQUB &00 A0B3 EQUS "<new fsp>" ;element &7, <new fsp> A0BC EQUB &00 A0BD EQUS "<old fsp>" ;element &8, <old fsp> A0C6 EQUB &00 A0C7 EQUS "(<dir>)" ;element &9, (<dir>) A0CE EQUB &00 A0CF EQUS "(<drv>)" ;element &A, (<drv>) A0D6 EQUB &00 A0D7 EQUS "<title>" ;element &B, <title> A0DE EQUB &00 A0DF EQUS "<Hex no.>" ;element &C, <Hex no.> A0E8 EQUB &00 A0E9 EQUS "<argument>" ;element &D, <argument> A0F3 EQUB &00 ;terminator byte ;*COMPACT A0F4 20 E5 A4 JSR R4E5 ;select specified or default volume A0F7 8D D3 10 STA &10D3 ;set as source drive A0FA 8D D4 10 STA &10D4 ;set as destination drive A0FD 20 94 A3 JSR R394 A100 EQUS "Compacting" A10A EA NOP A10B 20 08 8D JSR PD08 ;print " Drive " plus volume spec in A A10E 20 67 84 JSR P467 ;print newline A111 A0 00 LDY #&00 ;point Y to workspace of invalid channel &10 #if defined _BUGFIX A113 20 D3 95 JSR Q5D3 ;close all files #else A113 20 E2 95 JSR Q5E2 ;close file (does only ?&10C5 = 0: ?&10C9 = X) ;[BUG]Challenger has 'close all files' ;is that what was meant? #endif A116 20 AC 9F JSR QFAC ;get start and size of user memory A119 20 9E 92 JSR Q29E ;load volume catalogue L4 A11C 20 0E 85 JSR P50E ;save parameters of source drive A11F 20 15 85 JSR P515 ;save parameters of destination drive A122 AC 05 0F LDY &0F05 ;get number of files in catalogue A125 84 CC STY &CC ;set as catalogue pointer A127 20 84 9F JSR QF84 ;initialise LBA to start of data area .R12A A12A A4 CC LDY &CC ;set Y to catalogue pointer A12C 20 7B A4 JSR R47B ;subtract 8 from Y A12F C0 F8 CPY #&F8 ;if we've reached end of catalogue A131 F0 54 BEQ R187 ;then finish A133 84 CC STY &CC ;else set new catalogue pointer A135 20 BB 89 JSR P9BB ;print *INFO line if verbose A138 A4 CC LDY &CC A13A 20 C4 A1 JSR R1C4 ;test length of file A13D F0 40 BEQ R17F ;if empty then only print *INFO line A13F A9 00 LDA #&00 A141 85 BE STA &BE ;else set LSB load address = 0 A143 85 C2 STA &C2 ;set LSB transfer size = 0 A145 20 D0 A1 JSR R1D0 ;calculate number of sectors used by file A148 B9 0F 0F LDA &0F0F,Y ;get LSB start sector A14B 85 C8 STA &C8 ;set LSB source LBA A14D B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector A150 29 03 AND #&03 ;extract b1,b0 of A A152 85 C9 STA &C9 ;set MSB source LBA A154 C5 CB CMP &CB ;compare with destination LBA #if defined _DDOS357 A156 D0 1A BNE R172 ;if unequal then compact file A158 A5 C8 LDA &C8 ;else compare LSBs source - destination LBA A15A C5 CA CMP &CA A15C D0 14 BNE R172 ;if unequal then compact file A15E 20 19 A2 JSR R219 ;else add number of sectors to total A161 80 1C BRA R17F ;print *INFO line and loop for next file .R163 A163 AA TAX ;put drive number in X A164 AD E3 10 LDA &10E3 ;get density flag A167 29 40 AND #&40 ;extract bit 6 (1 = double density) A169 4A LSR A ;move to bit 5 A16A 5D 6E A1 EOR &A16E,X ;apply flags for drive 0..3 in X A16D 60 RTS ;return latch in A A16E EQUB &25,&26,&35,&36 .R172 ;Compact file A172 20 9C 9F JSR QF9C ;set LBA of catalogue entry A175 64 A8 STZ &A8 ;no catalogue entry waiting to be created A177 64 A9 STZ &A9 ;&00 = source and dest. are different drives ;(no swapping) #else /* _DDOS357 */ A156 D0 0C BNE R164 ;if unequal then compact file A158 A5 C8 LDA &C8 ;else compare LSBs source - destination LBA A15A C5 CA CMP &CA A15C D0 06 BNE R164 ;if unequal then compact file A15E 20 19 A2 JSR R219 ;else add number of sectors to total A161 4C 7F A1 JMP R17F ;print *INFO line and loop for next file ;can save 12 bytes here; A164 = JSR QF9C .R164 ;Compact file A164 A5 CA LDA &CA ;set LSB start sector = destination LBA A166 99 0F 0F STA &0F0F,Y A169 B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector A16C 29 FC AND #&FC ;clear b1,b0 MSB start sector A16E 05 CB ORA &CB ;replace with MSB destination LBA A170 99 0E 0F STA &0F0E,Y ;set top bits exec/length/load/start sector A173 A9 00 LDA #&00 A175 85 A8 STA &A8 ;no catalogue entry waiting to be created A177 85 A9 STA &A9 ;&00 = source and dest. are different drives ;(no swapping) #endif /* _DDOS357 */ A179 20 51 87 JSR P751 ;copy source drive/file to destination A17C 20 81 92 JSR Q281 ;write volume catalogue L4 .R17F A17F A4 CC LDY &CC A181 20 C0 89 JSR P9C0 ;print *INFO line A184 4C 2A A1 JMP R12A ;loop for next file .R187 A187 20 94 A3 JSR R394 ;print "Disk compacted " A18A EQUS "Disk compacted " A199 EA NOP A19A 38 SEC A19B AD 07 0F LDA &0F07 ;get LSB volume size A19E E5 CA SBC &CA ;subtract LSB sectors used on volume A1A0 48 PHA ;=LSB sectors free. save on stack A1A1 AD 06 0F LDA &0F06 ;get boot option/top bits volume size A1A4 29 03 AND #&03 ;extract volume size in b1,b0 A1A6 E5 CB SBC &CB ;subtract MSB sectors used on volume A1A8 20 31 A4 JSR R431 ;print hex nibble A1AB 68 PLA ;restore LSB sectors free A1AC 20 29 A4 JSR R429 ;print hex byte A1AF 20 94 A3 JSR R394 ;print " free sectors" A1B2 EQUS " free sectors" A1BF EQUB &0D A1C0 EA NOP A1C1 4C BA 86 JMP P6BA ;store empty BASIC program at OSHWM (NEW) .R1C4 ;Test length of file A1C4 B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector A1C7 29 30 AND #&30 ;extract length in b5,b4 A1C9 19 0D 0F ORA &0F0D,Y ;OR with 2MSB, LSB of length A1CC 19 0C 0F ORA &0F0C,Y ;return Z=1 if length=0, empty file. A1CF 60 RTS .R1D0 ;Calculate number of sectors used by file A1D0 18 CLC A1D1 B9 0C 0F LDA &0F0C,Y ;get LSB length A1D4 69 FF ADC #&FF ;c=1 iff LSB >0 A1D6 B9 0D 0F LDA &0F0D,Y ;add C to 2MSB length, rounding up A1D9 69 00 ADC #&00 ;(Y points to 8 bytes before file entry) A1DB 85 C6 STA &C6 ;store LSB length of file in sectors A1DD B9 0E 0F LDA &0F0E,Y ;get top bits exec/length/load/start sector A1E0 08 PHP ;save carry flag from addition A1E1 20 5F A4 JSR R45F ;extract length from b5,4 to b1,0 A1E4 28 PLP ;restore carry flag A1E5 69 00 ADC #&00 ;add C to MSB length, rounding up A1E7 85 C7 STA &C7 ;store length in sectors in zero page A1E9 60 RTS .R1EA ;Calculate free space on volume A1EA 20 FF A1 JSR R1FF ;start with used space on volume A1ED 38 SEC A1EE AD 07 0F LDA &0F07 ;get LSB volume size from catalogue A1F1 E5 CA SBC &CA ;subtract LSB used space A1F3 85 C0 STA &C0 ;store LSB result in zero page A1F5 AD 06 0F LDA &0F06 ;get boot option/top bits volume size A1F8 29 03 AND #&03 ;extract MSB volume size A1FA E5 CB SBC &CB ;subtract MSB used space, store in zp A1FC 85 C1 STA &C1 ;[BUG] can underflow due to overlaps A1FE 60 RTS .R1FF ;Calculate used space on volume A1FF AC 05 0F LDY &0F05 ;get number of files in catalogue * 8 A202 A9 00 LDA #&00 ;clear total number of used sectors on vol A204 85 CA STA &CA A206 85 CB STA &CB .R208 A208 20 7B A4 JSR R47B ;subtract 8 from Y A20B C0 F8 CPY #&F8 ;loop until entire catalogue done A20D D0 01 BNE R210 ;[BUG] can exceed vol size due to overlaps A20F 60 RTS .R210 A210 20 D0 A1 JSR R1D0 ;calculate number of sectors used by file A213 20 19 A2 JSR R219 ;add number of sectors to total A216 4C 08 A2 JMP R208 ;loop for next file .R219 ;Add number of sectors to total A219 18 CLC ;add LSB A21A A5 CA LDA &CA A21C 65 C6 ADC &C6 A21E 85 CA STA &CA A220 A5 CB LDA &CB ;add MSB A222 65 C7 ADC &C7 A224 85 CB STA &CB A226 60 RTS ;Note: DDOS 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. .R227 ;Set swapping and current disc flags A227 A9 00 LDA #&00 A229 85 A9 STA &A9 ;&00 = source and dest. are different drives A22B AD D4 10 LDA &10D4 ;get destination drive A22E CD D3 10 CMP &10D3 ;compare with source drive A231 D0 06 BNE R239 ;if equal A233 A9 FF LDA #&FF ;then A=&FF A235 85 A9 STA &A9 ;b7=1 source & dest. share drive (swapping) A237 85 AA STA &AA ;b7=1 dest. disc in drive (ask for source) .R239 A239 60 RTS .R23A ;Ensure *ENABLE active A23A 2C D2 10 BIT &10D2 ;test *ENABLE flag A23D 10 5F BPL R29E ;if b7=0 then current command is enabled A23F 20 62 A3 JSR R362 ;else raise "Not enabled" error. A242 EQUB &BD A243 EQUS "Not enabled" A24E EQUB &00 .R24F ;Parse and print source and dest. volumes A24F 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg A252 20 4F A5 JSR R54F ;parse volume spec A255 8D D3 10 STA &10D3 ;store source volume A258 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg A25B 20 4F A5 JSR R54F ;parse volume spec A25E 8D D4 10 STA &10D4 ;store destination volume A261 98 TYA ;save GSINIT offset in Y A262 48 PHA A263 20 27 A2 JSR R227 ;set swapping and current disc flags A266 20 AC 9F JSR QFAC ;get start and size of user memory A269 20 94 A3 JSR R394 ;print "Copying from drive " A26C EQUS "Copying from drive " A27F AD D3 10 LDA &10D3 ;get source volume A282 20 BA 8B JSR PBBA ;print volume spec in A A285 20 94 A3 JSR R394 ;print " to drive " A288 EQUS " to drive " A292 AD D4 10 LDA &10D4 ;get destination volume A295 20 BA 8B JSR PBBA ;print volume spec in A A298 20 67 84 JSR P467 ;print newline A29B 68 PLA ;restore GSINIT offset to Y A29C A8 TAY A29D 18 CLC .R29E A29E 60 RTS .R29F ;Increment and print BCD word A29F F8 SED ;set decimal mode A2A0 18 CLC ;increment low byte A2A1 A5 A8 LDA &A8 A2A3 69 01 ADC #&01 ;only ADC and SBC have decimal mode A2A5 85 A8 STA &A8 ;carry out in C, the only valid flag A2A7 A5 A9 LDA &A9 ;carry out to high byte A2A9 69 00 ADC #&00 A2AB 85 A9 STA &A9 A2AD D8 CLD ;clear decimal mode A2AE 18 CLC ;set C=0, pad numeric field with spaces A2AF 20 B4 A2 JSR R2B4 ;print hex byte, C=0 if space-padded A2B2 A5 A8 LDA &A8 .R2B4 ;Print hex byte, C=0 if space-padded A2B4 48 PHA A2B5 08 PHP ;save space padding flag in C A2B6 20 67 A4 JSR R467 ;shift A right 4 places A2B9 28 PLP ;restore C A2BA 20 BE A2 JSR R2BE ;print top nibble of byte A2BD 68 PLA ;restore bottom nibble: .R2BE ;Print space-padded hex nibble A2BE 48 PHA ;test accumulator, Z=1 if zero A2BF 68 PLA A2C0 B0 02 BCS R2C4 ;if digit has been printed print another A2C2 F0 08 BEQ R2CC ;else if nibble is zero print a space .R2C4 A2C4 20 31 A4 JSR R431 ;else print hex nibble A2C7 38 SEC ;set C=1 to suppress space padding A2C8 60 RTS ;and exit .R2C9 ;Print two spaces A2C9 20 CC A2 JSR R2CC .R2CC ;Print a space A2CC 48 PHA ;preserve A A2CD A9 20 LDA #&20 A2CF 20 03 A4 JSR R403 ;print character in A (OSASCI) A2D2 68 PLA A2D3 18 CLC ;return C=0 A2D4 60 RTS .R2D5 ;Claim service call and set up argument ptr A2D5 BA TSX A2D6 A9 00 LDA #&00 ;have A=0 returned on exit A2D8 9D 07 01 STA &0107,X A2DB 98 TYA ;save string offset A2DC 48 PHA A2DD 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg A2E0 68 PLA ;restore string offset A2E1 A8 TAY .R2E2 ;Set XY to GSINIT pointer + Y A2E2 98 TYA ;add Y to LSB of GSINIT pointer A2E3 18 CLC A2E4 65 F2 ADC &F2 A2E6 AA TAX ;hold in X A2E7 A5 F3 LDA &F3 ;carry out to high byte of GSINIT pointer A2E9 69 00 ADC #&00 A2EB A8 TAY ;hold in Y A2EC A9 00 LDA #&00 ;clear private pointer A2EE 85 A8 STA &A8 A2F0 85 A9 STA &A9 A2F2 60 RTS .R2F3 ;Have A=0 returned on exit A2F3 48 PHA ;caller called Save AXY, A was at &0105,S A2F4 8A TXA ;save caller's AX A2F5 48 PHA ;these two bytes plus return address make 4 A2F6 BA TSX ;superroutine's A is thus 5+4 = 9 bytes down A2F7 A9 00 LDA #&00 A2F9 9D 09 01 STA &0109,X A2FC 68 PLA ;restore caller's AX A2FD AA TAX A2FE 68 PLA A2FF 60 RTS #if defined _TURBO .R300 ;Save AXY A300 48 PHA ;stack = &03,&A3,a,cl,ch,sl,sh A301 20 0A A3 JSR R30A ;return to caller,RTS jumps to next line .R304 ;Restore AXY and return to superroutine A304 68 PLA ;stack = y,x,a,sl,sh A305 A8 TAY ;cl,ch=caller return address A306 68 PLA ;sl,sh=superroutine return address A307 AA TAX A308 68 PLA A309 60 RTS .R30A ;Poke AXY into stack, return to caller A30A 48 PHA A30B 48 PHA A30C 48 PHA A30D 8A TXA A30E 48 PHA A30F BA TSX ;stack = x,a,a,a,&03,&A3,a,cl,ch,sl,sh A310 BD 09 01 LDA &0109,X ;caller address high byte A313 9D 04 01 STA &0104,X A316 BD 08 01 LDA &0108,X ;caller address low byte A319 9D 03 01 STA &0103,X A31C BD 07 01 LDA &0107,X ;A on entry A31F 9D 09 01 STA &0109,X A322 98 TYA ;Y on entry A323 9D 07 01 STA &0107,X ;stack = x,a,cl,ch,&03,&A3,y,cl,a,sl,sh A326 68 PLA ;X on entry A327 9D 08 01 STA &0108,X ;stack = a,cl,ch,&03,&A3,y,x,a,sl,sh A32A AA TAX A32B 68 PLA ;restore A on entry A32C 60 RTS ;return to caller .R32D ;Save XY A32D 48 PHA ;stack = &30,&A3,a,cl,ch,sl,sh A32E 20 0A A3 JSR R30A ;return to caller,RTS jumps to next line A331 BA TSX A332 9D 03 01 STA &0103,X ;replace A on entry with A from caller A335 4C 04 A3 JMP R304 ;restore AXY and return to superroutine #else .R300 ;Save AXY A300 48 PHA ;stack = &22,&A3,y,x,a,cl,ch,sl,sh A301 8A TXA ;cl,ch=caller return address A302 48 PHA ;sl,sh=superroutine return address A303 98 TYA A304 48 PHA A305 A9 A3 LDA #&A3 A307 48 PHA A308 A9 22 LDA #&22 A30A 48 PHA .R30B A30B A0 05 LDY #&05 ;duplicate y,x,a,cl,ch .R30D A30D BA TSX A30E BD 07 01 LDA &0107,X A311 48 PHA A312 88 DEY A313 D0 F8 BNE R30D A315 A0 0A LDY #&0A ;copy top 10 bytes down 2 places: .R317 A317 BD 09 01 LDA &0109,X ;overwrite bottom copy of cl,ch A31A 9D 0B 01 STA &010B,X A31D CA DEX A31E 88 DEY ;stack now contains: A31F D0 F6 BNE R317 ;y,x,y,x,a,cl,ch,&22,&A3,y,x,a,sl,sh A321 68 PLA ;discard y,x: A322 68 PLA .R323 ;Restore AXY and return to superroutine A323 68 PLA A324 A8 TAY A325 68 PLA A326 AA TAX A327 68 PLA A328 60 RTS .R329 ;Save XY A329 48 PHA ;push y,x,a A32A 8A TXA A32B 48 PHA A32C 98 TYA A32D 48 PHA A32E 20 0B A3 JSR R30B ;restack then "call" rest of caller's routine! A331 BA TSX ;get stack pointer A332 9D 03 01 STA &0103,X ;store A on exit from caller in stack: A335 4C 23 A3 JMP R323 ;restore y,x on entry, a on exit. #endif .R338 ;Raise "Disk read only" error A338 20 47 A3 JSR R347 A33B EQUB &C9 A33C EQUS " read only" A346 EQUB &00 .R347 ;Raise "Disk " error A347 20 8A A3 JSR R38A A34A EQUS "Disk " A34F 90 11 BCC R362 .R351 ;Raise "Bad " error A351 20 8A A3 JSR R38A A354 EQUS "Bad " A358 90 08 BCC R362 .R35A ;Raise "File " error A35A 20 8A A3 JSR R38A A35D EQUS "File " .R362 ;Append error message immediate A362 85 B3 STA &B3 ;save A on entry A364 68 PLA ;pop caller's address into pointer A365 85 AE STA &AE A367 68 PLA A368 85 AF STA &AF A36A A5 B3 LDA &B3 ;restore A on entry and save on stack A36C 48 PHA A36D 98 TYA ;save Y A36E 48 PHA A36F A0 00 LDY #&00 ;set Y=0 for indirect indexed load A371 20 B4 A4 JSR R4B4 ;increment &AE,F A374 B1 AE LDA (&AE),Y ;get error number from byte after JSR A376 8D 01 01 STA &0101 ;store at bottom of stack A379 2C DD 10 BIT &10DD ;if error message already being built A37C 10 25 BPL R3A3 ;then complete it A37E A9 02 LDA #&02 ;else A = &02 A380 8D DD 10 STA &10DD ;error message being built from offset 2 A383 A9 00 LDA #&00 ;instruction at &0100 = BRK A385 8D 00 01 STA &0100 A388 F0 19 BEQ R3A3 ;build error message (always) .R38A ;Prefix error message immediate A38A A9 02 LDA #&02 ;error message being built from offset 2 A38C 8D DD 10 STA &10DD A38F A9 00 LDA #&00 ;instruction at &0100 = BRK: A391 8D 00 01 STA &0100 .R394 ;Print string immediate A394 85 B3 STA &B3 ;save A on entry A396 68 PLA ;pop caller's address into pointer A397 85 AE STA &AE A399 68 PLA A39A 85 AF STA &AF A39C A5 B3 LDA &B3 ;restore A on entry and save on stack A39E 48 PHA A39F 98 TYA ;save Y A3A0 48 PHA A3A1 A0 00 LDY #&00 ;set Y=0 for indirect indexed load: .R3A3 A3A3 20 B4 A4 JSR R4B4 ;increment &AE,F A3A6 B1 AE LDA (&AE),Y ;get character from after JSR A3A8 30 08 BMI R3B2 ;if b7=1 then opcode terminator, execute it A3AA F0 0D BEQ R3B9 ;else if NUL then raise error A3AC 20 03 A4 JSR R403 ;else print the character A3AF 4C A3 A3 JMP R3A3 ;and loop .R3B2 A3B2 68 PLA ;restore AY A3B3 A8 TAY A3B4 68 PLA A3B5 18 CLC A3B6 6C AE 00 JMP (&00AE) ;jump to address of end of string .R3B9 ;Terminate error message, raise error A3B9 A9 00 LDA #&00 A3BB AE DD 10 LDX &10DD ;terminate error message with NUL A3BE 9D 00 01 STA &0100,X A3C1 A9 FF LDA #&FF A3C3 8D DD 10 STA &10DD ;no error message being built print to screen A3C6 8D 84 10 STA &1084 ;no catalogue in pages &0E..F #if defined _DDOS316 A3C9 20 4B B7 JSR S74B ;no-op #elif defined _DDOS336 A3C9 20 4B B7 JSR S74B ;no-op #else A3C9 20 49 B7 JSR S749 ;no-op #endif A3CC 20 45 93 JSR Q345 ;ensure Tube is released A3CF 4C 00 01 JMP &0100 ;jump to BRK to raise error .R3D2 ;Print VDU sequence immediate A3D2 68 PLA ;pop caller's address into pointer A3D3 85 AE STA &AE A3D5 68 PLA A3D6 85 AF STA &AF A3D8 A0 00 LDY #&00 ;offset = 0 for indirect indexed load .R3DA A3DA 20 B4 A4 JSR R4B4 ;increment &AE,F A3DD B1 AE LDA (&AE),Y ;get character from after JSR A3DF C9 FF CMP #&FF ;if &FF terminator byte A3E1 F0 06 BEQ R3E9 ;then skip it and return to code after it A3E3 20 EE FF JSR &FFEE ;else call OSWRCH A3E6 4C DA A3 JMP R3DA ;and loop .R3E9 A3E9 20 B4 A4 JSR R4B4 ;increment &AE,F A3EC 6C AE 00 JMP (&00AE) ;jump to address at end of string .R3EF ;Begin error message, number in A A3EF 8D 01 01 STA &0101 ;&0101 = error number A3F2 A9 00 LDA #&00 ;instruction at &0100 = BRK A3F4 8D 00 01 STA &0100 A3F7 A9 02 LDA #&02 ;error message being built from offset 2 A3F9 8D DD 10 STA &10DD A3FC 60 RTS ;[BUG] If ?&10DD < &80 (because DDOS is not the static workspace owner) ;then the location is corrupted when DDOS prints a message such as ;*HELP text; also, DDOS writes the first few characters of the message ;to the stack page instead of the screen. .R3FD ;Print letter N A3FD A9 4E LDA #&4E A3FF D0 02 BNE R403 ;branch (always) .R401 ;Print a dot A401 A9 2E LDA #&2E .R403 ;Print character in A (OSASCI) A403 20 00 A3 JSR R300 ;save AXY A406 2C DD 10 BIT &10DD ;if error message is being built A409 10 14 BPL R41F ;then append character to error message A40B 48 PHA ;else save character A40C 20 08 A8 JSR R808 ;call OSBYTE &EC = read/write char dest status A40F 8A TXA ;save current output stream setting A410 48 PHA A411 09 10 ORA #&10 ;b4=1 disable *SPOOL output A413 20 03 A8 JSR R803 ;call OSBYTE &03 = specify output stream in A A416 68 PLA ;restore previous output stream setting A417 AA TAX A418 68 PLA ;restore character A419 20 E3 FF JSR &FFE3 ;call OSASCI A41C 4C 04 A8 JMP R804 ;call OSBYTE &03 = specify output stream .R41F ;Append character to error message A41F AE DD 10 LDX &10DD ;get pointer to end of error message A422 9D 00 01 STA &0100,X ;store character there A425 EE DD 10 INC &10DD ;and increment pointer A428 60 RTS .R429 ;Print hex byte A429 48 PHA ;save A A42A 20 67 A4 JSR R467 ;shift A right 4 places A42D 20 31 A4 JSR R431 ;print top nibble of byte A430 68 PLA ;restore bottom nibble: .R431 ;Print hex nibble A431 48 PHA ;save A A432 29 0F AND #&0F ;extract b3..0 A434 F8 SED ;set decimal mode for 6502 deep magic A435 18 CLC A436 69 90 ADC #&90 ;a=&90..99, C=0 or A=&00..05, C=1 A438 69 40 ADC #&40 ;a=&30..39 or A=&41..46 A43A D8 CLD ;clear decimal mode A43B 20 03 A4 JSR R403 ;print character in A (OSASCI) A43E 68 PLA ;restore A A43F 60 RTS .R440 ;Poll for ESCAPE #if defined _TURBO A440 20 2D A3 JSR R32D ;save XY #else A440 20 29 A3 JSR R329 ;save XY #endif A443 20 F7 A7 JSR R7F7 ;call INKEY(0) A446 C0 1B CPY #&1B ;if ESCAPE was pressed A448 D0 0D BNE R457 A44A 20 58 A4 JSR R458 ;then acknowledge ESCAPE condition A44D 20 A7 A7 JSR R7A7 ;release NMI A450 AE 10 10 LDX &1010 ;restore stack pointer from &1010 A453 9A TXS A454 6C 11 10 JMP (&1011) ;and restart command .R457 A457 60 RTS ;else return .R458 ;Acknowledge ESCAPE condition A458 A9 7E LDA #&7E ;OSBYTE &7E = acknowledge ESCAPE condition A45A 4C F4 FF JMP &FFF4 ;call OSBYTE and exit .R45D ;Extract b7,b6 of A A45D 4A LSR A A45E 4A LSR A .R45F ;Extract b5,b4 of A A45F 4A LSR A A460 4A LSR A .R461 ;Extract b3,b2 of A A461 4A LSR A A462 4A LSR A A463 29 03 AND #&03 A465 60 RTS .R466 ;Shift A right 5 places A466 4A LSR A .R467 ;Shift A right 4 places A467 4A LSR A A468 4A LSR A A469 4A LSR A A46A 4A LSR A A46B 60 RTS ;unreachable code A46C 0A ASL A .R46D ;Shift A left 4 places A46D 0A ASL A A46E 0A ASL A A46F 0A ASL A A470 0A ASL A A471 60 RTS .R472 ;Add 8 to Y A472 C8 INY .R473 ;Add 7 to Y A473 C8 INY A474 C8 INY A475 C8 INY #if defined _DFSFIX .R476 ;Add 4 to Y #endif A476 C8 INY A477 C8 INY A478 C8 INY A479 C8 INY A47A 60 RTS .R47B ;Subtract 8 from Y A47B 88 DEY A47C 88 DEY A47D 88 DEY A47E 88 DEY A47F 88 DEY A480 88 DEY A481 88 DEY A482 88 DEY A483 60 RTS .R484 ;Uppercase and validate letter in A A484 C9 41 CMP #&41 ;is character less than capital A? A486 90 0C BCC R494 ;if so then return C=1 A488 C9 5B CMP #&5B ;else is it more than capital Z? A48A 90 0A BCC R496 ;if not then uppercase and return C=0 A48C C9 61 CMP #&61 ;else is it less than lowercase a? A48E 90 04 BCC R494 ;if so then return C=1 A490 C9 7B CMP #&7B ;else is it more than lowercase z? A492 90 02 BCC R496 ;if not then uppercase and return C=0 .R494 A494 38 SEC ;else return C=1 A495 60 RTS .R496 A496 29 DF AND #&DF ;mask bit 5, convert letter to uppercase A498 18 CLC A499 60 RTS .R49A ;Set C=0 iff character in A is a letter A49A 48 PHA A49B 20 84 A4 JSR R484 ;uppercase and validate letter in A A49E 68 PLA A49F 60 RTS .R4A0 ;Convert ASCII hex digit to binary A4A0 20 AA A4 JSR R4AA ;c=0 iff digit valid A4A3 90 03 BCC R4A8 ;[BUG]accepts characters &3A..F (:..?) A4A5 C9 10 CMP #&10 A4A7 60 RTS .R4A8 A4A8 38 SEC A4A9 60 RTS .R4AA A4AA C9 41 CMP #&41 ;if digit is less than A A4AC 90 02 BCC R4B0 ;then convert 0..9 to binary A4AE E9 07 SBC #&07 ;else convert A..F to binary .R4B0 A4B0 38 SEC A4B1 E9 30 SBC #&30 A4B3 60 RTS .R4B4 ;Increment &AE,F A4B4 E6 AE INC &AE A4B6 D0 02 BNE R4BA A4B8 E6 AF INC &AF .R4BA A4BA 60 RTS .R4BB ;Call GSINIT with C=0 A4BB 18 CLC ;c=0 space or CR terminates unquoted strings A4BC 4C C2 FF JMP &FFC2 ;jump to GSINIT .R4BF ;Set current drive from ASCII digit A4BF 38 SEC A4C0 E9 30 SBC #&30 ;convert ASCII digit to binary A4C2 90 4D BCC R511 ;if invalid raise "Bad drive" error A4C4 85 CF STA &CF ;else set current drive=digit, volume=A #if defined _RAMBUGFIX A4C6 C9 22 CMP #&22 ;was drive number capital R? A4C8 4C 09 A5 JMP R509 ;if so replace with 4 else accept digits 0..7. #else A4C6 A5 CF LDA &CF ;get current volume A4C8 4C 8F A5 JMP R58F ;ensure drive number in range 0..3. #endif .R4CB ;Set volume from ASCII letter A4CB 20 84 A4 JSR R484 ;uppercase and validate letter in A A4CE 38 SEC ;subtract ASCII value of A A4CF E9 41 SBC #&41 ;obtain ordinal 0..25 A4D1 90 3E BCC R511 ;if ordinal negative then "Bad drive" A4D3 C9 08 CMP #&08 ;else is ordinal 8 or more? A4D5 B0 3A BCS R511 ;if so then raise "Bad drive" error A4D7 20 6D A4 JSR R46D ;else shift A left 4 places A4DA 05 CF ORA &CF ;combine volume letter with current drive A4DC 85 CF STA &CF ;set as current volume, return C=0 A4DE 60 RTS .R4DF ;Call GSINIT and parse mandatory vol spec A4DF 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg A4E2 4C 4F A5 JMP R54F ;parse volume spec .R4E5 ;Select specified or default volume A4E5 20 BB A4 JSR R4BB ;call GSINIT with C=0 A4E8 F0 16 BEQ R500 ;if argument empty select default volume A4EA 20 4F A5 JSR R54F ;else parse volume spec A4ED 4C D6 A7 JMP R7D6 ;set up for current drive and exit .R4F0 A4F0 AD CA 10 LDA &10CA ;get default directory A4F3 85 CE STA &CE ;set as current directory A4F5 AD CB 10 LDA &10CB ;get default volume #if defined _RAMBUGFIX .R4F8 #endif A4F8 85 CF STA &CF ;set as current volume A4FA 60 RTS .R4FB A4FB AD CA 10 LDA &10CA ;get default directory A4FE 85 CE STA &CE ;set as current directory .R500 A500 AD CB 10 LDA &10CB ;get default volume: .R503 ;Select volume in A A503 85 CF STA &CF ;save as current volume A505 20 D6 A7 JSR R7D6 ;set up for drive #if defined _RAMBUGFIX A508 60 RTS .R509 A509 D0 02 BNE R50D ;if drive number equals R A50B A9 04 LDA #&04 ;then substitute drive 4 .R50D A50D C9 08 CMP #&08 ;if drive number in range 0..7 A50F 90 E7 BCC R4F8 ;then save it as current drive #else .R508 A508 60 RTS ;unreachable code A509 20 E5 A4 JSR R4E5 ;select specified or default volume A50C 20 BB A4 JSR R4BB ;call GSINIT with C=0 A50F F0 F7 BEQ R508 ;if no more arguments then return #endif .R511 ;else raise "Bad drive" error. A511 20 51 A3 JSR R351 A514 EQUB &CD A515 EQUS "drive" A51A EQUB &00 .R51B ;Parse directory spec A51B 20 C5 FF JSR &FFC5 ;call GSREAD A51E B0 2E BCS R54E ;if end of argument then exit C=1 A520 C9 3A CMP #&3A ;else is character a colon? A522 D0 22 BNE R546 ;if not then accept directory character A524 20 C5 FF JSR &FFC5 ;else call GSREAD A527 B0 E8 BCS R511 ;if ":" by itself then "Bad drive" error A529 20 BF A4 JSR R4BF ;else set current drive from ASCII digit A52C 20 C5 FF JSR &FFC5 ;call GSREAD A52F B0 1D BCS R54E ;if ":<drv>" keep current volume and dir A531 C9 2E CMP #&2E ;else is character a full stop? A533 F0 0C BEQ R541 ;if so then expect a directory character A535 20 CB A4 JSR R4CB ;else set volume from ASCII letter A538 20 C5 FF JSR &FFC5 ;call GSREAD A53B B0 11 BCS R54E ;if ":<drv><vol>" keep current directory A53D C9 2E CMP #&2E ;else ".<dir>" must follow A53F D0 D0 BNE R511 ;if next char not full stop "Bad drive" .R541 A541 20 C5 FF JSR &FFC5 ;else call GSREAD A544 B0 CB BCS R511 ;directory char expected else "Bad drive" .R546 A546 20 80 A5 JSR R580 ;set directory from ASCII character A549 20 C5 FF JSR &FFC5 ;if not at end of argument A54C 90 C3 BCC R511 ;then raise "Bad drive" error. .R54E A54E 60 RTS .R54F ;Parse volume spec A54F A2 00 LDX #&00 ;x=0, nothing specified A551 20 C5 FF JSR &FFC5 ;call GSREAD A554 B0 F8 BCS R54E ;if end of argument then exit C=1 A556 08 PHP ;else save status, C=0 A557 C9 3A CMP #&3A ;is character a colon? A559 D0 05 BNE R560 ;if not then set drive from digit A55B 20 C5 FF JSR &FFC5 ;else call GSREAD A55E B0 B1 BCS R511 ;if ":" by itself then "Bad drive" error .R560 A560 20 BF A4 JSR R4BF ;set current drive from ASCII digit A563 A2 02 LDX #&02 ;x=2, only drive specified A565 20 C5 FF JSR &FFC5 ;call GSREAD A568 B0 0F BCS R579 ;if no more chars return drive, volume=A A56A 28 PLP ;else restore status, C=0 A56B 90 07 BCC R574 ;set volume and return current volume ;unreachable code A56D C9 2A CMP #&2A A56F D0 03 BNE R574 A571 A2 83 LDX #&83 A573 60 RTS .R574 A574 20 CB A4 JSR R4CB ;set volume letter from ASCII letter A577 E8 INX ;x=3, drive and volume specified A578 08 PHP ;save status, C=0 .R579 A579 28 PLP ;restore status, C=0 A57A A5 CF LDA &CF ;get current volume and exit A57C 60 RTS ;unreachable code A57D 20 C5 FF JSR &FFC5 .R580 ;Set directory from ASCII character A580 C9 2A CMP #&2A ;make * an alias of # A582 D0 02 BNE R586 A584 A9 23 LDA #&23 .R586 A586 85 CE STA &CE ;set as current directory A588 18 CLC A589 60 RTS #if defined _RAMBUGFIX .R58F ;Set up for RAM disc A58F A9 00 LDA #&00 A591 8D E1 10 STA &10E1 ;number of sectors per track is undefined A594 38 SEC ;set carry flag for later A595 B0 6C BCS R603 ;jump to patch to continue #else /* _RAMBUGFIX */ ;unreachable code ;Convert ASCII drive number to binary A58A 38 SEC A58B E9 30 SBC #&30 A58D 90 05 BCC R594 ;if invalid then raise "Bad drive" error .R58F ;Ensure drive number in range A58F C9 04 CMP #&04 ;0..3 A591 B0 01 BCS R594 ;if invalid then raise "Bad drive" error A593 60 RTS ;else exit .R594 A594 4C 11 A5 JMP R511 ;raise "Bad drive" error #endif /* _RAMBUGFIX */ .R597 ;Set current vol/dir from open filename A597 B9 0E 11 LDA &110E,Y ;get directory character of open file A59A 29 7F AND #&7F ;mask off b7 =channel file locked bit A59C 85 CE STA &CE ;set as current directory A59E B9 1F 11 LDA &111F,Y ;get volume containing open file A5A1 4C 03 A5 JMP R503 ;select volume in A and exit ;NB NMI area must be claimed before use. ;[BUG] If called on RAM disc then double density flag is not cleared. .R5A4 ;Detect disc format/set sector address A5A4 A9 00 LDA #&00 ;set track number = 0 A5A6 85 BA STA &BA A5A8 A5 CF LDA &CF ;get current volume A5AA 29 0C AND #&0C ;if b3 or b2 are set #if defined _RAMBUGFIX A5AC D0 E1 BNE R58F ;then a RAM drive so set up for RAM disc # if defined _DDOS316 A5AE 20 7E B6 JSR S67E ;else recalibrate drive (seek track 0) # elif defined _DDOS336 A5AE 20 7E B6 JSR S67E ;else recalibrate drive (seek track 0) # else A5AE 20 7C B6 JSR S67C ;else recalibrate drive (seek track 0) # endif A5B1 AD 00 10 LDA &1000 ;if data transfer call is not 0 = read data A5B4 D0 5A BNE R610 ;then set sector number = 2 * volume letter A5B6 8D E2 10 STA &10E2 ;else data area starts on track 0 A5B9 20 1F A6 JSR R61F ;set number of sectors per track A5BC 2C E3 10 BIT &10E3 ;if disc is double density A5BF 70 09 BVS R5CA ;then accept any volume letter A5C1 A5 CF LDA &CF ;else get current volume A5C3 29 F0 AND #&F0 ;extract volume letter A5C5 F0 03 BEQ R5CA ;if volume letter is not A A5C7 4C 11 A5 JMP R511 ;then raise "Bad drive" error .R5CA A5CA 2C E0 10 BIT &10E0 ;if double-stepping is automatic A5CD 10 03 BPL R5D2 A5CF 20 31 A6 JSR R631 ;then detect track stepping .R5D2 A5D2 2C E3 10 BIT &10E3 ;if disc is single density A5D5 50 39 BVC R610 ;then set sector number = 0 A5D7 20 F5 AF JSR RFF5 ;else copy volume allocations to wksp A5DA AD 00 0E LDA &0E00 ;test configuration/version number A5DD C9 E5 CMP #&E5 ;of disc catalogue A5DF D0 03 BNE R5E4 ;if byte is &E5 formatting fill byte A5E1 4C 7E A6 JMP R67E ;then "Disk not configured by VOLGEN" .R5E4 A5E4 AD 01 0E LDA &0E01 ;get number of sectors on surface A5E7 8D 0E 10 STA &100E ;save in workspace A5EA AD 02 0E LDA &0E02 A5ED 8D 0F 10 STA &100F A5F0 AD 03 0E LDA &0E03 ;get number of sectors per track A5F3 8D E1 10 STA &10E1 ;save in workspace A5F6 20 15 A6 JSR R615 ;set sector number = 2 * volume letter A5F9 A8 TAY ;= offset into the track allocation table A5FA B9 08 0E LDA &0E08,Y ;get first track of volume from disc cat. A5FD 8D E2 10 STA &10E2 ;set as first track of current volume A600 F0 56 BEQ R658 ;if =0 raise "Volume . not allocated" error A602 60 RTS .R603 ;Set up for RAM disc part 2 A603 8D E2 10 STA &10E2 ;a=0; data area starts on track 0 A606 85 BB STA &BB ;sector number = 0 A608 6A ROR A ;c=1; set a=&80 A609 2D E3 10 AND &10E3 ;preserve b7 = automatic density A60C 8D E3 10 STA &10E3 ;clear b6=0 single density A60F 60 RTS ;exit #else /* _RAMBUGFIX */ A5AC D0 57 BNE R605 ;then a RAM drive so set up for RAM disc # if defined _DDOS316 A5AE 20 7E B6 JSR S67E ;else recalibrate drive (seek track 0) # elif defined _DDOS336 A5AE 20 7E B6 JSR S67E ;else recalibrate drive (seek track 0) # else A5AE 20 7C B6 JSR S67C ;else recalibrate drive (seek track 0) # endif A5B1 AD 00 10 LDA &1000 ;if data transfer call is not 0 = read data A5B4 D0 5A BNE R610 ;then set sector number = 2 * volume letter A5B6 A9 00 LDA #&00 ;else data area starts on track 0 A5B8 8D E2 10 STA &10E2 A5BB 20 1F A6 JSR R61F ;set number of sectors per track A5BE 2C E3 10 BIT &10E3 ;if disc is double density A5C1 70 09 BVS R5CC ;then accept any volume letter A5C3 A5 CF LDA &CF ;else get current volume A5C5 29 F0 AND #&F0 ;extract volume letter A5C7 F0 03 BEQ R5CC ;if volume letter is not A A5C9 4C 11 A5 JMP R511 ;then raise "Bad drive" error .R5CC A5CC 2C E0 10 BIT &10E0 ;if double-stepping is automatic A5CF 10 03 BPL R5D4 A5D1 20 31 A6 JSR R631 ;then detect track stepping .R5D4 A5D4 2C E3 10 BIT &10E3 ;if disc is single density A5D7 50 37 BVC R610 ;then set sector number = 0 A5D9 20 F5 AF JSR RFF5 ;else copy volume allocations to wksp A5DC AD 00 0E LDA &0E00 ;test configuration/version number A5DF C9 E5 CMP #&E5 ;of disc catalogue A5E1 D0 03 BNE R5E6 ;if byte is &E5 formatting fill byte A5E3 4C 7E A6 JMP R67E ;then "Disk not configured by VOLGEN" .R5E6 A5E6 AD 01 0E LDA &0E01 ;get number of sectors on surface A5E9 8D 0E 10 STA &100E ;save in workspace A5EC AD 02 0E LDA &0E02 A5EF 8D 0F 10 STA &100F A5F2 AD 03 0E LDA &0E03 ;get number of sectors per track A5F5 8D E1 10 STA &10E1 ;save in workspace A5F8 20 15 A6 JSR R615 ;set sector number = 2 * volume letter A5FB A8 TAY ;= offset into the track allocation table A5FC B9 08 0E LDA &0E08,Y ;get first track of volume from disc cat. A5FF 8D E2 10 STA &10E2 ;set as first track of current volume A602 F0 54 BEQ R658 ;if =0 raise "Volume . not allocated" error A604 60 RTS .R605 ;Set up for RAM disc A605 A9 00 LDA #&00 A607 8D E1 10 STA &10E1 ;number of sectors per track is undefined A60A 8D E2 10 STA &10E2 ;data area starts on track 0 A60D 85 BB STA &BB ;sector number = 0 A60F 60 RTS #endif /* _RAMBUGFIX */ .R610 ;Set sector number = 2 * volume letter A610 AD E3 10 LDA &10E3 ;test density flag A613 F0 07 BEQ R61C ;if single (and manual!) then start sector =0 .R615 A615 A5 CF LDA &CF ;else get current volume A617 29 F0 AND #&F0 ;extract volume letter A619 4A LSR A ;shift right three places A61A 4A LSR A ;to get sector offset of volume catalogue A61B 4A LSR A .R61C A61C 85 BB STA &BB ;set as sector number A61E 60 RTS .R61F ;Set number of sectors per track A61F 2C E3 10 BIT &10E3 ;if density setting is automatic A622 10 03 BPL R627 #if defined _DDOS316 A624 4C C4 B6 JMP S6C4 ;then ensure disc is formatted #elif defined _DDOS336 A624 4C C4 B6 JMP S6C4 ;then ensure disc is formatted #else A624 4C C2 B6 JMP S6C2 ;then ensure disc is formatted #endif .R627 A627 A9 0A LDA #&0A ;else set 10 sectors per track A629 50 02 BVC R62D ;unless disc is double density A62B A9 12 LDA #&12 ;in which case set 18 sectors per track .R62D A62D 8D E1 10 STA &10E1 A630 60 RTS .R631 ;Detect track stepping A631 A9 80 LDA #&80 ;b7=1 automatic, b6=0 1:1 stepping A633 8D E0 10 STA &10E0 ;set stepping flag A636 A9 02 LDA #&02 ;track number = 2 #if defined _DDOS316 A638 20 99 B6 JSR S699 ;seek physical track A63B 20 14 B7 JSR S714 ;execute Read Address command #elif defined _DDOS336 A638 20 99 B6 JSR S699 ;seek physical track A63B 20 14 B7 JSR S714 ;execute Read Address command #else A638 20 97 B6 JSR S697 ;seek physical track A63B 20 12 B7 JSR S712 ;execute Read Address command #endif A63E AE 02 10 LDX &1002 ;get C cylinder number A641 CA DEX ;is it 1? A642 F0 0A BEQ R64E ;then disc is 40 track, set double stepping A644 CA DEX ;else is it 2? A645 F0 0C BEQ R653 ;then 1:1 stepping is correct, recalibrate A647 CA DEX ;else the format is wrong, raise an error A648 CA DEX ;is the head over logical track 4? A649 D0 55 BNE R6A0 ;if not then raise "Bad track format" error A64B 4C B5 A6 JMP R6B5 ;else "80 track disk in 40 track drive". .R64E A64E A9 C0 LDA #&C0 ;b7=1 automatic, b6=1 2:1 stepping A650 8D E0 10 STA &10E0 ;set stepping flag .R653 A653 A9 00 LDA #&00 ;track number = 0 #if defined _DDOS316 A655 4C 99 B6 JMP S699 ;seek physical track #elif defined _DDOS336 A655 4C 99 B6 JMP S699 ;seek physical track #else A655 4C 97 B6 JMP S697 ;seek physical track #endif .R658 ;Raise "Volume . not allocated" error A658 20 62 A3 JSR R362 ;begin error message "Volume " A65B EQUB &CD A65C EQUS "Volume " A663 EA NOP A664 18 CLC A665 98 TYA ;transfer sector offset to A A666 4A LSR A ;divide by 2; A=0..7, C=0 A667 69 41 ADC #&41 ;convert to ASCII character "A".."H" A669 20 03 A4 JSR R403 ;print character in A (to error message) A66C 20 94 A3 JSR R394 ;print " not allocated" and raise error A66F EQUS " not allocated" A67D EQUB &00 .R67E A67E 20 62 A3 JSR R362 A681 EQUB &CD A682 EQUS "Disk not configured by VOLGEN" A69F EQUB &00 .R6A0 A6A0 20 62 A3 JSR R362 A6A3 EQUB &CD A6A4 EQUS "Bad track format" A6B4 EQUB &00 .R6B5 A6B5 20 62 A3 JSR R362 A6B8 EQUB &CD A6B9 EQUS "80 track disk in 40 track drive" A6D8 EQUB &00 .R6D9 ;Load disc catalogue L3 A6D9 A9 00 LDA #&00 ;data transfer call &00 = read data A6DB F0 02 BEQ R6DF ;branch (always) .R6DD ;Write disc catalogue L3 A6DD A9 01 LDA #&01 ;data transfer call &01 = write data .R6DF A6DF 8D 00 10 STA &1000 ;set data transfer call number A6E2 A2 03 LDX #&03 ;x = 3 number of attempts allowed: .R6E4 A6E4 20 ED 92 JSR Q2ED ;set data pointer to &0E00 A6E7 A9 10 LDA #&10 ;set sector number = 16 A6E9 85 BB STA &BB A6EB A9 00 LDA #&00 ;set track number = 0 A6ED 85 BA STA &BA A6EF 85 A0 STA &A0 ;&0100 = 256 bytes to transfer A6F1 A9 01 LDA #&01 A6F3 85 A1 STA &A1 #if defined _DDOS316 A6F5 20 5F B7 JSR S75F ;transfer data to disc L2 #elif defined _DDOS336 A6F5 20 5F B7 JSR S75F ;transfer data to disc L2 #else A6F5 20 5D B7 JSR S75D ;transfer data to disc L2 #endif A6F8 D0 01 BNE R6FB ;if command failed try again A6FA 60 RTS ;else exit .R6FB A6FB CA DEX ;decrement attempts remaining A6FC D0 E6 BNE R6E4 ;if not run out then try again #if defined _DDOS316 A6FE 4C 95 B9 JMP S995 ;else raise "Disk fault" error #elif defined _DDOS336 A6FE 4C 93 B9 JMP S993 ;else raise "Disk fault" error #elif defined _DDOS357 A6FE 4C B2 B9 JMP S9B2 ;else raise "Disk fault" error #else A6FE 4C B6 B9 JMP S9B6 ;else raise "Disk fault" error #endif ;unreachable code A701 60 RTS .R702 ;Transfer data and report errors L4 A702 20 00 A3 JSR R300 ;save AXY A705 20 15 A7 JSR R715 ;transfer data L3 A708 D0 01 BNE R70B ;if non-zero status report error A70A 60 RTS ;else return .R70B A70B 29 40 AND #&40 A70D D0 03 BNE R712 ;if b6=0 WD1770 S6 = write protect #if defined _DDOS316 A70F 4C 95 B9 JMP S995 ;then raise "Disk fault" error #elif defined _DDOS336 A70F 4C 93 B9 JMP S993 ;then raise "Disk fault" error #elif defined _DDOS357 A70F 4C B2 B9 JMP S9B2 ;then raise "Disk fault" error #else A70F 4C B6 B9 JMP S9B6 ;then raise "Disk fault" error #endif .R712 A712 4C 38 A3 JMP R338 ;else raise "Disk read only" error ;[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. .R715 ;Transfer data L3 #if defined _TURBO A715 20 2D A3 JSR R32D ;save XY #else A715 20 29 A3 JSR R329 ;save XY #endif A718 A9 05 LDA #&05 ;set attempt counter to 5 A71A 8D 2A 10 STA &102A .R71D A71D AD E1 10 LDA &10E1 ;get number of sectors per track A720 08 PHP ;save Z flag A721 A6 A3 LDX &A3 ;set X=LSB byte count A723 A5 A4 LDA &A4 ;set A=2MSB byte count A725 28 PLP ;restore Z flag A726 F0 18 BEQ R740 ;if 0 sectors per track then RAM disc, branch A728 38 SEC ;else subtract A729 AD E1 10 LDA &10E1 ;number of sectors per track A72C E5 BB SBC &BB ;- starting sector A72E 85 A0 STA &A0 ;= sectors until end, store temp A730 A5 A5 LDA &A5 ;test MSB byte count A732 D0 08 BNE R73C ;if >=64 KiB then transfer rest of track A734 A6 A3 LDX &A3 ;else X=LSB byte count (redundant to &A721) A736 A5 A4 LDA &A4 ;set A=2MSB byte count A738 C5 A0 CMP &A0 ;if transfer ends before end of track A73A 90 04 BCC R740 ;then only transfer byte count, else: .R73C ;transfer rest of track A73C A2 00 LDX #&00 ;X=0 byte count is a multiple of 256 A73E A5 A0 LDA &A0 ;A=number of sectors (not bytes) to transfer: .R740 A740 8E 85 10 STX &1085 ;store LSB byte count A743 8D 86 10 STA &1086 ;store MSB byte count A746 86 A0 STX &A0 ;store LSB byte count A748 85 A1 STA &A1 ;store MSB byte count A74A 05 A0 ORA &A0 ;test if byte count > 0 A74C F0 53 BEQ R7A1 ;if no data to transfer then finish A74E 20 67 B4 JSR S467 ;else transfer data L2 A751 F0 0C BEQ R75F ;if zero status then continue A753 29 40 AND #&40 ;else if b6=1 WD1770 S6 = write protect A755 D0 07 BNE R75E ;then return A757 CE 2A 10 DEC &102A ;decrement attempt counter A75A D0 C1 BNE R71D ;if not tried 5 times then try again A75C A9 01 LDA #&01 ;else return A=1, Z=0 .R75E A75E 60 RTS .R75F A75F E6 BA INC &BA ;increment track A761 A9 00 LDA #&00 A763 85 BB STA &BB ;next transfer starts at sector 0 A765 18 CLC A766 AD 86 10 LDA &1086 ;add MSB of expected transfer size A769 6D 6E 10 ADC &106E ;to 3MSB Tube transfer address? (and discard!) ;[BUG] ?&106E is constant, high word either ;never changes or increments every track. ;The wrong address never reaches the copro- ;cessor which increments the initial address ;locally and so large Tube transfers work A76C 90 08 BCC R776 ;carry out to high word of Tube transfer addr A76E EE 6F 10 INC &106F ;= high word of OSFILE load address A771 D0 03 BNE R776 A773 EE 70 10 INC &1070 .R776 A776 18 CLC ;add expected transfer size to xfer. address A777 A5 A6 LDA &A6 A779 6D 85 10 ADC &1085 A77C 85 A6 STA &A6 A77E A5 A7 LDA &A7 A780 6D 86 10 ADC &1086 A783 85 A7 STA &A7 A785 38 SEC ;subtract expected transfer size A786 A5 A3 LDA &A3 ;from 24-bit byte count A788 ED 85 10 SBC &1085 A78B 85 A3 STA &A3 A78D A5 A4 LDA &A4 A78F ED 86 10 SBC &1086 A792 85 A4 STA &A4 A794 B0 02 BCS R798 A796 C6 A5 DEC &A5 .R798 A798 05 A3 ORA &A3 ;test remaining no. bytes to transfer A79A 05 A5 ORA &A5 A79C F0 03 BEQ R7A1 ;if no more data to transfer then finish A79E 4C 1D A7 JMP R71D ;else loop to transfer rest of file. .R7A1 A7A1 20 A7 A7 JSR R7A7 ;release NMI A7A4 A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. A7A6 60 RTS .R7A7 ;Release NMI A7A7 2C 87 10 BIT &1087 ;if NMI is not already ours A7AA 10 0C BPL R7B8 ;then exit A7AC AC 88 10 LDY &1088 ;else Y = ID of previous NMI owner A7AF C0 FF CPY #&FF ;if Y=&FF no previous owner A7B1 F0 05 BEQ R7B8 ;then skip release call [BUG]improper! A7B3 A2 0B LDX #&0B ;else service call &0B = NMI release A7B5 20 18 A8 JSR R818 ;call OSBYTE &8F = issue service call .R7B8 A7B8 A9 00 LDA #&00 A7BA 8D 87 10 STA &1087 ;&00 = NMI not ours #if defined _DDOS316 A7BD 20 4B B7 JSR S74B ;no-op #elif defined _DDOS336 A7BD 20 4B B7 JSR S74B ;no-op #else A7BD 20 49 B7 JSR S749 ;no-op #endif A7C0 60 RTS .R7C1 ;Claim NMI A7C1 2C 87 10 BIT &1087 ;if NMI is already ours A7C4 30 0F BMI R7D5 ;then exit A7C6 A9 8F LDA #&8F ;else OSBYTE &8F = issue service call A7C8 A2 0C LDX #&0C ;service call &0C = claim NMI A7CA 20 20 A8 JSR R820 ;call OSBYTE with Y=&FF A7CD 8C 88 10 STY &1088 ;save ID of previous NMI owner A7D0 A9 FF LDA #&FF ;set NMI ownership flag A7D2 8D 87 10 STA &1087 ;b7=1 iff we own the NMI .R7D5 A7D5 60 RTS .R7D6 ;Set up for current drive A7D6 A5 CF LDA &CF ;get current drive A7D8 29 0C AND #&0C ;if (drive number mod 16) = 0..3 A7DA D0 03 BNE R7DF A7DC 20 58 B6 JSR S658 ;then set control latch for drive .R7DF A7DF A5 CF LDA &CF ;return current drive in A A7E1 60 RTS .R7E2 ;Test write protect state of current drive A7E2 A5 CF LDA &CF ;get current volume A7E4 29 0C AND #&0C ;is the physical drive a RAM disc? A7E6 D0 03 BNE R7EB ;if so return Z=1, write enabled #if defined _DDOS316 A7E8 4C 75 B6 JMP S675 ;else test write protect state #elif defined _DDOS336 A7E8 4C 75 B6 JMP S675 ;else test write protect state #else A7E8 4C 73 B6 JMP S673 ;else test write protect state #endif .R7EB A7EB A9 00 LDA #&00 A7ED 60 RTS .R7EE ;Call *FX 15,1 = clear input buffer A7EE 20 00 A3 JSR R300 ;save AXY A7F1 A9 0F LDA #&0F A7F3 A2 01 LDX #&01 A7F5 D0 08 BNE R7FF .R7F7 ;Call INKEY(0) A7F7 A9 81 LDA #&81 ;OSBYTE &81 = read key within time limit A7F9 D0 02 BNE R7FD ;call OSBYTE with X=0, Y=0 .R7FB ;Disable *SPOOL output A7FB A9 C7 LDA #&C7 ;OSBYTE &C7 = read/write *SPOOL file handle .R7FD ;Call OSBYTE with X=0, Y=0 A7FD A2 00 LDX #&00 .R7FF ;Call OSBYTE with Y=0 A7FF A0 00 LDY #&00 A801 F0 1F BEQ R822 ;call OSBYTE .R803 ;Call OSBYTE &03 = specify output stream in A A803 AA TAX .R804 ;Call OSBYTE &03 = specify output stream A804 A9 03 LDA #&03 A806 D0 1A BNE R822 .R808 ;Call OSBYTE &EC = read/write char dest status A808 A9 EC LDA #&EC A80A D0 12 BNE R81E .R80C ;Call OSBYTE &C7 = read/write *SPOOL handle A80C A9 C7 LDA #&C7 A80E D0 0E BNE R81E .R810 ;Call OSBYTE &EA = read Tube presence flag A810 A9 EA LDA #&EA A812 D0 0A BNE R81E .R814 ;Call OSBYTE &A8 = get ext. vector table addr A814 A9 A8 LDA #&A8 A816 D0 06 BNE R81E .R818 ;Call OSBYTE &8F = issue service call A818 A9 8F LDA #&8F A81A D0 06 BNE R822 .R81C ;Call OSBYTE &FF = read/write startup options A81C A9 FF LDA #&FF .R81E A81E A2 00 LDX #&00 .R820 A820 A0 FF LDY #&FF .R822 A822 4C F4 FF JMP &FFF4 ;Table of addresses of extended vector handlers A825 EQUW &1B,&FF ;FILEV, &0212 = &FF1B A827 EQUW &1E,&FF ;ARGSV, &0214 = &FF1E A829 EQUW &21,&FF ;BGETV, &0216 = &FF21 A82B EQUW &24,&FF ;BPUTV, &0218 = &FF24 A82D EQUW &27,&FF ;GBPBV, &021A = &FF27 A82F EQUW &2A,&FF ;FINDV, &021C = &FF2A A831 EQUW &2D,&FF ;FSCV, &021E = &FF2D ;Table of action addresses for extended vector table A833 EQUW &DC,&9A ;E FILEV, evt + &1B = &9ADC A835 EQUW &94,&97 ;E ARGSV, evt + &1E = &9794 A837 EQUW &DA,&98 ;E BGETV, evt + &21 = &98DA A839 EQUW &B6,&99 ;E BPUTV, evt + &24 = &99B6 A83B EQUW &2D,&9C ;E GBPBV, evt + &27 = &9C2D #if defined _DFSFIX A83D EQUW &D2,&BF ;E FINDV, evt + &2A = &BFD2 #else A83D EQUW &C1,&95 ;E FINDV, evt + &2A = &95C1 #endif #if defined _DDOS357 A83F EQUW &40,&BF ;E FSCV, evt + &2D = &BF40 #else A83F EQUW &68,&94 ;E FSCV, evt + &2D = &9468 #endif ;Table of action addresses for FSC calls 0..8, low bytes A841 EQUB &7A ;FSC 0 = *OPT &947B A842 EQUB &B5 ;FSC 1 = read EOF state &94B6 #if defined _DDOS357 A843 EQUB &D1 ;FSC 2 = */ &94D2 A844 EQUB &4A ;FSC 3 = unrecognised *cmd &954B A845 EQUB &D1 ;FSC 4 = *RUN &94D2 #else A843 EQUB &CD ;FSC 2 = */ &94CE A844 EQUB &4A ;FSC 3 = unrecognised *cmd &954B A845 EQUB &CD ;FSC 4 = *RUN &94CE #endif A846 EQUB &5C ;FSC 5 = *CAT &955D A847 EQUB &74 ;FSC 6 = new FS starting up &9575 A848 EQUB &7C ;FSC 7 = valid file handles &957D A849 EQUB &81 ;FSC 8 = *command entered &9582 ;Table of action addresses for FSC calls 0..8, high bytes A84A EQUB &94 A84B EQUB &94 #if defined _DDOS357 A84C EQUB &94 A84D EQUB &95 A84E EQUB &94 #else A84C EQUB &94 A84D EQUB &95 A84E EQUB &94 #endif A84F EQUB &95 A850 EQUB &95 A851 EQUB &95 A852 EQUB &95 ;Table of action addresses for OSARGS calls A=&FF,0,1, Y=0, low bytes A853 EQUB &D0 ;OSARGS &FF = ensure all files &97D1 A854 EQUB &BA ;OSARGS 0 = return FS number &97BB A855 EQUB &BD ;OSARGS 1 = command line tail &97BE ;Table of action addresses for OSARGS calls A=&FF,0,1, Y=0, high bytes A856 EQUB &97 A857 EQUB &97 A858 EQUB &97 ;Table of action addresses for OSFILE calls &FF,0..6, low bytes A859 EQUB &55 ;OSFILE &FF = load file &9B56 A85A EQUB &0A ;OSFILE 0 = save file &9B0B A85B EQUB &16 ;OSFILE 1 = wr. catalog info &9B17 A85C EQUB &21 ;OSFILE 2 = wr. load address &9B22 A85D EQUB &29 ;OSFILE 3 = wr. exec address &9B2A A85E EQUB &31 ;OSFILE 4 = wr. attributes &9B32 A85F EQUB &40 ;OSFILE 5 = read catalog info &9B41 A860 EQUB &49 ;OSFILE 6 = delete file &9B4A ;Table of action addresses for OSFILE calls &FF,0..6, low bytes A861 EQUB &9B A862 EQUB &9B A863 EQUB &9B A864 EQUB &9B A865 EQUB &9B A866 EQUB &9B A867 EQUB &9B A868 EQUB &9B ;Table of action addresses for OSGBPB calls 0..8, low bytes A869 EQUB &E9 ;OSGBPB 0 = no operation &9CE9 A86A EQUB &EA ;OSGBPB 1 = set PTR and write &9CEA A86B EQUB &EA ;OSGBPB 2 = write data &9CEA A86C EQUB &F2 ;OSGBPB 3 = set PTR and read &9CF2 A86D EQUB &F2 ;OSGBPB 4 = read data &9CF2 A86E EQUB &FA ;OSGBPB 5 = read title/opt/drv &9CFA A86F EQUB &2B ;OSGBPB 6 = read CSD drv/dir &9D2B A870 EQUB &3A ;OSGBPB 7 = read lib'y drv/dir &9D3A A871 EQUB &49 ;OSGBPB 8 = read CSD filenames &9D49 ;Table of action addresses for OSGBPB calls 0..8, high bytes A872 EQUB &9C A873 EQUB &9C A874 EQUB &9C A875 EQUB &9C A876 EQUB &9C A877 EQUB &9C A878 EQUB &9D A879 EQUB &9D A87A EQUB &9D ;Table of microcode bytes for OSGBPB calls 0..8 A87B EQUB &04 ;%000001 0 . to memory, special handler A87C EQUB &02 ;%000000 1 0 from memory, xfer data, set PTR A87D EQUB &03 ;%000000 1 1 from memory, xfer data, leave PTR A87E EQUB &06 ;%000001 1 0 to memory, xfer data, set PTR A87F EQUB &07 ;%000001 1 1 to memory, xfer data, leave PTR A880 EQUB &04 ;%000001 0 . to memory, special handler A881 EQUB &04 ;%000001 0 . to memory, special handler A882 EQUB &04 ;%000001 0 . to memory, special handler A883 EQUB &04 ;%000001 0 . to memory, special handler .R884 ;Print DDOS banner A884 20 94 A3 JSR R394 #if defined _DDOS316 A887 EQUS "OPUS DDOS 3.16" #elif defined _DDOS336 A887 EQUS "OPUS DDOS 3.36" #elif defined _DDOS356 A887 EQUS "FTC DDOS v3.56" #elif defined _DDOS357 A887 EQUS "FTC DDOS v3.58" #elif defined _DDOS326 A887 EQUS "Otus DDOS 3.26" #else A887 EQUS "OPUS DDOS 3.46" #endif A895 EQUB &0D A896 EQUB &0D A897 EA NOP A898 60 RTS #if defined _DDOS316 A899 EQUB &03,&16 ;bcd version number = 3.16 #elif defined _DDOS336 A899 EQUB &03,&36 ;bcd version number = 3.36 #elif defined _DDOS326 A899 EQUB &03,&26 ;bcd version number = 3.26 #elif defined _DDOS346 A899 EQUB &03,&46 ;bcd version number = 3.46 #else A899 EQUB &03,&45 ;bcd version number = 3.45 #endif #if defined _DDOS326 A89B EQUB &16,&12,&22 ;bcd date dd/mm/yy = 16 December 2022 A89E EQUB &00,&00,&00 ;bcd revision number = 0 (printed as spaces) #else A89B EQUB &01,&03,&86 ;bcd date dd/mm/yy = 1 March 1986 A89E EQUB &00,&00,&00 ;bcd revision number = 0 (printed as spaces) #endif ;*FORMAT A8A1 A9 05 LDA #&05 ;set drive number = 5 (unused) A8A3 85 BC STA &BC A8A5 A9 00 LDA #&00 A8A7 85 BD STA &BD ;clear interleaved format flag A8A9 20 BB A4 JSR R4BB ;call GSINIT with C=0 A8AC F0 13 BEQ R8C1 ;if argument empty then skip A8AE 20 C5 FF JSR &FFC5 ;else call GSREAD A8B1 C9 49 CMP #&49 ;does argument begin with capital I? A8B3 D0 07 BNE R8BC ;if not then extract drive number A8B5 C6 BD DEC &BD ;else set interleaved format flag (unused) A8B7 20 C5 FF JSR &FFC5 ;call GSREAD, read next argument character A8BA B0 05 BCS R8C1 ;if end of string then skip .R8BC A8BC 20 A0 A4 JSR R4A0 ;else convert ASCII hex digit to binary A8BF 85 BC STA &BC ;save as drive number (unused) .R8C1 A8C1 20 F3 A2 JSR R2F3 ;have A=0 returned on exit A8C4 BA TSX A8C5 8E 10 10 STX &1010 ;set stack pointer to restore on restart A8C8 8E 24 10 STX &1024 ;set stack pointer to restore on exit A8CB 20 28 92 JSR Q228 ;set high word of buffer address = &FFFF ;command restart point set at &A93F A8CE 20 39 AA JSR RA39 ;set command restart to exit command A8D1 20 74 AD JSR RD74 ;set display MODE 7 A8D4 20 38 AD JSR RD38 ;print "DISK FORMATTER" heading .R8D7 A8D7 20 D2 A3 JSR R3D2 ;print VDU sequence immediate A8DA EQUB &1F ;move cursor to (0,21) A8DB EQUB &00 A8DC EQUB &15 A8DD EQUB &83 ;yellow alphanumerics #if defined _BUGFIX A8DE EQUS "Input no. of tracks (35/40/80) " A8FD EQUB &FF A8FE A0 08 LDY #&08 ;print 8 spaces, 8 DELs A900 20 08 B3 JSR S308 ;erase Y characters ahead of cursor A903 20 F4 AD JSR RDF4 ;input number up to 5 digits A906 98 TYA ;if user entered no digits A907 F0 CE BEQ R8D7 ;then repeat prompt and input A909 20 09 B1 JSR S109 ;else convert ASCII numeric to unsigned word A90C B0 17 BCS R925 ;if numeric invalid then display error A90E A9 28 LDA #&28 ;else 40 tracks maximum can be formatted A910 2C E0 10 BIT &10E0 ;test double-stepping flag A913 50 07 BVC R91C ;if 1:1 stepping then maximum = 80 tracks A915 10 06 BPL R91D ;if *4080 ON then maximum = 40 tracks A917 A2 80 LDX #&80 ;else *4080 AUTO; keep automatic on A919 8E E0 10 STX &10E0 ;force 1:1 stepping .R91C A91C 0A ASL A ;and format up to 80 tracks. .R91D A91D C5 B0 CMP &B0 ;compare max - LSB of number entered A91F 90 04 BCC R925 ;if max < LSB then display error A921 A5 B0 LDA &B0 ;else set A = LSB number of tracks requested A923 D0 18 BNE R93D ;can be any number up to maximum except 0: .R925 A925 20 C2 B0 JSR S0C2 ;briefly display error indication A928 4C D7 A8 JMP R8D7 ;and re-prompt and input number of tracks .R92B ;Execute command on host A92B AA TAX ;on entry A=&FF, C=1 A92C A9 01 LDA #&01 ;emulate Acorn DFS: A=1, C=1, A92E 6C C0 00 JMP (&00C0) ;X=&FF filename cmp complete .R931 A931 68 PLA ;discard return address to *VERIFY A932 68 PLA ;the RTS will exit the *VERIFY command A933 A9 00 LDA #&00 ;have A=0 returned on exit: .R935 ;Validate *VERIFY drive ;on entry A=drive number, X=stack pointer A935 29 0C AND #&0C ;ensure drive number refers to floppy drive A937 D0 F8 BNE R931 ;if b3 or b2 set then RAM disc, quit command A939 9D 05 01 STA &0105,X ;else A=0, have A=0 returned on exit A93C 60 RTS ;return to *VERIFY .R93D A93D 85 C0 STA &C0 ;set number of tracks and fall through: #else /* _BUGFIX */ A8DE EQUS "Input no. of tracks (35/40/80) " A905 EQUB &7F A906 EQUB &7F A907 EQUB &7F A908 EQUB &7F A909 EQUB &7F A90A EQUB &7F A90B EQUB &7F A90C EQUB &7F A90D EQUB &FF A90E 20 F4 AD JSR RDF4 ;input number up to 5 digits A911 98 TYA ;if user entered no digits A912 F0 C3 BEQ R8D7 ;then repeat prompt and input A914 20 09 B1 JSR S109 ;else convert ASCII numeric to unsigned word A917 B0 20 BCS R939 ;if numeric invalid then display error A919 A2 50 LDX #&50 ;else 80 tracks maximum can be formatted A91B AD E0 10 LDA &10E0 ;test double-stepping flag A91E 10 05 BPL R925 ;if double-stepping is automatic A920 29 80 AND #&80 ;then discard last detected setting A922 8D E0 10 STA &10E0 ;and force 1:1 stepping .R925 A925 2C E0 10 BIT &10E0 ;(else) test double-stepping flag A928 50 02 BVC R92C ;if *4080 ON, forced double-stepping A92A A2 28 LDX #&28 ;then maximum format is 40 tracks. .R92C A92C E4 B0 CPX &B0 ;compare max - LSB of number entered A92E 90 09 BCC R939 ;if max < LSB then display error A930 A5 B0 LDA &B0 ;else set A = LSB number of tracks requested A932 F0 05 BEQ R939 ;0 track format is not sensible, display error A934 85 C0 STA &C0 ;else set number of tracks to format A936 4C 3F A9 JMP R93F ;(can be any number up to maximum) .R939 A939 20 C2 B0 JSR S0C2 ;briefly display error indication A93C 4C D7 A8 JMP R8D7 ;and re-prompt and input number of tracks #endif /* _BUGFIX */ .R93F A93F A2 CE LDX #&CE ;point XY at *FORMAT entry point, &A8CE A941 A0 A8 LDY #&A8 A943 20 3D AA JSR RA3D ;set command restart action address A946 20 D7 AD JSR RDD7 ;clear row 23 .R949 A949 20 D2 A3 JSR R3D2 ;print VDU sequence immediate A94C EQUB &1F ;move cursor to (0,22) A94D EQUB &00 A94E EQUB &16 A94F EQUB &83 ;yellow alphanumerics A950 EQUS "Drive number (0/1/2/3) " A967 EQUB &FF A968 20 87 B0 JSR S087 ;get printable input character A96B C9 30 CMP #&30 ;is it less than ASCII "0"? A96D 90 DA BCC R949 ;if so then input new drive number A96F E9 30 SBC #&30 ;else convert to binary drive no. 0..3 A971 C9 04 CMP #&04 ;is drive number in range? A973 90 06 BCC R97B ;if so then proceed A975 20 C2 B0 JSR S0C2 ;else briefly display error indication A978 4C 3F A9 JMP R93F ;and input new drive number .R97B A97B 85 CF STA &CF ;set as current volume A97D 20 D7 AD JSR RDD7 ;clear row 23 .R980 A980 20 D2 A3 JSR R3D2 ;print VDU sequence immediate A983 EQUB &1F ;move cursor to (0,23) A984 EQUB &00 A985 EQUB &17 A986 EQUB &83 ;yellow alphanumerics A987 EQUS "Density (S/D) " A995 EQUB &FF A996 20 87 B0 JSR S087 ;get printable input character A999 C9 53 CMP #&53 ;is it capital S? A99B F0 0A BEQ R9A7 ;if so then format single density A99D C9 44 CMP #&44 ;else is it capital D? A99F F0 09 BEQ R9AA ;if so then format double density A9A1 20 C2 B0 JSR S0C2 ;else briefly display error indication A9A4 4C 80 A9 JMP R980 ;and re-input; [BUG] old density on screen! .R9A7 A9A7 4C F5 A9 JMP R9F5 ;jump to format single density (was in range) .R9AA ;Format double density A9AA A2 CE LDX #&CE ;point XY at *FORMAT entry point, &A8CE A9AC A0 A8 LDY #&A8 A9AE 20 3D AA JSR RA3D ;set command restart action address A9B1 AD E3 10 LDA &10E3 ;set double density A9B4 09 40 ORA #&40 ;preserve automatic setting bit 7 A9B6 8D E3 10 STA &10E3 ;set double density bit 6 A9B9 A9 12 LDA #&12 ;set 18 sectors per track A9BB 8D E1 10 STA &10E1 A9BE 20 D6 A7 JSR R7D6 ;set up for current drive A9C1 A9 00 LDA #&00 A9C3 8D 13 10 STA &1013 ;set return code = 0, no error A9C6 20 97 B1 JSR S197 ;prompt user and start format A9C9 AD 13 10 LDA &1013 ;test return code A9CC F0 03 BEQ R9D1 ;if no error then generate volumes A9CE 4C F2 A9 JMP R9F2 ;else exit command .R9D1 A9D1 20 B3 AE JSR REB3 ;clear pages &0E,&0F A9D4 20 C0 AE JSR REC0 ;clear volume sizes A9D7 A6 C0 LDX &C0 ;get number of tracks on disc A9D9 CA DEX ;all but one track available for volumes A9DA 86 B0 STX &B0 ;set multiplicand A9DC 20 25 B0 JSR S025 ;multiply by no. sectors per track A9DF 20 CB AE JSR RECB ;set default volume sizes A9E2 20 1D AF JSR RF1D ;write volume catalogues A9E5 20 41 AF JSR RF41 ;generate disc catalogue A9E8 20 DD A6 JSR R6DD ;write disc catalogue L3 A9EB A2 77 LDX #&77 ;point XY to "Please wait" at &B377 A9ED A0 B3 LDY #&B3 A9EF 20 A4 AD JSR RDA4 ;erase VDU sequence at XY (redundant) .R9F2 A9F2 4C 44 AA JMP RA44 ;exit command .R9F5 ;Format single density A9F5 A2 CE LDX #&CE ;point XY at *FORMAT entry point, &A8CE A9F7 A0 A8 LDY #&A8 A9F9 20 3D AA JSR RA3D ;set command restart action address A9FC AD E3 10 LDA &10E3 ;set single density A9FF 29 80 AND #&80 ;preserve automatic setting bit 7 AA01 8D E3 10 STA &10E3 ;clear double density bit 6 AA04 A9 0A LDA #&0A ;set 10 sectors per track AA06 8D E1 10 STA &10E1 AA09 20 D6 A7 JSR R7D6 ;set up for current drive AA0C A9 00 LDA #&00 AA0E 8D 13 10 STA &1013 ;set return code = 0, no error AA11 20 97 B1 JSR S197 ;prompt user and start format AA14 AD 13 10 LDA &1013 ;test return code AA17 D0 1D BNE RA36 ;if format or verify failed then exit AA19 A6 C0 LDX &C0 ;else get number of tracks on disc AA1B 86 B0 STX &B0 ;set multiplicand AA1D 20 25 B0 JSR S025 ;multiply by no. sectors per track AA20 20 B3 AE JSR REB3 ;clear pages &0E,&0F AA23 A5 C5 LDA &C5 ;set MSB volume size, boot option OFF AA25 8D 06 0F STA &0F06 AA28 A5 C4 LDA &C4 ;set LSB volume size AA2A 8D 07 0F STA &0F07 AA2D A9 00 LDA #&00 AA2F 85 BA STA &BA ;destination LBA = &0000 AA31 85 BB STA &BB AA33 20 CE 92 JSR Q2CE ;write disc/volume catalogue L3 .RA36 AA36 4C 44 AA JMP RA44 ;exit command .RA39 ;Set command restart to exit command AA39 A2 44 LDX #&44 ;point XY at command exit routine, &AA44 AA3B A0 AA LDY #&AA .RA3D ;Set command restart action address AA3D 8E 11 10 STX &1011 AA40 8C 12 10 STY &1012 AA43 60 RTS .RA44 ;Exit command AA44 AE 24 10 LDX &1024 ;restore stack pointer from workspace AA47 9A TXS AA48 20 8B B1 JSR S18B ;clear rows 20..22 AA4B A2 00 LDX #&00 ;set XY to screen coordinates (0,24) AA4D A0 18 LDY #&18 AA4F 20 80 AD JSR RD80 ;move cursor to (X,Y) #if defined _DDOS316 AA52 4C 4B B7 JMP S74B ;exit (jump to RTS) #elif defined _DDOS336 AA52 4C 4B B7 JMP S74B ;exit (jump to RTS) #else AA52 4C 49 B7 JMP S749 ;exit (jump to RTS) #endif ;*VERIFY AA55 20 E5 A4 JSR R4E5 ;select specified or default volume AA58 BA TSX AA59 8E 24 10 STX &1024 ;set stack pointer to restore on exit AA5C 8E 10 10 STX &1010 ;set stack pointer to restore on restart #if defined _BUGFIX AA5F 20 35 A9 JSR R935 ;validate *VERIFY drive #else AA5F 20 F3 A2 JSR R2F3 ;have A=0 returned on exit #endif AA62 20 28 92 JSR Q228 ;set high word of OSFILE load address = &FFFF ;command restart point set at &AAAC AA65 20 39 AA JSR RA39 ;set command restart to exit command AA68 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AA6B EQUB &16 ;set display MODE 7 AA6C EQUB &07 AA6D EQUB &0A ;print two newlines AA6E EQUB &0A AA6F EQUB &FF AA70 A2 02 LDX #&02 ;repeat next line twice: .RA72 AA72 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AA75 EQUB &83 ;yellow alphanumerics AA76 EQUB &8D ;double height AA77 EQUS " V E R I F Y D I S K" AA91 EQUB &0D AA92 EQUB &0A AA93 EQUB &FF AA94 CA DEX ;loop until line printed twice AA95 D0 DB BNE RA72 AA97 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AA9A EQUB &1F ;move cursor to (0,10) AA9B EQUB &00 AA9C EQUB &0A AA9D EQUS "Insert disk" AAA8 EQUB &FF AAA9 20 E4 B2 JSR S2E4 ;prompt for keypress AAAC A2 65 LDX #&65 ;point XY at *VERIFY entry point, &AA65 AAAE A0 AA LDY #&AA AAB0 20 3D AA JSR RA3D ;set command restart action address AAB3 20 74 AD JSR RD74 ;set display MODE 7 AAB6 A9 00 LDA #&00 AAB8 8D 00 10 STA &1000 AABB 20 A4 A5 JSR R5A4 ;detect disc format/set sector address ;[BUG]NMI area use before claim AABE 2C E3 10 BIT &10E3 ;test density flag AAC1 70 20 BVS RAE3 ;if double density then examine disc catalog AAC3 20 A1 92 JSR Q2A1 ;else load volume catalogue AAC6 AD 06 0F LDA &0F06 ;get boot option/top bits volume size AAC9 29 03 AND #&03 ;extract top bits volume size AACB 85 B1 STA &B1 ;store MSB of dividend AACD AD 07 0F LDA &0F07 ;get LSB volume size AAD0 85 B0 STA &B0 ;store LSB of dividend AAD2 A9 00 LDA #&00 AAD4 85 B3 STA &B3 ;clear MSB of divisor AAD6 AD E1 10 LDA &10E1 ;get number of sectors per track (= 10) AAD9 85 B2 STA &B2 ;store LSB of divisor AADB 20 3C AE JSR RE3C ;divide word by word ;[BUG]*VERIFY 4 divides by zero, hangs AADE 86 C0 STX &C0 ;store quotient as number of tracks AAE0 4C EB AA JMP RAEB ;verify disc .RAE3 AAE3 20 D9 A6 JSR R6D9 ;load disc catalogue L3 AAE6 AD 04 0E LDA &0E04 ;get number of tracks on disc AAE9 85 C0 STA &C0 ;store number of tracks to verify .RAEB ;Verify disc AAEB A9 00 LDA #&00 AAED 85 BA STA &BA ;set starting track = 0 AAEF 8D 13 10 STA &1013 ;set return code = 0, no error .RAF2 AAF2 20 53 B2 JSR S253 ;print track number in table AAF5 20 28 AB JSR RB28 ;verify track with display AAF8 F0 03 BEQ RAFD ;if hard error occurred AAFA EE 13 10 INC &1013 ;then set return code = 1, verify failed .RAFD AAFD E6 BA INC &BA ;increment track number AAFF A5 BA LDA &BA ;compare track number - number of tracks AB01 C5 C0 CMP &C0 AB03 90 ED BCC RAF2 ;if less then verify next track AB05 AD 13 10 LDA &1013 ;else test return code AB08 D0 37 BNE RB41 ;if error occurred print "VERIFY ERROR" AB0A 20 D2 A3 JSR R3D2 ;else print VDU sequence immediate AB0D EQUB &1F ;move cursor to (10,23) AB0E EQUB &0A AB0F EQUB &17 AB10 EQUB &83 ;yellow alphanumerics AB11 EQUS "Verify complete" AB20 EQUB &0D AB21 EQUB &FF #if defined _DDOS316 AB22 20 7E B6 JSR S67E ;recalibrate drive (seek track 0) #elif defined _DDOS336 AB22 20 7E B6 JSR S67E ;recalibrate drive (seek track 0) #else AB22 20 7C B6 JSR S67C ;recalibrate drive (seek track 0) #endif AB25 4C 44 AA JMP RA44 ;exit command .RB28 ;Verify track with display AB28 A2 06 LDX #&06 ;make 6 attempts AB2A A0 06 LDY #&06 ;erase next 6 characters AB2C 20 08 B3 JSR S308 ;erase Y characters ahead of cursor .RB2F AB2F 20 40 A4 JSR R440 ;poll for ESCAPE #if defined _DDOS316 AB32 20 4C B7 JSR S74C ;verify track #elif defined _DDOS336 AB32 20 4C B7 JSR S74C ;verify track #else AB32 20 4A B7 JSR S74A ;verify track #endif AB35 F0 09 BEQ RB40 ;if verify succeeded then exit AB37 A9 2E LDA #&2E ;else print a dot AB39 20 EE FF JSR &FFEE ;call OSWRCH AB3C CA DEX ;decrement attempt counter AB3D D0 F0 BNE RB2F ;if attempts remaining then try again AB3F CA DEX ;else X=&FF, Z=0 to indicate failure .RB40 AB40 60 RTS .RB41 AB41 20 67 B1 JSR S167 ;print "VERIFY ERROR" AB44 4C 44 AA JMP RA44 ;exit command ;*VOLGEN AB47 20 3A A2 JSR R23A ;ensure *ENABLE active AB4A 20 E5 A4 JSR R4E5 ;select specified or default volume AB4D BA TSX AB4E 8E 24 10 STX &1024 ;set stack pointer to restore on exit AB51 20 F3 A2 JSR R2F3 ;have A=0 returned on exit AB54 20 28 92 JSR Q228 ;set high word of OSFILE load address = &FFFF AB57 20 39 AA JSR RA39 ;set command restart to exit command #if defined _DDOS316 AB5A 20 7E B6 JSR S67E ;recalibrate drive (seek track 0) #elif defined _DDOS336 AB5A 20 7E B6 JSR S67E ;recalibrate drive (seek track 0) #else AB5A 20 7C B6 JSR S67C ;recalibrate drive (seek track 0) #endif AB5D A9 00 LDA #&00 AB5F 8D E2 10 STA &10E2 ;data area starts on track 0 AB62 20 0F AD JSR RD0F ;ensure disc is double density AB65 A5 CF LDA &CF ;get current volume AB67 29 03 AND #&03 ;extract physical drive number, clear b7..2 AB69 85 CF STA &CF ;set current volume letter to A AB6B 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AB6E EQUB &16 ;select display MODE 7 AB6F EQUB &07 AB70 EQUB &0A ;two line feeds AB71 EQUB &0A ;i.e. move cursor to (0,2) AB72 EQUB &FF AB73 A2 02 LDX #&02 ;print next row twice: .RB75 AB75 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AB78 EQUB &83 ;yellow alphanumerics AB79 EQUB &8D ;double height AB7A EQUS "V O L U M E G E N E R A T I O N" AB9B EQUB &0D AB9C EQUB &0A AB9D EQUB &FF AB9E CA DEX ;loop until two copies printed AB9F D0 D4 BNE RB75 ABA1 20 D2 A3 JSR R3D2 ;print VDU sequence immediate ABA4 EQUB &1F ;move cursor to (0,7) ABA5 EQUB &00 ABA6 EQUB &07 ABA7 EQUB &0D ABA8 EQUB &83 ;yellow alphanumerics ABA9 EQUS "Vol Size (K) " ABB7 EQUB &FF ABB8 A5 CF LDA &CF ;get current volume ABBA 20 08 8D JSR PD08 ;print " Drive " plus volume spec in A ABBD 20 D2 A3 JSR R3D2 ;print VDU sequence immediate ABC0 EQUB &0D ;carriage return ABC1 EQUB &0A ;two line feeds ABC2 EQUB &0A #if defined _BEEBEM ;Patch to get BeebEm to write the last byte of a track. NOT FOR HARDWARE ABC3 EQUB &FF ABC4 A2 41 LDX #&41 ;start at volume letter A .RBC6 ABC6 20 D2 A3 JSR R3D2 ;print start of line ABC9 EQUB &83 ;yellow alphanumerics ABCA EQUS " " ABCB EQUB &FF ABCC 8A TXA ;transfer volume letter to A ABCD 20 F2 8C JSR PCF2 ;print character in A and newline ABD0 E8 INX ;take next volume letter ABD1 E0 49 CPX #&49 ;is it beyond "H"? ABD3 D0 F1 BNE RBC6 ;if not then loop to print letters A..H ABD5 20 D2 A3 JSR R3D2 ;else print footer ABD8 EQUB &0A ABD9 EQUB &83 ;yellow alphanumerics ABDA EQUS "No. of Kbytes remaining" ABF1 EQUB &FF ABF2 20 AB AF JSR RFAB ;read volume sizes and allocations ABF5 A2 00 LDX #&00 ;start at volume A ABF7 F0 11 BEQ RC0A ;and branch (always) .RBFC ABFC A0 06 LDY #&06 ;7 bytes to copy: .RBFE ABFE B9 B4 AC LDA &ACB4,Y ;get byte of trampoline code AC01 99 3D 0D STA &0D3D,Y ;store in NMI area AC04 88 DEY ;loop until 7 bytes copied AC05 10 F7 BPL RBFE AC07 4C 31 B8 JMP S831 ;copy NMI read from disc/polling loop and exit #else /* _BEEBEM */ ABC3 EQUB &83 ;yellow alphanumerics ABC4 EQUS " A" ABC6 EQUB &0D ;carriage return ABC7 EQUB &0A ;line feed ABC8 EQUB &83 ;yellow alphanumerics ABC9 EQUS " B" ABCB EQUB &0D ABCC EQUB &0A ABCD EQUB &83 ;yellow alphanumerics ABCE EQUS " C" ABD0 EQUB &0D ABD1 EQUB &0A ABD2 EQUB &83 ;yellow alphanumerics ABD3 EQUS " D" ABD5 EQUB &0D ABD6 EQUB &0A ABD7 EQUB &83 ;yellow alphanumerics ABD8 EQUS " E" ABDA EQUB &0D ABDB EQUB &0A ABDC EQUB &83 ;yellow alphanumerics ABDD EQUS " F" ABDF EQUB &0D ABE0 EQUB &0A ABE1 EQUB &83 ;yellow alphanumerics ABE2 EQUS " G" ABE4 EQUB &0D ABE5 EQUB &0A ABE6 EQUB &83 ;yellow alphanumerics ABE7 EQUS " H" ABE9 EQUB &0D ABEA EQUB &0A ABEB EQUB &0A ABEC EQUB &83 ;yellow alphanumerics ABED EQUS "No. of Kbytes remaining" AC04 EQUB &FF AC05 20 AB AF JSR RFAB ;read volume sizes and allocations AC08 A2 00 LDX #&00 ;start at volume A: #endif /* _BEEBEM */ .RC0A AC0A 86 C1 STX &C1 ;set table position AC0C 8A TXA AC0D 48 PHA AC0E 20 8D AE JSR RE8D ;print tabulated volume size AC11 68 PLA AC12 AA TAX AC13 E8 INX ;increment volume letter AC14 E0 08 CPX #&08 ;loop until 8 volumes listed AC16 D0 F2 BNE RC0A .RC18 AC18 20 3D B0 JSR S03D ;sum volume sizes AC1B A5 C2 LDA &C2 AC1D 85 B0 STA &B0 AC1F A5 C3 LDA &C3 ;divide sector count by 4 AC21 4A LSR A ;to give kilobytes AC22 66 B0 ROR &B0 AC24 4A LSR A AC25 66 B0 ROR &B0 AC27 85 B1 STA &B1 AC29 20 5D AE JSR RE5D ;convert binary word to four decimal digits AC2C A2 19 LDX #&19 AC2E A0 12 LDY #&12 AC30 20 80 AD JSR RD80 ;move cursor to (X,Y) AC33 20 66 B0 JSR S066 ;print four decimal digits, space-padded AC36 4C 3C AC JMP RC3C ;and start taking user input. .RC39 AC39 20 C2 B0 JSR S0C2 ;briefly display error indication .RC3C AC3C A2 18 LDX #&18 ;point XY to "Volume :" at &B318 AC3E A0 B3 LDY #&B3 AC40 20 8D AD JSR RD8D ;print VDU sequence at XY AC43 20 AA B0 JSR S0AA ;get input character and acknowledge ESCAPE AC46 C9 0D CMP #&0D ;if user pressed RETURN AC48 D0 03 BNE RC4D AC4A 4C F1 AC JMP RCF1 ;then generate volumes and exit .RC4D #if defined _BEEBEM ;Patch to get BeebEm to write the last byte of a track. NOT FOR HARDWARE AC4D C9 49 CMP #&49 ;else if volume letter is beyond H AC4F B0 E8 BCS RC39 ;then display error AC51 E9 40 SBC #&40 ;else C=0; convert to volume index 0..7 AC53 90 E4 BCC RC39 ;if out of range then display error AC55 85 C1 STA &C1 ;else C=1; set volume index AC57 69 40 ADC #&40 ;convert back to letter A..H, print it AC59 20 EE FF JSR &FFEE ;call OSWRCH AC5C A9 20 LDA #&20 ;print a space AC5E 20 EE FF JSR &FFEE ;call OSWRCH AC61 20 F4 AD JSR RDF4 ;input number up to 5 digits AC64 B0 D6 BCS RC3C ;if invalid input then display error AC66 98 TYA ;else test number of characters entered AC67 D0 17 BNE RC80 ;if >0 then convert to binary AC69 A5 C1 LDA &C1 ;else RETURN pressed, delete volume AC6B 0A ASL A AC6C A8 TAY ;y = volume offset AC6D A9 00 LDA #&00 ;volume size = zero AC6F 99 14 10 STA &1014,Y AC72 99 15 10 STA &1015,Y AC75 20 E9 AD JSR RDE9 ;move cursor to table row in &C1 AC78 A2 04 LDX #&04 ;4 spaces to print AC7A 20 E0 AD JSR RDE0 ;print X spaces AC7D 4C 18 AC JMP RC18 ;update free space and take next command. .RC80 AC80 20 09 B1 JSR S109 ;convert ASCII numeric to unsigned word AC83 B0 B4 BCS RC39 ;if overflow then display error AC85 A5 B1 LDA &B1 ;else test MSB of entered number AC87 D0 B0 BNE RC39 ;if >=256 KiB requested then display error AC89 06 B0 ASL &B0 ;else multiply KiB by 4 to get sector count AC8B 26 B1 ROL &B1 AC8D 06 B0 ASL &B0 AC8F 26 B1 ROL &B1 AC91 A9 00 LDA #&00 ;clear rounded-down sector count AC93 85 B2 STA &B2 AC95 85 B3 STA &B3 .RC97 AC97 38 SEC AC98 A5 B0 LDA &B0 ;subtract 18 sectors = 4.5 KiB from request AC9A E9 12 SBC #&12 AC9C 85 B0 STA &B0 AC9E A5 B1 LDA &B1 ACA0 E9 00 SBC #&00 ACA2 85 B1 STA &B1 ACA4 90 15 BCC RCBB ;if underflow then fit rounded-down request ACA6 18 CLC ;else add 4.5 KiB to rounded-down request ACA7 A9 12 LDA #&12 ACA9 65 B2 ADC &B2 ACAB 85 B2 STA &B2 ACAD 90 02 BCC RCB1 ;carry out to high byte ACAF E6 B3 INC &B3 .RCB1 ACB1 4C 97 AC JMP RC97 ;and loop until request underflows. ;Trampoline called from &0D1B (&BA3F) ACB4 8D 00 0D STA &0D00 ;store 0D00=RTI ignore further NMIs ACB7 A9 CE LDA #&CE ;set A=&CE counter for 123 us delay ACB9 08 PHP ;save status; RTI unfreezes BeebEm's WD 1770 ACBA 40 RTI ;return to &0D1D and execute opcode &0D #else /* _BEEBEM */ AC4D 38 SEC ;else convert letter A..H to volume index 0..7 AC4E E9 41 SBC #&41 AC50 90 E7 BCC RC39 ;if out of range then display error AC52 C9 08 CMP #&08 AC54 B0 E3 BCS RC39 AC56 85 C1 STA &C1 ;else set volume index AC58 69 41 ADC #&41 ;convert back to letter A..H, print it AC5A 20 EE FF JSR &FFEE ;call OSWRCH AC5D A9 20 LDA #&20 ;print a space AC5F 20 EE FF JSR &FFEE ;call OSWRCH AC62 20 F4 AD JSR RDF4 ;input number up to 5 digits AC65 B0 D5 BCS RC3C ;if invalid input then display error AC67 98 TYA ;else test number of characters entered AC68 D0 17 BNE RC81 ;if >0 then convert to binary AC6A A5 C1 LDA &C1 ;else RETURN pressed, delete volume AC6C 0A ASL A AC6D A8 TAY ;y = volume offset AC6E A9 00 LDA #&00 ;volume size = zero AC70 99 14 10 STA &1014,Y AC73 99 15 10 STA &1015,Y AC76 20 E9 AD JSR RDE9 ;move cursor to table row in &C1 AC79 A2 04 LDX #&04 ;4 spaces to print AC7B 20 E0 AD JSR RDE0 ;print X spaces AC7E 4C 18 AC JMP RC18 ;update free space and take next command. .RC81 AC81 20 09 B1 JSR S109 ;convert ASCII numeric to unsigned word AC84 B0 B3 BCS RC39 ;if overflow then display error AC86 A5 B1 LDA &B1 ;else test MSB of entered number AC88 F0 06 BEQ RC90 ;if <256 KiB requested then continue AC8A 20 C2 B0 JSR S0C2 ;else briefly display error indication AC8D 4C 3C AC JMP RC3C ;and ask user for another command ;can save 6 bytes here; AC88 = BNE RC39 .RC90 AC90 06 B0 ASL &B0 ;multiply KiB by 4 to get sector count AC92 26 B1 ROL &B1 AC94 06 B0 ASL &B0 AC96 26 B1 ROL &B1 AC98 A9 00 LDA #&00 ;clear rounded-down sector count AC9A 85 B2 STA &B2 AC9C 85 B3 STA &B3 .RC9E AC9E 38 SEC AC9F A5 B0 LDA &B0 ;subtract 18 sectors = 4.5 KiB from request ACA1 E9 12 SBC #&12 ACA3 85 B0 STA &B0 ACA5 A5 B1 LDA &B1 ACA7 E9 00 SBC #&00 ACA9 85 B1 STA &B1 ACAB 90 0E BCC RCBB ;if underflow then fit rounded-down request ACAD 18 CLC ;else add 4.5 KiB to rounded-down request ACAE A9 12 LDA #&12 ACB0 65 B2 ADC &B2 ACB2 85 B2 STA &B2 ACB4 90 02 BCC RCB8 ;carry out to high byte ACB6 E6 B3 INC &B3 .RCB8 ACB8 4C 9E AC JMP RC9E ;and loop until request underflows. #endif /* _BEEBEM */ .RCBB ;Fit volume request ACBB A5 C1 LDA &C1 ;get volume index ACBD 0A ASL A ;double it ACBE A8 TAY ;transfer to Y as index ACBF A9 00 LDA #&00 ;clear assigned volume size ACC1 99 14 10 STA &1014,Y ACC4 99 15 10 STA &1015,Y ACC7 20 3D B0 JSR S03D ;sum volume sizes ACCA 38 SEC ACCB A5 C2 LDA &C2 ;compare free space - rounded-down request ACCD E5 B2 SBC &B2 ACCF A5 C3 LDA &C3 ACD1 E5 B3 SBC &B3 ACD3 B0 08 BCS RCDD ;if request fits then assign request ACD5 A5 C2 LDA &C2 ;else set request = free space on disc ACD7 85 B2 STA &B2 ACD9 A5 C3 LDA &C3 ACDB 85 B3 STA &B3 .RCDD ACDD A5 C1 LDA &C1 ;get volume index ACDF 0A ASL A ;double it ACE0 A8 TAY ;transfer to Y as index ACE1 A5 B3 LDA &B3 ;set assigned volume size ACE3 99 14 10 STA &1014,Y ;= min(rounded_down_request, free_space) ACE6 A5 B2 LDA &B2 ACE8 99 15 10 STA &1015,Y ACEB 20 8D AE JSR RE8D ;print tabulated volume size ACEE 4C 18 AC JMP RC18 ;update free space display and take input. .RCF1 ;Generate volumes ACF1 20 0F AD JSR RD0F ;ensure disc is double density .RCF4 ACF4 20 85 B2 JSR S285 ;ensure disc is write enabled ACF7 D0 FB BNE RCF4 ;if write protected then try again ACF9 20 B3 AE JSR REB3 ;clear pages &0E,&0F ACFC A2 77 LDX #&77 ;point XY to "generating volumes" at &BE77 ACFE A0 B3 LDY #&B3 AD00 20 8D AD JSR RD8D ;print VDU sequence at XY AD03 20 1D AF JSR RF1D ;write volume catalogues AD06 20 41 AF JSR RF41 ;generate disc catalogue AD09 20 DD A6 JSR R6DD ;write disc catalogue L3 AD0C 4C 44 AA JMP RA44 ;exit command .RD0F ;Ensure disc is double density #if defined _DDOS316 AD0F 20 C4 B6 JSR S6C4 ;ensure disc is formatted #elif defined _DDOS336 AD0F 20 C4 B6 JSR S6C4 ;ensure disc is formatted #else AD0F 20 C2 B6 JSR S6C2 ;ensure disc is formatted #endif AD12 2C E3 10 BIT &10E3 ;test density flag AD15 70 20 BVS RD37 ;if single density AD17 20 62 A3 JSR R362 ;then raise "must be double density" error. AD1A EQUB &C9 AD1B EQUS "Disk must be double density" AD36 EQUB &00 .RD37 AD37 60 RTS .RD38 ;Print "DISK FORMATTER" heading AD38 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AD3B EQUB &1F ;move cursor to (0,2) AD3C EQUB &00 AD3D EQUB &02 AD3E EQUB &FF AD3F A2 02 LDX #&02 .RD41 AD41 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AD44 EQUB &83 ;yellow alphanumerics AD45 EQUB &8D ;double height AD46 EQUS " D I S K F O R M A T T E R" AD64 EQUB &0D AD65 EQUB &0A AD66 EQUB &FF AD67 CA DEX AD68 D0 D7 BNE RD41 AD6A 20 D2 A3 JSR R3D2 ;print VDU sequence immediate AD6D EQUB &0D ;CR + 4x LF AD6E EQUB &0A AD6F EQUB &0A AD70 EQUB &0A AD71 EQUB &0A AD72 EQUB &FF AD73 60 RTS .RD74 ;Set display MODE 7 AD74 A9 07 LDA #&07 AD76 48 PHA AD77 A9 16 LDA #&16 AD79 20 EE FF JSR &FFEE AD7C 68 PLA AD7D 4C EE FF JMP &FFEE .RD80 ;Move cursor to (X,Y) AD80 A9 1F LDA #&1F ;issue VDU 31 = PRINT TAB(X,Y) AD82 20 EE FF JSR &FFEE AD85 8A TXA ;send X coordinate to OSWRCH, 0=leftmost col AD86 20 EE FF JSR &FFEE AD89 98 TYA ;send Y coordinate to OSWRCH, 0=top row AD8A 4C EE FF JMP &FFEE .RD8D ;Print VDU sequence at XY AD8D 86 B0 STX &B0 ;set up pointer at &B0,1 = XY AD8F 84 B1 STY &B1 AD91 A0 00 LDY #&00 ;set offset to 0: .RD93 AD93 B1 B0 LDA (&B0),Y ;get character of VDU sequence AD95 C9 FF CMP #&FF ;is it the terminator byte? AD97 F0 0A BEQ RDA3 ;if so then do not print, exit AD99 20 EE FF JSR &FFEE ;else call OSWRCH to print it AD9C C8 INY ;increment offset AD9D D0 F4 BNE RD93 ;loop until offset overflows AD9F E6 B1 INC &B1 ;then increment high byte of pointer ADA1 D0 F0 BNE RD93 ;and loop until terminator byte reached .RDA3 ADA3 60 RTS .RDA4 ;Erase VDU sequence at XY ADA4 86 B0 STX &B0 ;set up pointer at &B0,1 = XY ADA6 84 B1 STY &B1 ADA8 A0 00 LDY #&00 ;set offset to 0: .RDAA ADAA B1 B0 LDA (&B0),Y ;get character of VDU sequence ADAC C9 1F CMP #&1F ;is it 31 = TAB(X,Y)? ADAE D0 10 BNE RDC0 ;if not then test for terminator byte ADB0 20 CD AD JSR RDCD ;else VDU 31 and increment pointer ADB3 B1 B0 LDA (&B0),Y ;send X coordinate to VDU (OSWRCH) ADB5 20 CD AD JSR RDCD ;print character in A and increment pointer ADB8 B1 B0 LDA (&B0),Y ;send Y coordinate to VDU (OSWRCH) ADBA 20 CD AD JSR RDCD ;print character in A and increment pointer ADBD 4C AA AD JMP RDAA ;and test next character .RDC0 ADC0 C9 FF CMP #&FF ;is it &FF = the terminator byte? ADC2 D0 01 BNE RDC5 ;if not then print space ADC4 60 RTS ;else exit .RDC5 ADC5 A9 20 LDA #&20 ;print a space ADC7 20 CD AD JSR RDCD ;print character in A and increment pointer ADCA 4C AA AD JMP RDAA ;and loop to test next character .RDCD ;Print character in A and increment pointer ADCD 20 EE FF JSR &FFEE ;call OSWRCH with character in A ADD0 E6 B0 INC &B0 ;increment low byte of pointer at &B0 ADD2 D0 02 BNE RDD6 ;carry out to high byte ADD4 E6 B1 INC &B1 .RDD6 ADD6 60 RTS .RDD7 ;Clear row 23 ADD7 A2 00 LDX #&00 ;move cursor to (0,23) ADD9 A0 17 LDY #&17 ADDB 20 80 AD JSR RD80 ;move cursor to (X,Y) ADDE A2 28 LDX #&28 ;set X = 40, width of one MODE 7 row: .RDE0 ;Print X spaces ADE0 A9 20 LDA #&20 ;set A to ASCII value of space: .RDE2 ;Print character X times ADE2 20 EE FF JSR &FFEE ;call OSWRCH ADE5 CA DEX ;decrement X ADE6 D0 FA BNE RDE2 ;loop until X = 0, then exit ADE8 60 RTS .RDE9 ;Move cursor to table row in &C1 ADE9 A2 06 LDX #&06 ADEB 18 CLC ADEC A5 C1 LDA &C1 ADEE 69 09 ADC #&09 ADF0 A8 TAY ADF1 4C 80 AD JMP RD80 ;move cursor to (X,Y) .RDF4 ;Input number up to 5 digits ADF4 A0 00 LDY #&00 ;start with no characters in line buffer .RDF6 ADF6 20 AA B0 JSR S0AA ;get input character and acknowledge ESCAPE ADF9 C9 0D CMP #&0D ;if user pressed RETURN ADFB D0 02 BNE RDFF ADFD 18 CLC ;then return C=0 ADFE 60 RTS .RDFF ADFF C9 7F CMP #&7F ;else if user pressed DELETE AE01 D0 0C BNE RE0F AE03 98 TYA ;then test number of characters entered AE04 D0 02 BNE RE08 ;if no characters on line AE06 38 SEC ;then return C=1 AE07 60 RTS .RE08 AE08 20 25 AE JSR RE25 ;else backspace and erase last character AE0B 88 DEY ;decrement number of characters entered AE0C 4C F6 AD JMP RDF6 ;and loop .RE0F AE0F C0 05 CPY #&05 ;if 5 characters already entered AE11 F0 E3 BEQ RDF6 ;then ignore latest, loop to read DEL/CR AE13 C9 30 CMP #&30 ;else if character less than "0" AE15 90 DF BCC RDF6 ;then ignore it AE17 C9 3A CMP #&3A ;else if character more than "9" AE19 B0 DB BCS RDF6 ;then ignore it AE1B 20 EE FF JSR &FFEE ;else print input character AE1E 99 31 10 STA &1031,Y ;store in line buffer AE21 C8 INY ;increment number of characters entered AE22 4C F6 AD JMP RDF6 ;and loop until user presses RETURN. .RE25 ;Backspace and erase characters AE25 20 2D AE JSR RE2D ;print DEL AE28 A9 20 LDA #&20 ;print space: AE2A 20 EE FF JSR &FFEE .RE2D ;Print DEL AE2D A9 7F LDA #&7F ;set A = ASCII value of DEL character AE2F 4C EE FF JMP &FFEE ;call OSWRCH to print it and exit. .RE32 ;Convert ASCII digit to binary and validate AE32 38 SEC ;C=1 iff invalid AE33 E9 30 SBC #&30 AE35 90 03 BCC RE3A ;(redundant) AE37 C9 0A CMP #&0A AE39 60 RTS .RE3A AE3A 38 SEC AE3B 60 RTS .RE3C ;Divide word by word AE3C A2 00 LDX #&00 ;initialise quotient = 0: .RE3E AE3E A5 B1 LDA &B1 ;Compare dividend - divisor AE40 C5 B3 CMP &B3 AE42 90 18 BCC RE5C AE44 D0 06 BNE RE4C AE46 A5 B0 LDA &B0 AE48 C5 B2 CMP &B2 AE4A 90 10 BCC RE5C ;if dividend >= divisor .RE4C AE4C A5 B0 LDA &B0 ;then subtract dividend - divisor AE4E E5 B2 SBC &B2 AE50 85 B0 STA &B0 ;ultimately leaving remainder AE52 A5 B1 LDA &B1 AE54 E5 B3 SBC &B3 AE56 85 B1 STA &B1 AE58 E8 INX ;increment quotient in X AE59 4C 3E AE JMP RE3E ;and loop as remainder >= 0 .RE5C AE5C 60 RTS .RE5D ;Convert binary word to four decimal digits AE5D A9 03 LDA #&03 ;set divisor = &03E8 = 1000 AE5F 85 B3 STA &B3 AE61 A9 E8 LDA #&E8 AE63 85 B2 STA &B2 AE65 20 3C AE JSR RE3C ;divide word by word AE68 8E 2B 10 STX &102B ;store quotient as first digit (big-endian) AE6B A9 00 LDA #&00 ;set divisor = &0064 = 100 AE6D 85 B3 STA &B3 AE6F A9 64 LDA #&64 AE71 85 B2 STA &B2 AE73 20 3C AE JSR RE3C ;divide word by word AE76 8E 2C 10 STX &102C ;store quotient as second digit AE79 A9 00 LDA #&00 ;set divisor = &000A = 10 AE7B 85 B3 STA &B3 AE7D A9 0A LDA #&0A AE7F 85 B2 STA &B2 AE81 20 3C AE JSR RE3C ;divide word by word AE84 8E 2D 10 STX &102D ;store quotient as third digit AE87 A5 B0 LDA &B0 ;store remainder as fourth digit AE89 8D 2E 10 STA &102E AE8C 60 RTS .RE8D ;Print tabulated volume size AE8D A5 C1 LDA &C1 ;get volume index AE8F 0A ASL A ;double it AE90 A8 TAY ;transfer to Y as index AE91 B9 14 10 LDA &1014,Y ;get MSB volume size AE94 85 B1 STA &B1 ;store it in zero page AE96 B9 15 10 LDA &1015,Y ;get LSB volume size AE99 85 B0 STA &B0 ;store it in zero page AE9B A5 B0 LDA &B0 ;test volume size AE9D 05 B1 ORA &B1 AE9F F0 11 BEQ REB2 ;if =0 then leave row blank AEA1 20 E9 AD JSR RDE9 ;else move cursor to table row in &C1 AEA4 46 B1 LSR &B1 ;divide sector count by 4 to get kilobytes AEA6 66 B0 ROR &B0 AEA8 46 B1 LSR &B1 AEAA 66 B0 ROR &B0 AEAC 20 5D AE JSR RE5D ;convert binary word to four decimal digits AEAF 20 66 B0 JSR S066 ;print four decimal digits, space-padded .REB2 AEB2 60 RTS .REB3 ;Clear pages &0E,&0F AEB3 A9 00 LDA #&00 AEB5 A8 TAY .REB6 AEB6 99 00 0E STA &0E00,Y AEB9 99 00 0F STA &0F00,Y AEBC C8 INY AEBD D0 F7 BNE REB6 AEBF 60 RTS .REC0 ;Clear volume sizes AEC0 A9 00 LDA #&00 AEC2 A0 0F LDY #&0F ;8 words to clear for volumes A..H .REC4 AEC4 99 14 10 STA &1014,Y ;set assigned size of volume to &0000 AEC7 88 DEY AEC8 10 FA BPL REC4 ;loop until all words cleared AECA 60 RTS .RECB ;Set default volume sizes AECB A5 C4 LDA &C4 ;set free space = sectors avail. for volumes AECD 85 B2 STA &B2 AECF A5 C5 LDA &C5 AED1 85 B3 STA &B3 AED3 AD E1 10 LDA &10E1 ;get number of sectors per track AED6 85 B0 STA &B0 AED8 A9 00 LDA #&00 ;clear MSB of word AEDA 85 B1 STA &B1 AEDC A2 04 LDX #&04 ;4 places to shift, multiply by 16: .REDE AEDE 06 B0 ASL &B0 ;shift word one place left AEE0 26 B1 ROL &B1 AEE2 CA DEX ;repeat 4 times AEE3 D0 F9 BNE REDE ;max. 16 tracks = 72 KiB per volume AEE5 A0 00 LDY #&00 .REE7 AEE7 20 1A B0 JSR S01A ;compare requested allocation with free space AEEA 90 0D BCC REF9 ;if it fits then set allocation = request AEEC A5 B3 LDA &B3 ;else set allocation = free space AEEE 99 14 10 STA &1014,Y AEF1 A5 B2 LDA &B2 AEF3 99 15 10 STA &1015,Y AEF6 4C 1C AF JMP RF1C ;and exit (jump to RTS) .REF9 AEF9 A5 B1 LDA &B1 ;set allocation = request AEFB 99 14 10 STA &1014,Y AEFE A5 B0 LDA &B0 AF00 99 15 10 STA &1015,Y AF03 38 SEC ;subtract LSB request from free space AF04 A5 B2 LDA &B2 AF06 E5 B0 SBC &B0 AF08 85 B2 STA &B2 AF0A A5 B3 LDA &B3 ;subtract MSB request from free space AF0C E5 B1 SBC &B1 AF0E 85 B3 STA &B3 AF10 A5 B2 LDA &B2 ;test free space AF12 05 B3 ORA &B3 AF14 F0 06 BEQ RF1C ;if disc full then exit AF16 C8 INY ;else add 2 to offset, point to next volume AF17 C8 INY AF18 C0 10 CPY #&10 ;loop until volumes A..H set or disc full. AF1A D0 CB BNE REE7 .RF1C AF1C 60 RTS .RF1D ;Write volume catalogues AF1D A0 00 LDY #&00 ;start at volume A AF1F 84 BA STY &BA ;set MSB of absolute LBA = 0 .RF21 AF21 B9 14 10 LDA &1014,Y ;test sector count of volume AF24 19 15 10 ORA &1015,Y ;load MSB, or with LSB AF27 F0 11 BEQ RF3A ;if no sectors assigned then skip cat write AF29 B9 14 10 LDA &1014,Y ;else copy MSB sector count AF2C 8D 06 0F STA &0F06 ;to catalogue AF2F B9 15 10 LDA &1015,Y ;and copy LSB AF32 8D 07 0F STA &0F07 AF35 84 BB STY &BB ;set LSB absolute LBA = 2 * volume letter AF37 20 CE 92 JSR Q2CE ;write disc/volume catalogue L3 .RF3A AF3A C8 INY ;advance volume letter by 1/sector by 2 AF3B C8 INY AF3C C0 10 CPY #&10 ;have we initialised 8 volumes/16 sectors? AF3E D0 E1 BNE RF21 ;if not then loop to init all volumes AF40 60 RTS .RF41 ;Generate disc catalogue AF41 A9 20 LDA #&20 ;set version/configuration number = &20 AF43 8D 00 0E STA &0E00 ;indicating that sector count is big-endian AF46 18 CLC AF47 A5 C4 LDA &C4 ;get LSB of total sectors alloc. to volumes AF49 69 12 ADC #&12 ;add 18 sectors for the catalogue track AF4B 8D 02 0E STA &0E02 ;store LSB number of sectors on disc AF4E A5 C5 LDA &C5 ;carry out to MSB AF50 69 00 ADC #&00 AF52 8D 01 0E STA &0E01 AF55 A9 12 LDA #&12 ;18 sectors per track AF57 8D 03 0E STA &0E03 AF5A A5 C0 LDA &C0 ;set number of tracks on disc AF5C 8D 04 0E STA &0E04 AF5F A9 00 LDA #&00 ;mystery field (MSB no. tracks?), always 0 AF61 8D 05 0E STA &0E05 AF64 A9 01 LDA #&01 ;data area starts on track 1 AF66 85 BB STA &BB AF68 A0 00 LDY #&00 .RF6A AF6A B9 14 10 LDA &1014,Y ;get LSB requested sector count for volume AF6D 85 B3 STA &B3 ;set as LSB of comparand AF6F B9 15 10 LDA &1015,Y ;copy MSB AF72 85 B2 STA &B2 AF74 A5 B2 LDA &B2 ;test number of requested sectors AF76 05 B3 ORA &B3 AF78 F0 2A BEQ RFA4 ;if zero then volume absent, assign no tracks AF7A A5 BB LDA &BB ;else set starting track of volume data area AF7C 99 08 0E STA &0E08,Y AF7F A9 00 LDA #&00 ;clear next byte (MSB track number?) AF81 99 09 0E STA &0E09,Y AF84 A2 00 LDX #&00 ;start with 0 tracks allocated to volume AF86 86 B0 STX &B0 ;and 0 sectors allocated to volume: AF88 86 B1 STX &B1 .RF8A AF8A 20 1A B0 JSR S01A ;compare requested allocation with current AF8D F0 0F BEQ RF9E ;if equal (blech!) then assign these tracks AF8F E8 INX ;else add one track to allocation AF90 18 CLC AF91 A5 B0 LDA &B0 ;and add 18 sectors to allocation AF93 69 12 ADC #&12 AF95 85 B0 STA &B0 AF97 90 02 BCC RF9B AF99 E6 B1 INC &B1 .RF9B AF9B 4C 8A AF JMP RF8A ;loop until allocation fulfilled .RF9E AF9E 18 CLC ;add number of tracks in X to starting track AF9F 8A TXA AFA0 65 BB ADC &BB AFA2 85 BB STA &BB .RFA4 AFA4 C8 INY ;skip to next volume entry AFA5 C8 INY AFA6 C0 10 CPY #&10 ;loop until tracks assigned to 8 volumes AFA8 D0 C0 BNE RF6A AFAA 60 RTS .RFAB ;Read volume sizes and allocations AFAB 20 F5 AF JSR RFF5 ;copy volume allocations to workspace AFAE 38 SEC AFAF AD 02 0E LDA &0E02 ;get LSB number of sectors on disc AFB2 E9 12 SBC #&12 ;subtract 18 sectors of catalogue track AFB4 85 C4 STA &C4 ;set LSB total sectors allocated to volumes AFB6 AD 01 0E LDA &0E01 ;borrow from MSB AFB9 E9 00 SBC #&00 AFBB 85 C5 STA &C5 AFBD AD 04 0E LDA &0E04 ;get number of tracks on disc AFC0 85 C0 STA &C0 AFC2 20 C0 AE JSR REC0 ;clear volume sizes AFC5 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). .RFC7 AFC7 98 TYA ;y=2*volume AFC8 4A LSR A ;A=volume AFC9 AA TAX ;transfer to X for use as index AFCA BD 06 10 LDA &1006,X ;look up number of tracks in volume AFCD F0 1F BEQ RFEE ;if volume absent then skip AFCF 84 BB STY &BB ;else set sector number = 2*volume AFD1 E6 BB INC &BB ;add 1, point to 2nd sector of cat. AFD3 A9 01 LDA #&01 ;256 bytes to transfer AFD5 85 B1 STA &B1 AFD7 A9 00 LDA #&00 AFD9 85 B0 STA &B0 AFDB A9 00 LDA #&00 ;a=&00 (discarded) AFDD 20 67 B4 JSR S467 ;transfer data L2 AFE0 AD 06 0E LDA &0E06 ;get boot option/top bits volume size AFE3 29 03 AND #&03 ;extract MSB volume size AFE5 99 14 10 STA &1014,Y ;set as MSB size of this volume AFE8 AD 07 0E LDA &0E07 ;get LSB volume size from catalogue AFEB 99 15 10 STA &1015,Y ;set as LSB size of this volume .RFEE AFEE 88 DEY ;proceed to previous volume AFEF 88 DEY ;whose catalogue sector no. is two less AFF0 10 D5 BPL RFC7 ;loop until all eight volumes read #if defined _DDOS316 AFF2 4C 4B B7 JMP S74B ;exit (jump to RTS) #elif defined _DDOS336 AFF2 4C 4B B7 JMP S74B ;exit (jump to RTS) #else AFF2 4C 49 B7 JMP S749 ;exit (jump to RTS) #endif .RFF5 ;Copy volume allocations to workspace AFF5 20 D9 A6 JSR R6D9 ;load disc catalogue L3 AFF8 A0 0E LDY #&0E ;start at sector offset 14, volume H AFFA A2 07 LDX #&07 ;start at workspace offset 7, volume H .RFFC AFFC B9 08 0E LDA &0E08,Y ;get first track of data area of volume AFFF 9D 06 10 STA &1006,X ;store in workspace B002 88 DEY ;skip mystery field in sector B003 88 DEY ;decrement offset, work back from H to A B004 CA DEX ;decrement workspace offset B005 10 F5 BPL RFFC ;loop until 8 track numbers copied B007 60 RTS ;unreachable code .S008 ;multiply word by byte B008 18 CLC B009 A5 B2 LDA &B2 B00B 65 B4 ADC &B4 B00D 85 B2 STA &B2 B00F A5 B3 LDA &B3 B011 65 B5 ADC &B5 B013 85 B3 STA &B3 B015 C6 B0 DEC &B0 B017 D0 EF BNE S008 B019 60 RTS .S01A ;Compare requested allocation with limit B01A A5 B1 LDA &B1 B01C C5 B3 CMP &B3 B01E D0 04 BNE S024 B020 A5 B0 LDA &B0 B022 C5 B2 CMP &B2 .S024 B024 60 RTS .S025 ;Multiply by no. sectors per track B025 AC E1 10 LDY &10E1 ;get number of sectors per track B028 A9 00 LDA #&00 ;clear product B02A 85 C4 STA &C4 B02C 85 C5 STA &C5 .S02E B02E 18 CLC ;add number of tracks to product B02F A5 B0 LDA &B0 B031 65 C4 ADC &C4 B033 85 C4 STA &C4 B035 90 02 BCC S039 ;carry out to high byte B037 E6 C5 INC &C5 .S039 B039 88 DEY ;loop until all sectors per track added B03A D0 F2 BNE S02E B03C 60 RTS .S03D ;Sum volume sizes B03D A0 00 LDY #&00 ;clear offset = 0, point to volume A B03F 84 B0 STY &B0 ;clear total B041 84 B1 STY &B1 .S043 B043 18 CLC ;add volume size at offset Y to total B044 A5 B0 LDA &B0 B046 79 15 10 ADC &1015,Y B049 85 B0 STA &B0 B04B A5 B1 LDA &B1 B04D 79 14 10 ADC &1014,Y B050 85 B1 STA &B1 B052 C8 INY ;add 2 to offset B053 C8 INY B054 C0 10 CPY #&10 ;loop until 8 allocations added B056 D0 EB BNE S043 B058 38 SEC ;subtract disc size - total allocations B059 A5 C4 LDA &C4 B05B E5 B0 SBC &B0 B05D 85 C2 STA &C2 ;=disc space free B05F A5 C5 LDA &C5 B061 E5 B1 SBC &B1 B063 85 C3 STA &C3 B065 60 RTS .S066 ;Print four decimal digits, space-padded B066 A0 FF LDY #&FF ;set Y=&FF going to 0, start at first digit .S068 ;Print decimal digits, space-padded B068 38 SEC ;set C=1 pad with spaces .S069 B069 C8 INY B06A B9 2B 10 LDA &102B,Y ;get digit #if defined _BUGFIX B06D D0 0E BNE S07D ;if >0 then print it B06F 90 0C BCC S07D ;if a digit was printed then print the rest B071 C0 03 CPY #&03 ;else if at the fourth digit B073 F0 08 BEQ S07D ;then always print it B075 A9 20 LDA #&20 ;else print a space B077 20 EE FF JSR &FFEE ;call OSWRCH B07A 4C 68 B0 JMP S068 ;and print the rest .S07D B07D 09 30 ORA #&30 ;convert binary to ASCII "0".."9" #else /* _BUGFIX */ B06D D0 0D BNE S07C ;if >0 then print it B06F 90 0B BCC S07C ;if a digit was printed then print the rest B071 C0 03 CPY #&03 ;else if at the fourth digit B073 F0 07 BEQ S07C ;then always print it B075 A9 20 LDA #&20 ;else print a space B077 20 EE FF JSR &FFEE ;call OSWRCH B07A D0 EC BNE S068 ;and print the rest; [BUG] Z undefined .S07C B07C 18 CLC B07D 69 30 ADC #&30 ;convert binary to ASCII "0".."9" #endif /* _BUGFIX */ B07F 20 EE FF JSR &FFEE ;call OSWRCH B082 C0 03 CPY #&03 ;if fewer than 4 digits printed B084 D0 E3 BNE S069 ;then print the rest; C=0 print digits B086 60 RTS ;else exit .S087 ;Get printable input character B087 20 AA B0 JSR S0AA ;get input character and acknowledge ESCAPE B08A C9 30 CMP #&30 ;is ASCII value less than that of "0"? B08C 90 F9 BCC S087 ;if so then discard, get another character B08E C9 5B CMP #&5B ;else is ASCII value higher than "Z"? B090 B0 F5 BCS S087 ;if so then discard, get another character B092 48 PHA ;else save input character B093 20 EE FF JSR &FFEE ;call OSWRCH to print it: .S096 B096 20 AA B0 JSR S0AA ;get input character and acknowledge ESCAPE B099 C9 0D CMP #&0D ;is it CR? B09B D0 02 BNE S09F ;if not then test for DEL B09D 68 PLA ;else restore first character and exit B09E 60 RTS .S09F B09F C9 7F CMP #&7F ;was DELETE key pressed? B0A1 D0 F3 BNE S096 ;if neither CR or DEL then get another B0A3 68 PLA ;else discard first character B0A4 20 25 AE JSR RE25 ;backspace and erase characters B0A7 4C 87 B0 JMP S087 ;and loop to get another character. .S0AA ;Get input character and acknowledge ESCAPE B0AA 20 E0 FF JSR &FFE0 ;call OSRDCH B0AD B0 01 BCS S0B0 ;if C=1 then error occurred, test err. code B0AF 60 RTS ;else return character in A .S0B0 B0B0 C9 1B CMP #&1B ;test if error code from OSRDCH is &1B B0B2 F0 01 BEQ S0B5 ;if so then ESCAPE was pressed B0B4 60 RTS ;else return .S0B5 B0B5 20 58 A4 JSR R458 ;acknowledge ESCAPE condition B0B8 20 A7 A7 JSR R7A7 ;release NMI B0BB AE 10 10 LDX &1010 ;restore stack pointer from &1010 B0BE 9A TXS B0BF 6C 11 10 JMP (&1011) ;and restart command .S0C2 ;Briefly display error indication B0C2 A9 07 LDA #&07 B0C4 20 EE FF JSR &FFEE ;print BEL = make a short beep B0C7 A2 C4 LDX #&C4 ;point XY to "E R R O R" at &B3C4 B0C9 A0 B3 LDY #&B3 B0CB 8A TXA ;save XY B0CC 48 PHA B0CD 98 TYA B0CE 48 PHA B0CF A9 86 LDA #&86 B0D1 20 F4 FF JSR &FFF4 ;call OSBYTE &86 = read cursor pos'n B0D4 8E 26 10 STX &1026 ;save POS in workspace B0D7 8C CF 10 STY &10CF ;save VPOS in workspace B0DA 68 PLA ;restore pointer to "E R R O R" B0DB A8 TAY B0DC 68 PLA B0DD AA TAX B0DE 20 8D AD JSR RD8D ;print VDU sequence at XY B0E1 AE 26 10 LDX &1026 ;restore previous cursor position B0E4 AC CF 10 LDY &10CF B0E7 20 80 AD JSR RD80 ;move cursor to (X,Y) B0EA A9 05 LDA #&05 ;wait 822 milliseconds + interrupts: B0EC 85 B0 STA &B0 ;clear X and Y for use as counters B0EE A2 00 LDX #&00 B0F0 A0 00 LDY #&00 .S0F2 B0F2 88 DEY B0F3 D0 FD BNE S0F2 B0F5 CA DEX ;this point reached every 640 microseconds B0F6 D0 FA BNE S0F2 B0F8 C6 B0 DEC &B0 ;this point reached every 164 milliseconds B0FA D0 F6 BNE S0F2 B0FC 20 8B B1 JSR S18B ;clear rows 20..22 B0FF AE 26 10 LDX &1026 ;restore previous cursor position B102 AC CF 10 LDY &10CF B105 20 80 AD JSR RD80 ;move cursor to (X,Y) and exit B108 60 RTS .S109 ;Convert ASCII numeric to unsigned word B109 A2 00 LDX #&00 B10B 86 B0 STX &B0 B10D 86 B1 STX &B1 .S10F B10F BD 31 10 LDA &1031,X ;get character of string B112 20 32 AE JSR RE32 ;convert ASCII digit to binary and validate B115 B0 2B BCS S142 ;if invalid return with digits added so far B117 48 PHA ;else &B0,1 = &B0,1 * 10 + A: B118 A5 B1 LDA &B1 ;save current value of &B1 B11A 48 PHA B11B A5 B0 LDA &B0 ;save current value of &B0 B11D 06 B0 ASL &B0 ;shift &B0,&B1 left twice B11F 26 B1 ROL &B1 ;to multiply by 4 B121 06 B0 ASL &B0 B123 26 B1 ROL &B1 B125 18 CLC B126 65 B0 ADC &B0 ;add old &B0,&B1 to it making 5x B128 85 B0 STA &B0 B12A 68 PLA B12B 65 B1 ADC &B1 B12D 85 B1 STA &B1 B12F 06 B0 ASL &B0 ;shift &B0,&B1 left once to double it B131 26 B1 ROL &B1 ;making 10x B133 18 CLC B134 68 PLA ;add saved value of A to &B0 B135 65 B0 ADC &B0 B137 85 B0 STA &B0 B139 90 02 BCC S13D ;and carry out to &B1. B13B E6 B1 INC &B1 .S13D B13D E8 INX B13E 88 DEY B13F D0 CE BNE S10F B141 18 CLC .S142 B142 60 RTS .S143 ;Print "FORMAT ERROR" B143 20 8B B1 JSR S18B ;clear rows 20..22 B146 20 D2 A3 JSR R3D2 ;print VDU sequence immediate B149 EQUB &1F ;move cursor to (5,23) B14A EQUB &05 B14B EQUB &17 B14C EQUB &88 ;flashing text B14D EQUB &83 ;yellow alphanumerics B14E EQUS "F O R M A T E R R O R" B165 EQUB &FF ;terminator byte B166 60 RTS .S167 ;Print "VERIFY ERROR" B167 20 8B B1 JSR S18B ;clear rows 20..22 B16A 20 D2 A3 JSR R3D2 ;print VDU sequence immediate B16D EQUB &1F ;move cursor to (5,23) B16E EQUB &05 B16F EQUB &17 B170 EQUB &88 ;flashing text B171 EQUB &83 ;yellow alphanumerics B172 EQUS "V E R I F Y E R R O R" B189 EQUB &FF ;terminator byte B18A 60 RTS .S18B ;Clear rows 20..22 B18B A2 00 LDX #&00 ;move cursor to (0,20) B18D A0 14 LDY #&14 B18F 20 80 AD JSR RD80 ;move cursor to (X,Y) B192 A2 78 LDX #&78 ;print 120 spaces and exit B194 4C E0 AD JMP RDE0 ;print X spaces .S197 ;Prompt user and start format B197 A2 34 LDX #&34 ;point XY at "READY TO FORMAT" heading B199 A0 B3 LDY #&B3 ;at &B334 B19B 20 8D AD JSR RD8D ;print VDU sequence at XY B19E 20 87 B0 JSR S087 ;get printable input character B1A1 C9 46 CMP #&46 ;is it capital F? B1A3 D0 F2 BNE S197 ;if not then reprint heading and try again B1A5 20 85 B2 JSR S285 ;else ensure disc is write enabled B1A8 D0 ED BNE S197 ;if write protected then try again B1AA 20 D2 A3 JSR R3D2 ;else print VDU sequence immediate B1AD EQUB &0C ;clear screen B1AE EQUB &1F ;move cursor to (0,20) B1AF EQUB &00 B1B0 EQUB &14 B1B1 EQUB &88 ;flashing text B1B2 EQUB &83 ;yellow alphanumerics B1B3 EQUS "Please wait while formatting disk" B1D4 EQUB &FF ;terminator byte #if defined _DDOS316 B1D5 20 7E B6 JSR S67E ;recalibrate drive (seek track 0) #elif defined _DDOS336 B1D5 20 7E B6 JSR S67E ;recalibrate drive (seek track 0) #else B1D5 20 7C B6 JSR S67C ;recalibrate drive (seek track 0) #endif B1D8 A9 00 LDA #&00 B1DA 85 BA STA &BA ;set track number = 0 B1DC A9 02 LDA #&02 B1DE 85 B9 STA &B9 ;set running track skew counter = 2 B1E0 85 BB STA &BB ;set first sector of track 0 = 2 #if defined _DDOS316 B1E2 20 2B B8 JSR S82B ;create ID table and format track #elif defined _DDOS336 B1E2 20 2B B8 JSR S82B ;create ID table and format track #else B1E2 20 4E B8 JSR S84E ;create ID table and format track #endif .S1E5 B1E5 38 SEC ;implement track skew B1E6 A5 B9 LDA &B9 ;subtract 2 from first R of track B1E8 E9 02 SBC #&02 B1EA B0 03 BCS S1EF ;if it underflows B1EC 6D E1 10 ADC &10E1 ;then add number of sectors per track .S1EF B1EF 85 B9 STA &B9 ;set first sector number of track #if defined _DDOS316 B1F1 20 91 B6 JSR S691 ;seek logical track #elif defined _DDOS336 B1F1 20 91 B6 JSR S691 ;seek logical track #else B1F1 20 8F B6 JSR S68F ;seek logical track #endif B1F4 A9 03 LDA #&03 ;make three attempts (outer) B1F6 8D 2A 10 STA &102A ;set attempt counter .S1F9 B1F9 20 40 A4 JSR R440 ;poll for ESCAPE B1FC 20 53 B2 JSR S253 ;print track number in table B1FF A0 06 LDY #&06 ;erase next 6 characters B201 20 08 B3 JSR S308 ;erase Y characters ahead of cursor B204 A5 B9 LDA &B9 ;copy first sector number of track B206 85 BB STA &BB #if defined _DDOS316 B208 20 2B B8 JSR S82B ;create ID table and format track #elif defined _DDOS336 B208 20 2B B8 JSR S82B ;create ID table and format track #else B208 20 4E B8 JSR S84E ;create ID table and format track #endif B20B F0 0E BEQ S21B ;if succeeded then verify track B20D CE 2A 10 DEC &102A ;else decrement attempt counter B210 D0 E7 BNE S1F9 ;if attempts remaining then retry B212 20 43 B1 JSR S143 ;else print "FORMAT ERROR" B215 A9 02 LDA #&02 B217 8D 13 10 STA &1013 ;set return code = 2, format failed B21A 60 RTS .S21B B21B 20 28 AB JSR RB28 ;verify track with display B21E F0 0E BEQ S22E ;if succeeded then format next track B220 CE 2A 10 DEC &102A ;else decrement attempt counter B223 D0 D4 BNE S1F9 ;if attempts remaining then try again B225 20 67 B1 JSR S167 ;else print "VERIFY ERROR" B228 A9 03 LDA #&03 B22A 8D 13 10 STA &1013 ;set return code = 3, verify failed B22D 60 RTS .S22E B22E E6 BA INC &BA ;increment track number B230 A5 BA LDA &BA B232 C5 C0 CMP &C0 ;compare with total tracks B234 B0 03 BCS S239 ;if >= total tracks then "Format complete" B236 4C E5 B1 JMP S1E5 ;else loop to format next track .S239 B239 20 D2 A3 JSR R3D2 ;print VDU sequence immediate B23C EQUB &1F ;move cursor to (8,23) B23D EQUB &08 B23E EQUB &17 B23F EQUB &83 ;yellow alphanumerics B240 EQUS "Format complete" B24F EQUB &0D B250 EQUB &0A B251 EQUB &FF B252 60 RTS .S253 ;Print track number in table B253 A9 00 LDA #&00 ;set column to 0 B255 85 B1 STA &B1 B257 A5 BA LDA &BA ;copy track number as row number B259 85 B0 STA &B0 .S25B B25B 38 SEC ;subtract 20 from row number B25C A5 B0 LDA &B0 B25E E9 14 SBC #&14 B260 90 0C BCC S26E ;if underflow then keep current row B262 85 B0 STA &B0 ;else set as new row number B264 18 CLC ;add 10 to column B265 A5 B1 LDA &B1 B267 69 0A ADC #&0A B269 85 B1 STA &B1 B26B 4C 5B B2 JMP S25B ;and loop until row < 20 .S26E B26E A6 B1 LDX &B1 ;set X = column B270 A4 B0 LDY &B0 ;set Y = row B272 20 80 AD JSR RD80 ;move cursor to (X,Y) B275 A5 BA LDA &BA ;copy track number as low byte of word B277 85 B0 STA &B0 B279 A9 00 LDA #&00 ;clear high byte of word B27B 85 B1 STA &B1 B27D 20 5D AE JSR RE5D ;convert binary word to four decimal digits B280 A0 01 LDY #&01 ;set Y=1 print 3 - Y = 2 digits B282 4C 68 B0 JMP S068 ;print decimal digits, space-padded .S285 ;Ensure disc is write enabled B285 20 E2 A7 JSR R7E2 ;test write protect state of current drive B288 F0 59 BEQ S2E3 ;if write enabled then return B28A 20 D2 A3 JSR R3D2 ;else print VDU sequence immediate B28D EQUB &1F ;move cursor to (0,20) B28E EQUB &00 B28F EQUB &14 B290 EQUB &88 ;flashing text B291 EQUB &83 ;yellow alphanumerics B292 EQUS " *** Disk write protected ***" B2B1 EQUB &0D B2B2 EQUB &0A B2B3 EQUB &83 ;yellow alphanumerics B2B4 EQUS "Remove write protect label from disk" B2D8 EQUB &0D B2D9 EQUB &0A B2DA EQUB &FF B2DB 20 E4 B2 JSR S2E4 ;prompt for keypress B2DE 20 8B B1 JSR S18B ;clear rows 20..22 B2E1 A9 FF LDA #&FF ;return Z=0 .S2E3 B2E3 60 RTS .S2E4 ;Prompt for keypress B2E4 20 D2 A3 JSR R3D2 ;print VDU sequence immediate B2E7 EQUB &0D B2E8 EQUS "Press any key to continue" B301 EQUB &FF B302 20 AA B0 JSR S0AA ;get input character and acknowledge ESCAPE B305 4C 8B B1 JMP S18B ;clear rows 20..22 and exit .S308 ;Erase Y characters ahead of cursor B308 98 TYA B309 48 PHA B30A 20 DA 88 JSR P8DA ;print number of spaces in Y B30D 68 PLA B30E A8 TAY .S30F B30F A9 7F LDA #&7F ;print number of DELs in Y B311 20 EE FF JSR &FFEE B314 88 DEY B315 D0 F8 BNE S30F B317 60 RTS B318 EQUB &1F ;move cursor to (0,23) B319 EQUB &00 B31A EQUB &17 B31B EQUS "Volume : " B32B EQUB &7F B32C EQUB &7F B32D EQUB &7F B32E EQUB &7F B32F EQUB &7F B330 EQUB &7F B331 EQUB &7F B332 EQUB &7F B333 EQUB &FF B334 EQUB &16 ;set display MODE 7 B335 EQUB &07 B336 EQUB &0A B337 EQUB &0A B338 EQUB &0A B339 EQUB &83 ;yellow alphanumerics B33A EQUS " R E A D Y T O F O R M A T" B35B EQUB &0D B35C EQUB &0A B35D EQUB &0A B35E EQUB &0A B35F EQUB &83 ;yellow alphanumerics B360 EQUS "Press F(ret) to start " B376 EQUB &FF B377 EQUB &1F ;move cursor to (0,20) B378 EQUB &00 B379 EQUB &14 B37A EQUB &88 ;flashing text B37B EQUB &83 ;yellow alphanumerics B37C EQUS "Please wait while generating volumes" B3A0 EQUB &FF B3A1 EQUB &1F ;move cursor to (2,14) B3A2 EQUB &02 B3A3 EQUB &0E B3A4 EQUB &83 ;yellow alphanumerics B3A5 EQUS "VOLUME GENERATION COMPLETE" B3BF EQUB &0D B3C0 EQUB &0A B3C1 EQUB &0A B3C2 EQUB &0A B3C3 EQUB &FF B3C4 EQUB &1F ;move cursor to (4,20) B3C5 EQUB &04 B3C6 EQUB &14 B3C7 EQUB &88 ;flashing text B3C8 EQUB &83 ;yellow alphanumerics B3C9 EQUS " E R R O R" B3D6 EQUB &FF ;terminator byte ;*DENSITY B3D7 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg B3DA 98 TYA ;transfer command line offset to A B3DB A2 E6 LDX #&E6 ;point XY to keyword table at &B3E6 B3DD A0 B3 LDY #&B3 B3DF 20 C7 8E JSR PEC7 ;search for keyword in table B3E2 A2 03 LDX #&03 ;density flag goes to &10E3 B3E4 D0 28 BNE S40E ;jump to action address ;*DENSITY keyword table B3E6 EQUS "SINGLE" B3EC EQUW &B4,&28 B3EE EQUB &00 B3EF EQUS "DOUBLE" B3F5 EQUW &B4,&25 B3F7 EQUB &00 B3F8 EQUS "AUTO" B3FC EQUW &B4,&2B B3FE EQUB &00 ;unused syntax byte #if defined _DDOS357 B3FF EQUW &87,&2F ;wrong keyword, "Bad command" &872F #else B3FF EQUW &94,&F8 ;wrong keyword, "Bad command" &94F8 #endif ;*4080 B401 20 0E A0 JSR R00E ;call GSINIT with C=0 and reject empty arg B404 98 TYA ;transfer command line offset to A B405 A2 11 LDX #&11 ;point XY to keyword table at &B411 B407 A0 B4 LDY #&B4 B409 20 C7 8E JSR PEC7 ;search for keyword in table B40C A2 00 LDX #&00 ;stepping flag goes to &10E0 .S40E #if defined _DDOS357 B40E 4C C7 80 JMP P0C7 ;jump to action address #else B40E 4C CC 80 JMP P0CC ;jump to action address #endif ;*4080 keyword table B411 EQUS "ON" B413 EQUW &B4,&25 B415 EQUB &00 B416 EQUS "OFF" B419 EQUW &B4,&28 B41B EQUB &00 B41C EQUS "AUTO" B420 EQUW &B4,&2B B422 EQUB &00 ;unused syntax byte #if defined _DDOS357 B423 EQUW &87,&2F ;wrong keyword, "Bad command" &872F #else B423 EQUW &94,&F8 ;wrong keyword, "Bad command" &94F8 #endif B425 A9 40 LDA #&40 ;*4080 ON *DENSITY DOUBLE B427 AC A9 00 LDY &00A9 ;*4080 OFF *DENSITY SINGLE B428=LDA #&00 B42A AC A9 80 LDY &80A9 ;*4080 AUTO *DENSITY AUTO B42B=LDA #&80 B42D 9D E0 10 STA &10E0,X ;to &10E0 or &10E3 B430 60 RTS ;*RAMINIT B431 BA TSX ;have A=0 returned on exit, claim call B432 A9 00 LDA #&00 B434 9D 05 01 STA &0105,X #if defined _TURBO B437 20 2D A3 JSR R32D ;save XY (inner) #else B437 20 29 A3 JSR R329 ;save XY (inner) #endif B43A 20 C1 A7 JSR R7C1 ;claim NMI B43D A9 00 LDA #&00 ;destination LBA = &0000, start of RAM disc B43F 85 BA STA &BA B441 85 BB STA &BB B443 20 B3 AE JSR REB3 ;clear pages &0E,&0F #if defined _RAMINIT64K B446 A9 01 LDA #&01 ;set volume size in catalogue = 64 KiB #elif defined _RAMINIT76K B446 A9 01 LDA #&01 ;set volume size in catalogue = 76 KiB #elif defined _RAMINIT256K B446 A9 03 LDA #&03 ;set volume size in catalogue = 256 KiB #else B446 A9 02 LDA #&02 ;set volume size in catalogue = 128 KiB #endif B448 8D 06 0F STA &0F06 #if defined _RAMINIT76K B44B A9 30 LDA #&30 #elif defined _RAMINIT256K B44B A9 FF LDA #&FF #else B44B A9 00 LDA #&00 #endif B44D 8D 07 0F STA &0F07 B450 A9 02 LDA #&02 ;set transfer size in &A0,1 = 512 bytes B452 85 A1 STA &A1 B454 A9 00 LDA #&00 B456 85 A0 STA &A0 B458 A9 01 LDA #&01 ;data transfer call &01 = write data B45A 8D 00 10 STA &1000 ;set data transfer call number B45D 20 ED 92 JSR Q2ED ;set data pointer to &0E00 B460 20 70 B4 JSR S470 ;transfer data to paged RAM B463 20 A7 A7 JSR R7A7 ;release NMI B466 60 RTS .S467 ;Transfer data L2 B467 A5 CF LDA &CF ;get current volume B469 29 0C AND #&0C ;if not on physical drive 0..3 B46B D0 03 BNE S470 ;then transfer data to paged RAM #if defined _DDOS316 B46D 4C 5F B7 JMP S75F ;else transfer data to disc L2 #elif defined _DDOS336 B46D 4C 5F B7 JMP S75F ;else transfer data to disc L2 #else B46D 4C 5D B7 JMP S75D ;else transfer data to disc L2 #endif .S470 ;Transfer data to paged RAM #if defined _TURBO B470 20 2D A3 JSR R32D ;save XY #else B470 20 29 A3 JSR R329 ;save XY #endif B473 A5 A2 LDA &A2 ;save &A2..5 B475 48 PHA B476 A5 A3 LDA &A3 B478 48 PHA B479 A5 A4 LDA &A4 B47B 48 PHA B47C A5 A5 LDA &A5 B47E 48 PHA B47F A0 54 LDY #&54 ;copy 85 bytes: .S481 B481 B9 11 B5 LDA &B511,Y ;copy RAM transfer code from &B511..65 B484 99 00 0D STA &0D00,Y ;to NMI handler area at &0D00..54 B487 88 DEY ;loop until 85 bytes copied B488 10 F7 BPL S481 B48A AD 01 10 LDA &1001 ;copy *SROM slot number B48D 85 A3 STA &A3 ;to NMI zero page area B48F A5 BA LDA &BA ;copy starting LBA HIGH byte B491 85 A5 STA &A5 ;to &A5 B493 A5 BB LDA &BB ;copy starting LBA LOW byte B495 85 A4 STA &A4 ;to &A4 B497 A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 B499 F0 02 BEQ S49D ;not rounding up, converting number format; B49B E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .S49D B49D AD 00 10 LDA &1000 ;if data transfer call is not 0 = read data B4A0 D0 16 BNE S4B8 ;then modify RAM transfer code for write B4A2 A5 A6 LDA &A6 ;else paste user memory address at &0D14,5 B4A4 8D 14 0D STA &0D14 B4A7 A5 A7 LDA &A7 B4A9 8D 15 0D STA &0D15 B4AC AD D5 10 LDA &10D5 ;test Tube transfer flag #if defined _RAMBUGFIX B4AF F0 49 BEQ S4FA ;if b7=0 then an I/O transfer, branch #else B4AF F0 4C BEQ S4FD ;if b7=0 then an I/O transfer, branch #endif B4B1 A9 8D LDA #&8D ;else instruction at &0D13 = STA &FEE5 B4B3 A0 08 LDY #&08 B4B5 4C DF B4 JMP S4DF ;modify RAM transfer code for Tube. .S4B8 ;Modify RAM transfer code for write B4B8 A9 15 LDA #&15 ;instruction at &0D51 = STA &0D15 B4BA 8D 52 0D STA &0D52 B4BD A9 A3 LDA #&A3 ;instruction at &0D06 = LDX &A3 B4BF 8D 07 0D STA &0D07 B4C2 A9 A2 LDA #&A2 ;instruction at &0D0E = LDX &A2 B4C4 8D 0F 0D STA &0D0F B4C7 A5 A6 LDA &A6 ;paste user memory address at &0D0C,D B4C9 8D 0C 0D STA &0D0C B4CC A5 A7 LDA &A7 B4CE 8D 0D 0D STA &0D0D B4D1 A9 0D LDA #&0D ;instruction at &0D19 = INC &0D0D B4D3 8D 1A 0D STA &0D1A B4D6 AD D5 10 LDA &10D5 ;test Tube transfer flag #if defined _RAMBUGFIX B4D9 F0 1F BEQ S4FA ;if b7=0 then an I/O transfer, branch #else B4D9 F0 22 BEQ S4FD ;if b7=0 then an I/O transfer, branch #endif B4DB A9 AD LDA #&AD ;else instruction at &0D0B = LDA &FEE5 B4DD A0 00 LDY #&00 ;fall through: .S4DF ;Modify RAM transfer code for Tube B4DF 99 0B 0D STA &0D0B,Y ;store opcode LDA abs at &D0B/STA abs at &D13 #if defined _RAMBUGFIX B4E2 EA NOP ;no operation #else B4E2 C8 INY ;increment offset - d'oh! [BUG] #endif B4E3 A9 E5 LDA #&E5 ;store address of R3DATA, &FEE5 B4E5 99 0C 0D STA &0D0C,Y ;at &0D0D,E or &0D15,6 B4E8 A9 FE LDA #&FE B4EA 99 0D 0D STA &0D0D,Y B4ED A9 EA LDA #&EA ;instructions at &0D19,&0D1A,&0D1B = NOP B4EF 8D 19 0D STA &0D19 ;which was INC &0D15/INC &0D0D B4F2 8D 1A 0D STA &0D1A B4F5 8D 1B 0D STA &0D1B #if defined _RAMBUGFIX B4F8 49 00 EOR #&00 ;no operation .S4FA B4FA A0 00 LDY #&00 ;starting offset = &00 B4FC 20 36 0D JSR &0D36 ;compute source RAM slot number B4FF 20 03 0D JSR &0D03 ;do transfer to/from paged RAM #else B4F8 A9 60 LDA #&60 ;instruction at &0D4B = RTS B4FA 8D 4B 0D STA &0D4B ;disable paste high byte of source address .S4FD B4FD A0 00 LDY #&00 ;starting offset = &00 B4FF 20 00 0D JSR &0D00 ;do transfer to/from paged RAM #endif B502 68 PLA ;restore &A2..5 from stack B503 85 A5 STA &A5 B505 68 PLA B506 85 A4 STA &A4 B508 68 PLA B509 85 A3 STA &A3 B50B 68 PLA B50C 85 A2 STA &A2 B50E A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. B510 60 RTS ;Paged RAM transfer code copied to &0D00 #if defined _RAMBUGFIX B511 40 RTI ;ignore spurious interrupts #else B511 20 36 0D JSR &0D36 ;compute source RAM slot number #endif B514 20 4B 0D JSR &0D4B ;paste high byte of source address .S517 B517 A6 A2 LDX &A2 B519 8E 30 FE STX &FE30 B51C B9 00 FF LDA &FF00,Y ;high byte of source address pasted to &0D0D B51F A6 A3 LDX &A3 B521 8E 30 FE STX &FE30 B524 99 00 FF STA &FF00,Y ;high byte of dest. address pasted to &0D15 B527 C8 INY B528 D0 0F BNE S539 B52A EE 15 0D INC &0D15 ;increment high byte of STA address B52D E6 A4 INC &A4 B52F D0 02 BNE S533 B531 E6 A5 INC &A5 .S533 B533 20 36 0D JSR &0D36 ;compute source RAM slot number B536 20 4B 0D JSR &0D4B ;paste high byte of source address .S539 B539 C6 A0 DEC &A0 ;decrement byte count B53B D0 DA BNE S517 ;loop until all bytes transferred B53D C6 A1 DEC &A1 B53F D0 D6 BNE S517 B541 A5 F4 LDA &F4 ;page DDOS ROM back in B543 8D 30 FE STA &FE30 B546 60 RTS ;return #if defined _BMEM B547 A5 A5 LDA &A5 B549 4A LSR A B54A A5 A4 LDA &A4 B54C 29 C0 AND #&C0 ;ab...... H B54E 69 0F ADC #&0F ;ab.H~~~~ B550 4A LSR A B551 4A LSR A B552 4A LSR A B553 4A LSR A ;....ab.H B554 49 03 EOR #&03 ;37BF26AE B556 85 A2 STA &A2 B558 60 RTS #elif defined _IFEL B547 A5 A4 LDA &A4 ;abcdefgh B549 45 A5 EOR &A5 B54B 29 01 AND #&01 ;.......x B54D 45 A4 EOR &A4 ;abcdefgH B54F C9 80 CMP #&80 ;abcdefgH a B551 2A ROL A B552 2A ROL A B553 2A ROL A ;defgHaab c B554 29 0D AND #&0D ;....Ha.b B556 49 00 EOR #&00 ;014589CD B558 85 A2 STA &A2 B55A 60 RTS #elif defined _WILLIAMS B547 A5 A5 LDA &A5 B549 4A LSR A B54A A5 A4 LDA &A4 ;abcdefgh H B54C 2A ROL A B54D 2A ROL A B54E 2A ROL A ;defghHab c B54F 29 07 AND #&07 ;.....Hab B551 49 08 EOR #&08 ;89ABCDEF B553 85 A2 STA &A2 B555 60 RTS #elif defined _TWOMEG B547 A5 A4 LDA &A4 ;abcdefgh B549 45 A5 EOR &A5 B54B 29 01 AND #&01 ;.......x B54D 45 A4 EOR &A4 ;abcdefgH B54F 0A ASL A B550 2A ROL A B551 2A ROL A ;defgH.ab B552 29 0B AND #&0B ;....H.ab B554 49 04 EOR #&04 ;4567CDEF B556 85 A2 STA &A2 B558 60 RTS #elif defined _PLUGIN B547 A5 A5 LDA &A5 B549 4A LSR A B54A A5 A4 LDA &A4 ;abcdefgh H B54C 2A ROL A B54D 2A ROL A ;cdefghHa b B54E 29 03 AND #&03 B550 90 02 BCC S554 B552 49 04 EOR #&04 ;.....bHa .S554 B554 49 00 EOR #&00 ;04152637 or &03 to go right-to-left B556 85 A2 STA &A2 B558 60 RTS #elif defined _PLUGIN2 B547 A5 A5 LDA &A5 B549 4A LSR A B54A A5 A4 LDA &A4 B54C 2A ROL A B54D 29 81 AND #&81 ;b......H a B54F 10 02 BPL S553 B551 49 84 EOR #&84 ;.....b.H a .S553 B553 90 02 BCC S557 B555 49 02 EOR #&02 ;.....baH .S557 B557 49 00 EOR #&00 ;04261537 or slot no. of first plugin B559 85 A2 STA &A2 B55B 60 RTS #elif defined _PLUGIN3 B547 A5 A5 LDA &A5 B549 4A LSR A B54A A5 A4 LDA &A4 B54C 2A ROL A B54D 29 81 AND #&81 ;b......H a B54F 10 02 BPL S553 B551 49 84 EOR #&84 ;.....b.H a .S553 B553 90 02 BCC S557 B555 49 03 EOR #&03 ;.....ba~ .S557 B557 49 01 EOR #&01 ;15260437 or slot no. of first plugin B559 85 A2 STA &A2 B55B 60 RTS #elif defined _BPLUS B547 A5 A5 LDA &A5 B549 4A LSR A B54A A9 18 LDA #&18 B54C 6A ROR A ;H...11.. . B54D 24 A4 BIT &A4 B54F 10 05 BPL S556 ;PSR = ab1xxxx. B551 4D 4B 02 EOR &024B ;BASIC ROM slot no. B554 49 03 EOR #&03 ;H...xxxx . .S556 B556 70 02 BVC S55A B558 49 01 EOR #&01 ;CD01 or CDEF then 8C .S55A B55A 85 A2 STA &A2 ;fall through to calculate page no. #elif defined _MASTER B547 A5 A5 LDA &A5 B549 4A LSR A B54A A5 A4 LDA &A4 ;abcdefgh H B54C 2A ROL A B54D 2A ROL A B54E 2A ROL A ;defghHab c B54F 29 07 AND #&07 ;.....Hab B551 49 04 EOR #&04 ;45670123 B553 85 A2 STA &A2 B555 60 RTS #else B547 A5 A5 LDA &A5 ;0D36 B549 85 A2 STA &A2 ;copy bits of &A5: ABCDEFGH B54B A5 A4 LDA &A4 ;load bits of &A4: abcdefgh B54D 29 C0 AND #&C0 ;mask b7,6: ab...... B54F 46 A2 LSR &A2 B551 6A ROR A ;a=Hab....., &A2=.ABCDEFG B552 46 A2 LSR &A2 B554 6A ROR A ;a=GHab...., &A2=..ABCDEF B555 69 10 ADC #&10 ;c=0; skip slot &0E, reserved for paged ROM B557 09 0E ORA #&0E ;a=GHab111. adjusted B559 85 A2 STA &A2 ;save result as source RAM 'slot' number B55B 60 RTS #endif B55C A5 A4 LDA &A4 ;0D4B B55E 29 3F AND #&3F ;take high byte of source address B560 09 80 ORA #&80 ;confine to paged ROM address space &80..BF B562 8D 0D 0D STA &0D0D ;paste in high byte of LDA &FF00,Y instr. B565 60 RTS ;*FDCSTAT B566 BA TSX ;have A=0 returned on exit B567 A9 00 LDA #&00 B569 9D 05 01 STA &0105,X B56C 20 D2 A3 JSR R3D2 ;print VDU sequence immediate B56F EQUB &0D B570 EQUB &0A #if defined _DDOS316 B571 EQUS "WD 2791 status : " #elif defined _DDOS336 B571 EQUS "WD 2793 status : " #else B571 EQUS "WD 1770 status : " #endif B582 EQUB &FF B583 AD 8F 10 LDA &108F ;get status of last command B586 20 29 A4 JSR R429 ;print hex byte B589 4C 67 84 JMP P467 ;print newline B58C A2 00 LDX #&00 ;&13 Read data / &17 Read data & deleted data B58E AD A2 01 LDA &01A2 ;&0B Write data B58F=LDX #&01 B591 AD A2 02 LDA &02A2 ; B592=LDX #&02 B594 AD A2 03 LDA &03A2 ;&0F Write deleted data B595=LDX #&03 B597 AD A2 04 LDA &04A2 ;&1F Verify data B598=LDX #&04 B59A 8E 00 10 STX &1000 ;set data transfer call number B59D 20 36 B6 JSR S636 ;set starting sector and byte count #if defined _DDOS316 B5A0 20 5F B7 JSR S75F ;transfer data to disc L2 #elif defined _DDOS336 B5A0 20 5F B7 JSR S75F ;transfer data to disc L2 #else B5A0 20 5D B7 JSR S75D ;transfer data to disc L2 #endif B5A3 A0 0A LDY #&0A ;y = 10 = offset of status in read/write cmd B5A5 91 B0 STA (&B0),Y ;return status to user's OSWORD &7F block B5A7 60 RTS ;&29 Seek #if defined _DDOS316 B5A8 20 91 B6 JSR S691 ;seek logical track #elif defined _DDOS336 B5A8 20 91 B6 JSR S691 ;seek logical track #else B5A8 20 8F B6 JSR S68F ;seek logical track #endif B5AB A0 08 LDY #&08 ;y = 8 = offset of status in seek command B5AD 91 B0 STA (&B0),Y ;return status to user's OSWORD &7F block B5AF 60 RTS ;&1B Read ID #if defined _DDOS316 B5B0 20 CD B6 JSR S6CD ;read ID and detect density B5B3 20 CD B6 JSR S6CD ;read ID and detect density #elif defined _DDOS336 B5B0 20 CD B6 JSR S6CD ;read ID and detect density B5B3 20 CD B6 JSR S6CD ;read ID and detect density #else B5B0 20 CB B6 JSR S6CB ;read ID and detect density B5B3 20 CB B6 JSR S6CB ;read ID and detect density #endif B5B6 A0 0A LDY #&0A ;y = 10 = offset of status in read/write cmd B5B8 91 B0 STA (&B0),Y ;return status to user's OSWORD &7F block B5BA A8 TAY ;if status = 0 then no error B5BB D0 0B BNE S5C8 .S5BD B5BD B9 90 10 LDA &1090,Y ;so get byte of ID read from workspace B5C0 20 21 9E JSR QE21 ;put data byte in user memory B5C3 C8 INY ;loop until 4 bytes returned to user B5C4 C0 04 CPY #&04 B5C6 D0 F5 BNE S5BD .S5C8 B5C8 60 RTS ;&23 Format track #if defined _DDOS316 B5C9 4C 68 B8 JMP S868 ;format track #elif defined _DDOS336 B5C9 4C 68 B8 JMP S868 ;format track #else B5C9 4C 8B B8 JMP S88B ;format track #endif ;&2C Read drive status B5CC 88 DEY ;y = 8 going to 7, offset of result #if defined _DDOS316 B5CD 20 75 B6 JSR S675 ;test write protect state #elif defined _DDOS336 B5CD 20 75 B6 JSR S675 ;test write protect state #else B5CD 20 73 B6 JSR S673 ;test write protect state #endif B5D0 4A LSR A ;returned in bit 6 B5D1 4A LSR A ;move to bit 3 = WR PROT B5D2 4A LSR A B5D3 09 44 ORA #&44 ;set b6 = RDY 1, b2 = RDY 0 B5D5 91 B0 STA (&B0),Y ;return result to user's OSWORD &7F block .S5D7 B5D7 60 RTS ;&35 Specify B5D8 A5 BA LDA &BA ;get first parameter B5DA C9 0D CMP #&0D ;is it &0D = Specify Initialization? B5DC D0 F9 BNE S5D7 ;if not then exit B5DE B1 B0 LDA (&B0),Y ;else get second parameter = step rate B5E0 AA TAX ;(WD1770 format; 0=fast..3=slow; b7..2=0) B5E1 4C 6F B6 JMP S66F ;save as track stepping rate and force int. ;&3A Write special registers B5E4 B1 B0 LDA (&B0),Y ;get second parameter = value to write B5E6 A6 BA LDX &BA ;get first parameter = register address B5E8 E0 04 CPX #&04 ;if address in range 0..3 B5EA B0 04 BCS S5F0 B5EC 9D E0 10 STA &10E0,X ;then set parameter of current drive B5EF 60 RTS .S5F0 B5F0 D0 04 BNE S5F6 ;else if address = 4 B5F2 8D 01 10 STA &1001 ;then set *SROM slot number B5F5 60 RTS .S5F6 B5F6 E0 12 CPX #&12 ;else if address = 18 B5F8 D0 16 BNE S610 #if defined _DDOS316 B5FA 4C 85 B9 JMP S985 ;then store physical position of head #elif defined _DDOS336 B5FA 4C 85 B9 JMP S985 ;then store physical position of head #elif defined _DDOS357 B5FA 4C A4 B9 JMP S9A4 ;then store physical position of head #else B5FA 4C A8 B9 JMP S9A8 ;then store physical position of head #endif ;NB sets head addressed by ?XY, not head 0 ;&3D Read special registers B5FD A6 BA LDX &BA ;get first parameter = register address B5FF E0 04 CPX #&04 ;if address in range 0..3 B601 B0 06 BCS S609 B603 BD E0 10 LDA &10E0,X ;then return parameter of current drive B606 91 B0 STA (&B0),Y ;return to offset 8 of OSWORD control block B608 60 RTS .S609 B609 D0 05 BNE S610 ;else if address = 4 B60B AD 01 10 LDA &1001 ;then return *SROM slot number B60E 91 B0 STA (&B0),Y ;return to offset 8 of OSWORD control block .S610 B610 60 RTS ;Table of 8271 floppy drive controller commands with action addresses B611 EQUB &13 ;&13 Read data B612 EQUW &8B,&B5 B614 EQUB &0B ;&0B Write data B615 EQUW &8E,&B5 B617 EQUB &29 ;&29 Seek B618 EQUW &A7,&B5 B61A EQUB &1F ;&1F Verify data B61B EQUW &97,&B5 B61D EQUB &17 ;&17 Read data & deleted data B61E EQUW &8B,&B5 B620 EQUB &0F ;&0F Write deleted data B621 EQUW &94,&B5 B623 EQUB &1B ;&1B Read ID B624 EQUW &AF,&B5 B626 EQUB &23 ;&23 Format track B627 EQUW &C8,&B5 B629 EQUB &2C ;&2C Read drive status B62A EQUW &CB,&B5 B62C EQUB &35 ;&35 Specify B62D EQUW &D7,&B5 B62F EQUB &3A ;&3A Write special registers B630 EQUW &E3,&B5 B632 EQUB &3D ;&3D Read special registers B633 EQUW &FC,&B5 B635 EQUB &00 ;terminator byte .S636 ;Set starting sector and byte count B636 B1 B0 LDA (&B0),Y ;get 2nd parameter = starting sector number B638 C8 INY ;increment offset; Y = 9 B639 85 BB STA &BB ;store in zero page, &BA = track number B63B B1 B0 LDA (&B0),Y ;get number of sectors + size code B63D 20 66 A4 JSR R466 ;shift A right 5 places B640 AA TAX ;save size code in X B641 A9 00 LDA #&00 ;set LSB of byte count = 0 B643 85 A0 STA &A0 B645 B1 B0 LDA (&B0),Y ;get number of sectors + size code B647 C8 INY ;increment offset; Y = 10, points to status B648 29 1F AND #&1F ;extract number of sectors B64A 4A LSR A ;A,&A0 = 256 x sector count; divide by two B64B 66 A0 ROR &A0 ;= byte count if X=0, 128-byte sectors B64D 90 03 BCC S652 ;jump into doubling loop (always) .S64F B64F 06 A0 ASL &A0 ;multiply byte count by two B651 2A ROL A .S652 B652 CA DEX ;subtract 1 from X B653 10 FA BPL S64F ;if X was >0 then double byte count B655 85 A1 STA &A1 ;else store high byte of byte count and exit B657 60 RTS .S658 ;Set control latch for drive #if defined _DDOS356 B658 A5 CF LDA &CF ;get current volume B65A 29 03 AND #&03 ;extract physical drive number, clear b7..2 B65C DA PHX ;save X B65D 20 48 BF JSR SF48 ;convert control latch to Master format B660 FA PLX ;restore X B661 8D 24 FE STA &FE24 ;store in control latch B664 60 RTS #elif defined _DDOS357 B658 A5 CF LDA &CF ;get current volume B65A 29 03 AND #&03 ;extract physical drive number, clear b7..2 B65C DA PHX ;save X B65D 20 63 A1 JSR R163 ;convert control latch to Master format B660 FA PLX ;restore X B661 8D 24 FE STA &FE24 ;store in control latch B664 60 RTS #elif defined _DDOS326 B658 8A TXA ;save X B659 48 PHA B65A A5 CF LDA &CF ;get current volume B65C 29 03 AND #&03 ;extract physical drive number, clear b7..2 B65E AA TAX B65F AD E3 10 LDA &10E3 ;get density flag in bit 6 B662 4C 44 BF JMP SF44 ;jump to patch to continue #else B658 A5 CF LDA &CF ;get current volume B65A 29 03 AND #&03 ;extract physical drive number, clear b7..2 B65C 0D E3 10 ORA &10E3 ;apply density flag in bit 6 B65F 29 7F AND #&7F ;mask off bit 7, *DENSITY AUTO B661 8D 84 FE STA &FE84 ;store in control latch B664 60 RTS #endif .S665 ;Set track stepping rate from startup options B665 20 00 A3 JSR R300 ;save AXY B668 20 1C A8 JSR R81C ;call OSBYTE &FF = read/write startup options B66B 8A TXA ;transfer keyboard links to A B66C 20 5F A4 JSR R45F ;extract b5,b4 of A .S66F B66F 8D 8E 10 STA &108E ;save as track stepping rate #if defined _DDOS316 B672 4C 46 B7 JMP S746 ;send Force Interrupt command #elif defined _DDOS336 B672 4C 46 B7 JMP S746 ;send Force Interrupt command #else B672 60 RTS ;1770 doesn't need Force Interrupt?? #endif #if defined _DDOS316 ;////////////////////////////////////////////// DDOS 3.16 .S675 ;Test write protect state B675 20 3C B7 JSR S73C ;issue Seek and Force Interrupt B678 20 E6 B9 JSR S9E6 ;wait for command completion B67B 29 40 AND #&40 ;z=0 if WD2791 S6 = write protect. B67D 60 RTS ;[BUG] The recalibrate and seek routines raise the INTRQ pin which ;causes an NMI, but do not install code in the NMI service area. ;Any code left at the NMI entry point is executed. ;Typically there is an RTI instruction at &0D00 left by the MOS on ;reset, or by a previous NMI service routine that self-sealed. An FDC ;command that did not complete, however, leaves its ISR active and this ;services the NMI - mistreating the command completion interrupt as a ;data request - and interferes with the byte transfer count at &A0..1. ;A floppy disc operation performs a seek as a subtask after storing the ;count and before installing its service routine. It expects NMIs to be ;ignored in the meantime and because they are not, it goes on to ;transfer the wrong number of bytes. ;If re-entered, the RAM disc transfer code overwrites memory and crashes ;(original version; it is patched in this file under symbol _RAMBUGFIX.) ;Machines with Econet are also affected. ;Opus 2791/2793 board users (running DDOS 3.1x/3.3x) have their INTRQ ;pin disconnected from the NMI line and get off scot-free. .S67E ;Recalibrate drive (seek track 0) # if defined _TURBO B67E 20 2D A3 JSR R32D ;save XY # else B67E 20 29 A3 JSR R329 ;save XY # endif B681 A9 08 LDA #&08 ;WD2791 FDC command &00 = Restore # if defined _BUGFIX B683 20 F6 92 JSR Q2F6 ;execute command and wait for completion # else B683 20 BB B6 JSR S6BB ;execute command and wait for completion # endif B686 A5 CF LDA &CF ;get current volume B688 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B68A AA TAX ;transfer to X for use as index B68B A9 00 LDA #&00 ;set physical position of head to 0 B68D 9D 8C 10 STA &108C,X B690 60 RTS .S691 ;Seek logical track B691 A5 BA LDA &BA ;get logical track number B693 2C E0 10 BIT &10E0 ;test double-stepping flag B696 50 01 BVC S699 ;if b6=1 then double stepping is enabled B698 0A ASL A ;so double track number: .S699 ;Seek physical track B699 C9 00 CMP #&00 ;if track number = 0 B69B F0 E1 BEQ S67E ;then issue Restore command # if defined _TURBO B69D 20 2D A3 JSR R32D ;else save XY # else B69D 20 29 A3 JSR R329 ;else save XY # endif B6A0 48 PHA ;save target physical track B6A1 A5 CF LDA &CF ;get current volume B6A3 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B6A5 AA TAX ;transfer to X for use as index B6A6 BD 8C 10 LDA &108C,X ;get physical track number for drive B6A9 20 8F B9 JSR S98F ;store in track register of FDC B6AC 68 PLA ;restore target physical track B6AD 9D 8C 10 STA &108C,X ;store physical track number for drive B6B0 20 DA B9 JSR S9DA ;write to FDC data register B6B3 A9 18 LDA #&18 ;WD2791 FDC command &10 = Seek # if defined _BUGFIX B6B5 20 F6 92 JSR Q2F6 ;execute command and wait for completion # else B6B5 20 BB B6 JSR S6BB ;execute command and wait for completion # endif B6B8 29 10 AND #&10 ;z=0 if WD2791 S4 = record not found. B6BA 60 RTS .S6BB ;Execute Restore/Seek command B6BB 0D 8E 10 ORA &108E ;apply track stepping rate B6BE 20 CE B9 JSR S9CE ;write to FDC command register B6C1 4C E6 B9 JMP S9E6 ;wait for command completion and exit. .S6C4 ;Ensure disc is formatted B6C4 20 CD B6 JSR S6CD ;read ID and detect density B6C7 F0 03 BEQ S6CC ;if record found then exit B6C9 4C B7 B9 JMP S9B7 ;else raise "Disk not formatted" error. .S6CC B6CC 60 RTS ;[BUG]cannot force density, always tests both .S6CD ;Read ID and detect density # if defined _TURBO B6CD 20 2D A3 JSR R32D ;save XY # else B6CD 20 29 A3 JSR R329 ;save XY # endif B6D0 20 3C B7 JSR S73C ;issue Seek and Force Interrupt B6D3 A2 04 LDX #&04 ;4 attempts to make, 2 in each density: B6D5 2C E3 10 BIT &10E3 ;if current density is single B6D8 50 0F BVC S6E9 ;then attempt in single density first, else: .S6DA B6DA AD E3 10 LDA &10E3 ;get density flag B6DD 09 40 ORA #&40 ;set b6=1, double density B6DF A0 12 LDY #&12 ;18 sectors per track B6E1 20 0E B7 JSR S70E ;execute Read Address at specified density B6E4 F0 25 BEQ S70B ;if record found then return success B6E6 CA DEX ;else decrement number of attempts remaining B6E7 F0 0F BEQ S6F8 ;if run out of tries then return failure .S6E9 B6E9 AD E3 10 LDA &10E3 ;else get density flag B6EC 29 BF AND #&BF ;set b6=0, single density B6EE A0 0A LDY #&0A ;10 sectors per track B6F0 20 0E B7 JSR S70E ;execute Read Address at specified density B6F3 F0 16 BEQ S70B ;if record found then return success B6F5 CA DEX ;else decrement number of attempts remaining B6F6 D0 E2 BNE S6DA ;if attempts remaining try double density .S6F8 B6F8 AD E3 10 LDA &10E3 ;else set b6=0, single density B6FB 29 BF AND #&BF B6FD 8D E3 10 STA &10E3 B700 20 58 B6 JSR S658 ;set control latch for drive B703 A9 0A LDA #&0A ;set 10 sectors per track B705 8D E1 10 STA &10E1 B708 A9 18 LDA #&18 ;fake WD2791 S4 = record not found B70A 60 RTS ;fake WD2791 S3 = CRC error. .S70B B70B A9 00 LDA #&00 ;fake WD2791 status = 0, succeeded. B70D 60 RTS .S70E ;Execute Read Address at specified density B70E 8D E3 10 STA &10E3 ;store density flag B711 8C E1 10 STY &10E1 ;store number of sectors per track: .S714 ;Execute Read Address command B714 A0 16 LDY #&16 ;23 bytes to copy, &0D00..16: [DIFF] .S716 B716 B9 5C BA LDA &BA5C,Y ;get byte of NMI read ID B719 99 00 0D STA &0D00,Y ;store in NMI area B71C 88 DEY ;loop until all bytes copied B71D 10 F7 BPL S716 B71F A9 00 LDA #&00 ;initialise offset = 0 B721 85 A0 STA &A0 B723 20 58 B6 JSR S658 ;set control latch for drive B726 A9 C0 LDA #&C0 ;WD2791 command &C0 = Read address B728 20 CE B9 JSR S9CE ;write to FDC command register B72B 20 E6 B9 JSR S9E6 ;wait for command completion B72E 48 PHA ;save exit status B72F A0 03 LDY #&03 ;4 bytes to copy, &1090..3: .S731 B731 B9 90 10 LDA &1090,Y ;get CHRN byte of sector ID B734 99 02 10 STA &1002,Y ;copy to workspace B737 88 DEY ;loop until all bytes copied B738 10 F7 BPL S731 B73A 68 PLA ;restore Read Address command status and exit B73B 60 RTS .S73C ;Issue Seek and Force Interrupt B73C A9 18 LDA #&18 ;WD2791 command &18 = Seek w/spin up B73E 20 CE B9 JSR S9CE ;write to FDC command register B741 A2 0F LDX #&0F ;wait 38 microseconds .S743 B743 CA DEX B744 D0 FD BNE S743 .S746 B746 A9 D0 LDA #&D0 ;WD2791 command &D0 = Force interrupt B748 4C CE B9 JMP S9CE ;write to FDC command register and exit .S74B B74B 60 RTS .S74C ;Verify track # if defined _TURBO B74C 20 2D A3 JSR R32D ;save XY # else B74C 20 29 A3 JSR R329 ;save XY # endif B74F A9 00 LDA #&00 B751 85 BB STA &BB ;sector number = 0 B753 85 A0 STA &A0 ;whole number of sectors to transfer B755 AD E1 10 LDA &10E1 ;get number of sectors per track B758 85 A1 STA &A1 ;set number of sectors to transfer B75A A9 04 LDA #&04 ;set call number to &04, verify data B75C 8D 00 10 STA &1000 .S75F ;Transfer data to disc L2 # if defined _TURBO B75F 20 2D A3 JSR R32D ;save XY # else B75F 20 29 A3 JSR R329 ;save XY # endif B762 20 D6 A7 JSR R7D6 ;set up for current drive B765 20 91 B6 JSR S691 ;seek logical track ;[DIFF] no delay, status save or ;on-track verification B768 A5 BA LDA &BA ;get logical track number B76A 20 85 B9 JSR S985 ;store as 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 &B771. B76D 20 76 B7 JSR S776 ;execute floppy drive command L1 B770 48 PHA ;save masked status B771 20 7D B9 JSR S97D ;store head position for this drive B774 68 PLA ;restore masked status, setting Z B775 60 RTS ;and exit .S776 ;Execute floppy drive command L1 # if defined _TURBO B776 20 2D A3 JSR R32D ;save XY # else B776 20 29 A3 JSR R329 ;save XY # endif B779 A5 A0 LDA &A0 ;save ?&A0, ?&A1 on stack B77B 48 PHA B77C A5 A1 LDA &A1 B77E 48 PHA B77F 20 0E B8 JSR S80E ;copy NMI read from disc/polling loop to NMI B782 AD 01 10 LDA &1001 ;get *SROM slot number [DIFF] not &0D2D B785 8D 31 0D STA &0D31 ;store in polling loop to page in on entry B788 A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 B78A F0 02 BEQ S78E ;not rounding up, converting number format; B78C E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .S78E B78E AD 00 10 LDA &1000 ;get data transfer call number B791 29 05 AND #&05 ;if call=0 or 2, read (deleted) data B793 F0 14 BEQ S7A9 ;then branch B795 6A ROR A ;else if b2..0 = 1x0, A=&04 verify data B796 B0 15 BCS S7AD B798 A9 4C LDA #&4C ;then instruction at &0D08 = JMP &0D13 B79A 8D 08 0D STA &0D08 ;discard byte from FDC data register B79D A9 13 LDA #&13 ;[DIFF] not &0D06 = JMP &0D11 B79F 8D 09 0D STA &0D09 B7A2 A9 0D LDA #&0D B7A4 8D 0A 0D STA &0D0A B7A7 D0 10 BNE S7B9 .S7A9 B7A9 A0 09 LDY #&09 ;if call=0 or 2, read (deleted) data B7AB D0 09 BNE S7B6 ;then data address is located at &0D09. ;[DIFF] not &0D07 .S7AD B7AD A9 00 LDA #&00 ;if b0=1, A=1 or 3 write (deleted) data B7AF 85 A0 STA &A0 ;then clear ?&A0, write whole sectors B7B1 20 1A B8 JSR S81A ;copy NMI write to disc to NMI area B7B4 A0 04 LDY #&04 ;data address is located at &0D04 .S7B6 B7B6 20 E4 B7 JSR S7E4 ;set data address in NMI ISR .S7B9 B7B9 A5 F4 LDA &F4 ;get DDOS ROM slot number B7BB 8D 3E 0D STA &0D3E ;save in NMI area B7BE A5 BB LDA &BB ;get start sector number B7C0 20 D4 B9 JSR S9D4 ;write to FDC sector register B7C3 AC 00 10 LDY &1000 ;get data transfer call number B7C6 B9 FF B9 LDA &B9FF,Y ;get FDC command for call B7C9 20 CE B9 JSR S9CE ;write to FDC command register B7CC A2 1E LDX #&1E ;wait 76 microseconds .S7CE B7CE CA DEX B7CF D0 FD BNE S7CE B7D1 20 30 0D JSR &0D30 ;page SROM in and wait until finished L0 B7D4 68 PLA ;restore ?&A0, ?&A1 from stack B7D5 85 A1 STA &A1 B7D7 68 PLA B7D8 85 A0 STA &A0 B7DA 20 F6 B9 JSR S9F6 ;load FDC status register and store b6..0 B7DD AC 00 10 LDY &1000 B7E0 39 04 BA AND &BA04,Y ;apply status mask from table to set Z. B7E3 60 RTS .S7E4 ;Set data address in NMI ISR B7E4 AD D5 10 LDA &10D5 ;test Tube data transfer flag B7E7 F0 1A BEQ S803 ;if transferring data to Tube B7E9 A9 E5 LDA #&E5 ;then paste address of R3DATA at &0D00+Y B7EB 99 00 0D STA &0D00,Y B7EE A9 FE LDA #&FE B7F0 99 01 0D STA &0D01,Y B7F3 A9 4C LDA #&4C ;instruction at &0D0B = JMP &0D13 [DIFF] B7F5 8D 0B 0D STA &0D0B ;do not increment R3DATA address B7F8 A9 13 LDA #&13 B7FA 8D 0C 0D STA &0D0C B7FD A9 0D LDA #&0D B7FF 8D 0D 0D STA &0D0D B802 60 RTS .S803 B803 A5 A6 LDA &A6 ;else copy data pointer to NMI ISR at &0D00+Y B805 99 00 0D STA &0D00,Y B808 A5 A7 LDA &A7 B80A 99 01 0D STA &0D01,Y B80D 60 RTS .S80E ;Copy NMI read from disc/polling loop to NMI B80E A0 42 LDY #&42 ;67 bytes to copy, &0D00..42 [DIFF]: .S810 B810 B9 09 BA LDA &BA09,Y ;get byte of NMI read from disc/polling loop B813 99 00 0D STA &0D00,Y B816 88 DEY ;store in NMI area B817 10 F7 BPL S810 ;loop until all bytes copied B819 60 RTS .S81A ;Copy NMI write to disc to NMI area B81A A0 0F LDY #&0F ;14 bytes to copy, &0D03..10: .S81C B81C B9 4C BA LDA &BA4C,Y ;get byte of NMI write to disc B81F 99 03 0D STA &0D03,Y ;patch NMI read to disc routine with it B822 88 DEY ;loop until all bytes copied B823 10 F7 BPL S81C B825 A9 FC LDA #&FC ;enable 123 microsecond delay B827 8D 25 0D STA &0D25 ;before interrupting write operation B82A 60 RTS ;so that FDC will write CRC of sector .S82B ;Create ID table and format track B82B A9 0A LDA #&0A ;set A = 10 sectors per track B82D 2C E3 10 BIT &10E3 ;if double density format B830 50 02 BVC S834 B832 A9 12 LDA #&12 ;then set A = 18 sectors per track .S834 B834 85 A6 STA &A6 ;store as limit to sector count B836 0A ASL A ;multiply by 4 B837 0A ASL A B838 85 A7 STA &A7 ;store as size of CHRN table B83A A6 BB LDX &BB ;set X = number of first sector B83C A0 00 LDY #&00 ;(inverse track skew) Y=0 CHRN tbl index .S83E B83E A5 BA LDA &BA ;Get logical track number B840 99 A0 11 STA &11A0,Y ;store cylinder number C B843 C8 INY B844 A9 00 LDA #&00 ;head number = 0 B846 99 A0 11 STA &11A0,Y ;store head humber H B849 C8 INY B84A 8A TXA ;transfer sector number to A B84B 99 A0 11 STA &11A0,Y ;store record number R B84E C8 INY B84F A9 01 LDA #&01 ;size code = 1, 256-byte sector B851 99 A0 11 STA &11A0,Y ;store size code N B854 C8 INY B855 E8 INX ;increment sector number B856 E4 A6 CPX &A6 ;has it reached no. sectors per track? B858 90 02 BCC S85C B85A A2 00 LDX #&00 ;if so then wrap around to 0 .S85C B85C C4 A7 CPY &A7 ;has table offset reached 4x s.p.t? B85E 90 DE BCC S83E ;if not then loop B860 A9 A0 LDA #&A0 ;else set pointer to start of CHRN table: B862 85 A6 STA &A6 B864 A9 11 LDA #&11 B866 85 A7 STA &A7 .S868 ;Format track B868 A9 12 LDA #&12 ;set data table pointer to &1312 B86A 85 A2 STA &A2 ;(page break occurs 1/8 of the way through B86C 85 A4 STA &A4 ;the 11th sector of the track.) B86E A9 13 LDA #&13 B870 85 A3 STA &A3 B872 A9 15 LDA #&15 ;set run table pointer to &1512 B874 85 A5 STA &A5 B876 A2 00 LDX #&00 ;point to single density table, X = &00 B878 2C E3 10 BIT &10E3 ;if double density format B87B 50 02 BVC S87F B87D A2 23 LDX #&23 ;then point to double density table, X = &23 .S87F B87F A0 05 LDY #&05 ;set Y = 5 as counter: .S881 B881 20 C2 B8 JSR S8C2 ;add entry to track format RLE table B884 88 DEY ;loop until 5 entries added B885 D0 FA BNE S881 ;this copies gap 5, IDAM and start of gap 1 B887 A0 0A LDY #&0A ;set Y = 10 sectors per track B889 2C E3 10 BIT &10E3 ;if double density format B88C 50 02 BVC S890 B88E A0 12 LDY #&12 ;then Y = 18 sectors per track .S890 B890 8A TXA ;X points to repeating sector block B891 48 PHA ;save it .S892 B892 20 C2 B8 JSR S8C2 ;add entry to track format RLE table B895 90 FB BCC S892 ;loop until terminator byte reached B897 68 PLA ;reset X to start of sector block B898 AA TAX B899 88 DEY ;decrement number of sectors remaining B89A D0 F4 BNE S890 ;loop until all sectors added to track B89C A9 00 LDA #&00 ;data byte = &00 (run length = &10 or &16) B89E 20 15 B9 JSR S915 ;add gap 4 to table B8A1 20 91 B6 JSR S691 ;seek logical track B8A4 A9 0F LDA #&0F ;A = &0F (or just do LDY &1512:DEY:STY &A0!) B8A6 2C E3 10 BIT &10E3 ;if double density format B8A9 50 02 BVC S8AD B8AB A9 27 LDA #&27 ;then A = &27 .S8AD B8AD 85 A0 STA &A0 ;set number of filler bytes in gap 5 (- 1) B8AF A0 25 LDY #&25 ;38 bytes to copy, &0D00..25 [DIFF]: .S8B1 B8B1 B9 73 BA LDA &BA73,Y ;get byte of NMI format code B8B4 99 00 0D STA &0D00,Y ;store in NMI handler area B8B7 88 DEY ;loop until all bytes transferred B8B8 10 F7 BPL S8B1 B8BA A9 F4 LDA #&F4 ;&F4=Write track, settling delay B8BC 20 CE B9 JSR S9CE ;write to FDC command register B8BF 4C E6 B9 JMP S9E6 ;wait for command completion and exit. .S8C2 ;Add entry to track format RLE table B8C2 8A TXA ;save ROM table offset B8C3 48 PHA B8C4 98 TYA ;save number of sectors remaining B8C5 48 PHA B8C6 A0 00 LDY #&00 ;y=&00, unused B8C8 38 SEC B8C9 BD 33 B9 LDA &B933,X ;get run length from ROM table B8CC 30 12 BMI S8E0 ;if b7=1 then process special entry B8CE F0 09 BEQ S8D9 ;if the terminator byte then finish C=1 B8D0 85 A0 STA &A0 ;else store run length in zero page B8D2 BD 34 B9 LDA &B934,X ;get data byte from ROM table B8D5 20 15 B9 JSR S915 ;store run in table .S8D8 B8D8 18 CLC ;c=0, sector not completed .S8D9 B8D9 68 PLA ;restore number of sectors remaining B8DA A8 TAY B8DB 68 PLA ;restore ROM table offset B8DC AA TAX B8DD E8 INX ;add 2 to ROM table offset B8DE E8 INX B8DF 60 RTS .S8E0 ;Process special table entry (length=&FF) B8E0 BD 34 B9 LDA &B934,X ;get data byte from ROM format table B8E3 D0 1C BNE S901 ;if non-zero then add sector data area B8E5 A9 01 LDA #&01 ;else add ID bytes. run length of bytes = 1 B8E7 85 A0 STA &A0 ;store run length in zero page B8E9 A2 04 LDX #&04 ;4 bytes in sector ID: .S8EB B8EB A0 00 LDY #&00 ;y=0 for user memory load B8ED 20 15 9E JSR QE15 ;get data byte from user memory B8F0 20 15 B9 JSR S915 ;store run in table B8F3 E6 A6 INC &A6 ;increment CHRN table pointer B8F5 D0 02 BNE S8F9 ;carry out to high byte B8F7 E6 A7 INC &A7 .S8F9 B8F9 CA DEX ;loop until 4 ID bytes stored B8FA D0 EF BNE S8EB B8FC 85 A1 STA &A1 ;store last byte read = N = size code B8FE 4C D8 B8 JMP S8D8 ;restore XY and return .S901 ;Add sector data area B901 A6 A1 LDX &A1 ;load sector size code B903 BD 79 B9 LDA &B979,X ;get run length from table B906 85 A0 STA &A0 ;store in zero page B908 A2 08 LDX #&08 ;repeat prescribed run 8 times: .S90A B90A A9 E5 LDA #&E5 ;A=&E5 = sector filler byte B90C 20 15 B9 JSR S915 ;store run in table B90F CA DEX ;loop until 8 copies of run stored B910 D0 F8 BNE S90A B912 4C D8 B8 JMP S8D8 ;restore XY and return .S915 ;Store run in table B915 A0 00 LDY #&00 ;offset = 0 for indirect indexed store B917 91 A2 STA (&A2),Y ;store data byte in data table B919 A5 A0 LDA &A0 ;get run length B91B 91 A4 STA (&A4),Y ;store run length in run table B91D C6 A4 DEC &A4 ;if pointers are on a page boundary B91F E6 A4 INC &A4 B921 D0 05 BNE S928 B923 38 SEC ;then subtract 1 from run length B924 E9 01 SBC #&01 B926 91 A4 STA (&A4),Y .S928 B928 E6 A2 INC &A2 ;increment data table pointer B92A E6 A4 INC &A4 ;increment run table pointer B92C D0 04 BNE S932 ;carry out to high bytes B92E E6 A3 INC &A3 B930 E6 A5 INC &A5 .S932 B932 60 RTS ;RLE tables of formatting bytes ;Single density B933 EQUB &10,&FF ; 16x &FF filler bytes } Gap 5 B935 EQUB &03,&00 ; 6x &00 synchronization bytes } B937 EQUB &03,&00 B939 EQUB &01,&FC ; 1x &FC index address mark (clock &D7) B93B EQUB &0B,&FF ; 11x &FF filler bytes } Gap 1 ;block repeated for each sector B93D EQUB &03,&00 ; 6x &00 synchronization bytes } B93F EQUB &03,&00 B941 EQUB &01,&FE ; 1x &FE ID address mark (clock &C7) B943 EQUB &FF,&00 ;id bytes are inserted here B945 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B947 EQUB &0B,&FF ; 11x &FF filler bytes } Gap 2 B949 EQUB &03,&00 ; 6x &00 synchronization bytes } B94B EQUB &03,&00 B94D EQUB &01,&FB ; 1x &FB data address mark (clock &C7) B94F EQUB &FF,&01 ;data bytes are inserted here B951 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B953 EQUB &10,&FF ; 16x &FF filler bytes } Gap 3... ;end of repeated block B955 EQUB &00 ;terminator byte (not part of format) ;Double density B956 EQUB &28,&4E ; 40x &4E filler bytes } B958 EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 5 B95A EQUB &03,&F6 ; 3x &F6 synchronization bytes } B95C EQUB &01,&FC ; 1x &FC index address mark B95E EQUB &19,&4E ; 25x &4E filler bytes } Gap 1 ;block repeated for each sector B960 EQUB &0C,&00 ; 12x &00 preamble bytes } B962 EQUB &03,&F5 ; 3x &F5 synchronization bytes } B964 EQUB &01,&FE ; 1x &FE ID address mark B966 EQUB &FF,&00 ;id bytes are inserted here B968 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B96A EQUB &16,&4E ; 22x &4E filler bytes } B96C EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 2 B96E EQUB &03,&F5 ; 3x &F5 synchronization bytes } B970 EQUB &01,&FB ; 1x &FB data address mark B972 EQUB &FF,&01 ;data bytes are inserted here B974 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B976 EQUB &16,&4E ; 22x &4E filler bytes } Gap 3... ;end of repeated block B978 EQUB &00 ;terminator byte (not part of format) B979 EQUB &10 ;8x runs of 16 bytes for 128-byte sectors B97A EQUB &20 ;8x runs of 32 bytes for 256-byte sectors B97B EQUB &40 ;8x runs of 64 bytes for 512-byte sectors B97C EQUB &80 ;8x runs of 128 bytes for 1024-byte sectors .S97D ;Store per-drive head position B97D A5 BA LDA &BA ;get logical track number of disc operation B97F 2C E0 10 BIT &10E0 ;test double-stepping flag B982 50 01 BVC S985 ;if b6=1 then double stepping is enabled B984 0A ASL A ;so double track number: .S985 ;Store physical position of head B985 48 PHA B986 A5 CF LDA &CF ;get current volume B988 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B98A AA TAX ;transfer to X for use as index B98B 68 PLA ;get back A B98C 9D 8C 10 STA &108C,X ;store physical track number for drive .S98F B98F 49 FF EOR #&FF ;[DIFF] invert for WD 2791 B991 8D 81 FE STA &FE81 ;store in track register of FDC B994 60 RTS .S995 B995 20 47 A3 JSR R347 B998 EQUB &C5 B999 EQUS " fault" B99F EQUB &00 ;unreachable code B9A0 20 62 A3 JSR R362 B9A3 EQUB &C5 B9A4 EQUS "Cannot recalibrate" B9B6 EQUB &00 .S9B7 B9B7 20 62 A3 JSR R362 B9BA EQUB &C5 B9BB EQUS "Disk not formatted" B9CD EQUB &00 .S9CE ;Write to FDC command register B9CE 49 FF EOR #&FF ;[DIFF] invert for WD 2791 B9D0 8D 80 FE STA &FE80 B9D3 60 RTS .S9D4 ;Write to FDC sector register B9D4 49 FF EOR #&FF ;[DIFF] invert for WD 2791 B9D6 8D 82 FE STA &FE82 B9D9 60 RTS .S9DA ;Write to FDC data register B9DA 49 FF EOR #&FF ;[DIFF] invert for WD 2791 B9DC 8D 83 FE STA &FE83 B9DF 60 RTS .S9E0 ;Load FDC status register B9E0 AD 80 FE LDA &FE80 B9E3 29 80 AND #&80 ;mask b7 extract WD2791 S7 = not ready B9E5 60 RTS ;return A=0, Z=1 iff drive ready [DIFF] .S9E6 # if defined _TURBO B9E6 20 2D A3 JSR R32D ;save XY # else B9E6 20 29 A3 JSR R329 ;save XY # endif B9E9 A2 FF LDX #&FF ;wait 638 microseconds .S9EB B9EB CA DEX B9EC D0 FD BNE S9EB .S9EE B9EE 20 F6 B9 JSR S9F6 ;load FDC status register [DIFF] inverted B9F1 30 FB BMI S9EE ;[DIFF] loop until b7=0 WD2791 S7 = not rdy B9F3 6A ROR A ;place bit 0 in carry flag B9F4 B0 F8 BCS S9EE ;loop until b0=0 WD2791 S0 = busy .S9F6 B9F6 AD 80 FE LDA &FE80 ;load FDC status register B9F9 49 FF EOR #&FF ;[DIFF] flip bits 7..0 keep WD2791 S7 = not rdy B9FB 8D 8F 10 STA &108F ;save final status B9FE 60 RTS ;Table of WD2791 FDC commands for data transfer call numbers 0..4 B9FF EQUB &90 ;&00 = Read data BA00 EQUB &B4 ;&01 = Write data BA01 EQUB &90 BA02 EQUB &B5 ;&03 = Write deleted data BA03 EQUB &90 ;&04 = Verify data ;Table of status mask bytes for data transfer call numbers 0..4 ;{RecordNotFound CRCError LostData} (&1C) plus: BA04 EQUB &3C ;&00 = Read data: {RecordType} BA05 EQUB &7C ;&01 = Write data: {WriteProtect RecordType} BA06 EQUB &1C ;{} BA07 EQUB &5C ;&03 = Write deleted data: {WriteProtect} BA08 EQUB &3C ;&04 = Verify data: {RecordType} ;NMI read from disc, &0D00..2F [DIFF] ;opcode read 4+e..8 microseconds after NMI ;(up to 13.5 us if code running in 1 MHz mem) BA09 8D 2E 0D STA &0D2E ;save accumulator to restore on exit BA0C AD 83 FE LDA &FE83 ;read FDC data register BA0F 49 FF EOR #&FF ;[DIFF] invert for WD 2791 BA11 8D FF FF STA &FFFF ;store in user memory or R3DATA BA14 EE 09 0D INC &0D09 ;increment user memory address BA17 D0 03 BNE SA1C ;carry out to high byte BA19 EE 0A 0D INC &0D0A .SA1C BA1C C6 A0 DEC &A0 ;decrement count of bytes to transfer BA1E D0 16 BNE SA36 ;(&0101 = 1; &0000 = 0) BA20 C6 A1 DEC &A1 ;if count has not reached zero BA22 D0 12 BNE SA36 ;then restore A and return from interrupt BA24 A9 40 LDA #&40 ;else set 0D00=RTI; ignore further NMIs BA26 8D 00 0D STA &0D00 ;ISR safe by 22+e..29.5 us after NMI BA29 A9 CE LDA #&CE ;write complete by 24.5+e..32 us BA2B 69 01 ADC #&01 ;wait 123 microseconds (if loop enabled) BA2D 90 00 BCC SA2F ;0D23=&FC loops back to &0D20 .SA2F BA2F A9 D0 LDA #&D0 ;FDC command &D0 = Force Interrupt BA31 49 FF EOR #&FF ;[DIFF] invert for WD 2791 BA33 8D 80 FE STA &FE80 ;write to FDC command register .SA36 BA36 A9 00 LDA #&00 ;restore value of A on entry BA38 40 RTI ;return from interrupt ;NMI polling loop, &0D30..42 [DIFF] BA39 A9 0E LDA #&0E ;page *SROM slot in BA3B 8D 30 FE STA &FE30 .SA3E BA3E AD 80 FE LDA &FE80 ;load FDC status register BA41 10 FB BPL SA3E ;[DIFF] loop until b7=0 WD2791 S7 = not ready BA43 6A ROR A ;place bit 0 in carry flag BA44 90 F8 BCC SA3E ;[DIFF] loop until b0=0 WD2791 S0 = busy BA46 A9 00 LDA #&00 ;page DDOS ROM back in BA48 8D 30 FE STA &FE30 BA4B 60 RTS ;NMI write to disc, &0D03..12 [DIFF] BA4C AD FF FF LDA &FFFF BA4F 49 FF EOR #&FF BA51 8D 83 FE STA &FE83 BA54 EE 04 0D INC &0D04 BA57 D0 03 BNE SA5C BA59 EE 05 0D INC &0D05 .SA5C BA5C 8D 15 0D STA &0D15 ;NMI read ID, &0D00..16 [DIFF] BA5F 8C 13 0D STY &0D13 ;save AY to restore on exit BA62 A4 A0 LDY &A0 ;load offset in Y BA64 AD 83 FE LDA &FE83 ;load FDC data register BA67 49 FF EOR #&FF ;[DIFF] invert for WD 2791 BA69 99 90 10 STA &1090,Y ;store ID byte in buffer BA6C E6 A0 INC &A0 ;increment offset BA6E A0 00 LDY #&00 ;restore AY on entry BA70 A9 00 LDA #&00 BA72 40 RTI ;A run-length encoded table of formatting bytes is stored in two arrays ;starting at &1312 and &1512. Valid range of counts is &01..&80. ;When the byte source address crosses a page, the high byte is incremented ;in the same interrupt and the new count is fetched (from the next page) ;in the next interrupt. One byte from the next page is sent to the ;controller in the meantime, and so the first count of a page is one less ;than the number of bytes actually sent, i.e. the first byte of the page ;cannot be a singleton. The page crossing occurs 1/8th of the way through ;the data area of the eleventh sector after the index pulse. BA73 48 PHA ;NMI format, &0D00..23 BA74 AD 12 13 LDA &1312 ;save A on entry, fetch current data byte BA77 49 FF EOR #&FF ;[DIFF] invert for WD 2791 BA79 8D 83 FE STA &FE83 ;write to FDC data register BA7C C6 A0 DEC &A0 ;decrement run counter BA7E D0 0A BNE SA8A ;if all bytes in run written BA80 EE 02 0D INC &0D02 ;then increment data byte address low BA83 D0 0A BNE SA8F ;if no carry then fetch next run length BA85 EE 03 0D INC &0D03 ;else increment data byte address high .SA88 BA88 68 PLA ;restore A on entry BA89 40 RTI ;exit .SA8A BA8A 10 FC BPL SA88 ;if run still in progress then exit BA8C EE 21 0D INC &0D21 ;else page was crossed last time: .SA8F BA8F EE 20 0D INC &0D20 ;increment run length address BA92 AD 12 15 LDA &1512 ;fetch next run length BA95 85 A0 STA &A0 ;set run counter BA97 68 PLA ;restore A on entry BA98 40 RTI ;exit ;unreachable code BA99 EA NOP ;Tube hosting .SA9A ;Service calls &FE, &FF BA9A C9 FE CMP #&FE ;is service call number <&FE? BA9C 90 5C BCC SAFA ;if so then return to process other calls BA9E D0 1B BNE SABB ;if A=&FF then branch to do main init, else: BAA0 C0 00 CPY #&00 ;Service call &FE = Tube post initialisation BAA2 F0 56 BEQ SAFA ;ignore call if Y=0 on entry BAA4 A2 06 LDX #&06 ;else X=6 = fully exploded BAA6 A9 14 LDA #&14 ;OSBYTE &14 = explode soft character RAM BAA8 20 F4 FF JSR &FFF4 ;call OSBYTE .SAAB BAAB 2C E0 FE BIT &FEE0 ;print Tube coprocessor banner: BAAE 10 FB BPL SAAB ;poll until character in R1DATA BAB0 AD E1 FE LDA &FEE1 ;then read R1DATA BAB3 F0 43 BEQ SAF8 ;if =NUL then claim service call and exit BAB5 20 EE FF JSR &FFEE ;else print the character & loop BAB8 4C AB BA JMP SAAB .SABB ;Service call &FF = Tube main initialisation BABB A9 AD LDA #&AD ;EVNTV = &06AD BABD 8D 20 02 STA &0220 BAC0 A9 06 LDA #&06 BAC2 8D 21 02 STA &0221 BAC5 A9 16 LDA #&16 ;BRKV = &0016 BAC7 8D 02 02 STA &0202 BACA A9 00 LDA #&00 BACC 8D 03 02 STA &0203 BACF A9 8E LDA #&8E ;set Tube status (NAUG p.329) BAD1 8D E0 FE STA &FEE0 ;enable NMI on R3, IRQ on R1,R4 BAD4 A0 00 LDY #&00 ;initialise offset to 0: .SAD6 BAD6 B9 3C BB LDA &BB3C,Y ;copy Tube host code from &BB3C..&BE3B BAD9 99 00 04 STA &0400,Y ;to &0400..&06FF BADC B9 3C BC LDA &BC3C,Y ;offset 0 first, then 255..1 BADF 99 00 05 STA &0500,Y BAE2 B9 3C BD LDA &BD3C,Y BAE5 99 00 06 STA &0600,Y BAE8 88 DEY BAE9 D0 EB BNE SAD6 BAEB 20 21 04 JSR &0421 ;mark Tube unclaimed BAEE A2 60 LDX #&60 ;initialise offset to &60 .SAF0 BAF0 BD FB BA LDA &BAFB,X ;copy Tube BRK handler from &BAFB..5B BAF3 95 16 STA &16,X ;to &0016..76 BAF5 CA DEX BAF6 10 F8 BPL SAF0 .SAF8 BAF8 A9 00 LDA #&00 ;return A=0 to claim service call .SAFA BAFA 60 RTS ;Tube BRK handler copied to &0016..76 BAFB A9 FF LDA #&FF ;set A=&FF to interrupt coprocessor (JGH) BAFD 20 9E 06 JSR &069E ;write A to R4DATA BB00 AD E3 FE LDA &FEE3 ;empty inward R2DATA and discard byte BB03 A9 00 LDA #&00 ;set A=0 to specify error (JGH) BB05 20 95 06 JSR &0695 ;write A to R2DATA BB08 A8 TAY ;set Y=0 offset into error message BB09 B1 FD LDA (&FD),Y ;get error number at MOS error pointer BB0B 20 95 06 JSR &0695 ;write A to R2DATA .SB0E BB0E C8 INY ;increment offset BB0F B1 FD LDA (&FD),Y ;get character of error message BB11 20 95 06 JSR &0695 ;write A to R2DATA BB14 AA TAX ;test last character written BB15 D0 F7 BNE SB0E ;loop until it is NUL BB17 A2 FF LDX #&FF ;reset stack pointer BB19 9A TXS BB1A 58 CLI ;enable interrupts: .SB1B ;0036 Idle loop BB1B 2C E0 FE BIT &FEE0 ;test R1STAT BB1E 10 06 BPL SB26 ;if b7=1, data available .SB20 BB20 AD E1 FE LDA &FEE1 ;then read R1DATA to A BB23 20 EE FF JSR &FFEE ;call OSWRCH. .SB26 BB26 2C E2 FE BIT &FEE2 ;test R2STAT BB29 10 F0 BPL SB1B ;if b7=0, data not available then test R1 BB2B 2C E0 FE BIT &FEE0 ;else Tube call waiting. test R1STAT BB2E 30 F0 BMI SB20 ;first print waiting bytes to OSWRCH (if any) BB30 AE E3 FE LDX &FEE3 ;then read R2DATA to X =call number BB33 86 51 STX &51 ;modify LSB indirect address of next inst. BB35 6C 00 05 JMP (&0500) ;0050 handle Tube call via jump table ;Default Tube entry address = &00008000 BB38 EQUB &00 BB39 EQUB &80 BB3A EQUB &00 BB3B EQUB &00 ;Tube host code copied to &0400..&06FF ;0400 Copy language to coprocessor (NAUG) BB3C 4C 84 04 JMP &0484 ;0403 Copy ESCAPE flag to coprocessor (NAUG) BB3F 4C A7 06 JMP &06A7 ;0406 Tube service entry BB42 C9 80 CMP #&80 ;if A = &00..7F BB44 90 2B BCC SB71 ;then set up data transfer BB46 C9 C0 CMP #&C0 ;else if A = &C0..FF BB48 B0 1A BCS SB64 ;then handle Tube claim BB4A 09 40 ORA #&40 ;else A=&80..BF release Tube BB4C C5 15 CMP &15 ;set b6=1 to compare with claimant ID BB4E D0 20 BNE SB70 ;if releaser is not claimant then ignore else: ;0414 Release Tube BB50 08 PHP ;save interrupt state BB51 78 SEI ;disable interrupts BB52 A9 05 LDA #&05 ;type byte=5 No transfer (FS release) BB54 20 9E 06 JSR &069E ;write A to R4DATA BB57 A5 15 LDA &15 ;set A=claimant ID BB59 20 9E 06 JSR &069E ;write A to R4DATA BB5C 28 PLP ;restore interrupt state: BB5D A9 80 LDA #&80 ;0421 Mark Tube unclaimed BB5F 85 15 STA &15 ;not in range &C0..FF =no claimant BB61 85 14 STA &14 ;&80=Tube unclaimed BB63 60 RTS .SB64 ;0428 Claim Tube BB64 06 14 ASL &14 ;&00=Tube claimed BB66 B0 06 BCS SB6E ;if it was unclaimed then set claimant BB68 C5 15 CMP &15 ;else compare caller's ID - current claimant BB6A F0 04 BEQ SB70 ;if same claimant reclaims then return C=1 BB6C 18 CLC ;else reject claim, return C=0 BB6D 60 RTS .SB6E BB6E 85 15 STA &15 ;set current claimant, C=1 claim granted .SB70 BB70 60 RTS .SB71 ;0435 Set up data transfer BB71 08 PHP ;save interrupt state BB72 78 SEI ;disable interrupts BB73 84 13 STY &13 ;set control block pointer from XY BB75 86 12 STX &12 ;a=type byte/reason code BB77 20 9E 06 JSR &069E ;write A to R4DATA BB7A AA TAX ;hold type byte in X BB7B A0 03 LDY #&03 ;1+4 bytes to write BB7D A5 15 LDA &15 ;set A=claimant ID BB7F 20 9E 06 JSR &069E ;write A to R4DATA: .SB82 BB82 B1 12 LDA (&12),Y ;get byte of transfer address, MSB to LSB BB84 20 9E 06 JSR &069E ;write A to R4DATA BB87 88 DEY ;in descending/big-endian order BB88 10 F8 BPL SB82 ;loop until claimant+4 address bytes written BB8A A0 18 LDY #&18 ;set Tube status (NAUG p.329) BB8C 8C E0 FE STY &FEE0 ;set V,M=0 disable NMI and word mode on R3 BB8F BD 18 05 LDA &0518,X ;get status setting for transfer type in X BB92 8D E0 FE STA &FEE0 ;write to R1STAT BB95 4A LSR A ;test I in bit 1 = modify interrupts on R1 BB96 4A LSR A ;(if I was modified, then I was set) BB97 90 06 BCC SB9F ;if interrupts were enabled on R1 BB99 2C E5 FE BIT &FEE5 ;then transferring to host (C=1, used later) BB9C 2C E5 FE BIT &FEE5 ;discard word in R3 to empty it .SB9F BB9F 20 9E 06 JSR &069E ;write A to R4DATA = synchronising byte .SBA2 BBA2 2C E6 FE BIT &FEE6 ;wait for it to be taken; test R4STAT BBA5 50 FB BVC SBA2 ;loop until b6=1, not full BBA7 B0 0D BCS SBB6 ;if transferring to host then branch BBA9 E0 04 CPX #&04 ;else if type<>4 address only BBAB D0 11 BNE SBBE ;then return without handshake, else: .SBAD ;0471 Release Tube with handshake BBAD 20 14 04 JSR &0414 ;release Tube BBB0 20 95 06 JSR &0695 ;write A to R2DATA =&80 =transfer complete ;This value is used by code implementing OSCLI on the coprocessor to decide ;whether to return to the user or to jump to code at the type 4 transfer ;address. This call does not return. If the *command is not a binary to ;download to the coprocessor, DDOS's OSCLI code returns to the MOS which in ;turn exits to &059C (&BCD8), and there &7F is written to R2DATA indicating ;command completion. If that value is the first to arrive, it means there was ;no type 4 transfer address issued, and the coprocessor's OSCLI returns. BBB3 4C 32 00 JMP &0032 ;go to idle loop .SBB6 BBB6 4A LSR A ;test J in bit 2 = modify interrupts on R4 BBB7 90 05 BCC SBBE ;if J=1, types 0 or 2, bytes/words to host BBB9 A0 88 LDY #&88 BBBB 8C E0 FE STY &FEE0 ;then set M=1 enable NMIs on R3 .SBBE BBBE 28 PLP ;restore interrupt state BBBF 60 RTS ;0484 Copy language to coprocessor (NAUG) BBC0 58 CLI ;enable interrupts BBC1 B0 11 BCS SBD4 ;if C=1, entry from *FX142 (JGH) then copy BBC3 D0 03 BNE SBC8 ;else if A>0 then enter language (JGH) BBC5 4C 9C 05 JMP &059C ;else A=0 no language, signal completion .SBC8 BBC8 A2 00 LDX #&00 ;set X=&00 do not alter BBCA A0 FF LDY #&FF ;set Y=&FF do not update BBCC A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset BBCE 20 F4 FF JSR &FFF4 ;call OSBYTE BBD1 8A TXA ;if type = 0 soft BREAK BBD2 F0 D9 BEQ SBAD ;then release Tube and write &80 to R2DATA .SBD4 BBD4 A9 FF LDA #&FF ;&FF = claim Tube with claimant ID = &3F BBD6 20 06 04 JSR &0406 ;call Tube service BBD9 90 F9 BCC SBD4 ;loop until claim granted BBDB 20 D2 04 JSR &04D2 ;set up Tube destination address .SBDE BBDE A9 07 LDA #&07 ;type byte = 7, 256 byte transfer to host BBE0 20 CB 04 JSR &04CB ;set up Tube data transfer BBE3 A0 00 LDY #&00 ;clear page offset BBE5 84 00 STY &00 ;align ROM pointer to page boundary .SBE7 BBE7 B1 00 LDA (&00),Y ;get byte from ROM BBE9 8D E5 FE STA &FEE5 ;write A to R3DATA BBEC EA NOP ;wait 3 microseconds BBED EA NOP BBEE EA NOP BBEF C8 INY ;increment offset BBF0 D0 F5 BNE SBE7 ;loop until page boundary reached (10us/byte) BBF2 E6 54 INC &54 ;then add 256 to Tube transfer address BBF4 D0 06 BNE SBFC ;carry out to 2MSB BBF6 E6 55 INC &55 BBF8 D0 02 BNE SBFC ;and MSB BBFA E6 56 INC &56 .SBFC BBFC E6 01 INC &01 ;increment MSB of ROM pointer BBFE 24 01 BIT &01 ;test b14 of ROM pointer BC00 50 DC BVC SBDE ;loop until b14=1, when it has reached &C000 BC02 20 D2 04 JSR &04D2 ;set up Tube destination address BC05 A9 04 LDA #&04 ;type byte = 4 no transfer, execute 2P code: ;04CB set up Tube data transfer BC07 A0 00 LDY #&00 ;point XY at Tube transfer address at &0053 BC09 A2 53 LDX #&53 BC0B 4C 06 04 JMP &0406 ;jump into Tube service. ;04D2 Set up Tube destination address BC0E A9 80 LDA #&80 BC10 85 54 STA &54 ;set 3MSB of Tube transfer address = &80 BC12 85 01 STA &01 ;set MSB of ROM pointer = &80 BC14 A9 20 LDA #&20 ;set b5=1 to test custom address flag BC16 2D 06 80 AND &8006 ;AND with ROM type byte BC19 A8 TAY ;place result in AY for MSB, 2MSB of addr BC1A 84 53 STY &53 ;store as LSB (on the assumption that it's 0) BC1C F0 19 BEQ SC37 ;if b5=0 then no custom addr, set &00008000 BC1E AE 07 80 LDX &8007 ;else get offset of copyright string .SC21 BC21 E8 INX ;skip leading NUL, increment offset BC22 BD 00 80 LDA &8000,X ;test character of copyright string BC25 D0 FA BNE SC21 ;loop until terminating NUL reached BC27 BD 01 80 LDA &8001,X ;store next byte as LSB of Tube address BC2A 85 53 STA &53 BC2C BD 02 80 LDA &8002,X ;store byte after that as 3MSB BC2F 85 54 STA &54 BC31 BC 03 80 LDY &8003,X ;get next byte as 2MSB BC34 BD 04 80 LDA &8004,X ;get byte after that as MSB: .SC37 BC37 85 56 STA &56 ;store MSB of Tube transfer address BC39 84 55 STY &55 ;store 2MSB of Tube transfer address BC3B 60 RTS ;0500 Tube call handler jump table (SB) BC3C EQUW &37,&05 ;R2 was &00 - jump osrdch_call BC3E EQUW &96,&05 ;R2 was &02 - jump oscli_call BC40 EQUW &F2,&05 ;R2 was &04 - jump short_osbyte BC42 EQUW &07,&06 ;R2 was &06 - jump long_osbyte BC44 EQUW &27,&06 ;R2 was &08 - jump osword_call BC46 EQUW &68,&06 ;R2 was &0A - jump osword0_call BC48 EQUW &5E,&05 ;R2 was &0C - jump osargs_call BC4A EQUW &2D,&05 ;R2 was &0E - jump osbget_call BC4C EQUW &20,&05 ;R2 was &10 - jump osbput_call BC4E EQUW &42,&05 ;R2 was &12 - jump osfind_call BC50 EQUW &A9,&05 ;R2 was &14 - jump osfile_call BC52 EQUW &D1,&05 ;R2 was &16 - jump osgbpb_call ;0518 Tube status settings for transfer types 0..7 BC54 EQUB &86 ;0=bytes to host J,I=1 enable IRQ on R4,R1 BC55 EQUB &88 ;1=bytes from host M=1 enable NMI on R3 BC56 EQUB &96 ;2=words to host V,J,I=1 enable IRQ on R4,R1 BC57 EQUB &98 ;3=words from host V,M=1 enable NMI on R3 BC58 EQUB &18 ;4=address only V,M=0 disable NMI on R3 BC59 EQUB &18 ;5=(reserved) V,M=0 disable NMI on R3 BC5A EQUB &82 ;6=page to host I=1 enable IRQ on R1 BC5B EQUB &18 ;7=page from host V,M=0 disable NMI on R3 ;osbput_call BC5C 20 C5 06 JSR &06C5 ;read R2DATA to A BC5F A8 TAY ;set Y=channel BC60 20 C5 06 JSR &06C5 ;read R2DATA to A =byte to write BC63 20 D4 FF JSR &FFD4 ;call OSBPUT BC66 4C 9C 05 JMP &059C ;signal completion ;osbget_call BC69 20 C5 06 JSR &06C5 ;read R2DATA to A BC6C A8 TAY ;set Y=channel BC6D 20 D7 FF JSR &FFD7 ;call OSBGET BC70 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;osrdch_call BC73 20 E0 FF JSR &FFE0 ;call OSRDCH ;053A send C, A to R2DATA and idle BC76 6A ROR A ;rotate C into A b7, save A b0 in C BC77 20 95 06 JSR &0695 ;write A to R2DATA BC7A 2A ROL A ;restore A on entry BC7B 4C 9E 05 JMP &059E ;write to R2DATA and idle ;osfind_call BC7E 20 C5 06 JSR &06C5 ;read R2DATA to A BC81 F0 0B BEQ SC8E ;if A=0 then close file BC83 48 PHA ;else save A=call no. = open mode BC84 20 82 05 JSR &0582 ;read string to buffer BC87 68 PLA ;restore A BC88 20 CE FF JSR &FFCE ;call OSFIND BC8B 4C 9E 05 JMP &059E ;write to R2DATA and idle .SC8E BC8E 20 C5 06 JSR &06C5 ;read R2DATA to A BC91 A8 TAY ;set Y=file handle BC92 A9 00 LDA #&00 ;restore A=0 call no. = close file BC94 20 CE FF JSR &FFCE ;call OSFIND BC97 4C 9C 05 JMP &059C ;signal completion ;osargs_call BC9A 20 C5 06 JSR &06C5 ;read R2DATA to A BC9D A8 TAY ;set Y=channel BC9E A2 04 LDX #&04 ;4 bytes to read: .SCA0 BCA0 20 C5 06 JSR &06C5 ;read R2DATA to A BCA3 95 FF STA &FF,X ;save in locations 3..0 BCA5 CA DEX ;in descending order BCA6 D0 F8 BNE SCA0 ;loop until X bytes read BCA8 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BCAB 20 DA FF JSR &FFDA ;call OSARGS BCAE 20 95 06 JSR &0695 ;write A to R2DATA =return value BCB1 A2 03 LDX #&03 ;4 bytes to write: .SCB3 BCB3 B5 00 LDA &00,X ;get locations 3..0 BCB5 20 95 06 JSR &0695 ;write A to R2DATA BCB8 CA DEX ;in descending order BCB9 10 F8 BPL SCB3 ;loop until X+1 bytes written BCBB 4C 36 00 JMP &0036 ;go to idle loop ;0582 read string to buffer BCBE A2 00 LDX #&00 ;set X=0 LSB of buffer address BCC0 A0 00 LDY #&00 ;set Y=0 buffer offset .SCC2 BCC2 20 C5 06 JSR &06C5 ;read R2DATA to A BCC5 99 00 07 STA &0700,Y ;save in string buffer BCC8 C8 INY ;in ascending order, increment offset BCC9 F0 04 BEQ SCCF ;if end of buffer reached then stop BCCB C9 0D CMP #&0D ;else test character read BCCD D0 F3 BNE SCC2 ;if =CR then string terminated else loop .SCCF BCCF A0 07 LDY #&07 ;set Y=&07 MSB of buffer address BCD1 60 RTS ;oscli_call BCD2 20 82 05 JSR &0582 ;read string to buffer BCD5 20 F7 FF JSR &FFF7 ;call OSCLI ;059C Signal completion BCD8 A9 7F LDA #&7F .SCDA ;059E Write to R2DATA and idle BCDA 2C E2 FE BIT &FEE2 ;test R2STAT BCDD 50 FB BVC SCDA ;loop until b6=1, not full BCDF 8D E3 FE STA &FEE3 ;write A to R2DATA .SCE2 BCE2 4C 36 00 JMP &0036 ;go to idle loop ;osfile_call BCE5 A2 10 LDX #&10 ;16 bytes to read: .SCE7 BCE7 20 C5 06 JSR &06C5 ;read R2DATA to A BCEA 95 01 STA &01,X ;save to locations 17..2 BCEC CA DEX ;in descending order BCED D0 F8 BNE SCE7 ;loop until X bytes read BCEF 20 82 05 JSR &0582 ;read string to buffer BCF2 86 00 STX &00 ;save buffer address at 0,1 BCF4 84 01 STY &01 ;=&0700 BCF6 A0 00 LDY #&00 ;set Y=0; X=0 from 0582 BCF8 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BCFB 20 DD FF JSR &FFDD ;call OSFILE BCFE 20 95 06 JSR &0695 ;write A to R2DATA =return value BD01 A2 10 LDX #&10 ;16 bytes to write: .SD03 BD03 B5 01 LDA &01,X ;get locations 17..2 BD05 20 95 06 JSR &0695 ;write A to R2DATA BD08 CA DEX ;in descending order BD09 D0 F8 BNE SD03 ;loop until X bytes written BD0B F0 D5 BEQ SCE2 ;then go to idle loop ;osgbpb_call BD0D A2 0D LDX #&0D ;13 bytes to read: .SD0F BD0F 20 C5 06 JSR &06C5 ;read R2DATA to A BD12 95 FF STA &FF,X ;save to locations 12..0 BD14 CA DEX ;in descending order BD15 D0 F8 BNE SD0F ;loop until X bytes read BD17 20 C5 06 JSR &06C5 ;read R2DATA to A BD1A A0 00 LDY #&00 ;set Y=0; X=0 from loop BD1C 20 D1 FF JSR &FFD1 ;call OSGBPB BD1F 48 PHA ;save return value BD20 A2 0C LDX #&0C ;13 bytes to write: .SD22 BD22 B5 00 LDA &00,X ;get locations 12..0 BD24 20 95 06 JSR &0695 ;write A to R2DATA BD27 CA DEX ;in descending order BD28 10 F8 BPL SD22 ;loop until X bytes written BD2A 68 PLA ;restore A=return value BD2B 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;short_osbyte BD2E 20 C5 06 JSR &06C5 ;read R2DATA to A BD31 AA TAX ;save X=first parameter BD32 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD35 20 F4 FF JSR &FFF4 ;call OSBYTE .SD38 BD38 2C E2 FE BIT &FEE2 ;test R2STAT BD3B 50 FB BVC SD38 ;loop until b6=1, not full BD3D 8E E3 FE STX &FEE3 ;write X to R2DATA =result .SD40 BD40 4C 36 00 JMP &0036 ;go to idle loop ;long_osbyte BD43 20 C5 06 JSR &06C5 ;read R2DATA to A BD46 AA TAX ;set X=first parameter BD47 20 C5 06 JSR &06C5 ;read R2DATA to A BD4A A8 TAY ;set Y=second parameter BD4B 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD4E 20 F4 FF JSR &FFF4 ;call OSBYTE BD51 49 9D EOR #&9D ;if A=&9D fast Tube BPUT BD53 F0 EB BEQ SD40 ;then end call without handshake BD55 6A ROR A ;else rotate C into A b7 BD56 20 95 06 JSR &0695 ;write A to R2DATA .SD59 BD59 2C E2 FE BIT &FEE2 ;test R2STAT BD5C 50 FB BVC SD59 ;loop until b6=1, not full BD5E 8C E3 FE STY &FEE3 ;write Y to R2DATA =second result BD61 70 D5 BVS SD38 ;write X to R2DATA and idle (always) ;osword_call BD63 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD66 A8 TAY ;hold in Y .SD67 BD67 2C E2 FE BIT &FEE2 ;test R2STAT BD6A 10 FB BPL SD67 ;loop until b7=1, data available BD6C AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD6F CA DEX ;decrement X BD70 30 0F BMI SD81 ;if X was not in range 1..128 then no bytes .SD72 BD72 2C E2 FE BIT &FEE2 ;else test R2STAT BD75 10 FB BPL SD72 ;loop until b7=1, data available BD77 AD E3 FE LDA &FEE3 ;read R2DATA to A BD7A 9D 28 01 STA &0128,X ;save to locations &0128+(X-1..0) BD7D CA DEX ;in descending order BD7E 10 F2 BPL SD72 ;loop until X bytes written BD80 98 TYA ;restore A=call number .SD81 BD81 A2 28 LDX #&28 ;point XY to OSWORD control block at &0128 BD83 A0 01 LDY #&01 BD85 20 F1 FF JSR &FFF1 ;call OSWORD .SD88 BD88 2C E2 FE BIT &FEE2 ;test R2STAT BD8B 10 FB BPL SD88 ;loop until b7=1, data available BD8D AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD90 CA DEX ;decrement X BD91 30 0E BMI SDA1 ;if X was not in range 1..128 then no bytes .SD93 BD93 BC 28 01 LDY &0128,X ;else get byte of control block at ..&0128 .SD96 BD96 2C E2 FE BIT &FEE2 ;test R2STAT BD99 50 FB BVC SD96 ;loop until b6=1, not full BD9B 8C E3 FE STY &FEE3 ;write Y to R2DATA BD9E CA DEX ;in descending order BD9F 10 F2 BPL SD93 ;loop until X bytes written .SDA1 BDA1 4C 36 00 JMP &0036 ;go to idle loop ;osword0_call BDA4 A2 04 LDX #&04 ;5 bytes to read: .SDA6 BDA6 20 C5 06 JSR &06C5 ;read R2DATA to A BDA9 95 00 STA &00,X ;save to locations 4..0 BDAB CA DEX ;in descending order BDAC 10 F8 BPL SDA6 ;loop until X+1 bytes read BDAE E8 INX ;set X=0 BDAF A0 00 LDY #&00 ;set Y=0; point XY to OSWORD control block BDB1 8A TXA ;set A=0 read line from input stream BDB2 20 F1 FF JSR &FFF1 ;call OSWORD BDB5 90 05 BCC SDBC ;if user pressed ESCAPE BDB7 A9 FF LDA #&FF ;then A=&FF carry set/error condition BDB9 4C 9E 05 JMP &059E ;write to R2DATA and idle .SDBC BDBC A2 00 LDX #&00 ;else X=0 offset into string buffer BDBE A9 7F LDA #&7F ;set A=&7F carry clear/no error BDC0 20 95 06 JSR &0695 ;write A to R2DATA .SDC3 BDC3 BD 00 07 LDA &0700,X ;get character from string buffer BDC6 20 95 06 JSR &0695 ;write A to R2DATA BDC9 E8 INX ;increment offset BDCA C9 0D CMP #&0D ;test character just written BDCC D0 F5 BNE SDC3 ;if =CR then string terminated else loop BDCE 4C 36 00 JMP &0036 ;go to idle loop .SDD1 ;0695 Write A to R2DATA BDD1 2C E2 FE BIT &FEE2 ;test R2STAT BDD4 50 FB BVC SDD1 ;loop until b6=1, not full BDD6 8D E3 FE STA &FEE3 ;write A to R2DATA BDD9 60 RTS .SDDA ;069E Write A to R4DATA BDDA 2C E6 FE BIT &FEE6 ;test R4STAT BDDD 50 FB BVC SDDA ;loop until b6=1, not full BDDF 8D E7 FE STA &FEE7 ;write A to R4DATA BDE2 60 RTS ;06A7 Copy ESCAPE flag to coprocessor (NAUG) BDE3 A5 FF LDA &FF ;get MOS ESCAPE flag BDE5 38 SEC ;rotate 1 into bit 7, ESCAPE flag in bit 6 BDE6 6A ROR A ;A >= &80 indicating ESCAPE flag update BDE7 30 0F BMI SDF8 ;write A to R1DATA (always) ;06AD Event handler BDE9 48 PHA ;save event type BDEA A9 00 LDA #&00 ;set A=&00 to indicate event BDEC 20 BC 06 JSR &06BC ;write A to R1DATA BDEF 98 TYA ;transfer Y=second event parameter to A BDF0 20 BC 06 JSR &06BC ;write A to R1DATA BDF3 8A TXA ;transfer X=first event parameter to A BDF4 20 BC 06 JSR &06BC ;write A to R1DATA BDF7 68 PLA ;restore event type to A: .SDF8 ;06BC Write A to R1DATA BDF8 2C E0 FE BIT &FEE0 ;test R1STAT BDFB 50 FB BVC SDF8 ;loop until b6=1, not full BDFD 8D E1 FE STA &FEE1 ;write A to R1DATA BE00 60 RTS .SE01 ;06C5 Read R2DATA to A BE01 2C E2 FE BIT &FEE2 ;test R2STAT BE04 10 FB BPL SE01 ;loop until b7=1, data available BE06 AD E3 FE LDA &FEE3 ;read R2DATA to A and return BE09 60 RTS .SE0A ;Print "COPYRIGHT NOTICE" BE0A 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE0D EQUB &83 ;yellow alphanumerics BE0E EQUB &8D ;double height BE0F EQUS " C O P Y R I G H T N O T I C E" BE2F EQUB &0D BE30 EQUB &0A BE31 EQUB &FF BE32 60 RTS ;*COPYRIGHT BE33 20 74 AD JSR RD74 ;set display MODE 7 BE36 20 67 84 JSR P467 ;print newline BE39 20 0A BE JSR SE0A ;print "COPYRIGHT NOTICE" twice BE3C 20 0A BE JSR SE0A BE3F 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE42 EQUB &0D BE43 EQUB &0A BE44 EQUB &0A BE45 EQUS "This Double Density Operating System" BE69 EQUB &0D BE6A EQUB &0A BE6B EQUS "was developed for the BBC computer by" BE90 EQUB &0D BE91 EQUB &0A BE92 EQUB &83 ;yellow alphanumerics BE93 EQUS "SLOGGER SOFTWARE and OPUS SUPPLIES" BEB5 EQUB &0D BEB6 EQUB &0A BEB7 EQUS "Any unauthorised copying of this" BED7 EQUB &0D BED8 EQUB &0A BED9 EQUS "product is unlawful and may result in" BEFE EQUB &0D BEFF EQUB &0A BF00 EQUS "Slogger or Opus taking appropriate" BF22 EQUB &0D BF23 EQUB &0A BF24 EQUS "action." BF2B EQUB &0D BF2C EQUB &0A BF2D EQUB &0A BF2E EQUB &FF BF2F 60 RTS BF80 EQUB &FF,&FF,&FF,&FF BF84 EQUB &FF,&FF,&FF,&FF BF88 EQUB &FF,&FF,&FF,&FF BF8C EQUB &FF,&FF,&FF,&FF BF90 EQUB &FF,&FF,&FF,&FF BF94 EQUB &FF,&FF,&FF,&FF BF98 EQUB &FF,&FF,&FF,&FF BF9C EQUB &FF,&FF,&FF,&FF BFA0 EQUB &FF,&FF,&FF,&FF BFA4 EQUB &FF,&FF,&FF,&FF BFA8 EQUB &FF,&FF,&FF,&FF BFAC EQUB &FF,&FF,&FF,&FF BFB0 EQUB &FF,&FF,&FF,&FF BFB4 EQUB &FF,&FF,&FF,&FF BFB8 EQUB &FF,&FF,&FF,&FF BFBC EQUB &FF,&FF,&FF,&FF BFC0 EQUB &FF,&FF,&FF,&FF BFC4 EQUB &FF,&FF,&FF,&FF BFC8 EQUB &FF,&FF,&FF,&FF BFCC EQUB &FF,&FF,&FF,&FF BFD0 EQUB &FF,&FF,&FF,&FF BFD4 EQUB &FF,&FF,&FF,&FF BFD8 EQUB &FF,&FF,&FF,&FF BFDC EQUB &FF,&FF,&FF,&FF BFE0 EQUB &FF,&FF,&FF,&FF BFE4 EQUB &FF,&FF,&FF,&FF BFE8 EQUB &FF,&FF,&FF,&FF BFEC EQUB &FF,&FF,&FF,&FF BFF0 EQUB &FF,&FF,&FF,&FF BFF4 EQUB &FF,&FF,&FF,&FF BFF8 EQUB &FF,&FF,&FF,&FF BFFC EQUB &FF,&FF,&FF,&FF #elif defined _DDOS336 ;////////////////////////////////////////////// DDOS 3.36 .S675 ;Test write protect state B675 20 3C B7 JSR S73C ;issue Seek and Force Interrupt B678 20 E0 B9 JSR S9E0 ;wait for command completion B67B 29 40 AND #&40 ;z=0 if WD2793 S6 = write protect. B67D 60 RTS ;[BUG] The recalibrate and seek routines raise the INTRQ pin which ;causes an NMI, but do not install code in the NMI service area. ;Any code left at the NMI entry point is executed. ;Typically there is an RTI instruction at &0D00 left by the MOS on ;reset, or by a previous NMI service routine that self-sealed. An FDC ;command that did not complete, however, leaves its ISR active and this ;services the NMI - mistreating the command completion interrupt as a ;data request - and interferes with the byte transfer count at &A0..1. ;A floppy disc operation performs a seek as a subtask after storing the ;count and before installing its service routine. It expects NMIs to be ;ignored in the meantime and because they are not, it goes on to ;transfer the wrong number of bytes. ;If re-entered, the RAM disc transfer code overwrites memory and crashes ;(original version; it is patched in this file under symbol _RAMBUGFIX.) ;Machines with Econet are also affected. ;Opus 2791/2793 board users (running DDOS 3.1x/3.3x) have their INTRQ ;pin disconnected from the NMI line and get off scot-free. .S67E ;Recalibrate drive (seek track 0) # if defined _TURBO B67E 20 2D A3 JSR R32D ;save XY # else B67E 20 29 A3 JSR R329 ;save XY # endif B681 A9 08 LDA #&08 ;WD2793 FDC command &00 = Restore # if defined _BUGFIX B683 20 F6 92 JSR Q2F6 ;execute command and wait for completion # else B683 20 BB B6 JSR S6BB ;execute command and wait for completion # endif B686 A5 CF LDA &CF ;get current volume B688 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B68A AA TAX ;transfer to X for use as index B68B A9 00 LDA #&00 ;set physical position of head to 0 B68D 9D 8C 10 STA &108C,X B690 60 RTS .S691 ;Seek logical track B691 A5 BA LDA &BA ;get logical track number B693 2C E0 10 BIT &10E0 ;test double-stepping flag B696 50 01 BVC S699 ;if b6=1 then double stepping is enabled B698 0A ASL A ;so double track number: .S699 ;Seek physical track B699 C9 00 CMP #&00 ;if track number = 0 B69B F0 E1 BEQ S67E ;then issue Restore command # if defined _TURBO B69D 20 2D A3 JSR R32D ;else save XY # else B69D 20 29 A3 JSR R329 ;else save XY # endif B6A0 48 PHA ;save target physical track B6A1 A5 CF LDA &CF ;get current volume B6A3 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B6A5 AA TAX ;transfer to X for use as index B6A6 BD 8C 10 LDA &108C,X ;get physical track number for drive B6A9 20 8F B9 JSR S98F ;store in track register of FDC B6AC 68 PLA ;restore target physical track B6AD 9D 8C 10 STA &108C,X ;store physical track number for drive B6B0 20 D4 B9 JSR S9D4 ;write to FDC data register B6B3 A9 18 LDA #&18 ;WD2793 FDC command &10 = Seek # if defined _BUGFIX B6B5 20 F6 92 JSR Q2F6 ;execute command and wait for completion # else B6B5 20 BB B6 JSR S6BB ;execute command and wait for completion # endif B6B8 29 10 AND #&10 ;z=0 if WD2793 S4 = record not found. B6BA 60 RTS .S6BB ;Execute Restore/Seek command B6BB 0D 8E 10 ORA &108E ;apply track stepping rate B6BE 20 CC B9 JSR S9CC ;write to FDC command register B6C1 4C E0 B9 JMP S9E0 ;wait for command completion and exit. .S6C4 ;Ensure disc is formatted B6C4 20 CD B6 JSR S6CD ;read ID and detect density B6C7 F0 03 BEQ S6CC ;if record found then exit B6C9 4C B5 B9 JMP S9B5 ;else raise "Disk not formatted" error. .S6CC B6CC 60 RTS ;[BUG]cannot force density, always tests both .S6CD ;Read ID and detect density # if defined _TURBO B6CD 20 2D A3 JSR R32D ;save XY # else B6CD 20 29 A3 JSR R329 ;save XY # endif B6D0 20 3C B7 JSR S73C ;issue Seek and Force Interrupt B6D3 A2 04 LDX #&04 ;4 attempts to make, 2 in each density: B6D5 2C E3 10 BIT &10E3 ;if current density is single B6D8 50 0F BVC S6E9 ;then attempt in single density first, else: .S6DA B6DA AD E3 10 LDA &10E3 ;get density flag B6DD 09 40 ORA #&40 ;set b6=1, double density B6DF A0 12 LDY #&12 ;18 sectors per track B6E1 20 0E B7 JSR S70E ;execute Read Address at specified density B6E4 F0 25 BEQ S70B ;if record found then return success B6E6 CA DEX ;else decrement number of attempts remaining B6E7 F0 0F BEQ S6F8 ;if run out of tries then return failure .S6E9 B6E9 AD E3 10 LDA &10E3 ;else get density flag B6EC 29 BF AND #&BF ;set b6=0, single density B6EE A0 0A LDY #&0A ;10 sectors per track B6F0 20 0E B7 JSR S70E ;execute Read Address at specified density B6F3 F0 16 BEQ S70B ;if record found then return success B6F5 CA DEX ;else decrement number of attempts remaining B6F6 D0 E2 BNE S6DA ;if attempts remaining try double density .S6F8 B6F8 AD E3 10 LDA &10E3 ;else set b6=0, single density B6FB 29 BF AND #&BF B6FD 8D E3 10 STA &10E3 B700 20 58 B6 JSR S658 ;set control latch for drive B703 A9 0A LDA #&0A ;set 10 sectors per track B705 8D E1 10 STA &10E1 B708 A9 18 LDA #&18 ;fake WD2793 S4 = record not found B70A 60 RTS ;fake WD2793 S3 = CRC error. .S70B B70B A9 00 LDA #&00 ;fake WD2793 status = 0, succeeded. B70D 60 RTS .S70E ;Execute Read Address at specified density B70E 8D E3 10 STA &10E3 ;store density flag B711 8C E1 10 STY &10E1 ;store number of sectors per track: .S714 ;Execute Read Address command B714 A0 14 LDY #&14 ;21 bytes to copy, &0D00..14: .S716 B716 B9 4E BA LDA &BA4E,Y ;get byte of NMI read ID B719 99 00 0D STA &0D00,Y ;store in NMI area B71C 88 DEY ;loop until all bytes copied B71D 10 F7 BPL S716 B71F A9 00 LDA #&00 ;initialise offset = 0 B721 85 A0 STA &A0 B723 20 58 B6 JSR S658 ;set control latch for drive B726 A9 C0 LDA #&C0 ;WD2793 command &C0 = Read address B728 20 CC B9 JSR S9CC ;write to FDC command register B72B 20 E0 B9 JSR S9E0 ;wait for command completion B72E 48 PHA ;save exit status B72F A0 03 LDY #&03 ;4 bytes to copy, &1090..3: .S731 B731 B9 90 10 LDA &1090,Y ;get CHRN byte of sector ID B734 99 02 10 STA &1002,Y ;copy to workspace B737 88 DEY ;loop until all bytes copied B738 10 F7 BPL S731 B73A 68 PLA ;restore Read Address command status and exit B73B 60 RTS .S73C ;Issue Seek and Force Interrupt B73C A9 18 LDA #&18 ;WD2793 command &18 = Seek w/spin up B73E 20 CC B9 JSR S9CC ;write to FDC command register B741 A2 0F LDX #&0F ;wait 38.5 microseconds .S743 B743 CA DEX B744 D0 FD BNE S743 .S746 B746 A9 D0 LDA #&D0 ;WD2793 command &D0 = Force interrupt B748 4C CC B9 JMP S9CC ;write to FDC command register and exit .S74B B74B 60 RTS .S74C ;Verify track # if defined _TURBO B74C 20 2D A3 JSR R32D ;save XY # else B74C 20 29 A3 JSR R329 ;save XY # endif B74F A9 00 LDA #&00 B751 85 BB STA &BB ;sector number = 0 B753 85 A0 STA &A0 ;whole number of sectors to transfer B755 AD E1 10 LDA &10E1 ;get number of sectors per track B758 85 A1 STA &A1 ;set number of sectors to transfer B75A A9 04 LDA #&04 ;set call number to &04, verify data B75C 8D 00 10 STA &1000 .S75F ;Transfer data to disc L2 # if defined _TURBO B75F 20 2D A3 JSR R32D ;save XY # else B75F 20 29 A3 JSR R329 ;save XY # endif B762 20 D6 A7 JSR R7D6 ;set up for current drive B765 20 91 B6 JSR S691 ;seek logical track ;[DIFF] no delay, status save or ;on-track verification B768 A5 BA LDA &BA ;get logical track number B76A 20 85 B9 JSR S985 ;store as 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 &B771. B76D 20 76 B7 JSR S776 ;execute floppy drive command L1 B770 48 PHA ;save masked status B771 20 7D B9 JSR S97D ;store head position for this drive B774 68 PLA ;restore masked status, setting Z B775 60 RTS ;and exit .S776 ;Execute floppy drive command L1 # if defined _TURBO B776 20 2D A3 JSR R32D ;save XY # else B776 20 29 A3 JSR R329 ;save XY # endif B779 A5 A0 LDA &A0 ;save ?&A0, ?&A1 on stack B77B 48 PHA B77C A5 A1 LDA &A1 B77E 48 PHA B77F 20 0E B8 JSR S80E ;copy NMI read from disc/polling loop to NMI B782 AD 01 10 LDA &1001 ;get *SROM slot number B785 8D 2D 0D STA &0D2D ;store in polling loop to page in on entry B788 A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 B78A F0 02 BEQ S78E ;not rounding up, converting number format; B78C E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .S78E B78E AD 00 10 LDA &1000 ;get data transfer call number B791 29 05 AND #&05 ;if call=0 or 2, read (deleted) data B793 F0 14 BEQ S7A9 ;then branch B795 6A ROR A ;else if b2..0 = 1x0, A=&04 verify data B796 B0 15 BCS S7AD B798 A9 4C LDA #&4C ;then instruction at &0D06 = JMP &0D11 B79A 8D 06 0D STA &0D06 ;discard byte from FDC data register B79D A9 11 LDA #&11 B79F 8D 07 0D STA &0D07 B7A2 A9 0D LDA #&0D B7A4 8D 08 0D STA &0D08 B7A7 D0 10 BNE S7B9 .S7A9 B7A9 A0 07 LDY #&07 ;if call=0 or 2, read (deleted) data B7AB D0 09 BNE S7B6 ;then data address is located at &0D07. .S7AD B7AD A9 00 LDA #&00 ;if b0=1, A=1 or 3 write (deleted) data B7AF 85 A0 STA &A0 ;then clear ?&A0, write whole sectors B7B1 20 1A B8 JSR S81A ;copy NMI write to disc to NMI area B7B4 A0 04 LDY #&04 ;data address is located at &0D04 .S7B6 B7B6 20 E4 B7 JSR S7E4 ;set data address in NMI ISR .S7B9 B7B9 A5 F4 LDA &F4 ;get DDOS ROM slot number B7BB 8D 3A 0D STA &0D3A ;save in NMI area B7BE A5 BB LDA &BB ;get start sector number B7C0 20 D0 B9 JSR S9D0 ;write to FDC sector register B7C3 AC 00 10 LDY &1000 ;get data transfer call number B7C6 B9 F7 B9 LDA &B9F7,Y ;get FDC command for call B7C9 20 CC B9 JSR S9CC ;write to FDC command register B7CC A2 1E LDX #&1E ;wait 76 microseconds .S7CE B7CE CA DEX B7CF D0 FD BNE S7CE B7D1 20 2C 0D JSR &0D2C ;page SROM in and wait until finished L0 B7D4 68 PLA ;restore ?&A0, ?&A1 from stack B7D5 85 A1 STA &A1 B7D7 68 PLA B7D8 85 A0 STA &A0 B7DA 20 F0 B9 JSR S9F0 ;load FDC status register and store b6..0 B7DD AC 00 10 LDY &1000 B7E0 39 FC B9 AND &B9FC,Y ;apply status mask from table to set Z. B7E3 60 RTS .S7E4 ;Set data address in NMI ISR B7E4 AD D5 10 LDA &10D5 ;test Tube data transfer flag B7E7 F0 1A BEQ S803 ;if transferring data to Tube B7E9 A9 E5 LDA #&E5 ;then paste address of R3DATA at &0D00+Y B7EB 99 00 0D STA &0D00,Y B7EE A9 FE LDA #&FE B7F0 99 01 0D STA &0D01,Y B7F3 A9 4C LDA #&4C ;instruction at &0D09 = JMP &0D11 B7F5 8D 09 0D STA &0D09 ;do not increment R3DATA address B7F8 A9 11 LDA #&11 B7FA 8D 0A 0D STA &0D0A B7FD A9 0D LDA #&0D B7FF 8D 0B 0D STA &0D0B B802 60 RTS .S803 B803 A5 A6 LDA &A6 ;else copy data pointer to NMI ISR at &0D00+Y B805 99 00 0D STA &0D00,Y B808 A5 A7 LDA &A7 B80A 99 01 0D STA &0D01,Y B80D 60 RTS .S80E ;Copy NMI read from disc/polling loop to NMI B80E A0 3E LDY #&3E ;63 bytes to copy, &0D00..3E [DIFF]: .S810 B810 B9 01 BA LDA &BA01,Y ;get byte of NMI read from disc/polling loop B813 99 00 0D STA &0D00,Y B816 88 DEY ;store in NMI area B817 10 F7 BPL S810 ;loop until all bytes copied B819 60 RTS .S81A ;Copy NMI write to disc to NMI area B81A A0 0D LDY #&0D ;14 bytes to copy, &0D03..10: .S81C B81C B9 40 BA LDA &BA40,Y ;get byte of NMI write to disc B81F 99 03 0D STA &0D03,Y ;patch NMI read to disc routine with it B822 88 DEY ;loop until all bytes copied B823 10 F7 BPL S81C B825 A9 FC LDA #&FC ;enable 123 microsecond delay B827 8D 23 0D STA &0D23 ;before interrupting write operation B82A 60 RTS ;so that FDC will write CRC of sector .S82B ;Create ID table and format track B82B A9 0A LDA #&0A ;set A = 10 sectors per track B82D 2C E3 10 BIT &10E3 ;if double density format B830 50 02 BVC S834 B832 A9 12 LDA #&12 ;then set A = 18 sectors per track .S834 B834 85 A6 STA &A6 ;store as limit to sector count B836 0A ASL A ;multiply by 4 B837 0A ASL A B838 85 A7 STA &A7 ;store as size of CHRN table B83A A6 BB LDX &BB ;set X = number of first sector B83C A0 00 LDY #&00 ;(inverse track skew) Y=0 CHRN tbl index .S83E B83E A5 BA LDA &BA ;Get logical track number B840 99 A0 11 STA &11A0,Y ;store cylinder number C B843 C8 INY B844 A9 00 LDA #&00 ;head number = 0 B846 99 A0 11 STA &11A0,Y ;store head humber H B849 C8 INY B84A 8A TXA ;transfer sector number to A B84B 99 A0 11 STA &11A0,Y ;store record number R B84E C8 INY B84F A9 01 LDA #&01 ;size code = 1, 256-byte sector B851 99 A0 11 STA &11A0,Y ;store size code N B854 C8 INY B855 E8 INX ;increment sector number B856 E4 A6 CPX &A6 ;has it reached no. sectors per track? B858 90 02 BCC S85C B85A A2 00 LDX #&00 ;if so then wrap around to 0 .S85C B85C C4 A7 CPY &A7 ;has table offset reached 4x s.p.t? B85E 90 DE BCC S83E ;if not then loop B860 A9 A0 LDA #&A0 ;else set pointer to start of CHRN table: B862 85 A6 STA &A6 B864 A9 11 LDA #&11 B866 85 A7 STA &A7 .S868 ;Format track B868 A9 12 LDA #&12 ;set data table pointer to &1312 B86A 85 A2 STA &A2 ;(page break occurs 1/8 of the way through B86C 85 A4 STA &A4 ;the 11th sector of the track.) B86E A9 13 LDA #&13 B870 85 A3 STA &A3 B872 A9 15 LDA #&15 ;set run table pointer to &1512 B874 85 A5 STA &A5 B876 A2 00 LDX #&00 ;point to single density table, X = &00 B878 2C E3 10 BIT &10E3 ;if double density format B87B 50 02 BVC S87F B87D A2 23 LDX #&23 ;then point to double density table, X = &23 .S87F B87F A0 05 LDY #&05 ;set Y = 5 as counter: .S881 B881 20 C2 B8 JSR S8C2 ;add entry to track format RLE table B884 88 DEY ;loop until 5 entries added B885 D0 FA BNE S881 ;this copies gap 5, IDAM and start of gap 1 B887 A0 0A LDY #&0A ;set Y = 10 sectors per track B889 2C E3 10 BIT &10E3 ;if double density format B88C 50 02 BVC S890 B88E A0 12 LDY #&12 ;then Y = 18 sectors per track .S890 B890 8A TXA ;X points to repeating sector block B891 48 PHA ;save it .S892 B892 20 C2 B8 JSR S8C2 ;add entry to track format RLE table B895 90 FB BCC S892 ;loop until terminator byte reached B897 68 PLA ;reset X to start of sector block B898 AA TAX B899 88 DEY ;decrement number of sectors remaining B89A D0 F4 BNE S890 ;loop until all sectors added to track B89C A9 00 LDA #&00 ;data byte = &00 (run length = &10 or &16) B89E 20 15 B9 JSR S915 ;add gap 4 to table B8A1 20 91 B6 JSR S691 ;seek logical track B8A4 A9 0F LDA #&0F ;A = &0F (or just do LDY &1512:DEY:STY &A0!) B8A6 2C E3 10 BIT &10E3 ;if double density format B8A9 50 02 BVC S8AD B8AB A9 27 LDA #&27 ;then A = &27 .S8AD B8AD 85 A0 STA &A0 ;set number of filler bytes in gap 5 (- 1) B8AF A0 23 LDY #&23 ;36 bytes to copy, &0D00..23: .S8B1 B8B1 B9 63 BA LDA &BA63,Y ;get byte of NMI format code B8B4 99 00 0D STA &0D00,Y ;store in NMI handler area B8B7 88 DEY ;loop until all bytes transferred B8B8 10 F7 BPL S8B1 B8BA A9 F4 LDA #&F4 ;&F4=Write track, settling delay B8BC 20 CC B9 JSR S9CC ;write to FDC command register B8BF 4C E0 B9 JMP S9E0 ;wait for command completion and exit. .S8C2 ;Add entry to track format RLE table B8C2 8A TXA ;save ROM table offset B8C3 48 PHA B8C4 98 TYA ;save number of sectors remaining B8C5 48 PHA B8C6 A0 00 LDY #&00 ;y=&00, unused B8C8 38 SEC B8C9 BD 33 B9 LDA &B933,X ;get run length from ROM table B8CC 30 12 BMI S8E0 ;if b7=1 then process special entry B8CE F0 09 BEQ S8D9 ;if the terminator byte then finish C=1 B8D0 85 A0 STA &A0 ;else store run length in zero page B8D2 BD 34 B9 LDA &B934,X ;get data byte from ROM table B8D5 20 15 B9 JSR S915 ;store run in table .S8D8 B8D8 18 CLC ;c=0, sector not completed .S8D9 B8D9 68 PLA ;restore number of sectors remaining B8DA A8 TAY B8DB 68 PLA ;restore ROM table offset B8DC AA TAX B8DD E8 INX ;add 2 to ROM table offset B8DE E8 INX B8DF 60 RTS .S8E0 ;Process special table entry (length=&FF) B8E0 BD 34 B9 LDA &B934,X ;get data byte from ROM format table B8E3 D0 1C BNE S901 ;if non-zero then add sector data area B8E5 A9 01 LDA #&01 ;else add ID bytes. run length of bytes = 1 B8E7 85 A0 STA &A0 ;store run length in zero page B8E9 A2 04 LDX #&04 ;4 bytes in sector ID: .S8EB B8EB A0 00 LDY #&00 ;y=0 for user memory load B8ED 20 15 9E JSR QE15 ;get data byte from user memory B8F0 20 15 B9 JSR S915 ;store run in table B8F3 E6 A6 INC &A6 ;increment CHRN table pointer B8F5 D0 02 BNE S8F9 ;carry out to high byte B8F7 E6 A7 INC &A7 .S8F9 B8F9 CA DEX ;loop until 4 ID bytes stored B8FA D0 EF BNE S8EB B8FC 85 A1 STA &A1 ;store last byte read = N = size code B8FE 4C D8 B8 JMP S8D8 ;restore XY and return .S901 ;Add sector data area B901 A6 A1 LDX &A1 ;load sector size code B903 BD 79 B9 LDA &B979,X ;get run length from table B906 85 A0 STA &A0 ;store in zero page B908 A2 08 LDX #&08 ;repeat prescribed run 8 times: .S90A B90A A9 E5 LDA #&E5 ;A=&E5 = sector filler byte B90C 20 15 B9 JSR S915 ;store run in table B90F CA DEX ;loop until 8 copies of run stored B910 D0 F8 BNE S90A B912 4C D8 B8 JMP S8D8 ;restore XY and return .S915 ;Store run in table B915 A0 00 LDY #&00 ;offset = 0 for indirect indexed store B917 91 A2 STA (&A2),Y ;store data byte in data table B919 A5 A0 LDA &A0 ;get run length B91B 91 A4 STA (&A4),Y ;store run length in run table B91D C6 A4 DEC &A4 ;if pointers are on a page boundary B91F E6 A4 INC &A4 B921 D0 05 BNE S928 B923 38 SEC ;then subtract 1 from run length B924 E9 01 SBC #&01 B926 91 A4 STA (&A4),Y .S928 B928 E6 A2 INC &A2 ;increment data table pointer B92A E6 A4 INC &A4 ;increment run table pointer B92C D0 04 BNE S932 ;carry out to high bytes B92E E6 A3 INC &A3 B930 E6 A5 INC &A5 .S932 B932 60 RTS ;RLE tables of formatting bytes ;Single density B933 EQUB &10,&FF ; 16x &FF filler bytes } Gap 5 B935 EQUB &03,&00 ; 6x &00 synchronization bytes } B937 EQUB &03,&00 B939 EQUB &01,&FC ; 1x &FC index address mark (clock &D7) B93B EQUB &0B,&FF ; 11x &FF filler bytes } Gap 1 ;block repeated for each sector B93D EQUB &03,&00 ; 6x &00 synchronization bytes } B93F EQUB &03,&00 B941 EQUB &01,&FE ; 1x &FE ID address mark (clock &C7) B943 EQUB &FF,&00 ;id bytes are inserted here B945 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B947 EQUB &0B,&FF ; 11x &FF filler bytes } Gap 2 B949 EQUB &03,&00 ; 6x &00 synchronization bytes } B94B EQUB &03,&00 B94D EQUB &01,&FB ; 1x &FB data address mark (clock &C7) B94F EQUB &FF,&01 ;data bytes are inserted here B951 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B953 EQUB &10,&FF ; 16x &FF filler bytes } Gap 3... ;end of repeated block B955 EQUB &00 ;terminator byte (not part of format) ;Double density B956 EQUB &28,&4E ; 40x &4E filler bytes } B958 EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 5 B95A EQUB &03,&F6 ; 3x &F6 synchronization bytes } B95C EQUB &01,&FC ; 1x &FC index address mark B95E EQUB &19,&4E ; 25x &4E filler bytes } Gap 1 ;block repeated for each sector B960 EQUB &0C,&00 ; 12x &00 preamble bytes } B962 EQUB &03,&F5 ; 3x &F5 synchronization bytes } B964 EQUB &01,&FE ; 1x &FE ID address mark B966 EQUB &FF,&00 ;id bytes are inserted here B968 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B96A EQUB &16,&4E ; 22x &4E filler bytes } B96C EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 2 B96E EQUB &03,&F5 ; 3x &F5 synchronization bytes } B970 EQUB &01,&FB ; 1x &FB data address mark B972 EQUB &FF,&01 ;data bytes are inserted here B974 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B976 EQUB &16,&4E ; 22x &4E filler bytes } Gap 3... ;end of repeated block B978 EQUB &00 ;terminator byte (not part of format) B979 EQUB &10 ;8x runs of 16 bytes for 128-byte sectors B97A EQUB &20 ;8x runs of 32 bytes for 256-byte sectors B97B EQUB &40 ;8x runs of 64 bytes for 512-byte sectors B97C EQUB &80 ;8x runs of 128 bytes for 1024-byte sectors .S97D ;Store per-drive head position B97D A5 BA LDA &BA ;get logical track number of disc operation B97F 2C E0 10 BIT &10E0 ;test double-stepping flag B982 50 01 BVC S985 ;if b6=1 then double stepping is enabled B984 0A ASL A ;so double track number: .S985 ;Store physical position of head B985 48 PHA B986 A5 CF LDA &CF ;get current volume B988 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B98A AA TAX ;transfer to X for use as index B98B 68 PLA ;get back A B98C 9D 8C 10 STA &108C,X ;store physical track number for drive .S98F B98F 8D 81 FE STA &FE81 ;store in track register of FDC B992 60 RTS .S993 B993 20 47 A3 JSR R347 B996 EQUB &C5 B997 EQUS " fault" B99D EQUB &00 ;unreachable code B99E 20 62 A3 JSR R362 B9A1 EQUB &C5 B9A2 EQUS "Cannot recalibrate" B9B4 EQUB &00 .S9B5 B9B5 20 62 A3 JSR R362 B9B8 EQUB &C5 B9B9 EQUS "Disk not formatted" B9CB EQUB &00 .S9CC ;Write to FDC command register B9CC 8D 80 FE STA &FE80 B9CF 60 RTS .S9D0 ;Write to FDC sector register B9D0 8D 82 FE STA &FE82 B9D3 60 RTS .S9D4 ;Write to FDC data register B9D4 8D 83 FE STA &FE83 B9D7 60 RTS .S9D8 ;Load FDC status register B9D8 AD 80 FE LDA &FE80 B9DB 29 80 AND #&80 ;mask b7 extract WD2793 S7 = not ready B9DD 49 80 EOR #&80 ;return A=0, Z=1 iff drive ready [DIFF] B9DF 60 RTS .S9E0 # if defined _TURBO B9E0 20 2D A3 JSR R32D ;save XY # else B9E0 20 29 A3 JSR R329 ;save XY # endif B9E3 A2 FF LDX #&FF ;wait 638 microseconds .S9E5 B9E5 CA DEX B9E6 D0 FD BNE S9E5 .S9E8 B9E8 20 F0 B9 JSR S9F0 ;load FDC status register [DIFF] inverted B9EB 30 FB BMI S9E8 ;[DIFF] loop until b7=0 WD2793 S7 = not rdy B9ED 6A ROR A ;place bit 0 in carry flag B9EE B0 F8 BCS S9E8 ;loop until b0=0 WD2793 S0 = busy .S9F0 B9F0 AD 80 FE LDA &FE80 ;load FDC status register B9F3 8D 8F 10 STA &108F ;[DIFF] keep WD2793 S7 = not rdy B9F6 60 RTS ;save final status ;Table of WD2791 FDC commands for data transfer call numbers 0..4 B9F7 EQUB &90 ;&00 = Read data B9F8 EQUB &B4 ;&01 = Write data B9F9 EQUB &90 B9FA EQUB &B5 ;&03 = Write deleted data B9FB EQUB &90 ;&04 = Verify data ;Table of status mask bytes for data transfer call numbers 0..4 ;{RecordNotFound CRCError LostData} (&1C) plus: B9FC EQUB &3C ;&00 = Read data: {RecordType} B9FD EQUB &7C ;&01 = Write data: {WriteProtect RecordType} B9FE EQUB &1C ;{} B9FF EQUB &5C ;&03 = Write deleted data: {WriteProtect} BA00 EQUB &3C ;&04 = Verify data: {RecordType} ;NMI read from disc, &0D00..2F [DIFF] ;opcode read 4+e..8 microseconds after NMI ;(up to 13.5 us if code running in 1 MHz mem) BA01 8D 2A 0D STA &0D2A ;save accumulator to restore on exit BA04 AD 83 FE LDA &FE83 ;read FDC data register BA07 8D FF FF STA &FFFF ;store in user memory or R3DATA BA0A EE 07 0D INC &0D07 ;increment user memory address BA0D D0 03 BNE SA12 ;carry out to high byte BA0F EE 08 0D INC &0D08 .SA12 BA12 C6 A0 DEC &A0 ;decrement count of bytes to transfer BA14 D0 14 BNE SA2A ;(&0101 = 1; &0000 = 0) BA16 C6 A1 DEC &A1 ;if count has not reached zero BA18 D0 10 BNE SA2A ;then restore A and return from interrupt BA1A A9 40 LDA #&40 ;else set 0D00=RTI; ignore further NMIs BA1C 8D 00 0D STA &0D00 ;ISR safe by 22+e..29.5 us after NMI BA1F A9 CE LDA #&CE ;write complete by 24.5+e..32 us BA21 69 01 ADC #&01 ;wait 123 microseconds (if loop enabled) BA23 90 00 BCC SA25 ;0D23=&FC loops back to &0D20 .SA25 BA25 A9 D0 LDA #&D0 ;FDC command &D0 = Force Interrupt BA27 8D 80 FE STA &FE80 ;write to FDC command register .SA2A BA2A A9 00 LDA #&00 ;restore value of A on entry BA2C 40 RTI ;return from interrupt ;NMI polling loop, &0D30..42 [DIFF] BA2D A9 0E LDA #&0E ;page *SROM slot in BA2F 8D 30 FE STA &FE30 .SA32 BA32 AD 80 FE LDA &FE80 ;load FDC status register BA35 30 FB BMI SA32 ;[DIFF] loop until b7=0 WD2793 S7 = not ready BA37 6A ROR A ;place bit 0 in carry flag BA38 B0 F8 BCS SA32 ;[DIFF] loop until b0=0 WD2793 S0 = busy BA3A A9 00 LDA #&00 ;page DDOS ROM back in BA3C 8D 30 FE STA &FE30 BA3F 60 RTS ;NMI write to disc, &0D03..12 [DIFF] BA40 AD FF FF LDA &FFFF BA43 8D 83 FE STA &FE83 BA46 EE 04 0D INC &0D04 BA49 D0 03 BNE SA4E BA4B EE 05 0D INC &0D05 .SA4E BA4E 8D 13 0D STA &0D13 ;NMI read ID, &0D00..16 [DIFF] BA51 8C 11 0D STY &0D11 ;save AY to restore on exit BA54 A4 A0 LDY &A0 ;load offset in Y BA56 AD 83 FE LDA &FE83 ;load FDC data register BA59 99 90 10 STA &1090,Y ;store ID byte in buffer BA5C E6 A0 INC &A0 ;increment offset BA5E A0 00 LDY #&00 ;restore AY on entry BA60 A9 00 LDA #&00 BA62 40 RTI ;A run-length encoded table of formatting bytes is stored in two arrays ;starting at &1312 and &1512. Valid range of counts is &01..&80. ;When the byte source address crosses a page, the high byte is incremented ;in the same interrupt and the new count is fetched (from the next page) ;in the next interrupt. One byte from the next page is sent to the ;controller in the meantime, and so the first count of a page is one less ;than the number of bytes actually sent, i.e. the first byte of the page ;cannot be a singleton. The page crossing occurs 1/8th of the way through ;the data area of the eleventh sector after the index pulse. BA63 48 PHA ;NMI format, &0D00..23 BA64 AD 12 13 LDA &1312 ;save A on entry, fetch current data byte BA67 8D 83 FE STA &FE83 ;write to FDC data register BA6A C6 A0 DEC &A0 ;decrement run counter BA6C D0 0A BNE SA78 ;if all bytes in run written BA6E EE 02 0D INC &0D02 ;then increment data byte address low BA71 D0 0A BNE SA7D ;if no carry then fetch next run length BA73 EE 03 0D INC &0D03 ;else increment data byte address high .SA76 BA76 68 PLA ;restore A on entry BA77 40 RTI ;exit .SA78 BA78 10 FC BPL SA76 ;if run still in progress then exit BA7A EE 1F 0D INC &0D1F ;else page was crossed last time: .SA7D BA7D EE 1E 0D INC &0D1E ;increment run length address BA80 AD 12 15 LDA &1512 ;fetch next run length BA83 85 A0 STA &A0 ;set run counter BA85 68 PLA ;restore A on entry BA86 40 RTI ;exit ;unreachable code BA87 EA NOP ;Tube hosting .SA88 ;Service calls &FE, &FF BA88 C9 FE CMP #&FE ;is service call number <&FE? BA8A 90 5C BCC SAE8 ;if so then return to process other calls BA8C D0 1B BNE SAA9 ;if A=&FF then branch to do main init, else: BA8E C0 00 CPY #&00 ;Service call &FE = Tube post initialisation BA90 F0 56 BEQ SAE8 ;ignore call if Y=0 on entry BA92 A2 06 LDX #&06 ;else X=6 = fully exploded BA94 A9 14 LDA #&14 ;OSBYTE &14 = explode soft character RAM BA96 20 F4 FF JSR &FFF4 ;call OSBYTE .SA99 BA99 2C E0 FE BIT &FEE0 ;print Tube coprocessor banner: BA9C 10 FB BPL SA99 ;poll until character in R1DATA BA9E AD E1 FE LDA &FEE1 ;then read R1DATA BAA1 F0 43 BEQ SAE6 ;if =NUL then claim service call and exit BAA3 20 EE FF JSR &FFEE ;else print the character & loop BAA6 4C 99 BA JMP SA99 .SAA9 ;Service call &FF = Tube main initialisation BAA9 A9 AD LDA #&AD ;EVNTV = &06AD BAAB 8D 20 02 STA &0220 BAAE A9 06 LDA #&06 BAB0 8D 21 02 STA &0221 BAB3 A9 16 LDA #&16 ;BRKV = &0016 BAB5 8D 02 02 STA &0202 BAB8 A9 00 LDA #&00 BABA 8D 03 02 STA &0203 BABD A9 8E LDA #&8E ;set Tube status (NAUG p.329) BABF 8D E0 FE STA &FEE0 ;enable NMI on R3, IRQ on R1,R4 BAC2 A0 00 LDY #&00 ;initialise offset to 0: .SAC4 BAC4 B9 2A BB LDA &BB2A,Y ;copy Tube host code from &BB2A..&BE29 BAC7 99 00 04 STA &0400,Y ;to &0400..&06FF BACA B9 2A BC LDA &BC2A,Y ;offset 0 first, then 255..1 BACD 99 00 05 STA &0500,Y BAD0 B9 2A BD LDA &BD2A,Y BAD3 99 00 06 STA &0600,Y BAD6 88 DEY BAD7 D0 EB BNE SAC4 BAD9 20 21 04 JSR &0421 ;mark Tube unclaimed BADC A2 60 LDX #&60 ;initialise offset to &60 .SADE BADE BD E9 BA LDA &BAE9,X ;copy Tube BRK handler from &BAE9..49 BAE1 95 16 STA &16,X ;to &0016..76 BAE3 CA DEX BAE4 10 F8 BPL SADE .SAE6 BAE6 A9 00 LDA #&00 ;return A=0 to claim service call .SAE8 BAE8 60 RTS ;Tube BRK handler copied to &0016..76 BAE9 A9 FF LDA #&FF ;set A=&FF to interrupt coprocessor (JGH) BAEB 20 9E 06 JSR &069E ;write A to R4DATA BAEE AD E3 FE LDA &FEE3 ;empty inward R2DATA and discard byte BAF1 A9 00 LDA #&00 ;set A=0 to specify error (JGH) BAF3 20 95 06 JSR &0695 ;write A to R2DATA BAF6 A8 TAY ;set Y=0 offset into error message BAF7 B1 FD LDA (&FD),Y ;get error number at MOS error pointer BAF9 20 95 06 JSR &0695 ;write A to R2DATA .SAFC BAFC C8 INY ;increment offset BAFD B1 FD LDA (&FD),Y ;get character of error message BAFF 20 95 06 JSR &0695 ;write A to R2DATA BB02 AA TAX ;test last character written BB03 D0 F7 BNE SAFC ;loop until it is NUL BB05 A2 FF LDX #&FF ;reset stack pointer BB07 9A TXS BB08 58 CLI ;enable interrupts: .SB09 ;0036 Idle loop BB09 2C E0 FE BIT &FEE0 ;test R1STAT BB0C 10 06 BPL SB14 ;if b7=1, data available .SB0E BB0E AD E1 FE LDA &FEE1 ;then read R1DATA to A BB11 20 EE FF JSR &FFEE ;call OSWRCH. .SB14 BB14 2C E2 FE BIT &FEE2 ;test R2STAT BB17 10 F0 BPL SB09 ;if b7=0, data not available then test R1 BB19 2C E0 FE BIT &FEE0 ;else Tube call waiting. test R1STAT BB1C 30 F0 BMI SB0E ;first print waiting bytes to OSWRCH (if any) BB1E AE E3 FE LDX &FEE3 ;then read R2DATA to X =call number BB21 86 51 STX &51 ;modify LSB indirect address of next inst. BB23 6C 00 05 JMP (&0500) ;0050 handle Tube call via jump table ;Default Tube entry address = &00008000 BB26 EQUB &00 BB27 EQUB &80 BB28 EQUB &00 BB29 EQUB &00 ;Tube host code copied to &0400..&06FF ;0400 Copy language to coprocessor (NAUG) BB2A 4C 84 04 JMP &0484 ;0403 Copy ESCAPE flag to coprocessor (NAUG) BB2D 4C A7 06 JMP &06A7 ;0406 Tube service entry BB30 C9 80 CMP #&80 ;if A = &00..7F BB32 90 2B BCC SB5F ;then set up data transfer BB34 C9 C0 CMP #&C0 ;else if A = &C0..FF BB36 B0 1A BCS SB52 ;then handle Tube claim BB38 09 40 ORA #&40 ;else A=&80..BF release Tube BB3A C5 15 CMP &15 ;set b6=1 to compare with claimant ID BB3C D0 20 BNE SB5E ;if releaser is not claimant then ignore else: ;0414 Release Tube BB3E 08 PHP ;save interrupt state BB3F 78 SEI ;disable interrupts BB40 A9 05 LDA #&05 ;type byte=5 No transfer (FS release) BB42 20 9E 06 JSR &069E ;write A to R4DATA BB45 A5 15 LDA &15 ;set A=claimant ID BB47 20 9E 06 JSR &069E ;write A to R4DATA BB4A 28 PLP ;restore interrupt state: BB4B A9 80 LDA #&80 ;0421 Mark Tube unclaimed BB4D 85 15 STA &15 ;not in range &C0..FF =no claimant BB4F 85 14 STA &14 ;&80=Tube unclaimed BB51 60 RTS .SB52 ;0428 Claim Tube BB52 06 14 ASL &14 ;&00=Tube claimed BB54 B0 06 BCS SB5C ;if it was unclaimed then set claimant BB56 C5 15 CMP &15 ;else compare caller's ID - current claimant BB58 F0 04 BEQ SB5E ;if same claimant reclaims then return C=1 BB5A 18 CLC ;else reject claim, return C=0 BB5B 60 RTS .SB5C BB5C 85 15 STA &15 ;set current claimant, C=1 claim granted .SB5E BB5E 60 RTS .SB5F ;0435 Set up data transfer BB5F 08 PHP ;save interrupt state BB60 78 SEI ;disable interrupts BB61 84 13 STY &13 ;set control block pointer from XY BB63 86 12 STX &12 ;a=type byte/reason code BB65 20 9E 06 JSR &069E ;write A to R4DATA BB68 AA TAX ;hold type byte in X BB69 A0 03 LDY #&03 ;1+4 bytes to write BB6B A5 15 LDA &15 ;set A=claimant ID BB6D 20 9E 06 JSR &069E ;write A to R4DATA: .SB70 BB70 B1 12 LDA (&12),Y ;get byte of transfer address, MSB to LSB BB72 20 9E 06 JSR &069E ;write A to R4DATA BB75 88 DEY ;in descending/big-endian order BB76 10 F8 BPL SB70 ;loop until claimant+4 address bytes written BB78 A0 18 LDY #&18 ;set Tube status (NAUG p.329) BB7A 8C E0 FE STY &FEE0 ;set V,M=0 disable NMI and word mode on R3 BB7D BD 18 05 LDA &0518,X ;get status setting for transfer type in X BB80 8D E0 FE STA &FEE0 ;write to R1STAT BB83 4A LSR A ;test I in bit 1 = modify interrupts on R1 BB84 4A LSR A ;(if I was modified, then I was set) BB85 90 06 BCC SB8D ;if interrupts were enabled on R1 BB87 2C E5 FE BIT &FEE5 ;then transferring to host (C=1, used later) BB8A 2C E5 FE BIT &FEE5 ;discard word in R3 to empty it .SB8D BB8D 20 9E 06 JSR &069E ;write A to R4DATA = synchronising byte .SB90 BB90 2C E6 FE BIT &FEE6 ;wait for it to be taken; test R4STAT BB93 50 FB BVC SB90 ;loop until b6=1, not full BB95 B0 0D BCS SBA4 ;if transferring to host then branch BB97 E0 04 CPX #&04 ;else if type<>4 address only BB99 D0 11 BNE SBAC ;then return without handshake, else: .SB9B ;0471 Release Tube with handshake BB9B 20 14 04 JSR &0414 ;release Tube BB9E 20 95 06 JSR &0695 ;write A to R2DATA =&80 =transfer complete ;This value is used by code implementing OSCLI on the coprocessor to decide ;whether to return to the user or to jump to code at the type 4 transfer ;address. This call does not return. If the *command is not a binary to ;download to the coprocessor, DDOS's OSCLI code returns to the MOS which in ;turn exits to &059C (&BCC6), and there &7F is written to R2DATA indicating ;command completion. If that value is the first to arrive, it means there was ;no type 4 transfer address issued, and the coprocessor's OSCLI returns. BBA1 4C 32 00 JMP &0032 ;go to idle loop .SBA4 BBA4 4A LSR A ;test J in bit 2 = modify interrupts on R4 BBA5 90 05 BCC SBAC ;if J=1, types 0 or 2, bytes/words to host BBA7 A0 88 LDY #&88 BBA9 8C E0 FE STY &FEE0 ;then set M=1 enable NMIs on R3 .SBAC BBAC 28 PLP ;restore interrupt state BBAD 60 RTS ;0484 Copy language to coprocessor (NAUG) BBAE 58 CLI ;enable interrupts BBAF B0 11 BCS SBC2 ;if C=1, entry from *FX142 (JGH) then copy BBB1 D0 03 BNE SBB6 ;else if A>0 then enter language (JGH) BBB3 4C 9C 05 JMP &059C ;else A=0 no language, signal completion .SBB6 BBB6 A2 00 LDX #&00 ;set X=&00 do not alter BBB8 A0 FF LDY #&FF ;set Y=&FF do not update BBBA A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset BBBC 20 F4 FF JSR &FFF4 ;call OSBYTE BBBF 8A TXA ;if type = 0 soft BREAK BBC0 F0 D9 BEQ SB9B ;then release Tube and write &80 to R2DATA .SBC2 BBC2 A9 FF LDA #&FF ;&FF = claim Tube with claimant ID = &3F BBC4 20 06 04 JSR &0406 ;call Tube service BBC7 90 F9 BCC SBC2 ;loop until claim granted BBC9 20 D2 04 JSR &04D2 ;set up Tube destination address .SBCC BBCC A9 07 LDA #&07 ;type byte = 7, 256 byte transfer to host BBCE 20 CB 04 JSR &04CB ;set up Tube data transfer BBD1 A0 00 LDY #&00 ;clear page offset BBD3 84 00 STY &00 ;align ROM pointer to page boundary .SBD5 BBD5 B1 00 LDA (&00),Y ;get byte from ROM BBD7 8D E5 FE STA &FEE5 ;write A to R3DATA BBDA EA NOP ;wait 3 microseconds BBDB EA NOP BBDC EA NOP BBDD C8 INY ;increment offset BBDE D0 F5 BNE SBD5 ;loop until page boundary reached (10us/byte) BBE0 E6 54 INC &54 ;then add 256 to Tube transfer address BBE2 D0 06 BNE SBEA ;carry out to 2MSB BBE4 E6 55 INC &55 BBE6 D0 02 BNE SBEA ;and MSB BBE8 E6 56 INC &56 .SBEA BBEA E6 01 INC &01 ;increment MSB of ROM pointer BBEC 24 01 BIT &01 ;test b14 of ROM pointer BBEE 50 DC BVC SBCC ;loop until b14=1, when it has reached &C000 BBF0 20 D2 04 JSR &04D2 ;set up Tube destination address BBF3 A9 04 LDA #&04 ;type byte = 4 no transfer, execute 2P code: ;04CB set up Tube data transfer BBF5 A0 00 LDY #&00 ;point XY at Tube transfer address at &0053 BBF7 A2 53 LDX #&53 BBF9 4C 06 04 JMP &0406 ;jump into Tube service. ;04D2 Set up Tube destination address BBFC A9 80 LDA #&80 BBFE 85 54 STA &54 ;set 3MSB of Tube transfer address = &80 BC00 85 01 STA &01 ;set MSB of ROM pointer = &80 BC02 A9 20 LDA #&20 ;set b5=1 to test custom address flag BC04 2D 06 80 AND &8006 ;AND with ROM type byte BC07 A8 TAY ;place result in AY for MSB, 2MSB of addr BC08 84 53 STY &53 ;store as LSB (on the assumption that it's 0) BC0A F0 19 BEQ SC25 ;if b5=0 then no custom addr, set &00008000 BC0C AE 07 80 LDX &8007 ;else get offset of copyright string .SC0F BC0F E8 INX ;skip leading NUL, increment offset BC10 BD 00 80 LDA &8000,X ;test character of copyright string BC13 D0 FA BNE SC0F ;loop until terminating NUL reached BC15 BD 01 80 LDA &8001,X ;store next byte as LSB of Tube address BC18 85 53 STA &53 BC1A BD 02 80 LDA &8002,X ;store byte after that as 3MSB BC1D 85 54 STA &54 BC1F BC 03 80 LDY &8003,X ;get next byte as 2MSB BC22 BD 04 80 LDA &8004,X ;get byte after that as MSB: .SC25 BC25 85 56 STA &56 ;store MSB of Tube transfer address BC27 84 55 STY &55 ;store 2MSB of Tube transfer address BC29 60 RTS ;0500 Tube call handler jump table (SB) BC2A EQUW &37,&05 ;R2 was &00 - jump osrdch_call BC2C EQUW &96,&05 ;R2 was &02 - jump oscli_call BC2E EQUW &F2,&05 ;R2 was &04 - jump short_osbyte BC30 EQUW &07,&06 ;R2 was &06 - jump long_osbyte BC32 EQUW &27,&06 ;R2 was &08 - jump osword_call BC34 EQUW &68,&06 ;R2 was &0A - jump osword0_call BC36 EQUW &5E,&05 ;R2 was &0C - jump osargs_call BC38 EQUW &2D,&05 ;R2 was &0E - jump osbget_call BC3A EQUW &20,&05 ;R2 was &10 - jump osbput_call BC3C EQUW &42,&05 ;R2 was &12 - jump osfind_call BC3E EQUW &A9,&05 ;R2 was &14 - jump osfile_call BC40 EQUW &D1,&05 ;R2 was &16 - jump osgbpb_call ;0518 Tube status settings for transfer types 0..7 BC42 EQUB &86 ;0=bytes to host J,I=1 enable IRQ on R4,R1 BC43 EQUB &88 ;1=bytes from host M=1 enable NMI on R3 BC44 EQUB &96 ;2=words to host V,J,I=1 enable IRQ on R4,R1 BC45 EQUB &98 ;3=words from host V,M=1 enable NMI on R3 BC46 EQUB &18 ;4=address only V,M=0 disable NMI on R3 BC47 EQUB &18 ;5=(reserved) V,M=0 disable NMI on R3 BC48 EQUB &82 ;6=page to host I=1 enable IRQ on R1 BC49 EQUB &18 ;7=page from host V,M=0 disable NMI on R3 ;osbput_call BC4A 20 C5 06 JSR &06C5 ;read R2DATA to A BC4D A8 TAY ;set Y=channel BC4E 20 C5 06 JSR &06C5 ;read R2DATA to A =byte to write BC51 20 D4 FF JSR &FFD4 ;call OSBPUT BC54 4C 9C 05 JMP &059C ;signal completion ;osbget_call BC57 20 C5 06 JSR &06C5 ;read R2DATA to A BC5A A8 TAY ;set Y=channel BC5B 20 D7 FF JSR &FFD7 ;call OSBGET BC5E 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;osrdch_call BC61 20 E0 FF JSR &FFE0 ;call OSRDCH ;053A send C, A to R2DATA and idle BC64 6A ROR A ;rotate C into A b7, save A b0 in C BC65 20 95 06 JSR &0695 ;write A to R2DATA BC68 2A ROL A ;restore A on entry BC69 4C 9E 05 JMP &059E ;write to R2DATA and idle ;osfind_call BC6C 20 C5 06 JSR &06C5 ;read R2DATA to A BC6F F0 0B BEQ SC7C ;if A=0 then close file BC71 48 PHA ;else save A=call no. = open mode BC72 20 82 05 JSR &0582 ;read string to buffer BC75 68 PLA ;restore A BC76 20 CE FF JSR &FFCE ;call OSFIND BC79 4C 9E 05 JMP &059E ;write to R2DATA and idle .SC7C ;read R2DATA to A BC7C 20 C5 06 JSR &06C5 ;set Y=file handle BC7F A8 TAY ;restore A=0 call no. = close file BC80 A9 00 LDA #&00 ;call OSFIND BC82 20 CE FF JSR &FFCE ;signal completion BC85 4C 9C 05 JMP &059C ;osargs_call BC88 20 C5 06 JSR &06C5 ;read R2DATA to A BC8B A8 TAY ;set Y=channel BC8C A2 04 LDX #&04 ;4 bytes to read: .SC8E BC8E 20 C5 06 JSR &06C5 ;read R2DATA to A BC91 95 FF STA &FF,X ;save in locations 3..0 BC93 CA DEX ;in descending order BC94 D0 F8 BNE SC8E ;loop until X bytes read BC96 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BC99 20 DA FF JSR &FFDA ;call OSARGS BC9C 20 95 06 JSR &0695 ;write A to R2DATA =return value BC9F A2 03 LDX #&03 ;4 bytes to write: .SCA1 BCA1 B5 00 LDA &00,X ;get locations 3..0 BCA3 20 95 06 JSR &0695 ;write A to R2DATA BCA6 CA DEX ;in descending order BCA7 10 F8 BPL SCA1 ;loop until X+1 bytes written BCA9 4C 36 00 JMP &0036 ;go to idle loop ;0582 read string to buffer BCAC A2 00 LDX #&00 ;set X=0 LSB of buffer address BCAE A0 00 LDY #&00 ;set Y=0 buffer offset .SCB0 BCB0 20 C5 06 JSR &06C5 ;read R2DATA to A BCB3 99 00 07 STA &0700,Y ;save in string buffer BCB6 C8 INY ;in ascending order, increment offset BCB7 F0 04 BEQ SCBD ;if end of buffer reached then stop BCB9 C9 0D CMP #&0D ;else test character read BCBB D0 F3 BNE SCB0 ;if =CR then string terminated else loop .SCBD BCBD A0 07 LDY #&07 ;set Y=&07 MSB of buffer address BCBF 60 RTS ;oscli_call BCC0 20 82 05 JSR &0582 ;read string to buffer BCC3 20 F7 FF JSR &FFF7 ;call OSCLI ;059C Signal completion BCC6 A9 7F LDA #&7F .SCC8 ;059E Write to R2DATA and idle BCC8 2C E2 FE BIT &FEE2 ;test R2STAT BCCB 50 FB BVC SCC8 ;loop until b6=1, not full BCCD 8D E3 FE STA &FEE3 ;write A to R2DATA .SCD0 BCD0 4C 36 00 JMP &0036 ;go to idle loop ;osfile_call BCD3 A2 10 LDX #&10 ;16 bytes to read: .SCD5 BCD5 20 C5 06 JSR &06C5 ;read R2DATA to A BCD8 95 01 STA &01,X ;save to locations 17..2 BCDA CA DEX ;in descending order BCDB D0 F8 BNE SCD5 ;loop until X bytes read BCDD 20 82 05 JSR &0582 ;read string to buffer BCE0 86 00 STX &00 ;save buffer address at 0,1 BCE2 84 01 STY &01 ;=&0700 BCE4 A0 00 LDY #&00 ;set Y=0; X=0 from 0582 BCE6 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BCE9 20 DD FF JSR &FFDD ;call OSFILE BCEC 20 95 06 JSR &0695 ;write A to R2DATA =return value BCEF A2 10 LDX #&10 ;16 bytes to write: .SCF1 BCF1 B5 01 LDA &01,X ;get locations 17..2 BCF3 20 95 06 JSR &0695 ;write A to R2DATA BCF6 CA DEX ;in descending order BCF7 D0 F8 BNE SCF1 ;loop until X bytes written BCF9 F0 D5 BEQ SCD0 ;then go to idle loop ;osgbpb_call BCFB A2 0D LDX #&0D ;13 bytes to read: .SCFD BCFD 20 C5 06 JSR &06C5 ;read R2DATA to A BD00 95 FF STA &FF,X ;save to locations 12..0 BD02 CA DEX ;in descending order BD03 D0 F8 BNE SCFD ;loop until X bytes read BD05 20 C5 06 JSR &06C5 ;read R2DATA to A BD08 A0 00 LDY #&00 ;set Y=0; X=0 from loop BD0A 20 D1 FF JSR &FFD1 ;call OSGBPB BD0D 48 PHA ;save return value BD0E A2 0C LDX #&0C ;13 bytes to write: .SD10 BD10 B5 00 LDA &00,X ;get locations 12..0 BD12 20 95 06 JSR &0695 ;write A to R2DATA BD15 CA DEX ;in descending order BD16 10 F8 BPL SD10 ;loop until X bytes written BD18 68 PLA ;restore A=return value BD19 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;short_osbyte BD1C 20 C5 06 JSR &06C5 ;read R2DATA to A BD1F AA TAX ;save X=first parameter BD20 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD23 20 F4 FF JSR &FFF4 ;call OSBYTE .SD26 BD26 2C E2 FE BIT &FEE2 ;test R2STAT BD29 50 FB BVC SD26 ;loop until b6=1, not full BD2B 8E E3 FE STX &FEE3 ;write X to R2DATA =result .SD2E BD2E 4C 36 00 JMP &0036 ;go to idle loop ;long_osbyte BD31 20 C5 06 JSR &06C5 ;read R2DATA to A BD34 AA TAX ;set X=first parameter BD35 20 C5 06 JSR &06C5 ;read R2DATA to A BD38 A8 TAY ;set Y=second parameter BD39 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD3C 20 F4 FF JSR &FFF4 ;call OSBYTE BD3F 49 9D EOR #&9D ;if A=&9D fast Tube BPUT BD41 F0 EB BEQ SD2E ;then end call without handshake BD43 6A ROR A ;else rotate C into A b7 BD44 20 95 06 JSR &0695 ;write A to R2DATA .SD47 BD47 2C E2 FE BIT &FEE2 ;test R2STAT BD4A 50 FB BVC SD47 ;loop until b6=1, not full BD4C 8C E3 FE STY &FEE3 ;write Y to R2DATA =second result BD4F 70 D5 BVS SD26 ;write X to R2DATA and idle (always) ;osword_call BD51 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD54 A8 TAY ;hold in Y .SD55 BD55 2C E2 FE BIT &FEE2 ;test R2STAT BD58 10 FB BPL SD55 ;loop until b7=1, data available BD5A AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD5D CA DEX ;decrement X BD5E 30 0F BMI SD6F ;if X was not in range 1..128 then no bytes .SD60 BD60 2C E2 FE BIT &FEE2 ;else test R2STAT BD63 10 FB BPL SD60 ;loop until b7=1, data available BD65 AD E3 FE LDA &FEE3 ;read R2DATA to A BD68 9D 28 01 STA &0128,X ;save to locations &0128+(X-1..0) BD6B CA DEX ;in descending order BD6C 10 F2 BPL SD60 ;loop until X bytes written BD6E 98 TYA ;restore A=call number .SD6F BD6F A2 28 LDX #&28 ;point XY to OSWORD control block at &0128 BD71 A0 01 LDY #&01 BD73 20 F1 FF JSR &FFF1 ;call OSWORD .SD76 BD76 2C E2 FE BIT &FEE2 ;test R2STAT BD79 10 FB BPL SD76 ;loop until b7=1, data available BD7B AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD7E CA DEX ;decrement X BD7F 30 0E BMI SD8F ;if X was not in range 1..128 then no bytes .SD81 BD81 BC 28 01 LDY &0128,X ;else get byte of control block at ..&0128 .SD84 BD84 2C E2 FE BIT &FEE2 ;test R2STAT BD87 50 FB BVC SD84 ;loop until b6=1, not full BD89 8C E3 FE STY &FEE3 ;write Y to R2DATA BD8C CA DEX ;in descending order BD8D 10 F2 BPL SD81 ;loop until X bytes written .SD8F BD8F 4C 36 00 JMP &0036 ;go to idle loop ;osword0_call BD92 A2 04 LDX #&04 ;5 bytes to read: .SD94 BD94 20 C5 06 JSR &06C5 ;read R2DATA to A BD97 95 00 STA &00,X ;save to locations 4..0 BD99 CA DEX ;in descending order BD9A 10 F8 BPL SD94 ;loop until X+1 bytes read BD9C E8 INX ;set X=0 BD9D A0 00 LDY #&00 ;set Y=0; point XY to OSWORD control block BD9F 8A TXA ;set A=0 read line from input stream BDA0 20 F1 FF JSR &FFF1 ;call OSWORD BDA3 90 05 BCC SDAA ;if user pressed ESCAPE BDA5 A9 FF LDA #&FF ;then A=&FF carry set/error condition BDA7 4C 9E 05 JMP &059E ;write to R2DATA and idle .SDAA BDAA A2 00 LDX #&00 ;else X=0 offset into string buffer BDAC A9 7F LDA #&7F ;set A=&7F carry clear/no error BDAE 20 95 06 JSR &0695 ;write A to R2DATA .SDB1 BDB1 BD 00 07 LDA &0700,X ;get character from string buffer BDB4 20 95 06 JSR &0695 ;write A to R2DATA BDB7 E8 INX ;increment offset BDB8 C9 0D CMP #&0D ;test character just written BDBA D0 F5 BNE SDB1 ;if =CR then string terminated else loop BDBC 4C 36 00 JMP &0036 ;go to idle loop .SDBF ;0695 Write A to R2DATA BDBF 2C E2 FE BIT &FEE2 ;test R2STAT BDC2 50 FB BVC SDBF ;loop until b6=1, not full BDC4 8D E3 FE STA &FEE3 ;write A to R2DATA BDC7 60 RTS .SDC8 ;069E Write A to R4DATA BDC8 2C E6 FE BIT &FEE6 ;test R4STAT BDCB 50 FB BVC SDC8 ;loop until b6=1, not full BDCD 8D E7 FE STA &FEE7 ;write A to R4DATA BDD0 60 RTS ;06A7 Copy ESCAPE flag to coprocessor (NAUG) BDD1 A5 FF LDA &FF ;get MOS ESCAPE flag BDD3 38 SEC ;rotate 1 into bit 7, ESCAPE flag in bit 6 BDD4 6A ROR A ;A >= &80 indicating ESCAPE flag update BDD5 30 0F BMI SDE6 ;write A to R1DATA (always) ;06AD Event handler BDD7 48 PHA ;save event type BDD8 A9 00 LDA #&00 ;set A=&00 to indicate event BDDA 20 BC 06 JSR &06BC ;write A to R1DATA BDDD 98 TYA ;transfer Y=second event parameter to A BDDE 20 BC 06 JSR &06BC ;write A to R1DATA BDE1 8A TXA ;transfer X=first event parameter to A BDE2 20 BC 06 JSR &06BC ;write A to R1DATA BDE5 68 PLA ;restore event type to A: .SDE6 ;06BC Write A to R1DATA BDE6 2C E0 FE BIT &FEE0 ;test R1STAT BDE9 50 FB BVC SDE6 ;loop until b6=1, not full BDEB 8D E1 FE STA &FEE1 ;write A to R1DATA BDEE 60 RTS .SDEF ;06C5 Read R2DATA to A BDEF 2C E2 FE BIT &FEE2 ;test R2STAT BDF2 10 FB BPL SDEF ;loop until b7=1, data available BDF4 AD E3 FE LDA &FEE3 ;read R2DATA to A and return BDF7 60 RTS .SDF8 ;Print "COPYRIGHT NOTICE" BDF8 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BDFB EQUB &83 ;yellow alphanumerics BDFC EQUB &8D ;double height BDFD EQUS " C O P Y R I G H T N O T I C E" BE1D EQUB &0D BE1E EQUB &0A BE1F EQUB &FF BE20 60 RTS ;*COPYRIGHT BE21 20 74 AD JSR RD74 ;set display MODE 7 BE24 20 67 84 JSR P467 ;print newline BE27 20 F8 BD JSR SDF8 ;print "COPYRIGHT NOTICE" twice BE2A 20 F8 BD JSR SDF8 BE2D 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE30 EQUB &0D BE31 EQUB &0A BE32 EQUB &0A BE33 EQUS "This Double Density Operating System" BE57 EQUB &0D BE58 EQUB &0A BE59 EQUS "was developed for the BBC computer by" BE7E EQUB &0D BE7F EQUB &0A BE80 EQUB &83 ;yellow alphanumerics BE81 EQUS "SLOGGER SOFTWARE and OPUS SUPPLIES" BEA3 EQUB &0D BEA4 EQUB &0A BEA5 EQUS "Any unauthorised copying of this" BEC5 EQUB &0D BEC6 EQUB &0A BEC7 EQUS "product is unlawful and may result in" BEEC EQUB &0D BEED EQUB &0A BEEE EQUS "Slogger or Opus taking appropriate" BF10 EQUB &0D BF11 EQUB &0A BF12 EQUS "action." BF19 EQUB &0D BF1A EQUB &0A BF1B EQUB &0A BF1C EQUB &FF BF1D 60 RTS BF80 EQUB &FF,&FF,&FF,&FF BF84 EQUB &FF,&FF,&FF,&FF BF88 EQUB &FF,&FF,&FF,&FF BF8C EQUB &FF,&FF,&FF,&FF BF90 EQUB &FF,&FF,&FF,&FF BF94 EQUB &FF,&FF,&FF,&FF BF98 EQUB &FF,&FF,&FF,&FF BF9C EQUB &FF,&FF,&FF,&FF BFA0 EQUB &FF,&FF,&FF,&FF BFA4 EQUB &FF,&FF,&FF,&FF BFA8 EQUB &FF,&FF,&FF,&FF BFAC EQUB &FF,&FF,&FF,&FF BFB0 EQUB &FF,&FF,&FF,&FF BFB4 EQUB &FF,&FF,&FF,&FF BFB8 EQUB &FF,&FF,&FF,&FF BFBC EQUB &FF,&FF,&FF,&FF BFC0 EQUB &FF,&FF,&FF,&FF BFC4 EQUB &FF,&FF,&FF,&FF BFC8 EQUB &FF,&FF,&FF,&FF BFCC EQUB &FF,&FF,&FF,&FF BFD0 EQUB &FF,&FF,&FF,&FF BFD4 EQUB &FF,&FF,&FF,&FF BFD8 EQUB &FF,&FF,&FF,&FF BFDC EQUB &FF,&FF,&FF,&FF BFE0 EQUB &FF,&FF,&FF,&FF BFE4 EQUB &FF,&FF,&FF,&FF BFE8 EQUB &FF,&FF,&FF,&FF BFEC EQUB &FF,&FF,&FF,&FF BFF0 EQUB &FF,&FF,&FF,&FF BFF4 EQUB &FF,&FF,&FF,&FF BFF8 EQUB &FF,&FF,&FF,&FF BFFC EQUB &FF,&FF,&FF,&FF #else /* _DDOS316 */ ;////////////////////////////////////////////// COMMON .S673 ;Test write protect state B673 20 3A B7 JSR S73A ;issue Seek and Force Interrupt B676 20 03 BA JSR SA03 ;wait for command completion B679 29 40 AND #&40 ;z=0 if WD1770 S6 = write protect. B67B 60 RTS ;[BUG] The recalibrate and seek routines raise the INTRQ pin which ;causes an NMI, but do not install code in the NMI service area. ;Any code left at the NMI entry point is executed. ;Typically there is an RTI instruction at &0D00 left by the MOS on ;reset, or by a previous NMI service routine that self-sealed. An FDC ;command that did not complete, however, leaves its ISR active and this ;services the NMI - mistreating the command completion interrupt as a ;data request - and interferes with the byte transfer count at &A0..1. ;A floppy disc operation performs a seek as a subtask after storing the ;count and before installing its service routine. It expects NMIs to be ;ignored in the meantime and because they are not, it goes on to ;transfer the wrong number of bytes. ;If re-entered, the RAM disc transfer code overwrites memory and crashes ;(original version; it is patched in this file under symbol _RAMBUGFIX.) ;Machines with Econet are also affected. ;Opus 2791/2793 board users (running DDOS 3.1x/3.3x) have their INTRQ ;pin disconnected from the NMI line and get off scot-free. .S67C ;Recalibrate drive (seek track 0) # if defined _TURBO B67C 20 2D A3 JSR R32D ;save XY # else B67C 20 29 A3 JSR R329 ;save XY # endif B67F A9 00 LDA #&00 ;WD1770 FDC command &00 = Restore # if defined _BUGFIX B681 20 F6 92 JSR Q2F6 ;execute command and wait for completion # else B681 20 B9 B6 JSR S6B9 ;execute command and wait for completion # endif B684 A5 CF LDA &CF ;get current volume B686 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B688 AA TAX ;transfer to X for use as index B689 A9 00 LDA #&00 ;set physical position of head to 0 B68B 9D 8C 10 STA &108C,X B68E 60 RTS .S68F ;Seek logical track B68F A5 BA LDA &BA ;get logical track number B691 2C E0 10 BIT &10E0 ;test double-stepping flag B694 50 01 BVC S697 ;if b6=1 then double stepping is enabled B696 0A ASL A ;so double track number: .S697 ;Seek physical track B697 C9 00 CMP #&00 ;if track number = 0 B699 F0 E1 BEQ S67C ;then issue Restore command # if defined _TURBO B69B 20 2D A3 JSR R32D ;else save XY # else B69B 20 29 A3 JSR R329 ;else save XY # endif B69E 48 PHA ;save target physical track B69F A5 CF LDA &CF ;get current volume B6A1 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B6A3 AA TAX ;transfer to X for use as index B6A4 BD 8C 10 LDA &108C,X ;get physical track number for drive # if defined _DDOS357 B6A7 20 AE B9 JSR S9AE ;store in track register of FDC # else B6A7 20 B2 B9 JSR S9B2 ;store in track register of FDC # endif B6AA 68 PLA ;restore target physical track B6AB 9D 8C 10 STA &108C,X ;store physical track number for drive B6AE 20 F7 B9 JSR S9F7 ;write to FDC data register B6B1 A9 10 LDA #&10 ;WD1770 FDC command &10 = Seek # if defined _BUGFIX B6B3 20 F6 92 JSR Q2F6 ;execute command and wait for completion # else B6B3 20 B9 B6 JSR S6B9 ;execute command and wait for completion # endif B6B6 29 10 AND #&10 ;z=0 if WD1770 S4 = record not found. B6B8 60 RTS .S6B9 ;Execute Restore/Seek command B6B9 0D 8E 10 ORA &108E ;apply track stepping rate B6BC 20 EF B9 JSR S9EF ;write to FDC command register B6BF 4C 03 BA JMP SA03 ;wait for command completion and exit. .S6C2 ;Ensure disc is formatted B6C2 20 CB B6 JSR S6CB ;read ID and detect density B6C5 F0 03 BEQ S6CA ;if record found then exit B6C7 4C D8 B9 JMP S9D8 ;else raise "Disk not formatted" error. .S6CA B6CA 60 RTS ;[BUG]cannot force density, always tests both .S6CB ;Read ID and detect density # if defined _TURBO B6CB 20 2D A3 JSR R32D ;save XY # else B6CB 20 29 A3 JSR R329 ;save XY # endif B6CE 20 3A B7 JSR S73A ;issue Seek and Force Interrupt B6D1 A2 04 LDX #&04 ;4 attempts to make, 2 in each density: B6D3 2C E3 10 BIT &10E3 ;if current density is single B6D6 50 0F BVC S6E7 ;then attempt in single density first, else: .S6D8 B6D8 AD E3 10 LDA &10E3 ;get density flag B6DB 09 40 ORA #&40 ;set b6=1, double density B6DD A0 12 LDY #&12 ;18 sectors per track B6DF 20 0C B7 JSR S70C ;execute Read Address at specified density B6E2 F0 25 BEQ S709 ;if record found then return success B6E4 CA DEX ;else decrement number of attempts remaining B6E5 F0 0F BEQ S6F6 ;if run out of tries then return failure .S6E7 B6E7 AD E3 10 LDA &10E3 ;else get density flag B6EA 29 BF AND #&BF ;set b6=0, single density B6EC A0 0A LDY #&0A ;10 sectors per track B6EE 20 0C B7 JSR S70C ;execute Read Address at specified density B6F1 F0 16 BEQ S709 ;if record found then return success B6F3 CA DEX ;else decrement number of attempts remaining B6F4 D0 E2 BNE S6D8 ;if attempts remaining try double density .S6F6 B6F6 AD E3 10 LDA &10E3 ;else set b6=0, single density B6F9 29 BF AND #&BF B6FB 8D E3 10 STA &10E3 B6FE 20 58 B6 JSR S658 ;set control latch for drive B701 A9 0A LDA #&0A ;set 10 sectors per track B703 8D E1 10 STA &10E1 B706 A9 18 LDA #&18 ;fake WD1770 S4 = record not found B708 60 RTS ;fake WD1770 S3 = CRC error. .S709 B709 A9 00 LDA #&00 ;fake WD1770 status = 0, succeeded. B70B 60 RTS .S70C ;Execute Read Address at specified density B70C 8D E3 10 STA &10E3 ;store density flag B70F 8C E1 10 STY &10E1 ;store number of sectors per track: .S712 ;Execute Read Address command B712 A0 14 LDY #&14 ;21 bytes to copy, &0D00..14: .S714 # if defined _DDOS346 B714 B9 70 BA LDA &BA70,Y ;get byte of NMI read ID # else B714 B9 6F BA LDA &BA6F,Y ;get byte of NMI read ID # endif B717 99 00 0D STA &0D00,Y ;store in NMI area B71A 88 DEY ;loop until all bytes copied B71B 10 F7 BPL S714 B71D A9 00 LDA #&00 ;initialise offset = 0 B71F 85 A0 STA &A0 B721 20 58 B6 JSR S658 ;set control latch for drive B724 A9 C0 LDA #&C0 ;WD1770 command &C0 = Read address B726 20 EF B9 JSR S9EF ;write to FDC command register B729 20 03 BA JSR SA03 ;wait for command completion B72C 48 PHA ;save exit status B72D A0 03 LDY #&03 ;4 bytes to copy, &1090..3: .S72F B72F B9 90 10 LDA &1090,Y ;get CHRN byte of sector ID B732 99 02 10 STA &1002,Y ;copy to workspace B735 88 DEY ;loop until all bytes copied B736 10 F7 BPL S72F B738 68 PLA ;restore Read Address command status and exit B739 60 RTS .S73A ;Issue Seek and Force Interrupt B73A A9 18 LDA #&18 ;WD1770 command &18 = Seek w/spin up B73C 20 EF B9 JSR S9EF ;write to FDC command register B73F A2 0F LDX #&0F ;wait 38.5 microseconds .S741 B741 CA DEX B742 D0 FD BNE S741 B744 A9 D0 LDA #&D0 ;WD1770 command &D0 = Force interrupt B746 4C EF B9 JMP S9EF ;write to FDC command register and exit .S749 B749 60 RTS .S74A ;Verify track # if defined _TURBO B74A 20 2D A3 JSR R32D ;save XY # else B74A 20 29 A3 JSR R329 ;save XY # endif B74D A9 00 LDA #&00 B74F 85 BB STA &BB ;sector number = 0 B751 85 A0 STA &A0 ;whole number of sectors to transfer B753 AD E1 10 LDA &10E1 ;get number of sectors per track B756 85 A1 STA &A1 ;set number of sectors to transfer B758 A9 04 LDA #&04 ;set call number to &04, verify data B75A 8D 00 10 STA &1000 .S75D ;Transfer data to disc L2 # if defined _TURBO B75D 20 2D A3 JSR R32D ;save XY # else B75D 20 29 A3 JSR R329 ;save XY # endif B760 20 D6 A7 JSR R7D6 ;set up for current drive B763 A2 0A LDX #&0A ;wait 26 microseconds .S765 B765 CA DEX B766 D0 FD BNE S765 # if defined _DDOS356 B768 AD 28 FE LDA &FE28 ;load FDC status register # elif defined _DDOS357 B768 AD 28 FE LDA &FE28 ;load FDC status register # elif defined _DDOS326 B768 AD 84 FE LDA &FE84 ;load FDC status register # else B768 AD 80 FE LDA &FE80 ;load FDC status register # endif B76B 48 PHA ;save status B76C 20 8F B6 JSR S68F ;seek logical track B76F A5 BA LDA &BA ;get logical track number # if defined _DDOS357 B771 20 A4 B9 JSR S9A4 ;store as physical position of head # else B771 20 A8 B9 JSR S9A8 ;store as physical position of head # endif ;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 &B794. B774 68 PLA ;restore status B775 30 19 BMI S790 ;if WD1770 S7 = motor on then skip B777 AD 00 10 LDA &1000 ;else get data transfer call number B77A C9 01 CMP #&01 ;if writing to disc B77C D0 12 BNE S790 B77E 48 PHA ;then save call number, 1 B77F A9 04 LDA #&04 ;set call number to &04, verify data B781 8D 00 10 STA &1000 B784 A2 02 LDX #&02 ;execute floppy drive command twice: .S786 B786 20 99 B7 JSR S799 ;execute verify data command L1 B789 CA DEX ;decrement counter B78A D0 FA BNE S786 ;loop until two verify passes made B78C 68 PLA ;restore call number. B78D 8D 00 10 STA &1000 .S790 B790 20 99 B7 JSR S799 ;execute floppy drive command L1 B793 48 PHA ;save masked status # if defined _DDOS357 B794 20 9C B9 JSR S99C ;store head position for this drive # else B794 20 A0 B9 JSR S9A0 ;store head position for this drive # endif B797 68 PLA ;restore masked status, setting Z B798 60 RTS ;and exit .S799 ;Execute floppy drive command L1 # if defined _TURBO B799 20 2D A3 JSR R32D ;save XY # else B799 20 29 A3 JSR R329 ;save XY # endif B79C A5 A0 LDA &A0 ;save ?&A0, ?&A1 on stack B79E 48 PHA B79F A5 A1 LDA &A1 B7A1 48 PHA # if defined _BEEBEM ;Patch to get BeebEm to write the last byte of a track. NOT FOR HARDWARE B7A2 20 FC AB JSR RBFC ;copy NMI read from disc/polling loop to NMI # else B7A2 20 31 B8 JSR S831 ;copy NMI read from disc/polling loop to NMI # endif B7A5 AD 01 10 LDA &1001 ;get *SROM slot number B7A8 8D 2D 0D STA &0D2D ;store in polling loop to page in on entry B7AB A5 A0 LDA &A0 ;increment MSB byte count if LSB >0 B7AD F0 02 BEQ S7B1 ;not rounding up, converting number format; B7AF E6 A1 INC &A1 ;Z=1 from both DECs means zero reached .S7B1 B7B1 AD 00 10 LDA &1000 ;get data transfer call number B7B4 29 05 AND #&05 ;if call=0 or 2, read (deleted) data B7B6 F0 14 BEQ S7CC ;then branch B7B8 6A ROR A ;else if b2..0 = 1x0, A=&04 verify data B7B9 B0 15 BCS S7D0 B7BB A9 4C LDA #&4C ;then instruction at &0D06 = JMP &0D11 B7BD 8D 06 0D STA &0D06 ;discard byte from FDC data register B7C0 A9 11 LDA #&11 B7C2 8D 07 0D STA &0D07 B7C5 A9 0D LDA #&0D B7C7 8D 08 0D STA &0D08 B7CA D0 10 BNE S7DC .S7CC B7CC A0 07 LDY #&07 ;if call=0 or 2, read (deleted) data B7CE D0 09 BNE S7D9 ;then data address is located at &0D07. .S7D0 B7D0 A9 00 LDA #&00 ;if b0=1, A=1 or 3 write (deleted) data B7D2 85 A0 STA &A0 ;then clear ?&A0, write whole sectors B7D4 20 3D B8 JSR S83D ;copy NMI write to disc to NMI area B7D7 A0 04 LDY #&04 ;data address is located at &0D04 .S7D9 B7D9 20 07 B8 JSR S807 ;set data address in NMI ISR .S7DC B7DC A5 F4 LDA &F4 ;get DDOS ROM slot number B7DE 8D 38 0D STA &0D38 ;save in NMI area B7E1 A5 BB LDA &BB ;get start sector number B7E3 20 F3 B9 JSR S9F3 ;write to FDC sector register B7E6 AC 00 10 LDY &1000 ;get data transfer call number # if defined _DDOS346 B7E9 B9 1B BA LDA &BA1B,Y ;get FDC command for call # else B7E9 B9 1A BA LDA &BA1A,Y ;get FDC command for call # endif B7EC 20 EF B9 JSR S9EF ;write to FDC command register B7EF A2 1E LDX #&1E ;wait 76 microseconds .S7F1 B7F1 CA DEX B7F2 D0 FD BNE S7F1 B7F4 20 2C 0D JSR &0D2C ;page SROM in and wait until finished L0 B7F7 68 PLA ;restore ?&A0, ?&A1 from stack B7F8 85 A1 STA &A1 B7FA 68 PLA B7FB 85 A0 STA &A0 # if defined _DDOS346 B7FD 20 12 BA JSR SA12 ;load FDC status register and store b6..0 B800 AC 00 10 LDY &1000 B803 39 20 BA AND &BA20,Y ;apply status mask from table to set Z. # else B7FD 20 11 BA JSR SA11 ;load FDC status register and store b6..0 B800 AC 00 10 LDY &1000 B803 39 1F BA AND &BA1F,Y ;apply status mask from table to set Z. # endif B806 60 RTS .S807 ;Set data address in NMI ISR B807 AD D5 10 LDA &10D5 ;test Tube data transfer flag B80A F0 1A BEQ S826 ;if transferring data to Tube B80C A9 E5 LDA #&E5 ;then paste address of R3DATA at &0D00+Y B80E 99 00 0D STA &0D00,Y B811 A9 FE LDA #&FE B813 99 01 0D STA &0D01,Y B816 A9 4C LDA #&4C ;instruction at &0D09 = JMP &0D11 B818 8D 09 0D STA &0D09 ;do not increment R3DATA address B81B A9 11 LDA #&11 B81D 8D 0A 0D STA &0D0A B820 A9 0D LDA #&0D B822 8D 0B 0D STA &0D0B B825 60 RTS .S826 B826 A5 A6 LDA &A6 ;else copy data pointer to NMI ISR at &0D00+Y B828 99 00 0D STA &0D00,Y B82B A5 A7 LDA &A7 B82D 99 01 0D STA &0D01,Y B830 60 RTS .S831 ;Copy NMI read from disc/polling loop to NMI B831 A0 3C LDY #&3C ;61 bytes to copy, &0D00..3C: .S833 # if defined _DDOS346 B833 B9 25 BA LDA &BA25,Y ;get byte of NMI read from disc/polling loop # else B833 B9 24 BA LDA &BA24,Y ;get byte of NMI read from disc/polling loop # endif B836 99 00 0D STA &0D00,Y ;store in NMI area B839 88 DEY ;loop until all bytes copied B83A 10 F7 BPL S833 B83C 60 RTS .S83D ;Copy NMI write to disc to NMI area B83D A0 0D LDY #&0D ;14 bytes to copy, &0D03..10: .S83F # if defined _DDOS346 B83F B9 62 BA LDA &BA62,Y ;get byte of NMI write to disc # else B83F B9 61 BA LDA &BA61,Y ;get byte of NMI write to disc # endif B842 99 03 0D STA &0D03,Y ;patch NMI read to disc routine with it B845 88 DEY ;loop until all bytes copied B846 10 F7 BPL S83F B848 A9 FC LDA #&FC ;enable 123 microsecond delay B84A 8D 23 0D STA &0D23 ;before interrupting write operation B84D 60 RTS ;so that FDC will write CRC of sector .S84E ;Create ID table and format track B84E A9 0A LDA #&0A ;set A = 10 sectors per track B850 2C E3 10 BIT &10E3 ;if double density format B853 50 02 BVC S857 B855 A9 12 LDA #&12 ;then set A = 18 sectors per track .S857 B857 85 A6 STA &A6 ;store as limit to sector count B859 0A ASL A ;multiply by 4 B85A 0A ASL A B85B 85 A7 STA &A7 ;store as size of CHRN table B85D A6 BB LDX &BB ;set X = number of first sector B85F A0 00 LDY #&00 ;(inverse track skew) Y=0 CHRN tbl index .S861 B861 A5 BA LDA &BA ;Get logical track number B863 99 A0 11 STA &11A0,Y ;store cylinder number C B866 C8 INY B867 A9 00 LDA #&00 ;head number = 0 B869 99 A0 11 STA &11A0,Y ;store head humber H B86C C8 INY B86D 8A TXA ;transfer sector number to A B86E 99 A0 11 STA &11A0,Y ;store record number R B871 C8 INY B872 A9 01 LDA #&01 ;size code = 1, 256-byte sector B874 99 A0 11 STA &11A0,Y ;store size code N B877 C8 INY B878 E8 INX ;increment sector number B879 E4 A6 CPX &A6 ;has it reached no. sectors per track? B87B 90 02 BCC S87F B87D A2 00 LDX #&00 ;if so then wrap around to 0 .S87F B87F C4 A7 CPY &A7 ;has table offset reached 4x s.p.t? B881 90 DE BCC S861 ;if not then loop B883 A9 A0 LDA #&A0 ;else set pointer to start of CHRN table: B885 85 A6 STA &A6 B887 A9 11 LDA #&11 B889 85 A7 STA &A7 .S88B ;Format track B88B A9 12 LDA #&12 ;set data table pointer to &1312 B88D 85 A2 STA &A2 ;(page break occurs 1/8 of the way through B88F 85 A4 STA &A4 ;the 11th sector of the track.) B891 A9 13 LDA #&13 B893 85 A3 STA &A3 B895 A9 15 LDA #&15 ;set run table pointer to &1512 B897 85 A5 STA &A5 B899 A2 00 LDX #&00 ;point to single density table, X = &00 B89B 2C E3 10 BIT &10E3 ;if double density format B89E 50 02 BVC S8A2 B8A0 A2 23 LDX #&23 ;then point to double density table, X = &23 .S8A2 B8A2 A0 05 LDY #&05 ;set Y = 5 as counter: .S8A4 B8A4 20 E5 B8 JSR S8E5 ;add entry to track format RLE table B8A7 88 DEY ;loop until 5 entries added B8A8 D0 FA BNE S8A4 ;this copies gap 5, IDAM and start of gap 1 B8AA A0 0A LDY #&0A ;set Y = 10 sectors per track B8AC 2C E3 10 BIT &10E3 ;if double density format B8AF 50 02 BVC S8B3 B8B1 A0 12 LDY #&12 ;then Y = 18 sectors per track .S8B3 B8B3 8A TXA ;X points to repeating sector block B8B4 48 PHA ;save it .S8B5 B8B5 20 E5 B8 JSR S8E5 ;add entry to track format RLE table B8B8 90 FB BCC S8B5 ;loop until terminator byte reached B8BA 68 PLA ;reset X to start of sector block B8BB AA TAX B8BC 88 DEY ;decrement number of sectors remaining B8BD D0 F4 BNE S8B3 ;loop until all sectors added to track B8BF A9 00 LDA #&00 ;data byte = &00 (run length = &10 or &16) # if defined _DDOS357 B8C1 20 3D B9 JSR S93D ;add gap 4 to table # else B8C1 20 38 B9 JSR S938 ;add gap 4 to table # endif B8C4 20 8F B6 JSR S68F ;seek logical track B8C7 A9 0F LDA #&0F ;A = &0F (or just do LDY &1512:DEY:STY &A0!) B8C9 2C E3 10 BIT &10E3 ;if double density format B8CC 50 02 BVC S8D0 B8CE A9 27 LDA #&27 ;then A = &27 .S8D0 B8D0 85 A0 STA &A0 ;set number of filler bytes in gap 5 (- 1) B8D2 A0 23 LDY #&23 ;36 bytes to copy, &0D00..23: .S8D4 # if defined _DDOS346 B8D4 B9 85 BA LDA &BA85,Y ;get byte of NMI format code # else B8D4 B9 84 BA LDA &BA84,Y ;get byte of NMI format code # endif B8D7 99 00 0D STA &0D00,Y ;store in NMI handler area B8DA 88 DEY ;loop until all bytes transferred B8DB 10 F7 BPL S8D4 B8DD A9 F4 LDA #&F4 ;&F4=Write track, settling delay B8DF 20 EF B9 JSR S9EF ;write to FDC command register B8E2 4C 03 BA JMP SA03 ;wait for command completion and exit. .S8E5 ;Add entry to track format RLE table B8E5 8A TXA ;save ROM table offset B8E6 48 PHA B8E7 98 TYA ;save number of sectors remaining B8E8 48 PHA B8E9 A0 00 LDY #&00 ;y=&00, unused B8EB 38 SEC B8EC BD 56 B9 LDA &B956,X ;get run length from ROM table B8EF 30 12 BMI S903 ;if b7=1 then process special entry B8F1 F0 09 BEQ S8FC ;if the terminator byte then finish C=1 B8F3 85 A0 STA &A0 ;else store run length in zero page B8F5 BD 57 B9 LDA &B957,X ;get data byte from ROM table # if defined _DDOS357 B8F8 20 3D B9 JSR S93D ;store run in table # else B8F8 20 38 B9 JSR S938 ;store run in table # endif .S8FB B8FB 18 CLC ;c=0, sector not completed .S8FC B8FC 68 PLA ;restore number of sectors remaining B8FD A8 TAY B8FE 68 PLA ;restore ROM table offset B8FF AA TAX B900 E8 INX ;add 2 to ROM table offset B901 E8 INX B902 60 RTS .S903 ;Process special table entry (length=&FF) B903 BD 57 B9 LDA &B957,X ;get data byte from ROM format table B906 D0 1C BNE S924 ;if non-zero then add sector data area B908 A9 01 LDA #&01 ;else add ID bytes. run length of bytes = 1 B90A 85 A0 STA &A0 ;store run length in zero page B90C A2 04 LDX #&04 ;4 bytes in sector ID: .S90E B90E A0 00 LDY #&00 ;y=0 for user memory load B910 20 15 9E JSR QE15 ;get data byte from user memory # if defined _DDOS357 B913 20 3D B9 JSR S93D ;store run in table # else B913 20 38 B9 JSR S938 ;store run in table # endif B916 E6 A6 INC &A6 ;increment CHRN table pointer B918 D0 02 BNE S91C ;carry out to high byte B91A E6 A7 INC &A7 .S91C B91C CA DEX ;loop until 4 ID bytes stored B91D D0 EF BNE S90E B91F 85 A1 STA &A1 ;store last byte read = N = size code B921 4C FB B8 JMP S8FB ;restore XY and return .S924 ;Add sector data area B924 A6 A1 LDX &A1 ;load sector size code # if defined _DDOS357 B926 BD 39 B9 LDA &B939,X ;get run length from table # else B926 BD 9C B9 LDA &B99C,X ;get run length from table # endif B929 85 A0 STA &A0 ;store in zero page B92B A2 08 LDX #&08 ;repeat prescribed run 8 times: .S92D B92D A9 E5 LDA #&E5 ;A=&E5 = sector filler byte # if defined _DDOS357 B92F 20 3D B9 JSR S93D ;store run in table B932 CA DEX ;loop until 8 copies of run stored B933 D0 F8 BNE S92D B935 4C FB B8 JMP S8FB ;restore XY and return B939 EQUB &10 ;8x runs of 16 bytes for 128-byte sectors B93A EQUB &20 ;8x runs of 32 bytes for 256-byte sectors B93B EQUB &40 ;8x runs of 64 bytes for 512-byte sectors B93C EQUB &80 ;8x runs of 128 bytes for 1024-byte sectors .S93D ;Store run in table B93D A0 00 LDY #&00 ;offset = 0 for indirect indexed store B93F 91 A2 STA (&A2),Y ;store data byte in data table B941 A5 A0 LDA &A0 ;get run length B943 C4 A4 CPY &A4 ;if pointers are on a page boundary B945 D0 02 BNE S949 ;then subtract 1 from run length (C=1) B947 E9 01 SBC #&01 .S949 B949 91 A4 STA (&A4),Y ;store run length in run table # else /* _DDOS357 */ B92F 20 38 B9 JSR S938 ;store run in table B932 CA DEX ;loop until 8 copies of run stored B933 D0 F8 BNE S92D B935 4C FB B8 JMP S8FB ;restore XY and return .S938 ;Store run in table B938 A0 00 LDY #&00 ;offset = 0 for indirect indexed store B93A 91 A2 STA (&A2),Y ;store data byte in data table B93C A5 A0 LDA &A0 ;get run length B93E 91 A4 STA (&A4),Y ;store run length in run table B940 C6 A4 DEC &A4 ;if pointers are on a page boundary B942 E6 A4 INC &A4 B944 D0 05 BNE S94B B946 38 SEC ;then subtract 1 from run length B947 E9 01 SBC #&01 B949 91 A4 STA (&A4),Y .S94B # endif /* _DDOS357 */ B94B E6 A2 INC &A2 ;increment data table pointer B94D E6 A4 INC &A4 ;increment run table pointer B94F D0 04 BNE S955 ;carry out to high bytes B951 E6 A3 INC &A3 B953 E6 A5 INC &A5 .S955 B955 60 RTS ;RLE tables of formatting bytes ;Single density B956 EQUB &10,&FF ; 16x &FF filler bytes } Gap 5 B958 EQUB &03,&00 ; 6x &00 synchronization bytes } B95A EQUB &03,&00 B95C EQUB &01,&FC ; 1x &FC index address mark (clock &D7) B95E EQUB &0B,&FF ; 11x &FF filler bytes } Gap 1 ;block repeated for each sector B960 EQUB &03,&00 ; 6x &00 synchronization bytes } B962 EQUB &03,&00 B964 EQUB &01,&FE ; 1x &FE ID address mark (clock &C7) B966 EQUB &FF,&00 ;id bytes are inserted here B968 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B96A EQUB &0B,&FF ; 11x &FF filler bytes } Gap 2 B96C EQUB &03,&00 ; 6x &00 synchronization bytes } B96E EQUB &03,&00 B970 EQUB &01,&FB ; 1x &FB data address mark (clock &C7) B972 EQUB &FF,&01 ;data bytes are inserted here B974 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B976 EQUB &10,&FF ; 16x &FF filler bytes } Gap 3... ;end of repeated block B978 EQUB &00 ;terminator byte (not part of format) ;Double density B979 EQUB &28,&4E ; 40x &4E filler bytes } B97B EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 5 B97D EQUB &03,&F6 ; 3x &F6 synchronization bytes } B97F EQUB &01,&FC ; 1x &FC index address mark B981 EQUB &19,&4E ; 25x &4E filler bytes } Gap 1 ;block repeated for each sector B983 EQUB &0C,&00 ; 12x &00 preamble bytes } B985 EQUB &03,&F5 ; 3x &F5 synchronization bytes } B987 EQUB &01,&FE ; 1x &FE ID address mark B989 EQUB &FF,&00 ;id bytes are inserted here B98B EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B98D EQUB &16,&4E ; 22x &4E filler bytes } B98F EQUB &0C,&00 ; 12x &00 preamble bytes } Gap 2 B991 EQUB &03,&F5 ; 3x &F5 synchronization bytes } B993 EQUB &01,&FB ; 1x &FB data address mark B995 EQUB &FF,&01 ;data bytes are inserted here B997 EQUB &01,&F7 ; 1x &F7 CRC character insert (2 bytes) B999 EQUB &16,&4E ; 22x &4E filler bytes } Gap 3... ;end of repeated block B99B EQUB &00 ;terminator byte (not part of format) # if defined _DDOS357 .S99C ;Store per-drive head position B99C A5 BA LDA &BA ;get logical track number of disc operation B99E 2C E0 10 BIT &10E0 ;test double-stepping flag B9A1 50 01 BVC S9A4 ;if b6=1 then double stepping is enabled B9A3 0A ASL A ;so double track number: .S9A4 ;Store physical position of head B9A4 48 PHA B9A5 A5 CF LDA &CF ;get current volume B9A7 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B9A9 AA TAX ;transfer to X for use as index B9AA 68 PLA ;get back A B9AB 9D 8C 10 STA &108C,X ;store physical track number for drive .S9AE B9AE 8D 29 FE STA &FE29 ;store in track register of FDC B9B1 60 RTS .S9B2 B9B2 20 47 A3 JSR R347 B9B5 EQUB &C5 B9B6 EQUS " fault" B9BC EQUB &00 .S9BF ;command binary not found B9BF A9 0B LDA #&0B ;FSC 11 = *RUN from library B9C1 C5 B5 CMP &B5 ;if not already serving FSC 11 B9C3 F0 07 BEQ S9CC B9C5 A6 F2 LDX &F2 ;then XY = address of command line B9C7 A4 F3 LDY &F3 B9C9 4C 42 80 JMP P042 ;issue Filing System Call .S9CC B9CC 20 51 A3 JSR R351 ;else raise "Bad command" error. B9CF EQUB &FE B9D0 EQUS "command" B9D7 EQUB &00 # else /* _DDOS357 */ B99C EQUB &10 ;8x runs of 16 bytes for 128-byte sectors B99D EQUB &20 ;8x runs of 32 bytes for 256-byte sectors B99E EQUB &40 ;8x runs of 64 bytes for 512-byte sectors B99F EQUB &80 ;8x runs of 128 bytes for 1024-byte sectors .S9A0 ;Store per-drive head position B9A0 A5 BA LDA &BA ;get logical track number of disc operation B9A2 2C E0 10 BIT &10E0 ;test double-stepping flag B9A5 50 01 BVC S9A8 ;if b6=1 then double stepping is enabled B9A7 0A ASL A ;so double track number: .S9A8 ;Store physical position of head B9A8 48 PHA B9A9 A5 CF LDA &CF ;get current volume B9AB 29 01 AND #&01 ;extract physical unit number 0/2 or 1/3 B9AD AA TAX ;transfer to X for use as index B9AE 68 PLA ;get back A B9AF 9D 8C 10 STA &108C,X ;store physical track number for drive .S9B2 # if defined _DDOS356 B9B2 8D 29 FE STA &FE29 ;store in track register of FDC # elif defined _DDOS326 B9B2 8D 85 FE STA &FE85 ;store in track register of FDC # else B9B2 8D 81 FE STA &FE81 ;store in track register of FDC # endif B9B5 60 RTS .S9B6 B9B6 20 47 A3 JSR R347 B9B9 EQUB &C5 B9BA EQUS " fault" B9C0 EQUB &00 ;unreachable code B9C1 20 62 A3 JSR R362 B9C4 EQUB &C5 B9C5 EQUS "Cannot recalibrate" B9D7 EQUB &00 # endif /* _DDOS357 */ .S9D8 B9D8 20 62 A3 JSR R362 B9DB EQUB &C5 B9DC EQUS "Disk not formatted" B9EE EQUB &00 .S9EF ;Write to FDC command register # if defined _DDOS356 B9EF 8D 28 FE STA &FE28 # elif defined _DDOS357 B9EF 8D 28 FE STA &FE28 # elif defined _DDOS326 B9EF 8D 84 FE STA &FE84 # else B9EF 8D 80 FE STA &FE80 # endif B9F2 60 RTS .S9F3 ;Write to FDC sector register # if defined _DDOS356 B9F3 8D 2A FE STA &FE2A # elif defined _DDOS357 B9F3 8D 2A FE STA &FE2A # elif defined _DDOS326 B9F3 8D 86 FE STA &FE86 # else B9F3 8D 82 FE STA &FE82 # endif B9F6 60 RTS .S9F7 ;Write to FDC data register # if defined _DDOS356 B9F7 8D 2B FE STA &FE2B # elif defined _DDOS357 B9F7 8D 2B FE STA &FE2B # elif defined _DDOS326 B9F7 8D 87 FE STA &FE87 # else B9F7 8D 83 FE STA &FE83 # endif B9FA 60 RTS .S9FB ;Load FDC status register # if defined _DDOS356 B9FB AD 28 FE LDA &FE28 # elif defined _DDOS357 B9FB AD 28 FE LDA &FE28 # elif defined _DDOS326 B9FB AD 84 FE LDA &FE84 # else B9FB AD 80 FE LDA &FE80 # endif B9FE 29 80 AND #&80 ;mask b7 extract WD1770 S7 = motor on BA00 49 80 EOR #&80 ;return A=0, Z=1 iff motor is on BA02 60 RTS # if defined _DDOS346 ;////////////////////////////////////////////// DDOS 3.46 .SA03 ;Wait for command completion # if defined _TURBO BA03 20 2D A3 JSR R32D ;save XY # else BA03 20 29 A3 JSR R329 ;save XY # endif BA06 A2 FF LDX #&FF ;wait 638 microseconds .SA08 BA08 CA DEX BA09 D0 FD BNE SA08 .SA0B BA0B 20 12 BA JSR SA12 ;load FDC status register BA0E 29 01 AND #&01 ;extract bit 0 [DIFF] not into carry flag BA10 D0 F9 BNE SA0B ;loop until b0=0 WD1770 S0 = busy .SA12 BA12 AD 80 FE LDA &FE80 ;load FDC status register BA15 29 7F AND #&7F ;mask bits 6..0 ignore WD1770 S7 = motor on BA17 8D 8F 10 STA &108F ;save final status BA1A 60 RTS ;Table of WD1770 FDC commands for data transfer call numbers 0..4 BA1B EQUB &90 ;&00 = Read data BA1C EQUB &B4 ;&01 = Write data BA1D EQUB &90 BA1E EQUB &B5 ;&03 = Write deleted data BA1F EQUB &90 ;&04 = Verify data ;Table of status mask bytes for data transfer call numbers 0..4 ;{RecordNotFound CRCError LostData} (&1C) plus: BA20 EQUB &3C ;&00 = Read data: {RecordType} BA21 EQUB &7C ;&01 = Write data: {WriteProtect RecordType} BA22 EQUB &1C ;{} BA23 EQUB &5C ;&03 = Write deleted data: {WriteProtect} BA24 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) BA25 8D 2A 0D STA &0D2A ;save accumulator to restore on exit BA28 AD 83 FE LDA &FE83 ;read FDC data register BA2B 8D FF FF STA &FFFF ;store in user memory or R3DATA BA2E EE 07 0D INC &0D07 ;increment user memory address BA31 D0 03 BNE SA36 ;carry out to high byte BA33 EE 08 0D INC &0D08 .SA36 BA36 C6 A0 DEC &A0 ;decrement count of bytes to transfer BA38 D0 14 BNE SA4E ;(&0101 = 1; &0000 = 0) BA3A C6 A1 DEC &A1 ;if count has not reached zero BA3C D0 10 BNE SA4E ;then restore A and return from interrupt BA3E A9 40 LDA #&40 ;else set 0D00=RTI; ignore further NMIs BA40 8D 00 0D STA &0D00 ;ISR safe by 22+e..29.5 us after NMI BA43 A9 CE LDA #&CE ;write complete by 24.5+e..32 us BA45 69 01 ADC #&01 ;wait 123 microseconds (if loop enabled) BA47 90 00 BCC SA49 ;0D23=&FC loops back to &0D20 .SA49 BA49 A9 D0 LDA #&D0 ;FDC command &D0 = Force Interrupt BA4B 8D 80 FE STA &FE80 ;write to FDC command register .SA4E BA4E A9 00 LDA #&00 ;restore value of A on entry BA50 40 RTI ;return from interrupt ;NMI polling loop, &0D2C..3C BA51 A9 0E LDA #&0E ;page *SROM slot in BA53 8D 30 FE STA &FE30 .SA56 BA56 AD 80 FE LDA &FE80 ;load FDC status register BA59 6A ROR A ;place bit 0 in carry flag BA5A B0 FA BCS SA56 ;loop until b0=0 WD1770 S0 = busy BA5C A9 00 LDA #&00 ;page DDOS ROM back in BA5E 8D 30 FE STA &FE30 BA61 60 RTS BA62 AD FF FF LDA &FFFF ;NMI write to disc, &0D03..10 BA65 8D 83 FE STA &FE83 BA68 EE 04 0D INC &0D04 BA6B D0 03 BNE SA70 BA6D EE 05 0D INC &0D05 .SA70 BA70 8D 13 0D STA &0D13 ;NMI read ID, &0D00..14 BA73 8C 11 0D STY &0D11 ;save AY to restore on exit BA76 A4 A0 LDY &A0 ;load offset in Y BA78 AD 83 FE LDA &FE83 ;load FDC data register BA7B 99 90 10 STA &1090,Y ;store ID byte in buffer BA7E E6 A0 INC &A0 ;increment offset BA80 A0 00 LDY #&00 ;restore AY on entry BA82 A9 00 LDA #&00 BA84 40 RTI BA85 48 PHA ;NMI format, &0D00..23 BA86 AD 12 13 LDA &1312 ;save A on entry, fetch current data byte BA89 8D 83 FE STA &FE83 ;write to FDC data register BA8C C6 A0 DEC &A0 ;decrement run counter BA8E D0 0A BNE SA9A ;if all bytes in run written BA90 EE 02 0D INC &0D02 ;then increment data byte address low BA93 D0 0A BNE SA9F ;if no carry then fetch next run length BA95 EE 03 0D INC &0D03 ;else increment data byte address high .SA98 BA98 68 PLA ;restore A on entry BA99 40 RTI ;exit .SA9A BA9A 10 FC BPL SA98 ;if run still in progress then exit BA9C EE 1F 0D INC &0D1F ;else page was crossed last time: .SA9F BA9F EE 1E 0D INC &0D1E ;increment run length address BAA2 AD 12 15 LDA &1512 ;fetch next run length BAA5 85 A0 STA &A0 ;set run counter BAA7 68 PLA ;restore A on entry BAA8 40 RTI ;exit ;unreachable code BAA9 EA NOP ;Tube hosting .SAAA ;Service calls &FE, &FF BAAA C9 FE CMP #&FE ;is service call number <&FE? BAAC 90 5C BCC SB0A ;if so then return to process other calls BAAE D0 1B BNE SACB ;if A=&FF then branch to do main init, else: BAB0 C0 00 CPY #&00 ;Service call &FE = Tube post initialisation BAB2 F0 56 BEQ SB0A ;ignore call if Y=0 on entry BAB4 A2 06 LDX #&06 ;else X=6 = fully exploded BAB6 A9 14 LDA #&14 ;OSBYTE &14 = explode soft character RAM BAB8 20 F4 FF JSR &FFF4 ;call OSBYTE .SABB BABB 2C E0 FE BIT &FEE0 ;print Tube coprocessor banner: BABE 10 FB BPL SABB ;poll until character in R1DATA BAC0 AD E1 FE LDA &FEE1 ;then read R1DATA BAC3 F0 43 BEQ SB08 ;if =NUL then claim service call and exit BAC5 20 EE FF JSR &FFEE ;else print the character & loop BAC8 4C BB BA JMP SABB .SACB ;Service call &FF = Tube main initialisation BACB A9 AD LDA #&AD ;EVNTV = &06AD BACD 8D 20 02 STA &0220 BAD0 A9 06 LDA #&06 BAD2 8D 21 02 STA &0221 BAD5 A9 16 LDA #&16 ;BRKV = &0016 BAD7 8D 02 02 STA &0202 BADA A9 00 LDA #&00 BADC 8D 03 02 STA &0203 BADF A9 8E LDA #&8E ;set Tube status (NAUG p.329) BAE1 8D E0 FE STA &FEE0 ;enable NMI on R3, IRQ on R1,R4 BAE4 A0 00 LDY #&00 ;initialise offset to 0: .SAE6 BAE6 B9 4C BB LDA &BB4C,Y ;copy Tube host code from &BB4C..&BE4B BAE9 99 00 04 STA &0400,Y ;to &0400..&06FF BAEC B9 4C BC LDA &BC4C,Y ;offset 0 first, then 255..1 BAEF 99 00 05 STA &0500,Y BAF2 B9 4C BD LDA &BD4C,Y BAF5 99 00 06 STA &0600,Y BAF8 88 DEY BAF9 D0 EB BNE SAE6 BAFB 20 21 04 JSR &0421 ;mark Tube unclaimed BAFE A2 60 LDX #&60 ;initialise offset to &60 .SB00 BB00 BD 0B BB LDA &BB0B,X ;copy Tube BRK handler from &BB0B..6B BB03 95 16 STA &16,X ;to &0016..76 BB05 CA DEX BB06 10 F8 BPL SB00 .SB08 BB08 A9 00 LDA #&00 ;return A=0 to claim service call .SB0A BB0A 60 RTS ;Tube BRK handler copied to &0016..76 BB0B A9 FF LDA #&FF ;set A=&FF to interrupt coprocessor (JGH) BB0D 20 9E 06 JSR &069E ;write A to R4DATA BB10 AD E3 FE LDA &FEE3 ;empty inward R2DATA and discard byte BB13 A9 00 LDA #&00 ;set A=0 to specify error (JGH) BB15 20 95 06 JSR &0695 ;write A to R2DATA BB18 A8 TAY ;set Y=0 offset into error message BB19 B1 FD LDA (&FD),Y ;get error number at MOS error pointer BB1B 20 95 06 JSR &0695 ;write A to R2DATA .SB1E BB1E C8 INY ;increment offset BB1F B1 FD LDA (&FD),Y ;get character of error message BB21 20 95 06 JSR &0695 ;write A to R2DATA BB24 AA TAX ;test last character written BB25 D0 F7 BNE SB1E ;loop until it is NUL BB27 A2 FF LDX #&FF ;reset stack pointer BB29 9A TXS BB2A 58 CLI ;enable interrupts: .SB2B ;0036 Idle loop BB2B 2C E0 FE BIT &FEE0 ;test R1STAT BB2E 10 06 BPL SB36 ;if b7=1, data available .SB30 BB30 AD E1 FE LDA &FEE1 ;then read R1DATA to A BB33 20 EE FF JSR &FFEE ;call OSWRCH. .SB36 BB36 2C E2 FE BIT &FEE2 ;test R2STAT BB39 10 F0 BPL SB2B ;if b7=0, data not available then test R1 BB3B 2C E0 FE BIT &FEE0 ;else Tube call waiting. test R1STAT BB3E 30 F0 BMI SB30 ;first print waiting bytes to OSWRCH (if any) BB40 AE E3 FE LDX &FEE3 ;then read R2DATA to X =call number BB43 86 51 STX &51 ;modify LSB indirect address of next inst. BB45 6C 00 05 JMP (&0500) ;0050 handle Tube call via jump table ;Default Tube entry address = &00008000 BB48 EQUB &00 BB49 EQUB &80 BB4A EQUB &00 BB4B EQUB &00 ;Tube host code copied to &0400..&06FF ;0400 Copy language to coprocessor (NAUG) BB4C 4C 84 04 JMP &0484 ;0403 Copy ESCAPE flag to coprocessor (NAUG) BB4F 4C A7 06 JMP &06A7 ;0406 Tube service entry BB52 C9 80 CMP #&80 ;if A = &00..7F BB54 90 2B BCC SB81 ;then set up data transfer BB56 C9 C0 CMP #&C0 ;else if A = &C0..FF BB58 B0 1A BCS SB74 ;then handle Tube claim BB5A 09 40 ORA #&40 ;else A=&80..BF release Tube BB5C C5 15 CMP &15 ;set b6=1 to compare with claimant ID BB5E D0 20 BNE SB80 ;if releaser is not claimant then ignore else: ;0414 Release Tube BB60 08 PHP ;save interrupt state BB61 78 SEI ;disable interrupts BB62 A9 05 LDA #&05 ;type byte=5 No transfer (FS release) BB64 20 9E 06 JSR &069E ;write A to R4DATA BB67 A5 15 LDA &15 ;set A=claimant ID BB69 20 9E 06 JSR &069E ;write A to R4DATA BB6C 28 PLP ;restore interrupt state: BB6D A9 80 LDA #&80 ;0421 Mark Tube unclaimed BB6F 85 15 STA &15 ;not in range &C0..FF =no claimant BB71 85 14 STA &14 ;&80=Tube unclaimed BB73 60 RTS .SB74 ;0428 Claim Tube BB74 06 14 ASL &14 ;&00=Tube claimed BB76 B0 06 BCS SB7E ;if it was unclaimed then set claimant BB78 C5 15 CMP &15 ;else compare caller's ID - current claimant BB7A F0 04 BEQ SB80 ;if same claimant reclaims then return C=1 BB7C 18 CLC ;else reject claim, return C=0 BB7D 60 RTS .SB7E BB7E 85 15 STA &15 ;set current claimant, C=1 claim granted .SB80 BB80 60 RTS .SB81 ;0435 Set up data transfer BB81 08 PHP ;save interrupt state BB82 78 SEI ;disable interrupts BB83 84 13 STY &13 ;set control block pointer from XY BB85 86 12 STX &12 ;a=type byte/reason code BB87 20 9E 06 JSR &069E ;write A to R4DATA BB8A AA TAX ;hold type byte in X BB8B A0 03 LDY #&03 ;1+4 bytes to write BB8D A5 15 LDA &15 ;set A=claimant ID BB8F 20 9E 06 JSR &069E ;write A to R4DATA: .SB92 BB92 B1 12 LDA (&12),Y ;get byte of transfer address, MSB to LSB BB94 20 9E 06 JSR &069E ;write A to R4DATA BB97 88 DEY ;in descending/big-endian order BB98 10 F8 BPL SB92 ;loop until claimant+4 address bytes written BB9A A0 18 LDY #&18 ;set Tube status (NAUG p.329) BB9C 8C E0 FE STY &FEE0 ;set V,M=0 disable NMI and word mode on R3 BB9F BD 18 05 LDA &0518,X ;get status setting for transfer type in X BBA2 8D E0 FE STA &FEE0 ;write to R1STAT BBA5 4A LSR A ;test I in bit 1 = modify interrupts on R1 BBA6 4A LSR A ;(if I was modified, then I was set) BBA7 90 06 BCC SBAF ;if interrupts were enabled on R1 BBA9 2C E5 FE BIT &FEE5 ;then transferring to host (C=1, used later) BBAC 2C E5 FE BIT &FEE5 ;discard word in R3 to empty it .SBAF BBAF 20 9E 06 JSR &069E ;write A to R4DATA = synchronising byte .SBB2 BBB2 2C E6 FE BIT &FEE6 ;wait for it to be taken; test R4STAT BBB5 50 FB BVC SBB2 ;loop until b6=1, not full BBB7 B0 0D BCS SBC6 ;if transferring to host then branch BBB9 E0 04 CPX #&04 ;else if type<>4 address only BBBB D0 11 BNE SBCE ;then return without handshake, else: .SBBD ;0471 Release Tube with handshake BBBD 20 14 04 JSR &0414 ;release Tube BBC0 20 95 06 JSR &0695 ;write A to R2DATA =&80 =transfer complete ;This value is used by code implementing OSCLI on the coprocessor to decide ;whether to return to the user or to jump to code at the type 4 transfer ;address. This call does not return. If the *command is not a binary to ;download to the coprocessor, DDOS's OSCLI code returns to the MOS which in ;turn exits to &059C (&BCE8), and there &7F is written to R2DATA indicating ;command completion. If that value is the first to arrive, it means there was ;no type 4 transfer address issued, and the coprocessor's OSCLI returns. BBC3 4C 32 00 JMP &0032 ;go to idle loop .SBC6 BBC6 4A LSR A ;test J in bit 2 = modify interrupts on R4 BBC7 90 05 BCC SBCE ;if J=1, types 0 or 2, bytes/words to host BBC9 A0 88 LDY #&88 BBCB 8C E0 FE STY &FEE0 ;then set M=1 enable NMIs on R3 .SBCE BBCE 28 PLP ;restore interrupt state BBCF 60 RTS ;0484 Copy language to coprocessor (NAUG) BBD0 58 CLI ;enable interrupts BBD1 B0 11 BCS SBE4 ;if C=1, entry from *FX142 (JGH) then copy BBD3 D0 03 BNE SBD8 ;else if A>0 then enter language (JGH) BBD5 4C 9C 05 JMP &059C ;else A=0 no language, signal completion .SBD8 BBD8 A2 00 LDX #&00 ;set X=&00 do not alter BBDA A0 FF LDY #&FF ;set Y=&FF do not update BBDC A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset BBDE 20 F4 FF JSR &FFF4 ;call OSBYTE BBE1 8A TXA ;if type = 0 soft BREAK BBE2 F0 D9 BEQ SBBD ;then release Tube and write &80 to R2DATA .SBE4 BBE4 A9 FF LDA #&FF ;&FF = claim Tube with claimant ID = &3F BBE6 20 06 04 JSR &0406 ;call Tube service BBE9 90 F9 BCC SBE4 ;loop until claim granted BBEB 20 D2 04 JSR &04D2 ;set up Tube destination address .SBEE BBEE A9 07 LDA #&07 ;type byte = 7, 256 byte transfer to host BBF0 20 CB 04 JSR &04CB ;set up Tube data transfer BBF3 A0 00 LDY #&00 ;clear page offset BBF5 84 00 STY &00 ;align ROM pointer to page boundary .SBF7 BBF7 B1 00 LDA (&00),Y ;get byte from ROM BBF9 8D E5 FE STA &FEE5 ;write A to R3DATA BBFC EA NOP ;wait 3 microseconds BBFD EA NOP BBFE EA NOP BBFF C8 INY ;increment offset BC00 D0 F5 BNE SBF7 ;loop until page boundary reached (10us/byte) BC02 E6 54 INC &54 ;then add 256 to Tube transfer address BC04 D0 06 BNE SC0C ;carry out to 2MSB BC06 E6 55 INC &55 BC08 D0 02 BNE SC0C ;and MSB BC0A E6 56 INC &56 .SC0C BC0C E6 01 INC &01 ;increment MSB of ROM pointer BC0E 24 01 BIT &01 ;test b14 of ROM pointer BC10 50 DC BVC SBEE ;loop until b14=1, when it has reached &C000 BC12 20 D2 04 JSR &04D2 ;set up Tube destination address BC15 A9 04 LDA #&04 ;type byte = 4 no transfer, execute 2P code: ;04CB set up Tube data transfer BC17 A0 00 LDY #&00 ;point XY at Tube transfer address at &0053 BC19 A2 53 LDX #&53 BC1B 4C 06 04 JMP &0406 ;jump into Tube service. ;04D2 Set up Tube destination address BC1E A9 80 LDA #&80 BC20 85 54 STA &54 ;set 3MSB of Tube transfer address = &80 BC22 85 01 STA &01 ;set MSB of ROM pointer = &80 BC24 A9 20 LDA #&20 ;set b5=1 to test custom address flag BC26 2D 06 80 AND &8006 ;AND with ROM type byte BC29 A8 TAY ;place result in AY for MSB, 2MSB of addr BC2A 84 53 STY &53 ;store as LSB (on the assumption that it's 0) BC2C F0 19 BEQ SC47 ;if b5=0 then no custom addr, set &00008000 BC2E AE 07 80 LDX &8007 ;else get offset of copyright string .SC31 BC31 E8 INX ;skip leading NUL, increment offset BC32 BD 00 80 LDA &8000,X ;test character of copyright string BC35 D0 FA BNE SC31 ;loop until terminating NUL reached BC37 BD 01 80 LDA &8001,X ;store next byte as LSB of Tube address BC3A 85 53 STA &53 BC3C BD 02 80 LDA &8002,X ;store byte after that as 3MSB BC3F 85 54 STA &54 BC41 BC 03 80 LDY &8003,X ;get next byte as 2MSB BC44 BD 04 80 LDA &8004,X ;get byte after that as MSB: .SC47 BC47 85 56 STA &56 ;store MSB of Tube transfer address BC49 84 55 STY &55 ;store 2MSB of Tube transfer address BC4B 60 RTS ;0500 Tube call handler jump table (SB) BC4C EQUW &37,&05 ;R2 was &00 - jump osrdch_call BC4E EQUW &96,&05 ;R2 was &02 - jump oscli_call BC50 EQUW &F2,&05 ;R2 was &04 - jump short_osbyte BC52 EQUW &07,&06 ;R2 was &06 - jump long_osbyte BC54 EQUW &27,&06 ;R2 was &08 - jump osword_call BC56 EQUW &68,&06 ;R2 was &0A - jump osword0_call BC58 EQUW &5E,&05 ;R2 was &0C - jump osargs_call BC5A EQUW &2D,&05 ;R2 was &0E - jump osbget_call BC5C EQUW &20,&05 ;R2 was &10 - jump osbput_call BC5E EQUW &42,&05 ;R2 was &12 - jump osfind_call BC60 EQUW &A9,&05 ;R2 was &14 - jump osfile_call BC62 EQUW &D1,&05 ;R2 was &16 - jump osgbpb_call ;0518 Tube status settings for transfer types 0..7 BC64 EQUB &86 ;0=bytes to host J,I=1 enable IRQ on R4,R1 BC65 EQUB &88 ;1=bytes from host M=1 enable NMI on R3 BC66 EQUB &96 ;2=words to host V,J,I=1 enable IRQ on R4,R1 BC67 EQUB &98 ;3=words from host V,M=1 enable NMI on R3 BC68 EQUB &18 ;4=address only V,M=0 disable NMI on R3 BC69 EQUB &18 ;5=(reserved) V,M=0 disable NMI on R3 BC6A EQUB &82 ;6=page to host I=1 enable IRQ on R1 BC6B EQUB &18 ;7=page from host V,M=0 disable NMI on R3 ;osbput_call BC6C 20 C5 06 JSR &06C5 ;read R2DATA to A BC6F A8 TAY ;set Y=channel BC70 20 C5 06 JSR &06C5 ;read R2DATA to A =byte to write BC73 20 D4 FF JSR &FFD4 ;call OSBPUT BC76 4C 9C 05 JMP &059C ;signal completion ;osbget_call BC79 20 C5 06 JSR &06C5 ;read R2DATA to A BC7C A8 TAY ;set Y=channel BC7D 20 D7 FF JSR &FFD7 ;call OSBGET BC80 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;osrdch_call BC83 20 E0 FF JSR &FFE0 ;call OSRDCH ;053A send C, A to R2DATA and idle BC86 6A ROR A ;rotate C into A b7, save A b0 in C BC87 20 95 06 JSR &0695 ;write A to R2DATA BC8A 2A ROL A ;restore A on entry BC8B 4C 9E 05 JMP &059E ;write to R2DATA and idle ;osfind_call BC8E 20 C5 06 JSR &06C5 ;read R2DATA to A BC91 F0 0B BEQ SC9E ;if A=0 then close file BC93 48 PHA ;else save A=call no. = open mode BC94 20 82 05 JSR &0582 ;read string to buffer BC97 68 PLA ;restore A BC98 20 CE FF JSR &FFCE ;call OSFIND BC9B 4C 9E 05 JMP &059E ;write to R2DATA and idle .SC9E ;read R2DATA to A BC9E 20 C5 06 JSR &06C5 ;set Y=file handle BCA1 A8 TAY ;restore A=0 call no. = close file BCA2 A9 00 LDA #&00 ;call OSFIND BCA4 20 CE FF JSR &FFCE ;signal completion BCA7 4C 9C 05 JMP &059C ;osargs_call BCAA 20 C5 06 JSR &06C5 ;read R2DATA to A BCAD A8 TAY ;set Y=channel BCAE A2 04 LDX #&04 ;4 bytes to read: .SCB0 BCB0 20 C5 06 JSR &06C5 ;read R2DATA to A BCB3 95 FF STA &FF,X ;save in locations 3..0 BCB5 CA DEX ;in descending order BCB6 D0 F8 BNE SCB0 ;loop until X bytes read BCB8 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BCBB 20 DA FF JSR &FFDA ;call OSARGS BCBE 20 95 06 JSR &0695 ;write A to R2DATA =return value BCC1 A2 03 LDX #&03 ;4 bytes to write: .SCC3 BCC3 B5 00 LDA &00,X ;get locations 3..0 BCC5 20 95 06 JSR &0695 ;write A to R2DATA BCC8 CA DEX ;in descending order BCC9 10 F8 BPL SCC3 ;loop until X+1 bytes written BCCB 4C 36 00 JMP &0036 ;go to idle loop ;0582 read string to buffer BCCE A2 00 LDX #&00 ;set X=0 LSB of buffer address BCD0 A0 00 LDY #&00 ;set Y=0 buffer offset .SCD2 BCD2 20 C5 06 JSR &06C5 ;read R2DATA to A BCD5 99 00 07 STA &0700,Y ;save in string buffer BCD8 C8 INY ;in ascending order, increment offset BCD9 F0 04 BEQ SCDF ;if end of buffer reached then stop BCDB C9 0D CMP #&0D ;else test character read BCDD D0 F3 BNE SCD2 ;if =CR then string terminated else loop .SCDF BCDF A0 07 LDY #&07 ;set Y=&07 MSB of buffer address BCE1 60 RTS ;oscli_call BCE2 20 82 05 JSR &0582 ;read string to buffer BCE5 20 F7 FF JSR &FFF7 ;call OSCLI ;059C Signal completion BCE8 A9 7F LDA #&7F .SCEA ;059E Write to R2DATA and idle BCEA 2C E2 FE BIT &FEE2 ;test R2STAT BCED 50 FB BVC SCEA ;loop until b6=1, not full BCEF 8D E3 FE STA &FEE3 ;write A to R2DATA .SCF2 BCF2 4C 36 00 JMP &0036 ;go to idle loop ;osfile_call BCF5 A2 10 LDX #&10 ;16 bytes to read: .SCF7 BCF7 20 C5 06 JSR &06C5 ;read R2DATA to A BCFA 95 01 STA &01,X ;save to locations 17..2 BCFC CA DEX ;in descending order BCFD D0 F8 BNE SCF7 ;loop until X bytes read BCFF 20 82 05 JSR &0582 ;read string to buffer BD02 86 00 STX &00 ;save buffer address at 0,1 BD04 84 01 STY &01 ;=&0700 BD06 A0 00 LDY #&00 ;set Y=0; X=0 from 0582 BD08 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD0B 20 DD FF JSR &FFDD ;call OSFILE BD0E 20 95 06 JSR &0695 ;write A to R2DATA =return value BD11 A2 10 LDX #&10 ;16 bytes to write: .SD13 BD13 B5 01 LDA &01,X ;get locations 17..2 BD15 20 95 06 JSR &0695 ;write A to R2DATA BD18 CA DEX ;in descending order BD19 D0 F8 BNE SD13 ;loop until X bytes written BD1B F0 D5 BEQ SCF2 ;then go to idle loop ;osgbpb_call BD1D A2 0D LDX #&0D ;13 bytes to read: .SD1F BD1F 20 C5 06 JSR &06C5 ;read R2DATA to A BD22 95 FF STA &FF,X ;save to locations 12..0 BD24 CA DEX ;in descending order BD25 D0 F8 BNE SD1F ;loop until X bytes read BD27 20 C5 06 JSR &06C5 ;read R2DATA to A BD2A A0 00 LDY #&00 ;set Y=0; X=0 from loop BD2C 20 D1 FF JSR &FFD1 ;call OSGBPB BD2F 48 PHA ;save return value BD30 A2 0C LDX #&0C ;13 bytes to write: .SD32 BD32 B5 00 LDA &00,X ;get locations 12..0 BD34 20 95 06 JSR &0695 ;write A to R2DATA BD37 CA DEX ;in descending order BD38 10 F8 BPL SD32 ;loop until X bytes written BD3A 68 PLA ;restore A=return value BD3B 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;short_osbyte BD3E 20 C5 06 JSR &06C5 ;read R2DATA to A BD41 AA TAX ;save X=first parameter BD42 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD45 20 F4 FF JSR &FFF4 ;call OSBYTE .SD48 BD48 2C E2 FE BIT &FEE2 ;test R2STAT BD4B 50 FB BVC SD48 ;loop until b6=1, not full BD4D 8E E3 FE STX &FEE3 ;write X to R2DATA =result .SD50 BD50 4C 36 00 JMP &0036 ;go to idle loop ;long_osbyte BD53 20 C5 06 JSR &06C5 ;read R2DATA to A BD56 AA TAX ;set X=first parameter BD57 20 C5 06 JSR &06C5 ;read R2DATA to A BD5A A8 TAY ;set Y=second parameter BD5B 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD5E 20 F4 FF JSR &FFF4 ;call OSBYTE BD61 49 9D EOR #&9D ;if A=&9D fast Tube BPUT BD63 F0 EB BEQ SD50 ;then end call without handshake BD65 6A ROR A ;else rotate C into A b7 BD66 20 95 06 JSR &0695 ;write A to R2DATA .SD69 BD69 2C E2 FE BIT &FEE2 ;test R2STAT BD6C 50 FB BVC SD69 ;loop until b6=1, not full BD6E 8C E3 FE STY &FEE3 ;write Y to R2DATA =second result BD71 70 D5 BVS SD48 ;write X to R2DATA and idle (always) ;osword_call BD73 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD76 A8 TAY ;hold in Y .SD77 BD77 2C E2 FE BIT &FEE2 ;test R2STAT BD7A 10 FB BPL SD77 ;loop until b7=1, data available BD7C AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD7F CA DEX ;decrement X BD80 30 0F BMI SD91 ;if X was not in range 1..128 then no bytes .SD82 BD82 2C E2 FE BIT &FEE2 ;else test R2STAT BD85 10 FB BPL SD82 ;loop until b7=1, data available BD87 AD E3 FE LDA &FEE3 ;read R2DATA to A BD8A 9D 28 01 STA &0128,X ;save to locations &0128+(X-1..0) BD8D CA DEX ;in descending order BD8E 10 F2 BPL SD82 ;loop until X bytes written BD90 98 TYA ;restore A=call number .SD91 BD91 A2 28 LDX #&28 ;point XY to OSWORD control block at &0128 BD93 A0 01 LDY #&01 BD95 20 F1 FF JSR &FFF1 ;call OSWORD .SD98 BD98 2C E2 FE BIT &FEE2 ;test R2STAT BD9B 10 FB BPL SD98 ;loop until b7=1, data available BD9D AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BDA0 CA DEX ;decrement X BDA1 30 0E BMI SDB1 ;if X was not in range 1..128 then no bytes .SDA3 BDA3 BC 28 01 LDY &0128,X ;else get byte of control block at ..&0128 .SDA6 BDA6 2C E2 FE BIT &FEE2 ;test R2STAT BDA9 50 FB BVC SDA6 ;loop until b6=1, not full BDAB 8C E3 FE STY &FEE3 ;write Y to R2DATA BDAE CA DEX ;in descending order BDAF 10 F2 BPL SDA3 ;loop until X bytes written .SDB1 BDB1 4C 36 00 JMP &0036 ;go to idle loop ;osword0_call BDB4 A2 04 LDX #&04 ;5 bytes to read: .SDB6 BDB6 20 C5 06 JSR &06C5 ;read R2DATA to A BDB9 95 00 STA &00,X ;save to locations 4..0 BDBB CA DEX ;in descending order BDBC 10 F8 BPL SDB6 ;loop until X+1 bytes read BDBE E8 INX ;set X=0 BDBF A0 00 LDY #&00 ;set Y=0; point XY to OSWORD control block BDC1 8A TXA ;set A=0 read line from input stream BDC2 20 F1 FF JSR &FFF1 ;call OSWORD BDC5 90 05 BCC SDCC ;if user pressed ESCAPE BDC7 A9 FF LDA #&FF ;then A=&FF carry set/error condition BDC9 4C 9E 05 JMP &059E ;write to R2DATA and idle .SDCC BDCC A2 00 LDX #&00 ;else X=0 offset into string buffer BDCE A9 7F LDA #&7F ;set A=&7F carry clear/no error BDD0 20 95 06 JSR &0695 ;write A to R2DATA .SDD3 BDD3 BD 00 07 LDA &0700,X ;get character from string buffer BDD6 20 95 06 JSR &0695 ;write A to R2DATA BDD9 E8 INX ;increment offset BDDA C9 0D CMP #&0D ;test character just written BDDC D0 F5 BNE SDD3 ;if =CR then string terminated else loop BDDE 4C 36 00 JMP &0036 ;go to idle loop .SDE1 ;0695 Write A to R2DATA BDE1 2C E2 FE BIT &FEE2 ;test R2STAT BDE4 50 FB BVC SDE1 ;loop until b6=1, not full BDE6 8D E3 FE STA &FEE3 ;write A to R2DATA BDE9 60 RTS .SDEA ;069E Write A to R4DATA BDEA 2C E6 FE BIT &FEE6 ;test R4STAT BDED 50 FB BVC SDEA ;loop until b6=1, not full BDEF 8D E7 FE STA &FEE7 ;write A to R4DATA BDF2 60 RTS ;06A7 Copy ESCAPE flag to coprocessor (NAUG) BDF3 A5 FF LDA &FF ;get MOS ESCAPE flag BDF5 38 SEC ;rotate 1 into bit 7, ESCAPE flag in bit 6 BDF6 6A ROR A ;A >= &80 indicating ESCAPE flag update BDF7 30 0F BMI SE08 ;write A to R1DATA (always) ;06AD Event handler BDF9 48 PHA ;save event type BDFA A9 00 LDA #&00 ;set A=&00 to indicate event BDFC 20 BC 06 JSR &06BC ;write A to R1DATA BDFF 98 TYA ;transfer Y=second event parameter to A BE00 20 BC 06 JSR &06BC ;write A to R1DATA BE03 8A TXA ;transfer X=first event parameter to A BE04 20 BC 06 JSR &06BC ;write A to R1DATA BE07 68 PLA ;restore event type to A: .SE08 ;06BC Write A to R1DATA BE08 2C E0 FE BIT &FEE0 ;test R1STAT BE0B 50 FB BVC SE08 ;loop until b6=1, not full BE0D 8D E1 FE STA &FEE1 ;write A to R1DATA BE10 60 RTS .SE11 ;06C5 Read R2DATA to A BE11 2C E2 FE BIT &FEE2 ;test R2STAT BE14 10 FB BPL SE11 ;loop until b7=1, data available BE16 AD E3 FE LDA &FEE3 ;read R2DATA to A and return BE19 60 RTS .SE1A ;Print "COPYRIGHT NOTICE" BE1A 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE1D EQUB &83 ;yellow alphanumerics BE1E EQUB &8D ;double height BE1F EQUS " C O P Y R I G H T N O T I C E" BE3F EQUB &0D BE40 EQUB &0A BE41 EQUB &FF BE42 60 RTS ;*COPYRIGHT BE43 20 74 AD JSR RD74 ;set display MODE 7 BE46 20 67 84 JSR P467 ;print newline BE49 20 1A BE JSR SE1A ;print "COPYRIGHT NOTICE" twice BE4C 20 1A BE JSR SE1A BE4F 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE52 EQUB &0D BE53 EQUB &0A BE54 EQUB &0A BE55 EQUS "This Double Density Operating System" BE79 EQUB &0D BE7A EQUB &0A BE7B EQUS "was developed for the BBC computer by" BEA0 EQUB &0D BEA1 EQUB &0A BEA2 EQUB &83 ;yellow alphanumerics BEA3 EQUS "SLOGGER SOFTWARE and OPUS SUPPLIES" BEC5 EQUB &0D BEC6 EQUB &0A BEC7 EQUS "Any unauthorised copying of this" BEE7 EQUB &0D BEE8 EQUB &0A BEE9 EQUS "product is unlawful and may result in" BF0E EQUB &0D BF0F EQUB &0A BF10 EQUS "Slogger or Opus taking appropriate" BF32 EQUB &0D BF33 EQUB &0A BF34 EQUS "action." BF3B EQUB &0D BF3C EQUB &0A BF3D EQUB &0A BF3E EQUB &FF BF3F 60 RTS BF80 EQUB &FF,&FF,&FF,&FF BF84 EQUB &FF,&FF,&FF,&FF BF88 EQUB &FF,&FF,&FF,&FF BF8C EQUB &FF,&FF,&FF,&FF BF90 EQUB &FF,&FF,&FF,&FF BF94 EQUB &FF,&FF,&FF,&FF BF98 EQUB &FF,&FF,&FF,&FF BF9C EQUB &FF,&FF,&FF,&FF BFA0 EQUB &FF,&FF,&FF,&FF BFA4 EQUB &FF,&FF,&FF,&FF BFA8 EQUB &FF,&FF,&FF,&FF BFAC EQUB &FF,&FF,&FF,&FF BFB0 EQUB &FF,&FF,&FF,&FF BFB4 EQUB &FF,&FF,&FF,&FF BFB8 EQUB &FF,&FF,&FF,&FF BFBC EQUB &FF,&FF,&FF,&FF BFC0 EQUB &FF,&FF,&FF,&FF BFC4 EQUB &FF,&FF,&FF,&FF BFC8 EQUB &FF,&FF,&FF,&FF BFCC EQUB &FF,&FF,&FF,&FF BFD0 EQUB &FF,&FF,&FF,&FF BFD4 EQUB &FF,&FF,&FF,&FF BFD8 EQUB &FF,&FF,&FF,&FF BFDC EQUB &FF,&FF,&FF,&FF BFE0 EQUB &FF,&FF,&FF,&FF BFE4 EQUB &FF,&FF,&FF,&FF BFE8 EQUB &FF,&FF,&FF,&FF BFEC EQUB &FF,&FF,&FF,&FF BFF0 EQUB &FF,&FF,&FF,&FF BFF4 EQUB &FF,&FF,&FF,&FF BFF8 EQUB &FF,&FF,&FF,&FF BFFC EQUB &FF,&FF,&FF,&FF # else /* _DDOS346 */ ;////////////////////////////////////////////// COMMON .SA03 ;Wait for command completion # if defined _TURBO BA03 20 2D A3 JSR R32D ;save XY # else BA03 20 29 A3 JSR R329 ;save XY # endif BA06 A2 FF LDX #&FF ;wait 638 microseconds .SA08 BA08 CA DEX BA09 D0 FD BNE SA08 .SA0B BA0B 20 11 BA JSR SA11 ;load FDC status register BA0E 6A ROR A ;place bit 0 in carry flag BA0F B0 FA BCS SA0B ;loop until b0=0 WD1770 S0 = busy .SA11 # if defined _DDOS356 BA11 AD 28 FE LDA &FE28 ;load FDC status register # elif defined _DDOS357 BA11 AD 28 FE LDA &FE28 ;load FDC status register # elif defined _DDOS326 BA11 AD 84 FE LDA &FE84 ;load FDC status register # else BA11 AD 80 FE LDA &FE80 ;load FDC status register # endif BA14 29 7F AND #&7F ;mask bits 6..0 ignore WD1770 S7 = motor on BA16 8D 8F 10 STA &108F ;save final status BA19 60 RTS ;Table of WD1770 FDC commands for data transfer call numbers 0..4 BA1A EQUB &90 ;&00 = Read data BA1B EQUB &B4 ;&01 = Write data BA1C EQUB &90 BA1D EQUB &B5 ;&03 = Write deleted data BA1E EQUB &90 ;&04 = Verify data ;Table of status mask bytes for data transfer call numbers 0..4 ;{RecordNotFound CRCError LostData} (&1C) plus: BA1F EQUB &3C ;&00 = Read data: {RecordType} BA20 EQUB &7C ;&01 = Write data: {WriteProtect RecordType} BA21 EQUB &1C ;{} BA22 EQUB &5C ;&03 = Write deleted data: {WriteProtect} BA23 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) BA24 8D 2A 0D STA &0D2A ;save accumulator to restore on exit # if defined _DDOS356 BA27 AD 2B FE LDA &FE2B ;read FDC data register # elif defined _DDOS357 BA27 AD 2B FE LDA &FE2B ;read FDC data register # elif defined _DDOS326 BA27 AD 87 FE LDA &FE87 ;read FDC data register # else BA27 AD 83 FE LDA &FE83 ;read FDC data register # endif BA2A 8D FF FF STA &FFFF ;store in user memory or R3DATA BA2D EE 07 0D INC &0D07 ;increment user memory address BA30 D0 03 BNE SA35 ;carry out to high byte BA32 EE 08 0D INC &0D08 .SA35 BA35 C6 A0 DEC &A0 ;decrement count of bytes to transfer BA37 D0 14 BNE SA4D ;(&0101 = 1; &0000 = 0) BA39 C6 A1 DEC &A1 ;if count has not reached zero BA3B D0 10 BNE SA4D ;then restore A and return from interrupt BA3D A9 40 LDA #&40 ;else set 0D00=RTI; ignore further NMIs # if defined _BEEBEM ;Patch to get BeebEm to write the last byte of a track. NOT FOR HARDWARE ;ISR seals itself too late, real hardware may read one excess byte at DD BA3F 20 3D 0D JSR &0D3D ;call trampoline and come back with an RTI ;ISR safe by 25+e..32.5 us after NMI ;write complete by 27.5+e..35 us BA42 EQUW &41,&0D ;does ORA &0D41; A=&CE # else BA3F 8D 00 0D STA &0D00 ;ISR safe by 22+e..29.5 us after NMI ;write complete by 24.5+e..32 us BA42 A9 CE LDA #&CE ;wait 123 microseconds (if loop enabled) # endif BA44 69 01 ADC #&01 BA46 90 00 BCC SA48 ;0D23=&FC loops back to &0D20 .SA48 BA48 A9 D0 LDA #&D0 ;FDC command &D0 = Force Interrupt # if defined _DDOS356 BA4A 8D 28 FE STA &FE28 ;write to FDC command register # elif defined _DDOS357 BA4A 8D 28 FE STA &FE28 ;write to FDC command register # elif defined _DDOS326 BA4A 8D 84 FE STA &FE84 ;write to FDC command register # else BA4A 8D 80 FE STA &FE80 ;write to FDC command register # endif .SA4D BA4D A9 00 LDA #&00 ;restore value of A on entry BA4F 40 RTI ;return from interrupt BA50 A9 0E LDA #&0E ;NMI polling loop, &0D2C..3C BA52 8D 30 FE STA &FE30 ;page *SROM slot in .SA55 # if defined _DDOS356 BA55 AD 28 FE LDA &FE28 ;load FDC status register # elif defined _DDOS357 BA55 AD 28 FE LDA &FE28 ;load FDC status register # elif defined _DDOS326 BA55 AD 84 FE LDA &FE84 ;load FDC status register # else BA55 AD 80 FE LDA &FE80 ;load FDC status register # endif BA58 6A ROR A ;place bit 0 in carry flag BA59 B0 FA BCS SA55 ;loop until b0=0 WD1770 S0 = busy BA5B A9 00 LDA #&00 ;page DDOS ROM back in BA5D 8D 30 FE STA &FE30 BA60 60 RTS BA61 AD FF FF LDA &FFFF ;NMI write to disc, &0D03..10 # if defined _DDOS356 BA64 8D 2B FE STA &FE2B # elif defined _DDOS357 BA64 8D 2B FE STA &FE2B # elif defined _DDOS326 BA64 8D 87 FE STA &FE87 # else BA64 8D 83 FE STA &FE83 # endif BA67 EE 04 0D INC &0D04 BA6A D0 03 BNE SA6F BA6C EE 05 0D INC &0D05 .SA6F BA6F 8D 13 0D STA &0D13 ;NMI read ID, &0D00..14 BA72 8C 11 0D STY &0D11 ;save AY to restore on exit BA75 A4 A0 LDY &A0 ;load offset in Y # if defined _DDOS356 BA77 AD 2B FE LDA &FE2B ;load FDC data register # elif defined _DDOS357 BA77 AD 2B FE LDA &FE2B ;load FDC data register # elif defined _DDOS326 BA77 AD 87 FE LDA &FE87 ;load FDC data register # else BA77 AD 83 FE LDA &FE83 ;load FDC data register # endif BA7A 99 90 10 STA &1090,Y ;store ID byte in buffer BA7D E6 A0 INC &A0 ;increment offset BA7F A0 00 LDY #&00 ;restore AY on entry BA81 A9 00 LDA #&00 BA83 40 RTI ;A run-length encoded table of formatting bytes is stored in two arrays ;starting at &1312 and &1512. Valid range of counts is &01..&80. ;When the byte source address crosses a page, the high byte is incremented ;in the same interrupt and the new count is fetched (from the next page) ;in the next interrupt. One byte from the next page is sent to the ;controller in the meantime, and so the first count of a page is one less ;than the number of bytes actually sent, i.e. the first byte of the page ;cannot be a singleton. The page crossing occurs 1/8th of the way through ;the data area of the eleventh sector after the index pulse. BA84 48 PHA ;NMI format, &0D00..23 BA85 AD 12 13 LDA &1312 ;save A on entry, fetch current data byte # if defined _DDOS356 BA88 8D 2B FE STA &FE2B ;write to FDC data register # elif defined _DDOS357 BA88 8D 2B FE STA &FE2B ;write to FDC data register # elif defined _DDOS326 BA88 8D 87 FE STA &FE87 ;write to FDC data register # else BA88 8D 83 FE STA &FE83 ;write to FDC data register # endif BA8B C6 A0 DEC &A0 ;decrement run counter BA8D D0 0A BNE SA99 ;if all bytes in run written BA8F EE 02 0D INC &0D02 ;then increment data byte address low BA92 D0 0A BNE SA9E ;if no carry then fetch next run length BA94 EE 03 0D INC &0D03 ;else increment data byte address high .SA97 BA97 68 PLA ;restore A on entry BA98 40 RTI ;exit .SA99 BA99 10 FC BPL SA97 ;if run still in progress then exit BA9B EE 1F 0D INC &0D1F ;else page was crossed last time: .SA9E BA9E EE 1E 0D INC &0D1E ;increment run length address BAA1 AD 12 15 LDA &1512 ;fetch next run length BAA4 85 A0 STA &A0 ;set run counter BAA6 68 PLA ;restore A on entry BAA7 40 RTI ;exit ;unreachable code BAA8 EA NOP ;Tube hosting .SAA9 ;Service calls &FE, &FF BAA9 C9 FE CMP #&FE ;is service call number <&FE? BAAB 90 5C BCC SB09 ;if so then return to process other calls BAAD D0 1B BNE SACA ;if A=&FF then branch to do main init, else: BAAF C0 00 CPY #&00 ;Service call &FE = Tube post initialisation BAB1 F0 56 BEQ SB09 ;ignore call if Y=0 on entry BAB3 A2 06 LDX #&06 ;else X=6 = fully exploded BAB5 A9 14 LDA #&14 ;OSBYTE &14 = explode soft character RAM BAB7 20 F4 FF JSR &FFF4 ;call OSBYTE .SABA BABA 2C E0 FE BIT &FEE0 ;print Tube coprocessor banner: BABD 10 FB BPL SABA ;poll until character in R1DATA BABF AD E1 FE LDA &FEE1 ;then read R1DATA BAC2 F0 43 BEQ SB07 ;if =NUL then claim service call and exit BAC4 20 EE FF JSR &FFEE ;else print the character & loop BAC7 4C BA BA JMP SABA .SACA ;Service call &FF = Tube main initialisation BACA A9 AD LDA #&AD ;EVNTV = &06AD BACC 8D 20 02 STA &0220 BACF A9 06 LDA #&06 BAD1 8D 21 02 STA &0221 BAD4 A9 16 LDA #&16 ;BRKV = &0016 BAD6 8D 02 02 STA &0202 BAD9 A9 00 LDA #&00 BADB 8D 03 02 STA &0203 BADE A9 8E LDA #&8E ;set Tube status (NAUG p.329) BAE0 8D E0 FE STA &FEE0 ;enable NMI on R3, IRQ on R1,R4 BAE3 A0 00 LDY #&00 ;initialise offset to 0: .SAE5 BAE5 B9 4B BB LDA &BB4B,Y ;copy Tube host code from &BB4B..&BE4A BAE8 99 00 04 STA &0400,Y ;to &0400..&06FF BAEB B9 4B BC LDA &BC4B,Y ;offset 0 first, then 255..1 BAEE 99 00 05 STA &0500,Y BAF1 B9 4B BD LDA &BD4B,Y BAF4 99 00 06 STA &0600,Y BAF7 88 DEY BAF8 D0 EB BNE SAE5 BAFA 20 21 04 JSR &0421 ;mark Tube unclaimed BAFD A2 60 LDX #&60 ;initialise offset to &60 .SAFF BAFF BD 0A BB LDA &BB0A,X ;copy Tube BRK handler from &BB0A..6A BB02 95 16 STA &16,X ;to &0016..76 BB04 CA DEX BB05 10 F8 BPL SAFF .SB07 BB07 A9 00 LDA #&00 ;return A=0 to claim service call .SB09 BB09 60 RTS ;Tube BRK handler copied to &0016..76 BB0A A9 FF LDA #&FF ;set A=&FF to interrupt coprocessor (JGH) BB0C 20 9E 06 JSR &069E ;write A to R4DATA BB0F AD E3 FE LDA &FEE3 ;empty inward R2DATA and discard byte BB12 A9 00 LDA #&00 ;set A=0 to specify error (JGH) BB14 20 95 06 JSR &0695 ;write A to R2DATA BB17 A8 TAY ;set Y=0 offset into error message BB18 B1 FD LDA (&FD),Y ;get error number at MOS error pointer BB1A 20 95 06 JSR &0695 ;write A to R2DATA .SB1D BB1D C8 INY ;increment offset BB1E B1 FD LDA (&FD),Y ;get character of error message BB20 20 95 06 JSR &0695 ;write A to R2DATA BB23 AA TAX ;test last character written BB24 D0 F7 BNE SB1D ;loop until it is NUL BB26 A2 FF LDX #&FF ;reset stack pointer BB28 9A TXS BB29 58 CLI ;enable interrupts: .SB2A ;0036 Idle loop BB2A 2C E0 FE BIT &FEE0 ;test R1STAT BB2D 10 06 BPL SB35 ;if b7=1, data available .SB2F BB2F AD E1 FE LDA &FEE1 ;then read R1DATA to A BB32 20 EE FF JSR &FFEE ;call OSWRCH. .SB35 BB35 2C E2 FE BIT &FEE2 ;test R2STAT BB38 10 F0 BPL SB2A ;if b7=0, data not available then test R1 BB3A 2C E0 FE BIT &FEE0 ;else Tube call waiting. test R1STAT BB3D 30 F0 BMI SB2F ;first print waiting bytes to OSWRCH (if any) BB3F AE E3 FE LDX &FEE3 ;then read R2DATA to X =call number BB42 86 51 STX &51 ;modify LSB indirect address of next inst. BB44 6C 00 05 JMP (&0500) ;0050 handle Tube call via jump table ;Default Tube entry address = &00008000 BB47 EQUB &00 BB48 EQUB &80 BB49 EQUB &00 BB4A EQUB &00 ;Tube host code copied to &0400..&06FF ;0400 Copy language to coprocessor (NAUG) BB4B 4C 84 04 JMP &0484 ;0403 Copy ESCAPE flag to coprocessor (NAUG) BB4E 4C A7 06 JMP &06A7 ;0406 Tube service entry BB51 C9 80 CMP #&80 ;if A = &00..7F BB53 90 2B BCC SB80 ;then set up data transfer BB55 C9 C0 CMP #&C0 ;else if A = &C0..FF BB57 B0 1A BCS SB73 ;then handle Tube claim BB59 09 40 ORA #&40 ;else A=&80..BF release Tube BB5B C5 15 CMP &15 ;set b6=1 to compare with claimant ID BB5D D0 20 BNE SB7F ;if releaser is not claimant then ignore else: ;0414 Release Tube BB5F 08 PHP ;save interrupt state BB60 78 SEI ;disable interrupts BB61 A9 05 LDA #&05 ;type byte=5 No transfer (FS release) BB63 20 9E 06 JSR &069E ;write A to R4DATA BB66 A5 15 LDA &15 ;set A=claimant ID BB68 20 9E 06 JSR &069E ;write A to R4DATA BB6B 28 PLP ;restore interrupt state: BB6C A9 80 LDA #&80 ;0421 Mark Tube unclaimed BB6E 85 15 STA &15 ;not in range &C0..FF =no claimant BB70 85 14 STA &14 ;&80=Tube unclaimed BB72 60 RTS .SB73 ;0428 Claim Tube BB73 06 14 ASL &14 ;&00=Tube claimed BB75 B0 06 BCS SB7D ;if it was unclaimed then set claimant BB77 C5 15 CMP &15 ;else compare caller's ID - current claimant BB79 F0 04 BEQ SB7F ;if same claimant reclaims then return C=1 BB7B 18 CLC ;else reject claim, return C=0 BB7C 60 RTS .SB7D BB7D 85 15 STA &15 ;set current claimant, C=1 claim granted .SB7F BB7F 60 RTS .SB80 ;0435 Set up data transfer BB80 08 PHP ;save interrupt state BB81 78 SEI ;disable interrupts BB82 84 13 STY &13 ;set control block pointer from XY BB84 86 12 STX &12 ;a=type byte/reason code BB86 20 9E 06 JSR &069E ;write A to R4DATA BB89 AA TAX ;hold type byte in X BB8A A0 03 LDY #&03 ;1+4 bytes to write BB8C A5 15 LDA &15 ;set A=claimant ID BB8E 20 9E 06 JSR &069E ;write A to R4DATA: .SB91 BB91 B1 12 LDA (&12),Y ;get byte of transfer address, MSB to LSB BB93 20 9E 06 JSR &069E ;write A to R4DATA BB96 88 DEY ;in descending/big-endian order BB97 10 F8 BPL SB91 ;loop until claimant+4 address bytes written BB99 A0 18 LDY #&18 ;set Tube status (NAUG p.329) BB9B 8C E0 FE STY &FEE0 ;set V,M=0 disable NMI and word mode on R3 BB9E BD 18 05 LDA &0518,X ;get status setting for transfer type in X BBA1 8D E0 FE STA &FEE0 ;write to R1STAT BBA4 4A LSR A ;test I in bit 1 = modify interrupts on R1 BBA5 4A LSR A ;(if I was modified, then I was set) BBA6 90 06 BCC SBAE ;if interrupts were enabled on R1 BBA8 2C E5 FE BIT &FEE5 ;then transferring to host (C=1, used later) BBAB 2C E5 FE BIT &FEE5 ;discard word in R3 to empty it .SBAE BBAE 20 9E 06 JSR &069E ;write A to R4DATA = synchronising byte .SBB1 BBB1 2C E6 FE BIT &FEE6 ;wait for it to be taken; test R4STAT BBB4 50 FB BVC SBB1 ;loop until b6=1, not full BBB6 B0 0D BCS SBC5 ;if transferring to host then branch BBB8 E0 04 CPX #&04 ;else if type<>4 address only BBBA D0 11 BNE SBCD ;then return without handshake, else: .SBBC ;0471 Release Tube with handshake BBBC 20 14 04 JSR &0414 ;release Tube BBBF 20 95 06 JSR &0695 ;write A to R2DATA =&80 =transfer complete ;This value is used by code implementing OSCLI on the coprocessor to decide ;whether to return to the user or to jump to code at the type 4 transfer ;address. This call does not return. If the *command is not a binary to ;download to the coprocessor, DDOS's OSCLI code returns to the MOS which in ;turn exits to &059C (&BCE7), and there &7F is written to R2DATA indicating ;command completion. If that value is the first to arrive, it means there was ;no type 4 transfer address issued, and the coprocessor's OSCLI returns. BBC2 4C 32 00 JMP &0032 ;go to idle loop .SBC5 BBC5 4A LSR A ;test J in bit 2 = modify interrupts on R4 BBC6 90 05 BCC SBCD ;if J=1, types 0 or 2, bytes/words to host BBC8 A0 88 LDY #&88 BBCA 8C E0 FE STY &FEE0 ;then set M=1 enable NMIs on R3 .SBCD BBCD 28 PLP ;restore interrupt state BBCE 60 RTS ;0484 Copy language to coprocessor (NAUG) BBCF 58 CLI ;enable interrupts BBD0 B0 11 BCS SBE3 ;if C=1, entry from *FX142 (JGH) then copy BBD2 D0 03 BNE SBD7 ;else if A>0 then enter language (JGH) BBD4 4C 9C 05 JMP &059C ;else A=0 no language, signal completion .SBD7 BBD7 A2 00 LDX #&00 ;set X=&00 do not alter BBD9 A0 FF LDY #&FF ;set Y=&FF do not update BBDB A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset BBDD 20 F4 FF JSR &FFF4 ;call OSBYTE BBE0 8A TXA ;if type = 0 soft BREAK BBE1 F0 D9 BEQ SBBC ;then release Tube and write &80 to R2DATA .SBE3 BBE3 A9 FF LDA #&FF ;&FF = claim Tube with claimant ID = &3F BBE5 20 06 04 JSR &0406 ;call Tube service BBE8 90 F9 BCC SBE3 ;loop until claim granted BBEA 20 D2 04 JSR &04D2 ;set up Tube destination address .SBED BBED A9 07 LDA #&07 ;type byte = 7, 256 byte transfer to host BBEF 20 CB 04 JSR &04CB ;set up Tube data transfer BBF2 A0 00 LDY #&00 ;clear page offset BBF4 84 00 STY &00 ;align ROM pointer to page boundary .SBF6 BBF6 B1 00 LDA (&00),Y ;get byte from ROM BBF8 8D E5 FE STA &FEE5 ;write A to R3DATA BBFB EA NOP ;wait 3 microseconds BBFC EA NOP BBFD EA NOP BBFE C8 INY ;increment offset BBFF D0 F5 BNE SBF6 ;loop until page boundary reached (10us/byte) BC01 E6 54 INC &54 ;then add 256 to Tube transfer address BC03 D0 06 BNE SC0B ;carry out to 2MSB BC05 E6 55 INC &55 BC07 D0 02 BNE SC0B ;and MSB BC09 E6 56 INC &56 .SC0B BC0B E6 01 INC &01 ;increment MSB of ROM pointer BC0D 24 01 BIT &01 ;test b14 of ROM pointer BC0F 50 DC BVC SBED ;loop until b14=1, when it has reached &C000 BC11 20 D2 04 JSR &04D2 ;set up Tube destination address BC14 A9 04 LDA #&04 ;type byte = 4 no transfer, execute 2P code: ;04CB set up Tube data transfer BC16 A0 00 LDY #&00 ;point XY at Tube transfer address at &0053 BC18 A2 53 LDX #&53 BC1A 4C 06 04 JMP &0406 ;jump into Tube service. ;04D2 Set up Tube destination address BC1D A9 80 LDA #&80 BC1F 85 54 STA &54 ;set 3MSB of Tube transfer address = &80 BC21 85 01 STA &01 ;set MSB of ROM pointer = &80 BC23 A9 20 LDA #&20 ;set b5=1 to test custom address flag BC25 2D 06 80 AND &8006 ;AND with ROM type byte BC28 A8 TAY ;place result in AY for MSB, 2MSB of addr BC29 84 53 STY &53 ;store as LSB (on the assumption that it's 0) BC2B F0 19 BEQ SC46 ;if b5=0 then no custom addr, set &00008000 BC2D AE 07 80 LDX &8007 ;else get offset of copyright string .SC30 BC30 E8 INX ;skip leading NUL, increment offset BC31 BD 00 80 LDA &8000,X ;test character of copyright string BC34 D0 FA BNE SC30 ;loop until terminating NUL reached BC36 BD 01 80 LDA &8001,X ;store next byte as LSB of Tube address BC39 85 53 STA &53 BC3B BD 02 80 LDA &8002,X ;store byte after that as 3MSB BC3E 85 54 STA &54 BC40 BC 03 80 LDY &8003,X ;get next byte as 2MSB BC43 BD 04 80 LDA &8004,X ;get byte after that as MSB: .SC46 BC46 85 56 STA &56 ;store MSB of Tube transfer address BC48 84 55 STY &55 ;store 2MSB of Tube transfer address BC4A 60 RTS ;0500 Tube call handler jump table (SB) BC4B EQUW &37,&05 ;R2 was &00 - jump osrdch_call BC4D EQUW &96,&05 ;R2 was &02 - jump oscli_call BC4F EQUW &F2,&05 ;R2 was &04 - jump short_osbyte BC51 EQUW &07,&06 ;R2 was &06 - jump long_osbyte BC53 EQUW &27,&06 ;R2 was &08 - jump osword_call BC55 EQUW &68,&06 ;R2 was &0A - jump osword0_call BC57 EQUW &5E,&05 ;R2 was &0C - jump osargs_call BC59 EQUW &2D,&05 ;R2 was &0E - jump osbget_call BC5B EQUW &20,&05 ;R2 was &10 - jump osbput_call BC5D EQUW &42,&05 ;R2 was &12 - jump osfind_call BC5F EQUW &A9,&05 ;R2 was &14 - jump osfile_call BC61 EQUW &D1,&05 ;R2 was &16 - jump osgbpb_call ;0518 Tube status settings for transfer types 0..7 BC63 EQUB &86 ;0=bytes to host J,I=1 enable IRQ on R4,R1 BC64 EQUB &88 ;1=bytes from host M=1 enable NMI on R3 BC65 EQUB &96 ;2=words to host V,J,I=1 enable IRQ on R4,R1 BC66 EQUB &98 ;3=words from host V,M=1 enable NMI on R3 BC67 EQUB &18 ;4=address only V,M=0 disable NMI on R3 BC68 EQUB &18 ;5=(reserved) V,M=0 disable NMI on R3 BC69 EQUB &82 ;6=page to host I=1 enable IRQ on R1 BC6A EQUB &18 ;7=page from host V,M=0 disable NMI on R3 ;osbput_call BC6B 20 C5 06 JSR &06C5 ;read R2DATA to A BC6E A8 TAY ;set Y=channel BC6F 20 C5 06 JSR &06C5 ;read R2DATA to A =byte to write BC72 20 D4 FF JSR &FFD4 ;call OSBPUT BC75 4C 9C 05 JMP &059C ;signal completion ;osbget_call BC78 20 C5 06 JSR &06C5 ;read R2DATA to A BC7B A8 TAY ;set Y=channel BC7C 20 D7 FF JSR &FFD7 ;call OSBGET BC7F 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;osrdch_call BC82 20 E0 FF JSR &FFE0 ;call OSRDCH ;053A send C, A to R2DATA and idle BC85 6A ROR A ;rotate C into A b7, save A b0 in C BC86 20 95 06 JSR &0695 ;write A to R2DATA BC89 2A ROL A ;restore A on entry BC8A 4C 9E 05 JMP &059E ;write to R2DATA and idle ;osfind_call BC8D 20 C5 06 JSR &06C5 ;read R2DATA to A BC90 F0 0B BEQ SC9D ;if A=0 then close file BC92 48 PHA ;else save A=call no. = open mode BC93 20 82 05 JSR &0582 ;read string to buffer BC96 68 PLA ;restore A BC97 20 CE FF JSR &FFCE ;call OSFIND BC9A 4C 9E 05 JMP &059E ;write to R2DATA and idle .SC9D BC9D 20 C5 06 JSR &06C5 ;read R2DATA to A BCA0 A8 TAY ;set Y=file handle BCA1 A9 00 LDA #&00 ;restore A=0 call no. = close file BCA3 20 CE FF JSR &FFCE ;call OSFIND BCA6 4C 9C 05 JMP &059C ;signal completion ;osargs_call BCA9 20 C5 06 JSR &06C5 ;read R2DATA to A BCAC A8 TAY ;set Y=channel BCAD A2 04 LDX #&04 ;4 bytes to read: .SCAF BCAF 20 C5 06 JSR &06C5 ;read R2DATA to A BCB2 95 FF STA &FF,X ;save in locations 3..0 BCB4 CA DEX ;in descending order BCB5 D0 F8 BNE SCAF ;loop until X bytes read BCB7 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BCBA 20 DA FF JSR &FFDA ;call OSARGS BCBD 20 95 06 JSR &0695 ;write A to R2DATA =return value BCC0 A2 03 LDX #&03 ;4 bytes to write: .SCC2 BCC2 B5 00 LDA &00,X ;get locations 3..0 BCC4 20 95 06 JSR &0695 ;write A to R2DATA BCC7 CA DEX ;in descending order BCC8 10 F8 BPL SCC2 ;loop until X+1 bytes written BCCA 4C 36 00 JMP &0036 ;go to idle loop ;0582 read string to buffer BCCD A2 00 LDX #&00 ;set X=0 LSB of buffer address BCCF A0 00 LDY #&00 ;set Y=0 buffer offset .SCD1 BCD1 20 C5 06 JSR &06C5 ;read R2DATA to A BCD4 99 00 07 STA &0700,Y ;save in string buffer BCD7 C8 INY ;in ascending order, increment offset BCD8 F0 04 BEQ SCDE ;if end of buffer reached then stop BCDA C9 0D CMP #&0D ;else test character read BCDC D0 F3 BNE SCD1 ;if =CR then string terminated else loop .SCDE BCDE A0 07 LDY #&07 ;set Y=&07 MSB of buffer address BCE0 60 RTS ;oscli_call BCE1 20 82 05 JSR &0582 ;read string to buffer BCE4 20 F7 FF JSR &FFF7 ;call OSCLI ;059C Signal completion BCE7 A9 7F LDA #&7F .SCE9 ;059E Write to R2DATA and idle BCE9 2C E2 FE BIT &FEE2 ;test R2STAT BCEC 50 FB BVC SCE9 ;loop until b6=1, not full BCEE 8D E3 FE STA &FEE3 ;write A to R2DATA .SCF1 BCF1 4C 36 00 JMP &0036 ;go to idle loop ;osfile_call BCF4 A2 10 LDX #&10 ;16 bytes to read: .SCF6 BCF6 20 C5 06 JSR &06C5 ;read R2DATA to A BCF9 95 01 STA &01,X ;save to locations 17..2 BCFB CA DEX ;in descending order BCFC D0 F8 BNE SCF6 ;loop until X bytes read BCFE 20 82 05 JSR &0582 ;read string to buffer BD01 86 00 STX &00 ;save buffer address at 0,1 BD03 84 01 STY &01 ;=&0700 BD05 A0 00 LDY #&00 ;set Y=0; X=0 from 0582 BD07 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD0A 20 DD FF JSR &FFDD ;call OSFILE BD0D 20 95 06 JSR &0695 ;write A to R2DATA =return value BD10 A2 10 LDX #&10 ;16 bytes to write: .SD12 BD12 B5 01 LDA &01,X ;get locations 17..2 BD14 20 95 06 JSR &0695 ;write A to R2DATA BD17 CA DEX ;in descending order BD18 D0 F8 BNE SD12 ;loop until X bytes written BD1A F0 D5 BEQ SCF1 ;then go to idle loop ;osgbpb_call BD1C A2 0D LDX #&0D ;13 bytes to read: .SD1E BD1E 20 C5 06 JSR &06C5 ;read R2DATA to A BD21 95 FF STA &FF,X ;save to locations 12..0 BD23 CA DEX ;in descending order BD24 D0 F8 BNE SD1E ;loop until X bytes read BD26 20 C5 06 JSR &06C5 ;read R2DATA to A BD29 A0 00 LDY #&00 ;set Y=0; X=0 from loop BD2B 20 D1 FF JSR &FFD1 ;call OSGBPB BD2E 48 PHA ;save return value BD2F A2 0C LDX #&0C ;13 bytes to write: .SD31 BD31 B5 00 LDA &00,X ;get locations 12..0 BD33 20 95 06 JSR &0695 ;write A to R2DATA BD36 CA DEX ;in descending order BD37 10 F8 BPL SD31 ;loop until X bytes written BD39 68 PLA ;restore A=return value BD3A 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;short_osbyte BD3D 20 C5 06 JSR &06C5 ;read R2DATA to A BD40 AA TAX ;save X=first parameter BD41 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD44 20 F4 FF JSR &FFF4 ;call OSBYTE .SD47 BD47 2C E2 FE BIT &FEE2 ;test R2STAT BD4A 50 FB BVC SD47 ;loop until b6=1, not full BD4C 8E E3 FE STX &FEE3 ;write X to R2DATA =result .SD4F BD4F 4C 36 00 JMP &0036 ;go to idle loop ;long_osbyte BD52 20 C5 06 JSR &06C5 ;read R2DATA to A BD55 AA TAX ;set X=first parameter BD56 20 C5 06 JSR &06C5 ;read R2DATA to A BD59 A8 TAY ;set Y=second parameter BD5A 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD5D 20 F4 FF JSR &FFF4 ;call OSBYTE BD60 49 9D EOR #&9D ;if A=&9D fast Tube BPUT BD62 F0 EB BEQ SD4F ;then end call without handshake BD64 6A ROR A ;else rotate C into A b7 BD65 20 95 06 JSR &0695 ;write A to R2DATA .SD68 BD68 2C E2 FE BIT &FEE2 ;test R2STAT BD6B 50 FB BVC SD68 ;loop until b6=1, not full BD6D 8C E3 FE STY &FEE3 ;write Y to R2DATA =second result BD70 70 D5 BVS SD47 ;write X to R2DATA and idle (always) ;osword_call BD72 20 C5 06 JSR &06C5 ;read R2DATA to A =call number BD75 A8 TAY ;hold in Y .SD76 BD76 2C E2 FE BIT &FEE2 ;test R2STAT BD79 10 FB BPL SD76 ;loop until b7=1, data available BD7B AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD7E CA DEX ;decrement X BD7F 30 0F BMI SD90 ;if X was not in range 1..128 then no bytes .SD81 BD81 2C E2 FE BIT &FEE2 ;else test R2STAT BD84 10 FB BPL SD81 ;loop until b7=1, data available BD86 AD E3 FE LDA &FEE3 ;read R2DATA to A BD89 9D 28 01 STA &0128,X ;save to locations &0128+(X-1..0) BD8C CA DEX ;in descending order BD8D 10 F2 BPL SD81 ;loop until X bytes written BD8F 98 TYA ;restore A=call number .SD90 BD90 A2 28 LDX #&28 ;point XY to OSWORD control block at &0128 BD92 A0 01 LDY #&01 BD94 20 F1 FF JSR &FFF1 ;call OSWORD .SD97 BD97 2C E2 FE BIT &FEE2 ;test R2STAT BD9A 10 FB BPL SD97 ;loop until b7=1, data available BD9C AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size BD9F CA DEX ;decrement X BDA0 30 0E BMI SDB0 ;if X was not in range 1..128 then no bytes .SDA2 BDA2 BC 28 01 LDY &0128,X ;else get byte of control block at ..&0128 .SDA5 BDA5 2C E2 FE BIT &FEE2 ;test R2STAT BDA8 50 FB BVC SDA5 ;loop until b6=1, not full BDAA 8C E3 FE STY &FEE3 ;write Y to R2DATA BDAD CA DEX ;in descending order BDAE 10 F2 BPL SDA2 ;loop until X bytes written .SDB0 BDB0 4C 36 00 JMP &0036 ;go to idle loop ;osword0_call BDB3 A2 04 LDX #&04 ;5 bytes to read: .SDB5 BDB5 20 C5 06 JSR &06C5 ;read R2DATA to A BDB8 95 00 STA &00,X ;save to locations 4..0 BDBA CA DEX ;in descending order BDBB 10 F8 BPL SDB5 ;loop until X+1 bytes read BDBD E8 INX ;set X=0 BDBE A0 00 LDY #&00 ;set Y=0; point XY to OSWORD control block BDC0 8A TXA ;set A=0 read line from input stream BDC1 20 F1 FF JSR &FFF1 ;call OSWORD BDC4 90 05 BCC SDCB ;if user pressed ESCAPE BDC6 A9 FF LDA #&FF ;then A=&FF carry set/error condition BDC8 4C 9E 05 JMP &059E ;write to R2DATA and idle .SDCB BDCB A2 00 LDX #&00 ;else X=0 offset into string buffer BDCD A9 7F LDA #&7F ;set A=&7F carry clear/no error BDCF 20 95 06 JSR &0695 ;write A to R2DATA .SDD2 BDD2 BD 00 07 LDA &0700,X ;get character from string buffer BDD5 20 95 06 JSR &0695 ;write A to R2DATA BDD8 E8 INX ;increment offset BDD9 C9 0D CMP #&0D ;test character just written BDDB D0 F5 BNE SDD2 ;if =CR then string terminated else loop BDDD 4C 36 00 JMP &0036 ;go to idle loop .SDE0 ;0695 Write A to R2DATA BDE0 2C E2 FE BIT &FEE2 ;test R2STAT BDE3 50 FB BVC SDE0 ;loop until b6=1, not full BDE5 8D E3 FE STA &FEE3 ;write A to R2DATA BDE8 60 RTS .SDE9 ;069E Write A to R4DATA BDE9 2C E6 FE BIT &FEE6 ;test R4STAT BDEC 50 FB BVC SDE9 ;loop until b6=1, not full BDEE 8D E7 FE STA &FEE7 ;write A to R4DATA BDF1 60 RTS ;06A7 Copy ESCAPE flag to coprocessor (NAUG) BDF2 A5 FF LDA &FF ;get MOS ESCAPE flag BDF4 38 SEC ;rotate 1 into bit 7, ESCAPE flag in bit 6 BDF5 6A ROR A ;A >= &80 indicating ESCAPE flag update BDF6 30 0F BMI SE07 ;write A to R1DATA (always) ;06AD Event handler BDF8 48 PHA ;save event type BDF9 A9 00 LDA #&00 ;set A=&00 to indicate event BDFB 20 BC 06 JSR &06BC ;write A to R1DATA BDFE 98 TYA ;transfer Y=second event parameter to A BDFF 20 BC 06 JSR &06BC ;write A to R1DATA BE02 8A TXA ;transfer X=first event parameter to A BE03 20 BC 06 JSR &06BC ;write A to R1DATA BE06 68 PLA ;restore event type to A: .SE07 ;06BC Write A to R1DATA BE07 2C E0 FE BIT &FEE0 ;test R1STAT BE0A 50 FB BVC SE07 ;loop until b6=1, not full BE0C 8D E1 FE STA &FEE1 ;write A to R1DATA BE0F 60 RTS .SE10 ;06C5 Read R2DATA to A BE10 2C E2 FE BIT &FEE2 ;test R2STAT BE13 10 FB BPL SE10 ;loop until b7=1, data available BE15 AD E3 FE LDA &FEE3 ;read R2DATA to A and return BE18 60 RTS .SE19 ;Print "COPYRIGHT NOTICE" BE19 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE1C EQUB &83 ;yellow alphanumerics BE1D EQUB &8D ;double height BE1E EQUS " C O P Y R I G H T N O T I C E" BE3E EQUB &0D BE3F EQUB &0A BE40 EQUB &FF BE41 60 RTS ;*COPYRIGHT BE42 20 74 AD JSR RD74 ;set display MODE 7 BE45 20 67 84 JSR P467 ;print newline BE48 20 19 BE JSR SE19 ;print "COPYRIGHT NOTICE" twice BE4B 20 19 BE JSR SE19 BE4E 20 D2 A3 JSR R3D2 ;print VDU sequence immediate BE51 EQUB &0D BE52 EQUB &0A BE53 EQUB &0A BE54 EQUS "This Double Density Operating System" BE78 EQUB &0D BE79 EQUB &0A BE7A EQUS "was developed for the BBC computer by" BE9F EQUB &0D BEA0 EQUB &0A BEA1 EQUB &83 ;yellow alphanumerics BEA2 EQUS "SLOGGER SOFTWARE and OPUS SUPPLIES" BEC4 EQUB &0D BEC5 EQUB &0A BEC6 EQUS "Any unauthorised copying of this" BEE6 EQUB &0D BEE7 EQUB &0A BEE8 EQUS "product is unlawful and may result in" BF0D EQUB &0D BF0E EQUB &0A BF0F EQUS "Slogger or Opus taking appropriate" BF31 EQUB &0D BF32 EQUB &0A BF33 EQUS "action." BF3A EQUB &0D BF3B EQUB &0A BF3C EQUB &0A BF3D EQUB &FF BF3E 60 RTS # if defined _DDOS356 BF3F EQUB &FF BF40 EQUB &05,&06,&15,&16 BF44 EQUB &FF,&FF,&FF,&FF .SF48 BF48 AA TAX BF49 BD 40 BF LDA &BF40,X ;get flags for drive 0..3 in X BF4C 85 F9 STA &F9 ;store in temporary location BF4E AD E3 10 LDA &10E3 ;get density flag BF51 29 40 AND #&40 ;extract bit 6 (1 = double density) BF53 4A LSR A ;move to bit 5 BF54 49 20 EOR #&20 ;invert for Master (0 = double density) BF56 05 F9 ORA &F9 ;add drive flags (only Compact uses &F8,9) BF58 60 RTS # elif defined _DDOS357 ;FSC ;referenced at &80BB..C3, &A83F..40 BF40 C9 0A CMP #&0A BF42 D0 12 BNE SF56 BF44 20 00 A3 JSR R300 ;FSC 10 = *INFO. save AXY BF47 20 42 8F JSR PF42 ;set GSINIT pointer to XY, set Y=0 BF4A A2 E8 LDX #&E8 ;point XY to *INFO command table entry BF4C A0 8D LDY #&8D BF4E 20 28 8F JSR PF28 ;set up trampoline to read *INFO entry BF51 A0 00 LDY #&00 ;set Y = 0 offset for GSINIT BF53 4C 51 89 JMP P951 ;jump into *INFO .SF56 BF56 4C 2F 87 JMP P72F ;serve other FSC calls .SFE8 ;ROM service BFE8 C9 25 CMP #&25 BFEA D0 10 BNE SFFC ;Service call &25 = filing system info BFEC A2 15 LDX #&15 ;22 bytes to write: .SFEE BFEE BD 19 87 LDA &8719,X ;get byte of filing system info BFF1 91 F2 STA (&F2),Y ;add to MOS table BFF3 C8 INY ;increment table offset BFF4 CA DEX ;decrement count BFF5 10 F7 BPL SFEE ;loop until 22 bytes written BFF7 A6 F4 LDX &F4 ;restore AX, pass updated Y BFF9 A9 25 LDA #&25 BFFB 60 RTS .SFFC BFFC 4C 45 80 JMP P045 ;service other calls # elif defined _DDOS326 BF40 EQUB &29,&2A,&2D,&2E .SF44 BF44 29 40 AND #&40 ;extract bit 6 (1 = double density) BF46 4A LSR A ;move to bit 3 BF47 4A LSR A BF48 4A LSR A BF49 5D 40 BF EOR &BF40,X ;apply flags for drive 0..3 in X BF4C 8D 80 FE STA &FE80 ;store in control latch BF4F 68 PLA ;restore X and exit BF50 AA TAX BF51 60 RTS # endif /* _DDOS356 */ BFFF EQUB &00 ;make 16 KiB ROM image # endif /* _DDOS346 */ #endif /* _DDOS316 */ #if defined _DFSFIX .SF59 ;call OSFILE 2 write load addr or 0 save: BF59 0A ASL A ;move bit 0 of A to bit 1 BF5A 29 02 AND #&02 ;extract it; 9 -> 2, 10 -> 0 BF5C AA TAX ;set table offset to 3 or 1: .SF5D ;Handle OSFILE calls 7,9-11 or validate index BF5D E8 INX ;enter with X = A, convert X to table offset BF5E E0 0C CPX #&0C ;is it OSFILE 11 = create file with stamp? BF60 B0 06 BCS SF68 ;if OSFILE &0C..FE then C=1, return on exit BF62 E0 0A CPX #&0A ;else if OSFILE 9 = set filetype/stamp BF64 B0 F3 BCS SF59 ;or OSFILE 10 = save file w/stamp, translate BF66 E0 08 CPX #&08 ;else is it OSFILE 7 = create file? if not .SF68 BF68 D0 0A BNE SF74 ;then return X=offset, C=call unknown, else: ;OSFILE 7 = create file, 11 = create w/ stamp BF6A 20 F0 90 JSR Q0F0 ;create file from OSFILE block BF6D 20 22 9C JSR QC22 ;set up pointer to user's OSFILE block BF70 20 06 8A JSR PA06 ;return catalogue information to OSFILE block BF73 38 SEC ;set C=1, return on exit .SF74 BF74 60 RTS .SF75 BF75 68 PLA ;extend file. restore file handle BF76 A8 TAY BF77 20 06 98 JSR Q806 ;set PTR = request, to extend file BF7A A9 80 LDA #&80 ;a=&80 so that c=1 to restore original PTR: .SF7C ;OSARGS A=1/3, Y>0 set PTR/EXT BF7C F0 36 BEQ SFB4 ;if call number = 1, set PTR, else: BF7E 0A ASL A ;OSARGS 3,Y. c=0 read PTR to restore later BF7F 8A TXA ;save OSARGS pointer BF80 48 PHA BF81 A2 B6 LDX #&B6 ;point X to PTR store used by OSGBPB BF83 A9 00 LDA #&00 ;set A=0, Z=1 to read/set PTR not EXT! BF85 20 A4 97 JSR Q7A4 ;read temporary PTR if C=0 or set PTR if C=1 BF88 68 PLA ;restore user's OSARGS pointer BF89 AA TAX BF8A 98 TYA ;save file handle BF8B 48 PHA BF8C 20 BA BF JSR SFBA ;clear EOF warning flag BF8F 20 CC 9A JSR QACC ;compare EXT - request BF92 90 E1 BCC SF75 ;if EXT < request then extend file BF94 B9 0C 11 LDA &110C,Y ;else get channel read-only bit in b7 BF97 19 0E 11 ORA &110E,Y ;or with channel file locked bit in b7 BF9A 30 05 BMI SFA1 ;if either is set do not write new EXT to cat BF9C A9 20 LDA #&20 ;else b5=1 EXT changed BF9E 20 3F 99 JSR Q93F ;set channel flag bits (A = OR mask) .SFA1 BFA1 20 76 A4 JSR R476 ;truncate file. add 4 to Y BFA4 20 53 98 JSR Q853 ;copy request to EXT BFA7 68 PLA ;restore file handle BFA8 A8 TAY BFA9 8A TXA ;save OSARGS pointer BFAA 48 PHA BFAB 98 TYA ;copy file handle to X BFAC AA TAX BFAD 20 B6 94 JSR Q4B6 ;compare PTR - EXT BFB0 68 PLA ;restore OSARGS pointer BFB1 AA TAX BFB2 90 C0 BCC SF74 ;if PTR < EXT then return, else: .SFB4 ;OSARGS A=1, Y>0 BFB4 20 06 98 JSR Q806 ;set PTR = request BFB7 20 00 A3 JSR R300 ;save AXY again .SFBA BFBA 20 A7 98 JSR Q8A7 ;ensure file handle valid and open BFBD A9 EF LDA #&EF ;b4=0 EOF warning flag clear BFBF 4C 46 99 JMP Q946 ;clear channel flag bits .SFC2 ;Clear EOF warning flag in OSGBPB BFC2 AC D7 10 LDY &10D7 ;get LSB of OSGBPB action address BFC5 C0 5C CPY #&5C ;does it match 'return one filename'? BFC7 F0 06 BEQ SFCF ;if not BFC9 AC 60 10 LDY &1060 ;set Y = file handle from OSGBPB block BFCC 20 BA BF JSR SFBA ;clear EOF warning flag .SFCF BFCF 4C 0A 9E JMP QE0A ;set up pointer to user's OSGBPB block ;OSFIND BFD2 48 PHA ;save call number BFD3 29 48 AND #&48 ;test b6=read access, b3=error if not found BFD5 C9 48 CMP #&48 ;set carry flag iff b6, b3 both set BFD7 68 PLA ;restore call number BFD8 08 PHP ;save carry flag BFD9 29 C0 AND #&C0 ;pass only b7=write access, b6 to DDOS BFDB 20 C1 95 JSR Q5C1 ;call DDOS routine BFDE 28 PLP ;restore carry flag BFDF 49 00 EOR #&00 ;test if file handle in A is non-zero BFE1 90 91 BCC SF74 ;if no error is required then return BFE3 D0 8F BNE SF74 ;if a file was opened then return BFE5 4C 43 89 JMP P943 ;else raise "File not found" error. #endif /* _DFSFIX */ ;Code fragments with no known references: ;871A..50 = &37 = 55 bytes used by DDOS 3.57 ;8F22..27 = &06 = 6 bytes ;92C6..CD = &08 = 8 bytes ;92F6..FF = &0A = 10 bytes used by seek NMI fix ;A46C = &01 = 1 byte ;A509..10 = &08 = 8 bytes used by RAM disc fix ;A56D..73 = &07 = 7 bytes ;A57D..7F = &03 = 3 bytes ;A58A..8E = &05 = 5 bytes ;A701 = &01 = 1 byte ;B008..19 = &12 = 18 bytes ;B9??..?? = &17 = 23 bytes used by DDOS 3.57 ;BA?? = &01 = 1 byte ;Total = &92 = 146 bytes ;Variables ;00A0 Temporary number of sectors until end of track ;00A0 Offset of next byte to be stored while reading sector ID ;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 b7..0=Sideways slot number of disc during RAM disc transfer ;00A2..A3 Data table pointer while preparing format ;00A3 *SROM number of paged ROM slot to page in during RAM disc transfer ;00A3..A5 Total number of bytes to transfer to floppy disc ;00A4..A5 Starting logical block address (LBA) of RAM disc transfer ;00A4..A5 Run length table pointer while preparing format ;00A6..A7 User data address during transfer ;00A8 b7=catalogue entry is waiting to be created in *COPY, *COMPACT ;00A8 Flag for printing newlines in *CAT ;00A8..A9 Action address of *command ;00A8..A9 Line number in *BUILD, *LIST or file offset in *DUMP ;00A9 b7=Copying between different discs in same drive (swapping) ;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..AD Trampoline to read byte of *command and keyword table ;00AB Offset of catalogue entry of found file in *COPY ;00AB Handle of output file in *BUILD ;00AB Mask to enable line number printing &00=*TYPE &FF=*LIST ;00AC..B0 OSWORD 0 control block in *BUILD ;00AC..AD Pointer to second private page in *BUILD, *DUMP ;00AE..AF Pointer to error message source string or VDU sequence ;00AF Offset of syntax byte of selected *command = 2 + length of name ;00B0 Offset of insertion point while creating catalogue entry ;00B0 Counter for copying filename in OSGBPB 8 ;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 Count of total or free sectors to be printed in *STAT ;00B0..B1 Length of cassette file in *TAPEDISK ;00B0..B1 Offset of current sector buffer from start of file in OSARGS 1,Y ;00B0..B1 Integer workspace: multiplicand, dividend or numeric user input ;00B2 b5..0=OSWORD &7F command to compare with commands in table ;00B2 Offset of filename to compare with names of open handles ;00B2..B3 Integer workspace: multiplier or divisor ;00B3 Boot option in Y on entry to service call &03 ;00B3 Offset of catalogue entry, 0..&F0, multiple of 8 ;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 Channel workspace pointer while preparing "Can't extend" error ;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 ;00B8 Stack pointer to restore on abort ;00B8..B9 Pointer to user memory in OSGBPB ;00B8 Counter of *HELP entries to print ;00B9 Running track skew counter while formatting ;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 ;00BC Offset of catalogue entry in OSFILE &FF ;00BC Drive number to *FORMAT (unused) ;00BC..BD Pointer to argument string: OSCLI command tail or passed to FSC ;00BC..BD Pointer to filename in OSFILE ;00BC..BD Pointer to channel sector buffer ;00BD Interleave flag to *FORMAT (unused) ;00BE..C5 Load/exec/length/start sector in catalogue format ;00BE..C5 Low words of load, exec, start, end addresses in OSFILE ;00C3 (1, copied to &A4, then &A1, causes file buffer transfers to =256) ;00C6..C7 Source volume size in *BACKUP, *COPY ;00C6..C7 Length in sectors of file being copied ;00C7..CD Current filename ;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 *MCOPY, *COMPACT ;00CE Current directory ;00CF b3..0=current drive b6..4=current volume ;0DF0,X High byte of address of private page (X=?&F4) ;1000 Data transfer call number 0=read data 1=write data ; 3=write deleted data 4=verify data ;1001 *SROM number of paged ROM slot to page in during disc operations ;1002..05 Sector ID returned by Read ID NMI service routine, CHRN ;1006..0D First track of data area of volumes A..H ;100E..0F Number of sectors on surface of double density disc (from disc cat) ;1010 Stack pointer to restore on command restart ;1011..12 Command restart action address ;1013 Return code in *FORMAT, *VERIFY 0=no error 1=stand-alone verify failed 2=format failed 3=verify failed after format ;1014..23 Sizes assigned to volumes A..H in *VOLGEN ;1014..3,Y Number of sectors in data area of volumes A..H, big-endian ;1024 Stack pointer to restore on command exit (redundant to &1010) ;1026 X position of cursor ;1027..29 Saved A,X,Y registers on entry to OSBPUT ;1028..29 Saved X,Y registers on entry to OSBGET ;102A Retry counter at data transfer level 3 ;102B..2E Result of binary word to decimal digit conversion ;1031..35 Line buffer during numeric input routine ;1045..56 Temporary copy of &00BC..CD while creating catalogue entry ;1047..4E Load/exec/length/start sector of file being copied ;1050..57 Filename and directory of file being copied ;1058..5F Filename and directory portion of file specification to *COPY ;1060..6C Copy of OSGBPB control block ;106D..70 Address of Tube data transfer ;106F..76 High words of load, exec, start, end addresses in OSFILE ;107F..80 Pointer to user's OSGBPB control block ;1081 Transfer direction 0=writing from memory 1=reading to memory ;1082 Direction of Tube transfer, written at &9301, otherwise unused ;1083 &00=transferring to/from host &FF=transferring to/from Tube ;1084 Drive and volume of catalogue in pages &E..F; &FF=catalogue invalid ;1085..86 Expected size of bulk data transfer ;1087 NMI ownership flag b7=we own NMI ;1088 Previous owner of NMI area ;1089 MSB of OSHWM; lowest page number of user memory ;108A MSB of HIMEM; 1 + highest page number of user memory ;108B Number of pages of user memory; = ?&108A - ?&1089 ;108C..8D Physical track number under heads on drive 0/2, 1/3 ;108E Track stepping rate in WD 1770 format 0=fast..3=slow ;108F Status of last FDC command, reported by *FDCSTAT ;1090..95 Sector ID read by Read ID NMI service routine, CHRN + CRC ;10C0 Private page +&C0: b7=1 iff private page initialised ;10C1 Private page +&C1: b7=1 iff we own the shared workspace ;10C2 First shared workspace sentinel &41=workspace valid ;10C3 Channel open flags ;10C4 Channel open bit mask for current open file ;10C5 Channel workspace pointer for current open file ;10C6 MSB of maximum allocation available to current open file ;10C7 Offset of catalogue entry of current open file ;10C8 Counter for copying catalogue entry while opening file ;10C9 Temporary copy of X register during sequential file operations ;10CA Default (CSD) directory character ;10CB Default (CSD) drive (b3..0) and volume (b6..4) ;10CC Library directory character ;10CD Library drive (b3..0) and volume (b6..4) ;10CE Cleared at &82B7, otherwise unused ;10CF Offset of catalogue entry, 0..&F0, multiple of 8 ;10CF Y position of cursor ;10D0 &23=wildcard characters allowed in filename &FF=no wildcards ;10D1 *OPT 1 monitor 0=verbose &FF=quiet ;10D2 *ENABLE counter 1=*ENABLE just called 0=current command enabled ; &FF=current command not enabled ;10D3 Source volume in *BACKUP, *COPY ;10D4 Destination volume in *BACKUP, *COPY ;10D5 b7=Tube data transfer ;10D6 &00=Tube coprocessor present &FF=Tube absent (inverted MOS flag) ;10D7 b7..4=boot option of source volume in *BACKUP, *MCOPY ;10D7..D8 Action address in OSGBPB ;10D9 Offset of command line tail from GSINIT pointer ;10DA Offset of start of command line from GSINIT pointer ;10D9..DA Pointer to arguments of *RUN, */ command ;10DB..DC Pointer to user's OSFILE control block ;10DD <&80 "print" to error message >=&80 print to screen ; (if <&80, offset of next error character in page &01) ;10DE Second shared workspace sentinel &48=workspace valid ;10E0..E3 Special registers 0..3 ;10E0 &00=single stepping b6=double stepping b7=automatic stepping ;10E1 Number of sectors per track &0A=single density &12=double density ;10E2 First track of current volume (=0 unless set from disc catalogue) ;10E3 &00=single density b6=double density b7=automatic density ;10E6..B,Y Drive parameters for channel (6 bytes per channel, Y=6*n, n=0..6) ; n=0..4 for channel &11..15 n=5 source drive n=6 destination drive ; 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ;10E0 sC pC vC dC .. .. s1 p1 v1 d1 .. .. s2 p2 v2 d2 ;10F0 .. .. s3 p3 v3 d3 .. .. s4 p4 v4 d4 .. .. s5 p5 ;1100 v5 d5 .. .. sS pS vS dS .. .. sD pD vD dD .. .. ;1120..C,Y 1100,Y Name of open file (even addresses) ;1121..F,Y 1101,Y Load/exec/length/start sector in catalogue format (odds) ;112C,Y 110C,Y Seventh character of open filename; b7=read-only channel ;112E,Y 110E,Y Directory of open filename; b7=file locked ;1130..2,Y 1110,Y PTR file pointer ;1134..6,Y 1114,Y EXT file length ;1137,Y 1117,Y Channel flags b7=buffer contains byte at PTR ; b6=buffer changed b5=EXT changed (not cleared on ensure) ; b4=EOF warning given ;1138,Y Always 0 (&1138..A,Y = length in bytes, rounded up) ;1139..A,Y 1119,Y Length of file in sectors, according to catalogue ;113B,Y 111B,Y Bit mask corresponding to channel in flag byte &10C3 ;113C..D,Y 111C,Y LBA of sector buffer relative to start of vol. data area ;113F,Y 111F,Y Drive (b3..0) and volume (b6..4) of open file ;Errata ;OSFILE does not load or save files 64 KiB or larger to the RAM disc ;correctly. ;BeebEm 4.14 does not tolerate the WD 1770 Write Sector command being ;terminated during the NMI service routine; the last byte is dropped. ;(disc1770.cpp:326) ;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_DDOS346PRE -b 8000 -o ddos346pre ddos.asm.txt ; perl asm2bin.pl -D_DDOS316 -b 8000 -o ddos316 ddos.asm.txt ; perl asm2bin.pl -D_DDOS336 -b 8000 -o ddos336 ddos.asm.txt ; perl asm2bin.pl -D_DDOS346 -b 8000 -o ddos346 ddos.asm.txt ; perl asm2bin.pl -D_DDOS356 -b 8000 -o ddos356 ddos.asm.txt ; perl asm2bin.pl -D_DDOS357 -b 8000 -o ddos357 ddos.asm.txt ; perl asm2bin.pl -D_DDOS326 -b 8000 -o ddos326 ddos.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 ddos.asm.txt