;
;		EDUCATOR-8080
;
;Originally written by the Digital Group
;Converted to run on CP/M BY Keith Petersen,
;W8SDZ, July 28, 1980.
;
BKSPC	EQU	08H	;BACKSPACE
CR	EQU	0DH	;CARRIAGE RETURN
LF	EQU	0AH	;LINE FEED
CLR	EQU	1AH	;SCREEN CLEAR CHARACTER
DEL	EQU	7FH	;DELETE (RUBOUT)
;
	ORG	100H
;
;THE CONTROL ROUTINE IS THE TOP OF THE STRUCTURE AND
;CONTROLS THE OPERATION OF THE ENTIRE PROGRAM.
;
CNTRL:	LXI	SP,STACK ;SET STACK POINTER
	LHLD	1	;GET CBIOS POINTER
	LXI	D,3	;READY FOR DAD
	DAD	D	;CONSTAT
	DAD	D	;CONIN
	SHLD	VCONIN+1 ;MODIFY CALL ADDRESS
	DAD	D	;CONOUT
	SHLD	VCONOUT+1 ;MODIFY CALL ADDRESS
;
NOTZER:	CALL	DSPLY	;DISPLAY CONTENTS OF REGISTERS
	CALL	CMDNT	;ENTER A COMMAND
	CALL 	FETCH	;FETCH THE CORRECT OPCODE
	ORA	A	;SET ZERO FLAG AS PER CONTENTS
	JNZ	NOTZER	;JUMP IF NOT ZERO ERROR OCCURED
	CALL	XQTER	;GO EXECUTE THE CURRENT COMMAND
	JMP	NOTZER	;LOOP FOREVER
;
;THIS DISPLAY ROUTINE CONTROLS THE GENERATION OF THE DYNAMIC
;DISPLAY.
;
DSPLY:	LXI	H,TITLS	;LOAD ADDRESS OF TITLES INTO HL
	CALL	CHEDT	;DISPLAY TITLES
	LXI	H,BLINE	;LOAD ADDR OF BLINE TITLE
	LDA	BREG	;LOAD CONTENTS OF BREG INTO A
	CALL	DSPCV	;CONVERT AND DISPLAY
	LXI	H,CLINE	;LOAD ADDR OF CLINE TITLE
	LDA	CREG	;LOAD CONTENTS OF CREG INTO A
	CALL	DSPCV	;CONVERT AND DISPLAY
	LXI	H,AFHDR	;LOAD ADDR OF A FLAGS TITLE
	CALL	CHEDT	;DISPLAY TITLES
	LHLD	PSWA	;LOAD FLAGS AND A INTO HL
	MOV	A,L	;MOVE FLAGS TO A
	ANI	4	;AND OFF ALL BUT PARITY FLAG
	CALL	DSPFG	;DISPLAY THE FLAG VALUE
	MOV	A,L	;MOVE FLAGS TO A
	ANI	40H	;AND OFF ALL BUT ZERO FLAG
	CALL	DSPFG	;DISPLAY THE FLAG VALUE
	MOV	A,L	;MOVE FLAGS TO A
	ANI	80H	;AND OFF ALL BUT SIGN FLAG
	CALL	DSPFG	;DISPLAY THE FLAG VALUE
	MOV	A,L	;MOVE FLAGS TO A
	ANI	10H	;AND OFF ALL BUT AUX. CARRY FLAG
	CALL	DSPFG	;DISPLAY THE FLAG VALUE
	MOV	A,L	;MOVE FLAGS TO A
	ANI	1	;AND OFF ALL BUT CARRY FLAG
	CALL	DSPFG	;DISPLAY THE FLAG VALUE
	MOV	A,H	;MOVE A REGISTER VALUE TO A
	CALL	DSPCN	;DISPLAY WITH NO TITLE PRINT
	RET		;RETURN TO THE CNTRL ROUTINE
