; C02 Module fileio Assembly Language Eoutines for run6502 emulator ; This is the reference implementation of the fileo module ; The run6502 program has been customized with an emulated file command ; routine at the address set with the -F command line option. ; The file routine is JSRed with the command in A, and any parameters ; in Y and/or X. After command execution. Y and/or X will contain any ; return values, with Y is usually the error code. ; ; The Command Routine FSCMD is defines in file include/run6502.a02 SUBROUTINE FILEIO DRIVES EQU 26 ;Number of Disk Drives DRIVE BYTE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;Disk Drive Letters DISKS EQU 1 ;Number of Disks in Drive DISK BYTE 0 ;File Open Modes MREAD EQU $00 ;Open for Read MWRITE EQU $40 ;Open for Write MAPPND EQU $80 ;Open for Append MRECRD EQU $C0 ;Record Oriented File ;File Open Types TTEXT EQU $00 ;Open as Texy File TBNRY EQU $20 ;Open as Binary File ; File Load Modes MRELCT EQU $00 ;Relocate (Load at Specified Address) MABSLT EQU $80 ;Absolute (Load at Address in File Header) ;ferror(chan, &msg) - Check for Error ;Args: A = Channel Number ; Y,X = String Address ;Returns: A = Last Error ($FF - Invalid Channel) ; Y = Error (0=None) FERROR: JSR FSADDR ;Set Buffer Address TAY ;Set Channel Number LDA #'Y' ;Set Command to FERROR BNE .FEXECX ;Execute and Return Result in A ;fflush(chan) - Flush Write Buffer to File ;Args: A = Channel ;Returns: A = Status (0=Success, $FF = Failure) ; Y = Error (0=None) FFLUSH: TAY ;Set Channel Number LDA #'F' ;Set Command to FLUSH BNE .FEXECX ;Execute and Return Result in A ;fopen(mode, &name) - Open File ;Setup: Call FSRECS with Record Size if Mode is MRECRD ;Args: A = File Mode | Drive ID ; Y,X = Pointer to File Name ;Returns: A = File Channel (0=File Not Opened) ; Y = Error (0=None) FOPEN: JSR FSNAME ;Set Filename .FOPEN TAX ;Pass File Mode to X JSR FSDRVN ;Convert Drive Letter to Drive Number BCS .FOPERR ;If Error, Return Carry Set TAY ;Pass Drive Number in Y CLC ;Set Mode to FOPEN LDA #'O' ;Set Command to OPEN .FEXECX JSR FSCMD ;Execute Command TXA ;Return Channel in A .FOPERR RTS ;fclose(chan) - Close File ;Args: A = Channel Number ;Returns: A = Error (0=None) FCLOSE: TAY ;Set Channel CLC ;Set Mode to FCLOSE LDA #'C' ;Set Command to CLOSE .FEXECY JSR FSCMD ;Execute Command TYA ;Return Errno RTS ;feof(chan) - Check for End of File ;Args: A = Channel Number ;Returns: A = $00 - Not End of File ; $FF - End of File ; Otherwise, Error Code FEOF: TAY ;Set Channel LDA #'E' ;Set Command to EOF BNE .FEXECY ;Execute and Return Errno ;fgetc(chan) - Read Character from File ;Args: A = Channel Number ;Returns: A = Character ; Y = Error Code ($00 - Success) FGETC: TAY ;Set Channel LDA #'G' ;Set Command to GET BNE .FEXECX ;Execute and Return Result ;fgets(chan, &s) - Read String from File ;Args: A = Channel Number ; Y,X = Address of String ;Returns: A = Number of Bytes Read ; Y = Error Code ($00 - Success) FGETS: JSR FSADDR ;Set String Address TAY ;Set Channel Number LDA #'H' ;Set Command to GETS BNE .FEXECX ;Execute and Return Result in A ;fgetr(chan, recno) - Read Record from File ;Setup: Call FSADDR with buffer address ;Args: A = Channel Number ; Y,X = Record Number ;Returns: A = Error Code ; Y,X = Next Record Number FGETR: JSR FSINDX ;Set Record Number TAY ;Set Channel Number SEC ;Set Mode to RECORD LDA #'R' ;Set Command to READ BNE .FSCMD ;Execute Command and Return ;fgetw(chan) - Read Word from File ;Args: A = Channel Number ;Returns: A = Error Code ($00 - Success) ; Y,X = Word FGETW: TAY ;Set Channel CLC ;Set Mode to Get LDA #'J' ;Set Command to GET BNE .FSCMD ;Execute Command and Return ;fputc(chan, char) - Write Character to File ;Args: A = Character to Write ; Y = Channel Number ;Returns: A = Error Code ($00 - Success) FPUTC: TAX ;Set Character to Write LDA #'P' ;Set Command to PUT BNE .FEXECX ;Execute and Return Result in A ;fputln(chan, &s) - Write String to File with Newline ;Args: A = Channel Number ; Y,X = Address of String ;Returns: A = Number of Characters Written ; Y = Error Code ($00 - Success) FPUTLN: SEC ;Append Newline BCS .FPUTSA ;Write String to File ;fputr(chan, recno) - Write Record from File ;Setup: Call FSADDR with buffer address ;Args: A = Channel Number ; Y,X = Record Number ;Returns: A = Error Code ; Y,X = Next Record Number FPUTR: JSR FSINDX ;Set Record Number TAY ;Set Channel Number SEC ;Set Mode to RECORD LDA #'W' ;Set Command to READ BNE .FSCMD ;Execute Command and Return ;fputs(chan, &s) - Write String to File ;Args: A = Channel Number ; Y,X = Address of String ;Returns: A = Number of Characters Written ; Y = Error Code ($00 - Success) FPUTS: CLC ;Do Not Append Newline .FPUTSA JSR FSADDR ;Set File Buffer Address TAY ;Set Channel LDA #'Q' ;Set Command to PUTS BNE .FEXECX ;Execute and Return Result in A ;fputw(chan, word) - Write Word to File ;Args: A = Channel Number ; Y,X = Word ;Returns: A = Error Code ($00 - Success) FPUTW: JSR FSADDR ;Set File Buffer Address TAY ;Set Channel SEC ;Set Mode to PUT LDA #'J' ;Set Command to WORD BNE .FEXECY ;Execute and Return Result in A ;fread(count, chan) - Read Bytes from File ;Setup: Call FSADDR with array address ;Args: A = Number of Bytes to Read ; Y = Channel Number ;Returns: A = Number of Bytes Read ; Y = Error Code ($00 - Success) FREAD: TAX ;Set Number of Bytes to Write CLC ;Set Mode to BYTES LDA #'R' ;Set Command to READ BNE .FEXECX ;Execute and Return Result in A ;rewind(chan) - Move to Beginning of File ;Args: A = Channel Number ;Returns: A = Error Code ($00 - Success) REWIND: LDX #0 ;Set Position to $0000 LDY #0 ;and Fall Through to FSEEK ;fseek(chan, pos) - Move to Position in File ;Args: A = Channel Number ; Y,X = Position ;Returns: A = Error Code ($00 = Success) FSEEK: JSR FSINDX ;Set File Index to Position` TAY ;Set Channel to A CLC ;Set Mode to SEEK LDA #'Z' ;Set Command to SEEK BNE .FEXECY ;Execute and Return Errno ;ftell(chan, pos) - Get Position in File ;Args: A = Channel Number ;Returns: A = Error Code ($00 = Success) ; Y,X = Position in File ($FFFF = Failure) FTELL: JSR FSADDR ;Set File Address to Position` TAY ;Set Channel to A SEC ;Set Mode to TELL LDA #'Z' ;Set Command to SEEK BNE .FSCMD ;Execute Command and Return ;fwrite(count cban) - Write Bytes to File ;Setup: Call FSADDR with array address ;Args: A = Number of Bytes to Write ; Y = Channel Number ;Returns: A = Number of Bytes Written ; Y = Error Code ($00 - Success) FWRITE: TAX ;Set Number of Bytes to Write LDA #'W' ;Set Command to WRITE BNE .FEXECX ;Execute and Return Result in A ;fload(name) - Load File into Memory ;Setup: Call FSNAME with filename address ; Call FSADDR with start address ;Args: A = Option + DriveID ; Y,X = End Address ;Returns: A = Error Code ($00 - Success) ; X,Y = Load Address FLOAD: CMP #MABSLT ;Check Load Mode BNE .ERR22 ;If Invalid, Return Error LDA #'L' ;Set Command to LOAD BNE .FSCMD ;Execute Command and Return .ERR22 LDA #22 RTS ;fsave(name) - Save File from Memory ;Setup: Call FSNAME with filename address ; Call FSADDR with start address ;Args: A = Option + DriveID ; Y,X = End Address ;Returns: A = Error Code ($00 - Success) FSAVE: ORA $0 ;If Not Drive 0 BNE .ERR22 ;Return Error LDA #'S' ;Set Command to SAVE BNE .FSCMD ;Execute Command and Return ;File System Commands ;Convert Drive Letter Into Drive Number ;Drive letters A-Z in DOS map to drive numbers 1-26 ;A drice specifier of NULL - SPACE or @ maps to drive 0, which ;means the current drive in the run6502 File Command Processor. ;Args: A = Drive Letter ;Returns: A = Drive Number ; Carry Clear = Valid Drive Number ; Carry Set = Invalid Drive Number FSDRVN: SEC SBC #' ' ;If Drive Specifier BCS .FSDRVL ;is NULL through SPACE LDA #0 ; Return Drive Number 0 RTS ; and Carry Clear .FSDRVL AND #$1F ;Convert A-Z, a-z to 1-26 CMP #DRIVES+2 ;If Drive Number is BCC .RETURN ;greater than 26 LDA #$FF ; Return Operation Failed LDY #1 ; and Error - Invalid Argument .RETURN RTS ;fsinit() - Initialize File System FSINIT: LDA #'I' ;Set Command to INITFS .FSCMD JMP FSCMD ;Execute Command and Return ;fsrecs(size) - Set File Record Size ;Args: A = Size FSRECS: TAX ;Set Y.X to 0,A LDY #0 ;and Fall The to FSINDX ;fsindx(&array) - Set File Record Number ;Args: Y,X = Record Number FSINDX: PHP ;Save Status Register PHA ;Save Accumulator SEC ;Set Mode to FILEINDX BCS .FSADDR ;Execute ADDRESS and Restore Accumulator ;fsaddr(&array) - Set File Buffer Address ;Args: Y,X = Address of String or Array FSADDR: PHP ;Save Status Register PHA ;Save Accumulator CLC ;Set mode to FILEADDR .FSADDR LDA #'A' ;Set Command to ADDRESS JSR FSCMD ;Execute command PLA ;Restore Accumulator PLP ;Restore Status Register RTS ;fsbuff(&name) - Set File Buffer ;Args: Y,X = Address of String FSBUFF: PHA ;Save Accumulator PHP ;Save Status Register SEC ;Set Mode to FILEBUFF BCS .SETNAM ;Execute Command 'N' and Return ;fsname(&name) - Set File Name ;Args: Y,X = Address of Filename FSNAME: PHA ;Save Accumulator PHP ;Save Status Register CLC ;Set Mode to FILENAME .SETNAM LDA #'N' ;Set command to name .FSCMDA JSR FSCMD ;Execute command PLP ;Restore Status Register PLA ;Restore Accumulator RTS ; Command Description Arguments Returns ; FSADDR Set Buffer Address A='A',YX=Addr YX=Addr ; FCLOSE Close File A='C',Y=Chan,CC Y=Err ; CLOSEDIR Close Directory A='C',Y=Chan,CS Y=Err ; READDIR Read Dir Entry A='D',Y=Chan (1) Y=Err ; FEOF Check for EOF A="E',Y=Chan Y=Err ($FF=EOF) ; FFLUSH Flush Output A='F',Y=Chan Y=Err ; FGETC Get Character A='G',Y=Chan Y=Err, X=Char ; FGETS Get String A='H',Y=Chan (1) Y=Err ; FSINIT Init File System A='I', ; REMOVE Remove File A='K',YX=Name Err ; FLOAD Load File A='L' (3) A=Err, YX=End ; RENAME Rename File A='M',YX=New (2) Y=Err ; FSNAME Set Filename A='N',YX=Name,CC ; FOPEN Open File A='O',Y=Mode|Drive,CC (2) Y=Err, X=Chan ; OPENDIR Open Directory A='O',Y=Drive,CS (2) Y=Err, X=Chan ; FPUTC Put Character A='P',Y=Chan,X=Char Y=Err, X=Char ; FPUTS Put String A='Q',Y=Chan (1) Y=Err ; FREAD Read Bytes A='R',Y=Chan,X=Count (1) Y=Err, X=Count ; FSAVE Save File A='S',Y=Chan,YX=End (3) Y=Err ; GETCWD Get Current Dir A='U',Y=Drive (1) Y=Err, X=Len ; CHDIR Change Directory A='U',Y=Drive (2) Y=Err ; GETDRV Get Current Drive A='V',CC Y=Err, X=Result ; CHDRV Set Current Drive A='V',Y=Drive,CS Y=Err, X=Result ; FWRITE Write Bytes A='W',Y=Chan, X=Count (1) Y=Err, X=Count ; MKDIR Create Directory A='X',Y=Drive,CC (2) Y=Err, X=Result ; RMDIR Remove Directory A='X',Y=Drive,CS (2) Y=Err, X=Result ; FERROR Get Last Error A='Y',Y=Chan (1) Y=Err ; (1) Requires call to FSADDR ; (2) Requires call to FSNAME (and FSINDX for FOPEN w/MRECRD) ; (3) Requires calls to FSADDR and FSNAME