;=================================================================== ; MICRO RESOURCES CP/M -- MTX FILE TRANSFER PROGRAM ; FOR USE WITH PERTEC PCC 2000 DD CP/M 1.4 ;=================================================================== ; ; ; THIS PROGRAM IS A UTILITY TO TRANSFER FILES FROM PCC 2000 MTX ; DOUBLE DENSITY DISKS TO CP/M DISKS OR TO TRANSFER A CP/M ; FILE TO A PCC 2000 MTX DOUBLE DENSITY DISK. A PROVISION HAS ; ALSO BEEN INCLUDED TO ALLOW EXAMINATION OF THE DIRECTORY OF ; THE MTX DISKETTE. THE OPERATION OF THIS PROGRAM ASSUMES ; THAT A CP/M SYSTEM DISK IS PRESENT IN DRIVE A: AND THAT THE ; MTX DATA DISK IS IN DRIVE B:. THE BIOS PRIMITIVES OF THE CP/M ; SYSTEM ARE ACCESSED DIRECTLY TO ALLOW READING AND WRITING ; OF THE DOUBLE DENSITY MTX DISK WITH IT'S 2 TO 1 LOGICAL ; TO PHYSICAL SECTOR MAPPING. NOTE THAT THIS SOFTWARE IS ; SPECIFICALLY TAYLORED TO FUNCTION THROUGH THE BIOS VECTORS ; OF THE PERTED IMPLEMENTATION OF CP/M 1.4 ON A PCC 2000 WITH ; DOUBLE DENSITY FLOPPY DISKS. ; ; THIS PROGRAM DOES NOT PACK THE FILES OF THE MTX DISK ; WHEN CREATING NEW FILES UPON TRANSFER FROM A CP/M FILE. ; SUBSEQUENT PACKING MAY DONE UPON THE DESTINATION MTX/PCC 2000 ; 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 MTX 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 MTX DISK. ; FILE NAMES OF MTX FILES ARE A MAXIMUM OF 6 ASCII CHARACTERS ; IN LENGTH SO THE CP/M FILE TRANSFERRED TO THE MTX DISK ; WILL HAVE ITS NAME TRUNCATED TO THE FIRST SIX CHARACTERS. ; THE MTX FILE TYPE WILL ALWAYS BE SET TO 00 AS AN INDEXED ; FILE TYPE. RECORD SIZE OF A MTX DESTINATION FILE WILL BE ; SET TO 128 BYTES. FOR MTX DESTINATION FILES THAT ARE AN ; ODD NUMBER OF 128 BYTE RECORDS THE LAST HALF IS BACK ; FILLED WITH AN ARBITRARY CHOICE OF ZEROS. ; ; FOR FILES TRANSFERRED TO CP/M FROM MTX DISKS THE FILE ; TYPE WILL BE CHECKED AND IF THE SOURCE TYPE IS NOT AN ; INDEXED FILE THEN THE TRANSFER TO CP/M WILL NOT BE ; MADE. ; ; THIS PROGRAM BUFFERS CP/M SECTOR READS UP 156 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,' PCC 2000 CP/M <----> PCC 2000 MTX' DB CR,LF,' VER 1.31 11/15/80' DB CR,LF,'$' ; DB 'COPYRIGHT 1980 MICRO RESOURCES' DB '2468 HANSEN CT.' DB 'SIMI VALLEY, CA 93065' DB '(805) 527-7922' ; 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 CP/M FILE BUFFERING PARAMETERS ; MVI A,00H STA SECINBF ;ZERO SEC IN BUFFER COUNTER STA EOFLG ;RESET CP/M END OF FILE FLAG LXI H,DBUF ;INITIALIZE BUFFER POINTER SHLD SECPTR ; ;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 MTX FILE? JZ MTXRD ; CPI 'W' ;WRITE MTX FILE? JZ MTXWR ; CPI 'D' ;LOOK AT MTX DIRECTORY JZ MTXDIR ; CPI 'H' ;GO TO HELP FILE PRINTOUT? JZ HELP ; ;INVALID OPTION ; JMP BADOPT ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * MTXDIR: LISTS MTX DIRECTORY TO CONSOLE * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ; ;THE DIRECTORY OF THE DOUBLE DENSITY MTX ;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 ; MTXDIR: CALL ILPRT ;PRINT THE DIRECTORY HEADER LABEL DB CR,LF,CR,LF,' MTX DISK DIRECTORY' DB CR,LF,CR,LF DB 'FILENAME TYPE RECORD RECORD START END ',CR,LF DB ' COUNT SIZE SECTOR SECTOR',CR,LF DB '------------------------------------------',CR,LF,0 ; MVI A,016 ;SET PRINT LOOP COUNT STA LISTCNT MVI A,00 ;SET SCAN FOR FIRST ENTRY JMP MDIR2 ;JUMP INTO LOOP MDIR1: MVI A,01 ;SET SCAN CODE FOR NEXT ENTRY MDIR2: CALL MDIRSC ;SCAN FOR NEXT DIRECTORY ENTRY ORA A ;SET FLAGES FOR RETURN CODE JNZ MDEREX ;GO EXIT FOR FULL DISK DIRECTORY LDA MDENT ;GET FIRST CHAR OF DERECTORY ENTRY CPI 0FFH ;MUST BE AT END OF THE LIST JZ MDIREX CPI 000H ;CHECK IF THIS ENTRY IS EMPTY JZ MDIR1 ;SKIP PRINT IF SO CALL PRTDIR ;PRINT THIS ENTRY ; LDA LISTCNT ;GET LIST LINE COUNT DCR A ;DECREMENT IT STA LISTCNT ;STORE NEW COUNT BACK JNZ MDIR1 ;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 MDIR1 ;GO START ON 16 MORE ENTRIES ; MDIREX: CALL ILPRT ;PRINT END OF LIST MESSAGE DB CR,LF,CR,LF,'END OF MTX DISK DIRECTORY',CR,LF,0 MDIREX1: MVI C,00H ;RESTORE SELECT OF DRIVE A: CALL SELDSK ;DIRECT BIOS ACCESS JMP EXIT ;DONE WITH DIRECTORY ; MDEREX: CALL ILPRT ;PRINT DISK FULL MESSAGE DB CR,LF,'++MTX DISK DIRECTORY SPACE FULL++',CR,LF,0 ; JMP MDIREX1 ; ; ; ; ;SCAN MTX 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 WITH LOGICAL SECTOR 1 ; 01=GET NEXT DIRECTORY ENTRY ; ; RETURN VALUE IS THE FIRST OR NEXT ENTRY AS SPECIFIED BY THE ; FUNCTION CODE AND IS PASSED IN BUFFER "MDENT" WHICH IS 16 ; BYTES LONG. ; ; THIS ROUTINE SCANS AND RETURNS ALL POSSIBLE ENTRIES ; AND WHEN END OF LOGICAL SECTOR 25 IS ENCOUNTERED AN ; 0FFH CODE IS RETURNED IN THE ACCUMULATOR. ELSE A 00H ; CODE IS RETURNED. ; ; ; MDIRSC: ORA A ;SET FLAGS FOR FUNCTION CHECK JNZ NEXTENT ;FOR NON-ZERO CODE JUST GET NEXT ENTRY ; ;SETUP FOR BEGINNING OF SCAN MVI A,000H ;SETUP START SECTOR OF DIRECTORY-1 STA MDIRSEC MVI A,016 ;SET CURRENT SUBSCAN COUNT TO MAX STA DIRSECI ; NEXTENT: LDA DIRSECI ;GET SECTOR INDEX CPI 016 ;AT MAXIMUM ENTRY? JNZ SAMSEC ;NO STAY WITH THIS SECTOR LXI H,MDIRSEC INR M ;INCREMENT CURRENT SECTOR NUMBER MOV A,M ;GET THE SECTOR NUMBER CPI 026 ;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 L,A MVI H,00H CALL MRDSEC ;GO READ MTX SECTOR LXI H,MTXBUF ;MOVE INPUT BUFFER LXI D,DIRBUF ;..TO DIRECTORY BUFFER MVI B,00H ;SET COUNT FOR FULL 256 CALL MOVE 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 MTX DIRECTORY BUFFER LXI D,016 ;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,MDENT ;POINT TO ENTRY PASS BUFFER MVI B,016 ;SETUP LENGTH OF DIRECTORY ENTRY CALL MOVE ;GO MOVE A DIRECTORY ENTRY LXI H,MDENT ;SETUP TO STRIP MTX MBS'S FROM FILE NAME MOV A,M ;SEE IF FIRST BYTE IS 0FFH CPI 0FFH ;IF SO WE SKIP MSB STRIP JZ ENDRET MVI B,06H ;CHARACTER COUNT SAMSEC3: MOV A,M ;GET CHARACTER OF NAME ANI 07FH ;STRIP MTX STRING CRAP MOV M,A INX H DCR B ;DEC NAME BYTE COUNT JNZ SAMSEC3 ; ENDRET: MVI A,00H ;SET NORMAL RETURN FLAG RET ; ; ; ; ;DIRECTORY SCAN POINTER PARAMETERS ; ; MDIRSEC DB 00 ;CURRENT DIRECTORY SECTOR NUMBER DIRSECI DB 00 ;INDEX OF SCAN INTO CURRENT DIRECTORY SECTOR DIRBUF DS 256 ;256 BYTE DIRECTORY ENTRY BUFFER LISTCNT DB 00 ;DIRECTORY LIST ENTRY COUNT ; ; ; ;PRINT DIRECTORY ENTRY SUBROUTINE ; ; PRTDIR: LXI H,MDENT ;POINT TO DIRECTORY ENTRY BUFFER MVI A,'B' CALL CTYPE ;PRINT OUT DRIVE DESIGNATOR MVI A,':' CALL CTYPE MVI B,06 ;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 SP3 ;THREE SPACES MOV A,M ;GET TYPE BYTE CALL HEXO ;SHOW IT INX H ;INCREMENT THE BUFFER POINTER ; INX H ;SKIP THE KEY SIZE FIELD ; CALL SP2 ;TWO SPACES MOV D,M ;GET HIGH RECORD COUNT BYTE INX H MOV E,M ;GET LOW RECORD COUNT BYTE INX H PUSH H ;SAVE STRING POINTER CALL DECPRT ;GO PRINT RECORD COUNT POP H ; CALL SP2 ;TWO SPACES MOV D,M ;GET HIGH RECORD SIZE BYTE INX H MOV E,M ;GET LOW RECORD SIZE BYTE INX H PUSH H ;SAVE STRING POINTER CALL DECPRT ;GO PRINT RECORD SIZE POP H ; CALL SP2 ;TWO SPACES MOV D,M ;GET HIGH START SECTOR BYTE INX H MOV E,M ;GET LOW START SECTOR BYTE INX H PUSH H ;SAVE STRING POINTER CALL DECPRT ;GO PRINT START SECTOR COUNT POP H ; CALL SP2 ;TWO SPACES MOV D,M ;GET HIGH END SECTOR BYTE INX H MOV E,M ;GET LOW END SECTOR BYTE DCX D ;SET THE ENDING SECTOR TO REAL VALUE CALL DECPRT ;GO PRINT ENDING SECTOR COUNT ; CALL CRLF ;GET READY FOR NEXT LINE RET ; ; ;CONVERT AND PRINT A TWO BYTE VALUE AT CONSOLE IN DECIMAL ; DECPRT: XCHG ;HL=WORD TO PRINT LXI D,STRBUF ;POINT TO A CONVERT BUFFER CALL BINASC ;CONVERT TO DECIMAL ASCII MVI B,05H ;BYTE COUNT PRINT STRING LXI H,STRBUF ;POINT TO THE PRINT BUFFER DECPRT1: MOV A,M ;GET PARAMETER CHARACTER PUSH H CALL CTYPE ;PRINT AT CONSOLE POP H INX H ;INCREMENT STRING POINTER DCR B ;DEC BYTE COUNT JNZ DECPRT1 ;DONE WITH FIVE CHAR YET RET ; ; ;DECIMAL PRINTING ROUTINE TEMPORARY BUFFER STRING SPACE ; STRBUF: DS 14 ;RESERVE SOME BYTES FOR BUFFER ; ; ;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 ; ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * MTXWR: COPIES FILE TO MTX * * * * * * * * * * * * * * * * * * * * * * * * ; ;THE CP/M FILE SPECIFIED IN THE COMMAND ;IS TRANSFERRED TO THE MTX DISK IN DRIVE B: ; MTXWR: CALL OPENFIL ;OPEN THE FILE LXI H,0000H ;SET INITIAL RECORD COUNT TO ZERO SHLD RECCNT MVI H,26 ;SET MAX UTILIZED SECTOR TO 26 ;..MTX STARTS FILES AT LOGICAL SECTOR 26 SHLD MAXSEC ;STORE AWAY MVI A,00H STA MTXEOF ;CLEAR MTX EOF FLAG MVI A,00H ;SETUP FOR DIRECTORY SCAN JMP SCAN2 ;JUMP INTO LOOP SCAN1: MVI A,01H ;SET SCAN CODE FOR NEXT ENTRY SCAN2: CALL MDIRSC ;SCAN FOR NEXT DIRECTORY ENTRY ORA A ;SET FLAGS FOR RETURN CODE JNZ MDIRFUL ;EXIT FOR FULL DIRECTORY ; MVI B,06 ;SETUP FOR COMPARE OF FILE NAMES LXI D,FCB+1 ;..FOR 6 CHAR FROM CP/M FCB LXI H,MDENT ;..TO MTX DIRECTORY ENTRY CALL COMPARE ;GO DO THE COMPARE ORA A ;CHECK RETURN FLAG JNZ FEXEX ;EXIT WITH FILE EXISTS MESSAGE ; LDA MDENT ;FIRST BYTE OF NAME "FF" IF END CPI 0FFH ;ARE WE AT END OF LIST? JZ SCAN3 ;IF AT END THEN BALE OUT OF LOOP ; LHLD MAXSEC ;SET TO UPDATE MAX USED SECTOR IF NEEDED XCHG LHLD MDENT+14 MOV A,L ;COMPARE HIGH BYTE OF THIS ONE AND CURRENT MAX CMP E JC SCAN1 ;NO UPDATE NEEDED JNZ UDTMAX ;IF HIGH BYTE GREATER THEN UPDATE MAX MOV A,H ;COMPARE LOW BYTES OF THIS ONE AND CURRENT MAX CMP D JC SCAN1 ;NO UPDATE IF HIGHS EQUAL AND LOW NOT BIGGER UDTMAX: SHLD MAXSEC ;STORE NEW BIG SEC NUM AT MAX SEC LOC JMP SCAN1 ;GO DO MORE DIRECTORY ENTRIES ; SCAN3: MVI B,06 ;MOVE FILE NAME INTO MTX DIRECTORY ENTRY LXI H,FCB+1 LXI D,MDENT SCANAP: MOV A,M ;GET CHAR FROM FCB AREA ORI 080H ;PUT ON TOP BIT FOR MTX COMPATIBILITY STAX D ;PUT IN NEW DIRECTORY ENTRY INX H ;BUMP POINTERS INX D DCR B ;DEC NAME BYTE COUNT JNZ SCANAP ; MVI A,00 ;SET THE NEW FILE TYPE TO ZERO AS INDEXED FILE STA MDENT+6 STA MDENT+7 ;SET KEYSIZE FIELD TO ZERO STA MDENT+10 ;SET HIGH BYTE OF RECORD SIZE TO ZERO MVI A,080H STA MDENT+11 ;SET RECORD SIZE TO 128 BYTES AS CP/M ;SECTOR SIZE LHLD MAXSEC ;GET CURRENT MAX SECTOR AND PUT AS START SHLD MDENT+12 ; SHLD MDENT+14 ;SET INITIAL END SECTOR MFILWLP: CALL RDSECT ;READ A SECTOR FROM CP/M JC UPDATE ;UPDATE MTX DIRECTORY IF DONE LHLD RECCNT ;INC RECORD COUNT CALL MTXINC SHLD RECCNT LXI H,080H ;MOVE SECTOR FROM CPM AREA LXI D,MTXBUF CALL MOVE128 CALL RDSECT ;READ ANOTHER SECTOR FROM CP/M JC UPDAFIL ;UPDATE MTX DIRECTORY IF DONE LHLD RECCNT ;INC RECORD COUNT CALL MTXINC SHLD RECCNT LXI H,080H ;MOVE SECTOR FROM CP/M AREA LXI D,MTXBUF+128 CALL MOVE128 WRTENT: LXI H,MDENT+14 ;POINT TO SECTOR TO BE WRITTEN MOV D,M INX H MOV E,M ; LXI H,07B8H ;CHECK IF DISK FULL MOV A,H CMP D JNZ NOTFUL MOV A,L CMP E JZ DSKFUL ;EXIT WITH MESSAGE IF DISK IS FULL ; NOTFUL: XCHG ;HL=LOGICAL SECTOR TO WRITE CALL MWRSEC ;GO WRITE CURRENT MTX SECTOR LHLD MDENT+14 ;INCREMENT END SECTOR CALL MTXINC SHLD MDENT+14 ; LDA MTXEOF ;SEE IF WE GOT TO END BEFORE ORA A JNZ UPDATE ;GO TO UPDATE DIRECTORY IF END ; JMP MFILWLP ;GO TO GET THE NEXT SECTOR FROM CP/M ; ; ;CP/M EOF ENCOUNTERED ON MIDDLE OF SECTOR NEEDS FILLING TO END ; WE ARBITRARILY CHOOSE TO FILL WITH ZEROS. ; UPDAFIL: LXI H,MTXBUF+128 ;POINT TO SECOND HALF OF BUFFER MVI B,128 ;SET FILL COUNT SHFILL: MVI M,00H ;PUT IN A ZERO INX H ;BUMP POINTER DCR B ;DEC BYTE COUNT JNZ SHFILL ;MORE TO DO? ; MVI A,0FFH ;SET END OF FILE FLAG STA MTXEOF JMP WRTENT ;GO WRITE SECTOR ; ;FILE WRITTEN, NOW UPDATE THE DIRECTORY ; UPDATE: XRA A ;INITIALIZE TWO SECTOR UPDATE FLAG STA U2SEC ; LHLD RECCNT ;PUT RECORD COUNT INTO DIR ENTRY MOV A,H ;CHECK IF THERE WAS NO CP/M FILE SIZE ORA L JZ NOSIZF ;EXIT IF FILE FIZE IS ZERO SHLD MDENT+8 ; LXI H,DIRBUF ;MOVE DIRECTORY SECTOR TO OUTPUT BUFFER LXI D,MTXBUF MVI B,00H ;SET THE COUNT FOR FULL 256 BYTE MOVE CALL MOVE LDA DIRSECI ;GET DIRECTORY SECTOR INDEX LXI H,MTXBUF-16 LXI D,16 ;MAKE INSERT POINTER FOR NEW ENTRY UPDAT: DAD D DCR A JNZ UPDAT ; XCHG ;PUT INSERT POINTER IN DE LXI H,MDENT ;POINT TO NEW DIRECTORY ENTRY MVI B,16 ;LENGTH OF DIRECTORY ENTRY CALL MOVE ;MOVE INTO OUTPUT BUFFER LDA DIRSECI ;SEE IF NEW ENTRY IS LAST IN SECTOR CPI 016 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: MVI A,0FFH ;PUT "FF"ed OUT ENTRY INTO THIS SECTOR MVI B,16 ;ENTRY LENGTH-- DE OK FROM PREVIOUS MOVE ONESEC1: STAX D ;PUT FF IN ENTRY INX D ;INC FF'ING POINTER DCR B ;DEC BYTE COUNTER JNZ ONESEC1 ; WDIRSEC: LDA MDIRSEC ;GET THE DIRECTORY SECTOR NUMBER MVI H,0 ;MAKE TWO BYTE LOGICAL SECTOR NUMBER MOV L,A CALL MWRSEC ;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 MDIRSEC ;GET CURRENT DIRECTORY SECTOR NUMBER INR A STA MDIRSEC ;STORE THIS NEW ONE AWAY CPI 01BH ;SEE IF DIRECTORY FULL HERE JZ UDFULL ;GO PRINT EXIT MESSAGE ; MVI H,0 ;MAKE TWO BYTE SECTOR NUMBER MOV L,A CALL MRDSEC ;GO READ NEXT SECTOR ; LXI D,MTXBUF ;POINT TO START OF DIRECTORY SECTOR JMP ONESEC ;GO END THE PROCESS OF UPDATE ON SECOND SEC ; ; ;SUBROUTINE TO INCREMENT A REVERSE ORDER TWO BYTE PAIR ; MTXINC: MOV A,H ;SET TO INCREMENT END SECTOR MOV H,L MOV L,A INX H ;INC THE END SECTOR MOV A,H MOV H,L MOV L,A RET ; ; ;EXIT POINT FROM WRITE IF MTX DIRECTORY IS FULL UPON UPDATE ; UDFULL: CALL ILPRT ;PRINT DIRECTORY FULL MESSAGE DB CR,LF,'++MTX DIRECTORY FULL UPON UPDATE++' DB CR,LF,'++TRANSFERRED FILE EXISTS ON DISK++',CR,LF,0 JMP EXIT ; ; ;EXIT POINT FROM WRITE IF MTX DIRECTORY IS FULL ; MDIRFUL: CALL ILPRT ;PRINT DIRECTORY FULL MESSAGE DB CR,LF,'++MTX DIRECTORY MUST BE FULL++',CR,LF,0 JMP EXIT ; ; ;EXIT POINT FROM WRITE IF NOTHING IN CP/M FILE ; NOSIZF: CALL ILPRT ;PRINT NO SIZE TO CP/M FILE DB CR,LF,'++CP/M FILE EMPTY-NO MTX FILE CREATED++',CR,LF,0 JMP EXIT ; ; ;EXIT POINT FROM WRITE IF MTX DISK GETS FULL ; DSKFUL: CALL ILPRT ;PRINT DISK FULL MESSAGE DB CR,LF,'++FILE TOO BIG - MTX DISK FULL++' DB CR,LF,'++DIRECTORY NOT UPDATED WITH NEW FILE++',CR,LF,0 JMP EXIT ; ;EXIT POINT FROM WRITE IF MTX FILE ALREADY EXISTS ; FEXEX: CALL ILPRT DB CR,LF,'++MTX FILE ALREADY EXISTS++' DB CR,LF,'++CHANGE NAME OF SOURCE FILE ON CP/M++',CR,LF,0 JMP EXIT ; ; ; ; ;PARAMETER STORAGE AREA FOR MTX WRITE ROUTINE ; U2SEC DB 00 ;USED TO SEE IF TWO SECTORS S/B SET IN DIR MAXSEC DW 00 ;STORAGE FOR MAXIMUM USED LOGICAL SECTOR MTXEOF DB 00 ;FLAG TO INDICATE IF END OF MTX FILE RECCNT DW 00 ;CURRENT MTX FILE SIZE IN 128 BYTE RECORDS ; ; ; * * * * * * * * * * * * * * * * * * * * * * * * MTXRD: COPY FILE FROM MTX * * * * * * * * * * * * * * * * * * * * * * * * ; ;FETCHES AN MTX FILE AND THEN WRITES ;IT TO A CP/M FILE ON DRIVE A: ; MTXRD: CALL ERASFIL ;ERASE THE CP/M FILE CALL MAKEFIL ;..THEN MAKE NEW 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 MDIRSC ;SCAN FOR NEXT DIRECTORY ENTRY ORA A ;SET FLAGES FOR RETURN CODE JNZ MDNFEX ;GO EXIT FOR NOT FOUND MTX FILE LDA MDENT ;FIRST CHAR OF FILE NAME CPI 0FFH ;MUST BE AT END OF THE LIST IF "FF" JZ MDNFEX ;GO EXIT FOR NOT FOUND MTX FILE MVI B,06H ;SETUP FOR COMPARE FILE NAMES LXI D,FCB+1 ;..FOR 6 CHAR FROM FCB TO LXI H,MDENT ;..MTX DIRECTORY ENTRY CALL COMPARE ;GO COMPARE ORA A ;CHECK THE RETURN FLAG JZ FIND1 ;NO NAME MATCH IF ZERO ; ;FOUND FILE ON MTX DISK ; RMTXLP: LDA MDENT+6 CPI 000H ;CKECK IF SOURCE FILE IS OF INDEXED TYPE JNZ NINDX ;EXIT WITH ERROR IF NOT INDEXED FILE ; LXI H,MDENT+12 ;GET LOGICAL SECTOR NUMBER MOV D,M ;..HIGH BYTE INX H MOV E,M ;..LOW BYTE INX D ;INCREMENT SECTOR FOR NEXT TIME MOV M,E ;STORE BACK AWAY DCX H MOV M,D DCX D ;GET BACK NUMBER OF ONE WE WANT XCHG ;LOGICAL SECTOR COUNT TO HL CALL MRDSEC ;GO READ IT FROM MTX DISK ; LXI H,MTXBUF ;MOVE 1ST HALF TO CP/M AREA LXI D,080H ;..TO 128 BYTE PASS BUFFER FOR CP/M CALL MOVE128 CALL WRSECT ;MOVE DATA TO CP/M QUEUE ; LXI H,MTXBUF+128 ;MOVE 2ND HALF TO CP/M AREA LXI D,080H ;..TO 128 BYTE PASS BUFFER FOR CP/M CALL MOVE128 CALL WRSECT ;MOVE 2ND HALF DATA TO CP/M QUEUE ; LHLD MDENT+12 ;GET CURRENT INCREMENTED LOGICAL SECTOR XCHG ;TO (DE). NOTE HI/LOW ORDER WRONG LHLD MDENT+14 ;GET DIRECTORY ENTRY 1+ ENDING SECTOR TO (HL) MOV A,H ;COMPARE LOW BYTES OF SECTOR NUMBERS CMP D JNZ RMTXLP ;BOTH MUST COMPARE FOR EQUALITY MOV A,L ;NOW COMPARE HIGH BYTES OF SECTOR NUMBERS CMP E JNZ RMTXLP ;AGAIN NO COMPARE SO MORE TO READ ; ;GOT EOF ON SECTOR - FLUSH BUFFERS, END ; CALL WRBLOCK ;WRITE THE LAST BLOCK CALL CLOSFIL ;CLOSE THE FILE JMP DONE ;GO PRINT END OF TRANSFER MESSAGE ; ; ; MDNFEX: CALL ILPRT ;PRINT MTX FILE NOT FOUND DB CR,LF,'++MTX FILE NOT FOUND++',CR,LF,0 JMP EXIT ; ; ; NINDX: CALL ILPRT ;PRINT MTX FILE TYPE NOT INDEXED TYPE DB CR,LF,'++MTX FILE NOT AN INDEXED FILE++',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++',CR,LF,'$' ; ; ;----> 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++',CR,LF,'$' ; ;----> RDSECT: READS A SECTOR ; ;FOR SPEED, THIS ROUTINE BUFFERS UP 156 ;SECTORS AT A TIME. ; RDSECT: LDA SECINBF ;GET # SECT IN BUFF. DCR A ;DECREMENT.. STA SECINBF ;..IT CPI 0FFH ;CHECK IF SECTOR COUNT UNDERFLOWS JZ 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 156 ; 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++',CR,LF,'$' ; RDSECOK: LXI H,80H DAD D ;TO NEXT BUFF XCHG ;BUFF TO DE INR C ;MORE SECTORS? MOV A,C ;GET COUNT CPI 156 ;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 156 ;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 156 ;HAVE WE 156? 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,'$' ; ; ; ;----> 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 ; ; ; MTX DOUBLE DENSITY FLOPPY DISK ACCESS ROUTINE FOR DRIVE B: ; ON AN ICOM 3812 RUNNING LIFEBOAT CP/M VER 1.4 ; ; ; ;----> MRDSEC: READS A GIVEN SECTOR ACCORDING ; TO MTX CONVENTION. REGISTER PAIR (HL) ; CONTAINS THE LOGICAL SECTOR NUMBER. ; MRDSEC: CALL MTXSCAL ;GET OURSELVES A TRACK AND SECTOR PUSH H ;SAVE SECTOR NUMBER PUSH B ;SAVE TRACK NUMBER MVI C,01H ;LETS SELECT B: FOR MTX ACCESS CALL SELDSK ;LET BIOS SELECT DISK POP B ;GET TRACK NUMBER FOR NEXT CALL MOV C,B CALL SETTRK ;HAVE BIOS HANDLE TRACK SEEK LXI B,MTXBUF ;SET DMA ADDRESS FOR BUFFER CALL SETDMA POP H ;GET SECTOR NUMBER MOV C,L ;PUT FOR BIOS PUSH B ;SAVE FOR 2ND 128 BYTES CALL SETSEC ;BIOS POINT TO FIRST HALF CALL RDSEC ;READ THE SECTOR INTO BUFFER ORA A ;LOOK TO SEE IF READ ERROR JNZ MRDER ;TELL OF MTX READ ERROR LXI B,MTXBUF+128 CALL SETDMA ;FIX DMA ADDR FOR 2ND HALF POP B ;FIX FOR SEC +1 TO GET 2ND HALF INR C CALL SETSEC CALL RDSEC ;READ 2ND HALF ORA A ;LOOK AGAIN TO SEE IF READ ERROR JNZ MRDER RET ;GO BACK IF NO ERRORS DETECTED ; ;MTX DISK READ ERROR ; MRDER: CALL ERXIT DB '++MTX DISK READ ERROR++$' ; ; ;----> MWRSEC: WRITES A GIVEN SECTOR ACCORDING ; TO MTX CONVENTION. REGISTER PAIR (HL) ; CONTAINS THE LOGICAL SECTOR NUMBER. ; ; MWRSEC: CALL MTXSCAL ;GET OURSELVES A TRACK AND SECTOR PUSH H ;SAVE SECTOR NUMBER PUSH B ;SAVE TRACK NUMBER MVI C,01H ;LETS SELECT B: FOR MTX ACCESS CALL SELDSK ;LET BIOS SELECT DISK POP B ;GET TRACK NUMBER FOR NEXT CALL MOV C,B CALL SETTRK ;HAVE BIOS HANDLE TRACK SEEK LXI B,MTXBUF ;SET DMA ADDRESS FOR BUFFER CALL SETDMA POP H ;GET SECTOR NUMBER MOV C,L ;PUT FOR BIOS PUSH B ;SAVE FOR 2ND 128 BYTES CALL SETSEC ;BIOS POINT TO FIRST HALF CALL WRTSEC ;WRITE THE SECTOR FROM BUFFER ORA A ;LOOK TO SEE IF WRITE ERROR JNZ MWRER ;TELL OF MTX WRITE ERROR LXI B,MTXBUF+128 CALL SETDMA ;FIX DMA ADDR FOR 2ND HALF POP B ;FIX FOR SEC +1 TO GET 2ND HALF INR C CALL SETSEC CALL WRTSEC ;WRITE 2ND HALF ORA A ;LOOK AGAIN TO SEE IF WRITE ERROR JNZ MWRER RET ;GO BACK IF NO ERRORS DETECTED ; ;MTX DISK WRITE ERROR ; MWRER: CALL ERXIT DB '++MTX DISK WRITE ERROR++$' ; ; ;----> MTXSCAL: TRANSLATES MTX LOGICAL SECTOR TO ; TRACK AND PHYSICAL SECTOR NUMBERS ; ; ENTRY WITH DOUBLE BYTE LOGICAL SECTOR ; NUMBER IN (HL). ; EXIT WITH TRACK IN (B) AND PHYSICAL SECTOR ; IN (L) ; ; NOTE THAT THE SUBSEQUENT ROUTINE WILL HAVE ; READ SECTORS (L) AND (L+1) TO OBTAIN ALL OF ; THE MTX SECTORS DATA. ; MTXSCAL: LXI D,-26 ;SET TO CALCULATE TRACK NUMBER MVI B,00H ;INITIAL TRACK COUNTER TRCLP1: INR B ;TRACK LOOP COUNTER INCREMENT DAD D ;SUBTRACT SECTOR NUMBERS MOD 26 JC TRCLP1 ;LOOP IN SUBTRACT TILL WE UNDERFLOW ; LXI D,26 ;SET THE HL PAIR TO REAL LOGICAL SECTOR ; ON THIS TRACK DAD D ; XCHG ;PUT LOGICAL SECTOR IN DE FOR NOW LXI H,TRANTBL ;GET BASE OF TRANSLATION TABLE DAD D ;INDEX INTO TABLE MOV L,M ;GET PHYSICAL NUMBER RET ; ; ;MTX LOGICAL TO PHYSICAL SECTOR TRANSLATION TABLE ; TABLE ENTRIES ARE IN LOGICAL ORDER ; TRACK LOGICAL SECTOR ZERO MAPS TO PHYSICAL #1 ; ALSO NOTE THAT THIS TABLE ASSUMES THAT DISK ; SOFTWARE THINKS TRACK HAS 52 128 BYTE SECTORS ; TRANTBL: DB 01H DB 21H DB 0DH DB 2DH DB 19H DB 05H DB 25H DB 11H DB 31H DB 1DH DB 09H DB 29H DB 15H DB 2BH DB 17H DB 03H DB 23H DB 0FH DB 2FH DB 1BH DB 07H DB 27H DB 13H DB 33H DB 1FH DB 0BH ; ; ;----> 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 MTX 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 ; ; ; ;SETUP A DATA BUFFER FOR MTX SECTOR WHICH IS 256 BYTES LONG ;IT TAKES TWO CP/M 1.4 128 BYTE SECTOR READS TO FILL THE ;MTX LOGICAL SECTOR BUFFER. ; DS 20 ;DUMMY BUFFER PAD MTXBUF: DS 256 ;MTX READ DATA BUFFER DS 20 ;BUFFER PAD ; ; ; ; ;----> 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 ; ; ;----> BINASC: CONVERTS A 16 BIT BINARY NUMBER TO ASCII ; INPUT NUMBER ASSUMED TO BE IN HL AND ; OUTPUT ASCII 5 CHARACTER BUFFER IS POINTED ; TO BY DE. MAXIMUM NUMBER FOR CONVERSION IS ; THE EQUIVALENT OF 16 BITS BINARY. ; BINASC: PUSH PSW ;SAVE REGISTERS PUSH B PUSH D LXI B,004H ;FIX DE TO POINT TO END OF BUFFER XCHG DAD B XCHG PUSH D ;SAVE ASCII POINTER MVI A,05H ;GET A DIGIT COUNT STA DIGCNT NDIG: LXI B,-10 ;RADIX FOR CONVERSION LXI D,-1 ;THIS BECOMES NO DIVIDED BY RADIX DX: DAD B ;SUBTRACT 10 INX D JC DX LXI B,10 DAD B ;ADD RADIX BACK IN ONCE XCHG MOV A,E ADI '0' ;CONVERT FROM BCD TO ASCII POP D ;GET ASCII BUFFER POINTER STAX D ;STORE ASCII CHARACTER DCX D ;ADJUST ASCII POINTER LDA DIGCNT ;CHECK IF CONVERSION DONE DCR A JZ DDIG ;EXIT IF DONE STA DIGCNT PUSH D ;SAVE ASCII POINTER JMP NDIG ;GO DO NEXT DIGIT DDIG: POP D ;RESTORE REGISTERS POP B POP PSW RET ; ; ;BINASC ROUTINE STORAGE ALLOCATIONS ; DIGCNT DB 00 ;PLACE TO STORE ASCII DIGIT COUNT ; ; ; ; ; ---------------- ; ;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 ; ; ;MTX FILE HANDLER PARAMETER STORAGE LOCATIONS ; DS 20 MDENT DS 16 ;TEMPORARY STORAGE FOR A DIRECTORY ENTRY DS 20 ; ; ;SETUP A STACK AREA ; DS 400 ;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 ;++ ;+++++++++ ;+++++++++ ; ; ;16 SECTOR CP/M DISK BUFFER ; DS 20 DBUF EQU $+1 ;16 SECTOR CP/M DISK BUFFER ; ;INVALID COMMAND ; BADOPT: PUSH PSW ;SAVE BAD OPTION MVI A,'[' CALL CTYPE POP PSW 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 'MTX # 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 MTX FILE FROM B:',CR,LF DB ' W TO WRITE AN MTX FILE TO B:',CR,LF DB ' D TO VIEW THE MTX 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, 1ERR, 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