;
;THE DISPLAY CONVERSION ROUTINE PRINTS BINARY,
;OCTAL AND HEXADECIMAL.
;
DSPCV:	PUSH	PSW	;SAVE OUTPUT VALUE FOR CHEDT
	CALL	CHEDT	;DISPLAY LINE TITLE ADDR IN HL
	POP	PSW	;RETRIEVE SAVED OUTPUT VALUE
;
DSPCN:	MVI	E,8	;MOVE 8 TO E REGISTER
;
DSPBT:	RLC		;ROTATE MSB INTO CARRY AND LSB
	PUSH	PSW	;SAVE CURRENT VALUE
	ANI	1	;AND OFF ALL BUT LSB
	CALL	DSPFG	;GO DISPLAY BIT VALUE
	POP	PSW	;RETRIEVE SAVED CURRENT VALUE
	DCR	E	;DECREMENT LOOP COUNT
	JNZ	DSPBT	;JUMP IF LOOP COUNT NOT ZERO
	ORA	A	;RESET CARRY
	MVI	E,3	;MOVE 3 TO E REGISTER
;
DSPQT:	RAL		;MSB TO CARRY, CARRY TO LSB
	RAL		;DO IT AGAIN,
	RAL		; THREE TIMES FOR OCTAL DIGIT
	PUSH	PSW	;SAVE CURRENT VALUE
	ANI	7	;AND OFF ALL BUT OCTAL LSD
	ORI	'0'	;MAKE ASCII
	CALL	CHRPR	;OUTPUT THE CHARACTER
	POP	PSW	;RETRIEVE SAVED CURRENT VALUE
	DCR	E	;DECREMENT LOOP COUNT
	JNZ	DSPQT	;JUMP IF LOOP COUNT NOT ZERO
	CALL	DSPSP	;OUTPUT A SPACE
	MVI	E,2	;MOVE 2 TO E
;
DSPHT:	RLC		;ROTATE MSB INTO CARRY AND LSB
	RLC		;DO IT AGAIN
	RLC		; FOUR TIMES FOR
	RLC		;  HEXADECIMAL SHIFT
	PUSH	PSW	;SAVE CURRENT VALUE
	ANI	0FH	;AND OFF ALL BUT HEX LSD
	ADI	'0'	;ADD ON BITS TO MAKE ASCII
	CPI	'9'+1	;COMPARE RESULT TO ONE MORE THAN 9
	JC	DSPHS	;IF NUMERIC THEN SKIP ADJUSTMENT
	ADI	7	;ADD 7 GIVING ASCII A-F CODES
;
DSPHS:	CALL	CHRPR	;OUTPUT THE CHARACTER
	POP	PSW	;RETRIEVE SAVED CURRENT VALUE
	NOP	
	DCR	E	;DECREMENT LOOP COUNT
	JNZ	DSPHT	;JUMP IF LOOP COUNT NOT ZERO
	RET		;RETURN TO CALLING ROUTINE
;
;DISPLAY FLAG OR BINARY DIGIT FOLLOWED BY A SPACE.  ALTERNATE
;ENTRY IS USED TO DISPLAY A SPACE.
;
DSPFG:	JZ	DSPFZ	;JUMP IF PASSED VALUE IS A ZERO
	MVI	A,1	;OTHERWISE MOVE A 1 INTO A
;
DSPFZ:	ADI	'0'	;CONVERT INTO ASCII NUMERIC CHAR.
	CALL	CHRPR	;OUTPUT THE CHARACTER
;
DSPSP:	PUSH	PSW	;SAVE THE FLAGS AND VALUE IN A
	MVI	A,' '	;MOVE SPACE INTO A
	CALL	CHRPR	;OUTPUT THE SPACE
	POP	PSW	;RETRIEVE THE SAVED FLAGS AND A
	RET		;RETURN TO THE CALLING ROUTINE
;
;THE CHARACTER STRING OUTPUT EDIT ROUTINE.
;
CHEDT:	MOV	A,M	;MOVE NEXT CHARACTER INTO A
	CPI	80H	;COMPARE IT TO 200 OCTAL
	RZ		;RETURN IF EQUAL IT'S END OF STRING
	JNC	CHSPA	;JUMP IF GREATER FOR SPACE ROUTINE
	CALL	CHRPR	;ELSE GO OUTPUT THE CHARACTER
