; 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 ; routine at the address set with the -F command line option ; The file routine is JSRed with the command code in A, and any ; parameters in Y and/or X. After command execution. Y and/or X ; will contain any return values. Y is usually the error code. 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 MWRITE EQU $80 ; File Load Modes MRELCT EQU $00 ;Relocate (Load at Specified Address) MABSLT EQU $80 ;Absolute (Load at Address in File Header) ;fflush(chan) - Flush Write Buffer to File ;Args: A = Channel ;Returns: A = Error (0=None) FFLUSH: TAY ;Set Channel Number LDA #'F' ;Set Command to FLUSH BNE .FEXECX ;Execute and Return Result in A .FEXEC JSR FSCMD ;Execute Command TYA ;Return Error Code ;fopen(mode, &name) - Open File ;Args: A = 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 TAX ;Pass Mode to X JSR FSDRVN ;Convert Drive Letter to Drive Number BCS .RETURN ;If Error, Return Carry Set TAY ;Pass Drive Number in Y LDA #'O' ;Set Command to OPEN .FEXECX JSR FSCMD ;Execute Command TXA ;Return Channel in A RTS ;fclose(chan) - Close File ;Args: A = Channel Number ;Returns: A = Error (0=None) FCLOSE: TAY ;Set Channel LDA #'C' ;Set Command to CLOSE BNE .FEXEC ;Execute and Return Error in A ;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 .FEXEC ;Execute and Return Error in A ;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 in A ;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 ;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 .FEXEC ;Execute and Return Error 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 ;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 ;fread(chan, count) - 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 LDA #'R' ;Set Command to READ BNE .FEXECX ;Execute and Return Result in A ;fwrite(chan, count) - 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 JMP 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 ;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 ;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 ;fsaddr(&array) - Set File Buffer Address ;Emulation: sets internal variable filebuff ;Args: Y,X = Address of String or Array FSADDR: PHA ;Save Accumulator LDA #'A' ;Set Command to ADDRESS BNE .FSCMDA ;Execute and Restore Accumulator ;fsname(&name) - Set File Name ;Emulation: sets internal variable filename ;Args: Y,X = Address of Filename FSNAME: PHA ;Save Accumulator LDA #'N' ;Set command to name .FSCMDA JSR FSCMD ;Execute command PLA ;Restore Accumulator RTS ;fscmd(cmd, args) - File I/O Command Processor ;Args: A = Command Code ; Y,X = Arguments(s) ;Returns: A = Command Code (usually) ; Y = Error Code (usually) ; X = Result (when applicable) FSCMD: EQU $FFE6 ;run6502 File I/O Command Routine ; Command Description Arguments Requires Returns ; FSADDR Set Buffer Address A='A', YX=Addr YX=Addr ; CLOSEDIR Close Directory A='B', Y=Chan Y=Err ; FCLOSE Close File A='C', Y=Chan Y=Err ; OPENDIR Open Directory A='D', YX=Name Y=Err, X=Chan ; 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 # Y=Err ; FSINIT Init File System A='I' ; READDIR Read Dir Entry A='J', Y=Chan # Y=Err ; REMOVE Remove File A='K', YX=Name Y=Err ; FLOAD Load File A='L' * A=Err, YX=End ; RENAME Rename File A='M', YX=New + Y=Err ; FSNAME Set Filename A='N', YX=Name ; FOPEN Open File A='O', Y=Mode + Y=Err ; FPUTC Put Character A='P', Y=Chan, X=Char Y=Err ; FPUTS Put String A='Q', Y=Chan # Y=Err ; FREAD Read Bytes A='R', Y=Chan, X=Count # Y=Err, X=Count ; FSAVE Save File A='S', Y=Chan, YX=End * Y=Err ; GETCWD Get Current Dir A='T', Y=Chan, YX=Addr Y=Err, X=Len ; CHDIR Change Directory A='U', YX=Name Y=Err ; GCDRIVE Get/Set Cur Drive A='V', Y=Drive, C=Mode Y=Err, X=Result ; FWRITE Write Bytes A='W', Y=Chan, X=Count # Y=Err, X=Count ; MKRMDIR Create/Remove Dir A='X', YX=Name, C=Mode Y=Err, X=Result ; FERROR Get Last Error A='Y', Y=Chan # Y=Err ; # Requires call to FSADDR ; + Requires call to FSNAMR ; * Requires calls to FSADDR and FSNAME