;license:MIT ;(c) 2017-8 by 4am ; ; ProDOS and file routines ; ; Public functions ; - LoadFile ; - LoadDHRFile ; - SaveFile ; - SetPrefix ; - QuitToProDOS ; ; MLI command codes CMD_QUIT = $65 ; quit to ProDOS CMD_CREATE = $C0 ; create new file CMD_DESTROY = $C1 ; delete a file CMD_SETPREFIX= $C6 ; change default pathname prefix CMD_OPEN = $C8 ; open a file CMD_READ = $CA ; read an open file CMD_WRITE = $CB ; write to an open file CMD_CLOSE = $CC ; close an open file ; MLI parameter counts PC_QUIT = $04 PC_CREATE = $07 PC_DESTROY = $01 PC_SETPREFIX = $01 PC_OPEN = $03 PC_READ = $04 PC_WRITE = $04 PC_CLOSE = $01 PRODOSMLI = $BF00 ; [callable] MLI entry point ;------------------------------- ; LoadFile ; 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 { LoadFile pla sta $00 plx stx $01 lda #$08 clc adc $00 bcc + inx + phx 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 .exit ; 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) .exit rts } ;------------------------------- ; LoadDHRFile ; load uncompressed DHR file into memory from .A2FC file ; 1. load first half ($2000 bytes) ; 2. copy to auxmem ; 3. load second half ($2000 bytes) ; ; always loads into graphics page 1 ($2000/main and $2000/aux) ; ; in: stack contains 4 bytes of parameters: ; +1 address of pathname ; +3 address of ProDOS file buffer ; out: if C set, load failed ; if C clear, load succeeded ; all other flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------- !zone { LoadDHRFile pla sta $00 plx stx $01 lda #$04 clc adc $00 bcc + inx + phx pha ldy #$04 - lda ($00),y sta mliparam,y dey bne - jsr _openfile bcs .exit ; C set on error sta .saverefnum+1 ; store file refnum ldy #$20 stz mliparam+2 ; read into $2000 sty mliparam+3 stz mliparam+4 ; max $2000 bytes sty mliparam+5 jsr _readfile bcs .close sta $C000 ldx #$20 ; copy $2000 bytes to auxmem stx .copya+2 stx .copyb+2 ldy #$00 .writeToAux sta $C005 .copya lda $FF00, y .copyb sta $FF00, y iny bne .copya sta $C004 inc .copya+2 inc .copyb+2 dex bne .writeToAux lda .saverefnum+1 jsr _readfile .close php ; save flags from readfile .saverefnum lda #$d1 ; file refnum (set above) jsr _closefile plp ; restore flags from readfile .exit rts } ;------------------------------- ; SaveFile ; 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 { SaveFile pla sta $00 plx stx $01 lda #$0B clc adc $00 bcc + inx + phx 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 .exit 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 .exit 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) .exit rts } ;------------------------------- ; SetPrefix ; set current directory ; ; in: stack contains 2 bytes of parameters: ; +1 address of pathname ; out: if C set, call failed and A contains error code ; if C clear, call succeeded ; all other flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------- !zone { SetPrefix pla sta $00 plx stx $01 lda #$02 clc adc $00 bcc + inx + phx pha ldy #$01 lda ($00),y ; lo byte of pathname sta mliparam+1 iny lda ($00),y ; hi byte of pathname sta mliparam+2 jmp _setprefix } ;------------------------------- ; 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 ;------------------------------- _openfile lda #CMD_OPEN ; MLI command ldy #PC_OPEN ; number of parameters for 'open' command jsr mli bcs + lda refnum ; caller should save file reference number ; as this memory location may be ; overwritten by later MLI calls + 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 ;------------------------------- _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 + lda mliparam+1 ; if no error, return file reference number + 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 ;------------------------------- _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 + lda mliparam+1 ; if no error, return file reference number + 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) ldy #1 sty mliparam+7 ; storage type (file) dey sty mliparam+8 ; creation date (current) sty mliparam+9 sty mliparam+10 ; creation time (current) sty 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 ;------------------------------- ; 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 ;------------------------------- QuitToProDOS lda #CMD_QUIT ldy #PC_QUIT ; execution falls through here ;------------------------------- ; 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