;
CHEND:	INX	H	;INCREMENT THE STRING INDEX
	JMP	CHEDT	;LOOP FOR NEXT CHARACTER
;
CHSPA:	SUI	80H	;SUBTRACT 200 OCTAL FROM VALUE
	MOV	B,A	;MOVE SPACE COUNT TO B
;
CHSPL:	MVI	A,' '	;MOVE SPACE INTO A
	CALL	CHRPR	;OUTPUT THE SPACE
	DCR	B	;DECREMENT SPACE COUNT
	JNZ	CHSPL	;JUMP IF COUNT NOT ZERO TO START OF LOOP
	JMP	CHEND	;JUMP BACK INTO CHEDT LOOP
;
;THE COMMAND ENTRY ROUTINE ACCEPTS INPUT FROM THE KEYBOARD
;FOR COMMANDS.
;
CMDNT:	LXI	H,CMDMS	;MOVE ADDRESS OF COMMAND? INTO HL
	CALL	CHEDT	;DISPLAY THE MESSAGE
	LXI	H,CMDAR	;MOVE ADRS OF COMMAND INPUT AREA HL
	MVI	B,22	;MOVE MAXIMUM LENGTH TO B
;
CMDKB:	CALL	KEYBD	;GET AN INPUT CHARACTER
	CPI	'L'-40H	;IS IT A CONTROL-L LINE DELETE?
	JZ	CNTRL	;IF SO THEN RESTART PROGRAM
	CPI	CR	;IS IT A CARRIAGE RETURN?
	JZ	CMDND	;IF SO THEN GO COMPRESS INPUT
	CPI	DEL	;IS IT A DELETE CHARACTER?
	JNZ	CMDST	;IF NOT THEN GO STORE THE CHARACTER
	MVI	A,BKSPC	;IF SO REPLACE WITH BACKSPACE
;
CMDST:	MOV	M,A	;STORE INPUT CHAR. IN COMMAND BUFFER
	CALL	CHRPR	;DISPLAY THE INPUT CHARACTER
	INX	H	;INCREMENT COMMAND WORK AREA INDEX
	DCR	B	;DECREMENT COMMAND LENGTH COUNT
	JNZ	CMDKB	;IF NOT FULL THEN REITERATE
	MVI	A,1	;IF BUFFER FULL THEN SELECT ERROR
	CALL	ERROR	; NUMBER 1 AND PRINT ITS MSG.
	JMP	CNTRL	;RESTART THE PROGRAM
;
;THE COMMAND COMPRESS ROUTINE ELIMINATES ALL BUT LETTERS 
;AND NUMBERS.
;
CMDND:	LXI	H,CMDAR	;LOAD HL WITH ADRS OF WORK AREA
	PUSH	H	;PUSH & POP MOVE IT TO DE
	POP	D	; AS THE COMPRESSION POINTER
	MVI	A,22	;LOAD A WITH MAXIMUM LENGTH
	SUB	B	;SUBTRACT REMAINING LENGTH FROM B
	MOV	B,A	;MOVE ACTUAL LENGTH TO B
;
CMDNX:	MOV	A,M	;MOVE COMMAND CHARACTER TO A
	CPI	BKSPC	;IS IT BACKSPACE?
	JNZ	CMDCH	;IF NOT THEN GO TO OTHER TESTS
	MVI	A,CMDAR AND 0FFH ;LOW ADRS BYTE OF CMDAR TO A
	CMP	E	;COMPARE TO CURRENT LOW ADRS BYTE
	JNC	CMDNS	;IF NOT GREATER THEN SKIP SAVE
	DCX	D	;ELSE BACK UP COMPRESSION POINTER
	JMP	CMDNS	;SKIP SAVING THE CHARACTER
