Applecorn/auxmem.hostfs.s
2021-08-26 17:36:46 -04:00

585 lines
17 KiB
ArmAsm

* AUXMEM.HOSTFS.S
* (c) Bobbi 2021 GPL v3
*
* AppleMOS Host File System
* OSFIND - open/close a file for byte access
FINDHND PHX
PHY
PHA
STX ZP1 ; Points to filename
STY ZP1+1
CMP #$00 ; A=$00 = close
BEQ :CLOSE
PHA
LDA #<MOSFILE+1
STA ZP2
LDA #>MOSFILE+1
STA ZP2+1
LDY #$00
:L1 LDA (ZP1),Y
>>> WRTMAIN
STA (ZP2),Y
>>> WRTAUX
INY
CMP #$0D ; Carriage return
BNE :L1
DEY
>>> WRTMAIN
STY MOSFILE ; Length (Pascal string)
>>> WRTAUX
PLA ; Recover options
>>> XF2MAIN,OFILE
:CLOSE >>> WRTMAIN
STY MOSFILE ; Write file number
>>> WRTAUX
>>> XF2MAIN,CFILE
OSFINDRET
>>> ENTAUX
PLY ; Value of A on entry
CPY #$00 ; Was it close?
BNE :S1
TYA ; Preserve A for close
:S1 PLY
PLX
RTS
* OSGBPB - Get/Put a block of bytes to/from an open file
GBPBHND LDA #<OSGBPBM
LDY #>OSGBPBM
JMP PRSTR
OSGBPBM ASC 'OSGBPB.'
DB $00
* OSBPUT - write one byte to an open file
BPUTHND PHX
PHY
PHA ; Stash char to write
>>> WRTMAIN
STY MOSFILE ; File reference number
>>> WRTAUX
>>> XF2MAIN,FILEPUT
OSBPUTRET
>>> ENTAUX
CLC ; Means no error
PLA
PLY
PLX
RTS
* OSBGET - read one byte from an open file
BGETHND PHX
PHY
>>> WRTMAIN
STY MOSFILE ; File ref number
>>> WRTAUX
>>> XF2MAIN,FILEGET
OSBGETRET
>>> ENTAUX
CLC ; Means no error
CPY #$00 ; Check error status
BEQ :NOERR
SEC ; Set carry for error
BRA :EXIT
:NOERR CLC
:EXIT PLY
PLX
RTS
* OSARGS - adjust file arguments
* On entry, A=action
* X=>4 byte ZP control block
* Y=file handle
ARGSHND PHA
PHX
PHY
CPY #$00
BNE :HASFILE
CMP #$00 ; Y=0,A=0 => current file sys
BNE :S1
PLY
PLX
PLA
LDA #105 ; 105=AppleFS filing system
RTS
:S1 CMP #$01 ; Y=0,A=1 => addr of CLI
BNE :S2
* TODO: Implement this for *RUN and *command
JSR BEEP
BRA :IEXIT
:S2 CMP #$FF ; Y=0,A=FF => flush all files
BNE :IEXIT
>>> WRTMAIN
STZ MOSFILE ; Zero means flush all
>>> WRTAUX
BRA :IFLUSH
:HASFILE >>> WRTMAIN
STY MOSFILE ; File ref num
STX MOSFILE+1 ; Pointer to ZP control block
>>> WRTAUX
CMP #$00 ; Y!=0,A=0 => read seq ptr
BNE :S3
>>> WRTMAIN
STZ MOSFILE+2 ; 0 means get pos
>>> WRTAUX
>>> XF2MAIN,TELL
:IEXIT BRA :IEXIT2
:IFLUSH BRA :FLUSH
:S3 CMP #$01 ; Y!=0,A=1 => write seq ptr
BNE :S4
>>> WRTMAIN
LDA $00,X
STA MOSFILE+2
LDA $01,X
STA MOSFILE+3
LDA $02,X
STA MOSFILE+4
>>> WRTAUX
>>> XF2MAIN,SEEK
:IEXIT2 BRA :EXIT
:S4 CMP #$02 ; Y!=0,A=2 => read file len
BNE :S5
>>> WRTMAIN
STA MOSFILE+2 ; Non-zero means get len
>>> WRTAUX
>>> XF2MAIN,TELL
:S5 CMP #$FF ; Y!=0,A=FF => flush file
BNE :EXIT
:FLUSH >>> XF2MAIN,FLUSH
:EXIT PLY
PLX
PLA
RTS
OSARGSRET
>>> ENTAUX
PLY
PLX
PLA
RTS
* OSFILE - perform actions on entire files
* On entry, A=action
* XY=>control block
* On exit, A=preserved if unimplemented
* A=0 object not found (not load/save)
* A=1 file found
* A=2 directory found
* XY preserved
* control block updated
FILEHND PHX
PHY
PHA
STX ZP1 ; LSB of parameter block
STX CBPTR
STY ZP1+1 ; MSB of parameter block
STY CBPTR+1
LDA #<FILEBLK
STA ZP2
LDA #>FILEBLK
STA ZP2+1
LDY #$00 ; Copy to FILEBLK in main mem
:L1 LDA (ZP1),Y
>>> WRTMAIN
STA (ZP2),Y
>>> WRTAUX
INY
CPY #$12
BNE :L1
LDA (ZP1) ; Pointer to filename->ZP2
STA ZP2
LDY #$01
LDA (ZP1),Y
STA ZP2+1
LDA #<MOSFILE+1 ; ZP1 is dest pointer
STA ZP1
LDA #>MOSFILE+1
STA ZP1+1
LDA (ZP2) ; Look at first char of filename
CMP #'9'+1
BCS :NOTDIGT
CMP #'0'
BCC :NOTDIGT
LDA #'N' ; Prefix numeric with 'N'
>>> WRTMAIN
STA (ZP1)
>>> WRTAUX
LDY #$01 ; Increment Y
DEC ZP2 ; Decrement source pointer
LDA ZP2
CMP #$FF
BNE :L2
DEC ZP2+1
BRA :L2
:NOTDIGT LDY #$00
:L2 LDA (ZP2),Y
>>> WRTMAIN
STA (ZP1),Y
>>> WRTAUX
INY
CMP #$21 ; Space or Carriage return
BCS :L2
DEY
>>> WRTMAIN
STY MOSFILE ; Length (Pascal string)
>>> WRTAUX
PLA ; Get action back
PHA
BEQ :SAVE ; A=00 -> SAVE
CMP #$FF
BEQ :LOAD ; A=FF -> LOAD
CMP #$06
BEQ :DELETE ; A=06 -> DELETE
CMP #$08
BEQ :MKDIR ; A=08 -> MKDIR
LDA #<OSFILEM ; If not implemented, print msg
LDY #>OSFILEM
JSR PRSTR
PLA
PHA
JSR OUTHEX
LDA #<OSFILEM2
LDY #>OSFILEM2
JSR PRSTR
PLA ; Not implemented, return unchanged
PLY
PLX
RTS
:SAVE >>> XF2MAIN,SAVEFILE
:LOAD >>> XF2MAIN,LOADFILE
:DELETE >>> XF2MAIN,DELFILE
:MKDIR >>> XF2MAIN,MAKEDIR
* On return here, A<$80 just return to caller, A>$7F generate error
OSFILERET
>>> ENTAUX
PHA
LDA CBPTR ; Copy OSFILE CB to :CBPTR addr
STA ZP1
LDA CBPTR+1
STA ZP1+1
LDY #$02
:L3 LDA AUXBLK,Y ; Mainmem left it in AUXBLK
STA (ZP1),Y
INY
CPY #18 ; 18 bytes in control block
BNE :L3
PLA
* BMI :L4
* JMP :EXIT ; ret<$80, return it to user
:L4 PLY ; Value of A on OSFILE entry
CPY #$FF ; See if command was LOAD
BNE :NOTLOAD ; Deal with return from SAVE
CMP #$01 ; No file found
BNE :SL1
BRA ERRNOTFND
:SL1 CMP #$02 ; Read error
BNE :SL2
BRK
DB $CA ; $CA = Premature end, 'Data lost'
ASC 'Read error'
BRK
:SL2 LDA #$01 ; Return code - file found
BRA :EXIT
:NOTLOAD CPY #$00 ; See if command was SAVE
BNE :NOTLS ; Not LOAD or SAVE
CMP #$01 ; Unable to create or open
BNE :SS1
BRK
DB $C0 ; $C0 = Can't create file to save
ASC 'Can'
DB $27
ASC 't save file'
BRK
:SS1 CMP #$02 ; Unable to write
BNE :SS2
BRK
DB $CA ; $CA = Premature end, 'Data lost'
ASC 'Write error'
BRK
:SS2 LDA #$01 ; Return code - file found
:NOTLS CMP #$00 ; File was not found
BNE :SD1
JMP :EXIT
* BRK
* DB $D6 ; $D6 = File not found
* ASC 'Not found'
* BRK
:SD1 CMP #$FF ; Some other error
BNE :EXIT ; A=0 or 1 already
BRK
DB $D6 ; TODO: Better error code?
ASC 'Can'
DB $27
ASC 't delete'
BRK
:NOTLSD CPY #$08 ; Was it CDIR?
BNE :EXIT
CMP #$00 ; A=0 means dir was created
BNE ERREXISTS
:SC1 LDA #$02 ; A=2 - dir exists or was created
:EXIT PLY
PLX
RTS
ERRNOTFND BRK
DB $D6 ; $D6 = Object not found
ASC 'File not found'
BRK
ERREXISTS BRK
DB $C4 ; Can't create a dir if a file is
ASC 'File exists' ; already there
BRK
CBPTR DW $0000
OSFILEM ASC 'OSFILE($'
DB $00
OSFILEM2 ASC ')'
DB $00
OSFSCM ASC 'OSFSC.'
DB $00
* OSFSC - miscellanous file system calls
*****************************************
* On entry, A=action, XY=>command line
* or A=action, X=param1, Y=param2
* On exit, A=preserved if unimplemented
* A=modified if implemented
* X,Y=any return values
*
* TO DO: use jump table
FSCHND CMP #$00
BEQ FSOPT ; A=0 - *OPT
CMP #$01
BEQ CHKEOF ; A=1 - Read EOF
CMP #$02
BEQ FSCRUN ; A=2 - */filename
CMP #$04
BEQ FSCRUN ; A=4 - *RUN
CMP #$05
BEQ FSCCAT ; A=5 - *CAT
CMP #$09
BEQ FSCCAT ; A=9 - *EX
CMP #$0A
BEQ FSCCAT ; A=10 - *INFO
CMP #$0C
BEQ FSCREN ; A=12 - *RENAME
FSCUKN PHA
LDA #<OSFSCM
LDY #>OSFSCM
JSR PRSTR
PLA
RTS
FSCRUN STX OSFILECB ; Pointer to filename
STY OSFILECB+1
LDA #$FF ; OSFILE load flag
STA OSFILECB+6 ; Use file's address
LDX #<OSFILECB ; Pointer to control block
LDY #>OSFILECB
JSR OSFILE
JSR :CALL
LDA #$00 ; A=0 on return
RTS
:CALL JMP (OSFILECB+6) ; Jump to EXEC addr
RTS
FSCREN JSR XYtoLPTR ; Pointer to command line
JSR RENAME
RTS
* Performs OSFSC *OPT function
FSOPT RTS ; No FS options for now
* Performs OSFSC Read EOF function
* File ref number is in X
CHKEOF >>> WRTMAIN
STX MOSFILE ; File reference number
>>> WRTAUX
>>> XF2MAIN,FILEEOF
CHKEOFRET
>>> ENTAUX
TAX ; Return code -> X
RTS
* Perform CAT
* A=5 *CAT, A=9 *EX, A=10 *INFO
FSCCAT >>> XF2MAIN,CATALOG
STARCATRET
>>> ENTAUX
JSR OSNEWL
LDA #0 ; 0=OK
RTS
* Print one block of a catalog. Called by CATALOG
* Block is in AUXBLK
PRONEBLK >>> ENTAUX
LDA AUXBLK+4 ; Get storage type
AND #$E0 ; Mask 3 MSBs
CMP #$E0
BNE :NOTKEY ; Not a key block
LDA #<:DIRM
LDY #>:DIRM
JSR PRSTR
SEC
:NOTKEY LDA #$00
:L1 PHA
PHP
JSR PRONEENT
PLP
BCC :L1X
JSR OSNEWL
:L1X PLA
INC
CMP #13 ; Number of dirents in block
CLC
BNE :L1
>>> XF2MAIN,CATALOGRET
:DIRM ASC 'Directory: '
DB $00
* Print a single directory entry
* On entry: A = dirent index in AUXBLK
PRONEENT TAX
LDA #<AUXBLK+4 ; Skip pointers
STA ZP3
LDA #>AUXBLK+4
STA ZP3+1
:L1 CPX #$00
BEQ :S1
CLC
LDA #$27 ; Size of dirent
ADC ZP3
STA ZP3
LDA #$00
ADC ZP3+1
STA ZP3+1
DEX
BRA :L1
:S1 LDY #$00
LDA (ZP3),Y
BEQ :EXIT ; Inactive entry
AND #$0F ; Len of filename
TAX
LDY #$01
:L2 CPX #$00
BEQ :S2
LDA (ZP3),Y
JSR OSWRCH
DEX
INY
BRA :L2
:S2 LDA #$20
JSR OSWRCH
INY
CPY #$15
BNE :S2
:EXIT RTS
* Perform FSCV $0C RENAME function
* Parameter string in OSLPTR
RENAME LDY #$00
:ARG1 LDA (OSLPTR),Y
CMP #$20 ; Space
BEQ :ENDARG1
CMP #$0D ; Carriage return
BEQ :RENSYN
INY
>>> WRTMAIN
STA MOSFILE,Y
>>> WRTAUX
BRA :ARG1
:ENDARG1 >>> WRTMAIN
STY MOSFILE ; Length of Pascal string
>>> WRTAUX
JSR SKIPSPC
JSR LPTRtoXY ; Update LPTR and set Y=0
JSR XYtoLPTR ; ...
:ARG2 LDA (OSLPTR),Y
CMP #$20 ; Space
BEQ :ENDARG2
CMP #$0D ; Carriage return
BEQ :ENDARG2
INY
>>> WRTMAIN
STA MOSFILE2,Y
>>> WRTAUX
BRA :ARG2
:ENDARG2 >>> WRTMAIN
STY MOSFILE2 ; Length of Pascal string
>>> WRTAUX
>>> XF2MAIN,RENFILE
:RENSYN BRK
DB $DC
ASC 'Syntax: RENAME <old fname> <new fname>'
BRK
RENRET
>>> ENTAUX
CMP #$44 ; Path not found
BEQ :NOTFND
CMP #$45 ; Vol dir not found
BEQ :NOTFND
CMP #$46 ; File not found
BEQ :NOTFND
CMP #$47 ; Duplicate filename
BEQ :EXISTS
CMP #$4E ; Access error
BEQ :LOCKED
CMP #$00
BNE :OTHER ; All other errors
RTS
:NOTFND JMP ERRNOTFND
:EXISTS JMP ERREXISTS
:LOCKED BRK
DB $C3
ASC 'Locked'
:OTHER BRK
DB $C7
ASC 'Disc error'
BRK
* Handle *DIR (directory change) command
* On entry, ZP1 points to command line
STARDIR JSR EATSPC ; Eat leading spaces
:S1 LDX #$01
:L3 LDA (ZP1),Y
CMP #$0D
BEQ :S3
>>> WRTMAIN
STA MOSFILE,X
>>> WRTAUX
INY
INX
BRA :L3
:S3 DEX
>>> WRTMAIN
STX MOSFILE ; Length byte
>>> WRTAUX
>>> XF2MAIN,SETPFX
STARDIRRET
>>> ENTAUX
CMP #$00
BEQ :EXIT
BRK
DB $CE ; Bad directory
ASC 'Bad dir'
BRK
:EXIT RTS