TITLE 'ASM IO MODULE' ; I/O MODULE FOR CP/M ASSEMBLER ; ORG 200H BOOT EQU 000H ;REBOOT LOCATION ; I/O MODULE ENTRY POINTS JMP INIT ;INITIALIZE, START ASSEMBLER JMP SETUP ;FILE SETUP JMP GNC ;GET NEXT CHARACTER JMP PNC ;PUT NEXT OUTPUT CHARACTER JMP PNB ;PUT NEXT HEX BYTE JMP PCHAR ;PRINT CONSOLE CHARACTER JMP PCON ;PRINT CONSOLE BUFFER TO CRLF JMP WOBUFF ;WRITE OUTBUFFER JMP PERR ;PLACE ERROR CHARACTER INTO PBUFF JMP DHEX ;PLACE HEX BYTE INTO OUTPUT BUFFER JMP EOR ;END OF ASSEMBLY ; DATA FOR I/O MODULE BPC: DS 2 ;BASE PC FOR CURRENT HEX RECORD DBL: DS 1 ;HEX BUFFER LENGTH DBUFF: DS 16 ;HEX BUFFER ; ; DISK NAMES CDISK: DS 1 ;CURRENTLY SELECTED DISK ADISK: DS 1 ;.ASM DISK PDISK: DS 1 ;.PRN DISK HDISK: DS 1 ;.HEX DISK ; ; ; ; COMMON EQUATES QBMAX EQU 120 ;MAX PRINT SIZE QBUFF EQU 10CH ;PRINT BUFFER QBP EQU QBUFF+QBMAX ;PRINT BUFFER POINTER ; TOKEN EQU QBP+1 ;CURRENT TOKEN UDER SCAN VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH ACCUM EQU ACCLEN+1 ; EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS ; SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP SYMAX EQU SYTOP+2 ;MAX ADDRESS+1 ; PASS EQU SYMAX+2 ;CURRENT PASS NUMBER FPC EQU PASS+1 ;FILL ADDRESS FOR DHEX ROUTINE ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC ; CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED EOF EQU 1AH ;END OF FILE MARK ; ; ; DOS ENTRY POINTS BDOS EQU 5H ;DOS ENTRY POINT READC EQU 1 ;READ CONSOLE DEVICE WRITC EQU 2 ;WRITE CONSOLE DEVICE REDYC EQU 11 ;CONSOLE CHARACTER READY SELECT EQU 14 ;SELECT DISK SPECIFIED BY REGISTER E OPENF EQU 15 ;OPEN FILE CLOSF EQU 16 ;CLOSE FILE DELEF EQU 19 ;DELETE FILE READF EQU 20 ;READ FILE WRITF EQU 21 ;WRITE FILE MAKEF EQU 22 ;MAKE A FILE CSEL EQU 25 ;RETURN CURRENTLY SELECTED DISK SETDM EQU 26 ;SET DMA ADDRESS ; ; FILE AND BUFFERING PARAMETERS NSB EQU 8 ;NUMBER OF SOURCE BUFFERS NPB EQU 6 ;NUMBER OF PRINT BUFFERS NHB EQU 6 ;NUMBER OF HEX BUFFERS ; SSIZE EQU NSB*128 PSIZE EQU NPB*128 HSIZE EQU NHB*128 ; ; FILE CONTROL BLOCKS SCB: DS 9 ;FILE NAME DB 'ASM' ;FILE TYPE SCBR: DS 1 ;REEL NUMBER (ZEROED IN SETUP) DS 19 ;MISC AND DISK MAP SCBCR: DS 1 ;CURRENT RECORD (ZEROED IN SETUP) ; PCB: DS 9 DB 'PRN',0 DS 19 DB 0 ;RECORD TO WRITE NEXT ; HCB: DS 9 DB 'HEX',0 DS 19 DB 0 ; ; POINTERS AND BUFFERS SBP: DW SSIZE ;NEXT CHARACTER POSITION TO READ SBUFF: DS SSIZE ; PBP: DW 0 PBUFF: DS PSIZE ; HBP: DW 0 HBUFF: DS HSIZE FCB EQU 5CH ;FILE CONTROL BLOCK ADDRESS FNM EQU 1 ;POSITION OF FILE NAME FLN EQU 9 ;FILE NAME LENGTH BUFF EQU 80H ;INPUT DISK BUFFER ADDRESS ; SEL: ;SELECT DISK IN REG-A LXI H,CDISK CMP M ;SAME? RZ MOV M,A ;CHANGE CURRENT DISK MOV E,A MVI C,SELECT CALL BDOS RET ; SCNP: ;SCAN THE NEXT PARAMETER INX H MOV A,M CPI ' ' JZ SCNP0 SBI 'A' ;NORMALIZE RET SCNP0: LDA CDISK RET ; PCON: ;PRINT MESSAGE AT H,L TO CONSOLE DEVICE MOV A,M CALL PCHAR MOV A,M INX H CPI CR JNZ PCON MVI A,LF CALL PCHAR RET ; FNAME: ;FILL NAME FROM DEFAULT FILE CONTROL BLOCK LXI D,FCB MVI B,FLN FNAM0: LDAX D ;GET NEXT FILE CHARACTER CPI '?' JZ FNERR ;FILE NAME ERROR MOV M,A ;STORE TO FILE CNTRL BLOCK INX H INX D DCR B JNZ FNAM0 ;FOR NEXT CHARACTER RET ; INIT: ;SET UP STACK AND FILES, START ASSEMBLER LXI H,TITL CALL PCON JMP SET0 ; OPEN: ;OPEN FILE ADDRESSED BY D,E MVI C,OPENF CALL BDOS CPI 255 RNZ ; OPEN ERROR LXI H,ERROP CALL PCON JMP BOOT ; CLOSE: ;CLOSE FILE ADDRESSED BY D,E MVI C,CLOSF CALL BDOS CPI 255 RNZ ;CLOSE OK LXI H,ERRCL CALL PCON JMP BOOT ; DELETE: ;DELETE FILE ADDRESSED BY D,E MVI C,DELEF JMP BDOS ; MAKE: ;MAKE FILE ADDRESSED BY D,E MVI C,MAKEF CALL BDOS CPI 255 RNZ ; MAKE ERROR LXI H,ERRMA CALL PCON JMP BOOT ; SELA: LDA ADISK CALL SEL RET ; NPR: ;RETURN ZERO FLAG IF NO PRINT FILE LDA PDISK CPI 'Z'-'A' RZ CPI 'X'-'A' ;CONSOLE RET ; SELP: LDA PDISK CALL SEL RET ; SELH: LDA HDISK CALL SEL RET ; SET0: ;SET UP FILES FOR INPUT AND OUTPUT LDA FCB ;GET FIRST CHARACTER CPI ' ' ;MAY HAVE FORGOTTEN NAME JZ FNERR ;FILE NAME ERROR MVI C,CSEL ;CURRENT DISK? CALL BDOS ;GET IT TO REG-A STA CDISK ; ; SCAN PARAMETERS LXI H,FCB+FLN-1 CALL SCNP STA ADISK CALL SCNP STA HDISK CALL SCNP STA PDISK ; LXI H,SCB ;ADDRESS SOURCE FILE CONTROL BLOCK CALL FNAME ;FILE NAME OBTAINED FROM DEFAULT FCB ; CALL NPR ;Z OR X? JZ NOPR LXI H,PCB ;ADDRESS PRINT FILE CONTROL BLOCK PUSH H ;SAVE A COPY FOR OPEN PUSH H ;SAVE A COPY FOR DELETE CALL FNAME ;FILL PCB CALL SELP POP D ;FCB ADDRESS CALL DELETE POP D ;FCB ADDRESS CALL MAKE ; NOPR: ;TEST FOR HEX FILE LDA HDISK CPI 'Z'-'A' JZ NOHEX LXI H,HCB PUSH H PUSH H CALL FNAME CALL SELH POP D CALL DELETE POP D CALL MAKE ; ; FILES SET UP, CALL ASSEMBLER NOHEX: JMP ENDMOD ; SETUP: ;SETUP INPUT FILE FOR SOURCE PROGRAM LXI H,SSIZE SHLD SBP ;CAUSE IMMEDIATE READ XRA A ;ZERO VALUE STA SCBR ;CLEAR REEL NUMBER STA SCBCR ;CLEAR CURRENT RECORD STA DBL ;CLEAR HEX BUFFER LENGTH CALL SELA LXI D,SCB CALL OPEN ; RET ; FNERR: ;FILE NAME ERROR LXI H,ERRFN CALL PCON JMP BOOT ; ; GCOMP: ;COMPARE D,E AGAINS H,L MOV A,D CMP H RNZ MOV A,E CMP L RET ; GNC: ;GET NEXT CHARACTER FROM SOURCE BUFFER PUSH B PUSH D PUSH H ;ENVIRONMENT SAVED LHLD SBP LXI D,SSIZE CALL GCOMP JNZ GNC2 ; ; READ ANOTHER BUFFER CALL SELA LXI H,0 SHLD SBP MVI B,NSB ;NUMBER OF SOURCE BUFFERS LXI H,SBUFF GNC0: ;READ 128 BYTES PUSH B ;SAVE COUNT PUSH H ;SAVE BUFFER ADDRESS MVI C,READF LXI D,SCB CALL BDOS ;PERFORM THE READ POP H ;RESTORE BUFFER ADDRESS POP B ;RESTORE BUFFER COUNT ORA A ;SET FLAGS MVI C,128 JNZ GNC1 ; NORMAL READ OCCURRED LXI D,BUFF ;SOURCE BUFFER ADDRESS MVI C,128 MOV0: LDAX D ;GET CHARACTER MOV M,A ;STORE CHARACTER INX D INX H DCR C JNZ MOV0 ; BUFFER LOADED, TRY NEXT BUFFER ; DCR B JNZ GNC0 JMP GNC2 ; GNC1: ;EOF OR ERROR CPI 3 ;ALLOW 0,1,2 JNC FRERR ;FILE READ ERROR GNCE: MVI M,EOF ;STORE AND END OF FILE CHARACTER INX H DCR C JNZ GNCE ;FILL CURRENT BUFFER WITH EOF'S ; GNC2: ;GET CHARACTER TO ACCUMULATOR AND RETURN LXI D,SBUFF LHLD SBP PUSH H ;SAVE CURRENT SBP INX H ;READY FOR NEXT READ SHLD SBP POP H ;RESTORE PREVIOUS SBP DAD D ;ABSOLUTE ADDRESS OF CHARACTER MOV A,M ;GET IT POP H POP D POP B RET ; FRERR: LXI H,ERRFR CALL PCON ;PRINT READ ERROR MESSAGE JMP BOOT ; PNC: ;SAME AT PNCF, BUT ENVIRONMENT IS SAVED FIRST PUSH B ; CHECK FOR CONSOLE OUTPUT / NO OUTPUT MOV B,A ;SAVE CHARACTER LDA PDISK ;Z OR X? CPI 'Z'-'A' ;Z NO OUTPUT JZ PNRET ; CPI 'X'-'A' MOV A,B ;RECOVER CHAR FOR CON OUT JNZ PNGO CALL PCHAR JMP PNRET ; ; NOT X OR Z, SO PRINT IT PNGO: PUSH D PUSH H CALL PNCF POP H POP D PNRET: POP B RET ; PNCF: ;PRINT NEXT CHARACTER LHLD PBP XCHG LXI H,PBUFF DAD D MOV M,A ;CHARACTER STORED AT PBP IN PBUFF XCHG ;PBP TO H,L INX H ;POINT TO NEXT CHARACTER SHLD PBP ;REPLACE IT XCHG LXI H,PSIZE CALL GCOMP ;AT END OF BUFFER? RNZ ;RETURN IF NOT ; ; OVERFLOW, WRITE BUFFER CALL SELP LXI H,0 SHLD PBP LXI H,PBUFF LXI D,PCB ;D,E ADDRESS FILE CONTROL BLOCK MVI B,NPB ;NUMBER OF BUFFERS TO B ; (DROP THROUGH TO WBUFF) ; WBUFF: ;WRITE BUFFERS STARTING AT H,L FOR B BUFFERS ; CHECK FOR EOF'S MOV A,M CPI EOF RZ ;DON'T DO THE WRITE ; PUSH B ;SAVE NUMBER OF BUFFERS PUSH D ;SAVE FCB ADDRESS MVI C,128 ;READY FOR MOVE LXI D,BUFF WBUF0: ;MOVE TO BUFFER MOV A,M ;GET CHARACTER STAX D ;PUT CHARACTER INX H INX D DCR C JNZ WBUF0 ; ; WRITE BUFFER POP D ;RECOVER FCB ADDRESS PUSH D ;SAVE IT AGAIN FOR LATER PUSH H ;SAVE BUFFER ADDRESS MVI C,WRITF ;DOS WRITE FUNCTION CALL BDOS POP H ;RECOVER BUFFER ADDRESS POP D ;RECOVER FCB ADDRESS POP B ;RECOVER BUFFER COUNT ORA A ;SET ERROR RETURN FLAGS JNZ FWERR ; ; WRITE OK DCR B RZ ;RETURN IF NO MORE BUFFERS TO WRITE JMP WBUFF ; FWERR: ;ERROR IN WRITE LXI H,ERRFW CALL PCON ;ERROR MESSAGE OUT JMP EORC ;TO CLOSE AND REBOOT ; ; PNB: ;PUT NEXT HEX BYTE PUSH B PUSH D PUSH H CALL PNBF POP H POP D POP B RET ; PNBF: ;PUT NEXT BYTE ; (SIMILAR TO THE PNCF SUBROUTINE) LHLD HBP XCHG LXI H,HBUFF DAD D MOV M,A ;CHARACTER STORED AT HBP IN HBUFF XCHG INX H ;HBP INCREMENTED SHLD HBP XCHG ;BACK TO D,E LXI H,HSIZE CALL GCOMP ;EQUAL? RNZ ; ; OVERFLOW, WRITE BUFFERS CALL SELH LXI H,0 SHLD HBP LXI H,HBUFF LXI D,HCB ;FILE CONTROL BLOCK FOR HEX FILE MVI B,NHB JMP WBUFF ;WRITE BUFFERS ; PCHAR: ;PRINT CHARACTER IN REGISTER A PUSH B PUSH D PUSH H MVI C,WRITC MOV E,A CALL BDOS POP H POP D POP B RET ; WOCHAR: ;WRITE CHARACTER IN REG-A WITH REFLECT AT CONSOLE IF ERROR MOV C,A ;SAVE THE CHAR CALL PNC ;PRINT CHAR LDA QBUFF CPI ' ' RZ ; ERROR IN LINE LDA PDISK CPI 'X'-'A' RZ ;ALREADY PRINTED IF 'X' ; MOV A,C ;RECOVER CHARACTER CALL PCHAR ;PRINT IT RET ; WOBUFF: ;WRITE THE OUTPUT BUFFER TO THE PRINT FILE LDA QBP ;GET CHARACTER COUNT LXI H,QBUFF ;BASE OF BUFFER WOB0: ORA A ;ZERO COUNT? JZ WOBE ; NOT END, SAVE COUNT AND GET CHARACTER MOV B,A ;SAVE COUNT MOV A,M CALL WOCHAR ;WRITE CHARACTER INX H ;ADDRESS NEXT CHARACTER OF BUFFER MOV A,B ;GET COUNT DCR A JMP WOB0 ; WOBE: ;END OF PRINT - ZERO QBP STA QBP ; FOLLOW BY CR LF MVI A,CR CALL WOCHAR MVI A,LF CALL WOCHAR LXI H,QBUFF MVI A,QBMAX ;READY TO BLANK OUT WOB2: MVI M,' ' INX H DCR A JNZ WOB2 RET ; ; PERR: ;FILL QBUFF ERROR MESSAGE POSITION MOV B,A ;SAVE CHARACTER LXI H,QBUFF MOV A,M CPI ' ' RNZ ;DON'T CHANGE IT IF ALREADY SET MOV M,B ;STORE ERROR CHARACTER RET ; EOR: ;END OF ASSEMBLER CALL NPR ;Z OR A? JZ EOPR ; FILL OUTPUT FILES WITH EOF'S EOR2: LHLD PBP MOV A,L ORA H ;VALUE ZERO? JZ EOPR MVI A,EOF ;CTL-Z IS END OF FILE CALL PNC ;PUT ENDFILES IN PRINT BUFFER JMP EOR2 ;EVENTUALLY BUFFER IS WRITTEN ; EOPR: ;END OF PRINT FILE, CHECK HEX LDA HDISK CPI 'Z'-'A' JZ EORC EOR0: ;WRITE TERMINATING RECORD INTO HEX FILE LDA DBL ;MAY BE ZERO ALREADY ORA A CNZ WHEX ;WRITE HEX BUFFER IF NOT ZERO LHLD FPC ;GET CURRENT FPC AS LAST ADDRESS SHLD BPC ;RECORD LENGTH ZERO, BASE ADDRESS 0000 CALL WHEX ;WRITE HEX BUFFER ; ; NOW CLEAR OUTPUT BUFFER FOR HEX FILE EOR1: LHLD HBP MOV A,L ORA H JZ EORC MVI A,EOF CALL PNB JMP EOR1 ; ; CLOSE FILES AND TERMINATE EORC: CALL NPR JZ EORPC CALL SELP LXI D,PCB CALL CLOSE EORPC: LDA HDISK CPI 'Z'-'A' JZ EORHC CALL SELH LXI D,HCB CALL CLOSE ; EORHC: LXI H,ENDA CALL PCON JMP BOOT ; TITL: DB 'CP/M ASSEMBLER - VER 1.4',CR ERROP: DB 'NO SOURCE FILE PRESENT',CR ERRMA: DB 'NO DIRECTORY SPACE',CR ERRFN: DB 'SOURCE FILE NAME ERROR',CR ERRFR: DB 'SOURCE FILE READ ERROR',CR ERRFW: DB 'OUTPUT FILE WRITE ERROR',CR ERRCL: DB 'CANNOT CLOSE FILES',CR ENDA: DB 'END OF ASSEMBLY',CR ; DHEX: ;DATA TO HEX BUFFER (BYTE IN REG-A) PUSH B MOV B,A ;HOLD CHARACTER FOR 'Z' TEST LDA HDISK CPI 'Z'-'A' MOV A,B ;RECOVER CHARACTER JZ DHRET PUSH D ;ENVIRONMENT SAVED PUSH PSW ;SAVE DATA BYTE LXI H,DBL ;CURRENT LENGTH MOV A,M ;TO ACCUM ORA A ;ZERO? JZ DHEX3 ; ; LENGTH NOT ZERO, MAY BE FULL BUFFER CPI 16 JC DHEX1 ;BR IF LESS THAN 16 BYTES ; BUFFER FULL, DUMP IT CALL WHEX ;DBL = 0 UPON RETURN JMP DHEX3 ;SET BPC AND DATA BYTE ; DHEX1: ;PARTIAL BUFFER IN PROGRESS, CHECK FOR SEQUENTIAL BYTE LOAD LHLD FPC XCHG LHLD BPC ;BASE PC IN H,L MOV C,A ;CURRENT LENGTH OF BUFFER MVI B,0 ;IS IN B,C DAD B ;BPC+DBL TO H,L MOV A,E ;READY FOR COMPARE CMP L ;EQUAL? JNZ DHEX2 ;BR IF NOT MOV A,D ;CHECK HO BYTE CMP H JZ DHEX4 ;BR IF SAME ADDRESS ; DHEX2: ;NON SEQUENTIAL ADDRESS, DUMP AND CHANGE BASE ADDRESS CALL WHEX DHEX3: ;SET NEW BASE LHLD FPC SHLD BPC ; DHEX4: ;STORE DATA BYTE AND INC DBL LXI H,DBL MOV E,M ;LENGTH TO REG-E INR M ;DBL=DBL+1 MVI D,0 ;HIGH ORDER ZERO FOR DOUBLE ADD LXI H,DBUFF DAD D ;DBUFF+DBL TO H,L POP PSW ;RESTORE DATA BYTE MOV M,A ;INTO DATA BUFFER POP D DHRET: POP B ;ENVIRONMENT RESTORED RET ; WRC: ;WRITE CHARACTER WITH CHECK SUM IN D PUSH PSW RRC RRC RRC RRC ANI 0FH CALL HEXC ;OUTPUT HEX CHARACTER POP PSW ;RESTORE BYTE PUSH PSW ;SAVE A VERSION ANI 0FH CALL HEXC ;WRITE LOW NIBBLE POP PSW ;RESTORE BYTE ADD D ;COMPUTE CHECKSUM MOV D,A ;SAVE CS RET ; HEXC: ;WRITE CHARACTER ADI 90H DAA ACI 40H DAA JMP PNB ;PUT BYTE ; WHEX: ;WRITE CURRENT HEX BUFFER MVI A,':' ;RECORD HEADER CALL PNB ;PUT BYTE LXI H,DBL ;RECORD LENGTH ADDRESS MOV E,M ;LENGTH TO REG-E XRA A ;ZERO TO REG-A MOV D,A ;CLEAR CHECKSUM MOV M,A ;LENGTH IS ZEROED FOR NEXT WRITE LHLD BPC ;BASE ADDRESS FOR RECORD MOV A,E ;LENGTH TO A CALL WRC ;WRITE HEX VALUE MOV A,H ;HIGH ORDER BASE ADDR CALL WRC ;WRITE HO BYTE MOV A,L ;LOW ORDER BASE ADDR CALL WRC ;WRITE LO BYTE XRA A ;ZERO TO A CALL WRC ;WRITE RECORD TYPE 00 MOV A,E ;CHECK FOR LENGTH 0 ORA A JZ WHEX1 ; ; NON - ZERO, WRITE DATA BYTES LXI H,DBUFF WHEX0: MOV A,M ;GET BYTE INX H CALL WRC ;WRITE DATA BYTE DCR E ;END OF BUFFER? JNZ WHEX0 ; ; END OF DATA BYTES, WRITE CHECK SUM WHEX1: XRA A SUB D ;COMPUTE CHECKSUM CALL WRC ; ; SEND CRLF AT END OF RECORD MVI A,CR CALL PNB MVI A,LF CALL PNB RET ; ; ; ENDMOD EQU ($ AND 0FFE0H)+20H END