;
CMDCH:	CPI	'0'	;IS THE CHARACTER LESS THAN '0'?
	JC	CMDNS	;IF SO THEN SKIP SAVING IT
	CPI	'9'+1	;IS THE CHARACTER LESS THAN '9'+1?
	JC	CMDSV	;IF SO THEN SAVE NUMERIC VALUE
	CPI	'A'	;IS THE CHARACTER LESS THAN 'A'?
	JC	CMDNS	;IF SO THEN SKIP SAVING IT
	CPI	'Z'+1	;IS THE CHARACTER GREATER THAN 'Z'?
	JNC	CMDNS	;IF SO THEN SKIP SAVING IT
;
CMDSV:	STAX	D	;STORE CHARACTER IN COMPRESSED AREA
	INX	D	;INCREMENT COMPRESSION POINTER INDEX
;
CMDNS:	INX	H	;INCREMENT INPUT STRING POINTER
	DCR	B	;DECREMENT ACTUAL LENGTH COUNT
	JNZ	CMDNX	;IF LENGTH IS NOT ZERO THEN REITERATE
	RET		;ELSE RETURN TO CNTRL CALLING POINT
;
;THE FETCH INSTRUCTION/COMMAND ROUTINE VALIDATES AND BUILDS THE
;OBJECT CODE.
;
FETCH:	LXI	H,OPTAB	;LOAD ADDRESS OF OPCODE TABLE HL
	MVI	E,31	;MOVE TABLE ELEMENT COUNT TO E
;
FLOOP:	PUSH	H	;SAVE CURRENT ELEMENT ADDRESS
	LXI	B,CMDAR	;LOAD ADDRESS OF CMDAR INTO BC
	MVI	D,3	;MOVE OPCODE LENGTH TO D
;
FCOMP:	LDAX	B	;LOAD COMMAND CHARACTER TO A INDEXED BY B
	CMP	M	;COMPARE IT TO TABLE CHARACTER
	JNZ	FNXEL	;IF NOT EQUAL THEN GO TO NEXT ELEMENT
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	INX	H	;INCREMENT TABLE CHARACTER INDEX
	DCR	D	;DECREMENT OPCODE LENGTH COUNTER
	JNZ	FCOMP	;IF NOT ZERO CONTINUE TEST LOOP
	XTHL		;EXCHANGE HL WITH TOP OF STACK
	POP	H	;POP HL FROM STACK TO CLEAR IT
	MOV	E,M	;MOVE NAKED OPCODE TO E,D IS ZERO
	PUSH	D	;SAVE NAKED OPCODE
	INX	H	;INCREMENT TABLE POINTER
	MOV	E,M	;DECODE ROUTINE LOW ADDRESS BYTE TO E
	INX	H	;INCREMENT TABLE POINTER
	MOV	D,M	;DECODE ROUTINE HIGH ADDRESS BYTE TO D
	XCHG		;MOVE DECODE ROUTINE ADDRESS TO HL
	POP	D	;UNSAVE NAKED OPCODE TO DE
	XRA	A	;CLEAR A, NO ERROR CODE
	PCHL		;JUMP TO ADDRESS OF DECODE ROUTINE
;
FNXEL:	LXI	B,6	;LOAD DOUBLE LENGTH 6 INTO BC
	POP	H	;UNSAVE CURRENT ELEMENT ADDRESS
	DAD	B	;ADD 6 TO IT
	DCR	E	;DECREMENT TABLE ELEMENT COUNT
	JNZ	FLOOP	;REITERATE TO TEST NEXT ELEMENT
	MVI	A,2	;MOVE ERROR CODE 2 TO A
	JMP	ERROR	;GO DISPLAY ERROR 2, OPCODE UNKNOWN
	NOP		;NO OPERATION FILLER
;
;THE INSTRUCTION DECODER ROUTINES FOLLOW
;INSTRUCTIONS USING THE DIRCT ROUTINE REQUIRE NO DECODING.
;EXAMPLE: RAL, CMA, ETC.
;
DIRCT:	RET		;RETURN TO CNTRL FOR EXECUTION
;
;THE MOVRT IS USED ONLY BE THE MOV COMMAND
;
MOVRT:	CALL	RG543	;VALIDATE DESTINATION REGISTER
	ORA	A	;SET FLAGS BASED ON A CONTENTS
	RNZ		;RETURN NOT ZERO WITH ERROR
