passport/src/mli.a
2017-08-13 09:07:16 -07:00

855 lines
23 KiB
Plaintext
Executable File

; MLI command codes
CMD_CREATE = $C0 ; create new file
CMD_DESTROY = $C1 ; delete a file
CMD_GETFILEINFO = $C4 ; get file (or volume) info
CMD_ONLINE = $C5 ; check online volume(s)
CMD_SETPREFIX = $C6 ; change default pathname prefix
CMD_OPEN = $C8 ; open a file
CMD_NEWLINE = $C9 ; set line-by-line read mode
CMD_READ = $CA ; read an open file
CMD_WRITE = $CB ; write to an open file
CMD_CLOSE = $CC ; close an open file
CMD_SETMARK = $CE ; change position in an open file
CMD_SETEOF = $D0 ; set file size
; MLI parameter counts
PC_CREATE = $07
PC_DESTROY = $01
PC_GETFILEINFO = $0A
PC_ONLINE = $02
PC_SETPREFIX = $01
PC_OPEN = $03
PC_NEWLINE = $03
PC_READ = $04
PC_WRITE = $04
PC_CLOSE = $01
PC_SETMARK = $02
PC_SETEOF = $02
PRODOSMLI = $BF00 ; [callable] MLI entry point
!ct "lcase.ct"
RAMFileName !text "PASSPORTTMP.DSK"
RAMFileName_e
; MLI error codes
ERR_FNF = $46
ERR_EOF = $4C
;-------------------------------
; WriteTrackMLI - write the contents of
; BASEPAGE data buffer to disk
; in: @SLOT contains (slot x 16) + $30
; @DRIVE contains drive + $30
; @gTrack contains track number
; @BASEPAGE contains data to write ($1000 bytes)
; out: if C set, write failed (A contains MLI error code)
; if C clear, write succeeded (A is clobbered)
; all other flags clobbered
; all registers clobbered
;-------------------------------
!zone {
WriteTrackMLI
jsr SwapProDOS
lda gUsingRAMDisk
beq +
jsr ReorderBuffer
+ lda #$81 ; 'write block' command
sta mlicmd
lda DRIVE ; ProDOS "unit number" is
sec
sbc #$31
lsr ; DSSS0000, where D is the
lda #00 ; drive number (0=drive 1,
ror ; 1=drive 2) and SSS is
; the slot number (1-7).
; "Beneath Apple ProDOS"
; page 6-19
sta mliparam+1
lda SLOT
asl
asl
asl
asl
ora mliparam+1
sta mliparam+1
lda #$00
sta mliparam+2 ; lo byte of data buffer
lda #$08
sta .blockcount
lda gTrack
asl
asl
asl
sta mliparam+4 ; lo byte of block number
rol
and #$01
sta mliparam+5 ; hi byte of block number
lda #BASEPAGE ; hi byte of data buffer
sta mliparam+3
.writeloop
lda gUsingRAMDisk
beq +
lda mlicmd
ldy #$03 ; parameter count
jsr mli
bcs .writeerr
- inc mliparam+3 ; 2 pages per block
inc mliparam+3
inc mliparam+4
dec .blockcount
bne .writeloop
clc
bcc .writedone
+ jsr WriteToRAMFile
bcc -
.writeerr
.writedone
php
pha
lda gUsingRAMDisk
beq +
jsr ReorderBuffer
+ jsr SwapProDOS
pla
plp
rts
.blockcount !byte $FF
}
;-------------------------------
; ReorderBuffer - convert data
; buffer between ProDOS and
; DOS 3.3 ordering (use after
; read or before write under
; ProDOS)
; in: none
; out: all flags clobbered
; all registers clobbered
; @cmp1, @cmp2 clobbered
;-------------------------------
!zone {
ReorderBuffer
lda #$00
sta cmp1
sta cmp2
tay
lda #$01
clc
adc #BASEPAGE
sta cmp1+1
lda #$0E
clc
adc #BASEPAGE
sta cmp2+1
ldx #$07
.L lda (cmp1),y
pha
lda (cmp2),y
sta (cmp1),y
pla
sta (cmp2),y
iny
bne .L
inc cmp1+1
dec cmp2+1
dex
bne .L
rts
}
;-------------------------------
; SaveFile1Shot
; save a file to disk all at once,
; using ProDOS MLI calls
;
; in: stack contains 11 ($0B) bytes of parameters:
; +1 address of pathname
; +3 [byte] file type
; +4 [word] aux file type
; +6 address of data buffer
; +8 [word] length of data buffer
; +A address of ProDOS file buffer
; out: if C set, save failed and A contains error code
; from open or write
; if C clear, save succeeded
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
!zone {
SaveFile1Shot
pla
sta $00
pla
sta $01
tax
lda #$0B
clc
adc $00
bcc .noinc
inx
.noinc
tay
txa
pha
tya
pha
ldy #$01
lda ($00),y ; lo byte of pathname
sta mliparam+1
iny
lda ($00),y ; hi byte of pathname
sta mliparam+2
jsr DeleteFile ; don't care if this fails
ldy #$03
lda ($00),y ; file type
sta mliparam+4
iny
lda ($00),y ; lo byte of aux file type
sta mliparam+5
iny
lda ($00),y ; hi byte of aux file type
sta mliparam+6
jsr CreateFile
bcs .savefile1s
ldy #$0A
lda ($00),y ; lo byte of ProDOS file buffer
sta mliparam+3
iny
lda ($00),y ; hi byte of ProDOS file buffer
sta mliparam+4
jsr OpenFile
bcs .savefile1s
pha ; push file reference number
ldy #$06
lda ($00),y ; lo address of data buffer
sta mliparam+2
iny
lda ($00),y ; hi address of data buffer
sta mliparam+3
iny
lda ($00),y ; lo data length
sta mliparam+4
iny
lda ($00),y ; hi data length
sta mliparam+5
pla ; pull file reference number
jsr WriteFile
php ; save flags from writefile
pha
jsr CloseFile ; always close whether write worked or not
pla
plp ; restore flags from write
; (so caller gets codes from write attempt,
; not close)
.savefile1s
rts
}
;-------------------------------
; LoadFile1Shot
; load a file into memory all at once,
; using ProDOS MLI calls
;
; in: stack contains 8 bytes of parameters:
; +1 address of pathname
; +3 address of data buffer (to receive file contents)
; +5 [word] maximum length of data to read
; +7 address of ProDOS file buffer
; out: if C set, load failed and A contains error code
; from open or read
; if C clear, load succeeded and ($02) contains
; data loaded from file
; all other flags clobbered
; all registers clobbered
; stack set to next instruction after parameters
;-------------------------------
!zone {
LoadFile1Shot
pla
sta $00
pla
sta $01
tax
lda #$08
clc
adc $00
bcc .noinc
inx
.noinc
tay
txa
pha
tya
pha
ldy #$01
lda ($00),y ; lo byte of pathname
sta mliparam+1
iny
lda ($00),y ; hi byte of pathname
sta mliparam+2
ldy #$07
lda ($00),y ; lo byte of ProDOS file buffer
sta mliparam+3
iny
lda ($00),y ; hi byte of ProDOS file buffer
sta mliparam+4
jsr OpenFile
bcs .loadfile1s ; C set on error
pha ; push file reference number
ldy #$03
lda ($00),y ; lo address of data buffer
sta mliparam+2
iny
lda ($00),y ; hi address of data buffer
sta mliparam+3
iny
lda ($00),y ; lo data length
sta mliparam+4
iny
lda ($00),y ; hi data length
sta mliparam+5
pla ; pull file reference number
jsr ReadFile
php ; save flags from readfile
pha
jsr CloseFile ; always close whether read worked or not
pla
plp ; restore flags from readfile
; (so caller gets codes from read attempt,
; not close)
.loadfile1s
rts
}
;-------------------------------
; open file via ProDOS MLI
;
; in: caller has filled @mliparam with address of
; pathname, address of data buffer, and maximum
; data length
; out: if C set, open failed and A contains error code
; if C clear, open succeeded and A contains
; file reference number
;-------------------------------
!zone {
OpenFile
lda #CMD_OPEN ; MLI command
ldy #PC_OPEN ; number of parameters for 'open' command
jsr mli
bcs .openfile
lda refnum ; caller should save file reference number
; as this memory location may be
; overwritten by later MLI calls
.openfile
rts
}
;-------------------------------
; set line-by-line mode via ProDOS MLI
;
; in: A = file reference number
; out: if C set, set failed and A contains error code
; if S clear, set succeeded and A contains the same
; file reference number that was passed in
;-------------------------------
lbl_mask = $7F
lbl_cr = $0D
!zone {
SetLineByLine
sta mliparam+1 ; store file reference number
lda #lbl_mask ; accept high bit set or clear
sta mliparam+2
lda #lbl_cr ; carriage return character
sta mliparam+3
lda #CMD_NEWLINE ; MLI 'newline' command to set read mode
ldy #PC_NEWLINE ; number of parameters for 'newline' command
jsr mli
bcs .setlinebylin
lda mliparam+1 ; if no error, return file reference number
.setlinebylin
rts
}
;-------------------------------
; read an open file via ProDOS MLI
;
; in: A = file reference number
; caller has filled @mliparam with address of
; data buffer and maximum data length
; out: if C set, read failed and A contains error code
; if C clear, read succeeded and A contains the same
; file reference number that was passed in
;-------------------------------
!zone {
ReadFile
sta mliparam+1 ; store file reference number
lda #CMD_READ ; MLI read command
ldy #PC_READ ; number of parameters for 'read' command
jsr mli
bcs .readfile
lda mliparam+1 ; if no error, return file reference number
.readfile
rts
}
;-------------------------------
; change file position in an open file via ProDOS MLI
;
; in: A = file reference number
; caller has filled @mliparam+2/+3/+4 with
; new file position
; out: if C set, set_mark call failed and A contains error code
; if C clear, set_mark call succeeded and A contains
; the same file reference number that was passed in
;-------------------------------
!zone {
SetMark
sta mliparam+1 ; store file reference number
lda #CMD_SETMARK ; MLI set_mark command
ldy #PC_SETMARK ; number of params for 'set_mark' cmd
jsr mli
bcs .exit
lda mliparam+1 ; if no error, return file refnum
.exit rts
}
;-------------------------------
; write to an open file via ProDOS MLI
;
; in: A = file reference number
; caller has filled @mliparam with address of
; data buffer and data length
; out: if C set, write failed and A contains error code
; if C clear, write succeeded and A contains the same
; file reference number that was passed in
;-------------------------------
!zone {
WriteFile
sta mliparam+1 ; store file reference number
lda #CMD_WRITE ; MLI write command
ldy #PC_WRITE ; number of parameters for 'write' command
jsr mli
bcs .writefile
lda mliparam+1 ; if no error, return file reference number
.writefile
rts
}
;-------------------------------
; set file size in an open file via ProDOS MLI
;
; in: A = file reference number
; caller has filled @mliparam+2/+3/+4 with
; new file size
; out: if C set, set_eof call failed and A contains error code
; if C clear, set_eof call succeeded and A contains
; the same file reference number that was passed in
;-------------------------------
!zone {
SetEOF
sta mliparam+1 ; store file reference number
lda #CMD_SETEOF ; MLI set_eof command
ldy #PC_SETEOF ; number of params for 'set_eof' cmd
jsr mli
bcs .exit
lda mliparam+1 ; if no error, return file refnum
.exit rts
}
;-------------------------------
; close an open file
; in: A = file reference number
; out: if error, C set and A contains error code
; if success, C clear
;-------------------------------
CloseFile
sta mliparam+1 ; store file reference number
lda #CMD_CLOSE ; MLI close command
ldy #PC_CLOSE ; number of parameters for 'close' command
jsr mli
rts
;-------------------------------
; create a file via ProDOS MLI
; always sets access bits to $C3 (full access)
; always sets creation to 0 (current date/time)
; always sets storage type to 1 (file)
; in: caller has filled @mliparam
; with address of pathname,
; file type, aux file type
; out: if error, C set and A contains error code
; if success, C clear
;-------------------------------
accessbits = $C3 ; full access
CreateFile
lda #accessbits
sta mliparam+3 ; access bits (full access)
lda #1
sta mliparam+7 ; storage type (file)
lda #0
sta mliparam+8 ; creation date (current)
sta mliparam+9
sta mliparam+10 ; creation time (current)
sta mliparam+11
lda #CMD_CREATE ; MLI create command
ldy #PC_CREATE ; number of parameters for 'create' command
jsr mli
rts
;-------------------------------
; delete a file using ProDOS MLI
; in: caller has filled @mliparam
; with address of pathname
; out: if error, C set and A contains error code
; if success, C clear
;-------------------------------
DeleteFile
lda #CMD_DESTROY ; MLI destroy command
ldy #PC_DESTROY ; number of parameters for 'destroy' command
jsr mli
rts
;-------------------------------
; CreateRAMFile - create image file on RAM disk
; if RAM disk is in use
; in: nothing (assumes that prefix is set to /RAM)
; out: if C set, write failed (A contains MLI error code)
; if C clear, write succeeded (A is clobbered)
; all other flags clobbered
; all registers clobbered
;-------------------------------
!zone {
CreateRAMFile
lda gUsingRAMDisk
bne .done
;existing file being reused?
lda gRAMDiskRef
bne .done
;no, create a new one
lda OnlineReturn
tay
clc
adc #(RAMFileName_e-RAMFileName)+1
sta RAMPath
tax
lda #$2F
sta RAMPath+1,y
- lda OnlineReturn,y
sta RAMPath,y
dey
bne -
ldy #(RAMFileName_e-RAMFileName)
- lda RAMFileName-1,y
sta RAMPath,x
dex
dey
bne -
jsr DeleteRAMFile
jsr CreateFile
bcs .createfail
lda #0
sta mliparam+3
lda #8
sta mliparam+4
jsr OpenFile
bcs .openfail
sta gRAMDiskRef
;140kb
ldx #0
stx mliparam+2
ldx #$30
stx mliparam+3
ldx #2
stx mliparam+4
jsr SetEOF
;update file buffer array
php
jsr SaveGlobal
plp
bcc .done
lda gRAMDiskRef
jsr CloseFile
.openfail
pha
jsr DeleteRAMFile
pla
sec
.createfail
ldx #FALSE
stx gUsingRAMDisk
.done
rts
RAMPath !byte $d1
!fill 17
!fill RAMFileName_e-RAMFileName
}
;-------------------------------
; WriteToRAMFile - write memory to image file on RAM disk
; if RAM disk is in use
; in: called has filled @mliparam
; with block number and write address
; out: if error, C set and A contains error code
; if success, C clear
; all other flags clobbered
; all registers clobbered
;-------------------------------
!zone {
WriteToRAMFile
lda mliparam+2
pha
lda mliparam+3
pha
lda mliparam+4
sta .tmpparm4
asl
sta mliparam+3
lda mliparam+5
sta .tmpparm5
rol
sta mliparam+4
lda #0
sta mliparam+2
lda gRAMDiskRef
jsr SetMark
tax
pla
sta mliparam+3
pla
sta mliparam+2
txa
bcs .done
lda #0
sta mliparam+4
lda #2
sta mliparam+5
lda gRAMDiskRef
jsr WriteFile
.done
pha
lda .tmpparm4
sta mliparam+4
lda .tmpparm5
sta mliparam+5
pla
rts
.tmpparm4 !byte 0
.tmpparm5 !byte 0
}
;-------------------------------
; WriteRAMToDisk - write image file in RAM to physical disk
; if RAM disk is in use
; in: nothing
; out: if error, C set and A contains error code
; if success, C clear
; all other flags clobbered
; all registers clobbered
;-------------------------------
!zone {
WriteRAMToDisk
lda #0
sta mliparam+2
sta mliparam+3
sta mliparam+4
sta gTrack
jsr SwapProDOS
lda gRAMDiskRef
jsr SetMark
jsr SwapProDOS
;prevent track write from calling RAM again
lda #FALSE
sta gUsingRAMDisk
- lda #0
sta mliparam+2
sta mliparam+4
lda #$10
sta mliparam+3
sta mliparam+5
jsr SwapProDOS
lda gRAMDiskRef
jsr ReadFile
jsr SwapProDOS
jsr WriteTrackMLI
inc gTrack
lda gTrack
cmp #$22
bne -
lda #TRUE
sta gUsingRAMDisk
.done
rts
}
;-------------------------------
; (Close)DeleteRAMFile - (close and) remove image file on RAM disk
; if RAM disk is in use
; in: nothing
; out: if error, C set and A contains error code
; if success, C clear
; all other flags clobbered
; all registers clobbered
;-------------------------------
!zone {
CloseDeleteRAMFile
lda gRAMDiskRef
jsr CloseFile
lda #0
sta gRAMDiskRef
DeleteRAMFile
lda #<RAMPath
sta mliparam+1
lda #>RAMPath
sta mliparam+2
jsr DeleteFile
.done
rts
}
;-------------------------------
; change current directory (set prefix)
; using ProDOS MLI
; in: caller has filled @mliparam
; with address of pathname
; out: if error, C set and A contains error code
; if success, C clear
;-------------------------------
SetPrefix
lda #CMD_SETPREFIX
ldy #PC_SETPREFIX
jsr mli
rts
;-------------------------------
; get volume name of disk in specific slot+drive
; in: A = unit number (DSSS0000)
; out: if no disk in drive or any MLI error, C set and A contains error code
; if disk found, C clear and @VolumeName contains volume name
; (length byte + up to 14 character name, no leading slash)
;-------------------------------
!zone {
GetVolumeName
sta mliparam+1
lda #<OnlineReturn
sta mliparam+2
lda #>OnlineReturn
sta mliparam+3
jsr Online
rts
OnlineReturn
!byte $FF
VolumeName
!byte $FF,$FF,$FF,$FF,$FF,$FF,$FF
!byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
}
;-------------------------------
; check if volume is online
; using ProDOS MLI
; in: caller has filled @mliparam
; with unit number
; out: if error, C set and A contains error code
; if success, C clear
;-------------------------------
Online
lda #CMD_ONLINE
ldy #PC_ONLINE
jsr mli
rts
;-------------------------------
; query volume information
; using ProDOS MLI
; in: nothing (queries last fetched volume)
; out: if error, C set and A contains error code
; if success, C clear and MLI buffer is filled
; (access, file type, block count, dates and times)
;-------------------------------
GetVolumeInfo
lda OnlineReturn
and #$0F
tax
inx
stx OnlineReturn
tay
- lda OnlineReturn,y
sta VolumeName,y
dey
bne -
lda #$2F ;'/'
sta VolumeName
lda #<OnlineReturn
sta mliparam+1
lda #>OnlineReturn
sta mliparam+2
lda #CMD_GETFILEINFO
ldy #PC_GETFILEINFO
jsr mli
rts
;-------------------------------
; low-level MLI wrapper
; in: A = MLI command code
; Y = number of MLI parameters
; caller has filled @mliparam
; with all relevant parameters
; out: returns immediately after
; calling MLI, so whatever
; state the MLI routine sets,
; the caller will see it
; verbatim
;-------------------------------
mli sta mlicmd ; store command code
sty mliparam ; number of parameters
jsr PRODOSMLI ; call ProDOS
mlicmd !byte 00 ; command number
!word mliparam ; address of parameter table
rts
mliparam !byte $FE,$FE,$FE,$FE
filetype !byte $FE ; file type (set by MLI get_file_info)
auxtype ; auxiliary file type (2 bytes, set by MLI get_file_info)
refnum !byte $FE ; file refnum (set by MLI open)
mlilen !byte $FE,$FE ; file length (set by MLI read)
blocks !byte $FE,$FE ; blocks used (set by getvolumeinfo)
; member is also used by createfile
!byte $FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE
; used by get_file_info