10 REM > VDFS05/S
   20 REM Source for Virtual DFS ROM for WSS 6502Em emulator traps
   30 REM
   40 REM v0.01 MRB: Original
   50 REM v0.02 SPROW: Sprow update
   60 REM v0.03 JGH: Major tidy-up
   70 REM v0.04 JGH: Rearranged into separate ROM and Filing System code
   80 REM            Added FSClaim, fuller help, better *CAT plus *EX and *INFO
   90 REM            Added Osword7F veneer
  100 REM v0.05 JGH: Works better on Master, merged *command search routines
  110 REM            *INFO checks for Not Found, pre-test for ignored *commands
  120 REM            Claims/releases NMIs, *EX/*INFO shows date if present
  130 REM            Checks if host present, *INFO claims NMI workspace
  140 :
  150 OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE
  160 OSASCI=&FFE3:OSGBPB=&FFD1:OSNEWL=&FFE7:OSFILE=&FFDD
  170 :
  180 DIM mcode% &B00, L% -1
  190 FOR P=0TO1
  200   P%=&8000:O%=mcode%
  210   [OPT P*3+4
  220   .ROMStart
  230   EQUS "MRB"                        :\ No language entry
  240   JMP Service                       :\ Service entry
  250   EQUB &82:EQUB ROMCopyright-ROMStart
  260   .ROMVersion
  270   EQUB &05
  280   .ROMTitle
  290   EQUS "Virtual DFS":EQUB 0:EQUS "0.05 (01 Oct 2016)"
  300   .ROMCopyright
  310   EQUB 0:EQUS "(C)1995 MRB, 2004,2016 JGH":EQUB 0
  320   :
  330   .Service
  340   PHA:TYA:PHA                       :\ Save registers
  350   TSX:LDA &0102,X                   :\ Get service number
  360   CMP #&03:BNE P%+5:JMP ServFSStart :\ FS startup
  370   CMP #&04:BNE P%+5:JMP ServCommand :\ *command
  380   CMP #&08:BNE P%+5:JMP ServOsword  :\ OSWORD
  390   CMP #&09:BNE P%+5:JMP ServHelp    :\ *Help
  400   CMP #&12:BNE P%+5:JMP ServFSSelect:\ Select a filing system
  410   CMP #&25:BNE P%+5:JMP ServFSInfo  :\ Request FS info
  420   .ServExit
  430   PLA:TAY                           :\ Restore Y
  440   .ServExitY
  450   PLA:RTS                           :\ Restore service number and return
  460   .ServClaim
  470   PLA:PLA                           :\ Drop stacked registers
  480   LDA #0:RTS                        :\ Exit with A=0 to claim call
  490   :
  500   \ ===========================
  510   \ ROM Administration Routines
  520   \ ===========================
  530   .PrROMTitleNL              :\ Print NL, ROM title
  540   JSR OSNEWL
  550   .PrROMTitle                :\ Print ROM title
  560   LDX #0
  570   .PrRTLp
  580   LDA ROMTitle,X:BEQ PrRTDone
  590   JSR OSWRCH:INX:BNE PrRTLp
  600   .PrRTDone
  610   RTS
  620   .PrROMVersion
  630   JSR PrSpace:INX
  640   .PrRVLp
  650   LDA ROMTitle,X:CMP #ASC"!":BCC PrRVDone
  660   JSR OSWRCH:INX:BNE PrRVLp
  670   .PrRVDone
  680   JMP OSNEWL
  690   :
  700   \ ------------
  710   \ ROM Commands
  720   \ ------------
  730   .ServCommand
  740   PLA:TAY:PLA:LDX #&00       :\ X=>ROM command table
  750   :
  760   \ ---------------
  770   \ *command lookup
  780   \ ---------------
  790   .CmdSearch
  800   PHA:TYA:PHA                 :\ Save A and text offset
  810   .CmdLookNext
  820   PLA:PHA:TAY                 :\ Get text offset back
  830   .CmdLookLp
  840   LDA (&F2),Y:CMP #&2E:BEQ CmdMatchDot
  850   AND #&DF:CMP CommandBase,X:BNE CmdNoMatch
  860   INX:INY:LDA CommandBase,X
  870   CMP #&0D:BNE CmdLookLp      :\ Not a full command
  880   LDA (&F2),Y                 :\ Get following character
  890   CMP #ASC"A":BCS CmdCheckNext:\ Ensure command ends with non-alpha
  900   DEY                         :\ Prepare to skip spaces
  910   .CmdFoundSpc
  920   INY:LDA (&F2),Y             :\ Move past any spaces
  930   CMP #ASC" ":BEQ CmdFoundSpc
  940   LDA CommandBase+1,X:STA &B0 :\ Get command address
  950   LDA CommandBase+2,X:STA &B1
  960   JSR JumpB0                  :\ Call command routine
  970   PLA:PLA:LDA #0:RTS          :\ Drop saved A,Y, return claimed
  980   .CmdMatchDot
  990   INX:LDA CommandBase,X
 1000   CMP #&0D:BNE CmdMatchDot    :\ Find end of table entry
 1010   BEQ CmdFoundSpc             :\ Jump to enter command
 1020   .CmdNoMatch
 1030   LDA CommandBase,X:INX
 1040   CMP #&0D:BNE CmdNoMatch     :\ Find end of table entry
 1050   .CmdCheckNext
 1060   INX:INX:LDA CommandBase,X
 1070   BNE CmdLookNext             :\ Loop until terminator found
 1080   .CmdQuit
 1090   PLA:TAY:PLA:RTS             :\ Restore A,Y, exit unclaimed
 1100   :
 1110   \ -----------------
 1120   \ ROM Command Table
 1130   \ -----------------
 1140   .CommandBase
 1150   .ROMCommands
 1160   \ Filing system selection
 1170   EQUS "DISC"   :EQUB 13:EQUW disc
 1180   EQUS "DISK"   :EQUB 13:EQUW disk
 1190   EQUS "ADFS"   :EQUB 13:EQUW adfs
 1200   EQUS "FADFS"  :EQUB 13:EQUW fadfs
 1210   EQUS "VDFS"   :EQUB 13:EQUW vdfs
 1220   EQUS "FSCLAIM":EQUB 13:EQUW fsclaim
 1230   :
 1240   \ Utility commands
 1250   EQUS "OSW"+CHR$(ASC"7"AND&DF)+"F":EQUB 13:EQUW fdc
 1260   \EQUS "PAGE"  :\EQUB 13:\EQUW page
 1270   EQUS "QUIT"   :EQUB 13:EQUW quit
 1280   EQUS "DESKTOP":EQUB 13:EQUW quit
 1290   \EQUS "SHADOW":\EQUB 13:\EQUW shadow
 1300   :
 1310   \ SRAM commands
 1320   EQUS "SRLOAD" :EQUB 13:EQUW srload
 1330   EQUS "SRWRITE":EQUB 13:EQUW srwrite
 1340   EQUB 0
 1350   :
 1360   \ ---------------------------
 1370   \ Filing System Command Table
 1380   \ ---------------------------
 1390   .FSCommands
 1400   EQUS "ACCESS" :EQUB 13:EQUW access
 1410   EQUS "BACK"   :EQUB 13:EQUW back
 1420   EQUS "BACKUP" :EQUB 13:EQUW backup
 1430   EQUS "COMPACT":EQUB 13:EQUW compact
 1440   EQUS "COPY"   :EQUB 13:EQUW copy
 1450   EQUS "DELETE" :EQUB 13:EQUW delete
 1460   EQUS "DESTROY":EQUB 13:EQUW destroy
 1470   EQUS "DRIVE"  :EQUB 13:EQUW drive
 1480   EQUS "ENABLE" :EQUB 13:EQUW enable
 1490   EQUS "EX"     :EQUB 13:EQUW ex
 1500   EQUS "FORM"   :EQUB 13:EQUW form
 1510   EQUS "FREE"   :EQUB 13:EQUW free
 1520   EQUS "INFO"   :EQUB 13:EQUW info
 1530   EQUS "MAP"    :EQUB 13:EQUW free
 1540   EQUS "MOUNT"  :EQUB 13:EQUW mount
 1550   EQUS "RENAME" :EQUB 13:EQUW rename
 1560   EQUS "TITLE"  :EQUB 13:EQUW title
 1570   EQUS "VERIFY" :EQUB 13:EQUW verify
 1580   EQUS "WIPE"   :EQUB 13:EQUW wipe
 1590   EQUB 0
 1600   :
 1610   ]:IF P%-CommandBase>255:PRINT"Command table too big":END
 1620   [OPT P*3+4
 1630   \ ----------------------------------
 1640   \ Detailed help routine
 1650   \ Based on Sprow's code in VDFS 0.02
 1660   \ ----------------------------------
 1670   .ServHelp
 1680   LDA (&F2),Y
 1690   CMP #&0D:BEQ HelpTitle     :\ No subject, just print ROM title
 1700   CMP #&2E:BEQ L8514         :\ '.', print full info
 1710   AND #&DF:CMP #&56:BNE L8538:\ Doesn't start with 'V', check for "DFS"
 1720   INY:\JMP L8538             :\ Move past 'V', check for "DFS"
 1730   :
 1740   .L8538
 1750   DEY:LDX #&FF
 1760   .L853B
 1770   INX:INY                    :\ Point to next characters
 1780   LDA (&F2),Y:AND #&DF
 1790   CMP L854C,X:BEQ L853B      :\ If matches "DFS", loop to next char
 1800   LDA L854C,X:BEQ L8514      :\ If at end, jump to print full info
 1810   JMP ServExit
 1820   :
 1830   .L8514
 1840   JSR PrROMTitleNL           :\ Print ROM title
 1850   JSR PrROMVersion
 1860   LDX #ROMCommandHelp AND 255
 1870   LDY #ROMCommandHelp DIV 256:\ Point to help text
 1880   JSR PrintText:JMP ServExit
 1890   .HelpTitle
 1900   JSR PrROMTitleNL           :\ Just print ROM title
 1910   JSR PrROMVersion
 1920   JMP ServExit
 1930   :
 1940   .PrintText
 1950   STX &F6:STY &F7            :\ Store text pointer in ROMFS text pointer
 1960   LDY #&00:BEQ L8525         :\ Jump into loop
 1970   .L8522
 1980   CMP #10:BNE HelpChar       :\ LF is soft CR
 1990   LDA &30A:SBC &308          :\ Get window width
 2000   CMP #70:BCC HelpNarrow     :\ <80 columns
 2010   LDA #ASC" ":BNE HelpChar   :\ 80-column mode, print space
 2020   .HelpNarrow
 2030   JSR OSNEWL:JSR PrSpace     :\ <80-column mode, print newline+2spaces
 2040   .HelpChar
 2050   JSR OSASCI
 2060   .L8525
 2070   LDA (&F6),Y:BEQ L8530      :\ If &00 terminator, end
 2080   INY:BNE L8522              :\ Loop to print character
 2090   INC &F7:BMI L8522          :\ Increment high byte and loop back
 2100   .L8530
 2110   RTS
 2120   :
 2130   .L854C
 2140   EQUS "DFS":EQUB 0          :\ *Help match string
 2150   :
 2160   .ROMCommandHelp
 2170   EQUS "Filing system selection:":EQUB 13
 2180   EQUS "  DISK, DISC, ADFS, FADFS :":EQUB 10
 2190   EQUS "Select VDFS if claimed":EQUB 13
 2200   EQUS "  VDFS        : Select VDFS":EQUB 13
 2210   EQUS "  FSCLAIM ON  : Claim DISC, ADFS":EQUB 13
 2220   EQUS "  FSCLAIM OFF : Release DISC, ADFS":EQUB 13
 2230   EQUS "  OSW7F (NONE)(<ver>) :":EQUB 10
 2240   EQUS "Emulate Osword &7F memory corruption":EQUB 13
 2250   EQUB 13
 2260   EQUS "Utility commands:":EQUB 13
 2270   EQUS "  QUIT or DESKTOP : return to RISC OS":EQUB 13
 2280   \EQUS "  PAGE   :\ force PAGE location":\EQUB 13
 2290   \EQUS "  SHADOW :\ dummy command":\EQUB 13
 2300   EQUS "  SRLOAD <name> <address> <rom>":EQUB 13
 2310   EQUS "  SRWRITE <start> <end> <dest> <rom>":EQUB 13
 2320   EQUB 13
 2330   EQUS "VDFS commands:":EQUB 13
 2340   EQUS "  BACK  : return to root directory":EQUB 13
 2350   EQUS "  DRIVE : change current drive":EQUB 13
 2360   EQUS "  MOUNT : mount drive":EQUB 13
 2370   EQUS "  DIR   : change current directory":EQUB 13
 2380   EQUS "  LIB   : change current library":EQUB 13
 2390   EQUS "  INFO  : show info on single file":EQUB 13
 2400   EQUS "  EX    : show info on all files in CSD":EQUB 13
 2410   EQUS "  ACCESS, BACKUP, COMPACT, COPY,":EQUB 10
 2420   EQUS "DESTROY, ENABLE, FORM, FREE, MAP,":EQUB 13
 2430   EQUS "  RENAME, TITLE, VERIFY, WIPE :":EQUB 10
 2440   EQUS "trapped and ignored":EQUB 13
 2450   EQUB 0
 2460   :
 2470   \ --------------------
 2480   \ ROM Command routines
 2490   \ --------------------
 2500   .quit
 2510   EQUB &03:EQUB &FF          :\ Return to host
 2520   :
 2530   .page:.shadow
 2540   \LDA #&00:\RTS             :\ Ignore command
 2550   :
 2560   .srload :EQUB &03:EQUB &D0 :\ Pass to host and return
 2570   .srwrite:EQUB &03:EQUB &D1 :\ Pass to host and return
 2580   :
 2590   \ ROM Support Workspace
 2600   \ ---------------------
 2610   .PageOffset:EQUB &00       :\ Amount to raise PAGE by
 2620   :
 2630   \ ======================
 2640   \ Filing System Routines
 2650   \ ======================
 2660   \ Filing System Workspace
 2670   \ -----------------------
 2680   .ClaimFS:EQUB &00          :\ *FSCLAIM On/Off flag
 2690   .FSFlag :EQUB &11          :\ FS id when claimed
 2700   :
 2710   \ --------------------------------
 2720   \ Filing system selection commands
 2730   \ --------------------------------
 2740   .disc:.disk:.adfs
 2750   .fadfs:.vdfs                :\ On entry, X=4,11,18,26,33
 2760   TXA:LSR A:LSR A:LSR A:TAX   :\ X=0,1,2,3,4
 2770   LDA FSValues,X:TAY          :\ Get filing system number
 2780   CPY #9:BCS SelectFS         :\ Always select VDFS
 2790   BIT ClaimFS:BMI SelectFS    :\ If claimed, select VDFS
 2800   PLA:PLA:PLA:TAY:PLA:RTS     :\ Drop return, restore and return
 2810   .SelectFS
 2820   LDX #&12:LDA #&8F:JMP OSBYTE:\ Select filing system
 2830   .FSValues
 2840   EQUB 4:EQUB 4:EQUB 8        :\ DISC, DISK, ADFS
 2850   EQUB 8:EQUB 17              :\ FADFS, VDFS
 2860   :
 2870   .fsclaim
 2880   LDA (&F2),Y:AND #&DF
 2890   CMP #ASC"O":BNE fsclaimStatus
 2900   INY:LDA (&F2),Y:AND #&DF
 2910   CMP #ASC"N":LDA #0:SBC #0
 2920   EOR #&FF:STA ClaimFS:RTS
 2930   .fsclaimStatus
 2940   LDA #ASC"O":JSR OSWRCH
 2950   LDA ClaimFS:AND #8:PHP:ORA #ASC"F"
 2960   JSR OSWRCH:PLP:BNE P%+5:JSR OSWRCH
 2970   JMP OSNEWL
 2980   :
 2990   \ --------------------------
 3000   \ Filing System Service Code
 3010   \ --------------------------
 3020   .ServFSSelect
 3030   CPY #&11:BEQ FSSelect       :\ VDFS
 3040   BIT ClaimFS:BPL FSSelectNone:\ If not claimed, don't check for DFS or ADFS
 3050   CPY #&04:BEQ FSSelect       :\ Select DFS
 3060   CPY #&08:BEQ FSSelect       :\ Select ADFS
 3070   .FSSelectNone
 3080   JMP ServExit                :\ Exit unclaimed
 3090   .FSSelect
 3100   TYA:PHA                     :\ Save FS id
 3110   LDA #&06:JSR FSCCallHost    :\ Check host exists
 3120   JSR CallFSCV                :\ Inform current FS new FS taking over
 3130   LDX #0:LDY #&1B             :\ Set up new vectors
 3140   .ClaimVecLp
 3150   TYA:STA &212,X
 3160   LDA #&FF:STA &213,X         :\ vector=&FFxx
 3170   LDA VectorTable+0,X:STA &D9F+0,Y
 3180   LDA VectorTable+1,X:STA &D9F+1,Y
 3190   LDA &F4:STA &D9F+2,Y        :\ exvec=&RRxxyy
 3200   INY:INY:INY:INX:INX
 3210   CPX #&0E:BNE ClaimVecLp
 3220   LDA #&8F:LDX #&0F:JSR OSBYTE:\ Notify that vectors have changed
 3230   PLA:STA FSFlag              :\ Store FS id
 3240   JMP ServClaim
 3250   .CallFSCV
 3260   JMP (&021E)
 3270   .VectorTable
 3280   EQUW File:EQUW Args:EQUW BGet:EQUW BPut
 3290   EQUW GBPB:EQUW Find:EQUW FSC
 3300   :
 3310   \ ---------------------------------
 3320   \ Select FS on BREAK and maybe boot
 3330   \ ---------------------------------
 3340   .ServFSStart
 3350   TYA:PHA
 3360   LDA #&7A:JSR OSBYTE        :\ Check what keys are pressed
 3370   CPX #&FF:BEQ FSStartGo2    :\ No keys pressed, select me
 3380   CPX #&51:BEQ FSStartGo1    :\ 'S' pressed, select me
 3390   PLA:JMP ServExit           :\ Exit
 3400   .FSStartGo1
 3410   LDA #&78:JSR OSBYTE        :\ Clear keypressed info
 3420   .FSStartGo2
 3430   JSR PrROMTitle             :\ Print filing system name
 3440   JSR OSNEWL:JSR OSNEWL
 3450   LDY FSFlag:JSR SelectFS    :\ Select filing system
 3460   PLA:BNE P%+5:JSR HostBoot  :\ If booting, get !Boot from host
 3470   JMP ServClaim              :\ Exit, claimed
 3480   .HostBoot
 3490   EQUB &03:EQUB &D3          :\ Do !Boot
 3500   :
 3510   .ServFSInfo
 3520   LDX #&00
 3530   .FSInfoLp
 3540   LDA L81FB,X:STA (&F2),Y
 3550   INY:INX:CPX #44:BNE FSInfoLp:\ Copy filing system name
 3560   PLA:JMP ServExitY           :\ Drop saved Y and exit
 3570   .L81FB
 3580   EQUS "DISK    ":EQUB &11:EQUB &15:EQUB &04
 3590   EQUS "DISC    ":EQUB &11:EQUB &15:EQUB &04
 3600   EQUS "ADFS    ":EQUB &30:EQUB &3A:EQUB &08
 3610   EQUS "VDFS    ":EQUB &C0:EQUB &FF:EQUB &11
 3620   :
 3630   \ -------------------------------------------
 3640   \ Pass filing system calls to host and return
 3650   \ -------------------------------------------
 3660   .File  :EQUB &03:EQUB &06
 3670   .Args  :EQUB &03:EQUB &05
 3680   .BGet  :EQUB &03:EQUB &04
 3690   .BPut  :EQUB &03:EQUB &03
 3700   .GBPB  :EQUB &03:EQUB &02
 3710   .Find  :EQUB &03:EQUB &01
 3720   :
 3730   \ -------------------
 3740   \ File System Control
 3750   \ -------------------
 3760   .FSC
 3770   CMP #&08:BEQ FSCDone        :\ Jump if *command warning
 3780   CMP #&0A:BNE P%+5:JMP Info  :\ Info on a file
 3790   CMP #&09:BNE P%+5:JMP Ex    :\ Examine directory
 3800   CMP #&05:BNE P%+5:JMP Cat   :\ Catalogue directory
 3810   CMP #&04:BEQ FSCmdRun       :\ *RUN filename
 3820   CMP #&03:BEQ FSCommandLookup:\ Filing system commands
 3830   CMP #&02:BEQ FSCmdRun       :\ */filename
 3840   .FSCCallHost
 3850   EQUB &03:EQUB &00           :\ Pass to emulator and return
 3860   LDX #msgNoHost-msgNotFound  :\ If we fall through to here, there's no
 3870   JMP error                   :\ host and we've done ASL-ORA (&00,X)
 3880   :
 3890   \ ----------------------
 3900   \ Filing System Commands
 3910   \ ----------------------
 3920   .FSCommandLookup
 3930   PHA:TXA:PHA:TYA:PHA
 3940   STX &F2:STY &F3:LDY #0
 3950   LDX #FSCommands-CommandBase
 3960   LDA #3:JSR CmdSearch:CMP #1:\ Cy=done/not done
 3970   .FSCmdRetry
 3980   PLA:TAY:PLA:TAX:PLA        :\ Restore registers
 3990   BCC FSCDone
 4000   .FSCmdRun
 4010   JSR FSCCallHost            :\ Pass FSC to host to try
 4020   \ On return, A=action, XY=address
 4030   \ A=%1xxxxxxx - enter CoPro address, A=ID
 4040   \ A=%01xxxxxx - enter I/O address
 4050   \ A=%001xxxxx - print text
 4060   \ A=%0001xxxx - reserved
 4070   \ A=%0000xxxx - all done (usually A preserved)
 4080   \
 4090   AND #&FF:BMI FSCTube       :\ Execute CoPro code
 4100   ASL A:BMI FSCJump          :\ Execute I/O code
 4110   ASL A:BPL FSCDone
 4120   JMP PrintText              :\ Print text
 4130   .FSCTube
 4140   JSR &406:BCC FSCTube       :\ Claim Tube with ID in A
 4150   LDA #4:JMP &406            :\ Execute code at address at XY
 4160   .FSCJump
 4170   STX &B0:STY &B1
 4180   .JumpB0
 4190   JMP (&B0)
 4200   :
 4210   \ ------------------------------
 4220   \ Filing System Command Routines
 4230   \ ------------------------------
 4240   .F2toXY
 4250   TYA:CLC:ADC &F2:TAX:LDA &F3:ADC #0:TAY
 4260   .FSCDone
 4270   RTS
 4280   :
 4290   .drive    :EQUB &03:EQUB &D2:\ Pass to host and return
 4300   .back     :EQUB &03:EQUB &D5:\ Pass to host and return
 4310   .mount    :EQUB &03:EQUB &D6:\ Pass to host and return
 4320   .ex       :JSR F2toXY:LDA #&09:JMP CallFSCV
 4330   .info     :JSR F2toXY:LDA #&0A:JMP CallFSCV
 4340   .rename   :JSR F2toXY:LDA #&0C:JMP CallFSCV
 4350   :
 4360   .access
 4370   .backup
 4380   .compact
 4390   .copy
 4400   .delete
 4410   .destroy
 4420   .enable
 4430   .form
 4440   .free
 4450   .wipe
 4460   .title
 4470   .verify
 4480   LDA #8:JSR FSCCallHost     :\ Probe emulator
 4490   CMP #3:BNE FSCDone         :\ If doesn't return A=3, ignore
 4500   PLA:PLA:PLA:PLA:PLA:PLA    :\ Drop data from stack
 4510   SEC:BCS FSCmdRetry         :\ Pass command to emulator
 4520   :
 4530   \ ---------------------------
 4540   \ Functions performed locally
 4550   \ ---------------------------
 4560   .Info
 4570   STX &C0:STY &C1            :\ Perm FS workspace
 4580   LDA #&80:BNE CatExInfo
 4590   :
 4600   .Ex
 4610   LDA #&40:BNE CatExInfo
 4620   :
 4630   .Cat
 4640   LDA #&00
 4650   .CatExInfo                 :\ PL=multiple files, NE=full info
 4660   \ &D01 = GBPB block
 4670   NOTE, WSS OSGBPB 9 uses control block differently:
 4680   \  &D01 = count
 4690   \  &D02 = address
 4700   \  &D06 = filename buffer size
 4710   \  &D0A = offset
 4720   \ &D0E = FILE block
 4730   \ &D20 = pathname
 4740   \
 4750   PHA
 4760   LDY #255:JSR ClaimNMI:STY &A0:\ Claim NMI workspace
 4770   LDA #&40:STA &0D00:LDY #0    :\ Null RTI routine
 4780   .InfoLp
 4790   LDA (&C0),Y:STA &0D20,Y:INY  :\ Copy filename to buffer
 4800   CPY #&D60-&D20:BCC InfoLp
 4810   LDA #&00:LDX #&06
 4820   .CatInit
 4830   STA &0D07,X:DEX:BPL CatInit  :\ Start with first item
 4840   .CatLoop
 4850   LDX #&20:STX &0D02:STX &0D0E :\ =>Filename buffer
 4860   LDX #&0D:STX &0D03:STX &0D0F
 4870   PLA:PHA:BMI CatSingleFile
 4880   LDX #&FF:STX &0D04:STX &0D05
 4890   LDX #&01:STX &0D01         :\ Fetch one item
 4900   LDX #&D60-&D20:STX &0D06   :\ Filename buffer size
 4910   LDX #&01:LDY #&0D
 4920   LDA #&09:JSR OSGBPB        :\ Read catalogue entry
 4930   LDA &0D01:BEQ CatDone      :\ If no more, exit
 4940   LDX #&D5F-&D20
 4950   .CatLoopCR1
 4960   LDA &D20,X:BNE CatLoopCR2  :\ Check for &00 terminator
 4970   LDA #13:STA &D20,X         :\ Change it to a <cr>
 4980   .CatLoopCR2
 4990   DEX:BPL CatLoopCR1
 5000   .CatSingleFile
 5010   LDX #&0E:LDY #&0D
 5020   LDA #&05:JSR OSFILE        :\ Read info on this entry
 5030   TAY:BNE CatFound           :\ Y=object type
 5040   PLA:PHA:BMI errNotFound    :\ Error if *INFO not found
 5050   .CatFound
 5060   JSR CatPrint               :\ Print object name
 5070   PLA:PHA:BEQ CatNoInfo
 5080   TYA:PHA:LDY #3:LDX #5
 5090   .CatAddrLp1
 5100   TYA:PHA:LDY #4
 5110   .CatAddrLp2
 5120   LDA &0D0E,X:JSR PrHex
 5130   DEX:DEY:BNE CatAddrLp2
 5140   JSR PrSpace
 5150   TXA:CLC:ADC #8:TAX
 5160   PLA:TAY:DEY:BNE CatAddrLp1
 5170   PLA:TAY                    :\ Get object type back
 5180   .CatNoInfo
 5190   TYA:JSR CatAttrs
 5200   PLA:TAY:BEQ CatNext        :\ *CAT, no more info
 5210   JSR CatDate:JSR OSNEWL     :\ *EX/*INFO, print date, newline
 5220   .CatNext
 5230   TYA:BMI CatExit            :\ *INFO, finish
 5240   PHA:JMP CatLoop            :\ Loop back with *CAT/*EX
 5250   :
 5260   .CatDone
 5270   PLA:BNE CatExit            :\ *EX, no newline needed
 5280   LDA #&86:JSR OSBYTE        :\ Get POS,VPOS
 5290   TXA:BEQ CatExit            :\ No newline needed
 5300   JSR OSNEWL
 5310   .CatExit
 5320   LDY &A0                    :\ Relinquish NMI workspace
 5330   .ClaimNMI
 5340   LDX #11:LDA #143:JMP OSBYTE
 5350   :
 5360   .errNotFound
 5370   JSR CatExit:LDX #0
 5380   .error
 5390   LDY #0
 5400   .errLp
 5410   INX:INY:LDA msgNotFound-1,X:STA &100,Y
 5420   BNE errLp
 5430   STA &100:JMP &100
 5440   .msgNotFound:EQUB 214:EQUS "Not found":EQUB 0
 5450   .msgNoHost  :EQUB 248:EQUS "No host":EQUB 0
 5460   :
 5470   .CatPrint
 5480   TYA:PHA:LDA #0:TAX:TAY:PHA :\ Print leafname
 5490   .CatPrtLp1
 5500   LDA &D20,Y:INY:CMP #ASC".":BNE CatPrtLp2
 5510   PLA:TYA:PHA:LDA #ASC"."
 5520   .CatPrtLp2
 5530   CMP #ASC"!":BCS CatPrtLp1:PLA:TAY
 5540   .CatPrtLp3
 5550   LDA &0D20,Y:CMP #ASC" ":BCC CatPrPop
 5560   JSR OSWRCH:INY:INX:CPX #12:BNE CatPrtLp3
 5570   .CatPrPop
 5580   PLA:TAY
 5590   .CatPrSpc
 5600   LDA #ASC" "
 5610   .CatPrLp4
 5620   JSR OSWRCH:INX
 5630   CPX #13:BCC CatPrLp4       :\ Print spaces until column 13
 5640   .CatCharNone
 5650   RTS
 5660   :
 5670   .CatAttrs
 5680   LDX #7:LDY #8
 5690   AND #2:BEQ P%+5:JSR CatCharD:\ 'D'
 5700   LDY #3:LDA #&08:JSR CatChar :\ 'L'
 5710   LDY #1:LDA #&02:JSR CatChar :\ 'W'
 5720   LDY #0:LDA #&01:JSR CatChar :\ 'R'
 5730   BNE CatAttrs2
 5740   LDY #2:LDA #&04:JSR CatChar :\ 'E'
 5750   .CatAttrs2:JSR PrSlash      :\ '\'
 5760   LDY #5:LDA #&20:JSR CatChar :\ 'w'
 5770   LDY #4:LDA #&10:JSR CatChar :\ 'r'
 5780   BNE CatAttrs3
 5790   LDY #6:LDA #&40:JSR CatChar :\ 'e'
 5800   .CatAttrs3:JMP CatPrSpc
 5810   :
 5820   .CatChar
 5830   BIT &0D1C:BEQ CatCharNone
 5840   .CatCharD
 5850   LDA CatAttrChars,Y:INX:JMP OSWRCH
 5860   .CatAttrChars
 5870   EQUS "RWELrwePD"
 5880   :
 5890   .CatDate
 5900   LDA &D1D:BEQ CatCharNone      :\ No date
 5910   PHA:LDX #9:JSR CatPrSpc:PLA
 5920   AND #31:JSR PrDec:JSR PrSlash :\ Day
 5930   LDA &D1E:AND #15:JSR PrDec    :\ Month
 5940   JSR PrSlash:LDA &D1E:LSR A    :\ Year b0-b3
 5950   LSR A:LSR A:EOR &D1D:AND #&1E :\ Merge with year b4-b6
 5960   EOR &D1D:LSR A:PHA:CMP #19
 5970   LDA #20:SBC #0:JSR PrDec      :\ Calculate century
 5980   PLA:SEC:SBC #19:BCS PrDec     :\ Calculate year
 5990   ADC #100
 6000   :
 6010   .PrDec
 6020   TAX:LDA #&99:SED:.PrDecLp
 6030   CLC:ADC #1:DEX:BPL PrDecLp:CLD
 6040   :
 6050   .PrHex
 6060   PHA:LSR A:LSR A:LSR A:LSR A
 6070   JSR PrNyb:PLA:AND #15:.PrNyb
 6080   SED:CLC:ADC #&90:ADC #&40
 6090   CLD:JMP OSWRCH
 6100   :
 6110   .PrSpace:LDA #ASC" ":JMP OSWRCH
 6120   .PrSlash:LDA #ASC"/":JMP OSWRCH
 6130   :
 6140   :
 6150   \ ================
 6160   \ OSWORD emulation
 6170   \ ================
 6180   .fdc
 6190   LDA (&F2),Y:CMP #13:BEQ fdcstatus
 6200   AND #&DF
 6210   CMP #ASC"A":BEQ fdcAcorn
 6220   CMP #ASC"W":BEQ fdcWatford
 6230   LDA #3:BNE fdcSet
 6240   .fdcWatford
 6250   INY
 6260   .fdcAcorn
 6270   INY:PHA:LDA (&F2),Y:AND #7:STA &B0
 6280   PLA:AND #16:LSR A:LSR A:ADC &B0
 6290   :\ A=0/1/2/3   = A090/A120/A210/ALL
 6300   :\ A=5/7/8/9   = W110/W130/W14x/W154
 6310   .fdcSet
 6320   ASL A:ASL A:ASL A
 6330   CLC:ADC #Osw7FTable AND 255:STA Osw7FAddr+0
 6340   LDA #0:ADC #Osw7FTable DIV 256:STA Osw7FAddr+1
 6350   .fdcstEnd
 6360   RTS
 6370   :
 6380   .fdcstatus
 6390   JSR fdcFetchAddr:LDY #2
 6400   .fdcstLp1
 6410   LDA (&B0),Y:BEQ fdcstName
 6420   JSR OSASCI:INY:BNE fdcstLp1
 6430   .fdcstName
 6440   JSR fdcFetchPtr
 6450   LDA (&B0),Y:BEQ fdcstDone
 6460   LDA #ASC":":JSR OSWRCH
 6470   JMP fdcSpace
 6480   .fdcstLp2
 6490   LDA (&B0),Y:BEQ fdcstDone
 6500   PHA:LDA #ASC"&":JSR OSWRCH
 6510   LDA #&10:JSR PrHex
 6520   PLA:JSR PrHex:INY
 6530   .fdcSpace
 6540   JSR PrSpace:JSR PrSpace:JSR PrSpace
 6550   JMP fdcstLp2
 6560   .fdcstDone
 6570   JMP OSNEWL
 6580   :
 6590   .fdcFetchAddr
 6600   LDA Osw7FAddr+0:STA &B0
 6610   LDA Osw7FAddr+1:STA &B1
 6620   RTS
 6630   :
 6640   .fdcFetchPtr
 6650   LDY #0:LDA (&B0),Y:PHA
 6660   INY:LDA (&B0),Y:STA &B1
 6670   PLA:STA &B0:DEY
 6680   RTS
 6690   :
 6700   .ServOsword
 6710   LDA &EF:CMP #127           :\ Check OSWORD number
 6720   BNE P%+5:JSR Osword7F      :\ If FM disk access, play with memory
 6730   PLA:TAY:PLA                :\ Restore registers
 6740   EQUB &03:EQUB &40          :\ Pass OSWORD call to emulator and return
 6750   :
 6760   \ -------------------------------------------------------------
 6770   \ Corrupt bits of memory to simulate effects of real OSWORD &7F
 6780   \ -------------------------------------------------------------
 6790   .Osword7F
 6800   LDA &B0:PHA:LDA &B1:PHA    :\ Code calling Osword7F may be using &B0/1
 6810   JSR fdcFetchAddr
 6820   JSR fdcFetchPtr
 6830   .Osw7FLp
 6840   LDA (&B0),Y:BEQ Osw7FDone:TAX
 6850   EOR &1000,X:ROL A:EOR #&23:STA &1000,X
 6860   INY:BNE Osw7FLp
 6870   .Osw7FDone
 6880   PLA:STA &B1:PLA:STA &B0    :\ A,X,Y preserved outside here
 6890   RTS
 6900   :
 6910   .Osw7FAddr
 6920   EQUW Osw7FTableNone        :\ Pointer to address table
 6930   :
 6940   .Osw7FTable
 6950   EQUW Osw7FAcorn1:EQUS "A090":EQUB 0:EQUB 0
 6960   EQUW Osw7FAcorn1:EQUS "A120":EQUB 0:EQUB 1
 6970   EQUW Osw7FAcorn2:EQUS "A210":EQUB 0:EQUB 2
 6980   .Osw7FTableNone
 6990   EQUW Osw7FNone :EQUS "NONE":EQUB 0:EQUB 3
 7000   EQUW Osw7FAll  :EQUS "ALL ":EQUB 0:EQUB 4
 7010   EQUW Osw7FWatf :EQUS "W110":EQUB 0:EQUB 5
 7020   EQUW Osw7FWatf :EQUS "W120":EQUB 0:EQUB 6
 7030   EQUW Osw7FWatf :EQUS "W130":EQUB 0:EQUB 7
 7040   EQUW Osw7FWatf :EQUS "W14x":EQUB 0:EQUB 8
 7050   EQUW Osw7FWat5 :EQUS "W15x":EQUB 0:EQUB 9
 7060   .Osw7FNone
 7070   EQUB 0
 7080   :
 7090   .Osw7FAcorn1:\ Locations corrupted by Acorn DFS 0.90/1.20
 7100   EQUB &72:EQUB &73:EQUB &74:EQUB &75:EQUB &80:EQUB &82
 7110   EQUB &83:EQUB &85:EQUB &C8:EQUB &C9:EQUB &D3:EQUB &D5
 7120   EQUB &D6:EQUB 0
 7130   :
 7140   .Osw7FAcorn2:\ Locations corrupted by Acorn DFS 2.10/2.20
 7150   EQUB &87:EQUB &88:EQUB &89:EQUB &8B:EQUB &8C:EQUB &8D
 7160   EQUB &8E:EQUB &D3:EQUB &D6:EQUB &DE:EQUB &DF:EQUB &E0
 7170   EQUB &E1:EQUB 0
 7180   :
 7190   .Osw7FWatf :\ Locations corrupted by Watford 1.00-1.44
 7200   EQUB &42:EQUB &43:EQUB &4A:EQUB &78:EQUB &88:EQUB &89
 7210   EQUB &8A:EQUB 0
 7220   :
 7230   .Osw7FWat5 :\ Locations corrupted by Watford 1.54
 7240   EQUB &30:EQUB &36:EQUB &38:EQUB &3F:EQUB &42:EQUB &43
 7250   EQUB &4A:EQUB &78:EQUB &88:EQUB &89:EQUB &8A:EQUB &A0
 7260   EQUB &A1:EQUB &A2:EQUB &A3:EQUB &A4:EQUB &A5:EQUB &A6
 7270   EQUB &A7:EQUB &A8:EQUB &A9:EQUB &AA:EQUB 0
 7280   :
 7290   .Osw7FAll  :\ Composite of all locations
 7300   EQUB &30:EQUB &33:EQUB &36:EQUB &38:EQUB &3F:EQUB &42
 7310   EQUB &43:EQUB &44:EQUB &4A:EQUB &72:EQUB &73:EQUB &74
 7320   EQUB &75:EQUB &78:EQUB &79:EQUB &7A:EQUB &7B:EQUB &80
 7330   EQUB &82:EQUB &83:EQUB &85:EQUB &87:EQUB &88:EQUB &89
 7340   EQUB &8A:EQUB &8B:EQUB &8C:EQUB &8D:EQUB &8E:EQUB &A0
 7350   EQUB &A1:EQUB &A2:EQUB &A3:EQUB &A4:EQUB &A5:EQUB &A6
 7360   EQUB &A7:EQUB &A8:EQUB &A9:EQUB &AA:EQUB &C8:EQUB &C9
 7370   EQUB &D3:EQUB &D5:EQUB &D6:EQUB &DE:EQUB &DF:EQUB &E0
 7380   EQUB &E1::EQUB 0
 7390   :
 7400   ]
 7410   IF O%>L%:PRINT"Code overflow":END
 7420 NEXT
 7430 PRINT" *SAVE VDFS05/ROM ";~mcode%;" ";~O%;" 0 FFFBBC00"
 7440 REM &03 opcode calls, also performs a RTS:
 7450 REM &00 FSC
 7460 REM &01 OSFIND
 7470 REM &02 OSGBPB
 7480 REM &03 OSBPUT
 7490 REM &04 OSBGET
 7500 REM &05 OSARGS
 7510 REM &06 OSFILE
 7520 :
 7530 REM &40 OSWORD service call
 7540 REM &41 OSBYTE service call
 7550 :
 7560 REM &80 Read CMOS low level location X, return in Y and A
 7570 REM &81 Write Y to CMOS low level location X
 7580 REM &82 Read EPROM low level location X, return in Y and A
 7590 REM &83 Write Y to EPROM low level location X
 7600 :
 7610 REM &D0 *SRLOAD
 7620 REM &D1 *SRWRITE
 7630 REM &D2 *DRIVE
 7640 REM &D3 Load/Run/Exec !BOOT
 7650 REM &D4 Does nothing
 7660 REM &D5 *BACK
 7670 REM &D6 *MOUNT
 7680 :
 7690 REM &FF Quit