;
;INSTRUCTIONS USING THE RG210 ROUTINE REQUIRE A SOURCE REGISTER
;
RG210:	LDAX	B	;LOAD NEXT COMMAND CHARACTER INTO A
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	CALL	REGAN	;ANALYZE FOR VALID REGISTER
	JNC	RGERR	;IF CY=0 THEN REGISTER NOT VALID
	ADD	E	;ADD NAKED OPCODE TO REGISTER VALUE
	MOV	E,A	;MOVE RESULT BACK TO E
	XRA	A	;CLEAR A INDICATING NO ERRORS
	RET		;RETURN TO CNTRL
;
;THE REGISTER ERROR ROUTINE IS USED TO INDICATE REGISTER
;DESIGNATION ERRORS
;
RGERR:	MVI	A,3	;MOV ERROR CODE 3 TO A
	JMP	ERROR	;GO DISPLAY ERROR 3, INVALID REGISTER
;
;THE REGISTER ANALYSIS AND VALIDATION ROUTINE IS USED BY RG543,
;RG210, AND RG54B
;
REGAN:	SUI	'A'	;SUBTRACT AN 'A' FROM THE CHARACTER
	CPI	3	;COMPARE THE RESULT TO 3
	RNC		;IF NOT LESS THAN 3 RETURN WITH CY=0
	DCR	A	;DECREMENT RESULT: A=377,B=000,C=001
	ANI	7	;AND OFF ALL BUT OCTAL LSD
	STC		;SET CY=1 INDICATING NO ERROR
	RET		;RETURN TO CALLING ROUTINE
;
;THE MVIRT IS USED ONLY BY THE MVI COMMAND
;
MVIRT:	CALL	RG543	;VALIDATE DESTINATION REGISTER
	ORA	A	;SET FLAGS BASED ON A CONTENTS
	RNZ		;RETURN NOT ZERO WITH ERROR
;
;INSTRUCTIONS REQUIRING AN IMMEDIATE OPERAND USE THE IMMED
;ROUTINE
;
IMMED:	LDAX	B	;LOAD NEXT COMMAND CHARACTER INTO A
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	CPI	'B'	;IS THE CMND CHAR. A 'B' ?
	JZ	BINRY	;IF SO THEN PROCESS AS BINARY
	CPI	'Q'	;IS THE COMMAND CHARACTER A 'Q'?
	JZ	OCTAL	;IF SO THEN PROCESS AS OCTAL
	CPI	'H'	;IS THE CMND CHAR. AN 'H' ?
	JZ	HEX	;IF SO THEN PROCESS AS HEXADECIMAL
	CPI	'8'	;IS THE COMMAND CHARACTER LESS THAN '8'?
	JC	OCTAD	;IF SO THEN TREAT AS OCTAL
	MVI	A,5	;MOVE ERROR CODE 5 TO A
	JMP	ERROR	;GO DISPLAY ERROR 5, INVALID IMMEDIATE
;
;INSTRUCTIONS USING THE RG543 ROUTINE REQUIRE A DESTINATION
;REGISTER
;
RG543:	LDAX	B	;LOAD NEXT COMMAND CHARACTER INTO A
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	CALL	REGAN	;ANALYZE FOR VALID REGISTER
	JNC	RGERR	;IF CY=0 THEN REGISTER NOT VALID
	RLC		;SHIFT OCTAL REGISTER VALUE
	RLC		;LEFT THREE
	RLC		; PLACES
	ADD	E	;ADD NAKED OPCODE TO SHIFTED VALUE
	MOV	E,A	;MOVE RESULT BACK TO E
	XRA	A	;CLEAR A INDICATING NO ERRORS
	RET		;RETURN TO CALLING ROUTINE
