home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug034.arc
/
CROWECPM.Z80
< prev
next >
Wrap
Text File
|
1979-12-31
|
146KB
|
5,115 lines
TITLE 'CroweCP/M Z80 assembler'
;COPYRIGHT 1978 BY PAT CROWE
;**********************************************************************
; Z80 ASSEMBLER VERSION 1.2
; WRITTEN BY PAT CROWE
; 22 RINGSBURY CLOSE
; PURTON
; SWINDON
; SN5 9DE
; ENGLAND
;
; THE 'LBFSZ-1' AND
; THE "EX AF,AF'" BUGS FIXED BY
; THOMAS HAMEENAHO
; DJAKNEGATAN 7
; S-754 23 UPPSALA
; SWEDEN
;
; MACHINE DEPENDENT ROUTINES REPLACED
; WITH CP/M FUNCTION CALLS 9/8/83 BY
; DANA COTANT/ MICRO CORNUCOPIA TECHNICAL DEPT
;
;*************************************************************************
;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
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
CTLZ EQU 1AH ;EOF CHARACTER
INCON EQU 1 ;CONIN FUNCTION
OUTCO EQU 2 ;CONOUT FUNCTION
;****************************************************************************
;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.
;****************************************************************************
BOOT EQU 0000H
;
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,STACK ; SET STACK POINTER
CALL INITA ; INITIALIZE ASSEMBLER
CALL PHRLD ; PRINT HERALD
MAIN1: CALL GTPNO ; GET PASS NO.
JR 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.2'
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 POINTER TO LINE BUFFER
GETOR1: CALL SCNSP ; SCAN TO FIRST NON SPACE CHAR
GETOR5: CP CR ; IS IT CR?
JR Z,GETOR2
CP ';' ; IS IT ';'?
JR 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
JR 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
BIT 6,B ; QUOTE FLAG SET?
JR NZ,QUOTE ; IF SO, QUOTE
PUSH HL ; PREP TO CHECK IF AF'
DEC HL ; POINT TO PREV CHAR
LD A,(HL)
POP HL ; RESTORE POINTER
CP 'F' ; IS IT 'F'?
JR Z,GTOD28 ; YES, THEN NO QUOTE
QUOTE: 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, SYNTAX 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 KEYWORD 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
JR 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'
JR Z,PBIN ; BINARY LITERAL
CP 'D' ; 'D'?
JR Z,PDEC ; DECIMAL LITERAL
CP 'H' ; 'H'?
JP Z,PHEX ; HEX LITERAL
CP 'O' ; 'O'?
JR Z,POCT ; OCTAL LITERAL
CP 'Q' ; 'Q'?
JR Z,POCT ; OCTAL LITERAL
JR 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.2 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
;
;
PUTCON: LD E,A ;CP/M CONOUT FUNCTION
LD C,OUTCO
CALL CPM
RET
;
GETCON: LD C,INCON ;CP/M CONIN FUNCTION
CALL CPM
RET
;
;**********************************************************************
;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