;-----------------------------------------------; ; Z80 RESIDENT ASSEMBLER ; ;-----------------------------------------------; ; ; ;(C) 1977 LEHMAN CONSULTING SERVICES ; ; ALL RIGHTS RESERVED ; ; ; ;-----------------------------------------------; ; ; ; SUBROUTINE PACKAGE ; ; ; ;-----------------------------------------------; ; ; ; REV 0 14-JULY-77 MGL ; ; ; ;-----------------------------------------------; ; ; EJECT ;-----------------------------------------------; ; ; ; CPMUTIL COMMUNICATIONS AREA ; ; ; ;-----------------------------------------------; ; ORG 103H ; ; JUMP TABLE EQUATES ; WLINE DS 3 ;WRITE PRINTER LINE WMSG DS 3 ;WRITE CONSOLE MSG DSKSEL DS 3 ;SELECT DISK OPNFIL DS 3 ;OPEN FILE CLSFIL DS 3 ;CLOSE FILE DELFIL DS 3 ;DELETE FILE DREAD DS 3 ;DISK READ DWRITE DS 3 ;DISK WRITE CREFIL DS 3 ;CREATE FILE DMASET DS 3 ;SET DMA ADDRESS MOVE DS 3 ;MOVE BYTES CMPCHR DS 3 ;COMPARE CHARACTERS CMPHD DS 3 ;COMPARE HL:DE MUL16 DS 3 ;HL <= HL * DE GNB DS 3 ;GET NEXT BYTE (1K BLOCKING) WNB DS 3 ;WRITE NEXT BYTE GNB2 DS 3 ;GET NEXT BYTE (FCB2) WNB2 DS 3 ;WRITE NEXT BYTE (FCB2) CNV2HX DS 3 ;CONVERT TO HEX - BUF => HL REG ; ; FCB1 DS 33 FCB2 DS 33 IBP DS 2 IBP2 DS 1 OBP DS 1 OBP2 DS 1 IBUF DS 2 OBUF DS 2 IBUF2 DS 2 OBUF2 DS 2 INBUF DS 1024 OUTBUF DS 128 INBUF2 DS 128 OUTBF2 DS 128 ; ; EJECT ;-----------------------------------------------; ; COMMON DATA AREA (CDA) ; ;-----------------------------------------------; ; ORG 980H ;LEAVE SPACE FOR CPMUTIL ; HDRBUF DS 16 ;MUST FOLLOW ORG REC DS 80 ;MUST FOLLOW HDRBUF PC DS 2 ;CURRENT PROGRAM COUNTER OBJ DS 32 ;OBJECT CODE BUFFER OBJCNT DS 1 ;LEN OF DATA IN OBJ LEN DS 1 ;LEN OF CURRENT INSTRUCTION VAL DS 2 ;RETURN FROM EVAL ROUTINE INST DS 80 ;CURRENT INSTRUCTION (OR DATA FROM DB) EOM DB 0 ;END OF BUFFER CHARACTER (FOR WLINE) PTR1 DS 2 ;POINTS TO NEXT CHAR IN REC PASSNO DS 1 ;CURRENT PASS =0 PASS1 =FF PASS2 IDBUF DS 16 ;CURRENT ID INTBUF DS 2 ;RETURNED VALUE FROM INT ROUTINE CURLNE DS 1 ;CURRENT LINE NUMBER FOR PAGING OUTPUT LEN2 DS 2 ;FOR DEFS LBLADR DS 2 ;LAST LBL ADDR IN SYM (FOR EQU) EQUFLG DS 1 ;IF NON-ZERO EQUVAL IS USED INSTEAD OF PC FOR PRINT EQUVAL DS 2 ;VALUE OF LAST EQU ENDADR DS 2 ;EXPRESSION VALUE ON END STATEMENT EFLG DS 1 ;END OF PROGRAM FLAG (TO ALLOW PRINTING OF END STMT) OPCODE DS 2 ;CURRENT OPCODE FROM SYMBOL TABLE SAVVAL DS 2 ;SAVED CONTENTS OF VAL LFLAG DS 1 ;LISTING FLAG =N NO LISTING, =' ' OR 'Y' LISTING HFLAG DS 1 ;HEX OBJ FLAG =N NO HEX OBJ, =' ' OR 'Y' HEX OBJ OUTPUT ERRFLG DS 1 ;ERROR CHARACTER FOR THIS LINE TEMP DS 2 ;TEMP 2 BYTE AREA MULT DS 2 ;BASE OF NUMBER IN INT CONVERT LOOP SYMPTR DS 2 ;ADDRESS OF NEXT SYMBOL TABLE ENTRY SYMPT DS 2 ;ADDRESS OF BEGINING OF SYMBOL TABLE UFLAG DS 1 ;UNDEFINED FLAG FROM EVAL, =0 ALL OK, =1 >1 UNDEFINED EVFLGS DS 1 ;FLAG FIELD FROM LAST SYMLUK ; ; EJECT ; ; JUMP TABLE FOR ROUTINES IN THIS ASSEMBLY ; JMP EVAL JMP ID JMP INT JMP SETUP ;INIT FILES FOR ASSEMBLER JMP SYMENT JMP SYMLUK JMP GNR ;GET NEXT RECORD JMP GNC ;GET NEXT CHARACTER JMP BACKUP ;BACKUP TO LAST CHARACTER ; ; EJECT ; ; ; EXPRESSION EVALUATOR ; ; VALID OPERATORS ARE: +, - AND * ; ; VALID ELEMENTS ARE: ID'S, NUMBERS, AND '$' FOR PC ; ; EVAL EQU $ MVI A,0 ! STA OP ! STA UFLAG ;DEFAULT OP TO +, UFLAG=0 STA EVFLGS ;RESET FLAGS FROM LAST SEARCH LXI H,0 ! SHLD VAL ;SET VAL TO 0000 EVAL1 EQU $ CALL GNC ;GET NEXT ELEMENT OR OPERATOR CPI '0' ! JC EVAL3 ! CPI '9'+1 ! JC EVAL9 ;BRANCH IF NUMBER EVAL3 EQU $ CPI '$' ! JZ EVAL11 ;BRANCH IF PC REF CPI 'A' ! JC EVAL5 ! CPI 'Z'+1 ! JC EVAL13 ;BRANCH IF ID EVAL5 EQU $ CPI '+' ! JZ EVAL22 CPI '-' ! JZ EVAL24 CPI '*' ! JZ EVAL26 CPI 27H ! JZ EVAL29 ;PROCESS SINGLE BYTE QUOTED STRING RET ;GET OUT OF HERE WE ARE DONE ; ; PROCESS NUMBER ; EVAL9 EQU $ CALL BACKUP ! CALL INT ! JMP EVAL28 ; ; ; PROCESS '$' REF ; EVAL11 EQU $ LHLD PC ! SHLD INTBUF ! JMP EVAL28 ; ; ; PROCESS ID ; ; EVAL13 EQU $ CALL BACKUP ! CALL ID CALL BACKUP ;BACKUP SO AS TO NOT IGNORE OPERATOR OR COMMA LXI H,IDBUF ! CALL SYMLUK ! JNZ EVAL19 ;BRANCH IF UNDEFINED MOV A,M ! STA INTBUF ! INX H ! MOV A,M ! STA INTBUF+1 ! JMP EVAL28 EVAL19 EQU $ ;PROCESS UNDEFINED ID LXI H,0 ! SHLD INTBUF ;SET VALUE TO 0000 LDA UFLAG ! ORI 1 ! STA UFLAG ;SET UNDEFINED FLAG JMP EVAL28 ; ; PROCESS OPERATORS ; EVAL22 EQU $ MVI A,0 ! JMP EVAL27 ; EVAL24 EQU $ MVI A,1 ! JMP EVAL27 ; EVAL26 EQU $ MVI A,2 EVAL27 EQU $ STA OP JMP EVAL1 ; ; ; PROCESS VALUE USING CURRENT OPERATOR ; ; EVAL28 EQU $ ;VAL = VAL OP INTBUF LDA OP CPI 1 ! JZ EVAL28A ;BRANCH IF SUBTRACT CPI 2 ! JZ EVAL28B ;BRANCH IF MULTIPLY LHLD VAL ! XCHG ! LHLD INTBUF ! DAD D ! SHLD VAL ;+ JMP EVAL1 ; EVAL28A EQU $ ;SUBTRACT LHLD VAL ! XCHG ! LHLD INTBUF MOV A,E ! SUB L ! MOV L,A ! MOV A,D ! SBB H ! MOV H,A ! SHLD VAL JMP EVAL1 ; EVAL28B EQU $ ;MULTIPLY LHLD VAL ! XCHG ! LHLD INTBUF ! CALL MUL16 ! SHLD VAL JMP EVAL1 ; ; ; PROCESS SINGLE BYTE IN QUOTES ; EVAL29 EQU $ CALL GNC ;GET CHARACTER STA INTBUF ! XRA A ! STA INTBUF+1 ;FAKE 2 BYTE VALUE CALL GNC ;BYPASS TRAILING QUOTE JMP EVAL28 ;AND GO PROCESS VALUE NORMALLY ; ; OP DS 1 ;CURRENT OPERATOR FOR EVAL ; ; EJECT ; ; ; ID - COLLECT ID AND PLACE IN IDBUF ; ID EQU $ PUSH H ! PUSH D ! PUSH B ;SAVE REGS MVI A,' ' ! STA IDBUF LXI H,IDBUF+1 ! LXI D,IDBUF ! LXI B,15 ! CALL MOVE ;BLANK IDBUF LXI H,IDBUF CALL GNC ID2 EQU $ CPI 'A' ! JC ID1 ! CPI 'Z'+1 ! JNC ID1 ;IF NOT A LETTER THEN BRANCH ID3 MOV M,A ! INX H PUSH H ! LHLD PTR1 ! MOV A,M ! INX H ! SHLD PTR1 ! POP H JMP ID2 ; ID1 CPI '.' ! JZ ID3 ; ALLLOW LABELS WITH '.' IN THEM (E.G. LAB.01) CPI '$' ! JZ ID2 ; ALLOW $ FILLERS (E.G. SQR$ROOT) CPI '0' ! JC ID4 ! CPI '9'+1 ! JC ID3 ;ALLOW DIGITS ID4 POP B ! POP D ! POP H RET ; ; EJECT ; ; ; INT - CONVERT CHARACTERS TO BINARY ; ; ALLOW TRAILING 'H' FOR HEX AND 'B' FOR BINARY ; DEFAULT TYPE IS DECIMAL (BASE 10) ; INT EQU $ LHLD PTR1 ! SHLD TEMP ;SAVE POINTER LXI H,10 ! SHLD MULT ;SET DEFAULT BASE TO 10 MVI B,0 ;SET UP LENGTH COUNTER CALL GNC ;SKIP BLANKS INT1 EQU $ CPI '+' ! JZ INT1A ;BRANCH IF A TERMINATOR CPI '-' ! JZ INT1A CPI '*' ! JZ INT1A CPI 0DH ! JZ INT1A CPI ';' ! JZ INT1A CPI ')' ! JZ INT1A CPI ',' ! JZ INT1A CPI 20H ! JZ INT1A LHLD PTR1 ! MOV A,M ! INX H ! SHLD PTR1 ;GET NEXT CHARACTER INR B ! JMP INT1 ;INCREMENT COUNTER AND CONTINUE LOOP INT1A EQU $ DCX H ! SHLD PTR1 ! DCX H ! MOV A,M INT2 CPI 'H' ! JNZ INT3 ;BRANCH IF NOT HEX DCR B ;DECREMENT COUNTER LXI H,16 ! SHLD MULT ;SET UP BASE 16 JMP INT4 ; INT3 CPI 'B' ! JNZ INT4 ;BRANCH IF NOT BINARY DCR B ;DECREMENT COUNTER LXI H,2 ! SHLD MULT ;SET UP BASE 2 INT4 LHLD PTR1 ! XCHG ! LHLD TEMP ! SHLD PTR1 ! XCHG ! SHLD TEMP ;SAVE PTR LXI D,0 ;SET UP ACCUMULATOR CALL GNC ! CALL BACKUP INT5 EQU $ LHLD PTR1 ! MOV A,M INX H ! SHLD PTR1 CPI 'A' ! JC $+5 ! ADI 9 ;FOR A-F ANI 0FH ! PUSH PSW ;GET BINARY VALUE OF THIS DIGIT PUSH B ;SAVE COUNTER LHLD MULT ! CALL MUL16 POP B ;RESTORE COUNTER POP PSW ! MOV E,A ! MVI D,0 ! DAD D ;ADD IN NEW DIGIT XCHG ! DCR B ! JNZ INT5 ;GO BACK IF MORE TO DO INT6 LHLD TEMP ! SHLD PTR1 XCHG ! SHLD INTBUF ;SAVE VALUE RET ; ; EJECT ; ; SETUP - SET UP FILES FOR Z80ASM ; ; INPUT FROM CONSOLE IS FILENAME.AB ; ; A= Y OR N FOR LISTING ; B= Y OR N FOR HEX FILE ; SETUP EQU $ LXI H,FCB1 ! LXI D,5CH ! LXI B,33 ! CALL MOVE ;GET DEFAULT FCB LXI H,FCB1+9 ! LXI D,ASMEXT ! LXI B,3 ! CALL MOVE ;SET UP EXTENSION LXI H,FCB2 ! LXI D,5CH ! LXI B,33 ! CALL MOVE ;GET DEFAULT FCB LXI H,FCB2+9 ! LXI D,HEXEXT ! LXI B,3 ! CALL MOVE ;SET UP EXTENSION LDA 5CH+9 ! STA LFLAG ;SET UP LISTING FLAG LDA 5CH+10 ! STA HFLAG ;SET UP HEX FLAG LXI D,FCB1 ! CALL OPNFIL ! JZ SETER1 ;BRANCH IF SOURCE FILE NOT FOUND LDA HFLAG ! CPI 'N' ! JZ SETUP1 ;BRANCH IF NO HEX FILE SETUP LXI D,FCB2 ! CALL DELFIL ;DELETE FILE LXI D,FCB2 ! CALL CREFIL ! JZ SETER2 ;BRANCH IF UNABLE TO CREATE LXI D,FCB2 ! CALL OPNFIL ! JZ SETER2 ;BRANCH IF UNABLE TO OPEN SETUP1 EQU $ LXI H,INBUF+1024 ! SHLD IBP ! XRA A ! STA OBP2 ;SET UP POINTERS RET ;AND GET OUT OF HERE ; SETER1 LXI D,SM1 ! CALL WMSG ! JMP 0 ;MSG AND REBOOT ; SETER2 LXI D,SM2 ! CALL WMSG ! JMP 0 ;MSG AND REBOOT ; SM1 DB 13,10,'SOURCE (.ASM) FILE NOT FOUND',13,10,'$' ; SM2 DB 13,10,'UNABLE TO CREATE/OPEN OBJECT (.HEX) FILE',13,10,'$' ; ASMEXT DB 'ASM' HEXEXT DB 'HEX' ; ; EJECT ; ; SYMENT - ENTER A SYMBOL INTO THE SYMBOL TABLE ; ; UPON ENTRY HL POINTS TO NEW ENTRY ; ; ENTRY FORMAT: FLAGS/LENGTH (EACH 4 BITS) ; N A M E ... (UP TO 11 BYTES) ; VALUE LOW (1 BYTE) ; VALUE HIGH (1 BYTE) ; TYPE BYTE (1 BYTE) ; ; ON RETURN HL POINTS TO VALUE LOW BYTE IN NEW ENTRY FOR POSSIBLE ; FURTHER UPDATE (USED BY EQU PSEUDO OPERATOR) ; ; SYMENT EQU $ MOV A,M ! PUSH B ! XCHG ! ANI 0FH ! MOV C,A ! MVI B,0 ;GET LEN LHLD SYMPTR ! CALL MOVE ;MOVE INTO SYMBOL TABLE SHLD SYMPTR ! MVI M,0 ; SET UP NEW POINTER AND NEW END MARKER DCX H ! DCX H ! DCX H ;BACKUP TO POINT TO VALUE LOW FIELD POP B RET ; ; EJECT ; ; ; SYMLUK - LOOK UP SYMBOLS IN TABLE ; ; ON RETURN Z=0 MEANS SYMBOL NOT FOUND. ; Z=1 SYMBOL FOUND, HL POINTS TO VALUE LOW BYTE IN TABLE ENTRY ; ; SYMLUK EQU $ XCHG LHLD SYMPT ;GET POINTER TO BEGINING OF TABLE XCHG SYML1 LDAX D ! CPI 0 ! JZ SYMNF ;BRANCH IF END OF TABLE STA EVFLGS ;SAVE FOR MAIN PROCESSOR ANI 0FH ! SUI 4 ! MOV B,A ! INX D ;SET UP FOR COMPARE CALL CMPCHR ! JZ SYML2 ;BRANCH IF MATCH DCX D ;BACK UP LENGTH BYTE AGAIN SYML3 EQU $ LDAX D ! ANI 0FH ! MOV C,A ! MVI B,0 ! XCHG ! DAD B ! XCHG JMP SYML1 ;ADVANCE POINTER AND CONTINUE TO LOOP ; SYML2 EQU $ ;NOW SEE IF EXACT MATCH DCX D ! LDAX D ! ANI 0FH ! SUI 4 ;GET LENGTH PUSH H ! MOV C,A ! MVI B,0 ! DAD B ! MOV A,M CPI ' ' ! POP H ! JNZ SYML3 ;IF NXT CHR NOT BLANK THEN NOT EXACT MATCH LDAX D ! ANI 0FH ! DCR A ! DCR A ! DCR A ! MOV C,A ! MVI B,0 XCHG ! DAD B ! XRA A ! RET ;POINT TO VALUE LOW AND EXIT ; SYMNF XRA A ! INR A ! RET ;SET Z=0 AND RETURN ; ; EJECT ; ; GNR - GET NEXT RECORD - FILL REC UNTIL 0AH OR 1AH (CTRL/Z) IS FOUND ; GNR LXI H,REC ! SHLD PTR1 ;RESET POINTER MVI M,' ' ! XCHG ! LXI H,REC+1 ! LXI B,79 ! CALL MOVE ;BLNK BUFFER LXI H,REC ;GET ADDRESS OF RECORD BACK AGAIN GNR1 CALL GNB ! CPI 1AH ! RZ ;RETURN IF EOF MARKER (CTRL/Z) IF FOUND CPI 09H ! JZ GNR2 ;BRANCH IF TAB CHARACTER MOV M,A ! INX H ! CPI 0AH ! JNZ GNR1 ;BRANCH IF NOT LF RET GNR2 EQU $ ;PROCESS TAB LXI D,8 ! DAD D ! MOV A,L ! ANI 0F8H ! MOV L,A ;PROCESS TAB STOP JMP GNR1 ; ; EJECT ; ; ; GNC - GET NEXT CHARACTER ; USE PTR1 TO INDEX INTO REC, SKIP BLANKS ; GNC EQU $ PUSH H ! LHLD PTR1 MOV A,M ! CPI ' ' ! INX H ! JZ $-4 ;SKIP BLANKS CPI 09H ! JZ $-9 ;BRANCH IF TAB CHARACTER SHLD PTR1 ! POP H RET ; ; ; BACKUP - BACKUP PTR1 AND RETURN CHARACTER ; ; BACKUP PUSH H ! LHLD PTR1 DCX H ! MOV A,M SHLD PTR1 ! POP H RET ; ; EJECT