;
;INSTRUCTIONS USING THE RG54B ROUTINE ARE INX AND DCX
;
RG54B:	LDAX	B	;LOAD NEXT COMMAND CHARACTER INTO A
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	CALL	REGAN	;ANALYZE FOR VALID REGISTER
	CPI	0	;IS THE REGISTER A ZERO?
	RZ		;IF SO IT'S 'B' SO RETURN
	MVI	A,4	;MOVE ERROR CODE 4 TO A
	JMP	ERROR	;GO DISPLAY ERROR 4, INVALID REGISTER
;
;THE BINARY ROUTINE CONVERTS A BINARY IMMEDIATE VALUE INTO
;USABLE FORM
;
BINRY:	MVI	H,8	;MOVE 8 TO H FOR COUNT
;
BLOOP:	LDAX	B	;LOAD NEXT COMMAND CHARACTER INTO A
	SUI	'0'	;SUBTRACT A '0' FROM IT
	CPI	2	;IS THE RESULT LESS THAN 2?
	JNC	IMMER	;IF NOT THEN GO DISPLAY IMMEDIATE ERROR
	PUSH	H	;SAVE THE COUNT
	MOV	L,D	;MOVE D TO L (IMMEDIATE BYTE)
	DAD	H	;SHIFT HL LEFT ONE BIT
	ADD	L	;ADD L TO BIT IN A
	MOV	D,A	;MOVE THE RESULT BACK TO D
	POP	H	;UNSAVE THE COUNT
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	DCR	H	;DECREMENT THE COUNT
	JNZ	BLOOP	;IF NOT ZERO THEN REITERATE
	XRA	A	;CLEAR A INDICATING NO ERRORS
	RET		;RETURN TO CNTRL
;
;THE IMMEDIATE ERROR ROUTINE IS USED TO INDICATE IMMEDIATE VALUE 
;ERRORS
;
IMMER:	MVI	A,6	;MOVE ERROR CODE 3 TO A
	JMP	ERROR	;GO DISPLAY ERROR 3, INVALID IMMEDIATE
;
;THE OCTAD ENTRY POINT TO THE OCTAL ROUTINE IS FOR THE DEFAULT
;CONDITION
;
OCTAD:	DCX	B	;DECREMENT COMMAND CHARACTER INDEX
;
;THE OCTAL ROUTINE CONVERTS AN OCTAL IMMEDIATE VALUE INTO
;USABLE FORM
;
OCTAL:	MVI	H,3	;MOVE A 3 INTO H FOR COUNT
;
OLOOP:	LDAX	B	;LOAD NEXT COMMAND CHARACTER INTO A
	SUI	'0'	;SUBTRACT A '0' FROM IT
	CPI	8	;IS CMND LESS THAN 8?
	JNC	IMMER	;IF NOT GO DISP IMMED ERROR
	PUSH	H	;SAVE THE COUNT
	MOV	L,D	;MOVE D TO L IMMED BYTE
	DAD	H	;SHIFT IMMEDIATE
	DAD	H	;  BYTE LEFT
	DAD	H	;    THREE BITS
	ADD	L	;ADD L TO VALUE IN A
	MOV	D,A	;MOVE RESULT BACK TO D
	POP	H	;UNSAVE THE COUNT
	INX	B	;INCREMENT COMND CHAR INDEX
	DCR	H	;DECREMENT THE COUNT
	JNZ	OLOOP	;IF NOT ZERO THEN REITERATE
	XRA	A	;CLEAR A INDICATING NO ERRORS
	RET		;RETURN TO CNTRL
;
;THE HEX ROUTINE COVERTS A HEXADECIMAL IMMEDIATE VALUE INTO
;USABLE FORM. 
;
HEX:	MVI	H,2	;MOVE A 2 INTO H FOR COUNT
;
HLOOP:	LDAX	B	;LOAD NEXT CMND CHAR INTO A
	SUI	'0'	;SUBTRACT '0' FROM IT
	CPI	9+1	;IS IT LESS THAN '9'+1?
	JC	HCHOK	;IF SO THEN NUMERIC CHARACTER IS OK
	SUI	7	;ELSE CONVERT ALPHABETIC TO NUMERIC
	CPI	15+1	;IS CHARACTER VALUE GREATER THAN 15?
	JNC	IMMER	;IF SO THAN INVALID HEXADECIMAL VALUE
