;COPYRIGHT 1978 BY PAT CROWE ;********************************************************************** ; Z80 ASSEMBLER VERSION 1.1 ; WRITTEN BY PAT CROWE ; 22 RINGSBURY CLOSE ; PURTON ; SWINDON ; SN5 9DE ; ENGLAND ;************************************************************************* ;CONSTANTS ;************************************************************************* CR EQU 0DH ; ASCII CARRIAGE RETURN LF EQU 0AH ; ASCII LINE FEED HT EQU 09H ; ASCII HORIZ. TAB FORMFD EQU 0CH ; ASCII FORM FEED NUL EQU 0 ; ASCII NULL SPACE EQU 20H ; ASCII SPACE DEL EQU 0FFH ; ASCII DELETE CTOK EQU 71H ; TOKEN FOR UNCONDIT. OPND KW 'C' CCOND EQU 8BH ; TOKEN FOR CONDITIONAL OPND KW 'C' XYMASK EQU 0FBH ; MASK TO RECOGNISE IX/IY TOKENS IXORIY EQU 1AH ; COMMON VALUE OF IX/IY TOKENS INTTOK EQU 90H ; OPERAND TOKEN FOR 'INTEGER' ORGTOK EQU 1 ; TOKEN FOR 'ORG' PSEUDO-OP EQUTOK EQU 2 ; TOKEN FOR 'EQU' PSEUDO-OP DEFLTK EQU 3 ; TOKEN FOR 'DEFL' PSEUDO-OP DEFSTK EQU 7 ; TOKEN FOR 'DEFS' PSEUDO-OP TITTOK EQU 09H ; TOKEN FOR 'TITLE' PSEUDO-OP DEFMTK EQU 08H ; TOKEN FOR 'DEFM' PSUEDO-OP PLUTOK EQU 07H ; TOKEN FOR MONADIC PLUS MINTOK EQU 0FH ; TOKEN FOR MONADIC MINUS LBTOK EQU 0B0H ; TOKEN FOR '(' EXPTOK EQU 35H ; TOKEN FOR EXPONENTIATION ASKTOK EQU 3DH ; TOKEN FOR MULTIPLY MAXFSK EQU 10D ; MAX SIZE OF ARITHMETIC ; FUNCTION STACK MAXASK EQU 20D ; MAX SIZE OF ARITH STACK PLINES EQU 66 ; NO OF LINES ON LIST DEVICE PAGE LBFSZ EQU 64 ; LINE BUFFER CAPACITY ACBSIZ EQU 32 ; SIZE OF ASSD CODE BUFFER TITSIZ EQU 32 ; SIZE OF TITLE BUFFER RECSIZ EQU 16 ; MAX NO OF DATA BYTES PER OBJ RECORD SPERL EQU 5 ; NO OF SYMBOLS PER LINE ; IN SYMBOL TABLE LISTING STKSIZ EQU 68 ; SIZE OF STACK ; CP/M LINKS CPM EQU 5 ;FDOS ENTRY BOOT EQU 0 ;WARM START SETDMA EQU 26 ;CP/M FUNCTION OPNFIL EQU 15 ;OPEN FILE CLSFIL EQU 16 ;CLOSE FILE DELFIL EQU 19 ;DELETE FILE MAKFIL EQU 22 ;CREATE FILE RDNR EQU 20 ;READ NEXT RECORD WRNR EQU 21 ;WRITE NEXT RECORD PRBUF EQU 9 ;PRINT STRING ON CONSOLE DFCB EQU 5CH ;DEFAULT FCB DEFBUF EQU 80H ;DEFAULT BUFFER GETCON EQU 0F009H ;PFM-80 CONSOLE INPUT PUTCON EQU 0F00CH ;PFM-80 CONSOLE OUTPUT CTLZ EQU 1AH ;EOF CHARACTER ;**************************************************************************** ;START OF PROGRAM. ;I/O ROUTINE JUMP TABLE. ;THE USER SHOULD PLACE THE ADDRESSES OF HIS ;OWN I/O SUBROUTINES IN THE LOCATIONS IN ;THIS TABLE CONTAINING THE DESTINATIONS OF ;JP INSTRUCTIONS. ALL I/O IS PERFORMED VIA ;THIS TABLE. ;**************************************************************************** ORG 100H START: JR MAIN ; JUMP PAST JUMP TABLE CI: JP CONIN ; JUMP TO USER CONSOLE IN SUBR CO: JP CONOUT ; JUMP TO USER CONSOLE OUT SUBR LO: JP LSTO ; JUMP TO USER LIST OUT SUBR RI: JP RDRIN ; JUMP TO USER READER IN SUBR PCHO: JP PCHOUT ; JUMP TO USER PUNCH OUT SUBR MEMCHK: JP MEMCK ; JUMP TO USER MEM CHECK SUBR EXEC: JP BOOT ; JUMP TO USER MONITOR ENTRY POINT ;MAIN PROGRAM LOOP. ;**************************************************************************** MAIN: LD SP,0F900H ; SET STACK POINTER CALL INITA ; INITIALIZE ASSEMBLER CALL PHRLD ; PRINT HERALD MAIN1: CALL GTPNO ; GET PASS NO. JP Z,EXEC ; RETURN TO SYSTEM MONITOR LD A,(PASSNO) ; IS IT PASS 1? CP 1 CALL Z,INITA ; IF SO, INITIALIZE CALL PASS ; PERFORM 1 PASS LD HL,AFLAGS ; TEST SYMB TAB OVERFLOW FLAG BIT 2,(HL) ; JR Z,MAIN1 ; JUMP IF NOT SET LD HL,WARNNG ; ELSE PRINT WARNING ON CONSOLE CALL CONST JR MAIN1 ; GO DO ANOTHER PASS ;................................................ WARNNG: DEFB CR ; SYMTAB OVERFLOW WARNING MESSAGE DEFB LF DEFM 'SYMBOL TABLE OVERFLOW' DEFB CR DEFB LF DEFB 0 ;**************************************************************************** ;PRINT HERALD ON CONSOLE DEVICE. ;**************************************************************************** PHRLD: PUSH HL ; SAVE REG LD HL,HERALD ; SET POINTER TO HERALD MESSAGE CALL CONST POP HL ; REPLACE REG RET HERALD: DEFB CR DEFB LF DEFM 'CROWE Z80 ASSEMBLER V1.1' DEFB CR DEFB LF DEFM 'COPYRIGHT PAT CROWE 1978' DEFB CR DEFB LF DEFB 0 ;.............................................. ;PRINT STRING ON CONSOLE DEVICE ;ON ENTRY HL POINTS AT STRING ;END OF STRING MARKER IS 0 ;.............................................. CONST: PUSH BC ; SAVE REG CONST1: LD A,(HL) AND A JR Z,CONST2 LD C,A CALL CO INC HL JR CONST1 CONST2: POP BC ; REPLACE REG RET ;********************************************************************** ;GET PASS NUMBER ;ZERO FLAG SET IF 'Q' TYPED ;********************************************************************** GTPNO: PUSH HL ; SAVE REGISTERS PUSH BC GTPNO1: LD HL,CRLF ; POINT TO CR LF STRING CALL CONST ; OUTPUT STRING TO CONSOLE DEVICE LD HL,PASNO? ; POINT TO 'PASS NO.?' STRING CALL CONST ; OUTPUT STRING TO CONSOLE CALL CI ; GET CHAR FROM CONSOLE KEYBOARD LD C,A ; SAVE IN B AND C REGISTERS LD B,A CALL CO ; ECHO CHAR TO CONSOLE LD A,B CP 'Q' ; QUIT? JR Z,GTPNO2 ; JUMP IF SO CP '1' ; INPUT IN RANGE 1-4 ? JR C,GTPNO1 ; NO, GO ASK FOR ANOTHER CP '5' JR NC,GTPNO1 ; DITTO AND 7 ; MASK TO GET BINARY PASS NO. LD (PASSNO),A ; SAVE IN PASS NO. STORE LD HL,CRLF ; OUTPUT ANOTHER CR LF TO CONSOLE XOR A ; CLEAR ZERO FLAG INC A GTPNO2: POP BC ; REPLACE REGISTERS POP HL RET ; AND RETURN CRLF: DEFB CR DEFB LF DEFB 0 PASNO?: DEFM 'PASS NO. = ' DEFB 0 ;**************************************************************************** ;PERFORM A PASS ;**************************************************************************** PASS: CALL INITP ; INITIALIZE FOR PASS PASS1: CALL INITL ; INITIALIZE FOR LINE CALL GLIN ; GET A LINE CALL GLAB ; GET LABEL JR Z,PASS4 ; JMP IF NO MORE PROC. REQD. CALL GETOR ; GET OPERATOR TOKEN JR Z,PASS4 ; JUMP IF NO MORE PROC. REQD. LD A,(ORTKBF) ; IS OPERATOR 'TITLE'? CP TITTOK ; TOKEN FOR TITLE? JR NZ,PASS2 ; NO, IS OPERATOR 'DEFM'? CALL TITL ; YES, PROCESS ITS OPERAND JR PASS5 PASS2: CP DEFMTK ; TOKEN FOR 'DEFM'? JR NZ,PASS3 CALL DM ; YES, PROCESS ITS OPERAND JR PASS5 PASS3: CALL GTOD ; NEITHER, PROCESS NORMAL OPERANDS JR Z,PASS4 ; JMP IF NO MORE PROC. REQD. PASS5: CALL PTOK ; PROCESS TOKENS PASS4: CALL PFRLO ; PERFORM RELEVANT OUTPUT LD A,(AFLAGS) ; TEST FOR END STATEMENT BIT 1,A JR Z,PASS1 ; GO PROCESS ANOTHER LINE IF NOT RET ;************************************************************************** ;INITIALIZE ASSEMBLER ;************************************************************************** INITA: PUSH HL ; SAVE REGS PUSH BC ; XOR A ; CLEAR ACC LD (TITBUF),A ; EMPTY TITLE BUFFER LD (SYMTAB),A ; CLEAR SYMBOL TABLE LD HL,SYMTAB ; PUT SYMBOL TABLE START ADDR LD (SYMEND),HL ; INTO 'END OF SYMBOL TABLE' STORE LD HL,AFLAGS ; CLEAR SYMTAB OVERFLOW FLAG RES 2,(HL) CALL MEMCHK ; GET HIGHEST AVAIL MEM IN B-A LD HL,MEMTOP ; SAVE IN MEMTOP LD (HL),A INC HL LD (HL),B POP BC ; REPLACE REGS POP HL RET ;**************************************************************************** ;INITIALIZE PASS ;**************************************************************************** INITP: PUSH BC ; SAVE REG XOR A ; CLEAR ACC. LD (OBJCNT),A ; CLEAR OBJECT BUFFER COUNT LD (ADREFC),A ; SET ADDR REF CNTR = 0 LD (ADREFC+1),A LD (PAGE+1),A ; SET PAGE NO. = 1 INC A LD (PAGE),A LD A,PLINES-9 ; SET LINE NO. = MAX SIZE LD (LINE),A LD A,(PASSNO) ; GET PASS NO. CP 3 JR NZ,INITP1 ; JUMP IF NOT CALL RUNOUT ; PUNCH 30 CM RUNOUT LD C,CR ; PUNCH CR CALL PCHO LD C,LF ; PUNCH LF CALL PCHO JR INITP3 INITP1: CP 2 ; PASS 2? JR Z,INITP2 ; JUMP IF SO CP 4 ; PASS 4? JR NZ,INITP3 ; JUMP IF NOT INITP2: LD C,FORMFD ; LIST FORM FEED CALL LO LD C,CR ; LIST CR CALL LO LD C,LF ; LIST 3 LF'S LD B,3 CALL OUTC CALL LFEED ; LIST PAGE HEADER INITP3: POP BC ; REPLACE REG RET ;************************************************************************** ;INITIALIZE LINE ;*************************************************************************** INITL: PUSH BC ; SAVE REGS PUSH HL XOR A ; CLEAR ACC LD HL,ASSCOD ; SET PNTR TO ASSD CODE BUFFER LD B,ACBSIZ ; LOAD CNTR WITH SIZE OF BUFFER INITL1: LD (HL),A ; CLEAR A LOCATION INC HL ; INCR PNTR DJNZ INITL1 ; LOOP UNTIL DONE LD (ASCDNO),A ; SET 'BYTES ASSD CODE' = 0 LD (ODBT1),A ; CLEAR OPERAND TOKEN BUFFERS LD (ODBT2),A LD HL,0 ; CLEAR OPERAND INTEGER BUFFERS LD (ODINT1),HL LD (ODINT2),HL LD (ORTKBF),HL ; CLEAR OPERATOR TOKEN BUFFER LD HL,(ADREFC) ; COPY ADDR REF CNTR LD (ADDISR),HL ; INTO ADDR DIS REG LD HL,AFLAGS ; SET PNTR TO ASSEMBLER FLAGS RES 0,(HL) ; CLEAR ADDR DISCONTINUITY FLAG RES 1,(HL) ; CLEAR 'END' FLAG POP HL POP BC RET ;************************************************************************ ;GET LINE FROM READER ;COPIES LINE OF SOURCE TEXT INTO LINBUF ;ECHOES TO PRINTER IF PASS2 ;************************************************************************* GLIN: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD B,LBFSZ-1 ; SET LINE BUFFER SIZE LD HL,LINBUF ; SET POINTER TO LINE BUFFER LD DE,0 ; CLEAR TAB COUNTER (E) & STATUS REG LD A,SPACE ; PUT SPACE CHAR IN ERROR BUFFER LD (ERRBUF),A LD A,(PASSNO) ; SET 'PASS2' FLAG IF PASS 2 CP 2 JR NZ,GLIN1 SET 0,D GLIN1: CALL RI ; GET CHAR FROM READER LD C,A ; SAVE IT IN C CP CR ; IS IT CR? JR Z,GLIN2 CP HT ; IS IT TAB? JR Z,GLIN3 CP LF ; IS IT LINE FEED? JR Z,GLIN1 ; IGNORE CP NUL ; IS IT A NULL CHAR? JR Z,GLIN1 ; IGNORE CP DEL ; IS IT A DELETE CHAR? JR Z,GLIN1 ; IGNORE AND 60H ; IS IT ANY OTHER CONTROL CHAR? JR NZ,GLIN5 LD C,'I' ; PUT 'ILLEGAL CHAR'IN ERROR DISP CALL ERROR JR GLIN1 GLIN5: LD A,C ; GET CHAR BACK CP ';' ; SET COMMENT FLAG IF ';' JR NZ,GLIN7 SET 1,D GLIN7: LD (HL),A ; PUT IN BUFFER INC HL ; INCREMENT BUFFER POINTER BIT 0,D ; IF PASS 2 FLAG SET, CALL NZ,LO ; OUTPUT CHAR TO LIST DEVICE INC E ; INCREMENT TAB COUNTER GLIN11: DEC B ; BUFFER FULL? JR NZ,GLIN1 GLIN9: CALL RI ; SCAN TO NEXT CR FROM READER CP CR JR NZ,GLIN9 LD (HL),A ; PUT CR IN BUFFER LD C,A ; IF PASS 2 FLAG SET BIT 0,D CALL NZ,LO ; OUTUT CR TO LIST DEVICE BIT 1,D ; REACHED COMMENT BEFORE BUFFER FULL? JR NZ,GLIN4 LD C,'L' ; PUT 'LINE TOO LONG' IN ERROR DISP CALL ERROR JR GLIN4 GLIN2: LD (HL),A ; PUT CR IN BUFFER BIT 0,D ; IF PASS 2 FLAG SET CALL NZ,LO ; OUTPUT TO LIST DEVICE JR GLIN4 GLIN3: LD C,SPACE ; TAB. PUT SPACE IN BUFFER LD (HL),C INC HL BIT 0,D ; IF PASS 2 FLAG SET, CALL NZ,LO ; OUTPUT TO LIST DEVICE INC E ; REACHED NEXT TAB POSITION? LD A,7 AND E JR Z,GLIN11 DEC B ; BUFFER FULL? JR Z,GLIN9 JR GLIN3 GLIN4: POP BC ; REPLACE REGS POP DE POP HL RET ;********************************************************************** ;GET LABEL ;LOCATES LABEL (IF ANY) IN LINBUF AND PUTS IT IN LABBUF. ;LEAVES POINTER TO CHARACTER AFTER LABEL IN LINPNT. ;ZERO SET IF NOTHING ELSE TO PROCESS ;********************************************************************** GLAB: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD HL,LINBUF ; SET POINTER TO LINE BUFFER LD DE,LABBUF ; SET POINTER TO LABEL BUFFER LD B,0 ; CLEAR STATUS REG GLAB1: LD A,(HL) ; SCAN TO FIRST NON SPACE CHAR CP SPACE JR NZ,GLAB2 SET 2,B ; SET 'NOT FIRST COL' FLAG INC HL ; POINT TO NEXT CHAR JR GLAB1 GLAB2: CP CR ; NULL LINE? JR Z,GLAB8 CP ';' ; COMMENT? JR Z,GLAB8 CP 'A' ; IT IS A-Z? JR C,GLAB5 CP 'Z'+1 JR NC,GLAB5 CALL GSYM ; PUT SYMBOL IN BUFFER LD A,(HL) ; FOLLOWED BY ':'? CP ':' JR Z,GLAB3 ; JUMP IF FOLLOWED BY ':' ; I.E. IT'S A LABEL BIT 2,B ; STARTED IN FIRST COLUMN? JR NZ,GLAB6 ; JUMP IF NOT LABEL JR GLAB7 GLAB3: INC HL LD A,(HL) GLAB7: CP SPACE ; FOLLOWED BY SP/CR/;? JR Z,GLAB4 CP CR JR Z,GLAB4 CP ';' JR Z,GLAB4 GLAB5: CALL DNOPS ; RESERVE 4 DEFAULT NOP'S CALL ADJARC ; ADJUST ADDRESS REF COUNTER XOR A ; SET ZERO FLAG JR GLAB8 GLAB6: LD HL,LINBUF ; SET POINTER TO START OF LINBUF XOR A ; SET 'NO LABEL IN BUFFER' LD (LABBUF),A GLAB4: LD (LINPNT),HL ; DEPOSIT LINE POINTER XOR A ; CLEAR ZERO FLAG INC A GLAB8: POP BC ; REPLACE REGS POP DE POP HL RET ;********************************************************************* ;GET OPERATOR TOKEN, ;LOCATES OPERATOR (IF ANY) AND PUTS TOKEN AND VALUE FOR IT IN ORTKBF. ;LEAVES POINTER TO CHARACTER AFTER OPERATOR IN LINPNT ;ZERO FLAG SET IF NOTHING ELSE TO PROCESS. ;********************************************************************** GETOR: PUSH HL ; SAVE REGISTERS PUSH DE PUSH BC EXX PUSH HL PUSH DE PUSH BC LD HL,(LINPNT) ; FETCH PONTER TO LINE BUFFER GETOR1: CALL SCNSP ; SCAN TO FIRST NON SPACE CHAR GETOR5: CP CR ; IS IT CR? JR Z,GETOR2 CP ';' ; IS IT ';'? JP Z,GETOR2 CALL ALPHA ; IS IT A LETTER? JR NC,GETOR3 ; NO, SYNTAX ERROR LD DE,SYMBUF+1 ; SET POINTER TO SYMBOL BUFFER LD B,0 ; SET COUNT = 0 GETOR4: LD (DE),A ; PUT CHAR IN OPERATOR BUFFER INC HL ; INCR LINBUF POINTER INC DE ; INCREMENT SYMBUF POINTER INC B ; INCR CHAR COUNT LD A,5 ; GREATER THAN 5? CP B JR C,GETOR3 ; YES, SYNTAX ERROR LD A,(HL) ; GET NEXT CHAR CALL ALPHA ; IS IT A LETTER JR C,GETOR4 ; YES, LOOP LD A,B ; SAVE # OF OPR CHARS IN SYMBUF LD (SYMBUF),A LD A,(HL) ; FETCH NEXT CHAR AGAIN CP SPACE JP Z,GETOR6 CP CR JR Z,GETOR6 CP ';' JR NZ,GETOR3 ; INVALID SYNTAX GETOR6: EXX ; SET UP PARAMETERS FOR OPTOK LD HL,ORLSTP LD DE,ORTKBF LD C,2 CALL OPTOK ; GET TOKENS FROM LIST EXX JR Z,GETOR3 ; INVALID SYNTAX, NOT IN LIST GETOR2: LD (LINPNT),HL ; DEPOSIT LINE BUFFER POINTER XOR A ; CLEAR ZERO FLAG INC A GETOR7: POP BC ; RECOVER REGISTERS POP DE POP HL EXX POP BC POP DE POP HL RET GETOR3: CALL DNOPS ; RESERVE 4 DEFAULT NOP'S CALL ADJARC ; ADJUST ADDRESS REF COUNTER XOR A ; SET ZERO FLAG JR GETOR7 ;********************************************************************** ;GET OPERAND TOKENS AND VALUES ;LOCATES OPERANDS (IF ANY) AND SETS TOKENS FOR THEM IN ODBT1/ODBT2 ;AND CORRESPONDING INTEGER VALUES (IF ANY) IN ODINT1/ODINT2. ;ZERO FLAG SET IF NOTHING ELSE TO PROCESS ;********************************************************************** GTOD: PUSH IX ; SAVE REGISTERS PUSH IY PUSH HL PUSH DE PUSH BC EXX PUSH HL PUSH DE PUSH BC LD HL,(LINPNT) ; GET LINE BUFFER POINTER LD B,0 ; CLEAR B (OPERAND COUNTER, ; 'BRACKETS' FLAG & 'QUOTE' FLAG) GTOD1: CALL SCNSP ; SCAN TO FIRST NON SPACE CHAR CP ',' ; IS IT A COMMA? JR NZ,GTOD2 BIT 0,B ; YES, FOUND 1 OPERAND? JP Z,GTOD25 ; NO, SYNTAX ERROR INC HL ; YES, SCAN TO NEXT NON SP CHAR CALL SCNSP JR GTOD3 GTOD2: CP ';' ; IS IT A ';'? JP Z,GTOD24 CP CR ; OR A CR? JP Z,GTOD24 GTOD3: PUSH HL ; NO, SET POINTER TO START POP IX ; OF OPERAND IN IX ; SCAN TO NEXT DELIMITER RES 6,B ; CLEAR QUOTE FLAG GTOD4: LD A,(HL) ; GET CHAR IN A CP '''' ; IS IT A '? JR NZ,GTOD18 ; JUMP IF NOT LD A,B ; COMPLEMENT QUOTE FLAG XOR 01000000B LD B,A JR GTOD28 ; AND CONTINUE TO SCAN GTOD18: CP CR ; IS IT CR? JR Z,GTOD5 ; FOUND DELIMITER, JUMP CP SPACE ; IS IT SPACE JR Z,GTOD27 ; JUMP IF SO CP ',' ; IS IT A COMMA? JR Z,GTOD27 ; JUMP IF SO CP ';' ; IS IT ; ? JR NZ,GTOD28 ; CONTINUE SCAN OF NONE OF THESE GTOD27: BIT 6,B ; IS QUOTE FLAG SET? JR Z,GTOD5 ; JUMP IF NOT, FOUND DELIMITER GTOD28: INC HL ; POINT TO NEXT CHAR JR GTOD4 ; AND LOOP ; FOUND DELIMITER GTOD5: PUSH HL ; SET POINTER (IY) TO CHAR POP IY ; AFTER END OF OPERAND INC B ; INCR # OF OPERANDS FOUND LD A,B ; IS IT > 2 ? AND 3 CP 3 JP Z,GTOD25 ; YES, SYNTAK ERROR RES 7,B ; CLEAR BRACKETS FLAG LD A,(IX) ; DOES IT START WITH ( ? CP '(' JR NZ,GTOD6 LD A,(IY-1) ; DOES IT END WITH ) ? CP ')' JR NZ,GTOD6 SET 7,B ; SET BRACKETS FLAG IN B INC IX ; AND CLOSE IN POINTERS DEC IY GTOD6: PUSH IX ; GET POINTER TO START OF OPERAND POP HL LD DE,SYMBUF+1 ; SET POINTER TO SYMBUF LD C,0 ; ZERO CHAR COUNT GTOD10: LD A,(HL) ; FETCH A CHAR CALL ALPHA ; IS IT A LETTER? JR NC,GTOD7 LD (DE),A INC C ; INCR COUNT INC HL ; AND POINTERS INC DE LD A,C CP 3 JR NZ,GTOD10 JR GTOD9 ; MORE THAN 2 LETTERS, GO ; EVALUATE EXPRESSION GTOD7: CP '''' ; NOT LETTER, IS IT '? JR NZ,GTOD8 LD (DE),A ; SAVE IT IN BUFFER INC HL ; POINT TO CHAR FOLLOWING INC C ; INCREMENT COUNT GTOD8: LD A,C ; PUT COUNT IN SYMBUF LD (SYMBUF),A AND A ; IF COUNT=0 THEN JR Z,GTOD9 ; GO TO EVAL EXPRESSION EXX ; GET OPERAND KEYWORK TOKEN LD HL,OPKLST LD DE,TEMP LD C,1 ; 1 BYTE PER TOKEN CALL OPTOK EXX JR Z,GTOD9 ; JUMP IF NO KEYWORD FOUND LD C,A ; SAVE TOKEN IN C CP CTOK ; TOKEN FOR C? JR NZ,GTOD12 LD A,(ORTKBF) BIT 7,A ; IS OPERATOR CONDITIONAL? JR Z,GTOD12 LD C,CCOND ; TOKEN FOR CONDITIONAL 'C' GTOD12: LD A,C ; GET TOKEN AND XYMASK ; IS IT IX/IY ? CP IXORIY JR NZ,GTOD14 LD A,(HL) ; GET FOLLOWING CHAR CP '+' JR Z,GTOD13 CP '-' JR NZ,GTOD14 GTOD13: LD A,C ; CONVERT TOKEN TO DUMMY VALUE AND 0FH OR 0C0H LD C,A PUSH HL ; CLOSE POINTER IN TO START OF EXPRESS POP IX CALL EVAL ; GET VALUE OF EXPRESSION IN HL JR Z,GTOD25 ; SYNTAX ERROR BIT 0,B ; FOUND 1 OPERAND? JR Z,GTOD15 LD (ODINT1),HL ; SAVE VALUE IN 1ST OPERAND BUFFER JR GTOD11 GTOD15: LD (ODINT2),HL ; SAVE VALUE IN 2ND OPND BUFF JR GTOD11 GTOD14: PUSH IY ; END OF OPERAND? POP DE AND A ; CLEAR CARRY FLAG SBC HL,DE JR NZ,GTOD25 ; SYNTAX ERROR JR GTOD11 GTOD9: CALL EVAL ; EVALUATE EXPRESSION ; RESULT IN HL JR Z,GTOD25 ; SYNTAX ERROR BIT 0,B ; FOUND 1 OPERAND? JR Z,GTOD17 LD (ODINT1),HL ; SAVE VALUE IN FIRST OPERAND BUFFER JR GTOD16 GTOD17: LD (ODINT2),HL ; SAVE VALUE IN 2ND OPND BUFF GTOD16: LD C,INTTOK ; SET TOKEN FOR 'INTEGER' GTOD11: BIT 7,B ; WAS IT IN BRACKETS? JR Z,GTOD21 ; NO LD HL,BKLST ; YES, CHECK IF VALID, POINT TO LIST GTOD20: LD A,(HL) ; GET A TOKEN INC HL ; POINT TO REPLACEMENT TOKEN AND A ; IS TOKEN 0 ? JR Z,GTOD25 ; YES, NOT IN LIST, SYN. ERR. CP C ; IS IT EQUAL TO ACTUAL TOKEN? JR Z,GTOD19 ; YES, GO REPLACE IT INC HL ; POINT TO NEXT TOKEN JR GTOD20 GTOD19: LD C,(HL) ; REPLACE TOKEN WITH ; BRACKETTED VERSION. INC IY ; OPEN OUR FINAL POINTER AGAIN GTOD21: LD A,C ; SAVE TOKEN IN RELEVANT BUFFER BIT 0,B ; FOUND 1 OPERAND? JR Z,GTOD22 LD (ODBT1),A ; SAVE TOKEN IN 1ST OPND BUFF JR GTOD23 GTOD22: LD (ODBT2),A ; SAVE TOKEN IN 2ND OPND BUFF GTOD23: PUSH IY ; POINT AT NEXT THING POP HL JP GTOD1 ; GO PROCESS NEXT TOKEN GTOD24: XOR A ; CLEAR ZERO FLAG INC A GTOD26: POP BC ; REPLACE SAVED REGISTERS POP DE POP HL EXX POP BC POP DE POP HL POP IY POP IX RET GTOD25: CALL DNOPS ; APPEND DEFAULT NOP'S CALL ADJARC ; ADJUST ADDRESS REF COUNTER XOR A JR GTOD26 ;************************************************************************ ;EVALUATE AN EXPRESSION ;ON ENTRY AND EXIT: ; IX POINTS AT FIRST CHAR OF EXPRESSION ; IY POINTS AT CHAR AFTER END OF EXPRESSION ;ON EXIT: ; HL CONTAINS VALUE OF EXPRESSION ; AND ZERO FLAG IS SET IF SYNTAX ERROR ;************************************************************************ EVAL: PUSH DE ; SAVE REGISTERS PUSH BC EXX PUSH BC XOR A ; CLEAR ROUTINE FLAG REGISTER LD B,A EXX LD (ARCNT),A ; CLEAR STACKS LD (FCNT),A PUSH IX ; POINT TO START OF EXPR. POP HL EVAL1: PUSH IY ; END OF EXPRESSION? POP DE ; I.E. HL=IY ? EX DE,HL AND A ; CLEAR CARRY SBC HL,DE EX DE,HL JP Z,EOEX ; END OF EXPRESSION JP C,EVAL6 ; END OF EXPRESSION ERROR LD A,(HL) ; GET A CHAR CALL DIGIT ; IS IT A DIGIT? JR C,LIT ; YES, GO PROCESS LITERAL CALL ALPHA ; IS IT A LETTER? JR C,SYMB ; YES, GO PROCESS SYMBOL CP '.' ; IS IT A '.'? JR Z,MCF ; YES, GO PROCESS M/CHAR FUNCTION CP '''' ; IS IT A '? JR Z,ASC ; YES, GO PROC. ASCII CHAR CP '(' ; IS IT A '('? JP Z,LBKT ; YES, GO PROC. LEFT BRKT CP ')' ; IS IT ')'? JP Z,RBKT ; YES, GO PROC. R.H. BRKT CP '$' ; IS IT '$'? JR Z,CURLC ; YES, GO PROC. CURR. LOC. SCHF: CALL PSCF ; PROCESS AS SINGLE CHAR. FUNCTION JP Z,EVAL3 ; INVALID CHAR ERROR JR FUN LIT: CALL PLIT ; PROCESS AS LITERAL JR OPND SYMB: CALL PSYMB JR OPND ASC: CALL PASC ; PROCESS OS ASCII STRING JR OPND CURLC: LD DE,(ADREFC) ; CURRENT VALUE OF ADDR REF ; COUNTER REQUIRED INC HL ; POINT TO NEXT EXPR CHAR JR OPND1 OPND: JP C,EVAL4 ; 'VALUE' ERROR OPND1: CALL PUDE ; PUSH VALUE (IN DE) ONTO ; ARITHMETIC STACK JP Z,EVAL5 ; STACK OVERFLOW ERROR EXX ; SET 'LAST UNIT' FLAG SET 0,B EXX JR EVAL1 MCF: CALL PMCF JP Z,EVAL6 ; SYNTAX ERROR FUN: LD A,(FTOKR) ; GET FUNCTION TOKEN CP PLUTOK ; IS IT TOKEN FOR +? JR Z,FUN1 CP MINTOK ; IS IT TOKEN FOR -? JR NZ,FUN2 ; +/- FUN1: EXX ; WAS LAST UNIT START/(/FUNCTION ? BIT 0,B EXX JR Z,FUN3 ADD A,5DH ; CHANGE TOKEN TO DIADIC LD (FTOKR),A JP FUN3 FUN2: CP 3DH ; DIADIC FUNCTION JR C,FUN3 EXX ; WAS LAST UNIT START/(/FUNCTION? BIT 0,B EXX JP Z,EVAL6 ; SYNTAX ERROR FUN3: CALL POFU ; GET PREVIOUS FUNCTION JR Z,FUN4 ; NO PREVIOUS FUN, PUSH NEW ONE LD E,A ; SAVE TOP OF STACK IN E LD A,(FTOKR) ; GET NEW FUNCTION TOKEN AND 7 ; MASK OFF PRIORITY BITS IN NEW OPR LD B,A ; SAVE IN B LD A,E AND 7 ; MASK OFF PRIORITY BITS OF TOS CP B ; COMPARE PRIORITIES JR NC,FUN5 ; GO DO A FUNCTION ; NEW FUNCTION HAS HIGHER ; PRIORITY SO PUSH IT ON ; STACK. LD A,E ; FIRST PUSH BACK TOP OF STACK CALL PUFU FUN4: LD A,(FTOKR) ; THEN PUSH NEW FUNCTION CALL PUFU JR Z,EVAL5 ; STACK OVERFLOW ERROR EXX ; CLEAR 'LAST UNIT' FLAG RES 0,B EXX JP EVAL1 FUN5: LD A,E ; PUT T O S IN ACC CALL FUNC ; PERFORM A FUNCTION JR Z,EVAL6 ; SYNTAX ERROR JR FUN3 ; GO TRY NEXT FUNCTION ON STACK ;.................................................. LBKT: INC HL ; POINT TO NEXT EXPR CHAR LD A,LBTOK ; SET TOKEN FOR '(' CALL PUFU ; PUSH ON FUNCTION STACK JR Z,EVAL5 ; STACK OVERFLOW ERROR EXX ; CLEAR 'LAST UNIT' FLAG RES 0,B EXX JP EVAL1 ;.................................................. RBKT: INC HL RBKT2: CALL POFU ; POP FUNCTION STACK JR Z,EVAL7 ; EMPTY, BALANCE ERROR CP LBTOK ; IS IT A (? JR Z,RBKT1 CALL FUNC ; PERFORM THE FUNCTION JR Z,EVAL6 ; SYNTAX ERROR JR RBKT2 ; MORE OPS TO DO ? RBKT1: EXX ; SET 'LAST UNIT' FLAG SET 0,B EXX JP EVAL1 ;................................................. ; END OF EXPRESSION EOEX: CALL POFU ; POP FUNCTION STACK JR Z,EOEX1 ; NO MORE FUNCTIONS CP LBTOK JR Z,EVAL7 ; BALANCE ERROR CALL FUNC ; PERFORM THE FUNCTION JR Z,EVAL6 ; SYNTAX ERROR JR EOEX EOEX1: CALL PODE ; GET EXPR VALUE IN DE JR Z,EVAL6 ; SYNTAX ERROR (STACK EMPTY) LD A,(ARCNT) ; CHECK IF STACK NOW EMPTY AND A JR NZ,EVAL6 ; SYNTAX ERROR EX DE,HL EXX BIT 1,B ; TEST FOR ARITH OVERFLOW EXX JR Z,EOEX2 LD C,'A' EOEX4: CALL ERROR ; INDICATE ARITH OVERFLOW EOEX2: XOR A ; CLEAR ZERO FLAG INC A EOEX3: EXX POP BC EXX POP BC POP DE RET EVAL3: LD C,'I' JR EVAL8 EVAL4: LD C,'V' ; VALUE ERROR LD HL,0 ; SET RESULT=0 JR EOEX4 ; NOT FATAL EVAL5: LD C,'O' ; STACK OVERFLOW ERROR JR EVAL8 EVAL6: LD C,'S' ; SYNTAX ERROR JR EVAL8 EVAL7: LD C,'B' ; BALANCE ERROR EVAL8: CALL ERROR ; SET ERROR INDICATOR XOR A ; SET ZERO (ERROR) FLAG JR EOEX3 ; AND PREPARE TO EXIT ;********************************************************************** ;PROCESS LITERAL. ;THIS SUBROUTINE INCLUDES PBIN, PDEC, ;PHEX, POCT. ;ON ENTRY: ; HL POINTS TO FIRST CHAR OF LITERAL ;ON EXIT: ; HL POINTS TO CHAR AFTER LITERAL ; DE CONTAINS VALUE OF LITERAL ; CARRY FLAG IS SET FOR VALUE ERROR ;********************************************************************** PLIT: PUSH HL ; SAVE POINTER TO START OF LIT. PLIT1: LD A,(HL) ; GET CHAR CALL HEXDG ; IS IT VALID DIG FOR LIT.? JR NC,PLIT2 INC HL ; YES, POINT TO NEXT CHAR JR PLIT1 PLIT2: DEC HL ; NO, GO BACK TO LAST CHAR LD A,(HL) ; FETCH IT TO ACC. POP HL ; REPLACE POINTER TO START OF LIT. CP 'B' ; WAS FINAL CHAR 'B' JP Z,PBIN ; BINARY LITERAL CP 'D' ; 'D'? JP Z,PDEC ; DECIMAL LITERAL CP 'H' ; 'H'? JP Z,PHEX ; HEX LITERAL CP 'O' ; 'O'? JP Z,POCT ; OCTAL LITERAL CP 'Q' ; 'Q'? JP Z,POCT ; OCTAL LITERAL JP PDEC ; DECIMAL LITERAL ;********************************************************************** ;PROCESS BINARY LITERAL. ;********************************************************************** PBIN: PUSH BC ; SAVE REGISTERS LD DE,0 ; CLEAR 16 BIT ACC. PBIN1: LD A,(HL) ; GET CHAR CALL HEXDG ; VALID IN A LITERAL? JR NC,PBIN2 CP '1'+1 ; VALID IN BINARY LIT.? JR NC,PBIN2 SUB '0' ; CONVERT ASCII TO BINARY LD C,A CALL SHLDE ; SHIFT DE LEFT CALL ADCDE ; & ADD NEW DIG. TO DE INC HL ; INCREMENT POINTER TO NEXT CHAR. JR PBIN1 PBIN2: CP 'B' ; CHAR NOT BIN. DIG.. IS IT 'B'? JR NZ,PBIN4 INC HL ; YES, POINT TO NEXT CHAR LD A,(HL) ; GET IT IN ACC CALL HEXDG ; VALID CHAR FOR A LIT.? PBIN3: POP BC RET PBIN4: SCF ; SET CARRY FOR ERROR JR PBIN3 ;********************************************************************** ;PROCESS OCTAL LITERAL ;********************************************************************** POCT: PUSH BC LD DE,0 ; CLEAR 16 BIT ACC. POCT1: LD A,(HL) ; GET CHAR CALL HEXDG ; VALID IN LITERAL? JR NC,POCT3 CP '7'+1 ; VALID IN OCTAL LIT.? JR NC,POCT3 SUB '0' ; CONVERT ASCII TO BINARY LD C,A LD B,3 ; SHIFT DE LEFT 3 TIMES POCT2: CALL SHLDE DEC B ; DONE 3 SHIFTS YET? JR NZ,POCT2 CALL ADCDE ; ADD NEW DIGIT TO DE INC HL ; INCR POINTER TO NEXT CHAR JR POCT1 POCT3: CP 'O' ; CHAR NOT OCT DIG. IS IT 'O'? JR Z,POCT4 CP 'Q' ; IS IT 'Q'? JR NZ,POCT6 POCT4: INC HL ; YES, POINT TO NEXT CHAR LD A,(HL) ; GET IT IN ACC CALL HEXDG ; VALID CHAR IN A LIT.? POCT5: POP BC RET POCT6: SCF ; SET CARRY FOR ERROR JR POCT5 ;********************************************************************* ;PROCESS DECIMAL LITERAL. ;********************************************************************* PDEC: PUSH BC LD DE,0 ; CLEAR 16 BIT ACC. PDEC1: LD A,(HL) ; GET CHAR CALL HEXDG ; VALID IN A LIT.? JR NC,PDEC2 CP '9'+1 ; VALID IN A DEC. LIT.? JR NC,PDEC2 SUB '0' ; CONVERT ASCII TO BINARY LD C,A LD B,0 PUSH BC LD B,D LD C,E CALL SHLDE ; DE X 2 CALL SHLDE ; DE X 4 CALL ADCDE ; DE X 5 CALL SHLDE ; DE X 10 POP BC ; RECOVER NEW DIGIT CALL ABCDE ; ADD IN NEW DIGIT INC HL ; POINT TO NEXT CHAR JR PDEC1 PDEC2: CP 'D' JR NZ,PDEC3 INC HL LD A,(HL) ; GET IT IN ACC PDEC3: CALL HEXDG POP BC RET ;******************************************************************* ;PROCESS HEXADECIMAL LITERAL. ;******************************************************************* PHEX: PUSH BC LD DE,0 ; CLEAR 16 BIT ACC. PHEX1: LD A,(HL) ; GET CHAR CALL HEXDG ; VALID IN A LITERAL? JR NC,PHEX4 CP 'F'+1 ; VALID IN A HEX LIT.? JR NC,PHEX4 SUB '0' ; CONVERT ASCII TO BINARY CP 10D JR C,PHEX2 SUB 'A'-'0'-10D PHEX2: LD C,A LD B,4 ; SHIFT DE LEFT 4 TIMES PHEX3: CALL SHLDE DEC B ; DONE4 SHIFTS YET? JR NZ,PHEX3 CALL ADCDE ; ADD NEW DIGIT TO DE INC HL ; INCREMENT POINTER TO NEXT CHAR JR PHEX1 PHEX4: CP 'H' ; CHAR NOT HEX. IS IT 'H'? JR NZ,PHEX6 ; NO INC HL ; YES, POINT TO NEXT CAR LD A,(HL) ; GET IT IN ACC CALL HEXDG ; VALID CHAR FOR A LIT.? PHEX5: POP BC RET PHEX6: SCF ; SET CARRY FOR ERROR JR PHEX5 ;******************************************************************* ;HEXDG. IS CHAR IN ACC VALID IN A LITERAL. ;CARRY SET IF HEX DIGIT OR H/O/Q. ;******************************************************************* HEXDG: CALL DIGIT ; CARRY SET IF 0-9 RET C CP 'A' JR C,HEXDG1 CP 'F'+1 RET C CP 'H' JR Z,HEXDG2 CP 'O' JR Z,HEXDG2 CP 'Q' JR Z,HEXDG2 HEXDG1: AND A ; NOT HEX DIG., CLEAR CARRY RET HEXDG2: SCF ; HEX DIGIT, SET CARRY RET ;********************************************************************* ;SHIFT DE LEFT 1 BIT - ENTER 0 FROM RIGHT. ;SET 'VALUE' ERROR IF OVERFLOW. ;********************************************************************* SHLDE: EX DE,HL ; DO SHIFT BY ADDITION IN HL ADD HL,HL EX DE,HL RET NC ; NO CARRY, SO RETURN PUSH BC ; CARRY, SO INDICATE 'V' ERROR LD C,'V' CALL ERROR POP BC RET ;********************************************************************* ;ADD BC TO DE - SET 'VALUE' ERROR IF OVERFLOW. ;********************************************************************* ABCDE: PUSH BC EX DE,HL ; DO ADDITION IN HL ADD HL,BC ; DO ADDITION EX DE,HL ; GET RESULT BACK TO DE JR NC,ABCDE1 LD C,'V' ; CARRYOUT SO INDICATE 'V' ERROR CALL ERROR ABCDE1: POP BC RET ;********************************************************************* ;ADD C TO DE - NO OVERFLOW INDICATION ;********************************************************************* ADCDE: PUSH BC EX DE,HL LD B,0 ADD HL,BC EX DE,HL POP BC RET ;********************************************************************* ;PROCESS SYMBOL. ;GET SYMBOL AND FETCH ITS VALUE FROM THE SYMBOL TABLE. RETURN VALUE ;IN DE. ;******************************************************************** PSYMB: PUSH BC ; SAVE REGISTERS LD DE,SYMBUF ; SET PNTR TO SYMBOL BUFFER CALL GSYM ; GET SYMB FROM LINE TO SYMBUF PUSH HL ; SAVE PNTR TO CHAR AFTER SYMB CALL LOCATE ; FIND SYMB IN SYMTAB JR NZ,PSYMB1 ; NOT IN TABLE? LD E,(HL) ; MOVE VALUE TO DE INC HL LD D,(HL) JR PSYMB2 PSYMB1: LD C,'U' ; INDICATE 'UNDEFINED' ERROR CALL ERROR LD DE,0 ; SET DE=0 DEFAULT VALUE PSYMB2: POP HL ; REPLACE REGISTERS POP BC AND A ; CLEAR CARRY FLAG SO RET ; AS NOT TO INDICATE 'VALUE' ERROR ;********************************************************************* ;PROCESS ASCII LITERAL. ;RETURN VALUE OF 1 OR 2 ASCII CHARACTERS. ;ON ENTRY: ; HL POINTS TO START QUOTE ;ON EXIT: ; HL POINTS TO CHAR AFTER CLOSE QUOTE ; DE CONTAINS VALUE ; CARRY FLAG SET IF ERROR ;*********************************************************************** PASC: LD DE,0 ; CLEAR 16 BIT ACC. DE INC HL ; POINT TO CHAR AFTER QUOTE CALL DOUBQ ; IS NEXT CHAR CLOSING QUOTE? JR NZ,PASC2 ; JUMP IF SO LD E,(HL) ; OTHERWISE SAVE CHAR IN E INC HL ; POINT TO NEXT CHAR CALL DOUBQ ; NEXT CHAR CLOSE QUOTE? JR NZ,PASC2 ; JUMP IF SO LD D,(HL) ; OTHERWISE SAVE IN D INC HL ; POINT TO NEXT CHAR CALL DOUBQ ; NEXT CHAR CLOSE QUOTE? JR NZ,PASC2 ; JUMP IF SO PASC1: SCF ; ERROR, SET CARRY RET PASC2: AND A ; NO ERROR, CLEAR CARRY RET ;...................................................... ;DOUBLE QUOTE. ;IS NEXT ITEM IN STRING A CHARACTER OF THE END OF THE ASCII ;LITERAL? ON ENTRY: HL POINTS AT THE NEXT ITEM, ON EXIT: HL ;HAS BEEN INCREMENTED IF DOUBLE QUOTE. ZERO SET IF CHAR. ;...................................................... DOUBQ: LD A,(HL) ; GET CHAR CP '''' ; IS IT A QUOTE? JR NZ,DOUBQ1 ; JUMP IF NOT INC HL ; POINT TO NEXT CHAR LD A,(HL) ; GET IT CP '''' ; IS IT A QUOTE? RET ; ZERO SET FOR CHAR ; CLEARED IF LAST QUOTE WAS ; CLOSE QUOTE. DOUBQ1: XOR A ; LIT CHAR. SET ZERO. RET ;******************************************************************** ;PROCESS MULTI-CHAR FUNCTION. ;ON ENTRY: ; HL POINTS TO FIRST CHAR OF FUNCTION STRING ;ON EXIT: ; HL POINTS TO CHAR AFTER FUNCTION STRING ; FTOKR CONTAINS TOKEN FOR FUNCTION ; ZERO FLAG SET FOR ERROR ;******************************************************************** PMCF: PUSH BC ; SAVE REGISTERS PUSH DE INC HL ; POINT TO CHAR AFTER '.' LD A,(HL) ; GET IT CALL ALPHA ; IS IT A LETTER? JR NC,PMCF1 ; NO, SYNTAX ERROR LD DE,SYMBUF ; SET POINTER TO SYMBUF CALL GSYM ; GET FUNCTION IN SYMBUF INC HL ; INCR PNTR PUSH HL ; AND SAVE IT ON STACK CP '.' ; WAS CHAR AFT. FUN. '.'? JR NZ,PMCF2 ; JUMP IF NOT LD A,(SYMBUF) ; GET NO OF CHARS CP 5 ; MORE THAN 4? JR NC,PMCF2 ; JUMP IF SO LD DE,FTOKR ; PNTR TO TOKEN REG. LD HL,MFLSTP ; PNTR TO OPR LIST LD C,1 ; 1 TOKEN/ENTRY IN LIST CALL OPTOK ; GET TOKEN JR PMCF3 PMCF1: XOR A ; SET ZERO TO INDICATE ERR. JR PMCF4 PMCF2: XOR A ; SET ZERO TO INDICATE ERROR PMCF3: POP HL PMCF4: POP DE POP BC RET ;*********************************************************************** ;PROCESS SINGLE CHAR FUNCTION. ;ON ENTRY: ; HL POINTS AT FUNCTION CHAR ;ON EXIT: ; HL POINTS TO CHAR AFTER FUNCTION CHAR(S) ; FTOKR CONTAINS TOKEN FOR FUNCTION ; ZERO FLAG SET IF ERROR ;*********************************************************************** PSCF: PUSH BC ; SAVE REGISTERS PUSH DE LD B,(HL) ; GET POTENTIAL FUNCTION INC HL ; & INCR PNTR LD DE,SCF1 ; SET UP POINTER TO LIST PSCF1: LD A,(DE) ; GET LIST ENTRY AND A ; IS IT ZERO? JR Z,PSCF3 ; END OF LIST, INVAL. CHAR CP B ; MATCH? INC DE ; INCR. PNTR. TO TOKEN JR Z,PSCF2 ; JUMP IF MATCH INC DE ; OTHERWISE POINT TO NEXT ENTRY JR PSCF1 ; LOOP PSCF2: LD A,(DE) ; GET THE TOKEN LD (FTOKR),A ; & PUT IN TOKEN REG. CP ASKTOK ; IS IT * ?(MAYBE **) JR NZ,PSCF4 ; JUMP IF NOT LD A,(HL) ; GET NEXT CHAR CP '*' ; IS IT '*'? JR NZ,PSCF4 ; JUMP IF NOT LD A,EXPTOK ; PUT TOKEN FOR ** IN REG LD (FTOKR),A INC HL ; AND INCR PNTR AND A ; CLEAR ZERO FLAG JR PSCF4 PSCF3: XOR A ; SET ZERO TO INDICATE ERROR PSCF4: POP DE ; REPLACE REGS POP BC RET ;*********************************************************************** ;PUSH ACC TO FUNCTION STACK. ;BYTE IN A IS PUSHED ONTO THE FUNCTION ;STACK (FSTK). IF NOT POSSIBLE OWING TO ;THE STACK BEING FULL, THEN THE ZERO FLAG ;IS SET ON EXIT. ;*********************************************************************** PUFU: PUSH HL ; SAVE REGISTERS PUSH BC EX AF,AF' ; SAVE FUNCTION LD HL,FSTK ; LOAD START OF STACK ADDR LD A,(FCNT) ; GET STACK COUNTER CP MAXFSK ; IS STACK FULL? JR NC,PUFU2 LD C,A ; COMPUTE TOP OF STACK LD B,0 ADD HL,BC ; TOP OF STACK IN HL INC A ; INCREMENT STACK COUNTER LD (FCNT),A ; AND STORE NEW VALUE EX AF,AF' ; GET FUNCTION BACK LD (HL),A ; PUSH ONTO FUNCTION STACK XOR A ; CLEAR ZERO FLAG INC A PUFU1: POP BC ; REPLACE REGISTERS POP HL RET PUFU2: XOR A ; SET ZERO FLAG (STACK FULL) JR PUFU1 ;*********************************************************************** ;POP FROM FUNCTION STACK TO ACC ;THE TOP BYTE ON THE FUNCTION STACK IS ;POPPED INTO THE A REG. IF THE STACK WAS ;ALREADY EMPTY, THE ZERO FLAG IS SET ON ;EXIT ;*********************************************************************** POFU: PUSH HL ; SAVE REGS. PUSH BC LD HL,FSTK ; LOAD START OF STACK ADDR LD A,(FCNT) ; GET STACK COUNTER AND A ; TEST FOR EMPTY STACK JR Z,POFU1 DEC A LD (FCNT),A LD C,A LD B,0 ADD HL,BC XOR A ; CLEAR ZERO FLAG INC A LD A,(HL) ; GET STACK TOP TO ACC POFU1: POP BC ; REPLACE REGS. POP HL RET ;*********************************************************************** ;PUSH FROM DE TO ARITHMETIC STACK ;THE WORD IN DE IS PUSHED ONTO THE ;ARITHMETIC STACK. IF NOT POSSIBLE ;OWING TO THE STACK BEING FULL, THEN ;THE ZERO FLAG IS SET ON EXIT. ;*********************************************************************** PUDE: PUSH HL ; SAVE REGS. PUSH BC LD HL,ARSTK ; LOAD START OF STACK ADDR LD A,(ARCNT) ; GET STACK COUNTER CP MAXASK ; IS STACK FULL? JR NC,PUDE2 LD C,A ; COMPUTE TOP OF STACK LD B,0 ADD HL,BC ; TOP OF STACK IN HL ADD A,2 ; INCREMENT COUNTER BY 1 WORD LD (ARCNT),A ; STORE NEW VALUE OF COUNTER LD (HL),E ; PUSH DE ONTO STACK INC HL LD (HL),D XOR A ; CLEAR ZERO FLAG INC A PUDE1: POP BC POP HL RET PUDE2: XOR A ; SET ZERO FLAG (ERROR) JR PUDE1 ;********************************************************************** ;POP FROM ARITHMETIC STACK TO DE ;THE TOP WORD ON THE ARITHMETIC STACK ;IS POPPED INTO THE DE REG PAIR. IF ;THE STACK WAS EMPTY, THEN THE ZERO ;FLAG IS SET ON EXIT ;********************************************************************** PODE: PUSH HL ; SAVE REGS PUSH BC LD HL,ARSTK ; LOAD START OF STACK ADDR LD A,(ARCNT) ; GET STACK COUNTER AND A ; IS STACK EMPTY? JR Z,PODE1 SUB 2 ; DECR STACK COUNTER LD (ARCNT),A ; AND SAVE NEW VALUE LD C,A ; COMPUTE TOP OF STACK LD B,0 ADD HL,BC LD E,(HL) ; POP STACK TO DE INC HL LD D,(HL) XOR A ; CLEAR ZERO FLAG INC A PODE1: POP BC ; REPLACE REGS POP HL RET ;********************************************************************* ;PERFORM A FUNCTION ;ON ENTRY: ; A CONTAINS THE COMBINED FUNCTION ; TOKEN/PRIORITY VALUE. ;ON EXIT: ; THE REQUIRED ASSEMBLY TIME FUNCTION ; HAS BEEN PERFORMED USING VALUE(S) ; ON THE ARITHMETIC STACK AND LEAVING ; THE RESULT THERE. ; IF THE STACK DID NOT CONTAIN ENOUGH ; VALUES THEN THE ZERO FLAG IS SET. ; ;THE FOLLOWING SUBROUTINES STARTING WITH ;THE LETTER F ARE ALL ASSEMBLY TIME ;ARITHMETIC/LOGIC FUNCTIONS, OPERATING ON ;THE ARITHMETIC STACK, AND BEING CALLED ;INDIRECTLY BY FUNC ;******************************************************************** FUNC: PUSH HL ; SAVE REGS. PUSH DE PUSH BC SRL A ; GET (FUNC TOKEN)*2 SRL A AND 0FEH LD C,A ; COMPUTE POINTER TO SUBROUTINE LD B,0 ; START ADDR POINTER LD HL,FUNLST ADD HL,BC LD E,(HL) ; PUT SUBR START ADDR IN HL INC HL LD D,(HL) EX DE,HL LD DE,FUNC1 ; CALL RELEVANT FUNCTION INDIRECTLY PUSH DE JP (HL) FUNC1: POP BC POP DE POP HL RET ;............................................................. ;FUNCTION LIST. ;CONTAINS POINTERS TO THE FUNCTION ;SUBROUTINES, USED BY SUBR 'FUNC' ;FOR AN INDIRECT SUBR CALL BASED ON ;THE VALUE OF THE ARITHMETIC ;FUNCTION TOKEN. ;............................................................. FUNLST: DEFW FMNPL DEFW FMNMN DEFW FNOT DEFW FHIGH DEFW FLOW DEFW FRES DEFW FEXP DEFW FMULT DEFW FDIV DEFW FMOD DEFW FSHR DEFW FSHL DEFW FDIPL DEFW FDIMN DEFW FAND DEFW FOR DEFW FXOR DEFW FEQ DEFW FGT DEFW FLT DEFW FUGT DEFW FULT ;************************************************************** ;FUNCTION MONADIC PLUS. ;************************************************************** FMNPL: PUSH DE ; SAVE REG CALL PODE ; SEE IF VALUE AVAILABLE ON STACK JR Z,FMNPL1 ; JUMP IF NOT (ZERO SET) CALL PUDE ; PUSH BACK ON STACK FMNPL1: POP DE ; REPLACE REG RET ;************************************************************** ;FUNCTION MONADIC MINUS. ;************************************************************** FMNMN: PUSH DE ; SAVE REGS. PUSH HL CALL PODE ; GET VALUE OFF ARITH STACK JR Z,FMNMN1 ; JUMP IF EMPTY LD HL,0 ; PUT 0 INTO HL AND A ; CLEAR CARRY SBC HL,DE ; SUBTRACT VALUE FROM 0 EX DE,HL ; GET RESULT IN DE CALL PUDE ; PUSH BACK ON STACK FMNMN1: POP HL ; REPLACE REGS. POP DE RET ;************************************************************** ;FUNCTION NOT ;************************************************************** FNOT: PUSH DE ; SAVE REG. CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FNOT1 ; JUMP IF EMPTY LD A,D ; COMPLEMENT DE CPL LD D,A LD A,E CPL LD E,A CALL PUDE ; PUSH BACK ON ARITH STACK FNOT1: POP DE ; REPLACE REG. RET ;************************************************************** ;FUNCTION HIGH. ;RETURNS HIGH BYTE OF ARGUMENT AS RESULT. ;************************************************************** FHIGH: PUSH DE ; SAVE REGISTERS CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FHIGH1 ; ERROR IF EMPTY LD E,D ; PUT HIGH BYTE IN DE LD D,0 CALL PUDE ; PUSH RESULT ON ARITH STACK FHIGH1: POP DE RET ;************************************************************** ;FUNCTION LOW. ;RETURNS LOW BYTE OF ARGUMENT AS RESULT. ;************************************************************** FLOW: PUSH DE ; SAVE REGISTERS CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FLOW1 ; ERROR IF EMPTY LD D,0 ; LOW BYTE ONLY REQD CALL PUDE ; PUSH BACK RESULT FLOW1: POP DE ; REPLACE REGS RET ;*************************************************************** ;FNCTION RESULT ;CLEARS ARITHMETIC OVERFLOW FLAG ;*************************************************************** FRES: EXX ; CLEAR OVERFLOW FLAG RES 1,B ; BIT 1 IN REG B EXX RET ;*************************************************************** ;FUNCTION EXPONENTIATE ;*************************************************************** FEXP: PUSH HL ; SAVE REGS PUSH DE CALL PODE ; GET EXPONENT FROM STACK JR Z,FEXP5 ; JMP IF ARITH STACK EMPTY EX DE,HL ; PUT EXPONENT IN HL CALL PODE ; GET OTHER NUMBER IN DE JR Z,FEXP5 ; JUMP IF STACK EMPTY LD A,H ; EXPONENT ZERO? OR L JR NZ,FEXP1 ; JUMP IF NOT LD DE,1 ; RESULT = 1 CALL PUDE ; PUSH IT ON STACK JR FEXP5 FEXP1: BIT 7,H ; EXPONENT NEGATIVE? JR Z,FEXP2 ; JUMP IF NOT LD DE,0 ; RESULT = 0 CALL PUDE ; PUSH IT ON STACK JR FEXP5 FEXP2: CALL PUDE ; PUSH THE NUMBER FEXP3: DEC HL ; DECR EXPONENT LD A,H ; IS IT ZERO NOW? OR L JR Z,FEXP4 ; JUMP IF SO CALL PUDE ; PUSH THE NUMBER CALL FMULT ; & MULTIPLY JR FEXP3 ; LOOP FEXP4: XOR A ; CLEAR ZERO FLAG INC A FEXP5: POP DE ; REPLACE REGISTERS POP HL RET ; ******************************************************************* ; FUNCTION MULTIPLY ; ******************************************************************* FMULT: PUSH HL ; SAVE REGISTERS PUSH DE PUSH BC EXX PUSH DE LD E,0 ; CLEAR E' (SIGN FLAG) EXX CALL PODE ; GET A VALUE FROM ARITH STACK JR Z,FMULT6 ; JUMP IF EMPTY BIT 7,D ; IS IT NEGATIVE? CALL NZ,NEGDE ; IF SO, NEGATE, AND COMPLEMENT ; SIGN FLAG EX DE,HL CALL PODE ; GET ANOTHER VALUE FROM STACK JR Z,FMULT6 ; JUMP IF EMPTY BIT 7,D ; IS IT -VE CALL NZ,NEGDE ; IF SO, NEGATE, AND COMPL. ; SIGN FLAG AND A ; CLEAR CARRY SBC HL,DE ; TEST FOR LARGER NO. ADD HL,DE ; MULTIPLIER SHOULD BE SMALLER JR NC,FMULT1 ; JUMP IF CORRECT EX DE,HL ; OTHERWISE SWAP NOS. FMULT1: LD B,H ; PUT MULTIPLICAND IN BC LD C,L LD HL,0 ; CLEAR HL FOR ACCUMALATOR FMULT2: LD A,D ; IS MULTIPLIER 0? OR E JR Z,FMULT5 ; JUMP IF FINISHED SRL D ; SHIFT DE RIGHT INTO CARRY RR E JR NC,FMULT4 ; JUMP IF ZERO CARRY AND A ; CLEAR CARRY ADC HL,BC ; ADD MULTIPLICAND TO RUNNING TOTAL JP M,FMULT3 ; JUMP IF OVERFLOW TO BIT 15 JR NC,FMULT4 ; JUMP IF NO O/F TO BIT 16 FMULT3: EXX ; SET OVERFLOW FLAG SET 1,B EXX FMULT4: SLA C ; SHIFT MULTIPLICAND LEFT RL B JR FMULT2 ; LOOP FMULT5: EX DE,HL ; GET RESULT BACK IN DE EXX ; SHOULD RESULT BE -VE? BIT 0,E ; (PRODUCT SIGN IN E') EXX CALL NZ,NEGDE CALL PUDE ; PUSH PRODUCT ONTO ARITH STACK FMULT6: EXX ; REPLACE REGS. POP DE EXX POP BC POP DE POP HL RET ;*********************************************************************** ;FUNCTION DIVIDE ;*********************************************************************** FDIV: PUSH HL ; SAVE REGISTERS PUSH DE CALL PODE ; GET DIVISOR FROM ARITH STACK JR Z,FDIV1 ; JUMP IF EMPTY EX DE,HL ; PUT IN HL CALL PODE ; GET DIVIDEND FROM ARITH STACK JR Z,FDIV1 ; JUMP IF EMPTY CALL DIV ; DO THE DIVISION CALL PUDE ; PUSH QUOTIENT (IN DE) ONTO STACK FDIV1: POP DE ; REPLACE REGISTERS POP HL RET ;********************************************************************** ;FUNCTION MODULO ;********************************************************************** FMOD: PUSH HL ; SAVE REGISTERS PUSH DE CALL PODE ; GET DIVISOR FROM ARITH STACK JR Z,FMOD1 ; JUMP IF EMPTY EX DE,HL ; PUT IN HL CALL PODE ; GET DIVIDEND FOM ARITH STACK JR Z,FMOD1 ; JUMP IF EMPTY CALL DIV ; DO THE DIVISION EX DE,HL ; GET REMAINDER IN DE CALL PUDE ; PUSH ONTO ARITH STACK FMOD1: POP DE ; REPLACE REGISTERS POP HL RET ;********************************************************************** ;DIVIDE ;THIS SUBROUTINE IS USED BY FDIV AND FMOD ;IT DIVIDES DE BY HL, LEAVING THE QUOTIENT ;IN DE AND THE REMAINDER IN HL. ;SIGNED 16 BIT ARITHMETIC IS USED. ;********************************************************************** DIV: PUSH BC ; SAVE REGISTERS EXX PUSH DE LD DE,0 ; CLEAR DE' (D'=PLACE COUNT) ; (E'=SIGN COUNT) EXX BIT 7,D ; IS DIVIDEND -VE? JR Z,DIV1 ; JUMP IF NOT EXX ; OTHERWISE FLAG IN E', BIT 7 SET 7,E ; TO GIVE SIGN OF REMAINDER EXX DIV1: BIT 7,D ; IS DIVIDEND -VE? CALL NZ,NEGDE ; IF SO NEGATE, AND INCR ; QUOTIENT SIGN BIT (E' BIT 0) EX DE,HL ; SWAP NOS. BIT 7,D ; IS DIVISOR -VE? CALL NZ,NEGDE ; IF SO NEGATE AND ; INCR QUOTIENT SIGN FLAG LD A,D ; IS DIVISOR ZERO? OR E JR NZ,DIV2 ; JUMP IF NOT LD C,'Z' ; FLAG 'DIV BY ZERO' ERROR CALL ERROR LD HL,0 ; RETURN ZERO RESULTS LD DE,0 JR DIV6 ; GO TO END DIV2: EXX ; INCR PLACE COUNT INC D EXX SLA E ; SHIFT DIVISOR LEFT UNTIL SIGN RL D ; SET, COUNTING NO. OF PLACES JP P,DIV2 LD BC,0 ; CLEAR QUOTIENT REG BC DIV3: SLA C ; SHIFT QUOTIENT LEFT RL B SRL D RR E AND A ; CLEAR CARRY SBC HL,DE ; SUBTRACT DIVISOR FROM DIVIDEND JR C,DIV4 ; JUMP IF TOO MUCH SUBTRACTION INC BC ; OTHERWISE INCR QUOTIENT JR DIV5 DIV4: ADD HL,DE ; REPLACE EXCESSIVE SUBTRACTION DIV5: EXX ; DECR PLACE COUNT DEC D EXX JR NZ,DIV3 ; LOOP IF NOT FINISHED LD D,B ; TRANSFER QUOTIENT TO DE LD E,C EX DE,HL ; SWAP WITH REMAINDER EXX ; GET SIGN FLAGS INTO C LD A,E EXX LD C,A BIT 7,C ; WAS DIVIDEND -VE? CALL NZ,NEGDE ; NEGATE REMAINDER IF SO EX DE,HL ; SWAP BACK NOS. BIT 0,C ; IS QUOTIENT -VE? CALL NZ,NEGDE ; NEGATE IF SO DIV6: EXX ; REPLACE REGISTERS POP DE EXX POP BC RET ;************************************************************************* ;NEGATE DE ;USED BE FMULT AND DIV TO NEGATE CONTENTS OF DE ;AND COMPLEMENT A SIGN FLAG HELD IN E' BIT 0 ;************************************************************************* NEGDE: PUSH HL ; SAVE HL LD HL,0 ; NEGATE SIGNED NO. IN DE AND A ; CLEAR CARRY SBC HL,DE ; SUBTRACT DE FROM 0 EX DE,HL ; GET RESULT INTO DE EXX ; COMPLEMENT PRODUCT SIGN ; BIT IN E' RR E CCF RL E EXX POP HL RET ;************************************************************************ ;FUNCTION SHIFT RIGHT. ;************************************************************************ FSHR: PUSH DE ; SAVE REGS. PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FSHR3 ; ERROR IF EMPTY EX DE,HL ; OTHERWISE PUT IN HL CALL PODE ; GET VALUE TO BE SHIFTED JR Z,FSHR3 ; JUMP IF EMPTY, ERROR FSHR1: LD A,H ; TEST HL FOR ZERO OR L ; AND CLEAR CARRY JR Z,FSHR2 ; JUMP IF NO MORE SHIFTING SRL D ; SHIFT DE RIGHT ONE BIT RR E DEC HL ; DECR NO. OF SHIFTS REQD JR FSHR1 ; LOOP FSHR2: CALL PUDE ; PUSH RESULT BACK ON STACK FSHR3: POP HL ; REPLACE REGS POP DE RET ;*********************************************************************** ;FUNCTION SHIFT LEFT ;*********************************************************************** FSHL: PUSH DE ; SAVE REGS. PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FSHL3 ; JUMP IF EMPTY, ERROR EX DE,HL ; GET VALUE IN HL CALL PODE ; GET VALUE TO BE SHIFTED JR Z,FSHL3 ; ERROR IF EMPTY FSHL1: LD A,H ; TEST HL FOR ZERO OR L ; AND CLEAR CARRY JR Z,FSHL2 SLA E ; SHIFT DE LEFT 1 BIT RL D DEC HL ; DECR NO. OF SHIFTS REGD. JR FSHL1 ; LOOP FSHL2: CALL PUDE ; PUSH RESULT ON ARITH STACK FSHL3: POP HL ; REPLACE REGS. POP DE RET ;********************************************************************* ;FUNCTION DIADIC ADDITION ;********************************************************************* FDIPL: PUSH HL ; SAVE REGISTERS PUSH DE CALL PODE ; GET 1ST VALUE TO BE ADDED JR Z,FDIPL6 ; STACK EMPTY- ERROR EX DE,HL ; PUT 1ST VALUE IN HL CALL PODE ; GET 2ND VALUE JR Z,FDIPL6 ; STACK EMPTY ERROR EXX ; CLEAR +VE/-VE FLAGS IN B' RES 6,B ; (-VE) RES 7,B ; (+VE) EXX LD A,H ; BOTH VALUES -VE? AND D JP P,FDIPL1 EXX ; YES, SET 'BOTH -VE' FLAG SET 6,B EXX JR FDIPL2 FDIPL1: LD A,H ; BOTH VALUES +VE? OR D JP M,FDIPL2 EXX ; YES, SET BOTH +VE FLAG SET 7,B EXX FDIPL2: AND A ; CLEAR CARRY FLAG ADC HL,DE ; ADD THE 2 VALUES EXX JP M,FDIPL3 BIT 6,B ; RESULT +VE JR Z,FDIPL5 JR FDIPL4 ; SET OVERFLOW FLAG FDIPL3: BIT 7,B JR Z,FDIPL5 FDIPL4: SET 1,B ; SET OVERFLOW FLAG FDIPL5: EXX EX DE,HL ; GET RESULT IN DE CALL PUDE ; PUSH RESULT ON STACK FDIPL6: POP DE POP HL RET ;******************************************************************** ;FUNCTION DIADIC MINUS. ;******************************************************************** FDIMN: PUSH HL ; SAVE REGS. PUSH DE CALL PODE ; GET MINUEND FROM STACK JR Z,FDIMN6 ; JUMP IF EMPTY, ERROR EX DE,HL ; PUT IN HL CALL PODE ; GET SUBTRAHEND JR Z,FDIMN6 ; JUMP IF EMPTY EXX ; CLEAR +VE/-VE FLAGS IN B' RES 6,B ; (-VE EXPECTED FLAG) RES 7,B ; (+VE EXPECTED FLAG) EXX LD A,D AND A ; TEST SIGN OF SUBTRAHEND JP M,FDIMN1 ; JUMP IF -VE LD A,H AND A ; TEST SIGN OF MINUEND JP P,FDIMN2 ; JUMP IF OF OPPOSITE SIGN ; NO OVERFLOW POSSIBLE EXX ; OTHERWISE SET SET 7,B ; +VE EXPECTED FLAG EXX JR FDIMN2 FDIMN1: LD A,H ; TEST SIGN OF MINUEND AND A JP M,FDIMN2 ; JUMP IF OF OPPOSITE SIGN ; NO OVERFLOW POSSIBLE EXX ; SET '-VE EXPECTED' FLAG SET 6,B EXX FDIMN2: EX DE,HL ; GET SUBTRAHEND IN HL AND A ; CLEAR CARRY SBC HL,DE ; DO THE SUBTRACTION EX DE,HL ; GET THE RESULT IN DE EXX ; PREPARE TO EXAMINE B' JP M,FDIMN3 ; JUMP IF -VE RESULT BIT 6,B ; RESULT +VE, WAS -VE EXPECTED? JR NZ,FDIMN4 ; JUMP IF SO JR FDIMN5 ; OTHERWISE NO OVERFLOW FDIMN3: BIT 7,B ; RESULT -VE, WAS +VE EXPECTED? JR Z,FDIMN5 ; JUMP IF NOT FDIMN4: SET 1,B ; SET OVERFLOW FLAG (1,B') FDIMN5: EXX ; SWITCH REGS BACK CALL PUDE ; PUSH RESULT ON ARITH STACK FDIMN6: POP DE ; REPLACE REGS POP HL RET ;********************************************************************** ;FUNCTION AND ;********************************************************************** FAND: PUSH DE ; SAVE REGISTERS PUSH HL CALL PODE ; GET VALUE FROM STACK JR Z,FAND1 ; JUMP IF EMPTY EX DE,HL CALL PODE ; GET THE OTHER VALUE JR Z,FAND1 ; JUMP IF STACK EMPTY LD A,D ; DO 16 BIT LOGICAL AND AND H LD D,A ; WITH RESULT IN DE LD A,E AND L LD E,A CALL PUDE ; PUSH RESULT ON STACK FAND1: POP HL ; REPLACE REGS POP DE RET ;********************************************************************* ;FUNCTION OR ;********************************************************************* FOR: PUSH DE ; SAVE REGS. PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FOR1 ; JUMP IF STACK EMPTY EX DE,HL ; PUT IN HL CALL PODE ; GET THE OTHER VALUE JR Z,FOR1 ; JUMP IF STACK EMPTY LD A,D ; DO 16 BIT LOGICAL OR OR H ; ON HL AND DE LD D,A ; RESULT IN DE LD A,E OR L LD E,A CALL PUDE ; PUSH RESULT ON STACK FOR1: POP HL ; REPLACE REGS POP DE RET ;******************************************************************** ;FUNCTION EXCLUSIVE OR ;******************************************************************** FXOR: PUSH DE ; SAVE REGS PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FXOR1 ; JUMP IF STACK EMPTY EX DE,HL ; PUT IT IN HL CALL PODE ; GET THE OTHER VALUE JR Z,FXOR1 ; JUMP IF STACK EMPTY LD A,D ; DO 16 BIT XOR ON HL AND DE XOR H LD D,A ; RESULT IN DE LD A,E XOR L LD E,A CALL PUDE ; PUSH RESULT ON ARITH STACK FXOR1: POP HL ; REPLACE REGS POP DE RET ;******************************************************************* ;FUNCTION EQUALS ;******************************************************************* FEQ: PUSH DE ; SAVE REGS PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FEQ2 ; JUMP IF STACK EMPTY EX DE,HL ; PUT IT IN HL CALL PODE ; GET ANOTHER VALUE IN DE JR Z,FEQ2 ; JUMP IF STACK EMPTY AND A ; CLEAR CARRY SBC HL,DE ; COMPARE VALUES LD DE,0 ; RESULT IN DE (0 OR 1) JR NZ,FEQ1 ; JUMP IF VALUES NOT EQUAL DEC DE ; OTHERWISE LET RESULT= -1 FEQ1: CALL PUDE ; PUSH RESULT ON STACK FEQ2: POP HL ; REPLACE REGS POP DE RET ;********************************************************************* ;FUNCTION GREATER THAN ;********************************************************************* FGT: PUSH DE ; SAVE REGS. PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FGT2 ; JUMP IF STACK EMPTY EX DE,HL CALL PODE ; GET THE OTHER VALUE IN DE JR Z,FGT2 ; JUMP IF STACK EMPTY LD A,D ; ADD 8000H TO EACH NO. ADD A,80H LD D,A LD A,H ADD A,80H LD H,A AND A ; CLEAR CARRY SBC HL,DE ; COMPARE VALUES LD DE,0 ; RESULT IN DE (0 OR 1) JR NC,FGT1 ; JUMP IF NOT GREATER THAN DEC DE ; OTHERWISE RESULT= -1 FGT1: CALL PUDE ; PUSH RESULT ON STACK FGT2: POP HL ; REPLACE REGS POP DE RET ;********************************************************************* ;FUNCTION LESS THAN ;********************************************************************* FLT: PUSH DE ; SAVE REGS PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FLT2 ; JUMP IF STACK EMPTY EX DE,HL ; PUT VALUE IN HL CALL PODE ; GET THE OTHER VALUE IN DE JR Z,FLT2 ; JUMP IF STACK EMPTY LD A,D ; ADD 8000H TO EACH NO. ADD A,80H LD D,A LD A,H ADD A,80H LD H,A EX DE,HL ; SWAP NOS. AND A ; CLEAR CARRY SBC HL,DE ; COMPARE VALUES LD DE,0 ; RESULT IN DE (0 OR 1) JR NC,FLT1 ; JUMP IF NOT LESS THAN DEC DE ; OTHERWISE RESULT= -1 FLT1: CALL PUDE ; PUSH RESULT ON STACK FLT2: POP HL ; REPLACE REGS POP DE RET ;******************************************************************** ;FUNCTION UNSIGNED GREATER THAN ;******************************************************************** FUGT: PUSH DE ; SAVE REGS PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FUGT2 ; JUMP IF STACK EMPTY EX DE,HL CALL PODE ; GET THE OTHER VALUE IN DE JR Z,FUGT2 ; JUMP IF STACK EMPTY AND A ; CLEAR CARRY SBC HL,DE ; COMPARE VALUES LD DE,0 ; RESULT IN DE (0 OR 1) JR NC,FUGT1 ; JUMP IF NOT GREATER THAN DEC DE ; OTHERWISE RESULT= -1 FUGT1: CALL PUDE ; PUSH RESULT ON STACK FUGT2: POP HL ; REPLACE REGS POP DE RET ;******************************************************************** ;FUNCTION UNSIGNED LESS THAN ;******************************************************************** FULT: PUSH DE ; SAVE REGS. PUSH HL CALL PODE ; GET VALUE FROM ARITH STACK JR Z,FULT2 ; JUMP IF STACK EMPTY EX DE,HL ; PUT VALUE IN HL CALL PODE ; GET THE OTHER VALUE IN DE JR Z,FULT2 ; JUMP IF STACK EMPTY EX DE,HL ; SWAP NOS. AND A ; CLEAR CARRY SBC HL,DE ; COMPARE VALUES LD DE,0 ; RESULT IN DE (0 OR 1) JR NC,FULT1 ; JUMP IF NO LESS THAN DEC DE ; OTHERWISE RESULT= -1 FULT1: CALL PUDE ; PUSH RESULT ON STACK FULT2: POP HL ; REPLACE REGS POP DE RET ;******************************************************************* ;GET TITLE TO TITLE BUFFER. ;ON ENTRY: ; (LINPNT) POINTS AT CHAR AFTER THE ; 'TITLE' PSEUDO-OPERATOR. ;ON EXIT: ; THE OPERAND (A STRING BETWEEN SINGLE ; QUOTES) HAS BEEN TRANSFERED TO THE TITLE BUFFER. ;******************************************************************* TITL: PUSH HL ; SAVE REGISTERS PUSH DE PUSH BC LD HL,TITBUF ; CLEAR TITLE BUFFER LD C,TITSIZ+1 XOR A TITL1: LD (HL),A INC HL DEC C JR NZ,TITL1 LD HL,(LINPNT) ; GET LINE POINTER CALL STR ; FIND STRING JR Z,TITL5 ; NOT FOUND LD A,C ; GET COUNT OF STRING CP TITSIZ+1 ; MORE CHARS THAN SIZE OF TITBUF? JR C,TITL2 LD C,TITSIZ ; YES, FORCE TO TITBUF SIZE JR TITL3 TITL2: AND A ; IS IT 0 CHARS? JR Z,TITL5 TITL3: EX DE,HL ; DO TRANSFER LD DE,TITBUF TITL4: CALL DOUBQ ; SKIP CHAR IF COUBLE QUOTE LDI ; TRANSFER A CHAR JP PE,TITL4 ; JUMP IF TRANSFER NOT COMPLETE TITL5: POP BC ; REPLACE REGISTERS POP DE POP HL RET ;************************************************************************ ;GET DEFM OPERAND. ;ON ENTRY: ; (LINPNT) POINTS AT CHAR AFTER ; DEFM PSEUDO-OPERATOR. ;ON EXIT: ; THE OPERAND (A STRING BETWEEN QUOTES) ; HAS BEEN TRANSFERED INTO THE ; ASSEMBLED CODE BUFFER. ;************************************************************************ DM: PUSH HL ; SAVE REGISTERS PUSH DE PUSH BC LD HL,(LINPNT) ; GET LINE POINTER CALL STR ; FIND STRING JR Z,DM4 ; NOT FOUND LD A,C ; GET COUNT OF STRING CP ACBSIZ+1 ; MORE CHARS THAN SIZE OF A.C. BUFF? JR C,DM1 ; NO LD C,ACBSIZ ; YES, FORCE TO SIZE OF BUFFER JR DM2 DM1: AND A JR Z,DM4 DM2: LD A,C ; SET NO. OF ASSD BYTES LD (ASCDNO),A NOP ; ROOM FOR SPARE INSTRUCTION NOP NOP EX DE,HL ; DO TRANSFER LD DE,ASSCOD DM3: CALL DOUBQ ; SKIP CHAR IF DOUBLE QUOTE LDI ; TRANSFER A CHAR JP PE,DM3 ; JUMP IF TRANSFER NOT COMPLETE DM4: POP BC ; REPLACE REGISTERS POP DE POP HL RET ;************************************************************************** ;LOCATE STRING ;ON ENTRY: ; HL POINTS TO CHAR AFTER OPERAND ;ON EXIT: ; HL POINTS TO FIRST CHAR OF ACTUAL STRING. ; BC CONTAINS NO OF CHARS IN THAT STRING ; (COUNTING 2 QUOTES AS 1 CHAR) ; ZERO FLAG IS SET FOR SYNTAX ERROR ;************************************************************************** STR: CALL SCNSP ; SCAN TO NEXT NON SP CHAR CP '''' ; IS IT A ' ? JR NZ,STR4 ; SYNTAX ERROR, STRING NOT FOUND INC HL ; POINT TO NEXT CHAR LD D,H ; SAVE POINTER IN DE LD E,L LD BC,0 ; CLEAR BC STR1: ; COUNT CHARS TO NEXT 7 CALL DOUBQ ; END OF STRING QUOTE? JR NZ,STR2 ; JUMP IF SO LD A,(HL) ; GET CHAR CP CR ; IS IT CR? JR Z,STR4 ; JUMP IF SO, ERROR INC HL ; INCR PNTR INC C ; AND CNTR JR STR1 ; LOOP STR2: CALL SCNSP ; FIND NEXT NON SP CHAR CP CR ; MUST BE CR/; JR Z,STR3 CP ';' JR Z,STR3 PUSH BC ; SYNTAX ERROR, BUT STRING FOUND LD C,'S' CALL ERROR ; INDICATE SYNTAX ERROR POP BC STR3: XOR A INC A RET STR4: LD C,'S' ; SYNTAX ERROR, STRING NOT FOUND CALL ERROR ; INDICATE ERROR XOR A ; SET ZERO FLAG (FOR ERROR) RET ; AND RETURN ;*********************************************************************** ;PROCESS TOKENS ;PRODUCE ASSEMBLED CODE IN BUFFER BASED ON OPERATOR ;AND OPERAND TOKENS. ;*********************************************************************** PTOK: PUSH IX ; SAVE REGS PUSH HL PUSH DE PUSH BC LD A,(ODBT1) ; PUT OPD BYTE 1 IN B LD B,A LD A,(ODBT2) ; PUT OPD BYTE 2 IN C LD C,A LD HL,(ODINT1) ; PUT OPD INTEGER IN HL LD DE,(ODINT2) ; PUT OPD INTEGER IN DE LD A,(ORTKBF) ; GET OPERATOR TOKEN CP ORGTOK ; TOKEN FOR ORG? JR Z,PTOK4 ; JUMP IF SO CALL PLAB ; PROCESS LABEL EXX PUSH HL ; SAVE REGS PUSH DE PUSH BC LD A,(ORTKBF) ; GET TOKEN AGAIN AND 7FH ; MASK OFF CONDITIONAL FLAG BIT ADD A,A ; DOUBLE IT LD E,A ; PUT INTO DE LD D,0 LD HL,PORL ; PUT 'PROCESS OPR' LIST PNTR IN HL ADD HL,DE ; ADD DE TO GET PNTR TO PNTR TO ROUTIN LD E,(HL) ; GET POINTER IN DE INC HL LD D,(HL) EX DE,HL ; PUT IN HL CALL ODPBT ; GET OPD PAIR BYTE LD B,A ; SAVE IN B PTOK1: LD A,(HL) ; GET VALID TOKEN FROM LIST INC HL ; INCR LIST POINTER CP 0FFH ; COMPARE WITH END OF LIST FLAG JR Z,PTOK3 ; END OF LIST, NOT VALID COMBINATION CP 0FEH ; E.O.L. - NO NOP'S, NO ERROR IND JR Z,PTOK8 CP 0FDH ; END OF LIST - ERROR IND ONLY JR NZ,PTOK9 LD C,'S' ; INDICATE SYNTAX ERROR CALL ERROR JR PTOK8 PTOK9: CP B ; COMPARE TOKEN JR Z,PTOK2 ; JUMP IF MATCH INC HL ; POINT TO NEXT TOKEN INC HL JR PTOK1 ; AND LOOP PTOK2: LD C,(HL) ; GET ADDR OF SUBROUTINE FROM LIST INC HL LD H,(HL) LD L,C PUSH HL ; GET ADDR IN IX POP IX LD HL,PTOK8 ; PUSH RETURN ADDR PUSH HL EXX ; SWAP REGISTER BANKS JP (IX) ; AND CALL INDIRECT PTOK3: CALL DNOPS ; SYNTAX ERROR, APPEND NOP'S JR PTOK8 PTOK4: CALL PORG ; PROCESS ORG JR PTOK7 PTOK8: CALL ADJARC ; ADJUST ADDR REF CNTR EXX ; REPLACE REGS POP BC POP DE POP HL EXX PTOK7: POP BC POP DE POP HL POP IX RET ;********************************************************************* ;SYNTAX ERROR ;ALL THE FOLLOWING PROCESS SUBROUTINES ;RETURN VIA THIS SUBROUTINE IF THEY ;NEED TO APPEND NOP'S IF THE CASE OF ;A SYNTAX ERROR. ;********************************************************************* SYNERR: CALL DNOPS ; ERROR, APPEND DEFAULT NOP'S RET ;................................................... ;PROCESS OPERATOR LIST ;CONTAINS ADDRESSES OF SUBROUTINES ;TO PROCESS VARIOUS OPERATOR GROUPS. ;................................................... PORL: DEFW LSTNUL ; NULL ROUTINE FOR NO OPERATOR DEFW LSTNUL ; NULL ROUTINE FOR ORG DEFW LSTNUL ; NULL ROUTINE FOR EQU DEFW LSTNUL ; NULL FOUTINE FOR DEFL DEFW LST04 ; END DEFW LST05 ; DEFB DEFW LST06 ; DEFW DEFW LST07 ; DEFS DEFW LSTNUL ; NULL ROUTINE FOR DEFM DEFW LSTNUL ; NULL ROUTINE FOR TITLE DEFW LST0B ; SINGLE BYTE, NO OPERAND DEFW LST0B ; DOUBLE BYTE, NO OPERAND DEFW LST0C ; AND OR XOR CP SUB DEFW LST0D ; INC DEC DEFW LST0E ; IM DEFW LST0F ; RLC RL SLA RRC RR SRA SRL DEFW LST10 ; BIT SET RES DEFW LST11 ; JP DEFW LST12 ; JR DEFW LST13 ; DJNZ DEFW LST14 ; CALL DEFW LST15 ; RET DEFW LST16 ; RST DEFW LST17 ; IN DEFW LST18 ; OUT DEFW LST19 ; PUSH POP DEFW LST1A ; EX DEFW LST1B ; ADC SBC DEFW LST1C ; ADD DEFW LST1D ; LD ;......................................................... LSTNUL: DEFB 0FEH ;......................................................... LST04: DEFB 0 ; NO OPD DEFW GP04 DEFB 90H ; SINGLE INTEGER DEFW GP04 DEFB 0FDH ;......................................................... LST05: DEFB 90H ; DEFB N DEFW GP05 DEFB 0FFH ;......................................................... LST06: DEFB 90H ; DEFW NN DEFW GP06 DEFB 0FFH ;......................................................... LST07: DEFB 90H ; DEFS N DEFW GP07 DEFB 0FDH ;......................................................... LST0B: DEFB 0 ; NO OPERAND DEFW GP0B DEFB 0FFH ;......................................................... LST0C: DEFB 70H ; OPR R DEFW GP0C1 DEFB 90H ; OPR N DEFW GP0C2 DEFB 40H ; OPR (HL)/(IX)/(IY) DEFW GP0C3 DEFB 0B0H ; OPR (IX+D)/(IY+D) DEFW GP0C3 DEFB 0FFH ;......................................................... LST0D: DEFB 70H ; OPR R DEFW GP0D1 DEFB 40H ; OPR (HL)/(IX)/(IY) DEFW GP0D2 DEFB 0B0H ; OPR (IX+D)/(IY+D) DEFW GP0D2 DEFB 10H ; OPR RP DEFW GP0D3 DEFB 0FFH ;.......................................................... LST0E: DEFB 90H ; IM N DEFW GP0E DEFB 0FFH ;.......................................................... LST0F: DEFB 70H ; OPR R DEFW GP0F1 DEFB 40H ; OPR (HL)/(IX)/(IY) DEFW GP0F2 DEFB 0B0H ; OPR (IX+D)/(IY+D) DEFW GP0F2 DEFB 0FFH ;.......................................................... LST10: DEFB 97H ; OPR B,R DEFW GP101 DEFB 94H ; OPR B,(HL)/(IX)/(IY) DEFW GP102 DEFB 9BH ; OPR B,(IX+D)/(IY+) DEFW GP102 DEFB 0FFH ;........................................................... LST11: DEFB 40H ; JP (HL)/(IX)/(IY) DEFW GP111 DEFB 89H ; JP CC,NN DEFW GP112 DEFB 90H ; JP NN DEFW GP113 DEFB 0FFH ;............................................................ LST12: DEFB 89H ; JR CC,E DEFW GP121 DEFB 90H ; JR E DEFW GP122 DEFB 0FFH ;............................................................ LST13: DEFB 90H ; DJNZ NN DEFW GP13 DEFB 0FFH ;........................................................... LST14: DEFB 89H ; CALL CC,NN DEFW GP141 DEFB 90H ; CALL NN DEFW GP142 DEFB 0FFH ;............................................................ LST15: DEFB 00H ; RET DEFW GP151 DEFB 80H ; RET CC DEFW GP152 DEFB 0FFH ;............................................................ LST16: DEFB 90H ; RST N DEFW GP16 DEFB 0FFH ;............................................................ LST17: DEFB 7DH ; IN A,(N) DEFW GP171 DEFB 7AH ; IN R,(C) DEFW GP172 DEFB 0FFH ;............................................................ LST18: DEFB 0A7H ; OUT (C),R DEFW GP181 DEFB 0D7H ; OUT (N),A DEFW GP182 DEFB 0FFH ;............................................................. LST19: DEFB 10H ; OPR RP DEFW GP19 DEFB 0FFH ;............................................................. LST1A: DEFB 51H ; EX (SP),HL/IX/IY DEFW GP1A1 DEFB 1EH ; EX AF,AF' DEFW GP1A2 DEFB 11H ; EX DE,HL DEFW GP1A3 DEFB 0FFH ;............................................................. LST1B: DEFB 77H ; OPR A,R DEFW GP1B1 DEFB 79H ; OPR A,N DEFW GP1B2 DEFB 74H ; OPR A,(HL)/(IX)/(IY) DEFW GP1B3 DEFB 7BH ; OPR A,(IX+D)/(IY+D) DEFW GP1B3 DEFB 11H ; OPR HL,SS DEFW GP1B4 DEFB 0FFH ;............................................................... LST1C: DEFB 77H ; ADD A,R DEFW GP1C1 DEFB 79H ; ADD A,N DEFW GP1C2 DEFB 74H ; ADD A,(HL)/(IX)/(IY) DEFW GP1C3 DEFB 7BH ; ADD A,(IX+D)/(IY+D) DEFW GP1C3 DEFB 11H ; ADD HL/IX/IY,RP DEFW GP1C4 DEFB 0FFH ;............................................................... LST1D: DEFB 76H ; LD A,(BC)/(DE) DEFW GP1D1 DEFB 72H ; LD A,I/R DEFW GP1D2 DEFB 7DH ; LD A,(NN) DEFW GP1D3 DEFB 67H ; LD (BC)/(DE),A DEFW GP1D4 DEFB 49H ; LD (HL)/(IX)/(IY),N DEFW GP1D5 DEFB 19H ; LD RP,NN DEFW GP1D6 DEFB 1DH ; LD RP,(NN) DEFW GP1D7 DEFB 47H ; LD (HL)/(IX)/(IY),R DEFW GP1D8 DEFB 27H ; LD I/R,A DEFW GP1D9 DEFB 0B9H ; LD (IX+D)/(IY+D),N DEFW GP1D5 DEFB 0B7H ; LD (IX+D)/(IY+D),R DEFW GP1D8 DEFB 0D7H ; LD (NN),A DEFW GP1DA DEFB 0D1H ; LD (NN),RP DEFW GP1DB DEFB 74H ; LD (HL)/(IX)/(IY) DEFW GP1DC DEFB 7BH ; LD R,(IX+D)/(IY+D) DEFW GP1DC DEFB 79H ; LD R,N DEFW GP1DD DEFB 77H ; LD R,R DEFW GP1DE DEFB 11H ; LD SP,HL/IX/IY DEFW GP1DF DEFB 0FFH ;********************************************************************** ;ENTRY AND EXIT CONDITIONS FOR PORG, PLAB AND ;ALL GP... SUBROUTINES. ; ;ON ENTRY: ; B CONTAINS OPERAND-1 TOKEN BYTE ; C CONTAINS OPERAND-2 TOKEN BYTE ; HL CONTAINS OPERAND-1 INTEGER ; DE CONTAINS OPERAND-2 INTEGER ;ON EXIT: ; ASSEMBLED CODE HAS BEEN PLACED IN ASSEMBLED ; CODE BUFFER (ASSCOD). ; ADDRESS REFERENCE COUNTER HAS BEEN ADJUSTED. ;********************************************************************** ; ;********************************************************************** ;PROCESS ORG ;********************************************************************** PORG: PUSH HL ; SAVE REGS PUSH BC CALL ODPBT ; GET OPERAND PAIR BYTE IN A CP 90H ; SINGLE INTEGER? JR NZ,PORG1 ; JUMP OTHERWISE LD HL,(ODINT1) ; GET OPERAND-1 INTEGER LD (ADREFC),HL ; PUT IN ADDR REG CNTR LD (ADDISR),HL ; AND ADDR DISP REG LD HL,AFLAGS ; SET ADDR DISCONTINUITY FLAG SET 0,(HL) JR PORG2 PORG1: LD C,'S' ; INDICATE SYNTAX ERROR CALL ERROR PORG2: POP BC ; REPLACE REGS POP HL RET ;********************************************************************** ;PROCESS LABEL (INCLUDES EQU AND DEFL) ;********************************************************************** PLAB: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD A,(ORTKBF) ; GET OPR TOKEN PUSH AF ; SAVE ON STACK CP DEFLTK ; IS IT DEFL? JR Z,PLAB1 CP EQUTOK ; OR EQU? JR NZ,PLAB2 PLAB1: LD (ADDISR),HL ; DISPLAY VALUE IF SO CALL ODPBT ; GET OPD PAIR BYTE CP 90H ; SINGLE INTEGER? JR Z,PLAB3 ; JUMP IF SO, OK LD C,'S' ; ELSE INDICATE SYNTAX ERROR CALL ERROR JR PLAB3 PLAB2: LD HL,(ADREFC) ; GET CURRENT ADDR (LABEL VALUE) PLAB3: LD B,H ; COPY LABEL VALUE INTO BC LD C,L CALL LBSYM ; PUT LABEL AND VALUE IN SYMBUF JR Z,PLAB13 ; JUMP IF NO LABEL PRESENT CALL SYMCH ; CHECK IF SYMBOL IS RESERVED WORD JR NC,PLAB5 ; JUMP IF NOT PLAB13: POP AF ; GET OPR TOKEN PUSH AF CP DEFLTK ; IS IT DEFL? JR Z,PLAB4 CP EQUTOK ; OR EQU? JR NZ,PLAB12 PLAB4: LD C,'S' ; INDICATE SYNTAX ERROR IF SO CALL ERROR JR PLAB12 PLAB5: POP AF ; GET OPR TOKEN PUSH AF CP DEFLTK ; IS IT DEFL? JR NZ,PLAB6 ; JUMP IF NOT SET 0,(HL) ; SET DEFL FLAG IN ATTRIB PLAB6: CALL LOCATE ; LOCATE IN SYMBOL TABLE JR Z,PLAB8 ; JUMP IF ALREADY IN TABLE LD A,(PASSNO) ; IS THIS PASS 1? CP 1 JR Z,PLAB7 ; JUMP IF SO LD C,'P' ; OTHERWISE INDICATE PHASE ERROR CALL ERROR JR PLAB12 PLAB7: CALL INSERT ; INSERT IN SYMBOL TABLE JR PLAB12 ; ALREADY IN TABLE PLAB8: LD A,(PASSNO) ; IS THIS PASS 1? CP 1 JR Z,PLAB11 ; JUMP IF SO INC HL ; MULT DEFN FLAG SET? INC HL BIT 1,(HL) JR Z,PLAB9 ; JUMP IF NOT LD C,'M' ; INDICATE MULT DEFN ERROR CALL ERROR JR PLAB12 PLAB9: POP AF ; GET OPR TOKEN PUSH AF CP DEFLTK ; IS IT DEFL? JR NZ,PLAB10 ; JUMP IF NOT DEC HL ; INSERT NEW VALUE LD (HL),B DEC HL LD (HL),C JR PLAB12 PLAB10: ; HAS VALUE CHANGED? DEC HL ; GET OLD VALUE IN DE LD D,(HL) DEC HL LD E,(HL) EX DE,HL ; GET IT INTO HL AND A ; CLEAR CARRY SBC HL,BC ; AND COMPARE OLD AND NEW VALUES JR Z,PLAB12 ; JUMP IF EQUAL EX DE,HL ; ELSE INSERT NEW VALUE LD (HL),C INC HL LD (HL),B LD C,'P' ; AND INDICATE PHASE ERROR CALL ERROR JR PLAB12 PLAB11: INC HL ; POINT TO ATTRIBUTE BYTE INC HL POP AF ; GET OPR TOKEN PUSH AF CP DEFLTK ; IS IT DEFL? JR NZ,PLAB14 ; JUMP IF NOT BIT 0,(HL) ; TEST DEFL FLAG JR NZ,PLAB12 ; JUMP IF SET PLAB14: SET 1,(HL) ; SET MULT DEFN FLAG PLAB12: POP AF ; REPLACE REGS POP BC POP DE POP HL RET ;******************************************************************* ;PROCESS END (GROUP 04) ;******************************************************************* GP04: LD (STADDR),HL ; LOAD START ADDR WITH INTEGER LD (ADDISR),HL ; LOAD ADDR DIS REG WITH INTEGER LD HL,AFLAGS ; SET 'END' FLAG SET 1,(HL) RET ;******************************************************************** ;PROCESS DEFB ;******************************************************************** GP05: CALL CHKOF ; CHECK FOR OVERFLOW BEYOND ; 8 BIT VALUE (AND FLAG IF SO) LD A,L ; APPEND 1 BYTE TO ASSD CODE BUFF CALL APPBT ; APPEND BYTE TO ASSD CODE BUFF RET ;******************************************************************** ;PROCESS DEFW ;******************************************************************** GP06: CALL APPWD ; APPEND TO ASSD CODE BUFF RET ;******************************************************************** ;PROCESS DEFS (GROUP 07) ;******************************************************************** GP07: LD DE,(ADREFC) ; ADD INTEGER TO ADDR REF CNTR ADD HL,DE LD (ADREFC),HL LD HL,AFLAGS ; SET ADDR DISCONT. FLAG SET 0,(HL) RET ;******************************************************************** ;PROCESS NO OPERAND. ;******************************************************************** GP0B: LD A,(ORTKBF) ; GET OPR GROUP CP 0AH ; IS IT GROUP 0A? JR Z,GP0B1 ; SKIP PREFIX BYTE IF SO LD A,0EDH ; LOAD PREFIX BYTE TO ASSD CODE BUFF CALL APPBT ; APPEND TO ASSD CODE BUFFER GP0B1: LD A,(ORTKBF+1) ; GET OPCODE IN A CALL APPBT ; AND APPEND TO ASSD CODE BUFF RET ;******************************************************************** ;PROCESS AND/OR/XOR/CP/SUB (GROUP 0C) ;******************************************************************** ;GROUP 0C - R ;******************************************************************** GP0C1: LD A,(ORTKBF+1) ; GET OPR DISTING BITS LD C,B ; COMBINE REG BITS CALL ISREG OR 10000000B ; BUILD OP-CODE CALL APPBT ; APPEND RESULT TO ASSD CODE BUFFER RET ;******************************************************************** ;GROUP 0C - N ;******************************************************************** GP0C2: LD A,(ORTKBF+1) ; GET OPR DISTING BITS OR 11000110B ; BUILD OP-CODE CALL APPBT ; APPEND IT TO ASSD CODE BUFF CALL CHKOF ; INDICATE OVERFLOW ERROR IF ANY LD A,L ; PUT INTEGER IN ASSD CODE BUFFER CALL APPBT RET ;******************************************************************* ;GROUP 0C - (HL)/(IX+D)/(IY+D) ;******************************************************************* GP0C3: CALL INDPF ; GENERATE INDEX PREFIX, IF REQD LD A,(ORTKBF+1) ; GET OPR DISTING BITS OR 10000110B ; BUILD OP-CODE CALL APPBT ; APPEND TO ASSD CODE BUFF CALL DISBT ; APPEND DISP. IF REQD RET ;******************************************************************* ;PROCESS INC/DEC (GROUP 0D) ;******************************************************************* ;GROUP 0D - R ;******************************************************************* GP0D1: LD C,B LD A,(ORTKBF+1) ; GET OPR DISTING. BIT AND 00000001B OR 00000100B ; BUILD OP-CODE CALL IDREG ; INSERT REGISTER BITS CALL APPBT ; APPEND OPCODE TO BUFFER RET ;****************************************************************** ;GROUP 0D - (HL)/(IX+D)/(IY+D) ;****************************************************************** GP0D2: CALL INDPF ; GENERATE INDEX PREFIX IF REGD LD A,(ORTKBF+1) ; GET OPERATOR DISTING. BIT AND 00000001B OR 00110100B ; GENERATE OP-CODE CALL APPBT ; APPEND TO BUFFER CALL DISBT ; APPEND DISP. IF REQD RET ;****************************************************************** ;GROUP 0D - IX/IY/BC/DE/HL/SP ;****************************************************************** GP0D3: LD A,B ; GET OPERAND BYTE-1 CP 17H ; CHECK IF AF REFERENCE JP Z,SYNERR ; JUMP IF IT IS, ERROR CALL INDPF ; GENERATE INDEX PREFIX IF REQD LD C,B ; PUT OPERAND BYTE IN C LD A,(ORTKBF+1) ; GET OPR DISTING. BIT AND 00001000B OR 00000011B ; BUILD OP-CODE CALL IREGP ; INSERT REGISTER PAIR BITS CALL APPBT ; APPEND THIS OPCODE TO BUFFER RET ;****************************************************************** ;PROCESS IM (GROUP 0E) ;****************************************************************** GP0E: LD A,H ; GET HIGH BYTE AND A ; CHECK IT IS 0 JP NZ,SYNERR ; ERROR IF NOT, SO JUMP LD A,L ; GET LOW BYTE CP 3 ; IS IT 0,1 OR 2? JP NC,SYNERR ; JUMP IF NOT, ERROR AND A ; IS IT ZERO? JR Z,GP0E1 ; JUMP IF SO INC A ; OTHERWISE INCREMENT GP0E1: LD C,A ; PUT IT IN C LD A,0EDH ; APPEND PREFIX BYTE CALL APPBT ; TO ASSD CODE BUFFER LD A,01000110B ; GENERATE OP-CODE CALL IDREG ; INSERT PARAMETER BITS CALL APPBT ; APPEND TO ASSD CODE BUFF RET ;****************************************************************** ;PROCESS RLC/RL/SLA/RRC/RR/SRA/SRL (GROUP 0F) ;****************************************************************** ;GROUP 0F - R ;**************************************************************** GP0F1: LD A,0CBH ; APPEND PREFIX BYTE CALL APPBT ; TO ASSD CODE BUFF LD C,B ; PUT OPD BYTE 1 IN C LD A,(ORTKBF+1) ; GET OPD DISTING. BITS CALL ISREG ; INSERT REGISTER BITS CALL APPBT RET ;****************************************************************** ;GROUP OF - (HL)/(IX+D)/(IY+D) ;****************************************************************** GP0F2: CALL INDPF ; APPEND INDEX PREFIX BYTE IF REQD LD A,0CBH CALL APPBT ; APPEND PREFIX BYTE CALL DISBT ; APPEND DISPLACEMENT BYTE IF REQD LD A,(ORTKBF+1) ; GET OPR DISTING. BITS OR 00000110B ; BUILD OP-CODE CALL APPBT ; APPEND TO ASSD CODE BUFF RET ;************************************************************************* ;PROCESS BIT/SET/RES (GROUP 10) ;************************************************************************* ;GROUP 10 - B,R ;************************************************************************* GP101: ; OPD INTEGER ; MUST BE IN RANGE 0-7 LD A,L ; SEE IF ANY BITS OTHER THAN AND 11111000B ; 3 L.S. BITS ARE 1 OR H JP NZ,SYNERR ; JUMP IF SO, ERROR LD A,0CBH ; APPEND PREFIX BYTE TO BUFFER CALL APPBT LD A,(ORTKBF+1) ; GET OPD DISTING. BITS CALL ISREG ; COMBINE REGISTER BITS LD C,L ; GET INTEGER IN C CALL IDREG ; COMBINE INTEGER BITS CALL APPBT ; APPEND OP-CODE TO BUFFER RET ;************************************************************************ ;GROUP 10 - B,(HL)/(IX+D)/(IY+D) ;************************************************************************ GP102: ; OPD INTEGER ; MUST BE IN RANGE 0-7 LD A,L ; SEE IF ANY BITS OTHER THAN AND 11111000B ; 3 L.S. BITS ARE 1 OR H JP NZ,SYNERR ; JUMP IF SO, ERROR LD B,C CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,0CBH ; APPEND OP-CODE PREFIX CALL APPBT LD C,L ; GET INTEGER IN C EX DE,HL ; GET DISPLACEMENT INTEGER CALL DISBT ; APPEND IF REQD LD A,(ORTKBF+1) ; GET OPD DISTING. BITS OR 00000110B ; BUILD OP-CODE CALL IDREG ; COMBINE INTEGER BITS CALL APPBT RET ;*********************************************************************** ;PROCESS JP (GROUP 11) ;*********************************************************************** ;*********************************************************************** ;GROUP 11 - (HL)/(IX)/(IY) ;*********************************************************************** GP111: CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,0E9H ; APPEND OP-CODE PREFIX TO BUFFER CALL APPBT RET ;*********************************************************************** ;GROUP 11 - CC,NN ;*********************************************************************** GP112: LD C,B ; GET OPD BYTE 1 IN C LD A,11000010B ; BUILD OP-CODE CALL IDREG ; COMBINE CONDITION BITS CALL APPBT ; APPEND OP-CODE TO BUFFER EX DE,HL ; GET INTEGER CALL APPWD ; APPEND LOW BYTE RET ;********************************************************************** ;GROUP 11 - NN ;********************************************************************** GP113: LD A,0C3H ; APPEND OP-CODE TO BUFFER CALL APPBT CALL APPWD ; APPEND INTEGER RET ;********************************************************************** ;PROCESS JR (GROUP 12) ;********************************************************************** ;********************************************************************** ;GROUP 12 CC,E ;********************************************************************** GP121: BIT 2,B ; CHECK IF PO/PE/P/M JP NZ,SYNERR ; JUMP IF SO, ERROR LD C,B ; PUT OPR BYTE 1 IN C EX DE,HL ; GET OPD INTEGER 2 CALL CDIS ; CALCULATE DISPLACEMENT NOP ; ROOM FOR SPARE INSTRUCTION NOP NOP LD A,00100000B ; BUILD OP-CODE CALL IDREG ; COMBINE CONDITION BITS CALL APPBT ; APPEND OP-CODE TO BUFFER LD A,L ; GET DISPLACEMENT CALL APPBT ; APPEND TO BUFFER RET ;********************************************************************* ;GROUP 12 - E ;********************************************************************* GP122: CALL CDIS ; CALCULATE DISPLACEMENT NOP ; ROOM FOR SPARE INSTRUCTION NOP NOP LD A,18H ; APPEND OP-CODE TO BUFFER CALL APPBT LD A,L ; APPEND DISP TO BUFFER CALL APPBT RET ;********************************************************************* ;PROCESS DJNZ (GROUP 13) ;********************************************************************* GP13: CALL CDIS ; CALCULATE DISPLACEMENT NOP ; ROOM FOR SPARE INSTRUCTION NOP NOP LD A,10H ; APPEND OP-CODE TO BUFFER CALL APPBT LD A,L ; APPEND DISP TO BUFFER CALL APPBT RET ;********************************************************************* ;CALCULATE DISPLACEMENT ;********************************************************************* CDIS: PUSH DE ; SAVE REGS PUSH BC LD DE,(ADREFC) ; GET ADDR REF CNTR INC DE ; ADD 2 (ALLOW FOR INCRD PC) INC DE AND A ; CLEAR CARRY SBC HL,DE ; GET DISPLACEMENT FROM CURR LOC. LD A,L ; CHECK FOR 8 BIT OVERFLOW AND 10000000B OR H JR Z,CDIS2 ; JUMP IF NO OVERFLOW LD A,L ; CHECK -VE OVERFLOW OR 01111111B AND H CPL AND A JR Z,CDIS2 ; JUMP IF NO OVERFLOW CDIS1: LD C,'R' ; INDICATE RANGE ERROR CALL ERROR XOR A ; CLEAR ZERO FLAG INC A CDIS2: POP BC ; REPLACE REGS POP DE RET ;******************************************************************** ;PROCESS CALL (GROUP 14) ;******************************************************************** ;******************************************************************** ;GROUP 14 - CC,NN ;******************************************************************** GP141: LD C,B ; GET OPD BYTE 1 IN C LD A,11000100B ; BUILD OP-CODE CALL IDREG ; COMBINE CONDITION BIT CALL APPBT ; APPEND OP-CODE TO BUFFER EX DE,HL ; GET INTEGER CALL APPWD ; APPEND INTEGER RET ;******************************************************************** ;GROUP 14 - NN ;******************************************************************** GP142: LD A,0CDH ; APPEND OP-CODE TO BUFFER CALL APPBT CALL APPWD ; APPEND INTEGER RET ;******************************************************************** ;PROCESS RET (GROUP 15) ;******************************************************************** ;******************************************************************** ;GROUP 15 - NO OPERAND ;******************************************************************** GP151: LD A,0C9H ; APPEND OP-CODE TO BUFFER CALL APPBT RET ;******************************************************************** ;GROUP 15 - CC ;******************************************************************** GP152: LD C,B ; GET OPD BYTE 1 IN C LD A,11000000B ; BUILD OP-CODE CALL IDREG ; COMBINE CONDITION BITS CALL APPBT ; APPEND OP-CODE TO BUFFER RET ;******************************************************************** ;PROCESS RST (GROUP 16) ;******************************************************************** GP16: ; INTEGER MAY ONLY BE 0/08H/ ; 10H/18H/20H/28H/30H/38H LD A,L ; CHECK FOR INVALID VALUE AND 11000111B OR H JP NZ,SYNERR ; JUMP IF INVALID LD A,L ; BUILD OP-CODE OR 11000111B CALL APPBT ; APPEND TO BUFFER RET ;******************************************************************** ;PROCESS IN (GROUP 17) ;******************************************************************** ;******************************************************************** ;GROUP 17 - A,(N) ;******************************************************************** GP171: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,D ; INTEGER MUST BE < 256 AND A NOP ; ROOM FOR SPARE INSTRUCTION NOP NOP LD A,0DBH ; APPEND OP-CODE TO BUFFER CALL APPBT LD A,E ; APPEND INTEGER TO BUFFER CALL APPBT RET ;******************************************************************** ;GROUP 17 - R,(C) ;******************************************************************** GP172: LD A,0EDH ; APPEND OP-CODE PREFIX TO BUFFER CALL APPBT LD C,B ; GET OPD BYTE 1 IN C LD A,01000000B ; BUILD OP-CODE CALL IDREG ; COMBINE REG BITS CALL APPBT RET ;******************************************************************** ;PROCESS OUT (GROUP 18) ;******************************************************************** ;******************************************************************** ;GROUP 18 - (C),R ;******************************************************************** GP181: LD A,0EDH ; APPEND OP-CODE PREFIX TO BUFFER CALL APPBT LD A,01000001B ; BUILD OP-CODE CALL IDREG ; COMBINE REG BITS CALL APPBT ; APPEND TO BUFFER RET ;******************************************************************* ;GROUP 18 - (N),A ;******************************************************************* GP182: LD A,C ; GET OPD BYTE 2 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT LD A,H ; MUST BE < 256 AND A NOP ; ROOM FOR SPARE INSTRUCTION NOP NOP LD A,0D3H ; APPEND OP-CODE TO BUFFER CALL APPBT LD A,L ; APPEND INTEGER TO BUFFER CALL APPBT RET ;******************************************************************* ;PROCESS PUSH/POP (GROUP 19) ;******************************************************************* GP19: LD A,(ODBT1) ; GET OPD BYTE 1 CP 13H ; SP NOT PERMITTED JP Z,SYNERR LD C,B ; GET OPD BYTE 1 IN C CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,(ORTKBF+1) ; GET APR DISTING. BITS CALL IREGP ; COMBINE REG PAIR BITS CALL APPBT ; APPEND TO BUFFER RET ;******************************************************************** ;PROCESS EX (GROUP 1A) ;******************************************************************** ;******************************************************************** ;GROUP 1A - (SP),HL/IX/IY ;******************************************************************** GP1A1: LD B,C ; GET OPR BYTE 2 IN C LD A,C AND 3 ; MUST BE HL/IX/IY CP 2 JP NZ,SYNERR ; JUMP IF NOT, ERROR CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,0E3H ; APPEND AP-CODE TO BUFFER CALL APPBT RET ;******************************************************************** ;GROUP 1A - AF,AF' ;******************************************************************** GP1A2: LD A,B ; GET OPD BYTE 1 CP 17H ; MUST BE AF JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,08H ; APPEND OP-CODE TO BUFFER CALL APPBT RET ;******************************************************************** ;GROUP 1A - DE,HL ;******************************************************************** GP1A3: LD A,B ; GET SPD BYTE 1 CP 11H ; MUST BE DE JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,C ; GET OPD BYTE 2 CP 12H ; MUST BE HL JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,0EBH ; APPEND OP-CODE TO BUFFER CALL APPBT RET ;******************************************************************** ;PROCESS ADC/SBC (GROUP 1B) ;******************************************************************** ;GROUP 1B - A,R ;******************************************************************** GP1B1: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,(ORTKBF+1) ; GET OPD DISTING BITS AND 00010000B ; AND MASK IT OR 10001000B ; BUILD OP-CODE CALL ISREG ; COMBINE REGISTER BITS CALL APPBT ; APPEND BYTE TO BUFFER RET ;******************************************************************* ;GROUP 1B - A,N ;******************************************************************* GP1B2: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,(ORTKBF+1) ; GET OPR DISTING BITS AND 00010000B ; AND MASK IT OR 11001110B ; BUILD OP-CODE CALL APPBT ; APPEND TO BUFFER EX DE,HL ; GET INTEGER IN HL CALL CHKOF ; FLAG OVERFLOW FROM L IF ANY LD A,L ; APPEND INTEGER TO BUFFER CALL APPBT RET ;******************************************************************* ;GROUP 1B A,(HL)/(IX+D)/(IY+D) ;******************************************************************* GP1B3: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD B,C ; PUT OPD BYTE 2 IN B CALL INDPF ; APPEND INDEX PREFIX IF ANY LD A,(ORTKBF+1) ; GET OPR DISTING BIT AND 00010000B ; AND MASK IT OR 10001110B ; BUILD OP-CODE CALL APPBT ; APPEND IT TO BUFFER EX DE,HL ; GET DISP. INTEGER CALL DISBT ; APPEND DISPLACEMENT INTEGER IF REQD RET ;******************************************************************** ;GROUP 1B - HL,BC/DE/HL/SP ;******************************************************************** GP1B4: LD A,B ; GET OPD BYTE 1 CP 12H ; MUST BE HL JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,C ; GET OPD BYTE 2 CP 14H ; MUST BE BC/DE/HL/SP JP NC,SYNERR ; JUMP IF NOT, ERROR LD A,0EDH ; APPEND PREFIX BYTE TO BUFFER CALL APPBT LD A,(ORTKBF+1) ; GET OPR DISTING BIT AND 00001000B ; MASK IT OR 01000010B ; BUILD OP-CODE CALL IREGP ; COMBINE REG PAIR BITS CALL APPBT ; APPEND IT TO BUFFER RET ;******************************************************************* ;PROCESS ADD (GROUP 1C) ;******************************************************************* ;******************************************************************* ;GROUP 1C - A,R ;******************************************************************* GP1C1: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,10000000B ; BUILD OP-CODE CALL ISREG ; COMBINE REG BITS CALL APPBT ; APPEND TO BUFFER RET ;******************************************************************* ;GROUP 1C - A,N ;******************************************************************* GP1C2: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,0C6H ; APPEND OP-CODE CALL APPBT EX DE,HL ; GET INTEGER IN HL CALL CHKOF ; FLAG ANY OVERFLOW FROM L LD A,L ; APPEND INTEGER TO BUFFER CALL APPBT RET ;******************************************************************** ;GROUP 1C - A,(HL)/(IX+D)/(IY+D) ;******************************************************************** GP1C3: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR LD B,C ; PUT OPD BYTE 2 IN B CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,86H ; APPEND OP-CODE TO BUFFER CALL APPBT EX DE,HL ; GET DISP INTEGER IN HL CALL DISBT ; APPEND IT IF REQD RET ;******************************************************************** ;GROUP 1C - HL/IX/IY,RP ;******************************************************************** GP1C4: LD A,B ; GET OPD BYTE 1 AND 11B ; MUST BE HL/IX/IY CP 10B JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,C ; GET OPD BYTE 2 AND 11B ; IS IT BC/DE/SP CP 10B JR NZ,GP1C41 ; JUMP IF SO LD A,C ; IS IT SAME AS OPD 1? CP B JP NZ,SYNERR ; JUMP IF NOT, ERROR GP1C41: CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,00001001B ; BUILD OP-CODE CALL IREGP ; COMBINE REG PAIR BITS CALL APPBT RET ;******************************************************************** ;PROCESS LD (GROUP 1D) ;******************************************************************** ;******************************************************************** ;GROUP 1D - A,(BC)/(DE) ;******************************************************************** GP1D1: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,00001010B ; BUILD OP-CODE CALL IREGP ; COMBINE REG BITS CALL APPBT ; APPEND OP-CODE TO BUFFER RET ;******************************************************************** ;GROUP 1D - A,I/R ;******************************************************************** GP1D2: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,0EDH ; APPEND PREFIX BYTE TO BUFFER CALL APPBT LD A,01010111B ; BUILD OP-CODE CALL IDREG ; COMBINE REG BIT CALL APPBT ; APPEND OP-CODE TO BUFFER RET ;******************************************************************** ;GROUP 1D - A,(NN) ;******************************************************************** GP1D3: LD A,B ; GET OPD BYTE 1 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR EX DE,HL ; GET INTEGER IN HL LD A,3AH ; APPEND OP-CODE TO BEFFER CALL APPBT CALL APPWD ; APPEND INTEGER RET ;******************************************************************** ;GROUP 1D - (BC)/(DE),A ;******************************************************************** GP1D4: LD A,C ; GET OPD BYTE 2 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD C,B ; PUT OPD BYTE 1 IN C LD A,00000010B ; BUILD OP-CODE CALL IREGP ; COMBINE REG PAIR BITS CALL APPBT ; APPEND OP-CODE TO BUFFER RET ;******************************************************************* ;GROUP 1D - (HL)/(IX+D)/(IY+D),N ;******************************************************************* GP1D5: CALL INDPF ; APPEND INDEX PREFIX TO BUFFER LD A,36H CALL APPBT ; APPEND OP-CODE CALL DISBT ; APPEND DISP BYTE IF REQD EX DE,HL ; GET INTEGER IN HL CALL CHKOF ; FLAG OVERFLOW FROM L LD A,L ; APPEND INTEGER TO BUFFER CALL APPBT RET ;******************************************************************* ;GROUP 1D - BC/DE/HL/SP/IX/IY,NN ;******************************************************************* GP1D6: LD A,B ; GET OPD BYTE 1 CP 17H ; MUST NOT BE AF REG PAIR JP Z,SYNERR ; JUMP IF IT IS, ERROR LD C,B ; GET OPD BYTE 1 IN C CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,00000001B ; BUILD OP-CODE CALL IREGP ; COMBINE REG PAIR BITS CALL APPBT ; APPEND OP-CODE EX DE,HL ; GET INTEGER IN HL CALL APPWD ; APPEND INTEGER RET ;******************************************************************* ;GROUP 1D - BC/DE/HL/SP/IX/IY,(NN) ;******************************************************************* GP1D7: LD A,B ; GET OPD BYTE 1 LD C,B ; PUT IN C CP 17H ; MUST NOT BE AF JP Z,SYNERR ; JUMP IF IT IS, ERROR AND 11B ; TEST FOR HL/IX/IY CP 10B ; TREAT HL/IX/IY SEPARATELY JR Z,GP1D71 ; JUMP IF HL/IX/IY LD A,0EDH ; APPEND PREFIX BYTE CALL APPBT LD A,01001011B ; BUILD OP-CODE CALL IREGP ; COMBINE REG PAIR BITS JR GP1D72 GP1D71: CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,2AH ; APPEND OP-CODE TO BUFFER GP1D72: CALL APPBT EX DE,HL ; GET INTEGER IN HL CALL APPWD ; APPEND INTEGER RET ;******************************************************************** ;GROUP 1D - (HL)/(IX+D)/(IY+D),R ;******************************************************************** GP1D8: CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,01110000B ; BUILD OP-CODE CALL ISREG ; COMBINE REG BITS CALL APPBT ; APPEND OP-CODE TO BUFFER CALL DISBT ; APPEND TO BUFFER IF REQD RET ;******************************************************************** ;GROUP 1D - I/R,A ;******************************************************************** GP1D9: LD A,C ; GET OPD BYTE 2 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD C,B ; PUT OPD BYTE 1 IN C LD A,0EDH ; APPEND PREFIX BYTE CALL APPBT LD A,01000111B ; BUILD OP-CODE CALL IDREG ; COMBINE REG BIT CALL APPBT ; APPEND OP-CODE RET ;******************************************************************** ;GROUP 1D - (NN),A ;******************************************************************** GP1DA: LD A,C ; GET OPD BYTE 2 CP 77H ; MUST BE 'A' REG JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,32H ; APPEND OP-CODE TO BUFFER CALL APPBT CALL APPWD ; APPEND INTEGER RET ;******************************************************************** ;GROUP 1D = (NN),BC/DE/HL/SP/IX/IY ;******************************************************************** GP1DB: LD A,C ; GET OPD BYTE 2 LD B,C ; PUT IN B CP 17H ; MUST NOT BE AF JP Z,SYNERR ; JUMP IF IT IS, ERROR AND 11B ; TEST FOR HL/IX/IY CP 10B JR Z,GP1DB1 ; JUMP TO TREAT HL/IX/IY SEPARATELY LD A,0EDH ; APPEND PREFIX BYTE CALL APPBT LD A,01000011B ; BUILD OP-CODE CALL IREGP ; COMBINE REG PAIR BITS JR GP1DB2 GP1DB1: CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,22H ; PUT OP-CODE IN A GP1DB2: CALL APPBT ; APPEND OP-CODE CALL APPWD ; APPEND INTEGER RET ;********************************************************************** ;GROUP 1D - R,(HL)/(IX+D)/(IY+D) ;********************************************************************** GP1DC: LD A,B ; SWAP B AND C LD B,C LD C,A CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,01000110B ; BUILD OP-CODE CALL IDREG ; COMBINE REG BITS CALL APPBT ; APPEND OP-CODE EX DE,HL ; GET INTEGER IN HL CALL DISBT ; APPEND DISP BYTE IF REQD RET ;********************************************************************** ;GROUP 1D - R,N ;********************************************************************** GP1DD: LD C,B ; PUT OPD BYTE 1 IN C LD A,00000110B ; BUILD OP-CODE CALL IDREG ; COMBINE REG BITS CALL APPBT ; APPEND OP-CODE TO BUFFER EX DE,HL ; GET INTEGER IN HL CALL CHKOF ; FLAG OVERFLOW FROM L LD A,L ; APPEND INTEGER TO BUFFER CALL APPBT RET ;********************************************************************** ;GROUP 1D - R,R ;********************************************************************** GP1DE: LD A,01000000B ; BUILD OP-CODE CALL ISREG ; COMBINE SOURCE REG BITS LD C,B CALL IDREG ; COMBINE DEST REG BITS CALL APPBT ; APPEND OP-CODE RET ;********************************************************************* ;GROUP 1D - SP,HL/IX/IY ;********************************************************************* GP1DF: LD A,B ; GET OPD BYTE 1 CP 13H ; MUST BE SP JP NZ,SYNERR ; JUMP IF NOT, ERROR LD A,C ; GET OPD BYTE 2 LD B,C ; PUT IN B AND 11B ; MUST BE HL/IX/IY CP 10B JP NZ,SYNERR ; JUMP IF NOT, ERROR CALL INDPF ; APPEND INDEX PREFIX IF REQD LD A,0F9H ; APPEND OP-CODE TO BUFFER CALL APPBT RET ;******************************************************************* ;GET OPERAND PAIR BYTE ;THE M.S. NIBBLE OF AN OPERAND TOKEN BYTE ;SIGNIFIES THE OPERAND GROUP (0-E). THIS ;SUBROUTINE BUILDS A BYTE WHOSE M.S. NIBBLE ;IS THE GROUP OF OPERAND 1 AND WHOSE L.S. ;NIBBLE IS THE GROUP OF OPERAND 2. ;THIS COMPOSITE BYTE IS CALLED THE OPERAND ;PAIR BYTE AND IS USED TO DETERMINE WHICH ;PROCESSING SUBROUTINE (GP...) TO USE TO ;GENERATE THE ASSEMBLED CODE. ; ;ON EXIT: ; A CONTAINS THE OPERAND BYTE PAIR ;******************************************************************* ODPBT: PUSH BC ; SAVE BC LD A,(ODBT1) ; GET 1ST OPERAND BYTE AND 0F0H ; MASK OPERAND GROUP NIBBLE LD B,A ; SAVE IN B LD A,(ODBT2) ; GET 2ND OPERAND BYTE AND 0F0H ; MASK OPERAND GROUP NIBBLE RRCA ; SHIFT INTO LOWER 4 BITS RRCA RRCA RRCA OR B ; CONSTRUCT COMPOSITE OPERAND ; GROUP BYTE IN A POP BC ; REPLACE BC RET ;****************************************************************** ;GENERATE INDEX REGISTER PREFIX BYTE ;ON ENTRY: ; B CONTAINS OPERAND TOKEN ;PREFIX IS APPENDED TO ASSD CODE BUFFER IF ;OPERAND IS IX OR IY. ;****************************************************************** INDPF: BIT 3,B ; IS OPERAND IX OR IY? RET Z ; NO PREFIX IF NOT, RETURN LD A,0DDH ; PUT PREFIX BYTE FOR IX IN A BIT 2,B ; IS OPERAND IY? JR Z,INDPF1 ; JUMP IF NOT LD A,0FDH ; PUT PREFIX BYTE FOR IY IN A INDPF1: CALL APPBT ; APPEND BYTE TO ASSD CODE BUFFER RET ;****************************************************************** ;GENERATE DISPLACEMENT BYTE ;USE NO. IN HL FOR DISPLACEMENT ;B CONTAINS OPERAND BYTE ;****************************************************************** DISBT: BIT 3,B ; IS OPERAND IX OR IY? RET Z ; IF NOT, NO DISP. BYTE REQD CALL CHKOF ; CHECK NO. IN HL FOR 8 BIT OVERFLOW LD A,L ; GET L.S. BYTE IN ACC. CALL APPBT ; AND APPEND TO ASSD CODE BUFFER RET ;****************************************************************** ;CHECK OVERFLOW FROM L ;VALUE ERROR INDICATED IF SO ;****************************************************************** CHKOF: PUSH BC ; SAVE BC LD A,H ; GET REG CONTAINING POSSIBLE OVERFLOW AND A ; IS IT ZERO? JR Z,CHKOF1 ; IF SO, NO OVERFLOW INC A ; WAS IT -1? (FF) JR Z,CHKOF1 ; IF SO, NO OVERFLOW LD C,'V' ; OTHERWISE INDICATE 'VALUE' ERROR CALL ERROR CHKOF1: POP BC ; REPLACE BC RET ;***************************************************************** ;INSERT SOURCE REG ;ON ENTRY: ; C CONTAINS OPERAND BYTE ; A CONTAINS CODE BYTE BEING BUILT ;ON EXIT: ; A HAS HAD THE REGISTER VALUE INSERTED ; TO BITD 0,1 & 2 ;***************************************************************** ISREG: PUSH BC ; SAVE REG LD B,A ; SAVE CODE BEING BUILT IN B LD A,C ; GET OPERAND BYTE FROM C AND 00000111B ; MASK REGISTER VALUE OR B ; COMBINE WITH CODE BEING BUILT POP BC ; REPLACE REG RET ;****************************************************************** ;INSERT DESTINATION REGISTER ;ON ENTRY: ; C CONTAINS OPERAND BYTE ; A CONTAINS CODE BYTE BEING BUILT ;ON EXIT: ; A HAS HAD THE REGISTER VALUE INSERTED ; TO BITS 3,4 & 5 ;****************************************************************** IDREG: PUSH BC ; SAVE BC LD B,A ; SAVE CODE BEING BUILT IN B LD A,C ; GET OPERAND BYTE FROM C AND 00000111B ; MASK REGISTER VALUE RLCA ; SHIFT TO DESTINATION REG POSITION RLCA RLCA OR B ; COMBINE WITH CODE BEING BUILT POP BC ; REPLACE BC RET ;****************************************************************** ;INSERT REGISTER PAIR ;ON ENTRY: ; C CONTAINS OPERAND BYTE ; A CONTAINS CODE BYTE BEING BUILT ;ON EXIT: ; A HAS HAD THE REGISTER PAIR VALUE ; INSERTED TO BITS 4 & 5. ;****************************************************************** IREGP: PUSH BC ; SAVE BC LD B,A ; SAVE CODE BEING BUILT IN B LD A,C ; GET OPERAND BYTE FROM C AND 00000011B ; MASK REGISTER PAIR VALUE RLCA ; SHIFT TO CORRECT REG PAIR POSITION RLCA RLCA RLCA OR B ; COMBINE WITH CODE BEING BUILT POP BC ; REPLACE BC RET ;******************************************************************* ;APPEND WORD TO ASSEMBLED CODE BUFFER ;******************************************************************* APPWD: LD A,L ; APPEND LOW BYTE CALL APPBT LD A,H ; APPEND HIGH BYTE CALL APPBT RET ;******************************************************************* ;APPEND BYTE TO ASSEMBLED CODE BUFFER ;******************************************************************* APPBT: PUSH HL ; SAVE REGISTERS PUSH DE EX AF,AF' ; SAVE NEW BYTE IN A' LD HL,ASSCOD ; SET POINTER TO ASSD CODE BUFF LD A,(ASCDNO) ; GET 'NO. BYTES ASSD CODE' LD E,A ; TO E LD D,0 ; CLEAR D ADD HL,DE ; ADD TO POINTER EX AF,AF' ; RECOVER NEW BYTE LD (HL),A ; AND PUT IN ASSD CODE BUFF INC E ; INCR CNTR LD A,E ; AND REPLACE LD (ASCDNO),A ; IN 'NO. BYTES ASSD CODE' POP DE ; REPLACE REGS POP HL RET ;******************************************************************* ;ADJUST ADDRESS REFERENCE COUNTER ;******************************************************************* ADJARC: PUSH HL ; SAVE REGS PUSH DE LD HL,(ADREFC) ; GET ADDR REF CNTR LD A,(ASCDNO) ; ADD TO THIS VALUE THE NO. LD E,A LD D,0 ; OF BYTES OF ASSD CODE ADD HL,DE ; AND PUT BACK INTO LD (ADREFC),HL ; ADDR REF CNTR POP DE ; REPLACE REGS POP HL RET ;****************************************************************** ;DEFAULT NOP'S ;****************************************************************** DNOPS: PUSH BC ; SAVE BC LD C,'S' ; INDICATE SYNTAX ERROR CALL ERROR LD A,4 ; RESERVE 4 BYTES NOP'S LD (ASCDNO),A POP BC ; REPLACE BC RET ;****************************************************************** ;PERFORM RELEVANT OUTPUT ;****************************************************************** PFRLO: LD A,(PASSNO) ; WHICH PASS? CP 1 RET Z ; NO OUTPUT ON PASS 1 CP 2 JR Z,PFRLO1 ; JUMP IF PASS 2 CP 3 JR Z,PFRLO2 ; JUMP IF PASS 3 LD A,(ERRBUF) CP SPACE RET Z CALL OLNBF ; OUTPUT LINE BUFFER TO LIST DEV. CALL LSTLN ; LIST RESULTS OF ASSEMBLY RET PFRLO1: CALL LSTLN ; LIST RESULTS OF ASSEMBLY LD A,(AFLAGS) ; TEST 'END' FLAG BIT 1,A RET Z ; LOOP IF NOT END CALL LSYMT ; LIST SYMBOL TABLE RET PFRLO2: CALL OBJO ; DO OBJECT FILE OUTPUT RET ;***************************************************************** ;OUTPUT CONTENTS OF LINE BUFFER TO LIST DEV. ;***************************************************************** OLNBF: PUSH HL ; SAVE REGS PUSH BC LD HL,LINBUF ; SET POINTER TO LINE BUFFER OLNBF1: LD C,(HL) ; GET A CHAR CALL LO ; OUTPUT TO LIST DEVICE LD A,C ; WAS IT CR? CP CR JR Z,OLNBF2 ; JUMP IF SO INC HL JR OLNBF1 OLNBF2: POP BC ; REPLACE REGS POP HL RET ;**************************************************************** ;LIST RESULT OF ASSEMBLY OF 1 LINE. ;**************************************************************** LSTLN: PUSH HL ; SAVE REGS PUSH DE PUSH BC PUSH IX LD A,(ERRBUF) ; PRINT CONTENTS OF ERROR BUFFER LD C,A CALL LO LD C,SPACE ; PRINT SPACE CALL LO LD HL,(ADDISR) ; GET CONT. OF ADDR DISP. REG LD A,(ASCDNO) ; GET NO. OF BYTES OF ASSD. CODE LD D,A ; INTO D LD IX,ASSCOD ; SET POINTER TO ASSD. CODE LSTLN3: LD E,4 ; MAX. NO. OF BYTES/LINE PUSH DE ; PRESERVE D CALL LISTAD ; PRINT ADDR REF. POP DE LD C,SPACE ; PRINT SPACE CALL LO LD A,D ; ANY BYTES TO PRINT AND A JR Z,LSTLN4 ; JUMP IF NOT LSTLN1: LD A,(IX) ; GET BYTE PUSH DE ; PRESERVE D CALL LISTBT ; PRINT 1 BYTE POP DE INC IX ; INCR POINTER TO NEXT BYTE INC HL ; INCR CORRES. ADDR. REF. DEC E DEC D ; DECR NO OF BYTES JR Z,LSTLN4 ; JUMP IF NONE LEFT LD A,E ; PRINTED 4 ON THIS LINE? AND A JR NZ,LSTLN1 ; JUMP IF NOT LSTLN2: CALL LFEED LD C,CR ; PRINT CR CR SP SP LD B,2 CALL OUTC LD C,SPACE LD B,2 CALL OUTC JR LSTLN3 LSTLN4: RLC E ; PRINT SPACES UP TO BEGINNING OF TEXT INC E LD B,E LD C,SPACE CALL OUTC ; OUTPUT CHAR N TIMES CALL LFEED ; PRINT LF OR NEW PAGE HEADER POP IX ; REPLACE REGS POP BC POP DE POP HL RET ;******************************************************************* ;OUTPUT CHAR N TIMES TO LIST DEVICE ;******************************************************************* OUTC: CALL LO ; COUNT IN B DJNZ OUTC RET ;******************************************************************* ;LIST BYTE ;CONVERTS BYTE IN ACC TO 2 ASCII ;HEXADECIMAL CHARACTERS AND OUTPUTS THEM ;TO LIST OR PUNCH DEVICE DEPENDING ON PASS. ;THE BYTE IS ALSO SUBTRACTED FROM D TO ;HELP COMPUTE CHECKSUMS. ;******************************************************************* LISTBT: PUSH BC ; SAVE REGS LD B,A ; SAVE BYTE IN B AND 0F0H ; GET M.S. NIBBLE RRCA RRCA RRCA RRCA CALL BINHX ; CONVERT TO ASCII HEXADECIMAL LD C,A ; OUTPUT TO RELEVANT DEVICE CALL XO LD A,B ; GET BYTE AGAIN AND 0FH ; GET L.S. NIBBLE CALL BINHX ; CONVERT TO ASCII HEX LD C,A ; OUTPUT TO RELEVANT DEVICE CALL XO LD A,D ; GET CUMULATIVE CHECKSUM SUB B ; SUBTRACT NEW BYTE LD D,A ; REPLACE CHECKSUM POP BC ; REPLACE REG RET ;................................................................. BINHX: CP 10D ; CONVERT VALUE IN A TO ASCII HEX JR NC,BINHX1 ADD A,'0' RET BINHX1: ADD A,'A'-10D RET ;********************************************************************** ;OUTPUT TO DEVICE RELEVANT TO PASS NO. ;********************************************************************** XO: LD A,(PASSNO) CP 3 JP Z,PCHO JP LO ;********************************************************************** ;LIST ADDRESS ;********************************************************************** LISTAD: LD A,H CALL LISTBT LD A,L CALL LISTBT RET ;********************************************************************** ;LINE FEED. ;********************************************************************** LFEED: PUSH BC ; SAVE REGS LD A,(LINE) ; TIME FOR A NEW PAGE? CP PLINES-9-1 JR NC,LFEED1 INC A ; INCREMENT LINE NO. LD (LINE),A LD C,LF ; PRINT LF CALL LO JR LFEED2 LFEED1: CALL HEADR ; PRINT PAGE HEADER LD C,SPACE LD B,16D CALL OUTC LFEED2: POP BC ; REPLACE REGS RET ;********************************************************************* ;PRINT PAGE HEADER ON LIST DEVICE ;********************************************************************* HEADR: PUSH HL ; SAVE REGS PUSH BC LD C,CR ; PRINT CR, 5 X LF CALL LO LD C,LF LD B,5 CALL OUTC LD HL,PHEAD ; POINTER TO PAGE HEADING CALL LSTST JR HEADR1 PHEAD: DEFM 'CROWE Z80 ASSEMBLER V1.1 PAGE ' DEFB 0 HEADR1: CALL PRNTP ; PRINT PAGE NO. CALL INCP ; INCREMENT PAGE NO. XOR A ; ZERO LINE NO. LD (LINE),A LD C,CR ; PRINT CR LF CALL LO LD C,LF CALL LO LD HL,TITBUF ; PRINT CONTENTS OF TITLE BUFFER CALL LSTST LD C,CR ; PRINT CR, 3 X LR, 16 X SP CALL LO LD C,LF LD B,3 CALL OUTC POP BC ; REPLACE REGS POP HL RET ;********************************************************************** ;LIST STRING ;********************************************************************** LSTST: PUSH BC ; SAVE REG LSTST1: LD A,(HL) ; GET A CHAR AND A ; TEST FOR TERMINATOR CHAR JR Z,LSTST2 LD C,A ; IF NOT, PRINT IT CALL LO INC HL ; INCREMENT POINTER JR LSTST1 ; LOOP LSTST2: POP BC ; REPLACE REGS RET ;********************************************************************** ;PRINT PAGE NO. ;********************************************************************** PRNTP: PUSH HL ; SAVE REGS PUSH DE LD DE,0 ; CLEAR DIGIT CNTR AND NON ZERO FLAG LD HL,PAGE+1 CALL PNT2DG DEC HL CALL PNT2DG POP DE ; REPLACE REGS POP HL RET ;.................................................................... ;PRINT 2 DIGITS ;.................................................................... PNT2DG: RLD ; ROTATE NIBBLES CALL PNTDG ; PRINT A DIGIT RLD ; ROTATE NIBBLES CALL PNTDG ; PRINT A DIGIT RLD ; ROTATE NIBBLES RET ;................................................................... ;PRINT A DIGIT ;................................................................... PNTDG: PUSH BC ; SAVE REG LD B,A ; INCR DIGIT COUNT INC E AND 0FH JR NZ,PNTDG1 ; IS IT 0? BIT 0,D ; LEADING ZERO? JR NZ,PNTDG2 JR PNTDG3 PNTDG1: SET 0,D ; NON ZERO, SET FLAG PNTDG2: OR 30H ; CONVERT TO ASCII LD C,A ; PRINT IT CALL LO PNTDG3: LD A,B POP BC ; REPLACE REG RET ;******************************************************************* ;INCREMENT PAGE NO. ;******************************************************************* INCP: PUSH HL ; SAVE REG LD HL,(PAGE) ; GET PAGE NO (4 DIG BCD) LD A,L ; INCREMENT L.S. BYTE ADD A,1 DAA ; DECIMAL ADJUST LD L,A LD A,H ; CARRY TO M.S. BYTE ADC A,0 DAA ; DECIMAL ADJUST LD H,A LD (PAGE),HL ; REPLACE PAGE NO. POP HL ; REPLACE REG RET ;******************************************************************* ;LIST SYMBOL TABLE ;******************************************************************* LSYMT: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD C,CR ; OUTPUT CR CALL LO LD A,(LINE) ; GET LINE NO. LSYMT1: CP PLINES-9-1 ; BOTTOM OF PAGE? JR NC,LSYMT3 ; JUMP IF SO INC A ; ELSE INCR LINE NO. LD B,A ; SAVE IN B LD C,LF ; OUTPUT LF CALL LO LD A,B ; GET LINE NO. IN A JR LSYMT1 ; LOOP LSYMT3: CALL HEADR ; PRINT PAGE HEADER LD HL,SYMTAB ; POINT AT SYMBOL TABLE LSYMT4: LD D,SPERL ; LOAD NO OF SYMBOLS PER LINE LSYMT5: LD A,(HL) ; GET CHAR COUNT AND A ; IS IT ZERO? JR Z,LSYM10 ; JUMP IF SO, END OF TABLE LD B,A ; PUT COUNT IN B LD E,7 ; SPACES COUNT IN E INC HL ; INCR PNTR ; PRINT SYMBOL LSYMT6: LD C,(HL) ; GET CHAR IN C CALL LO ; OUTPUT TO LIST DEVICE INC HL ; INCR PNTR DEC E ; DECR SPACE CNTR DEC B ; DECR CHAR CNTR JR NZ,LSYMT6 ; LOOP IF NOT FINISHED LD B,E ; GET SPACES COUNT LD C,SPACE ; AND OUTPUT THAT NO. CALL OUTC ; OF SPACES INC HL ; INCR PNTR TO VALUE LD A,(HL) ; GET M.S. BYTE PUSH DE ; SAVE DE CALL LISTBT ; OUTPUT IN HEX DEC HL ; POINT AT L.S. BYTE LD A,(HL) ; GET IT CALL LISTBT ; OUTPUT IN HEX POP DE ; REPLACE DE INC HL ; POINT TO ATTRIBUTE BYTE INC HL LD C,SPACE ; OUTPUT A SPACE CALL LO LD C,SPACE ; SET UP A FURTHER SPACE BIT 1,(HL) ; M FLAG SET? INC HL ; (INCR POINTER) JR Z,LSYMT7 ; JUMP IF NOT LD C,'M' ; CHANGE SPACE TO 'M' LSYMT7: CALL LO ; OUTPUT CHAR DEC D ; DECR SYM/LINE CNT JR Z,LSYMT8 ; JUMP IF DONE LD C,SPACE ; ELSE OUTPUT 2 SPACES LD B,2 CALL OUTC JR LSYMT5 ; AND LOOP LSYMT8: LD A,(LINE) ; GET LINE NO. CP PLINES-9-1 ; BOTTOM OF PAGE? JR NC,LSYMT9 ; JUMP IF SO INC A ; ELSE INCR LINE NO. LD (LINE),A LD C,CR ; LIST CR/LF CALL LO LD C,LF CALL LO JR LSYMT4 ; AND LOOP LSYMT9: CALL HEADR ; PRINT PAGE HEADER JR LSYMT4 ; AND LOOP LSYM10: POP BC ; REPLACE REGS POP DE POP HL RET ;*************************************************************** ;OBJECT OUTPUT. ;PERFORM OUTPUT OF OBJECT CODE USING THE INTEL ;HEXADECIMAL OBJECT FORMAT WITH RECORD LENGTH ;OF 'RECSIZ' ;*************************************************************** OBJO: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD HL,AFLAGS ; END FLAG SET? BIT 1,(HL) JR Z,OBJO2 ; JUMP IF NOT CALL ODREC ; PUNCH DATA RECORD CALL OEREC ; PUNCH EOF RECORD CALL RUNOUT ; PUCH TAPE RUNOUT JR OBJO7 OBJO2: BIT 0,(HL) ; ADDR DISCONTINUITY FLAG SET? JR Z,OBJO3 ; JUMP IF NOT CALL ODREC ; PUNCH DATA RECORD JR OBJO7 OBJO3: LD C,0 ; CLEAR PNTR TO ASSD CODE BUFFER LD A,(ASCDNO) ; ANY BYTES OF ASSD CODE? LD B,A ; SAVE NO. IN B AND A ; ZERO? OBJO4: JR Z,OBJO7 ; JUMP IF ZERO LD HL,(ADDISR) ; GET ADDR DISP REG IN HL LD A,(OBJCNT) ; ANY BYTES IN OBJECT BUFFER? AND A JR NZ,OBJO5 ; JUMP IF SO LD (RECADR),HL ; ELSE COPY ADDR DISP REG ; INTO RECORD ADDR OBJO5: INC HL ; INCR ADDR DISP REG LD (ADDISR),HL ; TRANSFR BYTE FROM ASSD CODE BUFF ; TO OBJECT BUFFER LD HL,ASSCOD ; POINT AT ASSD CODE BUFF LD E,C ; PUT ASSD CODE BUFF CNTR IN DE LD D,0 ADD HL,DE ; COMPUTE PNTR TO BYTE FOR TRANSFER LD A,(HL) ; GET BYTE EX AF,AF' ; SAVE IN A' LD HL,OBJBUF ; POINT AT OBJECT BUFF LD A,(OBJCNT) ; PUT OBJ BUFF CNTR IN DE LD E,A ADD HL,DE ; COMPUTE PNTR TO INSERT POSITION EX AF,AF' ; GET BACK BYTE LD (HL),A ; AND APPEND TO OBJECT BUFFER LD A,E ; GET OBJ COUNT INC A ; INCREMENT IT LD (OBJCNT),A ; REPLACE COUNT IN OBJCNT CP RECSIZ ; ENOUGH BYTES FOR A RECORD JR NZ,OBJO6 ; JUMP IF NOT CALL ODREC ; ELSE OUTPUT DATA RECORD OBJO6: INC C ; INCREMENT ASD CODE BUFF CNTR DEC B ; DECR NO OF BYTES JR OBJO4 ; AND LOOP OBJO7: POP BC ; REPLACE REGS POP DE POP HL RET ;*********************************************************************** ;OUTPUT DATA RECORD ;OUTPUTS DATA RECORD USING INTEL'S HEXADECIMAL ;OBJECT CODE FORMAT ;*********************************************************************** ODREC: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD A,(OBJCNT) ; GET NO OF BYTES IN OBJ BUFF AND A ; IS IT ZERO? JR Z,ODREC2 ; JUMP IF SO LD B,A ; PUT COUNT IN B LD C,':' ; OUTPUT RECORD MARK CALL PCHO ; TO PUNCH DEVICE LD D,0 ; CLEAR CHECKSUM REG D LD A,B ; OUTPUT BYTE COUNT CALL LISTBT LD HL,(RECADR) ; OUTPUT RECORD ADDR CALL LISTAD XOR A ; OUTPUT RECORD TYPE (0) CALL LISTBT LD HL,OBJBUF ; SET PNTR TO OBJECT BUFFER ODREC1: LD A,(HL) ; OUTPUT DATA BYTE CALL LISTBT INC HL ; INCR PNTR DEC B ; DECR COUNT JR NZ,ODREC1 ; LOOP IF NOT ZERO LD A,D ; OUTPUT CHECKSUM CALL LISTBT LD C,CR ; OUTPUT CR CALL PCHO LD C,LF ; OUTPUT LF CALL PCHO XOR A ; SET NO. OF BYTES IN OBJBUF=0 LD (OBJCNT),A ODREC2: POP BC ; REPLACE REGS POP DE POP HL RET ;******************************************************************** ;OUTPUT END OF FILE RECORD ;OUTPUTS END OF FILE RECORD TO PUNCH DEVICE ;USING INTEL'S HEXADECIMAL OBJECT FORMAT ;******************************************************************** OEREC: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD C,':' ; OUTPUT RECORD MARK CALL PCHO XOR A ; CLEAR A AND CHECKSUM (IN D) LD D,A CALL LISTBT ; OUTPUT ZERO BYTE COUNT LD HL,(STADDR) ; GET START ADDR CALL LISTAD ; AND OUTPUT IT LD A,1 ; OUTPUT RECORD TYPE (1) CALL LISTBT LD A,D ; OUTPUT CHECKSUM CALL LISTBT LD C,CR ; OUTPUT CR CALL PCHO LD C,LF ; OUTPUT LF CALL PCHO POP BC ; REPLACE REGS POP DE POP HL RET ;******************************************************************* ;RUNOUT ;OUTPUTS 30 CM OF BLANK TAPE FOR PUNCHED TAPE ;LEADER AND TRAILER. ;IF NOT REQUIRED PUT 'RET' IN FIRST LOCATION ;OF SUBROUTINE. ;******************************************************************* RUNOUT: RET;PUSH BC ; SAVE REG LD B,120 ; PUT COUNT IN B LD C,NUL ; PUT NULL CHAR IN C RUN1: CALL PCHO ; OUTPUT CHAR TO PUNCH DJNZ RUN1 ; LOOP UNTIL DONE POP BC ; REPLACE REG RET ;******************************************************************* ;GET SYMBOL ;ON ENTRY: ; HL POINTS AT 1ST CHAR OF SYMBOL ; DE POINTS AT BUFFER ;ON EXIT: ; HL POINTS AT CHAR AFTER SYMBOL ; BUFFER CONTAINS SYMBOL ;******************************************************************* GSYM: PUSH IX ; SAVE REGISTERS PUSH BC LD B,0 ; CLEAR CHAR COUNT PUSH DE ; SAVE START OF BUFFER POINTER POP IX INC DE ; LEAVE SPACE IN BUFF FOR CHAR COUNT GSYM1: LD (DE),A ; PUT CHAR IN BUFFER INC DE ; INCREMENT POINTERS INC HL INC B ; AND COUNTER LD A,B ; IS THAT 6 CHARS? CP 6 JR Z,GSYM2 LD A,(HL) ; FETCH NEXT CHAR CALL VALID ; IS IT VALID IN A SYMBOL? JR C,GSYM1 ; JUMP IF SO GSYM3: LD (IX),B ; NO, END OF SYMBOL POP BC ; REPLACE SAVED REGISTERS POP IX RET GSYM2: LD A,(HL) ; SCAN TO FIRST NON VALID CHAR CALL VALID JR NC,GSYM3 INC HL JR GSYM2 ;********************************************************************** ;VALID LABEL CHAR? ;ON ENTRY: ; A CONTAINS CHARACTER ;ON EXIT: ; A CONTANS CHARACTER ; CARRY FLAG IS SET IF VALID. ;************************************************************************ VALID: CP 'A' JR C,VALID1 CP 'Z'+1 RET C ; VALID VALID1: CP '0' JR C,VALID2 CP '9'+1 RET C ; VALID VALID2: CP '?' JR Z,VALID3 CP '-' JR Z,VALID3 SCF ; NOT VALID, CLEAR CARRY FLAG. CCF RET VALID3: SCF ; VALID, SET CARRY FLAG RET ;********************************************************************* ;GET TOKEN(S) FROM LIST ;ON ENTRY: ; SYMBUF CONTAINS SYMBOL ; HL CONTAINS POINTER TO LIST POINTER TABLE ; DE POINTS AT DESTINATION FOR TOKENS ; C CONTAINS NO. OF TOKEN BYTES PER LIST ENTRY. ;ON EXIT: ; TOKEN(S) ARE IN DESTINATION. ; LAST ONE IS ALSO IN A ; ZERO FLAG SET IF NOT IN LIST. ;********************************************************************** OPTOK: PUSH DE ; SAVE PTR TO DEST FOR TOKENS. LD A,(SYMBUF) ; GET NO. OF BYTES IN STRING LD B,A PUSH BC ; SAVE TOKEN BYTE COUNT (C) ; AND STRING CHAR COUNT (B) SUB 1 ; (BYTES IN STRING - 1) RLCA ; *2 LD E,A LD D,0 ADD HL,DE ; POINTER TO CORRECT WORD OF PNTR TABL LD A,(HL) INC HL LD H,(HL) LD L,A ; HL POINTS TO CORRECT SECTION OF LIST OPTOK3: LD DE,SYMBUF+1 POP BC PUSH BC ; B CONTAINS NO. OF CHARS IN STRING LD A,(HL) ; GET FIRST CHAR OF LIST ENTRY OR A ; IS IT 0? JR Z,OPTOK4 ; YES, END OF LIST OPTOK1: EX DE,HL ; NO, COMPARE A CHAR CP (HL) EX DE,HL INC HL ; INCR POINTERS INC DE JR NZ,OPTOK2 ; CHARS NOT EQU, GO TO NEXT ENTRY DEC B ; CHARS EQU, DECR COUNT LD A,(HL) ; GET A CHAR JR NZ,OPTOK1 ; MORE CHARS TO COMPARE POP BC ; NO MORE CHARS TO COMPARE POP DE ; MATCH FOUND, GET POINTER AND ; COUNT FOR TOKEN BUFFER. OPTOK5: LD A,(HL) LD (DE),A ; TRANSFER A BYTE INC HL INC DE DEC C JR NZ,OPTOK5 INC C ; CLEAR ZERO FLAG RET ; AND RETURN OPTOK4: POP BC ; ADJUST STACK POP DE RET ; AND RETURN OPTOK2: LD A,B ; ADD REMAINING COUNT+ ; (NO OF TOKENS)-1 TO LIST PNTR POP BC PUSH BC ADD A,C DEC A LD E,A LD D,0 ADD HL,DE ; HL POINTING TO NEXT LIST ENTRY JR OPTOK3 ; GO CHECK NEXT ENTRY ;************************************************************************* ;LOCATE A GIVEN SYMBOL IN THE SYMBOL TABLE, ;OR THE CORRECT ALPHABETIC LOCATION FOR IT. ;ON ENTRY: ; SEARCHED SYMBOL IS IN SYMBOL BUFFER. ;ON EXIT: ; DE CONTAINS PNTR TO START OF ENTRY ; OR ALPHABETIC INSERTION POSITION. ; HL POINTS AT VALUE IF PRESENT ; ZERO FLAG SET IF FOUND IN TABLE. ;************************************************************************* LOCATE: PUSH BC ; SAVE REGISTERS PUSH IX LD HL,SYMTAB ; SET POINTER TO SYMBOL TABLE LOC1: PUSH HL ; SAVE POINTER TO START OF ENTRY POP DE ; IN DE LD C,(HL) ; SAVE NO OF CHARS IN SYM IN C INC C ; TEST C FOR ZERO DEC C JR Z,LOC3 ; IF ZERO THEN END OF TABLE LD IX,SYMBUF ; SET POINTER TO SYMBOL BUFFER LD B,(IX) ; SAVE NO OF CHARS IN SEARCHED SYM INC HL ; MOVE BOTH POINTERS TO 1ST INC IX ; CHARS OF SYMBOLS LOC2: LD A,(IX) ; COMPARE A CHAR CP (HL) JR C,LOC3 ; TOO FAR JR NZ,LOC5 ; NOT FAR ENOUGH ; CHARS EQUAL SO FAR INC HL ; MOVE BOTH POINTERS ON 1 INC IX DEC C ; DECR TABL SYM CHAR COUNT JR Z,LOC6 DEC B ; DECR SEARCHED SYM CHAR COUNT JR Z,LOC3 ; TOO FAR JR LOC2 ; EQUAL SO FAR LOC6: DEC B JR Z,LOC4 ; MATCH FOUND, RETURN WITH ZERO ; FLAG SET, DE POINTING AT ; ENTRY, & HL AT VALUE LOC5: LD A,3 ; SET POINTER TO NEXT ENTRY ; (ADD COUNTER+3 TO TABLE POINTER) ADD A,C LD C,A LD B,0 ADD HL,BC JR LOC1 LOC3: INC C ; TOO FAR, RESET ZERO FLAG LOC4: POP IX ; REPLACE REGS & RETURN POP BC ; WITH ZERO FLAG=0 RET ; DE CONTAINS START OF ENTRY ;*********************************************************************** ;TRANSFER LABEL (AND VALUE) TO SYMBOL BUFFER ;ON ENTRY: HL CONTAINS VALUE OF LABEL ;ON EXIT: HL CONTAINS POINTER TO ATTRIBUTE BYTE ; IN SYMBOL BUFFER ;*********************************************************************** LBSYM: PUSH BC ; SAVE REGS PUSH DE LD A,(LABBUF) ; HOW MANY CHARS IN LABEL? AND A ; IS IT ZERO? JR Z,LBSYM1 ; JUMP IF SO, NO LABEL INC A ; ADD 1 TO NUMBER LD C,A ; AND PUT IT IN BC LD B,0 PUSH HL ; SAVE VALUE OF LABEL LD HL,LABBUF ; SET SOURCE PNTR = LABEL BUFFER LD DE,SYMBUF ; SET DEST PNTR = SYMBOL BUFFER LDIR ; TRANSFER LABEL TO SYMBOL BUFFER EX DE,HL ; PUT SYMBOL BUFF PNTR IN HL POP DE ; GET VALUE IN DE LD (HL),E ; AND PUT IN SYMBUF INC HL LD (HL),D INC HL LD (HL),0 ; CLEAR ATTRIBUTES BYTE XOR A ; CLEAR ZERO FLAG INC A LBSYM1: POP DE ; REPLACE REGS POP BC RET ;*********************************************************************** ;CHECK SYMBOL IS NOT RESERVED WORD ;ON ENTRY SYMBOL IS IN SYMBUF ;CARRY FLAG SET IF RESERVED WORD. ;*********************************************************************** SYMCH: PUSH HL ; SAVE REGISTERS PUSH DE PUSH BC ; CHECK IF SYMB = RESERVED WORD LD A,(SYMBUF) ; GET NO OF CHARS IN SYMB CP 6 ; MORE THAN 5 ? JR NC,SYMCH3 ; IF SO NOT RESERVED WORD LD DE,TEMP ; CHECK IF IN OPERATOR LIST LD HL,ORLSTP ; PNTR TO OPR LIST PNTR TABLE LD C,2 ; 2 TOKENS/ENTRY IN LIST CALL OPTOK ; IN LIST? JR NZ,SYMCH1 ; JUMP IF SO LD A,(SYMBUF) ; GET NO OF CHARS IN SYMB CP 4 ; MORE THAT 3? JR NC,SYMCH3 ; IF SO NOT RESERVED WORD LD DE,TEMP ; CHECK IF IN OPND KW LIST LD HL,OPKLST ; PNTR TO LIST PNTR TABLE LD C,1 ; 1 TOKEN/ENTRY IN LIST CALL OPTOK ; IN LIST? JR Z,SYMCH2 ; JUMP IF NOT ; RESERVED WORD USED SYMCH1: LD C,'W' ; INDICATE ERROR CALL ERROR SCF ; SET CARRY FLAG JR SYMCH3 SYMCH2: AND A ; NOT RESERVED WORD, CLEAR CARRY SYMCH3: POP BC ; REPLACE REGISTERS POP DE POP HL RET ;********************************************************************** ;INSERT SYMBOL INTO SYMBOL TABLE ;ON ENTRY DE POINTS AT INSERTION POSITION ;SYMBOL IS IN SYMBOL BUFFER (SYMBUF) ;********************************************************************** INSERT: EXX ; SAVE REGS PUSH HL PUSH DE PUSH BC EXX PUSH HL PUSH BC PUSH DE LD HL,(MEMTOP) ; GET POINTER TO TOP OF LD DE,-10 ; AVAILABLE RAM (WITH ROOM FOR ANOTHER ADD HL,DE ; ENTRY) LD DE,(SYMEND) ; GET PNTR TO END OF SYMBOL TABLE AND A ; CLEAR CARRY SBC HL,DE ; IS TABLE FULL? JR NC,INSRT1 ; JUMP IF NOT LD HL,AFLAGS ; SET SYM TAB OVERFLOW FLAG SET 2,(HL) POP DE ; ADJUST STACK JR INSRT2 INSRT1: POP DE ; LEAVE PNTR TO INSERT POS IN DE' PUSH DE EXX POP DE ; GET PNTR TO INSERT POS ; OPEN UP A GAP IN TABLE USING ; BLOCK MOVE. DE WILL CONTAIN DEST. ; HL THE SOURCE AND BC THE NO. ; OF BYTES AND A ; CLEAR CARRY LD HL,(SYMEND) ; FIND NO OF BYTES BETWEEN INSERTION SBC HL,DE ; POSITION AND END OF SYMBOL INC HL ; TABLE PUSH HL ; SAVE NO OF BYTES ON STACK LD HL,(SYMEND) LD D,H LD E,L LD A,(SYMBUF) ; CALCULATE NO OF BYTES FOR INSERTION ADD A,4 LD C,A ; PUT IN BC LD B,0 PUSH BC ; SAVE IN BC' EXX POP BC EXX ADD HL,BC LD (SYMEND),HL ; SAVE NEW END OF SYMBOL TABLE EX DE,HL POP BC ; NO OF BYTES LDDR ; MOVE BLOCK TO OPEN GAP ; INSERT NEW SYMBOL RECORD ; INTO GAP EXX LD HL,SYMBUF LDIR INSRT2: POP BC ; REPLACE REGS POP HL EXX POP BC POP DE POP HL EXX RET ;********************************************************************* ;SCAN TO NEXT NON SPACE CHAR ;ON ENTRY: ; HL CONTAINS POINTER ;ON EXIT: ; HL POINTS AT FIRST NON-SPACE CHAR ;********************************************************************* SCNSP: LD A,(HL) ; GET A CHAR CP SPACE ; IS IT A SPACE? RET NZ ; IF NOT RETURN INC HL ; INCREMENT POINTER JR SCNSP ;********************************************************************* ;CHECK IF ASCII CHAR IN ACC ;IS A LETTER. SET CARRY FLAG IF SO. ;********************************************************************* ALPHA: CP 'A' JR C,ALPHA1 CP 'Z'+1 RET ALPHA1: OR A ; NOT LETTER, CLEAR CARRY RET ;********************************************************************* ;CHECK IF DIGIT (0-9) IN ACC. ;IF SO, RETURN WITH CARRY SET. ;********************************************************************* DIGIT: CP '0' JR C,DIGIT1 CP '9'+1 RET DIGIT1: OR A ; NOT DIGIT, CLEAR CARRY RET ;******************************************************************** ;ERROR ROUTINE. SET ERROR CHAR IF NOT ;ALREADY SET. ;ON ENTRY: ; C CONTAINS ASCII ERROR CHAR ;ON EXIT: ; ERRBUF CONTAINS ERROR CHAR ;******************************************************************* ERROR: LD A,(ERRBUF) ; GET CONTENT OF ERROR DISPLAY REG. CP SPACE ; IS IT A SPACE? RET NZ LD A,C ; YES, REPLACE WITH ERROR INDICATOR LD (ERRBUF),A RET ;******************************************************************* ;OPERATOR LIST ;EACH SECTION OF LIST CONTAINS OPERATOR ;STRING FOLLOWED BY OPERATOR GROUP TOKEN ;(1-1D) FOLLOWED BY OPERATOR VALUE. ;******************************************************************* ORLSTP: DEFW OR1 ; POINTER LIST TO THE SECTIONS DEFW OR2 ; OF THE OPERATOR LIST WITH DEFW OR3 ; DIFFERENT NOS. OF CHARS DEFW OR4 DEFW OR5 OR1: DEFB 0 ; OPERATOR LIST ITSELF OR2: DEFM 'LD' DEFB 1DH DEFB 00H DEFM 'JP' DEFB 91H DEFB 00H DEFM 'CP' DEFB 0CH DEFB 38H DEFM 'IN' DEFB 17H DEFB 00H DEFM 'OR' DEFB 0CH DEFB 30H DEFM 'DI' DEFB 0AH DEFB 0F3H DEFM 'EI' DEFB 0AH DEFB 0FBH DEFM 'IM' DEFB 0EH DEFB 00H DEFM 'RL' DEFB 0FH DEFB 10H DEFM 'RR' DEFB 0FH DEFB 18H DEFM 'JR' DEFB 92H DEFB 00H DEFM 'EX' DEFB 1AH DEFB 00H DEFB 00H OR3: DEFM 'INC' DEFB 0DH DEFB 00H DEFM 'DEC' DEFB 0DH DEFB 09H DEFM 'OUT' DEFB 18H DEFB 00H DEFM 'AND' DEFB 0CH DEFB 20H DEFM 'ORG' DEFB 01H DEFB 00H DEFM 'EQU' DEFB 02H DEFB 00H DEFM 'END' DEFB 04H DEFB 00H DEFM 'EXX' DEFB 0AH DEFB 0D9H DEFM 'DAA' DEFB 0AH DEFB 27H DEFM 'CPL' DEFB 0AH DEFB 2FH DEFM 'CCF' DEFB 0AH DEFB 3FH DEFM 'SCF' DEFB 0AH DEFB 37H DEFM 'NOP' DEFB 0AH DEFB 00H DEFM 'RLA' DEFB 0AH DEFB 17H DEFM 'RRA' DEFB 0AH DEFB 1FH DEFM 'LDI' DEFB 0BH DEFB 0A0H DEFM 'LDD' DEFB 0BH DEFB 0A8H DEFM 'CPI' DEFB 0BH DEFB 0A1H DEFM 'CPD' DEFB 0BH DEFB 0A9H DEFM 'NEG' DEFB 0BH DEFB 44H DEFM 'RLD' DEFB 0BH DEFB 6FH DEFM 'RRD' DEFB 0BH DEFB 67H DEFM 'INI' DEFB 0BH DEFB 0A2H DEFM 'IND' DEFB 0BH DEFB 0AAH DEFM 'XOR' DEFB 0CH DEFB 28H DEFM 'RLC' DEFB 0FH DEFB 00H DEFM 'SLA' DEFB 0FH DEFB 20H DEFM 'RRC' DEFB 0FH DEFB 08H DEFM 'SRA' DEFB 0FH DEFB 28H DEFM 'SRL' DEFB 0FH DEFB 38H DEFM 'BIT' DEFB 10H DEFB 40H DEFM 'SET' DEFB 10H DEFB 0C0H DEFM 'RES' DEFB 10H DEFB 80H DEFM 'RET' DEFB 95H DEFB 00H DEFM 'RST' DEFB 16H DEFB 00H DEFM 'POP' DEFB 19H DEFB 0C1H DEFM 'ADC' DEFB 1BH DEFB 08H DEFM 'SBC' DEFB 1BH DEFB 10H DEFM 'ADD' DEFB 1CH DEFB 00H DEFM 'SUB' DEFB 0CH DEFB 10H DEFB 00H OR4: DEFM 'CALL' DEFB 94H DEFB 00H DEFM 'DEFL' DEFB 03H DEFB 00H DEFM 'DEFB' DEFB 05H DEFB 00H DEFM 'DEFW' DEFB 06H DEFB 00H DEFM 'DEFS' DEFB 07H DEFB 00H DEFM 'DEFM' DEFB 08H DEFB 00H DEFM 'HALT' DEFB 0AH DEFB 76H DEFM 'RLCA' DEFB 0AH DEFB 07H DEFM 'RRCA' DEFB 0AH DEFB 0FH DEFM 'LDIR' DEFB 0BH DEFB 0B0H DEFM 'LDDR' DEFB 0BH DEFB 0B8H DEFM 'CPIR' DEFB 0BH DEFB 0B1H DEFM 'CPDR' DEFB 0BH DEFB 0B9H DEFM 'RETI' DEFB 0BH DEFB 4DH DEFM 'RETN' DEFB 0BH DEFB 45H DEFM 'INIR' DEFB 0BH DEFB 0B2H DEFM 'INDR' DEFB 0BH DEFB 0BAH DEFM 'OUTI' DEFB 0BH DEFB 0A3H DEFM 'OTIR' DEFB 0BH DEFB 0B3H DEFM 'OUTD' DEFB 0BH DEFB 0ABH DEFM 'OTDR' DEFB 0BH DEFB 8BH DEFM 'DJNZ' DEFB 13H DEFB 00H DEFM 'PUSH' DEFB 19H DEFB 0C5H DEFB 00H OR5: DEFM 'TITLE' DEFB 09H DEFB 00H DEFB 00H ;********************************************************************** ;OPERAND KEYWORD LIST ;CONTAINS OPERAND KEYWORDS FOLLOWED BY ;TOKENS FOR THEM. ;********************************************************************** OPKLST: DEFW OPKW1 ; POINTER LIST TO DIFFERENT DEFW OPKW2 ; SECTIONS OF OPERAND DEFW OPKW3 ; KEYWORD LIST. OPKW1: DEFB 'A' DEFB 77H DEFB 'B' DEFB 70H DEFB 'C' DEFB 71H DEFB 'D' DEFB 72H DEFB 'E' DEFB 73H DEFB 'H' DEFB 74H DEFB 'L' DEFB 75H DEFB 'Z' DEFB 89H DEFB 'P' DEFB 8EH DEFB 'M' DEFB 8FH DEFB 'I' DEFB 20H DEFB 'R' DEFB 21H DEFB 00H OPKW2: DEFM 'AF' DEFB 17H DEFM 'BC' DEFB 10H DEFM 'DE' DEFB 11H DEFM 'HL' DEFB 12H DEFM 'SP' DEFB 13H DEFM 'IX' DEFB 1AH DEFM 'IY' DEFB 1EH DEFM 'NC' DEFB 8AH DEFM 'NZ' DEFB 88H DEFM 'PE' DEFB 8DH DEFM 'PO' DEFB 8CH DEFB 00H OPKW3: DEFM 'AF''' DEFB 0E0H DEFB 00H ;********************************************************************* ;BRACKETABLE OPERAND LIST. ;********************************************************************* BKLST: DEFB 12H ; HL DEFB 40H ; (HL) DEFB 1AH ; IX DEFB 48H ; (IX) DEFB 1EH ; IY DEFB 4CH ; (IY) DEFB 13H ; SP DEFB 50H ; (SP) DEFB 11H ; DE DEFB 61H ; (DE) DEFB 10H ; BC DEFB 60H ; (BC) DEFB 71H ; C DEFB 0A0H ; (C) DEFB 0CAH ; IX+D DEFB 0BAH ; (IX+D) DEFB 0CEH ; IY+D DEFB 0BEH ; (IY+D) DEFB 90H ; N DEFB 0D0H ; (N) DEFB 00H ; END OF LIST ;********************************************************************* ;MULTI-CHARACTER FUNCTION LIST. ;********************************************************************* MFLSTP: DEFW MCF1 DEFW MCF2 DEFW MCF3 DEFW MCF4 MCF1: DEFB 0 MCF2: DEFM 'OR' DEFB 7AH DEFM 'EQ' DEFB 89H DEFM 'GT' DEFB 91H DEFM 'LT' DEFB 99H DEFB 0 MCF3: DEFM 'NOT' DEFB 17H DEFM 'LOW' DEFB 27H DEFM 'RES' DEFB 2EH DEFM 'MOD' DEFB 4DH DEFM 'SHR' DEFB 55H DEFM 'SHL' DEFB 5DH DEFM 'AND' DEFB 73H DEFM 'XOR' DEFB 82H DEFM 'UGT' DEFB 0A1H DEFM 'ULT' DEFB 0A9H DEFB 0 MCF4: DEFM 'HIGH' DEFB 1FH DEFB 0 ;*********************************************************************** ;SINGLE CHAR FUNCTION LIST. ;*********************************************************************** SFLSTP: DEFW SCF1 ; POINTER TO LIST SCF1: DEFM '+' DEFB 7H DEFM '-' DEFB 0FH DEFM '\' DEFB 17H DEFM '*' DEFB 3DH DEFM '/' DEFB 45H DEFM '&' DEFB 73H DEFM '^' DEFB 7AH DEFM '=' DEFB 89H DEFM '>' DEFB 91H DEFM '<' DEFB 99H DEFB 0 ; ;****************************************************************** ; LINKAGES TO CP/M START HERE - J.P.J. 4/5/82 ;****************************************************************** ; ; SRCFCB: DEFB 0 ;FCB STARTS WITH 0 FOR DEFAULT DRIVE SRCFN: DEFM ' ' ;RESERVE 8 CHARS FOR FILE NAME DEFM 'Z80' ;USE EXTENSION OF Z80 DEFB 0 ;START WITH EXTENT 0 DEFS 23 ;23 BYTES FOR CP/M SRCPTR: DEFS 2 ;FOR CHARACTER POINTER SRCOPN: DEFM 'C' ;DECLARE CLOSED ; LSTFCB: DEFB 0 ;LISTING FILE SETUP LSTFN: DEFM ' ' DEFM 'PRN' ;PRINT FILE DEFB 0 ;EXTENT 0 DEFS 23 LSTPTR: DEFS 2 LSTOPN: DEFM 'C' ; HEXFCB: DEFB 0 ;SAME FOR HEX FILE HEXFN: DEFM ' ' DEFM 'HEX' DEFB 0 DEFS 23 HEXPTR: DEFS 2 HEXOPN: DEFM 'C' ; MEMCK: LD A, (7H) ;GET HIGH ORDER BYTE OF BDOS ENTRY LD B,A ;XFER TO B LD A, (6H) ;LOW BYTE TO A RET ; CONOUT: PUSH BC ;NO REGISTERS MAY BE DESTROYED PUSH DE PUSH HL OUT4: LD A,C CALL PUTCON ; GENRET: POP HL ;GENERAL RETURN FOR ALL SUBR'S POP DE POP BC RET ; ; OPNOUT: PUSH DE ;OPEN (DE) FCB FOR OUTPUT LD C, DELFIL ;FIRST DELETE CURRENT CALL CPM POP DE LD C, MAKFIL ;THEN RE-CREATE JP CPM ; CONIN: PUSH BC ;CONSOLE INP IS ONLY COMMON PUSH DE ; POINT FOR ALL PASSES SO DO PUSH HL ; SETUP HERE ; LD A, (SRCOPN) ;IS SRC OPEN? CP 'O' CALL NZ, CPYFCB ;IF NOT, CREATE FCB'S LD HL, (NXTPAS) ;POINT TO PASS SEQUENCE LD A, (HL) ;GET NEXT PASS NUMBER INC HL ;UPDATE POINTER LD (NXTPAS), HL ;SAVE POINTER PUSH AF ; CP 'Q' ;QUIT ? CALL Z, FLUSH ;YES, FLUSH BUFFERS POP AF PUSH AF ; CP '1' ;PASS 1? JR Z, PAS1 CP '2' ;PASS 2? JP Z, PAS2 CP '3' ;PASS 3? JP Z, PAS3 CP '4' ;PASS 4 USES CONSOLE OUTPUT JR Z, PAS1 INPRET: POP AF ;IF NONE OF ABOVE, EXIT JR GENRET ; NXTPAS: DEFW SEQNO ;SEQUENCE # POINTER SEQNO: DEFM '1423Q' ;DEFAULT SEQUENCE CPYFCB: LD HL, DFCB+9 ;POINT TO FILE EXTENSION LD DE, SEQNO+2 ;POINT TO PASS 2 FLAG LD A, (HL) ;GET DRIVE/SKIP FLAG FOR LST CP 'N' JR Z, CPYF1 ;IF N, SKIP THE SRC LIST CP 'B' ;PUT ON DRIVE B? JR NZ, DOIT ;NO, PUT LISTING ON DRIVE A LD A, 2 ;B IS DRIVE 2 LD (LSTFCB),A ;SET DRIVE BYTE TO 'B' JR DOIT CPYF1: LD (DE), A ;SKIP IT DOIT: INC HL ;POINT TO HEX SWITCH INC DE ;POINT TO PASS 3 FLAG LD A,(HL) ;GET DRIVE/SKIP FOR HEX CP 'N' ;SKIP? JR Z, CPYF2 ;IF Z, SKIP CP 'B' ;PUT ON DRIVE B? JR NZ, COPYIT ;IF NOT 'B' NO LD A,2 ;B IS DRIVE 2 LD (HEXFCB),A JR COPYIT CPYF2: LD (DE), A ;DON'T DO IT COPYIT: LD BC, 8H ;SETUP FOR LDIR ; LD DE, SRCFN ;DESTINATION PUSH BC CALL MOVFCB ; LD DE, LSTFN POP BC PUSH BC CALL MOVFCB ; LD DE, HEXFN POP BC ; MOVFCB: LD HL, DFCB+1 ;FILE NAME STARTS IN POS 1 LDIR RET ; PAS1: XOR A ;MAKE SURE OPEN FIRST LD (SRCFCB+12), A ; EXTENT LD DE, SRCFCB LD C, OPNFIL CALL CPM CP 0FFH ;SUCESSFUL? JR Z, NOSRC ; NO, LET US KNOW LD A, 'O' ; DECLARE OPEN LD (SRCOPN), A XOR A ;FIRST RECORD IS #0 LD (SRCFCB+32), A LD HL, SRCBUF+1024 LD (SRCPTR), HL JR INPRET ; NOSRC: LD DE, NFMSG ;NO FILE MESSAGE ERROUT: LD C, PRBUF ;PRINT STRING FUNCTION CALL CPM CALL GETCON ;WAIT FOR KEYSTROKE TO EXIT JP BOOT ; NFMSG: DEFB CR DEFB LF DEFM 'NO SOURCE FILE FOUND' DEFB CR DEFB LF DEFM '$' ; PAS2: LD A, (HEXOPN) ;HEX FILE OPEN FROM PREV? CP 'O' CALL Z, FLUSH ;YES, FLUSH AND CLOSE ; LD DE, LSTFCB ;OPEN LISTING FILE CALL OPNOUT CP 0FFH ;SUCESSFUL? JR Z, DSKERR ;NO, ERROR MSG LD A, 'O' LD (LSTOPN),A ;DECLARE OPEN XOR A ;START WITH RECORD 0 LD (LSTFCB+32), A LD HL, LSTBUF ;DECLARE EMPTY LD (LSTPTR), HL JR PAS1 ;GO OPEN SRC ; DSKERR: LD DE, ERRMSG JR ERROUT ;GOTO ERROR OUTPUT RTN ; ERRMSG: DEFB CR DEFB LF DEFM 'DISK ERROR, ASSEMBLY ABORTED' DEFB CR DEFB LF DEFM '$' ; PAS3: LD A, (LSTOPN) ;LIST STILL OPEN? CP 'O' CALL Z, FLUSH ;YES, FLUSH AND CLOSE LD DE, HEXFCB CALL OPNOUT ;OPEN HEX FILE FOR OUTPUT CP 0FFH ;SUCESS? JR Z, DSKERR ;NO, ABORT ; LD A, 'O' LD (HEXOPN),A ;DECLARE OPEN XOR A LD (HEXFCB+32), A LD HL, HEXBUF ;DECLARE EMPTY LD (HEXPTR), HL JP PAS1 ;GO OPEN SRC ; FLUSH: LD A, (HEXOPN) ;HEX FILE OPEN? CP 'O' ; IF O, YES JR Z, HEXFL ; LD A, (LSTOPN) ;LIST FILE OPEN? CP 'O' ; IF O, YES RET NZ ; NO OPEN OUTPUT FILES, EXIT ; LD DE, LSTBUF ;DE POINTS TO START LD HL, (LSTPTR) ;HL POINTS TO CURRENT CHAR LD BC, LSTFCB ;NEED FCB PTR FOR CP/M JR MTBUF ; HEXFL: LD DE, HEXBUF ;COMMENTS AS FOR LST FILE LD HL, (HEXPTR) LD BC, HEXFCB ; MTBUF: LD A, L ;FIND IF ON RECORD BOUNDARY AND 127 JR Z, MTBUF2 ;IF Z, YES LD (HL), CTLZ ;PUT ^Z AS EOF MARK ; MTBUF2: PUSH BC ;SAVE FCB PTR OR A ;CLEAR CARRY SBC HL, DE ;CALC # BYTES IN BUFFER JR NZ, AREREC ;IF NZ, ARE RECORDS TO WRITE POP BC ;ELSE EXIT RET ; AREREC: LD B, 7 ;B = SHIFT COUNTER DIV128: SRL H ; BYTES/128 = # RECORDS RR L DJNZ DIV128 ;LOOP TIL DONE ; LD B, L ;B = # RECORDS OR A ;FIND IF EVEN RECORD AGAIN JR Z, EVNREC ; INC B ;DON'T WANT TO LOSE PARTIAL EVNREC: EX DE, HL ;HL = BUFFER POINTER POP DE ;DE = FCB POINTER ; CALL FLBUF ;WRITE BUFFER TO DISK LD C, CLSFIL ;CLOSE FUNCTION PUSH DE CALL CPM POP DE LD HL, 38 ;(DE+38) = FILE OPEN FLAG ADD HL, DE LD (HL), 'C' ;DECLARE CLOSED RET ; FLBUF: PUSH BC ;B=#RECS, C=CHAR PUSH HL ;HL=BUFFER POINTER PUSH DE ;DE=FCB PTR ; EX DE, HL ;DE NOW = BUFFER PTR LD C, SETDMA CALL CPM ;DMA NOW = BUFFER ; POP DE ;GET FCB PTR BACK PUSH DE LD C, WRNR ;WRITE NEXT REC FUNCTION CALL CPM ; OR A ;SET FLAGS JP NZ, DSKERR ; POP DE POP HL POP BC ; DEC B RET Z ;IF Z, ALL RECORDS WRITTEN ; LD A, L ADD A, 128 ;UPDATE DATA POINTER LD L, A JR NC, FLBUF INC H JR FLBUF ; PCHOUT: PUSH BC PUSH DE PUSH HL LD HL, (HEXPTR) ;BUFFER POINTER LD A,H ;GET HIGH ORDER CP (HEXBUF+1025)/256 ;FULL? JR Z, DMPHEX ;IF Z, BUFFER FULL ; HEXCHR: LD (HL),C INC HL ;NOT FULL, JUST STORE CHAR LD (HEXPTR), HL JP GENRET ; DMPHEX: PUSH BC ;SAVE CHAR LD B, 8 ;8 RECORD BUFFER LD HL, HEXBUF ;SETUP FOR FLBUF LD DE, HEXFCB CALL FLBUF ; POP BC ;GET CHAR BACK LD HL, HEXBUF ;START AT BEGINNING AGAIN JR HEXCHR ; LSTO: PUSH BC PUSH DE PUSH HL LD A,(PASSNO) ;GET CURRENT PASS CP 4 ;IS IT PASS 4 ? JP Z, OUT4 ;IF YES, OUTPUT TO CONSOLE LD HL, (LSTPTR) ;NO, OUTPUT TO .PRN LD A, H CP (LSTBUF+1025)/256 ;FULL? JR Z, DMPLST ;YES, FLUSH ; LSTCHR: LD (HL), C ;STORE CHAR IN I/O BUFFER INC HL ;UPDATE POINTER LD (LSTPTR), HL JP GENRET ; DMPLST: PUSH BC LD B, 8 ;BUFFER = 8 RECORDS LD HL, LSTBUF ;START AT BEGINNING LD DE, LSTFCB ;FCB FOR CP/M CALL FLBUF ; POP BC ;GET THIS OUTPUT CHAR BACK LD HL, LSTBUF ;RESTART AT BEGINNING JR LSTCHR ; RDRIN: PUSH BC PUSH DE PUSH HL LD HL, (SRCPTR) ;GET SRC POINTER LD A, H CP (SRCBUF+1025)/256 ;PAST END? JR Z, SRCRD ;YES, GO GET MORE ; NXTCHR: LD A, (HL) ;GET CHAR INC HL LD (SRCPTR), HL ;SAVE POINTER JP GENRET ; SRCRD: LD BC, 0880H ;B=#RECS, C=BYTES/REC LD DE, SRCBUF ;DESTINATION ; NXTREC: PUSH DE PUSH BC LD C, SETDMA CALL CPM ; LD DE, SRCFCB LD C, RDNR ;READ NEXT RECORD CALL CPM ; POP BC POP DE CP 1 ;1 MEANS FILE DONE JR Z, SRCDON ; LD A, E ;UPDATE DESTINATION ADD A, C LD E, A JR NC, DOK INC D DOK: DEC B ;DONE 8 RECORDS? JR NZ, NXTREC ;NO, CONTINUE ; SRCDON: LD HL, SRCBUF ;START AT BEGINNING JR NXTCHR ; ; ; ;********************************************************************** ;RAM STORAGE AREA. ;********************************************************************** MEMTOP: DEFS 2 ; HIGHEST AVAILABLE RAM LOC. ADDR PASSNO: DEFS 1 ; PASS NUMBER LINPNT: DEFS 2 ; POINTER TO LINE BUFFER LINBUF: DEFS LBFSZ ; LINE BUFFER LABBUF: DEFS 7 ; LABEL BUFFER SYMBUF: DEFS 10 ; SYMBOL BUFFER PAGE: DEFS 2 ; PAGE NO. (BCD) LINE: DEFS 1 ; LINE NUMBER ERRBUF: DEFS 1 ; ERROR INDICATOR BUFFER ADREFC: DEFS 2 ; ADDRESS REFERENCE COUNTER ADDISR: DEFS 2 ; ADDRESS DISPLAY REGISTER ASCDNO: DEFS 1 ; NO. OF BYTES OF ASSEMBLED CODE ASSCOD: DEFS ACBSIZ ; ASSEMBLED CODE BUFFER TITBUF: DEFS TITSIZ+1 ; TITLE BUFFER SYMEND: DEFS 2 ; POINTER TO END OF SYMBOL TABLE ORTKBF: DEFS 2 ; OPERATOR TOKEN BUFFER TEMP: DEFS 2 ; DUMMY LOCATION ODBT1: DEFS 1 ; OPERAND-1 TOKEN BUFFER ODBT2: DEFS 1 ; OPERAND-2 TOKEN BUFFER ODINT1: DEFS 2 ; OPERAND-1 VALUE ODINT2: DEFS 2 ; OPERAND-2 VALUE AFLAGS: DEFS 1 ; ASSEMBLY FLAGS ; BIT 0 - ADDR DISCONT. FLAG ; BIT 1 - END FLAG ; BIT 2 - SYMB TABLE O/F FLAG OBJCNT: DEFS 1 ; NO OF BYTES IN OBJ BUFF RECADR: DEFS 2 ; TARGET ADDR OF 1ST BYTE OF RECORD STADDR: DEFS 2 ; START ADDR BUFFER FOR 'END' OPD OBJBUF: DEFS RECSIZ ; OBJECT CODE BUFFER FTOKR: DEFS 1 ; FUNCTION TOKEN REGISTER FCNT: DEFS 1 ; FUNCTION STACK COUNTER FSTK: DEFS MAXFSK ; START OF FUNCTION STACK ARCNT: DEFS 1 ; ARITHMETIC STACK COUNTER ARSTK: DEFS MAXASK ; ARITHMETIC STACK DEFS STKSIZ STACK: DEFS 0 ; STACK FROM HERE BACK ^ ; ORG 1F00H ; MUST START ON PAGE BOUNDARY ; SRCBUF: DEFS 1024 LSTBUF: DEFS 1024 HEXBUF: DEFS 1024 ; SYMTAB: DEFS 0 ; SYMBOL TABLE HERE TO MEMTOP END