;=================================================================== ; MICRO RESOURCES CP/M -- FDOS III FILE TRANSFER PROGRAM ;=================================================================== ; ; ; THIS PROGRAM IS A UTILITY TO TRANSFER FILES FROM FDOS III ; SINGLE DENSITY DISKS TO CP/M DISKS OR TO TRANSFER A CP/M ; FILE TO AN FDOS III SINGLE DENSITY DISK. A PROVISION HAS ; ALSO BEEN INCLUDED TO ALLOW EXAMINATION THE DIRECTORY OF ; THE FDOS III DISKETTE. THE OPERATION OF THIS PROGRAM ASSUMES ; THAT A CP/M SYSTEM DISK IS PRESENT IN DRIVE A: AND THAT THE ; FDOS III DISK IS IN DRIVE B:. THE BIOS PRIMITIVES OF THE CP/M ; SYSTEM ARE ACCESSED DIRECTLY TO ALLOW READING AND WRITING ; OF THE SINGLE DENSITY FDOS III DISK WITH IT'S 10 TO 1 LOGICAL ; TO PHYSICAL SECTOR MAPPING. ; ; THIS PROGRAM DOES NOT PACK THE FILES OF THE FDOS III DISK ; WHEN CREATING NEW FILES UPON TRANSFER FROM A CP/M FILE. ; SUBSEQUENT PACKING MAY DONE UPON THE DESTINATION FDOS III ; SYSTEM. ; ; THE DIRECTORIES OF EITHER DISK WILL BE SCANNED FOR FILES ; OF SIMILAR NAMES BEFORE A TRANSFER IS ACTUALLY MADE. A PROMPT ; QUESTION WILL INDICATE WHEN THE FILE ALREADY EXISTS. IN THE ; CASE OF THE CP/M DISK THE INDICATED FILE MAY BE ERASED IF ; DESIRED. WITH THE FDOS III DISK A FILE WILL NOT BE DELETED ; AND THE NAME OF THE SOURCE FILE ON THE CP/M DISK WILL HAVE ; TO BE CHANGED TO A NAME NOT CURRENTLY ON THE FDOS III DISK. ; FILE NAMES OF FDOS FILES ARE A MAXIMUM OF 5 ASCII CHARACTERS ; IN LENGTH SO THE CP/M FILE TRANSFERRED TO THE FDOS III DISK ; WILL HAVE ITS NAME TRUNCATED TO THE FIRST FIVE CHARACTERS. ; THE FDOS FILE TYPE WILL ALWAYS BE SET TO 00 AS A USER TYPE ; DATA FILE. ; ; THIS PROGRAM BUFFERS SECTOR READS UP SIXTEEN IN LENGTH ; TO MAKE THE TRANSFER MORE EFFICIENT. ; ; ; ; ;***************************************************************** ; ;THIS SOFTWARE IS PROTECTED UNDER THE FOLLOWING COPYRIGHT ;AND MAY NOT BE REPRODUCED OR COPIED IN ANY FORM WITHOUT ;SPECIFIC PERMISSION FROM MICRO RESOURCES. ; ; ; COPYRIGHT (C) 1980 ; ; ; MICRO RESOURCES ; MICHAEL J. KARAS ; 2468 HANSEN CT. ; SIMI VALLEY, CA 93065 ; (805) 527-7922 ; ;ANY QUESTIONS ABOUT THIS PROGRAM OR ITS APPLICATION ;CAN BE DIRECTED TO THE ABOVE ADDRESS OR TELEPHONE NUMBER. ; ;********************************************************************** ; WBOOT EQU 00 ;CP/M WARM BOOT ENTRY ADDRESS ; ERRLIM EQU 10 ;MAX ALLOWABLE ERRORS ; ;DEFINE ASCII CHARACTERS USED ; LF EQU 10 ;LINEFEED CR EQU 13 ;CARRIAGE RETURN ; ; ;START OF EXECUTABLE CODE ; ORG 100H CALL START ;GO PRINT ID DB 'MICRO RESOURCES FILE TRANSFER UTILITY ' DB CR,LF,' CP/M <----> FDOS III' DB CR,LF,' VER 1.4 5/29/80' DB CR,LF,'$' ; START: POP D ;GET ID MESSAGE MVI C,PRINT CALL BDOS ;PRINT ID MESSAGE ; ;INIT PRIVATE STACK ; LXI H,0 ;HL=0 DAD SP ;HL=STACK FROM CP/M SHLD STACK ;..SAVE IT LXI SP,STACK ;SP=MY STACK ; ;INITIALIZE THE JMPS TO CP/M BIOS ; CALL INITADR ; ;SAVE PROGRAM OPTION ; CALL PROCOPT ; ;MOVE THE FILENAME FROM FCB 2 TO FCB 1 ; CALL MOVEFCB ; ;JMP TO APPROPRIATE FUNCTION ; LDA OPTION ;GET PROGRAM OPTION ; CPI 'R' ;READ FDOS FILE? JZ FDOSRD ; CPI 'W' ;WRITE FDOS FILE? JZ FDOSWR ; CPI 'D' ;LOOK AT FDOS III DIRECTORY JZ FDOSDIR ; CPI 'H' ;GO TO HELP FILE PRINTOUT? JZ HELP ; ;INVALID OPTION ; JMP BADOPT ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * FDOSDIR: LISTS FDOS DIRECTORY TO CONSOLE * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; ;THE DIRECTORY OF THE SINGLE DENSITY FDOS III ;DISK IN DRIVE B: IS LISTED TO THE CONSOLE IN ;A SINGLE COLUMN FORMAT. CONSOLE I/O IS DONE ;THROUGH CP/M SO THAT THE CTL-S AND CTL-P ;FUNCTIONS WILL WORK. THE LISTING ALSO STOPS ;AFTER EACH 16 ENTRIES HAVE BEEN TYPED ; FDOSDIR: CALL ILPRT ;PRINT THE DIRECTORY HEADER LABEL DB CR,LF,'FDOS III DISK DIRECTORY' DB CR,LF,CR,LF DB 'FILENAME TYPE TRK SEC LENGTH',CR,LF,CR,LF,0 ; MVI C,01H ;SELECT DISK DRIVE B: CALL SELDSK ;..THROUGH BIOS ACCESS MVI A,016 ;SET PRINT LOOP COUNT STA LISTCNT MVI A,00 ;SET SCAN FOR FIRST ENTRY JMP FDIR2 ;JUMP INTO LOOP FDIR1: MVI A,01 ;SET SCAN CODE FOR NEXT ENTRY FDIR2: CALL FDIRSC ;SCAN FOR NEXT DIRECTORY ENTRY ORA A ;SET FLAGES FOR RETURN CODE JNZ FDEREX ;GO EXIT FOR FULL DISK DIRECTORY LDA FDENT+5 ;GET ENTRY TYPE BYTE CPI 0FFH ;MUST BE AT END OF THE LIST JZ FDIREX CALL PRTDIR ;PRINT THIS ENTRY ; LDA LISTCNT ;GET LIST LINE COUNT DCR A ;DECREMENT IT STA LISTCNT ;STORE NEW COUNT BACK JNZ FDIR1 ;GO TO DO NEXT ENTRY ; CALL ILPRT ;GIVE THE GUY A CHANCE TO STOP A LONG DIRECTORY DB 1,CR,LF,0 ; MVI A,016 ;RESET PRINT LOOP COUNT STA LISTCNT JMP FDIR1 ;GO START ON 16 MORE ENTRIES ; FDIREX: CALL ILPRT ;PRINT END OF LIST MESSAGE DB CR,LF,CR,LF,'END OF FDOS III DISK DIRECTORY',CR,LF,0 FDIREX1: MVI C,00H ;RESTORE SELECT OF DRIVE A: CALL SELDSK ;DIRECT BIOS ACCESS JMP EXIT ;DONE WITH DIRECTORY ; FDEREX: CALL ILPRT ;PRINT DISK FULL MESSAGE DB CR,LF,'++FDOS III DISK DIRECTORY SPACE FULL++',CR,LF,0 ; JMP FDIREX1 ; ; ; ; ;SCAN FDOS III DIRECTORY ROUTINE ; ROUTINE ENTRY IS CODED TO ALLOW VARIABLE FUNCTIONS ; CODE IS PASSED IN THE A REGISTER ; CODES AS FOLLOWS: ; 00=OPEN SCAN FROM BEGINNING OF TRACK 0 SECTOR 4 ; 01=GET NEXT DIRECTORY ENTRY ; ; RETURN VALUE IS THE FIRST OR NEXT ENTRY AS SPECIFIED BY THE ; FUNCTION CODE AND IS PASSED IN BUFFER "FDENT" WHICH IS 11 ; BYTES LONG. ; ; THIS ROUTINE SCANS AND RETURNS ALL POSSIBLE ENTRIES ; AND WHEN END OF TRACK 0 IS ENCOUNTERED AN 0FFH CODE ; IS RETURNED IN THE ACCUMULATOR. ELSE A 00H CODE IS ; RETURNED. ; ; ; FDIRSC: ORA A ;SET FLAGS FOR FUNCTION CHECK JNZ NEXTENT ;FOR NON-ZERO CODE JUST GET NEXT ENTRY ; ;SETUP FOR BEGINNING OF SCAN MVI A,003H ;SETUP START SECTOR OF DIRECTORY-1 STA FDIRSEC MVI A,011 ;SET CURRENT SUBSCAN COUNT TO MAX STA DIRSECI MVI C,00H ;SET TRACK NUMBER TO ZERO CALL SETTRK ; NEXTENT: LDA DIRSECI ;GET SECTOR INDEX CPI 011 ;AT MAXIMUM ENTRY? JNZ SAMSEC ;NO STAY WITH THIS SECTOR LXI H,FDIRSEC INR M ;INCREMENT CURRENT SECTOR NUMBER MOV A,M ;GET THE SECTOR NUMBER CPI 01BH ;CHECK FOR THE LAST SECTOR JNZ NXTSEC ;GO AROUND THE END OF TRACK EXIT ; MVI A,0FFH ;SETUP EXIT FOR END OF DIRECTORY SPACE RET ; NXTSEC: MOV C,A CALL FRDSEC ;GO READ FDOS III SECTOR LXI H,IDBUF ;MOVE INPUT BUFFER LXI D,DIRBUF;..TO DIRECTORY BUFFER CALL MOVE128 MVI A,00 STA DIRSECI ;SET SECTOR INDEX TO MINIMUM ; SAMSEC: LXI H,DIRSECI MOV B,M ;GET THE INDEX INR M ;INCR THE SECTOR INDEX LXI H,DIRBUF;POINT TO THE FDOS III DIRECTORY BUFFER LXI D,011 ;LENGTH OF AN ENTRY MOV A,B CPI 00H ;CHECK FOR ILLEGAL ZERO LOOP COUNT JZ SAMSEC2 SAMSEC1: DAD D ;LOOP TO MAKE OFFSET INDEX DCR B JNZ SAMSEC1 SAMSEC2: LXI D,FDENT ;POINT TO ENTRY PASS BUFFER MVI B,011 ;SETUP LENGTH OF DIRECTORY ENTRY CALL MOVE ;GO MOVE A DIRECTORY ENTRY MVI A,00H ;SET NORMAL RETURN FLAG RET ; ; ; ; ;DIRECTORY SCAN POINTER PARAMETERS ; ; FDIRSEC DB 00 ;CURRENT DIRECTORY SECTOR NUMBER DIRSECI DB 00 ;INDEX OF SCAN INTO CURRENT DIRECTORY SECTOR DIRBUF DS 128 ;128 BYTE DIRECTORY ENTRY BUFFER LISTCNT DB 00 ;DIRECTORY LIST ENTRY COUNT ; ; ; ;PRINT DIRECTORY ENTRY SUBROUTINE ; ; PRTDIR: LXI H,FDENT ;POINT TO DIRECTORY ENTRY BUFFER MVI A,'B' CALL CTYPE ;PRINT OUT DRIVE DESIGNATOR MVI A,':' CALL CTYPE MVI B,05 ;FILE NAME CHARACTER COUNT NAMLP: MOV A,M ;GET NAME CHARACTER CALL CTYPE INX H ;INCREMENT BUFFER POINTER DCR B JNZ NAMLP ;GO FOR NEXT NAME CHAR ; CALL SP4 ;FOUR SPACES MOV A,M ;GET TYPE BYTE CALL HEXO ;SHOW IT INX H ;INCREMENT THE BUFFER POINTER ; CALL SP3 ;THREE SPACES MOV A,M ;GET START TRACK ADDRESS CALL HEXO ;SHOW IT INX H ;INCR THE BUFFER POINTER ; CALL SP2 ;TWO SPACES MOV A,M ;GET START SECTOR NUMBER CALL HEXO ;SHOW IT INX H ;INCR THE BUFFER POINTER ; CALL SP2 ;FINALLY TWO LAST SPACES PUSH D MOV D,M ;GET MSB OF LENGTH INX H MOV E,M ;GET LSB OF LENGTH DCX D ;DECREMENT LENGTH FOR CRAZY FDOS MOV A,D ;PRINT MSB OF ADJ LENGTH CALL HEXO MOV A,E ;PRINT LSB OF ADJ LENGTH CALL HEXO POP D ; CALL CRLF ;GET READY FOR NEXT LINE RET ; ; ;CONSOLE SPACE PRINTING ROUTINE ; SP5: MVI A,' ' ;5 SPACES CALL CTYPE SP4: MVI A,' ' ;4 SPACES CALL CTYPE SP3: MVI A,' ' ;3 SPACES CALL CTYPE SP2: MVI A,' ' ;2 SPACES CALL CTYPE SP1: MVI A,' ' ;1 SPACE CALL CTYPE RET ; ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * FDOSWR: COPIES FILE TO FDOS * * * * * * * * * * * * * * * * * * * * * * * * ; ;THE CP/M FILE SPECIFIED IN THE COMMAND ;IS TRANSFERRED TO THE FDOS III DISK IN DRIVE B: ; FDOSWR: CALL OPENFIL ;OPEN THE FILE MVI C,01 ;SELECT DRIVE B: CALL SELDSK MVI A,00H ;SET FDOS FILE EXIST FLAG FALSE STA FEFLG MVI A,00H ;SETUP FOR DIRECTORY SCAN JMP SCAN2 ;JUMP INTO LOOP SCAN1: MVI A,01H ;SET SCAN CODE FOR NEXT ENTRY SCAN2: CALL FDIRSC ;SCAN FOR NEXT DIRECTORY ENTRY ORA A ;SET FLAGS FOR RETURN CODE JNZ FDIRFUL ;EXIT FOR FULL DIRECTORY MVI B,05 ;SETUP COMPARE OF FILE NAMES LXI D,FCB+1 ;..FOR 5 CHAR FROM CP/M FCB LXI H,FDENT ;..TO FDOS III DIRECTORY ENTRY CALL COMPARE ;GO DO THE COMPARE ORA A ;CHECK RETURN FLAG JZ FNOMAT ;IF ZERO SKIP FLAG SET MVI A,0FFH ;SET FILE EXISTS FLAG STA FEFLG FNOMAT: LDA FDENT+5 ;GET ENTRY TYPE BYTE CPI 0FFH ;ARE WE AT END OF LIST? JNZ SCAN1 ;IF NOT AT END THEN GO GET NEXT ENTRY ; LDA FEFLG ;GET FLAG TO SEE IF FILE EXISTED ORA A JNZ FEXEX ;GO EXIT WITH FILE EXISTS MESSAGE MVI B,11 ;MOVE END ENTRY INTO THE END HOLDING AREA LXI H,FDENT LXI D,ENDENT CALL MOVE MVI B,05 ;MOVE FILE NAME INTO FDOS DIRECTORY ENTRY LXI H,FCB+1 LXI D,FDENT CALL MOVE MVI A,00 ;SET THE NEW FILE TYPE TO ZERO AS USER DATA STA FDENT+5 LXI H,0000 ;SET INITIAL FILE LENGTH TO ZERO SHLD FDENT+8 SENDLP: CALL RDSECT ;READ A SECTOR JC UPDATD ;UPDATE FDOS III DIRECTORY IF DONE LXI H,080H ;MOVE SECTOR FROM CPM AREA LXI D,ODBUF CALL MOVE128 MVI C,01 ;SELECT DISK DRIVE B: CALL SELDSK LDA ENDENT+6 MOV C,A ;GET AND SET TRACK NUMBER CALL SETTRK LDA ENDENT+7 MOV C,A ;GET SECTOR AND WRITE IT ON B: CALL FWRSEC ; LDA ENDENT+7 ;INCREMENT SECTOR NUMBER INR A STA ENDENT+7 CPI 01BH ;CHECK IF TRACK FULL JC SAMTRK ;NO, THEN STAY WITH THIS ONE MVI A,01H ;SET SECTOR BACK IF NEW TRACK STA ENDENT+7 LDA ENDENT+6 ;INCREMENT TRACK NUMBER INR A STA ENDENT+6 CPI 04DH ;CHECK TRACK NUMBER FOR FULL DISK JNC DSKFUL ; SAMTRK: LHLD FDENT+8 ;GET CURRENT WRITTEN FILE SIZE XCHG ;CHANGE SIGNIFICANT ORDER MOV L,D MOV H,E INX H ;INCREMENT BLOCK COUNT XCHG ;CHANGE ORDER BACK MOV L,D MOV H,E SHLD FDENT+8 ;SAVE NEW BLOCK COUNT JMP SENDLP ;GO DO NEXT SECTOR ; ;FILE WRITTEN, NOW UPDATE THE DIRECTORY ; UPDATD: XRA A ;INITIALIZE TWO SECTOR UPDATE FLAG STA U2SEC ; LHLD FDENT+8 ;GET CURRENT WRITTEN FILE SIZE XCHG ;CHANGE SIGNIFICANT ORDER MOV L,D MOV H,E INX H ;INCREMENT BLOCK COUNT ;ONE LAST TIME FOR COMPATABILITY ;WITH CRAZY FDOS XCHG ;CHANGE ORDER BACK MOV L,D MOV H,E SHLD FDENT+8 ;SAVE NEW BLOCK COUNT ; LXI H,DIRBUF ;MOVE DIRECTORY SECTOR TO OUTPUT BUFFER LXI D,ODBUF CALL MOVE128 LDA DIRSECI ;GET DIRECTORY SECTOR INDEX LXI H,ODBUF-11 LXI D,11 ;MAKE INSERT POINTER FOR NEW ENTRY UPDAT: DAD D DCR A JNZ UPDAT ; XCHG ;PUT INSERT POINTER IN DE LXI H,FDENT ;POINT TO NEW DIRECTORY ENTRY MVI B,11 ;LENGTH OF DIRECTORY ENTRY CALL MOVE ;MOVE INTO OUTPUT BUFFER LDA DIRSECI ;SEE IF NEW ENTRY IS LAST IN SECTOR CPI 011 JNZ ONESEC ;JUMP TO PUT END ENTRY IN THIS SECTOR ; MVI A,0FFH ;SET U2SEC FLAG STA U2SEC JMP WDIRSEC ;GO WRITE CURRENT SECTOR ; ONESEC: LXI H,ENDENT ;PUT END ENTRY INTO THIS SECTOR MVI B,11 ;ENTRY LENGTH-- DE OK FROM PREVIOUS MOVE CALL MOVE ;PUT IT IN ; WDIRSEC: MVI C,01 ;SELECT DRIVE B: CALL SELDSK MVI C,00 ;GO TO TRACK OF DIRECTORY CALL SETTRK LDA FDIRSEC ;GET THE DIRECTORY SECTOR NUMBER MOV C,A CALL FWRSEC ;GO WRITE THE SECTOR OF DIRECTORY LDA U2SEC ;CHECK IF WE SHOULD UPDATE TWO SECTORS ORA A JNZ GETSEC ;IF SO GO PREPARE FOR IT ; JMP DONE ;ALL DONE ; GETSEC: XRA A STA U2SEC ;RESET UPDATE TWO SECTORS FLAG LDA FDIRSEC ;GET CURRENT DIRECTORY SECTOR NUMBER INR A STA FDIRSEC ;STORE THIS NEW ONE AWAY CPI 01BH ;SEE IF DIRECTORY FULL HERE JZ UDFULL ;GO PRINT EXIT MESSAGE MOV C,A CALL FRDSEC ;GO READ NEXT SECTOR LXI H,IDBUF ;MOVE INPUT BUFFER TO OUTPUT BUFFER LXI D,ODBUF CALL MOVE128 MVI B,11 ;PUT IN ENDING ENTRY IN FIRST SLOT OF SECTOR LXI H,ENDENT LXI D,ODBUF CALL MOVE JMP WDIRSEC ;GO WRITE THE SECOND UPDATED SECTOR ; ; ;EXIT POINT FROM WRITE IF FDOS III DIRECTORY IS FULL UPON UPDATE ; UDFULL: CALL ILPRT ;PRINT DIRECTORY FULL MESSAGE DB CR,LF,'++FDOS III DIRECTORY FULL UPON UPDATE++' DB CR,LF,'++TRANSFERRED FILE EXISTS ON DISK++',CR,LF,0 JMP EXIT ; ; ;EXIT POINT FROM WRITE IF FDOS III DIRECTORY IS FULL ; FDIRFUL: CALL ILPRT ;PRINT DIRECTORY FULL MESSAGE DB CR,LF,'++FDOS III DIRECTORY MUST BE FULL++',CR,LF,0 JMP EXIT ; ; ;EXIT POINT FROM WRITE IF FDOS III DISK GETS FULL ; DSKFUL: CALL ILPRT ;PRINT DISK FULL MESSAGE DB CR,LF,'++FILE TOO BIG - FDOS III DISK FULL++' DB CR,LF,'++DIRECTORY NOT UPDATED WITH NEW FILE++',CR,LF,0 JMP EXIT ; ;EXIT POINT FROM WRITE IF FDOS III FILE ALREADY EXISTS ; FEXEX: CALL ILPRT DB CR,LF,'++FDOS III FILE ALREADY EXISTS++' DB CR,LF,'++CHANGE NAME OF SOURCE FILE ON CP/M++',CR,LF,0 JMP EXIT ; ; ; ; ;PARAMETER STORAGE AREA FOR FDOS WRITE ROUTINE ; U2SEC DB 00 ;USED TO SEE IF TWO SECTORS S/B SET IN DIRECTORY FEFLG DB 00 ;FDOS III FILE EXISTS IF SET ENDENT DS 11 ;STORAGE FOR END ENTRY OF DIRECTORY ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * FDOSRD: COPY FILE FROM FDOS * * * * * * * * * * * * * * * * * * * * * * * * ; ;FETCHES AN FDOS III FILE AND THEN WRITES ;IT TO A CP/M FILE ON DRIVE A: ; FDOSRD: CALL ERASFIL ;ERASE THE CP/M FILE CALL MAKEFIL ;..THEN MAKE NEW MVI C,01H ;SELECT DISK DRIVE B: CALL SELDSK ;..THROUGH BIOS ACCESS MVI A,00 ;SET SCAN FOR FIRST ENTRY JMP FIND2 ;JUMP INTO LOOP FIND1: MVI A,01 ;SET SCAN CODE FOR NEXT ENTRY FIND2: CALL FDIRSC ;SCAN FOR NEXT DIRECTORY ENTRY ORA A ;SET FLAGES FOR RETURN CODE JNZ FDNFEX ;GO EXIT FOR NOT FOUND FDOS FILE LDA FDENT+5 ;GET ENTRY TYPE BYTE CPI 0FFH ;MUST BE AT END OF THE LIST JZ FDNFEX ;GO EXIT FOR NOT FOUND FDOS FILE MVI B,05H ;SETUP FOR COMPARE FILE NAMES LXI D,FCB+1 ;..FOR 5 CHAR FROM FCB TO LXI H,FDENT ;..FDOS III DIRECTORY ENTRY CALL COMPARE ;GO COMPARE ORA A ;CHECK THE RETURN FLAG JZ FIND1 ;NO NAME MATCH IF ZERO ; ;ADJUST BLOCK COUNT FOR REAL WORLD PEOPLE ; LHLD FDENT+8 ;GET REMAINING FILE SIZE XCHG ;CHANGE SIGNIFICANT ORDER MOV L,D MOV H,E DCX H ;DECREMENT BLOCK COUNT ;THIS ADJUSTS FILE SIZE FROM ;CRAZY FDOS THAT SAVES LENGTH+1 XCHG ;CHANGE ORDER BACK MOV L,D MOV H,E SHLD FDENT+8 ;PUT NEW BLOCK COUNT BACK ; ;FOUND FILE ON FDOS III DISK ; RCVLP: MVI C,01 ;SELECT DRIVE B: FOR FDOS CALL SELDSK LDA FDENT+6 ;GET AND SET TRACK NUMBER MOV C,A ;GO DIRECT TO BDOS CALL SETTRK LDA FDENT+7 ;GET AND SET SECTOR NUMBER MOV C,A ;SET AND READ SECTOR CALL FRDSEC ; LXI H,IDBUF ;MOVE SECTOR TO CP/M AREA LXI D,080H CALL MOVE128 CALL WRSECT ;MOVE DATA TO CP/M QUEUE ; LDA FDENT+7 ;INCREMENT SECTOR NUMBER INR A STA FDENT+7 ;SAVE INCREMENTED SECTOR CPI 01BH ;CHECK IF TRACK DONE JC TRKOK MVI A,01H ;SET SECTOR BACK FOR NEW TRACK STA FDENT+7 ;SAVE NEW SECTOR NUMBER LDA FDENT+6 ;INCREMENT TRACK NUMBER INR A STA FDENT+6 TRKOK: LHLD FDENT+8 ;GET REMAINING FILE SIZE XCHG ;CHANGE SIGNIFICANT ORDER MOV L,D MOV H,E DCX H ;DECREMENT BLOCK COUNT XCHG ;CHANGE ORDER BACK MOV L,D MOV H,E SHLD FDENT+8 ;PUT NEW BLOCK COUNT BACK MOV A,L ;CHECK FOR DONE ORA H JZ RCVEOF ;EXIT FOR END OF FDOS FILE ; JMP RCVLP ;GO FOR NEXT SECTOR ; ;GOT EOF ON SECTOR - FLUSH BUFFERS, END ; RCVEOF: CALL WRBLOCK ;WRITE THE LAST BLOCK CALL CLOSFIL ;CLOSE THE FILE JMP DONE ;GO PRINT END OF TRANSFER MESSAGE ; ; ; FDNFEX: CALL ILPRT ;PRINT FDOS III FILE NOT FOUND DB CR,LF,'++FDOS FILE NOT FOUND++',CR,LF,0 JMP EXIT ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * SUBROUTINES * * * * * * * * * * * * * * * * * * * * * * * * ; ; ; ;----> ERASFIL: ERASE THE INCOMING FILE. ; ;IF IT EXISTS, ASK IF IT MAY BE ERASED. ; ERASFIL: LXI D,FCB ;POINT TO CTL BLOCK MVI C,SRCHF ;SEE IF IT.. CALL BDOS ;..EXISTS INR A ;FOUND? RZ ;..NO, RETURN CALL ILPRT ;PRINT: DB '++CP/M FILE EXISTS, TYPE Y TO ERASE: ',0 CALL KEYIN ;GET A CHARACTER FROM CONSOLE ANI 5FH ;MAKE UPPER CASE CPI 'Y' ;WANT ERASED? JNZ EXIT ;QUIT IF NOT ERASE CALL CRLF ;BACK TO START OF LINE ; ;ERASE OLD FILE ; LXI D,FCB ;POINT TO FCB MVI C,ERASE ;GET BDOS FNC CALL BDOS ;DO THE ERASE RET ;FROM "ERASFIL" ; ;----> MAKEFIL: MAKES THE FILE TO BE RECEIVED ; MAKEFIL: LXI D,FCB ;POINT TO FCB MVI C,MAKE ;GET BDOS FNC CALL BDOS ;TO THE MAKE INR A ;FF=BAD? RNZ ;OPEN OK ;DIRECTORY FULL - CAN'T MAKE FILE CALL ERXIT DB '++ERROR - CANNOT MAKE FILE',CR,LF DB '++DIRECTORY MUST BE FULL',CR,LF,'$' ; ;----> OPENFIL: OPENS THE FILE TO BE SENT ; OPENFIL: LXI D,FCB ;POINT TO FILE MVI C,OPEN ;GET FUNCTION CALL BDOS ;OPEN IT INR A ;OPEN OK? RNZ ;FILE OPENED OK CALL ERXIT ;..NO, ABORT DB 'CANNOT OPEN CP/M FILE$' ; ; ;----> CLOSFIL: CLOSES THE RECEIVED FILE ; CLOSFIL: LXI D,FCB ;POINT TO FILE MVI C,CLOSE ;GET FUNCTION CALL BDOS ;CLOSE IT INR A ;CLOSE OK? RNZ ;..YES, RETURN CALL ERXIT ;..NO, ABORT DB 'CANNOT CLOSE CP/M FILE$' ; ;----> RDSECT: READS A SECTOR ; ;FOR SPEED, THIS ROUTINE BUFFERS UP 16 ;SECTORS AT A TIME. ; RDSECT: LDA SECINBF ;GET # SECT IN BUFF. DCR A ;DECREMENT.. STA SECINBF ;..IT JM RDBLOCK ;EXHAUSTED? NEED MORE. LHLD SECPTR ;GET POINTER LXI D,80H ;TO DATA CALL MOVE128 ;MOVE TO BUFFER SHLD SECPTR ;SAVE BUFFER POINTER STC CMC ;CLEAR CARRY SO EOF NOT INDICATED ;ON NORMAL RETURN RET ;FROM "READSEC" ; ;BUFFER IS EMPTY - READ IN ANOTHER BLOCK OF 16 ; RDBLOCK: LDA EOFLG ;GET EOF FLAG CPI 1 ;IS IT SET? STC ;TO SHOW EOF RZ ;GOT EOF MVI C,00H ;SELECT DRIVE A: CALL SELDSK MVI C,0 ;SECTORS IN BLOCK LXI D,DBUF ;TO DISK BUFFER RDSECLP: PUSH B PUSH D MVI C,STDMA ;SET DMA.. CALL BDOS ;..ADDR LXI D,FCB MVI C,READ CALL BDOS POP D POP B ORA A ;READ OK? JZ RDSECOK ;YES DCR A ;EOF? JZ REOF ;GOT EOF ; ;READ ERROR ; CALL ERXIT DB '++CP/M FILE READ ERROR$' ; RDSECOK: LXI H,80H DAD D ;TO NEXT BUFF XCHG ;BUFF TO DE INR C ;MORE SECTORS? MOV A,C ;GET COUNT CPI 16 ;DONE? JZ RDBFULL ;..YES, BUF IS FULL JMP RDSECLP ;READ MORE ; REOF: MVI A,1 STA EOFLG ;SET EOF FLAG MOV A,C ; ;BUFFER IS FULL, OR GOT EOF ; RDBFULL: STA SECINBF ;STORE SECTOR COUNT LXI H,DBUF ;INIT BUFFER.. SHLD SECPTR ;..POINTER LXI D,80H ;RESET.. MVI C,STDMA ;..DMA.. CALL BDOS ;..ADDR JMP RDSECT ;PASS SECT TO CALLER ; ;----> WRSECT: WRITE A SECTOR ; ;WRITES THE SECTOR INTO A BUFFER. WHEN 16 ;HAVE BEEN WRITTEN, WRITES THE BLOCK TO DISK. ; ;ENTRY POINT "WRBLOCK" FLUSHES THE BUFFER AT EOF. ; WRSECT: LHLD SECPTR ;GET BUFF ADDR XCHG ;TO DE FOR MOVE LXI H,80H ;FROM HERE CALL MOVE128 ;MOVE TO BUFFER XCHG ;SAVE NEXT.. SHLD SECPTR ;..BLOCK POINTER LDA SECINBF ;BUMP THE.. INR A ;..SECTOR #.. STA SECINBF ;..IN THE BUFF CPI 16 ;HAVE WE 16? RNZ ;NO, RETURN ; ;----> WRBLOCK: WRITES A BLOCK TO DISK ; WRBLOCK: LDA SECINBF ;# SECT IN BUFFER ORA A ;0 MEANS END OF FILE RZ ;NONE TO WRITE PUSH PSW ;SAVE SECINBUF MVI C,00H ;SELECT DISK DRIVE A: CALL SELDSK POP PSW ;GET SECINBUF BACK MOV C,A ;SAVE COUNT LXI D,DBUF ;POINT TO DISK BUFF DKWRLP: PUSH H PUSH D PUSH B MVI C,STDMA ;SET DMA CALL BDOS ;TO BUFFER LXI D,FCB ;THEN WRITE MVI C,WRITE ;..THE.. CALL BDOS ;..BLOCK POP B POP D POP H ORA A JNZ WRERR ;OOPS, ERROR LXI H,80H ;LENGTH OF 1 SECT DAD D ;HL= NEXT BUFF XCHG ;TO DE FOR SETDMA DCR C ;MORE SECTORS? JNZ DKWRLP ;..YES, LOOP XRA A ;GET A ZERO STA SECINBF ;RESET # OF SECTORS LXI H,DBUF ;RESET BUFFER.. SHLD SECPTR ;..POINTER RET ; WRERR: CALL ERXIT ;EXIT W/MSG: DB '++ERROR WRITING CP/M FILE',CR,LF,'$' ; ; ;----> FRDSEC: READS A GIVEN SECTOR ACCORDING ; TO FDOS III CONVENTION. REGISTER ; C CONTAINS THE LOGICAL SECTOR NUMBER. ; FRDSEC: MVI B,00H ;SET THE TABLE INDEX RIGHT PUSH B PUSH H PUSH D LXI H,TBL-1 ;MAKE POINTER TO SECTOR TRANSLATION TABLE DAD B ;MAKE POINTER INTO TABLE MOV C,M ;GET PHYSICAL SECTOR CALL SETSEC ;SET SECTOR NUMBER PHYSICAL AT CONTROLLER LXI B,IDBUF ;SETUP THE POINTER TO THE FDOS INPUT BUFFER CALL SETDMA ;ACCESS BIOS DIRECT CALL RDSEC ;READ THE SECTOR INTO BUFFER POP D POP H POP B ORA A ;LOOK TO SEE IF READ ERROR RZ ;GO BACK IF NO ERRORS DETECTED ; ;FDOS DISK READ ERROR ; CALL ERXIT DB '++FDOS III DISK READ ERROR$' ; ; ;----> FWRSEC: WRITES A GIVEN SECTOR ACCORDING ; TO FDOS III CONVENTION. REGISTER C ; CONTAINS THE LOGICAL SECTOR NUMBER. ; ; FWRSEC: MVI B,00H ;SET THE TABLE INDEX RIGHT PUSH B PUSH H PUSH D LXI H,TBL-1 ;MAKE POINTER TO SECTOR TRANSLATION TABLE DAD B ;MAKE POINTER INTO TABLE MOV C,M ;GET PHYSICAL SECTOR CALL SETSEC ;SET SECTOR NUMBER PHYSICAL AT CONTROLLER LXI B,ODBUF ;SETUP THE POINTER TO THE FDOS OUTPUT BUFFER CALL SETDMA ;ACCESS BIOS DIRECT CALL WRTSEC ;WRITE THE SECTOR INTO BUFFER POP D POP H POP B ORA A ;LOOK TO SEE IF WRITE ERROR RZ ;GO BACK IF NO ERRORS DETECTED ; ;FDOS DISK WRITE ERROR ; CALL ERXIT DB '++FDOS III DISK WRITE ERROR$' ; ; ; ; ;----> INITADR: INIT'S CP/M BDOS ADDRESSES ; ;THIS ROUTINE FILLS IN THE ADDRESSES OF VARIOUS ;JUMP VECTOR ENTRY POINTS SO THAT CP/M BDOS ;IS BYPASSED WHILE ACCESSING THE FDOS III DISK ;IN DRIVE B: SO THAT THE MODIFIED LOGICAL ;SECTORING MAY BE USED. ; INITADR: LHLD 1 ;GET WARM BOOT ADDR LXI D,015H ;OFFSET TO HOME VECTOR DAD D ;TO HOME DISK ROUTINE SHLD HOME+1 ;SET INTERNAL HOME VECTOR LXI D,003H ;OFFSET TO NEXT VECTOR DAD D ;TO SELECT DISK ROUTINE SHLD SELDSK+1;SET INTERNAL SELDSK VECTOR DAD D ;TO SET TRACK ROUTINE SHLD SETTRK+1;SET INTERNAL SETTRK VECTOR DAD D ;TO SET SECTOR ROUTINE SHLD SETSEC+1;SET INTERNAL SETSEC VECTOR DAD D ;TO SET DMA ADDRESS ROUTINE SHLD SETDMA+1;SET INTERNAL SETDMA VECTOR DAD D ;TO READ SECTOR ROUTINE SHLD RDSEC+1 ;SET INTERNAL READ VECTOR DAD D ;TO WRITE SECTOR ROUTINE SHLD WRTSEC+1;SET INTERNAL WRITE VECTOR ; RET ; ; ;----> ENTRY POINTS FOR BIOS DISK ACCESS PRIMATIVES-ADDRESSES SETUP AT INIT ; HOME: JMP $-$ ;HOME DISK INTERNAL VECTOR SELDSK: JMP $-$ ;SELECT DISK INTERNAL VECTOR SETTRK: JMP $-$ ;SET TRACK INTERNAL VECTOR SETSEC: JMP $-$ ;SET SECTOR INTERNAL VECTOR SETDMA: JMP $-$ ;SET DMA ADDRESS INTERNAL VECTOR RDSEC: JMP $-$ ;READ SECTOR INTERNAL VECTOR WRTSEC: JMP $-$ ;WRITE SECTOR INTERNAL VECTOR ; ; ; ;----> PROCOPT: PROCESS COMMAND OPTIONS ; ;SAVES THE PROGRAM OPTION IN 'OPTION'; ; PROCOPT: LXI D,FCB+1 ;TO PROGRAM OPT. LDAX D ;GET OPTION STA OPTION ;SAVE IT RET ;FROM 'PROCOPT' ; ;DONE - CLOSE UP SHOP ; DONE: CALL ILPRT DB CR,LF,'TRANSFER COMPLETE' DB CR,LF,0 ; JMP EXIT ;DONE, GO BACK ; ; ;ROUTINE MOVES THE FILENAME FROM THE SECOND FCB ;TO THE FIRST ; MOVEFCB: LXI H,FCB+16 ;FROM LXI D,FCB ;TO MVI B,16 ;LEN CALL MOVE ;DO THE MOVE XRA A ;GET 0 STA FCBSNO ;ZERO SECTOR # STA FCB ;..AND DRIVE DESIGNATOR STA FCBEXT ;..AND EXTENT RET ; ; ;----> KEYIN: GETS A KEY CODE IN FROM CONSOLE ; KEYIN: PUSH B ;SAVE.. PUSH D ;..ALL.. PUSH H ;..REGS MVI C,RDCON ;GET CONSOLE CHARACTER FUNCTION CODE CALL BDOS ;GET CHARACTER MOV A,E POP H ;RESTORE.. POP D ;..ALL.. POP B ;..REGS RET ; ; ;----> CTYPE: TYPES VIA CP/M SO TABS ARE EXPANDED ; CTYPE: PUSH B ;SAVE.. PUSH D ;..ALL.. PUSH H ;..REGS MOV E,A ;CHAR TO E MVI C,WRCON ;GET BDOS FNC CALL BDOS ;PRIN THE CHR POP H ;RESTORE.. POP D ;..ALL.. POP B ;..REGS RET ;FROM "CTYPE" ; CRLF: MVI A,CR CALL CTYPE MVI A,LF CALL CTYPE RET ; ; ;HEX OUTPUT ; HEXO: PUSH PSW ;SAVE FOR RIGHT DIGIT RAR ;RIGHT.. RAR ;..JUSTIFY.. RAR ;..LEFT.. RAR ;..DIGIT.. CALL NIBBL ;PRINT LEFT DIGIT POP PSW ;RESTORE RIGHT CALL NIBBL ;PRINT RIGHT DIGIT RET ; ; NIBBL: ANI 0FH ;ISOLATE DIGIT CPI 10 ;IS IS <10? JC ISNUM ;YES, NOT ALPHA ADI 7 ;ADD ALPHA BIAS ISNUM: ADI '0' ;MAKE PRINTABLE CALL CTYPE ;..THEN TYPE IT RET ; ; ;----> ILPRT: INLINE PRINT OF MSG ; ;THE CALL TO ILPRT IS FOLLOWED BY A MESSAGE, ;BINARY 0 AS THE END. BINARY 1 MAY BE USED TO ;PAUSE (MESSAGE 'PRESS RETURN TO CONTINUE') ; ILPRT: XTHL ;SAVE HL, GET HL=MSG ILPLP: MOV A,M ;GET CHAR ORA A ;END OF MSG? JZ ILPRET ;..YES, RETURN CPI 1 ;PAUSE? JZ ILPAUSE ;..YES CALL CTYPE ;TYPE THE CHARACTER OF MESSAGE ILPNEXT: INX H ;TO NEXT CHAR JMP ILPLP ;LOOP ; ;PAUSE WHILE TYPING HELP SO INFO DOESN'T ; SCROLL OFF OF VIDEO SCREENS ; ILPAUSE: CALL ILPRT ;PRINT: DB CR,LF,'PRESS RETURN TO CONTINUE OR ^C TO EXIT' DB CR,LF,0 CALL KEYIN ;GET ANY CHAR CPI 'C'-40H ;REBOOT? JZ EXIT ;YES. JMP ILPNEXT ;LOOP ; ILPRET: XTHL ;RESTORE HL RET ; & RETURN ADDR PAST MESSAGE ; ;----> PRTMSG: PRINTS MSG POINTED TO BY (DE) ; ;A '$' IS THE ENDING DELIMITER FOR THE PRINT. ;NO REGISTERS SAVED. ; PRTMSG: MVI C,PRINT ;GET BDOS FNC JMP BDOS ;PRINT MESSAGE, RETURN ; ;----> ERXIT: EXIT PRINTING MSG FOLLOWING CALL ; ERXIT: POP D ;GET MESSAGE CALL PRTMSG ;PRINT IT ; EXIT: MVI C,00H ;SET SELECTED UNIT BACK TO A: CALL SELDSK LXI D,080H ;RESET DEFAULT DMA ADDRESS FOR EXIT MVI C,STDMA CALL BDOS LHLD STACK ;GET ORIGINAL STACK SPHL ;RESTORE IT JMP WBOOT ;GO DO A WARM BOOT OF CP/M SO THIS ;THING WILL WORK IN A SUBMIT FILE ; ;MOVE 128 CHARACTERS ; MOVE128: MVI B,128 ;SET MOVE COUNT ; ;MOVE FROM (HL) TO (DE) LENGTH IN (B) ; MOVE: MOV A,M ;GET A CHAR STAX D ;STORE IT INX H ;TO NEXT "FROM" INX D ;TO NEXT "TO" DCR B ;MORE? JNZ MOVE ;..YES, LOOP RET ;..NO, RETURN ; ; ;COMPARE FROM (HL) TO (DE) FOR (B) BYTES ;RETURN WITH A REGISTER: ; =00 IF NO COMPARE ; =FF IF VALID COMPARE ; COMPARE: LDAX D ;GET A CHAR CMP M ;CHECK AGAINST OTHER JNZ COMFAL ;GO EXIT FOR FAIL INX H ;INCREMENT COMPARE POINTERS INX D DCR B ;DECREMENT CHAR COUNT JNZ COMPARE ;MORE? MVI A,0FFH ;EXIT FOR GOOD COMPARE RET COMFAL: XRA A ;EXIT FOR NON COMPARE RET ; ; ; ---------------- ; ;PROGRAM DATA AREA SPACE ALLOCATIONS ; OPTION DB 0 ;PROGRAM OPTION ; ; ;FOLLOWING 3 USED BY THE CP/M DISK BUFFERING ROUTINES ; EOFLG DB 0 ;EOF FLAG (1=TRUE) SECPTR DW DBUF SECINBF DB 0 ;# OF SECTORS IN BUFFER ; ; ; ;FDOS III LOGICAL TO PHYSICAL SECTOR MAP ;TABLE ENTRIES ARE IN LOGICAL SECTOR ORDER ; ; TBL: DB 001H DB 00AH DB 013H DB 002H DB 00BH DB 014H DB 003H DB 00CH DB 015H DB 004H DB 00DH DB 016H DB 005H DB 00EH DB 017H DB 006H DB 00FH DB 018H DB 007H DB 010H DB 019H DB 008H DB 011H DB 01AH DB 009H DB 012H DB 000H ;DUMMY ENTRY DB 000H ;DUMMY ENTRY DB 000H ;DUMMY ENTRY ; ; ;FDOS III FILE HANDLER PARAMETER STORAGE LOCATIONS ; ; FDENT DS 11 ;TEMPORARY STORAGE FOR A DIRECTORY ENTRY ; ; ;SETUP A STACK AREA ; DS 200 ;STACK AREA STACK DS 2 ;STACK POINTER ; ;+++++++++ ;+++++++++ ;++ ;++ NOTE: THE FOLLOWING DISK DATA BUFFERS ARE ALLOCATED ;++ OVER THE HELP FILE AND NON DISK I/O SOFTWARE ;++ ;+++++++++ ;+++++++++ ; ; ; ;INPUT AND OUTPUT BUFFER STORAGE ALLOCATIONS FOR FDOS III DISK ; IDBUF EQU $ ;SINGLE SECTOR INPUT BUFFER ODBUF EQU $+128 ;SINGLE SECTOR OUTPUT BUFFER ; ; ; ;16 SECTOR CP/M DISK BUFFER ; DBUF EQU $+256 ;16 SECTOR CP/M DISK BUFFER ; ;INVALID COMMAND ; BADOPT: CALL CTYPE CALL ILPRT ;EXIT W/ERROR DB ': INVALID OPTION FOR PROGRAM SELECTION ' DB 'COMMAND - ',CR,LF DB 'PRESS CTL-C TO ABORT',1,0 ; HELP: CALL ILPRT DB CR,LF,CR,LF,'FORMAT FOR COMMAND IS:',CR,LF,CR,LF DB 'FDOS # FILENAME',CR,LF,CR,LF DB 'WHERE # IS A 1 CHARACTER PROGRAM OPTION,',CR,LF DB 'PROGRAM OPTIONS:',CR,LF DB ' R TO READ AN FDOS III FILE FROM B:',CR,LF DB ' W TO WRITE AN FDOS III FILE TO B:',CR,LF DB ' D TO VIEW THE FDOS III DIRECTORY ON B:',CR,LF DB ' H TO PRINT THIS HELP FILE',CR,LF,CR,LF,0 JMP EXIT ; ; ; BDOS EQUATES (VERSION 2) ; RDCON EQU 1 WRCON EQU 2 PRINT EQU 9 CONST EQU 11 ;CONSOLE STAT OPEN EQU 15 ;0FFH=NOT FOUND CLOSE EQU 16 ; " " SRCHF EQU 17 ; " " SRCHN EQU 18 ; " " ERASE EQU 19 ;NO RET CODE READ EQU 20 ;0=OK, 1=EOF WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC MAKE EQU 22 ;0FFH=BAD REN EQU 23 ;0FFH=BAD STDMA EQU 26 ;SET DMA BDOS EQU 5 REIPL EQU 0 FCB EQU 5CH ;SYSTEM FCB FCBEXT EQU FCB+12 ;FILE EXTENT FCBSNO EQU FCB+32 ;SECTOR # FCB2 EQU 6CH ;SECOND FCB END