;
HCHOK:	PUSH	H	;SAVE THE COUNT
	MOV	L,D	;MOVE D TO L IMMEDIATE BYTE
	DAD	H	;SHIFT IMMEDIATE
	DAD	H	; BYTE LEFT
	DAD	H	;  FOUR
	DAD	H	;   BITS
	ADD	L	;ADD L TO VALUE IN A
	MOV	D,A	;MOVE RESULT BACK TO D
	POP	H	;UNSAVE THE COUNT
	INX	B	;INCREMENT COMMAND CHARACTER INDEX
	DCR	H	;DECREMENT THE COUNT
	JNZ	HLOOP	;IF NOT ZERO THAN REITERATE
	XRA	A	;CLEAR A INDICATING NO ERRORS
	RET		;RETURN TO CNTRL
;
;THE XQTER ROUTINE EXECUTES THE GENERATED OBJECT CODE FOR
;EDUCATOR 8080
;
XQTER:	XCHG		;MOVE GENERATED OPCODE TO HL
	SHLD	XQTOP	;STORE IT AT EXECUTION POINT
	LHLD	PSWA	;LOAD WORKING PSW & A INTO HL
	PUSH	H	;PUSH & POP SETS VALUES FOR
	POP	PSW	; WORKING REGISTER AND FLAGS
	LHLD	BANDC	;LOAD WORKING B AND C INTO HL
	PUSH	H	;PUSH & POP SETS VALUES FOR
	POP	B	; WORKING B AND C REGISTERS
;
XQTOP:	NOP		;THE COMMAND TO BE EXECUTED
	NOP		;IMMEDIATE VALUE OR NOP
	PUSH	B	;PUSH B AND C WORKING REGISTER VALUES
	POP	H	;POP THEM INTO HL
	SHLD	BANDC	;STORE THEM IN SAVE AREA
	PUSH	PSW	;PUSH PSW AND A WORKING VALUES
	POP	H	;POP THEM INTO HL
	SHLD	PSWA	;STORE THEM IN SAVE AREA
	RET		;RETURN TO CNTRL FOR NEXT COMMAND
;
;THE ERROR ROUTINE IS USED TO DISPLAY ERROR MESSAGES
;
ERROR:	PUSH	PSW	;SAVE ERROR CODE IN A
	LXI	H,ERRSP	;LOAD ADDRESS OF ERROR HEADER SPACES
	CALL	CHEDT	;GO OUTPUT ERROR HEADER SPACES
	POP	PSW	;UNSAVE ERROR CODE
	LXI	H,ERTAB	;LOAD ADDRESS OF ERROR MESSAGE TABLE
	ADD	L	;ADD LOW ADDRESS BYTE TO ERROR CODE
	MOV	L,A	;MOVE RESULT TO L, POINTS TO OFFSET
	MOV	L,M	;MOVE OFFSET TO L
;
;NOTE: HL NOW CONTAINS THE ADDRESS OR THE ERROR MESSAGE
;
	CALL	CHEDT	;OUTPUT THE ERROR MESSAGE
;
ERTIM:	LXI	D,0	;LOAD DE WITH TIMING LOOP VALUE
	DCR	E	;DECREMENT VALUE IN E 256 TIMES
	JNZ	ERTIM+1	;REITERATE LOOP 256 TIMES
;
;THE ABOVE JMP GOES TO THE FIRST 000 IN THE LXI COMMAND WHICH
;IS AN EFFECTIVE NOP
;
	DCR	D	;DECREMENT D
	JNZ	ERTIM+1	;REITERATE OUTER LOOP 256 TIMES
	MVI	A,0FFH	;MOVE A 377 TO A INDICATING ERROR
	RET		;RETURN TO CNTRL
