;Assembly of Challenger 2.20
;Greg Cook, 23 December 2024
;This is a BeebAsm assembly source file.
;
; https://github.com/stardot/beebasm
;
;Most symbols copied from matching code in Acorn DNFS 3.00,
;as landmarks.
;
; https://github.com/stardot/AcornDNFSv300/
;
;Comments by Greg Cook. Comments beginning with capital letters
;are entry points. [D] marks differences from Opus DDOS 3.46.
;Disc transfer level 1 is eliminated in Challenger; L2 calls L0.
;Define any of the following symbols on the BeebAsm command line
;to select build options.
;For example:
; beebasm -i chal220.asm.txt -D _M1770C -D _MASTER
;Floppy drive controller selection
_O2791C =? 0 ;Opus WD 2791 controller
_O2793C =? 0 ;Opus WD 2793 controller
_O1770C =? 0 ;Opus WD 1770 controller
_W1770C =? 0 ;Watford WD 1770 controller
_A1770C =? 0 ;Acorn B/B+ WD 1770 controller
_M1770C =? 0 ;Acorn Master WD 1770 controller
_PG400C =? 0 ;Slogger Pegasus 400 controller
_S1770C =? 0 ;Solidisk WD 1770 controller
_CHALLC =? 0 ;Opus Challenger 3-in-1 unit (default)
;Usability options
_MASTER =? 0 ;Add service calls $25, $26, $27
;Pass unrecognised *commands to the LIBFS via FSC 11
;Based on the Challenger 2.00 filing system ROM released by
;Slogger Software, with patches by Tom Seddon.
;Differences from Challenger 200B:
;- Fix parsing of file specifications "*" and "
.*"
;- Fix *INFO, *EX, *VERIFY, and EOF warning flag behaviour
;- Preserve stack in *FDCSTAT
;- Preserve open files in *FORMAT
;- Ignore *BUILD if Challenger unit not fitted
;- Install empty BASIC program properly after copying
;- *RUN, */ enter executables with Acorn DFS-like registers
;- OSFILE calls 7,9,10,11 (create/stamp/save file) implemented
;- OSFILE $FF (load file) releases NMI and returns A=1
;- Transfer files >64 KiB between RAM disc and coprocessor
;- OSFILE 4 sets attribute from control block
;- Consider only b7,b6,b3 of A on entry to OSFIND. Raise
; "Not found" error iff b6,b3 are both set and no file
; can be opened.
;- OSARGS A=3, Y>0 (set EXT) implemented
;- Preserve RAM disc on OSWORD $7F call $5F (verify data)
;- Return special registers $12, $1A in OSWORD $7F
;- Add *EX to command table
;The functions of the Chafix module are built into this assembly.
;A ROM assembled from this source allows a simple RISC OS program
;running on an attached SPROW ARM7TDMI coprocessor to read and write
;files using the ANSI C Library and the built-in ARM Tube OS.
;The DFSfix and/or Chafix+DFSfix modules (DFSmod, Duomod) must not be
;installed together with this ROM.
;
; http://regregex.bbcmicro.net/#prog.dfsfix
;Floppy disc parameters
sdspt = $0A ;10 sectors per track in SD
ddspt = $12 ;18 sectors per track in DD
badtrk = $50 ;80 cylinders maximum on disc
volums = $08 ;number of volume catalogues on track 0
skew = $02 ;track skew during formatting in single density
sdgap5 = $10 ;number of bytes in gap 5, SD (excl. sync sequence)
sdgap1 = $0B ;number of bytes in gap 1, SD (excl. sync sequence)
sdgap3 = $10 ;number of bytes in gap 3, SD (excl. sync sequence)
ddgap5 = $28 ;number of bytes in gap 5, DD (excl. sync sequence)
ddgap1 = $19 ;number of bytes in gap 1, DD (excl. sync sequence)
ddgap3 = $16 ;number of bytes in gap 3, DD (excl. sync sequence)
;Floppy drive controller parameters
IF _O2791C
sense = $FF ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $00 ;sense of FDC status register compared to WD 2793
hdload = $08 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $00 ;latch value to select drive 0, single density
latch1 = $01 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $02 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $40 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _O2793C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $00 ;sense of FDC status register compared to WD 2793
hdload = $08 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $00 ;latch value to select drive 0, single density
latch1 = $01 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $02 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $40 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _O1770C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $00 ;latch value to select drive 0, single density
latch1 = $01 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $02 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $40 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _W1770C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $01 ;latch value to select drive 0, single density
latch1 = $04 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $02 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $01 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _A1770C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $29 ;latch value to select drive 0, single density
latch1 = $03 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $04 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $08 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _M1770C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $25 ;latch value to select drive 0, single density
latch1 = $03 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $10 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $09 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $20 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _PG400C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $39 ;latch value to select drive 0, single density
latch1 = $03 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $04 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $08 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELIF _S1770C
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $04 ;latch value to select drive 0, single density
latch1 = $01 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $02 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $00 ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $04 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ELSE
sense = $00 ;sense of FDC data bus pins (WD 2791 = $FF, else $00)
stsens = $80 ;sense of FDC status register compared to WD 2793
hdload = $00 ;sense of Type I command bit 3; $00=spin up $08=load head
latch0 = $32 ;latch value to select drive 0, single density
latch1 = $06 ;latch XOR mask to select drive 1 (unit 1 side 0)
latch2 = $01 ;latch XOR mask to select drive 2 (unit 0 side 1)
latch6 = $0A ;latch XOR mask to select drive 6 (unit 2 side 0)
latchd = $20 ;latch XOR mask to select double density
latchr = $00 ;latch value to reset FDC
ENDIF
;Challenger FS parameters
cbtsiz = $08 ;max. number of entries in copy buffer table
l3tris = $03 ;number of disc operation attempts at level 3
idtris = $05 ;number of Read ID attempts (must be odd)
bpmove = $0001 ;number of sectors to extend file by in OSBPUT
;(must be >0; 1 guarantees success unless disc full)
srom = $0E ;default *OPT 9 setting; ROM slot to page in
;during disc operations
dftbid = $01 ;Tube claimant ID for Disc Filing System
;Expansion memory layout
runofs = $0612 ;byte address of RLE tables in JIM space
jaux = $0000 ;page address of auxiliary workspace
jmain = $0001 ;page address of main workspace
jcat = $0002 ;page address of current DFS catalogue
jshift = $0002 ;page address of file shift buffer
shftsz = $0002 ;no. of pages in file shift buffer
jslots = $0004 ;page address of open file sector buffers
jbuild = $0009 ;page address of *BUILD line input buffer
jdrv4 = $000A ;page address of DFS RAM disc 4
d4size = $03F5 ;no. of pages in DFS RAM disc 4
jdrv5 = $0400 ;page address of DFS RAM disc 5
d5size = $03FF ;no. of pages in DFS RAM disc 5
;Constants defined by ChADFS
fstlba = $0000 ;logical block address to write ADFS free space table
fstsiz = $0200 ;byte size of ADFS free space table
fstadr = $C000 ;memory address of free space table (in HAZEL)
rootlb = $0002 ;logical block address to write ADFS root directory
rootsz = $0500 ;byte size of ADFS root directory
rootad = $C900 ;memory address of root directory (in HAZEL)
;Variables in zero-page reserved NMI area, $00A0..$00A7
sectog = $00A0 ;temporary number of sectors until end of track
rtxszl = $00A0 ;LSB number of bytes to transfer to RAM disc or current track
frmrun = $00A0 ;number of bytes in current run while preparing/executing format
rtxszh = $00A1 ;MSB number of bytes to transfer to RAM disc or current track
szcode = $00A1 ;sector size code while preparing format
fsectg = $00A2 ;number of sectors remaining while preparing format
txsizl = $00A3 ;LSB total number of bytes to transfer to floppy disc
romofs = $00A3 ;temporary pointer to repeating sector block in ROM format table
txsizm = $00A4 ;2MSB total number of bytes to transfer to floppy disc
runptl = $00A4 ;LSB run length table pointer while preparing format
txsizh = $00A5 ;MSB total number of bytes to transfer to floppy disc
runpth = $00A5 ;MSB run length table pointer while preparing format
nmiusr = $00A6 ;2 bytes; user data address during transfer
fsectk = $00A6 ;number of sectors per track while preparing format
chrnsz = $00A7 ;size of CHRN table while preparing format
;Variables in utility workspace, $00A8..$00AF
linnol = $00A8 ;LSB line number in *BUILD, *LIST or file offset in *DUMP
cbcont = $00A8 ;number of entries in copy buffer file table
nlflag = $00A8 ;flag for printing newlines in *CAT [D]linno now one byte
action = $00A8 ;2 bytes; action address of *command
nice = $00A8 ;b6=1 will accept shorter allocation than requested
;while creating file (b6=0 OSFILE, b6=1 OSFIND)
;[BUG] FS variable clobbers command workspace
linnoh = $00A9 ;MSB line number in *BUILD, *LIST or file offset in *DUMP
swaps = $00A9 ;b7=Copying between different discs in same drive (swapping)
movcat = $00A9 ;catalogue offset of file to extend while moving files
;[BUG] FS variable clobbers command workspace
lineln = $00AA ;length of input line in *BUILD
tindrv = $00AA ;$00=Source disc in drive $80=Destination disc in drive
catqua = $00AA ;=0 listing current directory during *CAT >0 listing other dirs
tramp = $00AA ;4 bytes; trampoline to read byte of *command and keyword table
attrib = $00AA ;file attribute mask in *ACCESS $00=unlocked $80=locked
movlen = $00AA ;number of files in catalogue while moving files
;[BUG] FS variable clobbers command workspace
inputl = $00AA ;LSB hexadecimal word input by user, or tentative volume size
lstmsk = $00AB ;mask to enable line number printing $00=*TYPE $FF=*LIST
bldfh = $00AB ;handle of output file in *BUILD
catptr = $00AB ;offset of catalogue entry of file being listed in *CAT
inputh = $00AB ;MSB hexadecimal word input by user, or tentative volume size
dumpct = $00AC ;ASCII column counter in *DUMP
bldtbl = $00AC ;5 bytes; OSWORD 0 control block in *BUILD
zdirln = $00AC ;zero-page copy of number of files in catalogue during *CAT
dmpstk = $00AD ;stack pointer in *DUMP
movret = $00AE ;2 bytes; caller's address while producing/consuming file map
;[BUG] FS variable clobbers command workspace
strret = $00AE ;2 bytes; pointer to error message string or VDU sequence
;Variables in filing system scratch workspace, $00B0..$00BF
;Variables in filing system persistent workspace, $00C0..$00CF
blkptr = $00B0 ;2 bytes; pointer to OSFILE or OSWORD $7F control block
evtptr = $00B0 ;2 bytes; pointer to extended vector table read from OSBYTE $A8
headlo = $00B0 ;LSB number of free sectors after file (MSB in X)
inscat = $00B0 ;offset of insertion point while creating catalogue entry
namptr = $00B0 ;2 bytes; pointer to filename to be compared with open filenames
vslbal = $00B0 ;LSB calculated LBA of new random access
;(in _BUGFIX; was offset of buffer from start of file)
mapctr = $00B0 ;count of file map entries to test while testing available space
gbctr = $00B0 ;counter for copying filename in OSGBPB 8
cnfofs = $00B0 ;offset into drive mapping table during *CONFIG
muland = $00B0 ;multiplicand
divenl = $00B0 ;LSB dividend
asklo = $00B0 ;LSB requested size of volume during *FORMAT, *VOLGEN
sklbah = $00B1 ;MSB LBA of largest slack space on volume (big-endian)
divenh = $00B1 ;MSB dividend
askhi = $00B1 ;MSB requested size of volume during *FORMAT, *VOLGEN
o7fcmd = $00B2 ;b5..0=OSWORD $7F command to compare with commands in table
sklbal = $00B2 ;MSB LBA of largest slack space on volume
namofs = $00B2 ;offset of filename to compare with names of open handles
mapsp = $00B2 ;pointer to file map in stack page
divorl = $00B2 ;LSB divisor
freelo = $00B2 ;LSB number of sectors available for allocation to volumes
trktot = $00B2 ;total number of tracks assigned to volumes
bootfs = $00B3 ;boot option in Y on entry to service call $03
lokcat = $00B3 ;offset of filename to be updated in catalogue
seqvol = $00B3 ;physical volume of file while comparing names of open handles
stra = $00B3 ;saved A register on entry to print string/append error message
divorh = $00B3 ;MSB divisor
freehi = $00B3 ;MSB number of sectors available for allocation to volumes
noop = $00B4 ;startup options while initialising private page (unused)
bitwrk = $00B4 ;reason code in A on entry to OSFIND, for testing by BIT
dcbofs = $00B4 ;channel workspace offset while comparing names of open handles
gbadr = $00B4 ;2 bytes; pointer to user's OSGBPB control block
fscx = $00B5 ;saved X register on entry to FSC
fscno = $00B5 ;$0B=FSC handler is serving FSC 11
dcbsr = $00B5 ;shift register containing channel open flags
zgbptr = $00B6 ;4 bytes; temporary copy of pointer from OSGBPB control block
frmclo = $00B7 ;command line argument offset in *FORMAT
restsp = $00B7 ;stack pointer to restore on command restart
abrtsp = $00B8 ;stack pointer to restore on abort or command exit
gbusr = $00B8 ;2 bytes; pointer to user memory in OSGBPB
hlpcot = $00B8 ;counter of *HELP entries to print
dopint = $00B9 ;=0 disc operation is uninterruptible >0 interruptible
track = $00BA ;logical track number of disc operation
txlbah = $00BA ;MSB starting LBA of disc operation (big-endian)
txlbal = $00BB ;LSB starting LBA of disc operation (big-endian)
sector = $00BB ;starting sector number of disc operation
gentrk = $00BB ;first free track while assigning volumes
skewit = $00BB ;running track skew counter while formatting
work = $00BC ;18 bytes; rearranged copy of OSFILE control block plus temporaries:
lodcat = work +$0000 ;temp cat offset in OSFILE $FF
zfrpg = work +$0001 ;address of lowest free/used page in copy buffer
wrkcat = work +$0002 ;load/exec/length/start sector in catalogue format
lodlo = work +$0002 ;LSB load address in OSFILE
page = work +$0002 ;pointer to OSHWM (PAGE) while writing empty BASIC program
lodhi = work +$0003 ;3MSB load address in OSFILE
tries = work +$0003 ;retry counter at data transfer level 3
exelo = work +$0004 ;LSB exec address in OSFILE
ceillo = work +$0004 ;LSB size in sectors of maximum available allocation
ftraks = work +$0004 ;number of tracks on disc in *FORMAT, *VERIFY, *VOLGEN
exehi = work +$0005 ;3MSB exec address in OSFILE
ceilhi = work +$0005 ;MSB size in sectors of maximum available allocation
volidx = work +$0005 ;volume index in *VOLGEN
lenlo = work +$0006 ;LSB file length in OSFILE
strtlo = work +$0006 ;LSB start address in OSFILE 0
icatmp = work +$0006 ;offset while testing for space to create catalogue entry
excesl = work +$0006 ;LSB sector excess: requested file allocation minus space available;
;headroom when negative
mapvol = work +$0006 ;physical volume of open file while moving open files
mapdfl = work +$0006 ;difference between LBAs / move distance while moving open files
zfrsiz = work +$0007 ;zero-page copy of size of user memory
lenhi = work +$0007 ;2MSB file length in OSFILE
strthi = work +$0007 ;3MSB start address in OSFILE 0
excesh = work +$0007 ;MSB sector excess: requested file allocation minus space available;
;headroom when negative
movofs = work +$0007 ;channel workspace offset of open file being extended
;(to avoid moving it while shifting following files down)
;=0 while shifting up to ensure open file is included
lbahi = work +$0008 ;MSB LBA in OSFILE
endlo = work +$0008 ;LSB end address in OSFILE 0
allocl = work +$0008 ;LSB length of file in sectors
lbaxlo = work +$0008 ;LSB LBA of end of previous file (little-endian)
slackl = work +$0008 ;LSB size of slack space before current file, in sectors
prodl = work +$0008 ;LSB product of multiplication
lbalo = work +$0009 ;LSB LBA in OSFILE
endhi = work +$0009 ;3MSB end address in OSFILE 0
alloch = work +$0009 ;MSB length of file in sectors
lbaxhi = work +$0009 ;MSB LBA of end of previous file (little-endian)
slackh = work +$0009 ;MSB size of slack space before current file, in sectors
prodh = work +$0009 ;MSB product of multiplication
lenhl = work +$000A ;MSB length of file while creating catalogue entry
todolo = work +$000A ;LSB length in sectors of file being copied
mfreel = work +$000A ;LSB total number of free sectors in volume
todohi = work +$000B ;MSB length in sectors of file being copied
mfreeh = work +$000B ;MSB total number of free sectors in volume
wrknam = work +$000B ;current filename
mheadl = work +$000C ;LSB sector headroom: total free sectors minus sector excess
;i.e. free sectors remaining after files moved
srclo = work +$000C ;LSB LBA of next sector to copy from source
mheadh = work +$000D ;MSB sector headroom: total free sectors minus sector excess
;i.e. free sectors remaining after files moved
srchi = work +$000D ;MSB LBA of next sector to copy from source
dstlo = work +$000E ;LSB LBA of next sector to copy to destination
dsthi = work +$000F ;MSB LBA of next sector to copy to destination
mvuplo = work +$0010 ;LSB sector excess to be absorbed by shifting previous files up
cpycat = work +$0010 ;offset of catalogue entry in *COMPACT
mvuphi = work +$0011 ;MSB sector excess to be absorbed by shifting previous files up
qualif = $00CE ;current directory
fdrive = $00CF ;current drive
;Zero-page system variables
worda = $00EF ;reason code in A on entry to OSWORD
wordx = $00F0 ;LSB control block address in X on entry to OSWORD
wordy = $00F1 ;MSB control block address in Y on entry to OSWORD
linptr = $00F2 ;2 bytes; pointer to character array in GSINIT/Svc $25
romid = $00F4 ;slot number of ROM currently paged in
escflg = $00FF ;b7=0 normal, b7=1 ESCAPE pressed
;System reserved memory
stack = $0100 ;hardwired 6502 stack page
errbuf = $0100 ;error trampoline so a language ROM can print the message
vtab2 = $0212 ;FILEV, first FS vector claimed by DFS
fscvec = $021E ;FSCV vector to control/shut down current FS
taddrl = $0406 ;Set up address for Tube
intnmi = $0D00 ;NMI service routine
priptr = $0DF0 ;table of private pages to each ROM
;Conventional Acorn DFS shared workspace
ddirlo = $0E00 ;memory address of catalogue sector 0 under Acorn DFS
ddirhi = $0F00 ;catalogue sector 1 presented here when *ENABLE CAT selected
;Expansion hardware
fred = $FC00 ;page of addresses for external MMIO devices
jpghi = fred +$00FE ;MSB expansion RAM paging register
jpglo = fred +$00FF ;LSB expansion RAM paging register
;Expansion memory
jim = $FD00 ;when testing for expansion RAM or copying pages
base = jim +$0000 ;Challenger workspace starts here
auxws = base +$0000 ;auxiliary workspace at $000000..$0000FF
config = auxws +$0000 ;*CONFIG mapping, logical drives 0..7 to physical drive (b2..0)
adfsmp = config+$0008 ;ChADFS mapping, logical drives 0..7 to physical drive (b2..0)
cbtbl = auxws +$0011 ;copy buffer table, 8 entries * 23 bytes
cbcat = cbtbl +$0000 ;cf. BE..C5 Load/exec/length/start sector of file in copy buffer
cbtxsz = cbcat +$0007 ;size of current transfer
cbflag = cbcat +$0008 ;flag byte b7=source read incomplete b6=dest. file part written
cbname = cbflag+$0001 ;cf. C7..CE Name and directory of file in copy buffer
cblnlo = cbname+$0008 ;LSB length in sectors of file being copied
cblnhi = cblnlo+$0001 ;MSB length in sectors of file being copied
cbslbl = cblnhi+$0001 ;LSB LBA of next sector to copy from source volume, little-endian
cbslbh = cbslbl+$0001 ;MSB LBA of next sector to copy from source volume, little-endian
cbdlbh = cbslbh+$0001 ;MSB LBA of next sector to copy to destination volume, big-endian
cbdlbl = cbdlbh+$0001 ;LSB LBA of next sector to copy to destination volume, big-endian
cbtble = cbdlbl+$0001 ;end of copy buffer table entry
voltks = auxws +$00CD ;first track of data area of volumes A..H
volszh = auxws +$00D5 ;MSB sizes assigned to volumes A..H in *VOLGEN (big-endian)
volszl = auxws +$00D6 ;LSB sizes assigned to volumes A..H in *VOLGEN (big-endian)
mainws = base +$0000 ;main workspace at $000100..$0001FF
senti1 = mainws+$0000 ;first workspace sentinel $65,$E5=workspace valid
;b7=Challenger is current FS
;$000101..$0001A0 reserved for channel workspace (see below)
chrn = mainws+$0061 ;$000161..$0001A9 = table of sector headers during *FORMAT
dosram = mainws+$00A1 ;18 bytes; copy of OSFILE/OSGBPB control block
ldlow = mainws+$00B3 ;4 bytes; load address passed to OSFILE; Tube tx addr
hiwork = ldlow +$0002 ;8 bytes; high words of load/exec/start/end to OSFILE
exlow = hiwork+$0000 ;overlaps ldlow; exec address passed to OSFILE
strthl = hiwork+$0004 ;2MSB start address in OSFILE 0
strthh = hiwork+$0005 ;MSB start address in OSFILE 0
endhl = hiwork+$0006 ;2MSB end address in OSFILE
btemp = mainws+$00BE ;2 bytes; pointer to user's OSGBPB control block
renvol = mainws+$00C0 ;source physical volume in *RENAME
catofs = mainws+$00C2 ;offset of catalogue entry, 0..$F0, multiple of 8
stasha = mainws+$00C3 ;saved A register on entry to OSBPUT
stashx = mainws+$00C4 ;saved X register on entry to OSBPUT, OSBGET
stashy = mainws+$00C5 ;saved Y register on entry to OSBPUT, OSBGET
defqua = mainws+$00C6 ;default (CSD) directory character
defdsk = mainws+$00C7 ;default (CSD) drive (b3..0) and volume (b6..4)
libqua = mainws+$00C8 ;library directory character
libdsk = mainws+$00C9 ;library drive (b3..0) and volume (b6..4)
fdriv = mainws+$00CA ;source volume in *BACKUP, *COPY
tdriv = mainws+$00CB ;destination volume in *BACKUP, *COPY
tubflg = mainws+$00CC ;b7=Tube data transfer
notube = mainws+$00CD ;$00=Tube coprocessor present $FF=Tube absent (inverted MOS flag)
dcbmap = mainws+$00CE ;channel open flags
dcbbit = mainws+$00CF ;channel open bit mask for current open file
dcby = mainws+$00D0 ;channel workspace pointer for current open file
seqwb = mainws+$00D2 ;offset of catalogue entry of current open file
seqwc = mainws+$00D3 ;not used in _BUGFIX
frpage = mainws+$00D5 ;MSB of OSHWM; lowest page number of user memory
hipage = mainws+$00D6 ;MSB of HIMEM; 1 + highest page number of user memory
frsize = mainws+$00D7 ;number of pages of user memory; = hipage - frpage
wildch = mainws+$00D8 ;$23=wildcard characters allowed in filename $FF=no wildcards
monflg = mainws+$00D9 ;*OPT 1 monitor 0=verbose $FF=quiet
ctemp = mainws+$00DA ;transfer direction 0=writing from memory 1=reading to memory
tumflg = mainws+$00DB ;$00=transferring to/from host $FF=transferring to/from Tube
catdrv = mainws+$00DC ;drive and volume of catalogue in pages 2..3; b7=catalogue invalid
nmiflg = mainws+$00DD ;NMI ownership flag b7=we own NMI
prenmi = mainws+$00DE ;previous owner of NMI area
enaflg = mainws+$00DF ;*ENABLE counter 1=*ENABLE just called 0=current command enabled
;$FF=current command not enabled
qtemp = mainws+$00E0 ;2 bytes; action address in OSGBPB
srcopt = mainws+$00E0 ;b7..4=boot option of source volume in *BACKUP
linadr = mainws+$00E2 ;2 bytes; offsets of command line start and tail;
;pointer to arguments of *RUN, */ command
fcbadr = mainws+$00E4 ;2 bytes; pointer to user's OSFILE control block
restrt = mainws+$00E6 ;command restart action address
txcall = mainws+$00E9 ;data transfer call number 0=read data 1=write data
;3=write deleted data 4=verify data b7=data address in JIM space
spregs = mainws+$00EA ;5 bytes; special registers 0..4
t40flg = spregs+$0000 ;$00=single stepping b6=double stepping b7=automatic stepping
sectrk = spregs+$0001 ;number of sectors per track $0A=single density $12=double density
voltrk = spregs+$0002 ;first track of current volume (=0 unless set from disc catalogue)
denflg = spregs+$0003 ;$00=single density b6=double density b7=automatic density
savrom = spregs+$0004 ;*OPT 9 number of paged ROM slot to page in during disc operations
head = mainws+$00EF ;3 bytes; physical track number under heads on drive 0/2, 1/3, 6/7
speed = mainws+$00F2 ;track stepping rate in WD 1770 format 0=fast..3=slow
fdstat = mainws+$00F3 ;status of last FDC command, reported by *FDCSTAT
enacat = mainws+$00F4 ;b7=*ENABLE CAT emulate Acorn DFS's main memory use
dscszh = mainws+$00F5 ;MSB size of disc in sectors (big-endian)
dscszl = mainws+$00F6 ;LSB size of disc in sectors (big-endian)
cblast = mainws+$00F7 ;offset of last entry of copy buffer file table, n*$17 ($00..A1)
cbcurs = mainws+$00F8 ;offset of current entry of copy buffer file table
packed = mainws+$00F9 ;packed drive parameters of source, destination volume (Y=0 or 2)
cpvltk = mainws+$00FA ;first track of source, destination volume (Y=0 or 2)
senti2 = mainws+$00FD ;second workspace sentinel $E5=workspace valid
ramden = mainws+$00FE ;RAM disc density flag b6=double density
chadfs = mainws+$00FF ;b6=ChADFS is current filing system
seqmap = base -$001F ;channel workspace at $000101..$0001A0, accessed at offsets $20..$A0
seqcat = seqmap+$0000 ;name of open file (even offsets)
;load/exec/length/start sector in catalogue format (odds)
seqll = seqcat+$0009 ;LSB of file length in catalogue entry
seqlm = seqcat+$000B ;2MSB of file length in catalogue entry
seqrdo = seqcat+$000C ;seventh character of filename; b7=channel read-only
seqlh = seqcat+$000D ;top bits exec/length/load/LBA in catalogue entry
seqlok = seqcat+$000E ;directory character of filename; b7=file locked
seqloc = seqcat+$000F ;LSB of starting LBA in catalogue entry
seqpl = seqmap+$0010 ;LSB of sequential pointer (PTR)
seqpm = seqmap+$0011 ;2MSB of sequential pointer
seqph = seqmap+$0012 ;MSB of sequential pointer
seqbuf = seqmap+$0013 ;packed drive parameters b7=auto density b6=double density
seqlla = seqmap+$0014 ;LSB of open file's extent (EXT)
seqlma = seqmap+$0015 ;2MSB of open file's extent
seqlha = seqmap+$0016 ;MSB of open file's extent
seqflg = seqmap+$0017 ;channel flags b7=buffer contains PTR b6=buffer changed
;b5=EXT changed b4=EOF warning given
;NB seqmap+$0018 'seqel' always contains zero
seqem = seqmap+$0019 ;LSB of number of sectors allocated to file
seqeh = seqmap+$001A ;MSB of number of sectors allocated to file
seqbit = seqmap+$001B ;channel open bit mask corresponding to open file
seqdal = seqmap+$001C ;LSB of starting LBA
seqdah = seqmap+$001D ;MSB of starting LBA
sequal = seqmap+$001E ;first track of volume of open file
seqchk = seqmap+$001F ;volume and drive of open file
dirlow = base +$0000 ;catalogue of current volume or disc catalogue at $000200..$0003FF
dcver = dirlow+$0000 ;disc catalogue version number, $20=DDOS/Challenger
dcszhi = dcver +$0001 ;MSB number of sectors on disc surface
dcszlo = dcszhi+$0001 ;LSB number of sectors on disc surface
dcspt = dcszlo+$0001 ;number of sectors per track
dctrks = dcspt +$0001 ;number of tracks on disc surface
dcmyst = dctrks+$0001 ;mystery field, always zero
dcvtrk = dirlow+$0008 ;first track of data area of volume, 8 volumes (Y=2*n, n=0..7)
dcvmst = dcvtrk+$0001 ;mystery per-volume field, always zero
catlow = dirlow+$0008 ;first catalogue entry; filename
catdun = catlow+$0000 ;b7=catalogue entry listed
modify = catlow+$0007 ;directory letter; b7=file locked
dirhig = base +$0000 ;second sector of catalogue
cycno = dirhig+$0004 ;BCD cycle number, incremented when updating catalogue
dirlen = dirhig+$0005 ;number of files in catalogue * 8; pointer to last entry
option = dirhig+$0006 ;when accessing option bits
cathig = dirhig+$0008 ;first catalogue entry; attributes
slots = base +$0000 ;channel sector buffers at $000400..$0008FF
runlen = slots +$0000 ;run lengths in RLE formatting table, lower half of each page
rundat = slots +$0080 ;data bytes in RLE formatting table, upper half of each page
lnbuff = base +$0000 ;OSWORD $00 line buffer in *BUILD
;System hardware
sheila = $FE00 ;page of addresses for internal MMIO devices
romsw = sheila+$0030 ;ROMSEL paged ROM selection latch
reg3 = sheila+$00E5 ;Tube FIFO 3
;Floppy drive controller
IF _O2791C
fdc = sheila+$0080 ;base of floppy drive controller registers
latch = sheila+$0084 ;floppy drive interface control latch
ELIF _O2793C
fdc = sheila+$0080 ;base of floppy drive controller registers
latch = sheila+$0084 ;floppy drive interface control latch
ELIF _O1770C
fdc = sheila+$0080 ;base of floppy drive controller registers
latch = sheila+$0084 ;floppy drive interface control latch
ELIF _W1770C
fdc = sheila+$0084 ;base of floppy drive controller registers
latch = sheila+$0080 ;floppy drive interface control latch
ELIF _A1770C
fdc = sheila+$0084 ;base of floppy drive controller registers
latch = sheila+$0080 ;floppy drive interface control latch
ELIF _M1770C
fdc = sheila+$0028 ;base of floppy drive controller registers
latch = sheila+$0024 ;floppy drive interface control latch
ELIF _PG400C
fdc = fred +$00C4 ;base of floppy drive controller registers
latch = fred +$00C0 ;floppy drive interface control latch
ELIF _S1770C
fdc = sheila+$0080 ;base of floppy drive controller registers
latch = sheila+$0086 ;floppy drive interface control latch
ELSE
fdc = fred +$00F8 ;base of floppy drive controller registers
latch = fred +$00FC ;floppy drive interface control latch
ENDIF
fdccmd = fdc +$0000 ;WD 1770 command register (write only)
fdcsta = fdc +$0000 ;WD 1770 status register (read only)
fdctrk = fdc +$0001 ;WD 1770 track register
fdcsec = fdc +$0002 ;WD 1770 sector register
fdcdat = fdc +$0003 ;WD 1770 data register
;Acorn MOS system calls
gsinit = $FFC2 ;Set up to read string from character array
gsread = $FFC5 ;Read character from string
osfind = $FFCE ;Open or close a sequential file
osbput = $FFD4 ;Write byte to sequential file
osbget = $FFD7 ;Read byte from sequential file
osrdch = $FFE0 ;Read character from console
osasci = $FFE3 ;Write character to console translating CR to newline
oswrch = $FFEE ;Write character to console
osword = $FFF1 ;Perform various OS functions according to control block
osbyte = $FFF4 ;Perform various OS functions according to registers
oscli = $FFF7 ;Interpret command line
ORG $8000
.lang ;Language entry
BRK
EQUW $0000
JMP called ;Service entry
EQUB $82 ;rom type: service only
EQUB copyr-lang ;copyright offset pointer
EQUB $22 ;version No.
EQUS "Challenger 3" ;title
EQUB $00 ;terminator byte
EQUS "2.20" ;version string
.copyr
EQUB $00 ;terminator byte
EQUS "(C)2024 Otus" ;copyright string validated by MOS
EQUB $00 ;terminator byte
.osfscm ;Issue Filing System Call
JMP (fscvec)
.called ;ROM service
CMP #$01
BNE savpri ;Service call $01 = reserve absolute workspace
JSR savita ;save AXY
JSR L821F ;probe Challenger unit RAM size
TAX
BEQ L8086 ;if Challenger unit absent then return
JSR pgmain ;else page in main workspace
JSR LBA00 ;issue Force Interrupt
LDA senti1 ;validate first workspace sentinel
AND #$7F ;[D]mask off b7=Challenger is current FS
CMP #$65 ;[D]compare remainder with valid value $65/E5
BEQ L8053 ;if equal then validate second sentinel
LDA #$65 ;else initialise sentinel=$65, b7=0 no FS
STA senti1
JSR LAB7E ;initialise Challenger and ChADFS mappings
.L8053
LDA #$E5 ;validate second workspace sentinel
CMP senti2
BEQ L806D ;if not equal to valid value $E5
STA senti2 ;then initialise second sentinel
LDA #$04 ;[D]set current drive = 4
STA fdrive
LDX #$02 ;x=2 select drive 4 volume size = $3F5
JSR LAFF8 ;initialise RAM disc catalogue
INC fdrive ;current drive = 5
LDX #$03 ;x=3 select drive 5 volume size = $3FF
JSR LAFF8 ;initialise RAM disc catalogue
.L806D
LDA #$FD ;OSBYTE $FD = read/write type of last reset
JSR readby ;call OSBYTE with X=0, Y=$FF
TXA ;test type of last reset
BEQ L8078 ;if A=0 then soft break so skip
JSR L82A4 ;else initialise workspace
.L8078
JSR L82C8 ;initialise workspace part 2
BIT enacat ;[D]test b7=*ENABLE CAT
BPL L8086 ;if enabled
TSX ;[D]then return Y=$17 nine pages of workspace
LDA #$17
CMP stack+$03,X ;unless a higher ROM needs more
BCC L8086 ;in which case exit
STA stack+$03,X ;else return Y=$17
.L8086
RTS
.savpri
CMP #$02
BNE pmsg ;Service call $02 = reserve private workspace
JSR pgmain ;page in main workspace
BIT enacat ;[D]test b7=*ENABLE CAT
BPL L8095 ;if enabled
INY ;then reserve two pages of private workspace
INY ;pass updated HWM in Y
.L8095
RTS
.pmsg
CMP #$03
BNE chkcom ;Service call $03 = boot
JSR pgmain ;page in main workspace
STY bootfs ;save boot flag in scratch space
JSR savita ;save AXY
LDA #$7A ;call OSBYTE $7A = scan keyboard from $10+
JSR osbyte
TXA ;test returned key code
BMI aboot0 ;if N=1 no key is pressed, so init and boot
CMP #$52 ;[D]else if key pressed is not C
BNE L8095 ;then exit
LDA #$78 ;else register keypress for two-key rollover
JSR osbyte
.aboot0
.L81EE ;Initialise Chall. and boot default volume
LDA bootfs ;get back boot flag (Y on entry to call $3)
PHA ;save on stack
SEC
JSR LAE5E ;print Challenger banner
JSR pcrlf ;print newline
JSR L8219 ;get Challenger unit type
AND #$03 ;extract b1,b0 of A
BEQ L8217 ;if Challenger not installed then exit
JSR L82C8 ;else initialise workspace part 2
JSR sinit0 ;initialise Challenger FS
PLA ;if boot flag was >0
BNE L820B ;then return A=0 to claim call
JMP L82F7 ;else examine and boot default volume
.L820B ;Return A=0
; LDA #$00 ;redundant; returns zero poked by sinit0
RTS ;in savita set by pmsg
.chkcom
CMP #$04
BNE dohelp ;Service call $04 = unrecognised *command
JSR pgmain ;page in main workspace
JSR savita ;save AXY
TSX
STX abrtsp ;save stack pointer to restore on abort
TYA ;a=offset of *command from GSINIT pointer
LDX #initbl
JSR wname0 ;search for command in table
BCS unkswz ;if not found then exit
LDA senti1 ;[D]else test b7=Challenger is current FS
BMI L80D7 ;if b7=1 then execute *command
JSR tramp ;else get syntax byte from command table
BMI unkswz ;if b7=1 restricted command then return
.L80D7
JMP (action) ;else execute *command, Y=cmd line tail ptr
.dohelp
CMP #$09
BNE inifsy ;Service call $09 = *HELP
JSR pgmain ;page in main workspace
JSR savita ;save AXY
LDA (linptr),Y ;test character at start of *HELP string
CMP #$0D ;if not CR then *HELP called with keyword
BNE L80F4 ;so scan keyword
LDX #hlptab
LDA #$03 ;3 entries to print
JMP help1 ;print *HELP keywords and pass on the call.
.L80F4 ;Scan *HELP keyword
JSR setupr ;call GSINIT with C=0
BEQ unkswz ;if no keyword then exit, else:
;Search for *HELP keyword
TYA ;a=offset of keyword from GSINIT pointer
PHA ;also save on stack
LDX #hlptab
JSR wname0 ;search for keyword in table
BCS L810A ;if keyword found
JSR L80D7 ;then call its action address; print help
.L810A
PLA ;restore string offset
TAY
.L810C
JSR gsread ;call GSREAD
BCC L810C ;until end of argument (discarding it)
BCS L80F4 ;then scan next *HELP keyword
.inifsy
CMP #$12
BNE msters
CPY #$04 ;Service call $12 = initialise FS
BNE unkswz ;if number of FS to initialise = 4
JSR pgmain ;then page in main workspace
JSR savita ;save AXY
.L820E ;*DISC / *DISK
PHA
JSR L8236 ;probe JIM page $0001 for RAM
BNE L8217 ;if RAM found then Challenger unit installed
JSR sinit0 ;so initialise Challenger FS
.L8217
PLA
.unkswz
RTS
IF _MASTER
.sv25h ;Service call $25 = filing system info
LDX #fsblke-L88F0-$01 ;22 bytes to write:
.L890C
LDA L88F0,X ;get byte of filing system info
STA (linptr),Y ;add to MOS table
INY ;increment table offset
DEX ;decrement count
BPL L890C ;loop until 22 bytes written
LDX romid ;restore AX, pass updated Y
LDA #$25
RTS
ENDIF
.msters
IF _MASTER
CMP #$25
BCC unkwrd ;if call no. < $25 then test for 8
BEQ sv25h ;if call no. = $25 then write FS info
CMP #$27
BCC sv26h ;if call no. = $26 then *SHUT all files
BNE unkswz ;if call no. > $26 then pass it on, else:
JSR ischal ;Service call $27 = reset occurred
BNE nreset ;if Challenger not initialised then pass call
JSR L9753 ;else forget catalogue in JIM pages 2..3
.nreset
LDA #$27 ;restore call number
RTS ;pass on service call.
.sv26h ;Service call $26 = *SHUT command issued
JSR ischal ;if Challenger initialised
BEQ shut ;then proceed
.bail
LDA #$26 ;else pass on the call.
RTS
.ischal ;Test whether Challenger FS active
;on entry X=romid
LDA priptr,X ;get type from private page pointer
AND #$03 ;mask Challenger unit type 0..2
BEQ bail ;if Challenger not present then return Z=0
JSR pgmain ;else page in main workspace
LDA #$E5 ;validate second sentinel
CMP senti2 ;if invalid then return Z=0
BNE bail
EOR senti1 ;else validate first sentinel (bits 6..0)
ASL A ;return Z=1 iff Challenger initialised
RTS ;return C=1 if Challenger NOT the current FS
.shut
LDA dcbmap ;if no files are open
AND #$F8
BEQ bail ;then exit
LDA #$26 ;else restore call number
JSR savita ;save AXY
BCC shut1 ;if Challenger FS active then shut all files
JSR sinit1 ;initialise Challenger preserving call no.
.shut1
JMP close2 ;close a file/all files and return
ENDIF
.unkwrd
CMP #$08
BNE unkswz ;Service call $08 = unrecognised OSWORD
JSR pgmain ;page in main workspace
JSR savit ;save XY (X will be clobbered on return)
LDY wordx ;set $B0..1 = pointer to OSWORD control block
STY blkptr+$00
LDY wordy
STY blkptr+$01
LDY #$00
STY dopint ;=0 disc operation is uninterruptible
LDY worda ;set Y = OSWORD call number (in A on entry)
CPY #$7F
BNE gtdsks
JSR nmicla ;OSWORD A = $7F
LDY #$01 ;claim NMI
LDA (blkptr),Y ;offset 1 = address LSB
STA nmiusr+$00 ;copy to $A6
INY
LDA (blkptr),Y ;offset 2 = address 3MSB
STA nmiusr+$01 ;copy to $A7
LDY #$00
LDA (blkptr),Y ;offset 0 = drive number
BMI L8165 ;if b7=1 then use previous drive
PHA ;[D]else save requested drive
ROL A ;shift bit 3 = force double density
ROL A ;to bit 6
ROL A
AND #$40 ;mask bit 6 = hardware double density flag
ORA denflg ;or with *DENSITY detected/forced DD flag
STA denflg ;update *DENSITY flag
PLA ;restore requested drive
AND #$07 ;extract drive number 0..7
STA fdrive ;set as current drive
.L8165
INY ;offset 1 = address
LDX #$02
JSR shftbo ;copy address to $BE,F,$FDB5,6
LDA (blkptr),Y ;[D]y = 5 on exit; offset 5 = no. parameters
PHA ;save number of parameters
INY ;increment offset
LDA (blkptr),Y ;offset 6 = command
AND #$3F
STA o7fcmd
JSR sfour ;shift A right 4 places, extract bit 4:
AND #$01 ;a=0 if writing to disc, A=1 if reading
JSR chktub ;open Tube data transfer channel
LDY #$07
LDA (blkptr),Y ;offset 7 = first parameter (usu. track)
INY ;offset 8, Y points to second parameter
STA track
LDX #$FD ;x = $FD to start at offset 0:
.L8186
INX ;add 3 to X
INX
INX
LDA LB8AD+$00,X ;get command byte from table
BEQ L81AE ;if the terminator byte then exit
CMP o7fcmd ;else compare with OSWORD $7F command
BNE L8186 ;if not the same try next entry
PHP ;else save interrupt state
CLI ;enable interrupts
LDA #>(L81A3-$01) ;[D]push return address $81A3 on stack
PHA
LDA #<(L81A3-$01)
PHA
LDA LB8AD+$02,X ;fetch action address high byte
PHA ;push on stack
LDA LB8AD+$01,X ;fetch action address low byte
PHA ;push on stack
RTS ;jump to action address.
.L81A3 ;Finish OSWORD $7F
TAX ;[D]hold result in X
PLP ;restore interrupt state
PLA ;[D]restore number of parameters
CLC ;add 7; drive, address, no.parms, command
ADC #$07 ;=offset of result in O7F control block
TAY ;transfer to Y for use as offset
TXA
STA (blkptr),Y ;[D]store result in user's OSWORD $7F block
PHA ;[D]push dummy byte on stack:
.L81AE
PLA ;[D]discard byte from stack
JSR nmirel ;release NMI
JSR L96E6 ;release Tube
LDA #$00 ;exit A=0 to claim service call
RTS
.gtdsks ;OSWORD A <> $7F
BCS L81ED ;if A > $7F then exit
CPY #$7D ;else if A < $7D
BCC L81ED ;then exit
JSR setdef ;set current vol/dir = default, set up drive
JSR L962F ;load volume catalogue L4
CPY #$7E
BEQ getdsz ;OSWORD A = $7D
JSR pgcat1 ;page in catalogue sector 1
LDY #$00 ;store in OSWORD control block offset 0
LDA cycno ;get catalogue cycle number
STA (blkptr),Y ;store in OSWORD control block offset 0
TYA ;return A = 0, claiming service call.
RTS
.getdsz ;OSWORD A = $7E get size of volume in bytes
JSR pgcat1 ;page in catalogue sector 1
LDA #$00
TAY
STA (blkptr),Y ;store 0 at offset 0: multiple of 256 bytes
INY ;offset 1
LDA dirhig+$07 ;get LSB volume size from catalogue
STA (blkptr),Y ;save as 3MSB volume size
INY ;offset 2
LDA dirhig+$06 ;get boot option/top bits volume size
AND #$03 ;extract MSB volume size
STA (blkptr),Y ;save as 2MSB volume size
INY ;offset 3
LDA #$00 ;store 0: volume size less than 16 MiB
STA (blkptr),Y ;Y = 3; store LSB volume size
.L81ED
RTS ;return A = 0, claiming service call.
.L8219 ;Get Challenger unit type
LDX romid ;get our ROM slot number
LDA priptr,X ;get type from private page pointer
RTS
;ChADFS ROM call 2
.L821F ;Probe Challenger unit RAM size
LDX #$00 ;set X=0, no RAM found
JSR L8236 ;probe JIM page $0001 for RAM
BNE L822F ;if RAM absent return 0
INX ;else X=1, 256 KiB unit
LDA #$04 ;probe JIM page $0401 for RAM
JSR L8238 ;will hit empty sockets, not alias to bank 0
BNE L822F ;if RAM absent return 1
INX ;else X=2, 512 KiB unit
.L822F
TXA
LDX romid ;get our ROM slot number
STA priptr,X ;store Challenger unit type in private pg ptr
RTS
.L8236 ;Probe JIM page $0001 for RAM
LDA #$00
.L8238 ;Probe JIM page (A*$100)+$01 for RAM
STA jpghi ;store MSB JIM paging register
LDA #$01 ;page $0001 (main workspace) or $0401
STA jpglo ;store LSB JIM paging register
LDA jim+$00 ;read offset 0 of JIM page
EOR #$FF ;invert it
STA jim+$00 ;write it back
LDY #$05 ;wait 13 microseconds
.L824A
DEY ;allow 1 MHz data bus to discharge
BNE L824A
CMP jim+$00 ;read offset 0, compare with value written
PHP ;save result
EOR #$FF ;restore original value
STA jim+$00 ;write back in case RAM is there
PLP ;return Z=1 if location 0 acts like RAM
RTS
.sinit0 ;Initialise Challenger FS
LDA #$00
TSX
STA stack+$08,X ;have A=0 returned on exit
.sinit1
LDA #$06 ;FSC $06 = new FS about to change vectors
JSR osfscm ;issue Filing System Call
LDX #$00 ;x = 0 offset in MOS vector table
.init0
LDA vtabb,X ;copy addresses of extended vector handlers
STA vtab2,X ;to FILEV,ARGSV,BGETV,BPUTV,GBPBV,FINDV,FSCV
INX ;loop until 7 vectors transferred
CPX #$0E
BNE init0
JSR LADE8 ;call OSBYTE $A8 = get ext. vector table addr
STY evtptr+$01 ;set up pointer to vector table
STX evtptr+$00
LDX #$00 ;x = 0 offset in Challenger vector table
LDY #$1B ;y = $1B offset of FILEV in extended vec tbl
.init1
LDA vtabf,X ;get LSB action address from table
STA (evtptr),Y ;store in extended vector table
INX
INY
LDA vtabf,X ;get MSB action address from table
STA (evtptr),Y ;store in extended vector table
INX
INY
LDA romid ;get our ROM slot number
STA (evtptr),Y ;store in extended vector table
INY
CPX #$0E ;loop until 7 vectors transferred
BNE init1
LDA senti1 ;[D]get first workspace sentinel
ORA #$80 ;set b7=1 Challenger is current FS
STA senti1 ;update first sentinel
LDA #$00
STA chadfs ;b6=0 Challenger is current FS
LDX #$0F ;service call $0F = vectors claimed
JMP doswcl ;call OSBYTE $8F = issue service call
;[D]no wksp/private page validation/init
.L82A4 ;Initialise workspace part 1
JSR pgmain ;page in main workspace
LDA #$80 ;a=$80
STA denflg ;*OPT 6,0 automatic density
STA t40flg ;*OPT 8,255 automatic stepping
LDA #srom ;a=$0E
STA savrom ;*OPT 9,14 page in ROM slot 14 during disc ops
LDA #$00
STA defdsk ;set default volume = "0A"
STA libdsk ;set library volume = "0A"
STA enacat ;[D]no *ENABLE CAT
LDA #$24
STA defqua ;set default directory = "$"
STA libqua ;set library directory = "$"
RTS
.L82C8 ;Initialise workspace part 2
JSR pgmain ;page in main workspace
JSR LADE4 ;call OSBYTE $EA = read Tube presence flag
TXA
EOR #$FF ;invert; 0=tube present $FF=Tube absent
STA notube ;save Tube presence flag
LDY #$00 ;y=$00 [D]no workspace validation
STY dcbmap ;no files are open
STY prenmi ;no previous NMI owner
STY nmiflg ;NMI resource is not ours
STY tubflg ;[D]no Tube data transfer in progress
STY chadfs ;b6=0 Challenger is current FS
DEY ;y=$FF
STY enaflg ;*commands are not *ENABLEd
STY monflg ;*OPT 1,0 quiet operation
STY catdrv ;no catalogue in JIM pages 2..3
JMP LB8F7 ;set track stepping rate from startup options
.L82F7
JSR setdef ;set current volume and directory = default
JSR dirldy ;load volume catalogue
LDY #$00
LDX #$00
JSR pgcat1 ;page in catalogue sector 1
LDA option ;get boot option/top bits volume size
JSR sfour ;shift A right 4 places
BEQ L8331 ;if boot option = 0 then exit
PHA
LDX #run
JSR stxylp ;set GSINIT pointer to XY, set Y=0
JSR getnam ;set current file from file spec
JSR lookup ;search for file in catalogue
PLA ;restore boot option
BCS L8332 ;if !BOOT found then boot from it
JSR vstrng ;else print "File not found" and return
EQUS "File not found"
EQUB $0D
EQUB $0D
NOP
.L8331
RTS
.L8332
CMP #$02
BCC L8344 ;if boot option = 1 then load !BOOT
BEQ L833E ;if boot option = 2 then run !BOOT
LDX #exec ;point XY to "E.!BOOT"
BNE L8348 ;call OSCLI
.L833E
LDX #run
BNE L8348 ;call OSCLI
.L8344
LDX #load
.L8348
JMP oscli ;call OSCLI
.load
EQUS "L.!BOOT"
EQUB $0D
.exec
EQUS "E."
.run
EQUS "!BOOT"
EQUB $0D
.type ;*TYPE
JSR zerchk ;claim service call and set up argument ptr
LDA #$00 ;a = $00 CR does not trigger line no.
BEQ type0
.list ;*LIST
JSR zerchk ;claim service call and set up argument ptr
LDA #$FF ;a = $FF CR triggers line number
.type0
STA lstmsk ;store CR mask
LDA #$40 ;OSFIND $40 = open a file for reading
JSR osfind ;call OSFIND
TAY ;test returned file handle
BEQ L83A1 ;if file not found then raise error
LDA #$0D ;preload CR so *LIST prints line no. 1
BNE type3 ;branch to CR test (always)
.type1
JSR osbget ;call OSBGET
BCS type2 ;if EOF then finish
CMP #$0A ;else if character is LF
BEQ type1 ;ignore it and get next one
PLP ;else restore result of (A AND mask) - CR
BNE type4 ;if no match just print the character
PHA ;else save first character of line
JSR iprdec ;increment and print BCD word
JSR pspace ;print a space
PLA ;restore first character
.type4
JSR osasci ;call OSASCI
BIT escflg ;if ESCAPE pressed
BMI L8399 ;then finish
.type3
AND lstmsk ;else apply mask to character just prt'd
CMP #$0D ;compare masked character with CR
PHP ;save result
JMP type1 ;and loop to read next character
.type2
PLP ;discard result of (A AND mask) - CR
.L8399
JSR pcrlf ;print newline
.type9
LDA #$00 ;OSFIND $00 = close file
JMP osfind ;call OSFIND and exit
.L83A1
JMP L8B46 ;raise "File not found" error
.dump ;*DUMP
JSR zerchk ;claim service call and set up argument ptr
LDA #$40 ;OSFIND $40 = open a file for reading
JSR osfind ;call OSFIND
TAY ;transfer file handle to Y
BEQ L83A1 ;if file not found raise error
.L83AF
BIT escflg ;if ESCAPE pressed
BMI type9 ;then close file and exit
LDA linnoh ;else get high byte of file offset
JSR bytout ;print hex byte
LDA linnol ;get low byte of file offset
JSR bytout ;print hex byte
JSR pspace ;print a space
TSX
STX dmpstk ;save stack pointer
LDX #$08 ;offset = 8 for indexed indirect load [D]not 0
.L83C5
JSR osbget ;call OSBGET
BCS L83D4 ;if EOF then finish
PHA ;[D]else save byte read for ASCII column
JSR bytout ;print hex byte
JSR pspace ;print a space
DEX ;decrement counter
BNE L83C5 ;loop until line complete
.L83D4
DEX ;test counter
BMI L83E4 ;if EOF on incomplete line
PHP ;then save status (N=0, C=1)
JSR vstrng ;pad hex column with "** "
EQUS "** "
LDA #$00
PLP ;restore status
PHA ;push NUL to pad ASCII column
BPL L83D4 ;loop until line complete (always)
.L83E4
PHP ;save C=EOF
TSX ;transfer stack pointer to X
LDA #$07
STA dumpct ;set counter to 7:
.dump6
LDA stack+$09,X ;[D]get byte 9..2 down = byte 1..8 of column
CMP #$7F ;if DEL or higher
BCS dump7 ;then print a dot
CMP #$20 ;else if a printable character
BCS dump8 ;then print it
.dump7
LDA #$2E ;else print a dot:
.dump8
JSR osasci ;call OSASCI
DEX ;decrement pointer, work toward top of stack
DEC dumpct ;decrement counter
BPL dump6 ;loop until line complete
JSR pcrlf ;print newline
LDA #$08 ;add 8 to file offset
CLC
ADC linnol
STA linnol
BCC dump9 ;carry out to high byte
INC linnoh
.dump9
PLP ;restore carry flag from OSBGET
LDX dmpstk ;[D]restore stack pointer to discard column
TXS
BCC L83AF ;if not at end of file then print next row
BCS type9 ;else close file and exit
.build ;*BUILD
JSR L8219 ;get Challenger unit type
AND #$03 ;extract b1,b0 of A
BNE build0 ;if Challenger not installed then ignore command
RTS
.build0
JSR zerchk ;claim service call and set up argument ptr
LDA #$80 ;OSFIND $80 = open a file for writing
JSR osfind ;call OSFIND
STA bldfh ;save file handle
JSR LA838 ;[D]set line number = 0 (OSFIND clobbers)
.L8422
JSR iprdec ;increment and print BCD word
JSR pspace ;print a space
LDA #>lnbuff ;y = $FD point to JIM page for OSWORD
STA bldtbl+$01
LDX #bldtbl-$01 AND $FF ;y = $FF
STY bldtbl+$02 ;maximum line length = 255
STY bldtbl+$04 ;maximum ASCII value = 255
INY
STY bldtbl+$00 ;clear low byte of pointer
STY bldtbl+$03 ;minimum ASCII value = 0
JSR pgbuil ;page in line buffer
TYA ;OSWORD $00 = read line of input
JSR osword ;call OSWORD
PHP ;save returned flags
STY lineln ;save length of line
LDY bldfh ;y = file handle for OSBPUT
LDX #$00 ;offset = 0 for indexed indirect load
.L8447
CPX lineln ;compare offset with line length
BEQ L8458 ;if end of line reached then terminate line
JSR pgbuil ;else page in line buffer
LDA lnbuff,X ;get character of line
JSR osbput ;call OSBPUT
INX ;increment offset
BNE L8447 ;and loop to write rest of line (always)
.L8458
PLP ;restore flags from OSWORD
BCS L8463 ;if user escaped from input then finish
LDA #$0D ;else A = carriage return
JSR osbput ;write to file
JMP L8422 ;and loop to build next line
.L8463
JSR ackesc ;acknowledge ESCAPE condition
JSR type9 ;close file:
.pcrlf ;Print newline
PHA
LDA #$0D
JSR pchr ;print character in A (OSASCI)
PLA
.L8470
RTS
.chkdsf ;Select source volume
JSR savita ;save AXY
JSR pgmain ;page in main workspace
LDX fdriv ;set X = source volume
LDA #$00 ;a=$00 = we want source disc
BEQ L8489 ;branch (always)
.chkdst ;Select destination volume
JSR savita ;save AXY
JSR pgmain ;page in main workspace
LDX tdriv ;set X = destination volume
LDA #$80 ;a=$80 = we want destination disc
.L8489
STX fdrive ;set wanted volume as current volume
;[D]no 'set up for current drive'
BIT swaps ;if disc swapping not required
BPL L8470 ;then exit, else:
.L8492
CMP tindrv ;compare wanted disc with disc in drive
BEQ L8470 ;if the same then do not prompt
STA tindrv ;else wanted disc is going into drive
JSR vstrng ;print "Insert "
EQUS "Insert "
NOP
BIT tindrv ;if b7=1
BMI L84B2 ;then print "destination"
JSR vstrng ;else print "source"
EQUS "source"
BCC L84C1 ;and branch (always)
.L84B2
JSR vstrng ;print " destination"
EQUS "destination"
NOP
.L84C1
JSR vstrng ;print " disk and hit a key"
EQUS " disk and hit a key"
NOP
JSR L84EF ;wait for keypress
JMP pcrlf ;print newline and exit
.getyn ;Ask user yes or no
JSR L84EF ;wait for keypress
AND #$5F ;convert to uppercase
CMP #$59 ;is it "Y"?
PHP ;save the answer
BEQ getyn0 ;if so then print "Y"
LDA #$4E ;else print "N"
.getyn0
JSR pchr ;print character in A (OSASCI)
PLP ;return Z=1 if "Y" or "y" pressed
RTS
.L84EF ;Wait for keypress
JSR clrkey ;call *FX 15,1 = clear input buffer
JSR osrdch ;call OSRDCH, wait for input character
BCC L84FA ;if ESCAPE was pressed
LDX abrtsp ;then abort our routine
TXS ;clear our stacked items, return to caller
.L84FA
RTS
.L84FB ;Restore parameters of source drive
LDY #$00 ;offset = 0
BEQ L8501 ;branch (always)
.L84FF ;Restore parameters of destination drive
LDY #$02 ;offset = 2:
.L8501 ;Restore parameters of source/dest drive
JSR pgmain ;page in main workspace
LDA cpvltk,Y ;[D]get first track of selected volume
STA voltrk ;set as first track of current volume
LDA packed,Y ;get packed drive parameters:
.L850D ;Restore packed drive parameters
PHA ;save packed drive parameters
AND #$C0 ;mask b7,b6
STA denflg ;store *OPT 6 density setting
PLA ;restore packed drive parameters
LSR A ;shift b1,b0 of A to b7,b6
ROR A
ROR A
PHA ;save other bits
AND #$C0 ;mask b7,b6
STA t40flg ;store *OPT 8 tracks setting
PLA ;restore b1,b0 = original b4,b3
AND #$03 ;mask b1,b0:
;Unpack and store sectors per track
;if A=0 on entry then RAM disc
BEQ L8558 ;so store 0=sectors per track undefined
LSR A ;else if A=1
BEQ unpksd ;then store 10 sectors per track
LDA #ddspt EOR sdspt ;else A>1, store 18 sectors per track
.unpksd
EOR #sdspt
.L8558
STA sectrk ;store number of sectors per track
RTS
.L8523 ;Save parameters of source drive
JSR savita ;save AXY
LDY #$00
BEQ L852F
.L852A ;Save parameters of destination drive
JSR savita ;save AXY
LDY #$02
.L852F ;Save parameters of source/dest drive
JSR pgmain ;page in main workspace
LDA voltrk ;get first track of current volume
STA cpvltk,Y ;set as first track of selected volume
JSR L853F ;pack drive parameters
STA packed,Y
RTS
.L853F ;Pack drive parameters
JSR L855C ;pack number of sectors per track
ORA t40flg ;apply *OPT 8 tracks setting in b7,b6
ASL A ;shift spt to b4,b3, *OPT 8 to b1,b0
ROL A
ROL A
ORA denflg ;apply *OPT 6 density setting in b7,b6
RTS ;return packed drive parameters
.L855C ;Pack number of sectors per track
LDA sectrk ;get current setting
BEQ L8568 ;if A=0 then RAM disc, return 0
CMP #ddspt ;else if less than 18 i.e. 10, single dens.
LDA #$01 ;then return 1
ADC #$00 ;if 18 or more i.e. double density return 2.
.L8568
RTS
.cpydsk ;*BACKUP
JSR chkena ;ensure *ENABLE active
JSR get2dr ;parse and print source and dest. volumes
LDA #$00
STA cbcont ;no catalogue entry waiting to be created
STA srclo ;set source volume LBA = 0
STA srchi
STA dstlo ;set destination volume LBA = 0
STA dsthi
JSR L865F ;load source volume catalogue
LDA #$00
STA voltrk ;data area starts on track 0
JSR L8523 ;save parameters of source drive
JSR L863A ;return volume size in XY/boot option in A
STA srcopt ;save source volume boot option
STX todolo
STY todohi
JSR L8659 ;load destination volume catalogue
LDA #$00
STA voltrk ;data area starts on track 0
JSR L852A ;save parameters of destination drive
LDA packed+$00 ;get density of source drive
EOR packed+$02 ;xor with density flag of destination drive
ASL A ;extract bit 6 density flag, ignore auto b7
BPL L85CA ;if the same density then skip
JSR estrng ;else raise density mismatch error.
EQUB $D5
EQUS "Both disks MUST be same density"
EQUB $00
.L85CA
JSR L863A ;return volume size in XY/boot option in A
TXA ;save destination volume size on stack
PHA
TYA
PHA
CMP todohi ;compare MSBs dest volume size - source
BCC L85DC ;if dest < source then raise error
BNE L8600 ;if dest > source then proceed
CPX todolo ;else compare LSBs dest - source
BCS L8600 ;if dest >= source then proceed
.L85DC
LDA #$D5 ;else error number = $D5
JSR LA938 ;begin error message, number in A
LDA fdriv ;get source drive
JSR L8EAD ;print " Drive " plus volume spec in A
JSR vstrng ;print " larger than "
EQUS " larger than "
LDA tdriv ;get destination drive
JSR L8EAD ;print " Drive " plus volume spec in A
JMP LA8F8 ;terminate error message, raise error
.L8600
JSR mvdkda ;copy source drive/file to destination
JSR L88CA ;[D]store empty BASIC program at OSHWM (NEW)
JSR LB74C ;[D]set Z=1 iff current drive is a RAM disc
BNE L860E ;if so
PLA ;then discard destination volume size
PLA
RTS ;and exit
.L860E
BIT denflg ;else test density flag
BVS L8629 ;if double density then update disc catalogue
JSR dirldy ;else load volume catalogue L4
PLA ;pop MSB destination volume size
AND #$0F ;mask bits 0..3
ORA srcopt ;apply source boot option in bits 4..5
JSR pgcat1 ;page in catalogue sector 1
STA dirhig+$06 ;store in catalogue
PLA ;pop LSB destination volume size
STA dirhig+$07 ;store in catalogue
JMP dirout ;write volume catalogue L4
;[BUG] Copying a 40 track DD disc to an 80 track DD disc preserves
;the destination disc size at $1001..2 = 1440 sectors but copies
;the source track count at $1004 = 40 tracks. EDOS *CATGEN will be
;unable to assign tracks in the second half of the disc.
.L8629 ;Update disc catalogue
JSR LACBA ;load disc catalogue L3
JSR pgcat0 ;page in catalogue sector 0
PLA ;pop MSB disc size
STA dcszhi ;store in disc catalogue
PLA ;pop LSB disc size
STA dcszlo ;store in disc catalogue
JMP LACBD ;write disc catalogue L3
.L863A ;Return volume size in XY/boot option in A
JSR pgcat1 ;page in catalogue sector 1
LDX dirhig+$07 ;get LSB volume size from catalogue
LDA dirhig+$06 ;get boot option/top bits volume size
PHA
AND #$03 ;extract MSB volume size
TAY ;put volume size in XY
JSR pgmain ;page in main workspace
BIT denflg ;test density flag
BVC L8655 ;if double density
LDX dscszl ;then load disc size from workspace instead
LDY dscszh
.L8655
PLA ;return disc size in XY
AND #$F0 ;return boot option in A bits 5 and 4
RTS
.L8659 ;Load destination volume catalogue
JSR chkdst ;select destination volume
JMP dirldy ;load volume catalogue L4
.L865F ;Load source volume catalogue
JSR chkdsf ;select source volume
JMP dirldy ;load volume catalogue L4
.cpyfil ;*COPY
JSR setwld ;allow wildcard characters in filename
JSR get2dr ;parse and print source and dest. volumes
JSR chksyn ;call GSINIT with C=0 and require argument
JSR getnam ;set current file from file spec
JSR chkdsf ;select source volume
JSR errlok ;ensure matching file in catalogue
JSR L8523 ;save parameters of source drive
LDA frpage ;[D]get start of user memory
STA zfrpg ;[D]save in zero page
LDA #$01
STA cbcont ;one entry in copy buffer file table
LSR A ;a=0
STA cblast ;point to start of copy buffer file table:
;Copy file
.L868A
TYA ;[D]save catalogue offset of found file
PHA
LDX #$00
.L868E
LDA wrknam,X ;save file spec on stack
PHA
INX
CPX #$08
BNE L868E
JSR vstrng ;print "Reading "
EQUS "Reading "
LDX cblast ;get pointer to free end of buffer table
JSR prtnam ;print filename from catalogue
JSR pcrlf ;print newline
.L86AF
JSR pgcat1 ;page in catalogue sector 1
LDA cathig,Y ;get matching file's catalogue information
JSR pgaux ;page in auxiliary workspace
STA cbcat,X ;store information in copy buffer table
INX ;$FD11..18,X
INY
TYA ;loop until 8 bytes copied
AND #$07
BNE L86AF
.L86C5
JSR pgcat0 ;page in catalogue sector 0
LDA catlow-$08,Y ;get matching file's name and directory
JSR pgaux ;page in auxiliary workspace
STA cbname-$08,X ;store filename in copy buffer table
INX ;$FD1A..21,X
INY
TYA ;loop until 8 characters copied
AND #$07
BNE L86C5 ;then A=0
STA cbflag-$10,X ;clear $FD19,X flag byte
LDA cbcat+$04-$10,X ;get LSB length
CMP #$01 ;[D]set C=1 iff file includes partial sector
LDA cbcat+$05-$10,X ;get 2MSB length
ADC #$00 ;round up to get LSB length in sectors
STA cblnlo-$10,X ;[D]store LSB length in sectors in table
PHP ;save carry flag
LDA cbcat+$06-$10,X ;get top bits exec/length/load/start sector
JSR isolen ;extract b5,b4 of A
PLP ;restore carry flag
ADC #$00 ;carry out to get MSB length in sectors
STA cblnhi-$10,X ;save length in sectors at $FD22..23,X
LDA cbcat+$07-$10,X ;get LSB start LBA
STA cbslbl-$10,X ;copy to $FD24,X
LDA cbcat+$06-$10,X ;get top bits exec/length/load/start sector
AND #$03 ;extract MSB start sector
STA cbslbh-$10,X ;store MSB start LBA at $FD25,X:
;Read segment of file
.L8704
JSR pgmain ;page in main workspace
SEC ;subtract HIMEM - OSHWM
LDA hipage
SBC zfrpg
STA zfrsiz ;= number of pages of user memory
LDY cblast ;get pointer to latest buffer table entry
JSR pgaux ;page in auxiliary workspace
LDA cblnlo,Y ;copy LSB length in sectors
STA todolo ;to zero page
LDA cblnhi,Y ;MSB length in sectors
STA todohi
LDA cbslbl,Y ;LSB start LBA
STA srclo
LDA cbslbh,Y ;MSB start LBA
STA srchi
JSR L8989 ;set start and size of next transfer
LDA zfrpg ;set MSB load address = start of user memory
STA lodhi
LDA #$00
STA lodlo ;[D]set LSB load address = 0
STA lenlo ;set LSB transfer size = 0
LDA lenhi ;get size of transfer
JSR pgaux ;page in auxiliary workspace
STA cbtxsz,Y ;overwrite LSB start LBA at $FD18,Y
JSR L959C ;set high word of OSFILE load address = $FFFF
JSR L970D ;read extended file L5
JSR L899E ;adjust addresses by amount transferred
CLC
LDA zfrpg ;get start of free copy buffer
ADC lenhi ;add size of transfer
STA zfrpg ;update start of free copy buffer
LDY cblast ;get pointer to latest buffer table entry
JSR pgaux ;page in auxiliary workspace
LDA todolo ;return LSB length in sectors
STA cblnlo,Y ;to copy buffer table
LDA todohi ;MSB length in sectors
STA cblnhi,Y
LDA srclo ;LSB start LBA
STA cbslbl,Y
LDA srchi ;MSB start LBA
STA cbslbh,Y
LDA todolo ;test number of sectors to transfer
ORA todohi
BEQ L8779 ;if no more then read next file/write buffer
JSR pgaux ;else page in auxiliary workspace
LDA cbflag,Y ;get buffer table entry's flag byte
ORA #$80 ;b7=1 file incomplete in buffer
STA cbflag,Y ;update flag byte:
;Continue filling copy buffer until full, or write it out
.L8779
JSR pgmain ;page in main workspace
LDA zfrpg ;has copy buffer been filled up to HIMEM?
CMP hipage
BEQ L87BA ;if so then write it out
BIT cbcont ;else if b7=1 all files read
BMI L87BA ;then write out copy buffer
LDA cbcont ;else if copy buffer table is full
AND #$7F
CMP #cbtsiz
BEQ L87BA ;then write it out
CLC
LDA cblast ;else point copy buffer table pointer
ADC #cbtble-cbtbl ;to next entry:
STA cblast
;Copy next matching file
.L8798
LDX #$07 ;8 bytes to restore:
.L879A
PLA ;restore file spec from stack
STA wrknam,X
DEX ;loop until 8 bytes restored
BPL L879A
PLA ;restore catalogue offset of found file
STA catofs
JSR next ;find next matching file
BCC L87AE ;if no more files match then finish
INC cbcont ;else increment no. of files in buffer
JMP L868A ;and copy next file.
;Flush copy buffer
.L87AE
LDY cblast ;more than one table entry in use?
BNE L87B4 ;if so then write out copy buffer
RTS ;else exit
.L87B4
LDA cbcont ;set b7=1 all files read
ORA #$80
STA cbcont
.L87BA
JSR pgmain ;page in main workspace
JSR chkdst ;select destination volume
LDA frpage
STA zfrpg ;set start of copy buffer to OSHWM
LDA cbcont ;get no. entries in copy buffer
AND #$7F ;extract actual number of entries
TAX
LDY #cbtbl+$0100-cbtble ;y=$E9 going to $00:
;Write file from copy buffer
.L87CC
TXA
PHA ;save number of buffer table entries
CLC
TYA
ADC #cbtble-cbtbl ;point to next buffer table entry
STA cbcurs ;set pointer to last entry of buffer table
PHA ;and save it
TAY
JSR pgaux ;page in auxiliary workspace
LDA cbflag,Y ;if b6=1 destination file partly copied
ASL A
BMI L8838 ;write out rest of file
ROR A ;else b6=1 don't create entry twice
ORA #$40
STA cbflag,Y
LDX #$00
.L87EB
LDA cbtbl,Y ;read from buffer table entry $FD11..21,Y
STA wrkcat,X ;restore file catalogue info $BE..$C5
INY ;and filename and directory $C7..$CE
INX
CPX #cblnlo-cbtbl
BNE L87EB
JSR L9753 ;forget catalogue in JIM pages 2..3
JSR lookup ;search for file in catalogue
BCC L8801 ;if file found
JSR delfil ;then delete catalogue entry
.L8801
JSR L852A ;save parameters of destination drive
JSR decodl ;expand 18-bit load address to 32-bit
JSR decode ;expand 18-bit exec address to 32-bit
LDA wrkcat+$06 ;get top bits exec/length/load/start sector
JSR isolen ;extract b5,b4 of A
STA lenhl ;store MSB length of file
JSR genfil ;create catalogue entry
JSR vstrng ;print "Writing "
EQUS "Writing "
NOP
JSR prtnam ;print filename from catalogue
JSR pcrlf ;print newline
LDY cbcurs ;point to last entry of buffer table
JSR pgaux ;page in auxiliary workspace
LDA wrkcat+$06 ;get top bits exec/length/load/start sector
AND #$03 ;extract b1,b0 of A
STA cbdlbh,Y ;store MSB destination LBA
LDA lbalo ;copy LSB destination LBA
STA cbdlbl,Y
;Write segment of file
.L8838
LDA cbtxsz,Y ;get no. pages of data in buffer
STA lenhi ;set size of transfer
CLC
LDA cbdlbl,Y ;copy LSB destination LBA
STA lbalo
ADC lenhi ;add transfer size
STA cbdlbl,Y ;update LSB destination LBA of next write
LDA cbdlbh,Y ;copy MSB destination LBA
STA wrkcat+$06
ADC #$00 ;carry out transfer size
STA cbdlbh,Y ;update MSB destination LBA of next write
LDA zfrpg ;get start of filled copy buffer
STA lodhi ;set MSB of source address
LDA #$00
STA lodlo ;clear LSB source address
STA lenlo ;clear LSB transfer size
JSR L84FF ;restore parameters of destination drive
JSR L959C ;set high word of OSFILE load address = $FFFF
JSR L9713 ;write extended file L5
CLC
LDA zfrpg ;get start of filled copy buffer
ADC lenhi ;add size of transfer
STA zfrpg ;update start of filled copy buffer
PLA ;restore pointer to last table entry
TAY
PLA ;restore no. entries in buffer table
TAX
DEX ;remove one
BEQ L8876 ;if last entry then check for multi-pass copy
JMP L87CC ;else write next file in copy buffer
;Wrote last entry of copy buffer. Copy rest of file or refill buffer
.L8876
JSR L84FB ;restore parameters of source drive
LDY cbcurs ;point to last entry of buffer table
JSR pgaux ;page in auxiliary workspace
LDA cbflag,Y ;test flag byte
AND #$80 ;if b7=0 file(s) in buffer are complete
BEQ L88B0 ;then start refilling copy buffer
LDX #$00 ;else start at offset = 0:
;The last entry in the copy buffer table needs another pass
;to fulfil. Move it to the first table slot.
.L8888
LDA cbtbl,Y ;copy last entry to first position
STA cbtbl,X
INY ;increment offsets
INX
CPX #cbtble-cbtbl ;loop until all 23 bytes copied
BNE L8888
LDA #$40 ;b6=1 destination file partly copied
STA cbflag ;set buffer table entry's flag byte
JSR chkdsf ;select source volume
JSR dirldy ;load volume catalogue L4
LDA frpage
STA zfrpg ;set start of copy buffer to OSHWM
LDA #$01
STA cbcont ;one entry in copy buffer table
LSR A ;a=0
STA cblast ;one buffer table entry in use
JMP L8704 ;read in the rest of this file.
;Exit if no more files to read; else empty copy buffer and refill it
.L88B0
BIT cbcont ;if b7=1 all files read
BMI L88C9 ;then exit
JSR chkdsf ;else select source volume
JSR dirldy ;load volume catalogue L4
LDA frpage
STA zfrpg ;set start of copy buffer to OSHWM
LDA #$00
STA cblast ;no buffer table entries in use
STA cbcont ;no entries in copy buffer table
JMP L8798 ;copy next matching file.
.L88C9
RTS
.L891D ;Shift data
JSR savita ;save AXY
LDA #shftsz
STA frsize ;2 pages of user memory = catalogue sectors
LDA #>jshift
STA lodhi ;MSB of load address in JIM space = $00
.L8929
JSR L8984 ;set start and size of first transfer
LDA #track 0
BEQ L8B88
JSR vstrng ;then print "Track offset = "
EQUS " Track offset = "
NOP
JSR bytout ;print hex byte
JSR pcrlf ;print newline
.L8B88
JSR pgcat1 ;page in catalogue sector 1
LDY dirlen ;y = offset of last catalogue entry:
.L8B8E
JSR L9507 ;calculate slack space after file
BEQ L8BBF ;if no slack space then only map the file
CLC
LDA headlo ;else add LSB slack space
ADC mfreel ;to LSB total free space
STA mfreel
TXA ;add MSB slack space
ADC mfreeh ;and carry out
STA mfreeh ;to MSB total free space
JSR vstrng ;print " Free space "
EQUS " Free space "
NOP
JSR LB7E3 ;print start sector (from lbahi/lo)
JSR pspace ;print a space
TXA ;a = MSB slack space
JSR digout ;print hex nibble
LDA headlo ;a = LSB slack space
JSR LB786 ;print hex byte and newline
.L8BBF
TYA ;if end of catalogue reached
BEQ L8BDD ;then print total free space
JSR unstep ;else subtract 8 from Y
JSR prtnam ;print filename from catalogue
JSR L8CE3 ;print start sector
JSR pspace ;print a space
JSR L94EB ;calculate number of sectors used by file
JSR LB7E3 ;print number of sectors
JSR pcrlf ;print newline
JSR L94D6 ;calculate LBA of end of file
JMP L8B8E ;loop to map next file.
.L8BDD ;Print total free space
JSR vstrng ;print "Free sectors "
EQUB $0D
EQUS "Free sectors "
LDA mfreeh ;a = MSB total free space
JSR digout ;print hex nibble
LDA mfreel ;a = LSB total free space
JSR LB786 ;print hex byte and newline
JMP pgmain ;page in main workspace and exit
.ex ;FSC 9 = *EX
JSR stxylp ;set GSINIT pointer to XY, set Y=0
.L8BFF
JSR setwld ;allow wildcard characters in filename
JSR L8A5F ;a=$23; set current filename = "#######"
JSR setdef ;set current volume and directory = default
JSR LAA3B ;call GSINIT and parse directory spec
JSR errlok ;ensure matching file in catalogue
BCS L8C25 ;always branch
.info ;FSC 10 = *INFO
JSR stxylp ;set GSINIT pointer to XY, set Y=0
LDX #infcom ;fall through:
JSR L921E ;set up trampoline to read *INFO entry
LDY #$00 ;set Y = 0 offset for GSINIT
.L8C1C ;*INFO
JSR setwld ;allow wildcard characters in filename
JSR chksyn ;call GSINIT with C=0 and require argument
JSR getlok ;ensure file matching spec in catalogue
.L8C25
JSR prtinf ;print *INFO line
JSR next ;find next matching file
BCS L8C25 ;loop until no more files match.
RTS
.lookup ;Search for file in catalogue
JSR dirld ;ensure current volume catalogue loaded
LDY #$F8 ;y=$F8, start beyond first catalogue entry
BNE L8C3B ;and jump into search loop (always)
.next ;Find next matching file
JSR pgmain ;page in main workspace
LDY catofs ;set Y = catalogue pointer
.L8C3B
JSR pgcat1 ;page in catalogue sector 1
JSR step ;add 8 to Y
CPY dirlen ;have we reached the end of the catalogue?
BCS lookx ;if so return C=0 file not found
JSR step ;else add 8 to Y
LDX #$07 ;x=7 point to directory character:
.L8C4B
JSR pgmain ;page in main workspace
LDA wrknam,X ;get character of current filename
CMP wildch ;compare with wildcard mask
BEQ L8C66 ;if ='#' and wildcards allowed accept char
JSR caps ;else set C=0 iff character in A is a letter
JSR pgcat0 ;page in catalogue sector 0
EOR catlow-$01,Y ;compare with character in catalogue
BCS L8C62 ;if character in current filename is letter
AND #$DF ;then ignore case
.L8C62
AND #$7F ;ignore bit 7, Z=1 if characters equal
BNE L8C72 ;if not equal then test next file
.L8C66
DEY ;loop to test next (previous) char of name
DEX
BPL L8C4B ;if no more chars to test then files match
JSR pgmain ;page in main workspace
STY catofs ;save cat. offset of found file in workspace
SEC ;return C=1 file found
RTS
.L8C72
DEY ;advance catalogue pointer to next file
DEX
BPL L8C72
BMI L8C3B ;loop until file found or not
.delfil ;Delete catalogue entry
JSR chkopl ;ensure file not locked or open (mutex)
.dellop
JSR pgcat0 ;page in catalogue sector 0
LDA catlow+$08,Y ;copy next file's entry over previous entry
STA catlow+$00,Y ;shifting entries up one place
JSR pgcat1 ;page in catalogue sector 1
LDA cathig+$08,Y ;(copies title/boot/size if catalogue full)
STA cathig+$00,Y
INY ;loop until current file count reached
CPY dirlen ;have we reached the end of the catalogue?
BCC dellop
TYA ;copy Y to A = pointer to last file; C=1
SBC #$08 ;subtract 8, catalogue contains one file less
STA dirlen ;store new file count
.lookx
CLC
.L8C9A
JMP pgmain ;page in main workspace and exit.
.inform ;Print *INFO line if verbose
JSR pgmain ;page in main workspace
BIT monflg ;test *OPT 1 setting
BMI L8C9A ;if b7=1 then *OPT 1,0 do not print, else:
.prtinf ;Print *INFO line
JSR savita ;save AXY
JSR prtnam ;print filename from catalogue
TYA ;save catalogue pointer
PHA
LDA #dosram
STA blkptr+$01
JSR chukbk ;return catalogue information to OSFILE block
LDY #$02 ;y = $02 offset of load address in block
JSR pspace ;print a space
JSR prtin0 ;print load address
JSR prtin0 ;print execution address
JSR prtin0 ;print file length
PLA ;restore catalogue pointer
TAY
JSR L8CE3 ;print start sector
JMP pcrlf ;print newline
.prtin0 ;Print 24-bit field at dosram+Y
LDX #$03 ;start at MSB, offset = 3:
.prtin1
LDA dosram+$02,Y ;get byte at $FDA3,Y
JSR bytout ;print hex byte
DEY ;increment offset
DEX ;decrement counter
BNE prtin1 ;loop until 3 bytes printed
JSR step7 ;add 7 to Y to point to MSB of next field
JMP pspace ;print a space and exit
.L8CE3 ;Print start sector
JSR pgcat1 ;page in catalogue sector 1
LDA cathig+$06,Y ;get top bits exec/length/load/start sector
AND #$03 ;extract MSB start sector
JSR digout ;print hex nibble
LDA cathig+$07,Y ;get LSB start sector
JSR bytout ;print hex byte
JMP pgmain ;page in main workspace [D]not print newline
.maker ;OSFILE 7 = create file, 11 = create w/ stamp
LDA #$00
STA nice ;b6=0 will not accept shorter allocation
JSR dirdo ;create file from OSFILE block
JSR tryfl0 ;set up pointer to user's OSFILE block
LDA #$01 ;return A=$01 from OSFILE:
.chukbk ;Return catalogue information to OSFILE block
JSR savita ;save AXY
TYA ;save catalogue pointer on stack
PHA
TAX ;and copy to X
JSR pgmain ;page in main workspace
LDY #$02 ;clear bytes at offsets 2..17
LDA #$00
.L8D04
STA (blkptr),Y
INY
CPY #$12
BNE L8D04
LDY #$02 ;offset 2 = LSB load address
.chukb5
JSR chukb4 ;copy two bytes from catalogue to OSFILE block
INY ;skip high bytes of OSFILE field
INY
CPY #$0E ;loop until 3 fields half-filled:
BNE chukb5 ;load address, execution address, file length
PLA ;restore catalogue pointer
TAX
JSR pgcat0 ;page in catalogue sector 0
LDA modify,X ;get directory character
BPL chukb3 ;if b7=1 then file is locked
LDA #$0A ;so set attributes to LR/RW (old style)
LDY #$0E ;no delete, owner read only, public read/write
;note: Acorn DFS returns $08 instead
JSR pgmain ;page in main workspace
STA (blkptr),Y ;store in OSFILE block
.chukb3
JSR pgcat1 ;page in catalogue sector 1
LDA cathig+$06,X ;get top bits exec/length/load/start sector
JSR pgmain ;page in main workspace
LDY #$04 ;offset 4 = 2MSB load address
JSR chukb1 ;expand bits 3,2 to top 16 bits of field
LDY #$0C ;offset 12 = 2MSB file length
LSR A ;PD43 returned A = ..eelldd
LSR A ;shift A right twice to make A = ....eell
PHA ;save exec address
AND #$03 ;extract bits 1,0 for length (don't expand)
STA (blkptr),Y ;store in OSFILE block
PLA ;restore exec address in bits 3,2
LDY #$08 ;offset 8 = 2MSB execution address:
.chukb1
LSR A ;shift A right 2 places
LSR A
PHA ;save shifted value for return
AND #$03 ;extract bits 3,2 of A on entry
CMP #$03 ;if either one is clear
BNE L8D51 ;then save both as b1,0 of 2MSB
LDA #$FF ;else set MSB and 2MSB = $FF.
STA (blkptr),Y
INY
.L8D51
STA (blkptr),Y
PLA ;discard byte on stack
RTS
.chukb4 ;Copy two bytes from catalogue to OSFILE block
JSR chukb6
.chukb6
JSR pgcat1 ;page in catalogue sector 1
LDA cathig,X
JSR pgmain ;page in main workspace
STA (blkptr),Y
INX
INY
RTS
.L8D8A ;*STAT eight volumes
JSR L8F0B ;print disc type and volume list
LDX #$00 ;for each volume letter A..H:
.L8D8F
JSR pgaux ;page in auxiliary workspace
LDA voltks,X ;test if number of tracks in volume > 0
BEQ L8DA4 ;if = 0 then no such volume, skip
TXA ;save volume counter
PHA
JSR pcrlf ;print newline
JSR dirld ;ensure current volume catalogue loaded
JSR L9033 ;print volume statistics
PLA ;restore volume counter
TAX
.L8DA4
CLC
LDA fdrive ;get current volume
ADC #$10 ;increment volume letter
STA fdrive ;set as current volume
INX ;increment counter
CPX #volums ;loop until 8 volumes catalogued
BNE L8D8F
JMP pgmain
.L8D66 ;*STAT
JSR setupr ;call GSINIT with C=0
JSR LAA72 ;select specified or default volume
TXA ;test bit 0 of X
AND #$01 ;if X=3 drive and volume specified
BNE L8DB3 ;then stat specified volume, else:
;*STAT eight volumes if double density
LDA fdrive ;get current volume
AND #$0F ;extract drive number
STA fdrive ;set current volume letter to A
LDA #$80 ;data transfer call $80 = read data to JIM
STA txcall ;set data transfer call number
JSR LABB5 ;detect disc format/set sector address
BIT denflg ;test density flag
BVS L8D8A ;if double density then *STAT eight volumes
.L8DB3 ;*STAT specified volume
JSR dirld ;ensure current volume catalogue loaded
JSR L8F0B ;print disc type and volume list
.L9033 ;Print volume statistics
LDY #$03 ;y=3 print 2 spaces/ 1 space
LDA fdrive ;get current volume
JSR L8EAD ;print " Drive " plus volume spec in A
JSR yspace ;print number of spaces in Y
JSR vstrng ;print "Volume size "
EQUS "Volume size "
NOP
JSR pgcat1 ;page in catalogue sector 1
LDA dirhig+$07 ;copy volume size to sector count
STA linnol ;LSB
LDA dirhig+$06 ;get boot option/top bits volume size
AND #$03 ;mask top bits volume size
STA linnoh ;store MSB
JSR LB380 ;print sector count as kilobytes
JSR pcrlf ;print newline
LDY #$0A ;set Y = $0A print 10 spaces
JSR yspace ;print number of spaces in Y
JSR vstrng ;print "Volume unused"
EQUS "Volume unused "
NOP
JSR pgcat1 ;[D]calculate used space on volume
LDY dirlen ;get number of files in catalogue * 8
LDA #$00
STA dsthi ;clear MSB number of used sectors on volume
JSR LA4F8 ;return no. reserved sectors in data area
STA dstlo ;set LSB number of used sectors on volume
.L908A
JSR unstep ;subtract 8 from Y
CPY #$F8 ;if Y=$F8 then was 0, first (last) file done
BEQ L909A ;[D]if all files added then continue, else:
JSR LA714 ;calculate number of sectors used by file
JSR LA733 ;add number of sectors to total
JMP L908A ;loop for next file
.L909A
;[BUG] can exceed vol size due to overlaps
JSR pgcat1 ;page in catalogue sector 1
SEC ;c=1 for subtract
LDA dirhig+$07 ;get LSB volume size from catalogue
SBC dstlo ;subtract LSB used space
STA linnol ;store LSB result in zero page
LDA dirhig+$06 ;get boot option/top bits volume size
AND #$03 ;extract MSB volume size
SBC dsthi ;subtract MSB used space, store in zp
STA linnoh ;[BUG] can underflow due to overlaps
JSR LB380 ;print sector count as kilobytes
JMP pcrlf ;print newline
.L8DBC ;Print "No file"
JSR vstrng ;print string immediate [D]not VDU sequence
EQUB $0D ;newline
EQUS "No file"
EQUB $0D ;newline
NOP
RTS
.L8DCA ;List files in catalogue
JSR pgcat1 ;page in catalogue sector 1
LDA dirlen ;get number of files in catalogue * 8
BEQ L8DBC ;if catalogue empty then print "No file"
STA zdirln ;[D]else copy file count to zero page
LDY #$FF
STY nlflag ;print a newline before first entry
INY
STY catqua ;CSD printed first, directory char = NUL
.cat0
JSR pgcat0 ;page in catalogue sector 0
CPY zdirln ;have we reached the end of the catalogue?
BCS catscn ;if so then start sorting entries
LDA modify,Y ;else get directory character of cat entry
JSR pgmain ;page in main workspace
EOR defqua ;compare with default (CSD) directory
JSR pgcat0 ;page in catalogue sector 0
AND #$7F ;mask off lock bit
BNE cat1 ;if directories differ skip to next entry
LDA modify,Y ;else set directory character to NUL
AND #$80 ;and preserve lock bit
STA modify,Y
.cat1
JSR step ;add 8 to Y
BCC cat0 ;and loop (always)
.catscn
JSR pgcat0 ;page in catalogue sector 0
LDY #$00 ;y=$00, start at first file entry
JSR findir ;find unlisted catalogue entry
BCC L8E12 ;[D]if entry found then list it
JSR pgmain ;[D]else finish catalogue.
JSR L9753 ;[D]forget catalogue in JIM pages 2..3
JMP pcrlf ;[D]print newline and exit
.L8E12
STY catptr ;save catalogue pointer
LDX #$00 ;set filename offset = 0
.L8E16
JSR pgcat0 ;page in catalogue sector 0
LDA catlow,Y ;copy name and directory of first entry
AND #$7F ;with b7 clear
JSR pgmain ;page in main workspace
STA dosram,X ;to workspace
INY ;loop until 8 characters copied
INX
CPX #$08
BNE L8E16
.cattry
JSR pgcat0 ;page in catalogue sector 0
JSR findir ;find unlisted catalogue entry
BCS scand ;if none remaining then print lowest entry
SEC ;else set C=1 for subtraction
LDX #$06 ;start at 6th character (LSB) of leaf name:
.catsbc
JSR pgcat0 ;page in catalogue sector 0
LDA catlow+$06,Y ;get character of entry
JSR pgmain ;page in main workspace
SBC dosram,X ;subtract character of workspace
DEY ;loop until 7 characters compared
DEX
BPL catsbc
JSR step7 ;add 7 to Y
JSR pgcat0 ;page in catalogue sector 0
LDA modify,Y ;get directory character (MSB) of entry
AND #$7F ;mask off lock bit
JSR pgmain ;page in main workspace
SBC dosram+$07 ;subtract directory character in workspace
BCC L8E12 ;if entry < wksp then copy entry to wksp
JSR step ;else add 8 to Y
BCS cattry ;and loop (always)
.scand
JSR pgcat0 ;page in catalogue sector 0
LDY catptr ;get catalogue pointer
LDA catdun,Y ;set b7 in first character of leaf name
ORA #$80 ;marking entry as listed
STA catdun,Y
JSR pgmain ;page in main workspace
LDA dosram+$07 ;get directory character from workspace
CMP catqua ;compare with last one printed
BEQ sameq ;if same then add entry to group
LDX catqua ;else test previous directory
STA catqua ;set previous directory = current directory
BNE sameq ;if prev=NUL we go from CSD to other dirs
JSR pcrlf ;so print double newline:
.cat3
JSR pcrlf ;print newline
LDY #$FF ;set Y = $FF going to 0, start of line
BNE firstc ;branch (always)
.sameq
LDY nlflag ;have we printed two entries on this line?
BNE cat3 ;if so then print newline and reset counter
LDY #$05 ;else tab to next field. Y = 5 spaces
JSR yspace ;print number of spaces in Y, set index = 1:
.firstc
INY
STY nlflag ;y = index of next entry on this line
LDY catptr ;get catalogue pointer
JSR pdspc ;print two spaces
JSR prtnam ;print filename from catalogue
JMP catscn ;loop until all files listed
.nxtcat ;Find next unlisted catalogue entry
JSR step ;add 8 to Y
.findir ;Find unlisted catalogue entry
CPY zdirln ;if catalogue pointer beyond last file
BCS L8EA7 ;then return C=1
LDA catdun,Y ;else test first character of leaf name
BMI nxtcat ;if b7=1 then already listed, skip
.L8EA7
RTS ;else return C=0, catalogue pointer in Y
.L8EA8 ;Print volume spec in A (assuming DD)
BIT L8EA7 ;set V=1
BVS L8EBE ;always print volume letter B..H after drive
.L8EAD ;Print " Drive " plus volume spec in A
JSR vstrng
EQUS "Drive "
NOP
.L8EB8 ;Print volume spec in A
JSR pgmain ;test density flag
BIT denflg
.L8EBE
PHP ;save density flag on stack
PHA ;save volume on stack
AND #$07 ;extract bits 2..0, drive 0..7
JSR digout ;print hex nibble
PLA ;restore volume
PLP ;restore density flag
BVC L8ECF ;if single density then only print drive no.
LSR A ;else shift volume letter to bits 2..0
LSR A
LSR A
LSR A
BNE L8ED0 ;if volume letter is not A then print it
.L8ECF
RTS ;else exit
.L8ED0
DEY ;decrement Y (no. spaces to print later)
CLC ;add ASCII value of "A"
ADC #$41 ;to produce volume letter B..H
JMP pchr ;print character in A (OSASCI) and exit
.L8ED7 ;Print volume title
LDY #$0B ;set y = $0B print 11 spaces
JSR yspace ;print number of spaces in Y
.cat8
JSR pgcat0 ;page in catalogue sector 0
LDA dirlow,Y ;y=0; if Y=0..7 get char from sector 0
CPY #$08 ;if Y=8..11
BCC cat9
JSR pgcat1 ;page in catalogue sector 1
LDA dirhig-$08,Y ;then get character of title from sector 1
.cat9
JSR pchr ;print character in A (OSASCI)
INY ;loop until 12 characters of title printed
CPY #$0C
BNE cat8
JSR vstrng ;print "("
EQUB $0D
EQUS "("
NOP
JSR pgcat1 ;page in catalogue sector 1
LDA cycno ;get BCD catalogue cycle number
JSR bytout ;print hex byte
JSR vstrng ;print ")" +newline
EQUS ")"
EQUB $0D
NOP
RTS
.L8F0B
JSR pgmain ;page in main workspace
JSR LB74C ;[D]set Z=1 iff current drive is a RAM disc
BEQ L8F79 ;[D]if so then print "RAM Disk"
BIT denflg ;else test density flag
BVS L8F21 ;if double density print "Double density"
JSR vstrng ;else print "Single density"
EQUS "Sing"
BCC L8F29
.L8F21
JSR vstrng
EQUS "Doub"
NOP
.L8F29
JSR vstrng
EQUS "le density"
LDY #$0F ;set Y = 15 spaces for single density
BIT denflg ;test density flag
BVC L8F62 ;if single density skip list of volumes
LDY #$06 ;else Y = 6 spaces for double density
JSR yspace ;print number of spaces in Y
LDX #$00 ;set volume index = 0, start at volume A:
.L8F45
CLC ;clear carry for add
JSR pgaux ;page in auxiliary workspace
LDA voltks,X ;test if number of tracks in volume > 0
PHP ;preserve result
TXA ;copy index to A to make volume letter
PLP ;restore result
BNE L8F53 ;if volume present print its letter
LDA #$ED ;else A=$ED + $41 = $2E, ".":
.L8F53
ADC #$41 ;add ASCII value of "A"
JSR pchr ;print character in A (OSASCI)
INX ;point to next volume
CPX #volums ;have all 8 volumes been listed?
BNE L8F45 ;if not then loop
JSR pgmain ;page in main workspace
LDY #$01 ;else Y=1 space separating volume list:
.L8F62
BIT t40flg ;test double-stepping flag
BPL L8F76 ;if set manually (*OPT 8,0/1) then end line
BVC L8F76 ;if 1:1 stepping was detected then end line
JSR yspace ;else print 1 or 14 spaces
JSR vstrng ;print "40in80"
EQUS "40in80"
NOP
.L8F76
JMP pcrlf ;print newline
.L8F79 ;Print "RAM Disk"
JSR LA917 ;print VDU sequence immediate
EQUS "RAM Disk"
EQUB $FF
BCS L8F76 ;print newline (always)
.L8F88 ;Print volume spec and boot option
LDY #$0D ;set Y = $0D print 13 spaces
LDA fdrive ;get current volume
JSR L8EAD ;print " Drive " plus volume spec in A
JSR yspace ;print number of spaces in Y
JSR pgcat1 ;page in catalogue sector 1
JSR vstrng ;print "Option "
EQUS "Option "
LDA option ;get boot option/top bits volume size
JSR sfour ;shift A right 4 places
JSR digout ;print hex nibble
JSR vstrng ;print " ("
EQUS " ("
TAX ;transfer to X for use as index
JSR L8FF7 ;[D]print boot or Challenger config descriptor
JSR vstrng ;print ")"+newline
EQUS ")" ;[BUG]prints Challenger config descriptor
EQUB $0D ;or garbage if boot option exceeds 3
NOP ;(i.e. if offset $0106 b7 or b6 set)
RTS
.L8FB8 ;Print CSD and library directories
JSR vstrng ;print "Directory :"
EQUS "Directory :"
LDY #$06 ;6 characters in next field
JSR pgmain ;page in main workspace
LDX #defqua-defqua ;[D]x = 0 point to default (CSD) directory
JSR L8FE8 ;[D]print default or library directory
JSR yspace ;print number of spaces in Y
JSR vstrng ;print "Library :"
EQUS "Library :"
LDX #libqua-defqua ;[D]x = 2 point to library directory
JSR L8FE8 ;[D]print default or library directory
JMP pcrlf ;print newline
.L8FE8 ;Print default or library directory
LDA defdsk,X ;get default or library volume
JSR L8EA8 ;print volume spec in A (assuming DD)
JSR pdot ;print a dot
LDA defqua,X ;get default or library directory
JMP pchr ;print character in A (OSASCI)
.L8FF7 ;Print boot or Challenger config descriptor
LDA L9007,X ;look up offset of message selected by X
TAX ;replace X with offset of message:
.L8FFB
LDA opttab,X ;get character of message
BEQ L9006 ;if NUL terminator reached then exit
JSR pchr ;else print character in A (OSASCI)
INX ;increment offset
BPL L8FFB ;and loop (always)
.L9006
.return ;Return from unrecognised keyword
RTS
;Table of offsets of boot descriptors 0..3
.L9007
EQUB boff -opttab
EQUB bload -opttab
EQUB brun -opttab
EQUB bexec -opttab
;Table of offsets of Challenger configuration descriptors 4..6
EQUB bout -opttab
EQUB b256k -opttab
EQUB b512k -opttab
;Table of boot option descriptors 0..3
.opttab
.boff
EQUS "off"
EQUB $00
.bload
EQUS "LOAD"
EQUB $00
.brun
EQUS "RUN"
EQUB $00
.bexec
EQUS "EXEC"
EQUB $00
;Table of Challenger configuration descriptors 4..6
.bout
EQUS "inactive"
EQUB $00
.b256k
EQUS "256K"
EQUB $00
.b512k
EQUS "512K"
EQUB $00
.comtab ;Challenger command table
EQUS "ACCESS"
EQUB >access, (L)
EQUS "BACKUP"
EQUB >cpydsk,
EQUS "COMPACT"
EQUB >compct,)
EQUS "CONFIG"
EQUB >LAAF6, )
EQUS "COPY"
EQUB >cpyfil,
EQUS "DELETE"
EQUB >delete,
EQUS "DESTROY"
EQUB >destry,
EQUS "DIR"
EQUB >set, )
EQUS "DRIVE"
EQUB >drive, )
EQUS "ENABLE"
EQUB >enable,L8BFF, )
EQUS "FDCSTAT"
EQUB >LB76C, L8C1C,
EQUS "LIB"
EQUB >slib, )
EQUS "MAP"
EQUB >map,