;license:MIT ;(c) 2017-8 by 4am ; ; ProDOS - file and other MLI routines ; ; Public functions ; - LoadFile ; - LoadDHRFile ; - LoadSHRFile ; - SaveFile ; - SetPrefix ; - GetFileInfo ; ; MLI command codes CMD_QUIT = $65 ; quit to ProDOS CMD_CREATE = $C0 ; create new file CMD_DESTROY = $C1 ; delete a file CMD_SETFILEINFO= $C3 ; set file info CMD_GETFILEINFO= $C4 ; get file (or volume) info 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_SETFILEINFO = $07 PC_GETFILEINFO = $0A PC_SETPREFIX = $01 PC_OPEN = $03 PC_READ = $04 PC_WRITE = $04 PC_CLOSE = $01 ; ROM addresses PRODOSMLI = $BF00 ; [callable] MLI entry point MACHID = $BF98 ; machine identification byte kAccessBits = $C3 ; full access (used in SaveFile) ;------------------------------- ; LoadFile ; load a file into memory all at once, using ProDOS MLI calls ; ; in: stack contains 6 bytes of parameters: ; +1 address of pathname ; +3 address of data buffer (to receive file contents) ; +5 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 ;------------------------------- LoadFile +PARAMS_ON_STACK 6 +LDPARAM 1 +STAY mliparam+1 ; pathname +LDPARAM 5 +STAY mliparam+3 ; ProDOS file buffer jsr _openfile bcs @exit ; C set on error pha ; push file reference number +LDPARAM 3 +STAY mliparam+2 ; data buffer lda #$FF sta mliparam+4 ; max data length (unlimited, YOLO) 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 ;------------------------------- LoadDHRFile +PARAMS_ON_STACK 4 ldy #$04 - lda (PARAM),y sta mliparam,y dey bne - jsr _openfile bcs @exit ; C set on error sta @saverefnum ; store file refnum ldy #$20 stz mliparam+2 ; read into $2000 in main mem sty mliparam+3 stz mliparam+4 ; read length = $2000 bytes (first half of file) sty mliparam+5 jsr _readfile bcs @close sta $C000 ldx #$20 ; copy $2000 bytes to auxmem stx @copya+2 stx @copyb+2 ldy #0 @writeToAuxLoop sta $C005 @copya lda $FF00, y @copyb sta $FF00, y iny bne @copya sta $C004 inc @copya+2 inc @copyb+2 dex bne @writeToAuxLoop lda @saverefnum jsr _readfile ; read another $2000 bytes into $2000 (stays in main mem) @close php ; save flags from readfile @saverefnum=*+1 lda #$FD ; file refnum (SMC) jsr _closefile plp ; restore flags from readfile @exit rts ;------------------------------- ; LoadSHRFile ; load uncompressed SHR file into memory from .PIC file ; 1. load first quarter ($2000 bytes) ; 2. copy to graphics memory ; 3. load second quarter ($2000 bytes) ; 4. copy to graphics memory ; 5. load third quarter ($2000 bytes) ; 6. copy to graphics memory ; 7. load fourth quarter ($2000 bytes) ; 8. copy to graphics memory ; ; 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 ;------------------------------- LoadSHRFile +PARAMS_ON_STACK 4 ldy #$04 - lda (PARAM),y sta mliparam,y dey bne - jsr _openfile bcs exit ; C set on error sta saverefnum ; store file refnum ldy #$20 stz mliparam+2 ; read into $2000 in main mem sty mliparam+3 stz mliparam+4 ; read length = $2000 bytes (one quarter of file) sty mliparam+5 sty shrdest+2 ldx #4 ; four quarters - lda saverefnum ; file refnum jsr _readfile bcs close phx PatchVidHD bcs copyvidhd !cpu 65816 xce rep #$30 !rl !al lda #$1FFF tax inx shrdest ldy #$FD00 ; SMC phb mvn 0,$E1 plb sty shrdest+1 !as !rs sec xce !cpu 65C02 resumeread plx dex bne - close php ; save flags from readfile saverefnum=*+1 lda #$FD ; file refnum (SMC) jsr _closefile plp ; restore flags from readfile exit rts copyvidhd lda $C035 and #$F7 ;Enable SHR shadowing sta $C035 lda #$a0 sec @calcdest sbc #$20 dex bne @calcdest sta $45 stx $44 ldx #$20 ldy #0 stx $43 sty $42 sta $C005 ;CPU writes go to aux 64K @copyshr lda ($42), y sta ($44), y iny bne @copyshr inc $43 inc $45 dex bne @copyshr sta $C004 ;CPU writes go to main 64K clc bcc resumeread ; 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 ; if C clear, save succeeded ; all other flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------- SaveFile +PARAMS_ON_STACK $0B +LDPARAM 1 +STAY mliparam+1 ; pathname lda #CMD_DESTROY ; MLI destroy command ldy #PC_DESTROY ; number of parameters for 'destroy' command jsr mli ; don't care if this fails ldy #$03 lda (PARAM),y ; file type sta mliparam+4 +LDPARAM 4 +STAY mliparam+5 ; aux file type lda #kAccessBits 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 bcs @exit +LDPARAM 10 +STAY mliparam+3 ; PrODOS file buffer jsr _openfile bcs @exit sta mliparam+1 ; store file reference number +LDPARAM 6 +STAY mliparam+2 ; data buffer +LDPARAM 8 +STAY mliparam+4 ; data length lda #CMD_WRITE ; MLI write command ldy #PC_WRITE ; number of parameters for 'write' command jsr mli php ; save flags from write command jsr _closefile ; always close whether write worked or not plp ; restore flags from write ; (so caller gets codes from write attempt, ; not close) @exit rts ;------------------------------- ; SetAuxFileType ; set auxiliary file information only ; access bits and file-type are hard-coded ; intended for updating save-games only ; ; in: stack contains 4 bytes of parameters: ; +1 address of pathname ; +3 auxiliary type to set ; out: if C set, MLI call failed and A contains error code ; from set ; if C clear, MLI call succeeded ; all other flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------- SetAuxFileType +PARAMS_ON_STACK 4 +LDPARAM 1 +STAY mliparam+1 ; pathname +LDPARAM 3 +STAY mliparam+5 ; aux type lda #%11000011 sta mliparam+3 ; access bits lda #4 sta mliparam+4 ; file type lda #0 sta extra+0 ; date sta extra+1 ; date sta extra+2 ; time sta extra+3 ; time lda #CMD_SETFILEINFO ; MLI command ldy #PC_SETFILEINFO ; number of parameters for 'setfileinfo' command bra mli ;------------------------------- ; 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 ;------------------------------- SetPrefix +PARAMS_ON_STACK 2 +LDPARAM 1 +STAY mliparam+1 ; pathname lda #CMD_SETPREFIX ldy #PC_SETPREFIX bra mli ;------------------------------- ; GetFileInfo ; just what it says on the tin ; ; in: stack contains 2 bytes of parameters: ; +1 address of pathname ; out: if C set, MLI call failed and A contains error code ; from open or read ; if C clear, MLI call succeeded and mliparam contains ; all the info ; all other flags clobbered ; all registers clobbered ; stack set to next instruction after parameters ;------------------------------- GetFileInfo +PARAMS_ON_STACK 2 +LDPARAM 1 +STAY mliparam+1 ; pathname lda #CMD_GETFILEINFO ; MLI command ldy #PC_GETFILEINFO ; number of parameters for 'getfileinfo' command bra mli ;------------------------------- ; 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 @exit lda refnum ; caller should save file reference number ; as this memory location may be ; overwritten by later MLI calls @exit 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 @exit lda mliparam+1 ; if no error, return file reference number @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 bra mli 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/getfileinfo) ; member is also used by createfile extra !byte $FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE ; used by get_file_info