;license:MIT ;(c) 2020 by 4am ; ; ProDOS MLI wrapper (6502 compatible) ; ; Public functions: ; - LoadFile1Shot ; - SaveFile1Shot ; - CreateFile ; - OpenFile ; - ReadFile ; - WriteFile ; - SeekFile ; - FlushFile ; - CloseFile ; - Quit ; ProDOS constants (these are memory addresses) PRODOSMLI = $BF00 ; [callable] MLI entry point DEVNUM = $BF30 ; last accessed device ; MLI parameter counts + command codes (these are not memory addresses) CMD_QUIT = $0465 ; quit to ProDOS CMD_GETTIME = $0082 ; get current time CMD_CREATE = $07C0 ; create new file CMD_DESTROY = $01C1 ; delete a file CMD_GETFILEINFO = $0AC4 ; get file (or volume) info CMD_ONLINE = $02C5 ; check online volume(s) CMD_SETPREFIX = $01C6 ; change current directory CMD_GETPREFIX = $01C7 ; get current directory CMD_OPEN = $03C8 ; open a file CMD_NEWLINE = $03C9 ; set line-by-line read mode CMD_READ = $04CA ; read an open file CMD_WRITE = $04CB ; write to an open file CMD_CLOSE = $01CC ; close an open file CMD_FLUSH = $01CD ; flush an open, written file to disk CMD_SETMARK = $02CE ; change position in an open file CMD_SETEOF = $02D0 ; set file size ;------------------------------------------------------------------------------ ; LoadFile1Shot ; load a file into memory all at once, using ProDOS MLI calls ; ; in: stack contains 8 bytes of parameters: ; +1 [word] address of pathname ; +3 [word] address of data buffer (to receive file contents) ; +5 [word] maximum length of data to read ; +7 [word] address of ProDOS file buffer ; out: if C set, load failed and A = error code from open or read ; if C clear, load succeeded ; Y clobbered ; X preserved ; all other flags & registers clobbered ;------------------------------------------------------------------------------ LoadFile1Shot +PARAMS_ON_STACK 8 +LDPARAM16 1, @filename +LDPARAM16 3, @databuffer +LDPARAM16 5, @datalength +LDPARAM16 7, @filebuffer jsr OpenFile @filename !word $FDFD @filebuffer !word $FDFD bcs @exit sta @refnum jsr ReadFile @refnum !byte $FD @databuffer !word $FDFD @datalength !word $FDFD php lda @refnum jsr CloseFile plp @exit 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 (if we need to create the file) ; +4 [word] aux file type ; +6 [word] address of data buffer ; +8 [word] length of data buffer ; +A [word] address of ProDOS file buffer ; out: if C set, save failed and A = error code ; from open or write ; if C clear, save succeeded ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ SaveFile1Shot +PARAMS_ON_STACK 11 +LDPARAM16 $01, @filename +LDPARAM16 $01, @filename2 +LDPARAM8 $03, @filetype +LDPARAM16 $04, @auxfiletype +LDPARAM16 $06, @databuffer +LDPARAM16 $08, @datalength +LDPARAM16 $0A, @filebuffer - jsr OpenFile @filename !word $FDFD @filebuffer !word $FDFD bcc + jsr CreateFile @filename2 !word $FDFD @filetype !byte $FD @auxfiletype !word $FDFD bcs @exit bcc - + sta @refnum jsr WriteFile @databuffer !word $FDFD @datalength !word $FDFD php ; save C flag from WriteFile pha ; save error code or file refnum @refnum=*+1 lda #$FD ; SMC jsr CloseFile pla ; A = error code or file refnum from WriteFile plp ; get C flag from Writefile @exit rts ;------------------------------------------------------------------------------ ; CreateFile ; 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: stack contains 5 bytes of parameters: ; +1 address of pathname ; +3 [byte] file type ; +4 [word] aux file type ; out: if error, C set and A = error code ; if success, C clear ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ CreateFile +PARAMS_ON_STACK 5 +LDPARAM16 1, mliparam+1 ; address of filename +LDPARAM8 3, mliparam+4 ; filetype +LDPARAM16 4, mliparam+5 ; aux filetype lda #$C3 ; = full access sta mliparam+3 ; set access bits ldy #1 ; = file sty mliparam+7 ; storage type dey ; = 0 (current date/time) sty mliparam+8 ; creation date sty mliparam+9 sty mliparam+10 ; creation time sty mliparam+11 +LDADDR CMD_CREATE jmp mli ;------------------------------------------------------------------------------ ; OpenFile ; open file via ProDOS MLI ; ; in: stack contains 4 bytes of parameters: ; +1 [word] address of filename ; +3 [word] ProDOS file buffer ; out: if C set, open failed and A = error code ; if C clear, open succeeded and A = file reference number ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ OpenFile +PARAMS_ON_STACK 4 +LDPARAM16 1, mliparam+1 ; address of filename +LDPARAM16 3, mliparam+3 ; address of ProDOS file buffer +LDADDR CMD_OPEN jsr mli bcs + lda refnum ; caller should save file reference number ; as this memory location may be ; overwritten by later MLI calls + rts ;------------------------------------------------------------------------------ ; ReadFile ; read an open file via ProDOS MLI ; ; in: stack contains 5 bytes of parameters: ; +1 [byte] ProDOS file reference number ; +2 [word] address of data buffer (to receive file contents) ; +4 [word] maximum length of data to read ; out: if C set, read failed and A = error code ; if C clear, read succeeded and A = the same ; file reference number that was passed in ; Y clobbered ; X preserved ; other flags clobbered ; stack set to next instruction after parameters ;------------------------------------------------------------------------------ ReadFile +PARAMS_ON_STACK 5 +LDPARAM8 1, mliparam+1 ; file reference number +LDPARAM16 2, mliparam+2 ; address of data buffer +LDPARAM16 4, mliparam+4 ; data length +LDADDR CMD_READ jsr mli bcs + lda mliparam+1 ; if no error, return file reference number + rts ;------------------------------------------------------------------------------ ; WriteFile ; write to an open file via ProDOS MLI ; ; in: A = file reference number ; stack contains 4 bytes of parameters: ; +1 [word] address of data buffer ; +3 [word] length of data buffer ; out: if C set, save failed and A = error code ; if C clear, write succeeded and A = the same file reference ; number that was passed in ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ WriteFile sta mliparam+1 ; file reference number +PARAMS_ON_STACK 4 +LDPARAM16 1, mliparam+2 ; data buffer address +LDPARAM16 3, mliparam+4 ; data buffer length +LDADDR CMD_WRITE jsr mli bcs + ; error, A = MLI error code lda mliparam+1 ; no error, return file reference number + rts ;------------------------------------------------------------------------------ ; SeekFile ; set file position within an open file ; ; in: A = file reference number ; X = seek offset (lo) ; Y = seek offset (hi) ; note: this routine can not seek beyond 65535 bytes even though ; ProDOS can do that ; out: if C set, seek failed and A = error code ; if C clear, seek succeeded and A = the same file reference ; number that was passed in ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ SeekFile sta mliparam+1 ; file reference number stx mliparam+2 sty mliparam+3 lda #0 sta mliparam+4 +LDADDR CMD_SETMARK bne mli ; always branches ;------------------------------------------------------------------------------ ; FlushFile ; flush an open file (actually writes it to disk, but without closing it) ; ; in: A = file reference number ; out: if error, C set and A = error code ; if success, C clear ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ FlushFile sta mliparam+1 ; file reference number +LDADDR CMD_FLUSH bne mli ; always branches ;------------------------------------------------------------------------------ ; CloseFile ; close an open file ; ; in: A = file reference number ; out: if error, C set and A = error code ; if success, C clear ; Y clobbered ; X preserved ; other flags clobbered ;------------------------------------------------------------------------------ CloseFile sta mliparam+1 ; file reference number +LDADDR CMD_CLOSE bne mli ; always branches GetTime +LDADDR CMD_GETTIME beq mli ; always branches ;------------------------------------------------------------------------------ ; Quit ; quit to ProDOS ; in: none ; out: does not return ;------------------------------------------------------------------------------ Quit lda #0 jsr CloseFile +LDADDR CMD_QUIT ; /!\ execution falls through here ;------------------------------------------------------------------------------ ; mli ; 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 $FD,$FD,$FD,$FD filetype !byte $FD ; file type (set by MLI get_file_info) auxtype ; auxiliary file type (2 bytes, set by MLI get_file_info) refnum !byte $FD ; file refnum (set by MLI open) mlilen !byte $FD,$FD ; file length (set by MLI read) blocks !byte $FD,$FD ; blocks used (set by getvolumeinfo) ; member is also used by createfile !byte $FD,$FD,$FD,$FD,$FD,$FD,$FD,$FD ; used by get_file_info