;
OPTAB:	DB	'ACI',0CEH
	DW	IMMED
	DB	'ADC',88H
	DW	RG210
	DB	'ADD',80H
	DW	RG210
	DB	'ADI',0C6H
	DW	IMMED
	DB	'ANA',0A0H
	DW	RG210
	DB	'ANI',0E6H
	DW	IMMED
	DB	'CMA',2FH
	DW	DIRCT
	DB	'CMC',3FH
	DW	DIRCT
	DB	'CMP',0B8H
	DW	RG210
	DB	'CPI',0FEH
	DW	IMMED
	DB	'DAA',27H
	DW	DIRCT
	DB	'DCR',05H
	DW	RG543
	DB	'DCX',0BH
	DW	RG54B
	DB	'INR',04H
	DW	RG543
	DB	'INX',03H
	DW	RG54B
	DB	'MOV',40H
	DW	MOVRT
	DB	'MVI',06H
	DW	MVIRT
	DB	'NOP',00H
	DW	DIRCT
	DB	'ORA',0B0H
	DW	RG210
	DB	'ORI',0F6H
	DW	IMMED
	DB	'RAL',17H
	DW	DIRCT
	DB	'RAR',1FH
	DW	DIRCT
	DB	'RLC',07H
	DW	DIRCT
	DB	'RRC',0FH
	DW	DIRCT
	DB	'SBB',98H
	DW	RG210
	DB	'SBI',0DEH
	DW	IMMED
	DB	'STC',37H
	DW	DIRCT
	DB	'SUB',90H
	DW	RG210
	DB	'SUI',0D6H
	DW	IMMED
	DB	'XRA',0A8H
	DW	RG210
	DB	'XRI',0EEH
	DW	IMMED
;
ERTAB:	DB	ERR AND 0FFH,ITL AND 0FFH,ICM AND 0FFH
	DB	IRR AND 0FFH,IRR AND 0FFH,IIT AND 0FFH
	DB	IIV AND 0FFH,ERR AND 0FFH
;
ITL:	DB	'INPUT TOO LONG',80H
;
ICM:	DB	'INVALID COMMAND',80H
;
IRR:	DB	'INVALID REGISTER',80H
;
IIT:	DB	'INVALID IMMED TYPE',80H
;
IIV:	DB	'INVALID IMMED VALUE',80H
;
ERR:	DB	'ERROR!',80H
;
ERRSP:	DB	CR,LF,90H,80H
;
TITLS:	DB	CLR,CR,LF
	DB	9BH,'EDUCATOR-8080',CR,LF
	DB	CR,LF,9AH,'<---'
	DB	'BINARY-----'
	DB	' OCT HX',CR,LF
	DB	9AH,'7 6 5 4 3 2 1 0',80H
;
BLINE:	DB	CR,LF,CR,LF,90H
	DB	'B-REG >>  ',80H
;
CLINE:	DB	CR,LF,CR,LF,90H
	DB	'C-REG >>  ',80H
;
AFHDR:	DB	CR,LF,CR,LF,90H
	DB	'FLAGS & ACC',CR,LF,90H
	DB	'P Z S A C',CR,LF,90H,80H
;
CMDMS:	DB	CR,LF,CR,LF,90H
	DB	'COMMAND ? ',80H
;
;CHARACTER OUTPUT ROUTINE
;
CHRPR	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	MOV	C,A	;CHARACTER TO C FOR CP/M
VCONOUT	CALL	$-$	;MODIFIED AT INIT
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;
;KEYBOARD INPUT ROUTINE
;
KEYBD	PUSH	B
	PUSH	D
	PUSH	H
VCONIN	CALL	$-$	;MODIFIED AT INIT
	POP	H
	POP	D
	POP	B
	CPI	'C'-40H	;CONTROL-C FOR EXIT?
	JZ	0	;YES, REBOOT CP/M
	RET
;
;	DEFINE TEMPORARY STORAGE AREA
;
BANDC:			;B AND C REGISTERS
CREG:	DB	0
BREG:	DB	0
PSWA:	DW	0
CMDAR:	DS	40
STACK	EQU	$+60
;
	END

