;Disassembly of Opus DDOS 3.46 and variants
;Greg Cook, 4 September 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: &3923
;PKZIP CRC: &C496FC3A
;XFER CRC: &3C28DCCF
;Cksum: 1395122086
;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
; OSFILE 4 sets attribute from control block
;_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
#if defined _BUGFIX
.P1AB ;OSWORD A <> &7F
81AB B0 2D BCS P1DA ;if A > &7F then exit
81AD C0 7D CPY #&7D ;else if A < &7D
81AF 90 29 BCC P1DA ;then exit
81B1 20 FB A4 JSR R4FB ;set current vol/dir = default, set up drive
81B4 20 9E 92 JSR Q29E ;load volume catalogue L4
81B7 A9 00 LDA #&00
81B9 C0 7E CPY #&7E
81BB F0 06 BEQ P1C3 ;OSWORD A = &7D
81BD A8 TAY ;store in OSWORD control block offset 0
81BE AD 04 0F LDA &0F04 ;get catalogue cycle number
81C1 90 14 BCC P1D7 ;return A = 0, claiming service call.
.P1C3 ;OSWORD A = &7E get size of volume in bytes
81C3 A0 03 LDY #&03
81C5 91 B0 STA (&B0),Y ;store 0 at offset 3: less than 16 MiB
81C7 A9 03 LDA #&03 ;set A = 3 as mask
81C9 88 DEY ;offset 2
81CA 2D 06 0F AND &0F06 ;extract MSB volume size
81CD 91 B0 STA (&B0),Y ;save as 2MSB volume size
81CF 88 DEY ;offset 1
81D0 AD 07 0F LDA &0F07 ;get LSB volume size from catalogue
81D3 91 B0 STA (&B0),Y ;save as 3MSB volume size
81D5 88 DEY ;offset 0
81D6 98 TYA ;store 0: volume size multiple of 256 bytes
.P1D7
81D7 91 B0 STA (&B0),Y ;Y = 0; store LSB volume size or cycle no.
81D9 98 TYA ;return A = 0, claiming service call
.P1DA
81DA 60 RTS
#else /* _BUGFIX */
.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
#endif /* _BUGFIX */
.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 = MSB 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 MSB of LBA
8908 A5 C5 LDA &C5 ;copy 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:
8E2E EQUS "XCAT"
8E32 EQUW &8A,&B0
8E34 EQUB &0A ;syntax &A: ()
;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:
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:
8E75 EQUS "FORMAT"
8E7B EQUW &A8,&A1
8E7D EQUB &8D ;syntax &D: b7=1
8E7E EQUS "LIST"
8E82 EQUW &83,&5D
8E84 EQUB &01 ;syntax &1:
8E85 EQUS "TYPE"
8E89 EQUW &83,&56
8E8B EQUB &01 ;syntax &1:
8E8C EQUS "VERIFY"
8E92 EQUW &AA,&55
8E94 EQUB &8A ;syntax &A: () b7=1
8E95 EQUS "VOLGEN"
8E9B EQUW &AB,&47
8E9D EQUB &8A ;syntax &A: () 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 ;Set xfer call no. = read, claim NMI
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 ;Set xfer call no. = write, claim NMI
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
#if defined _DFSFIX
969D AC C5 10 LDY &10C5 ;put channel workspace pointer in Y
.Q6A0
96A0 BD 08 0E LDA &0E08,X ;copy name and attributes of file
96A3 99 00 11 STA &1100,Y ;to bottom half of channel workspace
96A6 C8 INY
96A7 BD 08 0F LDA &0F08,X
96AA 99 00 11 STA &1100,Y
96AD C8 INY
96AE E8 INX
96AF 8A TXA ;loop until 8 byte pairs copied
96B0 29 07 AND #&07
96B2 D0 EC BNE Q6A0
96B4 A2 10 LDX #&10 ;a=0
.Q6B6
96B6 99 00 11 STA &1100,Y ;clear top half of channel workspace
96B9 C8 INY
96BA CA DEX
96BB D0 F9 BNE Q6B6
96BD AC C5 10 LDY &10C5 ;put channel workspace pointer in Y
96C0 98 TYA
96C1 99 1D 11 STA &111D,Y ;set buffer address out of range
96C4 4C C8 96 JMP Q6C8 ;(to force a read)
.Q6C8
#else /* _DFSFIX */
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
#endif /* _DFSFIX */
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
#if defined _DFSFIX
980C 20 CC 9A JSR QACC ;compare EXT - requested PTR
980F B0 1F BCS Q830 ;if EXT >= request then just set PTR
9811 B9 14 11 LDA &1114,Y ;else set PTR = EXT
9814 99 10 11 STA &1110,Y
9817 B9 15 11 LDA &1115,Y
981A 99 11 11 STA &1111,Y
981D B9 16 11 LDA &1116,Y
9820 99 12 11 STA &1112,Y
9823 20 3F 98 JSR Q83F ;set b7 according to &111C..D,Y
.Q826
9826 A9 00 LDA #&00 ;a = &00 filler byte
9828 20 B0 99 JSR Q9B0 ;write byte to end of file
982B 20 CC 9A JSR QACC ;compare EXT - request
982E 90 F6 BCC Q826 ;loop until last byte is just before new PTR
.Q830
9830 B5 00 LDA &00,X ;copy requested PTR in user's OSARGS block
9832 99 10 11 STA &1110,Y ;to channel pointer
9835 B5 01 LDA &01,X
9837 99 11 11 STA &1111,Y
983A B5 02 LDA &02,X ;copy MSB PTR
983C 99 12 11 STA &1112,Y
.Q83F
983F A9 6F LDA #&6F ;b7=0 PTR not in buffer, b4=0 EOF warning clr
9841 20 8F 99 JSR Q98F ;clear channel flag bits
9844 B9 11 11 LDA &1111,Y
9847 79 0F 11 ADC &110F,Y ;c=0; add LSB start sector to 2MSB PTR
984A 85 B0 STA &B0 ;save LSB new buffer address
984C B9 12 11 LDA &1112,Y
984F 79 0D 11 ADC &110D,Y ;add top bits exec/length/load/start sector
9852 29 03 AND #&03 ;mask b1,b0 MSB new buffer address
9854 D9 1D 11 CMP &111D,Y ;compare MSB current buffer address
9857 D0 29 BNE Q882 ;if equal
9859 A5 B0 LDA &B0 ;get back LSB new buffer address
985B D9 1C 11 CMP &111C,Y ;compare LSB current buffer address
985E D0 22 BNE Q882 ;if equal
9860 4C 3D 99 JMP Q93D ;then set b7=1 buffer contains PTR.
#else /* _DFSFIX */
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
#endif /* _DFSFIX */
.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
#if defined _DFSFIX
.Q882
#endif
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
#if defined _DFSFIX
.Q93D
#endif
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
#if !defined _DFSFIX
.Q94E
#endif
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
#if defined _DFSFIX
998D A9 BF LDA #&BF ;b6=0 buffer not changed
.Q98F
998F AC C5 10 LDY &10C5 ;put channel workspace pointer in Y
#else
998D AC C5 10 LDY &10C5 ;put channel workspace pointer in Y
9990 A9 BF LDA #&BF ;b6=0 buffer not changed
#endif
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
9CA8 20 06 98 JSR Q806 ;then call OSARGS 1,Y set PTR.
.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 "" ;element &1,
A080 EQUB &00
A081 EQUS "" ;element &2,
A087 EQUB &00
A088 EQUS "(L)" ;element &3, (L)
A08B EQUB &00
A08C EQUS "" ;element &4,
A095 EQUB &00
A096 EQUS "" ;element &5,
A0A0 EQUB &00
A0A1 EQUS " " ;element &6,
A0B2 EQUB &00
A0B3 EQUS "" ;element &7,
A0BC EQUB &00
A0BD EQUS "" ;element &8,
A0C6 EQUB &00
A0C7 EQUS "()" ;element &9, ()
A0CE EQUB &00
A0CF EQUS "()" ;element &A, ()
A0D6 EQUB &00
A0D7 EQUS "" ;element &B,
A0DE EQUB &00
A0DF EQUS "" ;element &C,
A0E8 EQUB &00
A0E9 EQUS "" ;element &D,
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 ":" 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 ":" keep current directory
A53D C9 2E CMP #&2E ;else "." 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 ;redundant to R7A7
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 &B9,&CC ;wrong keyword, "Bad command" &B9CC
#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 &B9,&CC ;wrong keyword, "Bad command" &B9CC
#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 30 98 JSR Q830 ;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 4C 06 98 JMP 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