;************************************************************************* ; ; File: EinTrans.txt ; ; PC EINTRANS - This application is intended to allow the transfer of ; of files and discs between an Tatung EinStein and a PC. ; ; Original Author: Ste Ruddy (13-Sep-02) ; Maintainer: Ste Ruddy ; ; Copyright (c) 2002, Stephen Ruddy. All rights reserved. ; ;************************************************************************* CPU Z80 ;-------------------------------------------------------------------------------- ; MOS Equates MOS_CALL EQU $08 ; MOS rst code and commands used MOS_DISC_READ EQU $80+$22 ; read sectors from disc MOS_DISC_WRITE EQU $80+$23 ; write sectors to disc MOS_DISC_CMD EQU $80+$2e ; send command to disc controller MOS_DISC_RESET EQU $80+$3d ; reset disc? (sends 0 to $23 and makes some noise!) MOS_GET_KEY EQU $80+$1a ; get key MOS_PRINT_CHAR EQU $80+$1e ; print char MOS_POP_MESSAGE EQU $80+$4f ; print message until (and including) negative terminator ; MOS working parameters MOS_DRIVE_NUM EQU $FB50 ; current drive number (0-3) MOS_TRACK_NUM EQU $FB51 ; current track number (0-39 or 0-79) MOS_SECTOR_NUM EQU $FB52 ; current sector number (0-9 or 0-19) MOS_BUFADR_LO EQU $FB53 ; lo byte of data address buffer MOS_BUFADR_HI EQU $FB54 ; hi byte of data address buffer MOS_ERROR_CODE EQU $FB56 ; error code returned from MOS MOS_DRIVE_POS EQU $FB58 ; current head location (4 entries, one for each drive) ; MOS reference vars MOS_DRIVE_TYPES EQU $FBB1 ; bits specify sides and tracks for all four drives, ; bit number 76543210 ; drive 32103210 ; tracks XXXX.... where X=0 for 40, X=1 for 80 ; sides ....XXXX where X=0 for single, X=1 for MOS_OS_DRIVE EQU $FB7D ; drive to load OS from MOS_SECTOR_SIZE EQU $200 ;-------------------------------------------------------------------------------- ; CPM Equates DOS_RESET EQU $0000 DOS_KEY_VECTOR EQU $FA09 ; DOS gets keys through this (it is "JP $FA34" in DOS 1.31) CPM_BDOS EQU $0005 ; location to call to process CPM functions CPM_ADDR_FCB EQU $005C ; address of 1st FCB provided on command line CPM_ADDR_FCB2 EQU $006C ; address of 2nd FCB provided on command line (note overlay with first) CPM_ADDR_DMA EQU $0080 ; DMA buffer used when reading/writing files CPM_DMA_SIZE EQU $80 ; DMA buffer used in file transfers ; CPM Functions CPM_FUNC_CONSOLE_IN EQU 1 CPM_FUNC_CONSOLE_OUT EQU 2 CPM_FUNC_SET_DISC EQU 14 CPM_FUNC_OPEN_FILE EQU 15 CPM_FUNC_CLOSE_FILE EQU 16 CPM_FUNC_SEARCH_FIRST EQU 17 CPM_FUNC_SEARCH_NEXT EQU 18 CPM_FUNC_DELETE_FILE EQU 19 CPM_FUNC_READ_SEQ EQU 20 CPM_FUNC_WRITE_SEQ EQU 21 CPM_FUNC_CREATE_FILE EQU 22 CPM_FUNC_RENAME_FILE EQU 23 CPM_FUNC_SET_DMA_ADDR EQU 26 CPM_FUNC_GET_DPB EQU 31 ; CPM FCB structure ORG 0 FCB_DRIVE DFS 1 FCB_FILENAME DFS 8 FCB_EXTENSION DFS 3 ; top bit of offset 0=read only, top bit of offset 1=system file FCB_EX DFS 1 FCB_S1 DFS 1 FCB_S2 DFS 1 FCB_RC DFS 1 FCB_DATA DFS 16 FCB_CR DFS 1 SIZE_OF_FCB ; The following are only referenced on random access files FCB_RECORD DFS 3 SIZE_OF_FCB_RAND ;---------------------------------------------------------------------------------------------------------- ; Commands available to PC CMD_HEADER EQU '!' CMD_HEADER_NOP EQU '*' CMD_RESET EQU '%' CMD_EXIT EQU 'X' CMD_READ_FILE EQU 'R' CMD_WRITE_FILE EQU 'W' CMD_READ_DISC EQU 'r' CMD_WRITE_DISC EQU 'w' CMD_GET_DRIVE EQU 'D' CMD_GET_DIR EQU '$' CMD_GET_DPB EQU 'B' CMD_SET_DISC EQU 'S' CMD_EXECUTE EQU 'E' CMD_REN_FILE EQU '=' CMD_DEL_FILE EQU '.' ; Status ORG 0 STATUS_OK DFS 1 STATUS_NO_FILE DFS 1 STATUS_EOF DFS 1 STATUS_REPEAT DFS 1 STATUS_DISC_ERROR DFS 1 ; send disc code as status value STATUS_DISC_CODE EQU $80 ;---------------------------------------------------------------------------------------------------------- ; Configuration parameters STACK_SIZE EQU 256 ; size of stack in bytes ;---------------------------------------------------------------------------------------------------------- ORG $100 ENTRY_POINT LD SP,STACK+STACK_SIZE-1 RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 12 DFB "EINTRANS: Einstein[]PC Transfer V2.00" DFB 13,10 DFB "Copyright (c) 2002 Ste Ruddy." DFB 13,10,13,10+$80 RESTART_POINT LD SP,STACK+STACK_SIZE-1 CALL serial_reset CALL cpm_set_dma MAIN_LOOP RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13,"Waiting... ",' '+$80 !get_raw CALL serial_get_raw ; get raw ignores timeout CP CMD_HEADER_NOP JR Z,!get_raw CP CMD_HEADER JR NZ,!fail CALL serial_get LD HL,command_table-2 LD DE,!jump+1 !compare_loop INC HL INC HL BIT 7,(HL) JR NZ,!fail CP (HL) INC HL JR NZ,!compare_loop LDI LDI !jump JP 0 !fail RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 7,13," * Unknown command " !com_letter DFB "?" DFB 10,13+$80 JR MAIN_LOOP command_table DFB CMD_RESET : DFW cmd_reset DFB CMD_READ_FILE : DFW cmd_read_file DFB CMD_WRITE_FILE : DFW cmd_write_file DFB CMD_REN_FILE : DFW cmd_rename_file DFB CMD_DEL_FILE : DFW cmd_delete_file DFB CMD_READ_DISC : DFW cmd_read_disc DFB CMD_WRITE_DISC : DFW cmd_write_disc DFB CMD_GET_DRIVE : DFW cmd_get_drive DFB CMD_GET_DIR : DFW cmd_get_dir DFB CMD_GET_DPB : DFW cmd_get_dpb DFB CMD_SET_DISC : DFW cmd_set_disc DFB CMD_EXECUTE : DFW cmd_execute DFB CMD_EXIT : DFW DOS_RESET DFB $FF CPM_BDOS_KEY CALL key_swap CALL CPM_BDOS key_swap PUSH HL LD HL,(old) PUSH HL LD HL,(DOS_KEY_VECTOR+1) LD (old),HL POP HL LD (DOS_KEY_VECTOR+1),HL POP HL RET ; toggled between error vector and DOS key function old DFW CPM_ERR_VECTOR CPM_ERR_VECTOR LD A,(MOS_ERROR_CODE) ADD A,STATUS_DISC_CODE CALL serial_put RST MOS_CALL:DFB MOS_DISC_RESET CALL key_swap JP RESTART_POINT ;######################################################################################################### ;--------------------------------------------------------------------------------------------------------- ; COMMANDS FUNCTIONS - These are called from the main loop and are expected to JP MAIN_LOOP on exit ;--------------------------------------------------------------------------------------------------------- ;######################################################################################################### ; *********************************************************** ; Read specified file and send it to PC ; *********************************************************** cmd_read_file CALL receive_fcb CALL show_fcb ; open file CALL cpm_open_file JR NZ,!found ; file not found so let PC know LD A,STATUS_NO_FILE CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Not found",10,13+$80 JP MAIN_LOOP ; file found, let PC know !found LD A,STATUS_OK CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Sendin",'g'+$80 !loop CALL cpm_read_seq JR NZ,!eof LD A,STATUS_OK CALL serial_put LD HL,CPM_ADDR_DMA LD BC,CPM_DMA_SIZE CALL send_block ; loop until all blocks done JR !loop !eof LD A,STATUS_EOF CALL serial_put ; sent show message CALL show_fcb RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Sent ",13," +",13,10+$80 ; close file CALL cpm_close_file JP MAIN_LOOP ; *********************************************************** ; Get a file from the PC and save it ; *********************************************************** cmd_write_file CALL receive_fcb CALL show_fcb ; delete any existing file CALL cpm_delete_file ; create a new file CALL cpm_create_file JR NZ,!created ; couldn't create file so let PC know !failed CALL show_fcb LD A,STATUS_NO_FILE CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Write error",10,13+$80 JP MAIN_LOOP ; file created, let PC know !created LD A,STATUS_OK CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Receivin",'g'+$80 !loop LD HL,CPM_ADDR_DMA LD BC,CPM_DMA_SIZE CALL receive_block ; save out this block of data CALL cpm_write_seq OR A JR NZ,!failed LD A,STATUS_OK CALL serial_put ; check if at end of file CALL serial_get CP STATUS_EOF JR NZ,!loop ; show received message CALL show_fcb RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Received ",13," +",10+$80 ; close file CALL cpm_close_file JP MAIN_LOOP ; *********************************************************** ; Read a disc in a specified drive and send it to the PC ; *********************************************************** cmd_read_disc CALL serial_get LD (MOS_DRIVE_NUM),A CALL serial_get LD (num_tracks),A CALL serial_get LD (num_sectors),A CALL serial_get LD (sectors_per_rw),A LD HL,buffer LD BC,0 LD A,(MOS_DRIVE_NUM) CALL bios_disc_param ; show message XOR A CALL bios_drive_show !loop CALL serial_get CP A,STATUS_EOF JR Z,!done ; read another set of sectors from disc LD HL,buffer LD (MOS_BUFADR_LO),HL LD HL,sectors_status LD A,(sectors_per_rw) LD B,A !read_print XOR A CALL bios_drive_show !read_loop PUSH BC PUSH HL ; read sector from disc XOR A LD (MOS_ERROR_CODE),A RST MOS_CALL:DFB MOS_DISC_READ CALL inc_sector_num POP HL POP BC LD (HL),A INC HL DEC B JR Z,!done_read OR A JR NZ,!read_print LD A,(MOS_SECTOR_NUM) OR A JR NZ,!read_loop JR !read_print ; send status information !done_read CALL send_status ; now send sector data LD HL,buffer LD A,(sectors_per_rw) LD B,A !send_loop PUSH BC LD BC,512 CALL send_block POP BC DJNZ !send_loop JR !loop !done RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + DISC read and sent ",10,13+$80 JP MAIN_LOOP ; *********************************************************** ; Get a disc image from the PC and write it to a disc ; *********************************************************** cmd_write_disc CALL serial_get LD (MOS_DRIVE_NUM),A CALL serial_get LD (num_tracks),A CALL serial_get LD (num_sectors),A CALL serial_get LD (sectors_per_rw),A LD HL,buffer LD BC,0 LD A,(MOS_DRIVE_NUM) CALL bios_disc_param ; show message LD A,1 CALL bios_drive_show !loop CALL serial_get CP A,STATUS_EOF JR Z,!done ; write another block of data to disc LD HL,buffer LD A,(sectors_per_rw) LD B,A ; get sectors from PC !read_sector PUSH BC LD BC,512 CALL receive_block POP BC DJNZ !read_sector ; write sectors to disc LD HL,buffer LD (MOS_BUFADR_LO),HL LD A,(sectors_per_rw) LD B,A LD HL,sectors_status !write_print LD A,1 CALL bios_drive_show !write_loop PUSH HL PUSH BC ; write current sector XOR A LD (MOS_ERROR_CODE),A RST MOS_CALL:DFB MOS_DISC_WRITE CALL inc_sector_num POP BC POP HL LD (HL),A INC HL DEC B JR Z,!send_status OR A JR NZ,!write_print LD A,(MOS_SECTOR_NUM) OR A JR NZ,!write_loop JR !write_print !send_status CALL send_status JR !loop !done RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + DISC received and written ",10,13+$80 JP MAIN_LOOP ; increment sector inc_sector_num LD A,(num_sectors) LD HL,(MOS_TRACK_NUM) INC H CP H JR NZ,!sec_ok LD H,0 INC L !sec_ok LD (MOS_TRACK_NUM),HL ; increment buffer address LD A,(MOS_BUFADR_HI) INC A INC A LD (MOS_BUFADR_HI),A ; store result LD A,(MOS_ERROR_CODE) OR A RET Z PUSH AF RST MOS_CALL:DFB MOS_DISC_RESET POP AF RET ; *********************************************************** ; Get a directory for a spcified drive ; *********************************************************** cmd_get_dir CALL serial_get PUSH AF ADD A,'0' LD (!mess_drive),A RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," - Reading DIR track " !mess_drive DFB "?",':'+$80 CALL serial_get ; directory track LD C,A CALL serial_get ; number sectors in directory LD D,0 LD E,A ; num_sectors POP AF LD HL,buffer LD B,0 CALL bios_disc_param LD B,E PUSH DE !read_loop PUSH BC ; read sector from disc XOR A LD (MOS_ERROR_CODE),A RST MOS_CALL:DFB MOS_DISC_READ ; increment sector LD A,(MOS_SECTOR_NUM) INC A LD (MOS_SECTOR_NUM),A ; store result LD A,(MOS_ERROR_CODE) OR A JR Z,!no_error RST MOS_CALL:DFB MOS_DISC_RESET ; reset sector buffer LD HL,(MOS_BUFADR_LO) PUSH HL POP DE INC DE LD BC,511 LD A,$E5 LD (HL),A LDIR !no_error ; change buffer addr LD A,(MOS_BUFADR_HI) INC A INC A LD (MOS_BUFADR_HI),A POP BC DJNZ !read_loop RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," - Sending DIR entries",' '+$80 POP HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL PUSH HL POP DE ; send all valid entries LD HL,buffer !loop LD A,(HL) CP $E5 JR Z,!no_send LD A,STATUS_OK CALL serial_put PUSH HL LD BC,16 CALL send_block POP HL LD B,0 !no_send LD C,32 ADD HL,BC DEC E JR NZ,!loop LD A,STATUS_EOF CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + DIR track ",'-'+$80 cmd_print_sent RST MOS_CALL:DFB MOS_POP_MESSAGE DFB " Sent ",13,10+$80 JP MAIN_LOOP ; *********************************************************** ; Get drive related info and send it to PC ; *********************************************************** cmd_get_drive RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + DRIVE config ",'%'+$80 LD A,(MOS_DRIVE_TYPES) CALL serial_put LD A,(MOS_DRIVE_TYPES) CALL show_binary JR cmd_print_sent ; *********************************************************** ; Get drive related info and send it to PC ; *********************************************************** cmd_get_dpb RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + DP",'B'+$80 CALL cpm_get_dpb LD BC,15 CALL send_block JR cmd_print_sent ; *********************************************************** ; Set CP/M disc and return status info ; *********************************************************** cmd_set_disc CALL serial_get PUSH AF ADD A,'0' LD (!mess_drive),A RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + Set DISC " !mess_drive DFB "0:",' '+$80 POP AF CALL cpm_select_disc JR Z,!failed LD A,STATUS_OK CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Ok",13,10+$80 JP MAIN_LOOP !failed LD A,STATUS_NO_FILE CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Failed",13,10+$80 JP MAIN_LOOP ; *********************************************************** ; Execute ; *********************************************************** EXEC_ADDR EQU $100-5 cmd_execute RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," - Receive cod",'e'+$80 ; send address of buffer LD A,buffer CALL serial_put ; check everything is hunky dory CALL serial_get CP A,STATUS_OK JR NZ,!fail ; get address of code CALL serial_get LD L,A CALL serial_get LD H,A ; get number of 256 byte blocks CALL serial_get LD B,A LD C,0 PUSH HL PUSH BC !get_data PUSH BC LD BC,256 CALL receive_block POP BC DJNZ !get_data ; get first 32 bytes of DMA buffer (CPM commands expect this to contain filenames) LD HL,CPM_ADDR_DMA LD BC,32 CALL receive_block RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + Executing ",13,10,10+$80 ; get relocation address CALL serial_get LD E,A CALL serial_get LD D,A ; setup execution code LD HL,EXEC_ADDR LD A,$ED ; LDIR (two bytes) LD (HL),A INC HL LD A,$B0 ; LDIR (two bytes) LD (HL),A INC HL LD A,$C3 ; JP LD (HL),A INC HL ; get execution address CALL serial_get LD (HL),A INC HL CALL serial_get LD (HL),A ; pop registers back POP BC POP HL ; HL=source address, DE=dest address, BC=size JP EXEC_ADDR !fail RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13," + Exec failed ",13,10+$80 JP MAIN_LOOP ; *********************************************************** ; Delete specified file ; *********************************************************** cmd_delete_file CALL receive_fcb CALL show_fcb ; delete file CALL cpm_delete_file JR Z,!failed LD A,STATUS_OK CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "deleted",13," +",13,10+$80 JP MAIN_LOOP !failed LD A,STATUS_EOF CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "not found",13," +",13,10+$80 JP MAIN_LOOP ; *********************************************************** ; Rename a file ; *********************************************************** cmd_rename_file CALL receive_fcb CALL show_fcb ; get 2nd FCB LD HL,fcb+16 PUSH HL CALL receive_fcb_in POP HL CALL show_fcb_in ; rename file CALL cpm_rename_file ; process status LD A,STATUS_EOF JR Z,!failed LD A,STATUS_OK !failed CALL serial_put RST MOS_CALL:DFB MOS_POP_MESSAGE DFB " +",13,10+$80 JP MAIN_LOOP ;######################################################################################################### ;--------------------------------------------------------------------------------------------------------- ; COMMUNICATION UTILS - These functions provide high level serial port support ;--------------------------------------------------------------------------------------------------------- ;######################################################################################################### ; *********************************************************** ; Get a FCB. file specifier only, from the PC. ; ; INPUT: none ; OUTPUT: none (FCB is setup for filing usage), registers are ; preserved ; *********************************************************** receive_fcb LD HL,fcb receive_fcb_in PUSH HL LD B,12 !loop CALL serial_get LD (HL),A INC HL DJNZ !loop XOR A LD B,SIZE_OF_FCB-12 !loop2 LD (HL),A INC HL DJNZ !loop2 ; change drive number from ASCII POP HL LD A,(HL) SUB A,'0'-1 LD (HL),A RET ; *********************************************************** ; Send the disc read/write status buffer to the PC. ; ; INPUT: none ; OUTPUT: none, DE is preserved (nothing else is) ; *********************************************************** send_status LD HL,sectors_status LD A,(sectors_per_rw) LD C,A LD B,0 ; fall through to "send_block" ; *********************************************************** ; Send a block of data to the PC. ; ; INPUT: HL=addr, BC=size ; OUTPUT: HL=addr+size, BC=size, DE is preserved ; *********************************************************** send_block PUSH DE ; check if all data in block is the same PUSH HL PUSH BC LD E,(HL) INC HL DEC BC !compare LD A,E CP (HL) JR NZ,!not_rep INC HL DEC BC LD A,B OR C JR NZ,!compare POP BC POP HL ; status is the same just send a REPEAT token and the first byte of the block LD A,STATUS_REPEAT CALL serial_put LD A,(HL) CALL serial_put ADD HL,BC POP DE RET ; its not all the same so send all the block !not_rep POP BC POP HL LD A,STATUS_OK CALL serial_put !resend PUSH HL PUSH BC LD E,0 !send_loop LD A,(HL) INC HL CALL serial_put ADD A,E LD E,A DEC BC LD A,B OR C JR NZ,!send_loop ; exchange checksums LD A,E CALL serial_put CALL serial_get ; if checksums dont match then resend the block CP E JR Z,!ok POP BC POP HL JR !resend !ok POP BC POP DE POP DE RET ; *********************************************************** ; Receive a block of data from the PC. ; ; INPUT: HL=addr, BC=size ; OUTPUT: HL=addr+size, BC=size, DE is preserved ; *********************************************************** receive_block PUSH DE CALL serial_get CP STATUS_REPEAT JR NZ,!reget ; block is a repeat so just get byte and store it CALL serial_get PUSH BC PUSH HL POP DE LD (HL),A INC DE DEC BC LDIR INC HL POP BC POP DE RET ; block is not a repeat so fetch it !reget PUSH HL PUSH BC LD E,0 !get_loop CALL serial_get LD (HL),A INC HL ADD A,E LD E,A DEC BC LD A,B OR C JR NZ,!get_loop ; exchange checksums LD A,E CALL serial_put CALL serial_get ; if checksums dont match then resend the block CP E JR Z,!ok POP BC POP HL JR !reget !ok POP BC POP DE POP DE RET ;######################################################################################################### ;--------------------------------------------------------------------------------------------------------- ; CP/M UTILS - These are all the CP/M calls made ;--------------------------------------------------------------------------------------------------------- ;######################################################################################################### ; flag to indicate whether a file is currently open or not (used during a reset) fcb_open DFB 0 ; *********************************************************** ; Send output to the console driver ; ; INPUT: A=byte to output ; OUTPUT: none, no registers preserved ; *********************************************************** cpm_console_out LD E,A LD C,CPM_FUNC_CONSOLE_OUT JP CPM_BDOS ; *********************************************************** ; Open an existing file for reading ; ; INPUT: none, FCB must be setup ; OUTPUT: Z set if error, no registers preserved ; *********************************************************** cpm_open_file LD DE,fcb LD C,CPM_FUNC_OPEN_FILE CALL CPM_BDOS_KEY INC A LD (fcb_open),A RET ; *********************************************************** ; Read data from file ; ; INPUT: none, FCB must be relevant to an "opened" file ; OUTPUT: Z set if EOF or other error error otherwise 128 ; bytes of data available in DMA buffer, no registers ; preserved ; *********************************************************** cpm_read_seq LD DE,fcb LD C,CPM_FUNC_READ_SEQ CALL CPM_BDOS_KEY OR A RET ; *********************************************************** ; Write data to a file ; ; INPUT: none, FCB must be relevant to a "created" file and ; 128 bytes of data should be in the DMA buffer ; OUTPUT: Z set if write successful otherwise error occurred ; (probably disk full), no registers preserved ; *********************************************************** cpm_write_seq LD DE,fcb LD C,CPM_FUNC_WRITE_SEQ CALL CPM_BDOS_KEY OR A RET ; *********************************************************** ; Close a file ; ; INPUT: none, FCB must be relevant to an "opened" or ; "created" file ; OUTPUT: Z set if error, no registers preserved ; *********************************************************** cpm_close_file LD A,(fcb_open) OR A RET Z XOR A LD (fcb_open),A LD DE,fcb LD C,CPM_FUNC_CLOSE_FILE CALL CPM_BDOS_KEY INC A RET ; *********************************************************** ; Delete a file ; ; INPUT: none, FCB must be setup ; OUTPUT: Z set if error, no registers preserved ; *********************************************************** cpm_delete_file LD DE,fcb LD C,CPM_FUNC_DELETE_FILE CALL CPM_BDOS_KEY INC A RET ; *********************************************************** ; Rename a file ; ; INPUT: none, FCB must be setup (FCB+16 is new name) ; OUTPUT: Z set if error, no registers preserved ; *********************************************************** cpm_rename_file LD DE,fcb LD C,CPM_FUNC_RENAME_FILE CALL CPM_BDOS_KEY INC A RET ; *********************************************************** ; Create a file ; ; INPUT: none, FCB must be setup ; OUTPUT: Z set if error, no registers preserved ; *********************************************************** cpm_create_file LD DE,fcb LD C,CPM_FUNC_CREATE_FILE CALL CPM_BDOS_KEY INC A LD (fcb_open),A RET ; *********************************************************** ; Get address of DPB block ; ; INPUT: none ; OUTPUT: HL is address of DPB, no registers preserved ; *********************************************************** cpm_get_dpb LD C,CPM_FUNC_GET_DPB JP CPM_BDOS_KEY ; *********************************************************** ; Select disc ; ; INPUT: A=disc (0-3) ; OUTPUT: Z set if error, no registers preserved ;;; H may be error code ; *********************************************************** cpm_select_disc LD E,A LD C,CPM_FUNC_SET_DISC CALL CPM_BDOS_KEY INC A RET ; *********************************************************** ; Set DMA buffer address ; ; INPUT: A=disc (0-3) ; OUTPUT: Z set if error, no registers preserved ;;; H may be error code ; *********************************************************** cpm_set_dma LD DE,CPM_ADDR_DMA LD C,CPM_FUNC_SET_DMA_ADDR JP CPM_BDOS ;######################################################################################################### ;--------------------------------------------------------------------------------------------------------- ; SERIAL PORT FUNCTIONS - These are the low level serial port access functions ;--------------------------------------------------------------------------------------------------------- ;######################################################################################################### ; timeout for any serial transfer TIMEOUT EQU $08 ; *********************************************************** ; Reset serial port ; ; INPUT: none ; OUTPUT: none, A is corrupted all other registers preserved ; *********************************************************** serial_reset CALL serial_RTS_on !loop IN A,($10) ; read any byte received IN A,($11) ; check if byte received BIT 1,A JR NZ,!loop CALL serial_RTS_off RET ; *********************************************************** ; Enable RTS line ; ; INPUT: none ; OUTPUT: none, all registers preserved ; *********************************************************** serial_RTS_on PUSH AF LD A,%00100111 OUT ($11),A POP AF RET ; *********************************************************** ; Disable RTS line ; ; INPUT: none ; OUTPUT: none, all registers preserved ; *********************************************************** serial_RTS_off PUSH AF LD A,%00000111 OUT ($11),A POP AF RET ; *********************************************************** ; Get a byte from the serial port (with TIMEOUT reset) ; ; INPUT: none ; OUTPUT: none, A=byte, all other registers preserved ; *********************************************************** serial_get CALL serial_RTS_on PUSH HL PUSH DE LD HL,0 LD E,TIMEOUT !loop IN A,($11) DEC L JR NZ,!dec_ok DEC H JR NZ,!dec_ok DEC E JR Z,serial_timeout !dec_ok BIT 1,A JR Z,!loop IN A,($10) POP DE POP HL CALL serial_RTS_off RET ; *********************************************************** ; Write a byte to the serial port (with TIMEOUT reset) ; ; INPUT: none ; OUTPUT: none, all registers preserved ; *********************************************************** serial_put PUSH AF PUSH HL PUSH DE LD HL,0 LD E,TIMEOUT !loop IN A,($11) DEC L JR NZ,!dec_ok DEC H JR NZ,!dec_ok DEC E JR Z,serial_timeout !dec_ok BIT 0,A JR Z,!loop POP DE POP HL POP AF OUT ($10),A RET ; *********************************************************** ; Serial TIMEOUT function ; ; INPUT: none ; OUTPUT: none, does not return! ; *********************************************************** serial_timeout RST MOS_CALL:DFB MOS_POP_MESSAGE DFB " - TIMEOUT",'!'+$80 cmd_reset RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13,10,"---- RESET ----",10,13+$80 CALL cpm_close_file JP RESTART_POINT ; *********************************************************** ; Get a byte from the serial port (no TIMEOUT) ; ; INPUT: none ; OUTPUT: none, A=byte, all other registers preserved ; *********************************************************** serial_get_raw CALL serial_RTS_on !loop IN A,($11) BIT 1,A JR Z,!loop IN A,($10) CALL serial_RTS_off RET ;######################################################################################################### ;--------------------------------------------------------------------------------------------------------- ; GENERAL UTILITY FUNCTIONS - Anything that provides additional support functionality ;--------------------------------------------------------------------------------------------------------- ;######################################################################################################### bios_disc_param LD (MOS_DRIVE_NUM),A LD (MOS_BUFADR_LO),HL LD (MOS_TRACK_NUM),BC RET bios_drive_show PUSH BC PUSH DE PUSH HL PUSH AF RST MOS_CALL:DFB MOS_POP_MESSAGE DFB 13, " -",' '+$80 POP AF OR A JR NZ,!write RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Read",' '+$80 JR !show !write RST MOS_CALL:DFB MOS_POP_MESSAGE DFB "Writ",'e'+$80 !show LD A,(MOS_DRIVE_NUM) ADD A,'0' LD (!mess_drive),A LD A,(MOS_TRACK_NUM) LD HL,!mess_track CALL store_decimal LD A,(MOS_SECTOR_NUM) LD HL,!mess_sector CALL store_decimal RST MOS_CALL:DFB MOS_POP_MESSAGE DFB " " !mess_drive DFB "0: Track " !mess_track DFB "00 Sector " !mess_sector DFB "00",' '+$80 POP HL POP DE POP BC RET store_decimal LD BC,10 !count SUB C INC B JR NC,!count ADD A,C ADD A,'0' ; store 1's INC HL LD (HL),A DEC HL LD A,B ADD A,'0'-1 ; store 10's LD (HL),A RET show_binary LD B,8 !loop RLCA PUSH AF PUSH BC AND 1 ADD '0' CALL cpm_console_out POP BC POP AF DJNZ !loop RET show_fcb LD HL,fcb show_fcb_in LD DE,!mess_drive LDI INC DE LD BC,8 LDIR LD B,3 !loop INC DE LD A,(HL) AND 127 LD (DE),A INC HL DJNZ !loop LD A,(!mess_drive) ADD A,'0'-1 LD (!mess_drive),A RST MOS_CALL:DFB MOS_POP_MESSAGE !mess DFB 13," - " !mess_drive DFB "?:????????.??? -",' '+$80 RET ;######################################################################################################### ;--------------------------------------------------------------------------------------------------------- ; WORKSPACE ;--------------------------------------------------------------------------------------------------------- ;######################################################################################################### INF "Assembled from $",ENTRY_POINT," to $",. MEMSAVE "Eintrans.bin",ENTRY_POINT,ENTRY_POINT+$800 ; Unitialised workspace... fcb DFS SIZE_OF_FCB num_tracks DFS 1 num_sectors DFS 1 sectors_per_rw DFS 1 sectors_status DFS 80 ; move to next page ORG (.+255)&$FF00 STACK DFS STACK_SIZE buffer ; END OF FILE