ENTRY EQU 0005H ;BDOS ENTRY POINT TFCB EQU 005CH ;SYSTEM FILE CONTROL BLOCK DBUF EQU 0080H ;SYSTEM DISK BUFFER CR EQU 0DH LF EQU 0AH RCFC EQU 01 ;READ CONSOLE WCFC EQU 02 ;WRITE CONSOLE RDFC EQU 13 ;RESET DISK OFFC EQU 15 ;OPEN FILE CFFC EQU 16 ;CLOSE FILE SFFC EQU 17 ;SEARCH FIRST SNFC EQU 18 ;SEARCH NEXT DFFC EQU 19 ;DELETE FILE RRFC EQU 20 ;READ RECORD WRFC EQU 21 ;WRITE RECORD MFFC EQU 22 ;MAKE FILE SAFC EQU 26 ;SET ADDRESS FN EQU 01 ;FILE NAME OFFSET FT EQU 09 ;FILE TYPE OFFSET EX EQU 12 ;EXTENT NUMBER OFFSET NR EQU 32 ;NEXT RECORD OFFSET ORG 100H MFT: LXI SP,STACK+64 LXI H,MSG1 ;PRINT 'MFT V3.1' CALL WASC XRA A ;CLEAR BREAK FLAGS STA IBFLG STA OBFLG ; CALCULATE BUFFER SIZE = FWA(BDOS) - FWA(MBUF) LHLD ENTRY+1 ;HL = (ENTRY+1) - 6 LXI D,-6 DAD D MOV A,L ANI 80H ;HL = HL MOD 128 MOV L,A LXI D,MBUF ;HL = HL - FWA(MBUF) MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A DAD H ;HL = HL / 128 MOV L,H MVI A,0 ACI 0 MOV H,A DCX H ;SUBTRACT ONE SHLD SPACE ;SAVE AS BUFFER SIZE LXI H,MSG2 ;WRITE 'BUFFER SIZE = ' CALL WASC LHLD SPACE ;WRITE SIZE OF BUFFER CALL WDWC LXI H,MSG3 ;WRITE ' SECTORS' CALL WASC ; ASK USER TO MOUNT INPUT DISK MFT1: LXI H,MSG4 ;WRITE 'MOUNT INPUT DISK, TYPE CR' CALL WASC CALL RACC ;READ RESPONSE CPI CR ;LOOP IF ANYTHING BUT CR JNZ MFT1 CALL WEOLC ;ECHO CR,LF LDA IBFLG ;JUMP If IBFLG SET ORA A JNZ MFT2A ; COPY COMMAND LINE INTO CBUF LXI H,DBUF ;FWA OF COMMAND LINE IMAGE LXI D,CBUF ;FWA OF COMMAND BUFFER MOV B,M ;FETCH COMMAND LINE IMAGE LENGTH INX H MFT2: MOV A,M ;FETCH NEXT BYTE FROM CLI INX H STAX D ;STORE IN DBUF INX D DCR B ;DECREMENT COUNT JNZ MFT2 ;LOOP UNTIL ZERO XRA A ;STORE ZERO BYTE AT END STAX D LXI H,CBUF ;RESET CBUFP SHLD CBUFP CALL CFNT ;CREATE FILE NAME TABLE LXI H,FNT ;RESET FNT POINTERS SHLD IFNTP SHLD OFNTP MFT2A: LXI H,MBUF ;RESET MBUF POINTER SHLD MBUFP LHLD SPACE ;RESET MSIZE SHLD MSIZE LDA IBFLG ;JUMP IF IBFLG NOT SET ORA A JZ MFT3 LXI H,IFCB ;COPY IFCB INTO TFCB LXI D,TFCB MVI B,33 CALL MOVE XRA A ;CLEAR IBFLG STA IBFLG MVI A,1 ;SET OBFLG STA OBFLG LHLD IFNTP ;BACK IFNTP UP 4 BYTES LXI D,-4 DAD D SHLD IFNTP LXI H,TFCB+FN ;WRITE FILENAME CALL WASC LXI H,MSG6 ;WRITE ' - ' CALL WASC LHLD IFNTP ;DE = IFNTP XCHG JMP MFTU ;CONTINUE READING PREVIOUS FILE ; PARSE OFF NEXT NAME FROM CBUF MFT3: LHLD IFNTP ;FETCH INPUT FNT POINTER MOV A,M ;JUMP IF END OF TABLE CPI 0FFH JZ MFT9 MVI M,1 ;SET 'FILE READ' FLAG INX H LXI D,TFCB+FN ;COPY FILENAME INTO TFCB MVI B,11 CALL MOVE SHLD IFNTP ;SAVE INPUT FNT POINTER LXI H,TFCB+FN ;WRITE FILENAME CALL WASC LXI H,MSG6 ;WRITE ' - ' CALL WASC XRA A ;SETUP TFCB STA TFCB STA TFCB+EX STA TFCB+NR CALL OPEN ;OPEN FILE LHLD IFNTP XCHG MFTU: LHLD MBUFP MOV A,H ;COPY INTO FNt ENTRY STAX D INX D MOV A,L STAX D INX D XCHG ;SAVE FNT POINTER SHLD IFNTP LXI H,0 ;FILE SIZE (IN SECTORS) = 0 SHLD FSIZE ; READ NEXT FILE FROM INPUT DISK MFT6: LHLD MBUFP XCHG CALL SETDMA CALL READ ;READ NEXT SECTOR ORA A ;JUMP IF NORMAL TRANSFER JZ MFT7 CPI 1 ;JUMP IF EOF JZ MFT8 LXI H,MSG8 ;WRITE 'READ ERROR - ' CALL WASC JMP MFT8 ;CONTINUE AS IF EOF MFT7: LHLD MBUFP ;MBUFP = MBUFP + 128 LXI D,128 DAD D SHLD MBUFP LHLD FSIZE ;FSIZE = FSIZE + 1 INX H SHLD FSIZE LHLD MSIZE ;DECREMENT MSIZE DCX H SHLD MSIZE MOV A,H ;LOOP IF STILL POSITIVE ORA L JNZ MFT6 LXI H,TFCB ;COPY TFCB INTO IFCB LXI D,IFCB MVI B,33 CALL MOVE MVI A,1 ;SET IBFLG STA IBFLG MFT8: LXI D,DBUF ;RESET DMA POINTER CALL SETDMA CALL CLOSE ;CLOSE FILE LHLD FSIZE ;WRITE FILE SIZE CALL WDWC LXI H,MSG9 ;WRITE ' SECTORS READ' CALL WASC ; UPDATE FNT, LOOP LHLD FSIZE ;DE = FILE SIZE XCHG LHLD IFNTP ;STORE FILE SIZE IN FNT ENTHY MOV M,D INX H MOV M,E INX H SHLD IFNTP ;SAVE FNT POINTER LDA IBFLG ;LOOP IF IBFLG NOT SET ORA A JZ MFT3 ; ASK USER TO MOUNT OUTPUT DISK MFT9: LXI H,MSGA ;WRITE 'MOUNT OUTPUT DISK, TYPE CR' CALL WASC CALL RACC ;READ RESPONSE CPI CR ;LOOP IF ANYTHING BUT CR JNZ MFT9 CALL WEOLC ;ECHO CR,LF CALL RESET ;RESET DISK SYSTEM (MAKE R/W) LDA OBFLG ;JUMP IF OBFLG NOT SET ORA A JZ MFTA LXI H,OFCB ;COPY OFCB INTO TFCB LXI D,TFCB MVI B,33 CALL MOVE CALL OPEN ;OPEN PREVIOUS FILE LHLD OFNTP ;BACKUP OUTPUT FNT POINTER 4 BYTES LXI D,-4 DAD D SHLD OFNTP LXI H,TFCB+FN ;WRITE FILE NAME CALL WASC LXI H,MSG6 ;WRITE ' - ' CALL WASC JMP MFTB ;CONTINUE WRITING PREVIOUS FILE ; WRITE NEXT FILE TO OUTPUT DISK MFTA: LHLD OFNTP MOV A,M ORA A JZ MFTF CPI 0FFH JZ MFTF INX H LXI D,TFCB+FN MVI B,11 CALL MOVE SHLD OFNTP LXI H,TFCB+FN CALL WASC LXI H,MSG6 CALL WASC XRA A STA TFCB STA TFCB+EX STA TFCB+NR LDA TFCB+9 ;FORCE TO $R/W FOR 2.0 ANI 7FH STA TFCB+9 LDA TFCB+10 ;FORCE TO $DIR FOR 2.0 ANI 7FH STA TFCB+10 CALL DELT ;TRY TO CREATE OUTPUT FILE CALL MAKE CPI 255 ;JUMP IF OK JNZ MFTB LXI H,MSGB ;WRITE 'UNABLE TO CREATE' CALL WASC JMP MFTG MFTB: LHLD OFNTP MOV D,M ;FETCH FWA OF FILE FROM FNT INX H MOV E,M INX H XCHG SHLD MBUFP ;SAVE IT XCHG MOV D,M ;FETCH SIZE OF FILE FROM FNT INX H MOV E,M INX H XCHG SHLD FSIZE ;SAVE IT SHLD XSIZE ;SAVE FOR PRINTOUT XCHG SHLD OFNTP LHLD FSIZE ;JUMP IF FSIZE=0 MOV A,H ORA L JZ MFTDA MFTC: LHLD MBUFP ;SET DMA ADDRESS TO MBUFP XCHG CALL SETDMA CALL WRITE ;WRITE NEXT SECTOR ORA A ;JUMP IF OK JZ MFTD LXI H,MSGC ;WRITE 'ERROR WRITING FILE' CALL WASC JMP MFTG MFTD: LHLD MBUFP ;MBUFP = MBUFP + 128 LXI D,128 DAD D SHLD MBUFP LHLD FSIZE ;FSIZE = FSIZE - 1 DCX H SHLD FSIZE MOV A,H ;LOOP UNTIL ZERO ORA L JNZ MFTC MFTDA: LXI H,TFCB ;COPY TFCB INTO OFCB LXI D,OFCB MVI B,33 CALL MOVE LXI D,DBUF ;RESET DMA POINTER CALL SETDMA CALL CLOSE ;TRY TO CLOSE FILE CPI 255 ;JUMP IF OK JNZ MFTE LXI H,MSGD ;WRITE 'UNABLE TO CLOSE' CALL WASC MFTE: LHLD XSIZE ;WRITE NUMBER OF SECTORS WRITTEN CALL WDWC LXI H,MSGE ;WRITE ' SECTORS WRITTEN' CALL WASC JMP MFTA MFTF: LDA IBFLG ;LOOP IF IBFLG SET ORA A JNZ MFT1 MFTG: JMP 0 ;EXIT TO CP/M ; SUBROUTINES MOVE: MOV A,M INX H STAX D INX D DCR B JNZ MOVE RET ;; GFN - GET FILE NAME ; GFN: MOV A,M ORA A RZ CPI ' ' JNZ GFN0 INX H JMP GFN GFN0: LXI D,XFCB XRA A STAX D INX D PUSH D MVI B,11 MVI A,' ' GFN6: STAX D INX D DCR B JNZ GFN6 POP D MVI B,9 GFN1: MOV A,M ORA A JZ GFN1 INX H CPI ' ' JZ GFN4 CPI '.' JZ GFN2 CPI '*' JZ GFN7 STAX D INX D DCR B JZ GFN5 JMP GFN1 GFN7: DCR B JZ GFN9 MVI A,'?' STAX D INX D JMP GFN7 GFN9: MOV A,M CPI '.' JNZ GFN4 INX H GFN2: LXI D,XFCB+FT MVI B,4 GFN3: MOV A,M ORA A JZ GFN4 INX H CPI ' ' JZ GFN4 CPI '*' JZ GFN8 STAX D INX D DCR B JZ GFN5 JMP GFN3 GFN8: DCR B JZ GFN4 MVI A,'?' STAX D INX D JMP GFN8 GFN4: XRA A RET GFN5: STC RET ;; CFNT - CREATE FILE NAME TABLE ; CFNT: LXI H,FNT ;RESET IFNTP SHLD IFNTP CFNT1: LHLD CBUFP ;GET CBUFP MOV A,M ;EXIT IF END OF LIST ORA A RZ CALL GFN ;GET NEXT AFN SHLD CBUFP ;SAVE COMMAND BUFFER PTR JNC CFNT2 ;JUMP IF FILENAME OK LXI H,MSG5 ;WRITE 'SYNTAX ERROR IN FILENAME' CALL WASC JMP CFNT1 ;LOOP CFNT2: XRA A ;CLEAR XFCB EXTENT FIELD STA XFCB+EX LXI D,XFCB ;SEARCH FOR FIRST OCCURANCE CALL SRCHF CPI 255 ;JUMP IF FOUND JNZ CFNT3 LXI H,XFCB+FN ;WRITE FILENAME CALL WASC LXI H,MSG7 ;WRITE ' NOT FOUND' CALL WASC JMP CFNT1 ;LOOP CFNT3: ANI 3 ;INDEX INTO CBUF MOV L,A MVI H,0 DAD H DAD H DAD H DAD H DAD H LXI D,DBUF DAD D XCHG ;COPY FILENAME INTO FNT LHLD IFNTP XCHG MVI B,12 CALL MOVE LXI H,ZEROS ;ZERO FILL REST OF ENTRY MVI B,4 CALL MOVE XCHG SHLD IFNTP ;SAVE INPUT FNT POINTER MVI M,0FFH ;INSURE FF BYTE AT END LXI D,XFCB ;SEARCH FOR NEXT OCCURANCE CALL SRCHN CPI 255 ;JUMP IF FOUND JNZ CFNT3 JMP CFNT1 ;GO GET NEXT AFN ;; WASC - WRITE ASCII STRING TO CONSOLK ; WASC: MOV A,M ORA A RZ CALL WACC INX H JMP WASC ;; WEOLC - WRITE END OF LINE TO CONSOLE ; WEOLC: MVI A,CR CALL WACC MVI A,LF JMP WACC ;; WDWC - WRITE DECIMAL WORD TO CONSOLE ; WDWC: PUSH H PUSH D PUSH B MVI B,0 ;CLEAR 'DIGIT WRITTEN' FLAG LXI D,10000 ;WRITE 1ST DIGIT CALL WNDD LXI D,1000 ;WRITE 2ND DIGIT CALL WNDD LXI D,100 ;WRITE 3RD DIGIT CALL WNDD LXI D,10 ;WRITE 4TH DTGIT CALL WNDD LXI D,1 ;WRITE 5TH DIGIT MVI B,1 ;FORCE LAST DIGIT TO PRINT CALL WNDD POP B POP D POP H RET WNDD: MVI C,0 ;C=0 WNDD1: MOV A,L ;HL = HL - DE SUB E MOV L,A MOV A,H SBB D MOV H,A JC WNDD2 ;JUMP IF < 0 INR C ;C = C + 1 JMP WNDD1 ;LOOP WNDD2: DAD D ;HL = HL + DE MOV A,C ;JUMP IF C NON-ZERO ORA C JNZ WNDD4 MOV A,B ;JUMP IF DIGIT WRITTEN ORA B JNZ WNDD4 MVI A,' ' ;WRITE ONE SPACE JMP WACC WNDD4: MVI B,1 ;SET 'DIGIT WRITTEN' FLAG MOV A,C ;ENCODE C INTO DECIMAL ASCII ADI '0' JMP WACC ;GO WRITE IT ;; WACC - WRITE ASCII CHARACTER TO CONSOLE ; WACC: PUSH H PUSH D PUSH B PUSH PSW MVI C,WCFC MOV E,A CALL ENTRY POP PSW POP B POP D POP H RET ;; RACC - READ ASCII CHARACTER FHOM CONSOLE ; RACC: PUSH H PUSH D PUSH B MVI C,RCFC CALL ENTRY POP B POP D POP H RET ;; RESET - RESET DISK SYSTEM ; RESET: PUSH H PUSH D PUSH B MVI C,RDFC CALL ENTRY POP B POP D POP H RET ;; OPEN - OPEN DISK FILE ; OPEN: PUSH H PUSH D PUSH B LXI D,TFCB MVI C,OFFC CALL ENTRY POP B POP D POP H RET ;; READ - READ RECORD FROM DISK FILE ; READ: PUSH H PUSH D PUSH B LXI D,TFCB MVI C,RRFC CALL ENTRY POP B POP D POP H RET ;; CLOSE - CLOSE DISK FILE ; CLOSE: PUSH H PUSH D PUSH B LXI D,TFCB MVI C,CFFC CALL ENTRY POP B POP D POP H RET ;; DELT - DELETE DISK FILE ; DELT: PUSH H PUSH D PUSH B LXI D,TFCB MVI C,DFFC CALL ENTRY POP B POP D POP H RET ;; MAKE - MAKE NEW DISK FILE ; MAKE: PUSH H PUSH D PUSH B LXI D,TFCB MVI C,MFFC CALL ENTRY POP B POP D POP H RET ;; WRITE - WRITE RECORD TO FILE ; WRITE: PUSH H PUSH D PUSH B LXI D,TFCB MVI C,WRFC CALL ENTRY POP B POP D POP H RET ;; SETDMA - SET DMA ADDRESS ; SETDMA: PUSH H PUSH D PUSH B MVI C,SAFC CALL ENTRY POP B POP D POP H RET ;; SRCHF - SEARCH FOR FIRST OCCURANCE OF AFN ; SRCHF: PUSH H PUSH D PUSH B MVI C,SFFC CALL ENTRY POP B POP D POP H RET ;; SRCHN - SEARCH FOR NEXT OCCURANCE OF AFN ; SRCHN: PUSH H PUSH D PUSH B MVI C,SNFC CALL ENTRY POP B POP D POP H RET MSG1: DB 'MFT V3.1',CR,LF,0 MSG2: DB 'Buffer size = ',0 MSG3: DB ' sectors',CR,LF,0 MSG4: DB 'Mount input disk, type CR',0 MSG5: DB 'Syntax error in filename',CR,LF,0 MSG6: DB ' - ',0 MSG7: DB ' not found',CR,LF,0 MSG8: DB 'read error - ',0 MSG9: DB ' sectors read ' ,CR,LF,0 MSGA: DB 'Mount output disk, type CR',0 MSGB: DB 'unable to create',CR,LF,0 MSGC: DB 'error writing file',CR,LF,0 MSGD: DB 'unable to close',CR,LF,0 MSGE: DB ' sectors written',CR,LF,0 ZEROS: DB 0,0,0,0 ORG ($+15)/16*16 FNT: DS 16*64+1 STACK: DS 64 SPACE: DS 2 ;AVAILABLE SPACE MSIZE: DS 2 ;MEMORY SIZE CBUF: DS 80 ;COMMAND BUFFEH CBUFP: DS 2 ;COMMAND BUFFER POINTEH FSIZE: DS 2 ;FILE SIZE IN SECTORS XSIZE: DS 2 ;FILE SIZE FOR PRINTOUT IFNTP: DS 2 ;INPUT FNT POINTER OFNTP: DS 2 ;OUTPUT FNT POINTER MBUFP: DS 2 ;MEMORY BUFFER POINTER IFCB: DS 33 ;INPUT FCB OFCB: DS 33 ;OUTPUT FCB XFCB: DS 33 ;TEMPORARY FCB IBFLG: DS 1 ;INPUT BREAK FLAG OBFLG: DS 1 ;OUTPUT BREAK FLAG MBUF EQU $ END MFT