;-----------------------------------------------------------------------
;			PROGRAM PLOT
;-----------------------------------------------------------------------
;
;THIS PROGRAM READS A SEQUENTIAL PLOT COMMAND FILE, MAKES A MEMORY IMAGE
;OF THE PLOT, AND PRINTS THE PLOT ON THE PRINTER
;
;	COPYRIGHT (C) 1984 BY THOMAS E. SPEER. ALL RIGHTS RESERVED
;	                      887 BRIDDLEWOOD LN.
;	                      DAYTON, OHIO  45430
;	THIS PROGRAM IS RELEASED TO THE PUBLIC DOMAIN FOR 
;	NON-COMMERCIAL USE ONLY.
;
;
;REVISION HISTORY
;
;	VERSION 3.3	31 JUL 84	T. SPEER
;	FIXED BUG IN OKI VERSION OF PRESET ROUTINE.  EXTRANEOUS EXIT
;	GRAPHICS COMMAND WAS BEING SENT.  
;
;	VERSION 3.3	 7 JUL 84	T. SPEER
;	ADDED TEXT COMAND.  ADDED QUIT TO PROPERLY CLOSE OUTPUT FILE.
;	MODIFIED GBUFOUT TO SKIP TOTALLY BLANK LINES.
;
;	VERSION 3.2B	27 JUN 84	T. SPEER
;	CROSS HATCHED COLOR PATTERNS FINE TUNED.  ADDED BLINKING 
;	STATUS MESSAGE.  SPECIAL PATTERNS CORRECTED.  ALL SUBROUTINES
;	PLACED IN ALPHABETICAL ORDER.
;
;	VERSION 3.2A	18 JUN 84	T. SPEER
;	COLOR PATTERNS CHANGED.  15 SPECIAL PATTERNS ADDED FROM
;	49 TO 63.  THESE MAKE IT EASIER TO MATCH PATTERNS FROM
;	OTHER SYSTEMS.  THE DEFAULT PATTERNS SUPPLIED ARE THE SAME
;	AS USED FOR NMOS AND CMOS VLSI CIF PLOTS.
;
;	VERSION 3.2	28 MAR 84	T. SPEER
;	CITOH MODIFICATIONS DEBUGGED. IDS MODS REMOVED (SAME AS OKI)
;	BASE2 MODS REMOVED (UNTESTED- NOT SUITABLE FOR RELEASE)
;
;	VERSION 3.2	3 FEB 84	T. SPEER
;	THIS VERSION ADDS THE PATTERNED ERASE, THE UPLOAD (COLOR 
;	CODES), AND EXTEND COMMANDS.
;
;	VERSION 3.1	10 DEC 83	T. SPEER
;	ADDED PATTERN FILLS AND LINES USING A CROSS-HATCHED METHOD AND
;	AN ORDERED DITHER MATRIX METHOD.
;
;	VERSION 3.0	5 NOV 83	T. SPEER
;	THIS VERSION READS ALL X AND Y COORDINATES AS 
;	2 BYTE FIXED POINT NUMBERS (16 BIT SIGNED VALUES BETWEEN 0 AND 1)
;
;	COORDINATES MUST BE BETWEEN 0.0 AND 1.0 TO LIE ON PLOT.  THIS 
;	MAKES THE PLOT DEVICE INDEPENDENT.  THE FIXED POINT VALUES ARE EASILY
;	CREATED BY THE HIGH LEVEL PROGRAM BY MULTIPLYING THE COORDINATES BY
;	32767 AND TRUNCATING TO AN INTEGER.
;
;	VERSION 2.0			T. SPEER
;	THIS VERSION USED 32 BIT FLOATING POINT INTEGERS WITH A FORTRAN
;	ROUTINE PATCHED IN TO DO THE CONVERSION TO INTEGER RASTER COORD.
;
;	VERSION 1.0			T. SPEER
;	THIS VERSION USED 16 BIT INTEGER COORDINATES THAT WERE TIED TO
;	THE EPSON MX-80 RESOLUTION.  NO CONVERSION WAS REQUIRED.
;
;-----------------------------------------------------------------------
;
	ORG	100H		;BEGINNING OF TPA
	MVI	C,09H		;SELECT PRINT FUNCTION
	LXI	D,BANNER	;PRINT BANNER MESSAGE
	CALL	FDOS
;
	JMP	ENTRY		;JUMP AROUND VARIABLE STORAGE AREA
BANNER:	DB	'	     PLOT Version 3.3  31/7/84',0DH,0AH
	DB	'	        (c) by T. E. Speer',0DH,0AH,0AH,'$'
	DB	'	       All Rights Reserved',0DH,0AH,0DH,0AH,'$'
;
;
;
;========================= PRINTER FLAGS ==================================
;SET THE ONE THAT MATCHES YOUR PRINTER TO TRUE, AND SET THE OTHERS TO FALSE.
;
	TRUE	EQU	0FFFFH
	FALSE	EQU	NOT TRUE
EPSON	EQU	TRUE		;FLAG FOR EPSON MX-80 WITH GRAPHTRAX
CITOH	EQU	FALSE		;FLAG FOR CITOH, PROWRITER, ETC 
OKI	EQU	FALSE		;FLAG FOR OKIDATA
;IDS		SET OKI   FLAG TO TRUE- IDS PRINTERS ACT SAME AS OKI
;GEMINI	10	SET EPSON FLAG TO TRUE- GEMINI 10 ACTS SAME AS EPSON
;NEC		SET CITOH FLAG TO TRUE- NEC       ACTS SAME AS CITOH
;APPLE DOT MATRIX - ACTS SAME AS CITOH, BUT SOME <ESC> SEQUENCES DIFFER.
;		SET CITOH FLAG TO TRUE AND CHECK <ESC> SEQUENCES AT ESCK,
;		AND IN LN772 AND PRESET SUBROUTINES.
;
;====================== PRINTER PARAMETERS ===============================
; THIS SECTION SETS THE SPECIFIC CONSTANTS FOR YOUR PRINTER.
;
;***** NOTE ***** THE MAXIMUM VALUE FOR MAXX THAT CAN BE USED IS 1530.
; THE MAXIMUM VALUE FOR MAXY THAT CAN BE USED IS 1785. THESE LIMITS 
; ARE REQUIRED TO AVOID ARITHMETIC OVERFLOWS.
; THE SIZE OF THE MAP ( (MAXX+1)*(MAXY+1)/7 ) MUST FIT BETWEEN THE END OF
; THE PROGRAM AND THE END OF THE TPA.
;
;	PRINTERS SEEM TO HAVE TWO BASIC METHODS OF GOING INTO GRAPHICS
; MODE.  THE EPSON AND CITOH PRINTERS USE AN <ESC> SEQUENCE 
; FOLLOWED BY A SPECIFIED NUMBER OF GRAPHICS BYTES.  THE OKIDATA AND IDS
; PRINTERS USE AN <ETX> TO TOGGLE INTO GRAPHICS MODE, AND THEN REMAIN
; IN GRAPHICS UNTIL AN <ETX><SO> IS RECEIVED.  
;      THE BASIC PHILOSOPHY ADOPTED HERE IS TO APPEND THE <ESC> 
; SEQUENCE AND THE NUMBER OF BYTES (IF REQUIRED) TO THE HEAD OF THE 
; GRAPHICS OUTPUT BUFFER FOR THOSE PRINTERS IN THE FIRST GROUP. PRINTERS 
; IN THE SECOND GROUP ARE HANDLED BY PUTTING THE <ETX> COMMANDS IN THE 
; GBUFOUT ROUTINE.  ALL PRINTERS ARE KEPT IN NORMAL TEXT MODE, EXCEPT
; WHEN ACTUALLY PRINTING GRAPHICS.
;
	IF	EPSON
MAXX	EQU	479		;SET MAXIMUM WIDTH TO EPSON LOW RES MODE
MAXY	EQU	573		;SET MAXIMUM HEIGHT TO MAKE SQUARE PLOT
MAPSIZE	EQU	39360D	;TOTAL SIZE OF MAP
CWIDTH	EQU	6		;RASTER WIDTH OF A PRINTED CHARACTER
NO8BIT	EQU	FALSE		;SET TO FALSE IF YOUR INTERFACE CAN
MSBTOP	EQU	TRUE		;MOST SIG. BIT IS TOP OF STROKE
;	SET UP GRAPHIC OUTPUT BUFFER AREA
ESCK	DB	1BH,'K'		;DEFINE ESC "K" CHARACTER SEQUENCE
NGRAPH	DW	0000H		;INITIALIZE GRAPHIC COUNTER
GBUFF	DS	MAXX+1		;SET ASIDE AREA FOR GRAPHIC O/P BUFFER
	ENDIF			;(EPSON)
;
	IF	CITOH
MAXX	EQU	636		;SET MAXIMUM WIDTH FOR 80 DOTS/INCH MODE
MAXY	EQU	573		;SET MAXIMUM HEIGHT TO MAKE SQUARE PLOT
MAPSIZE	EQU	52234D	;TOTAL SIZE OF MAP
CWIDTH	EQU	8		;RASTER WIDTH OF A PRINTED CHARACTER
NO8BIT	EQU	FALSE		;SET TO FALSE EVEN IF 7 BIT INTERFACE
MSBTOP	EQU	FALSE		;LEAST SIG. BIT IS TOP DOT OF STROKE
;	SET UP GRAPHIC OUTPUT BUFFER AREA
ESCK:	DB	1BH,'S',0,0,0,0	;GRAPHIC MODE SELECT CODE
GBUFF:	DS	MAXX+1		;SET ASIDE AREA FOR GRAPHIC O/P BUFFER
NGRAPH	DW	0000H		;INITIALIZE GRAPHIC COUNTER
	ENDIF			;(CITOH)
;
	IF	OKI
MAXX	EQU	575		;SET MAXIMUM WIDTH FOR 72 DOTS/INCH
MAXY	EQU	573		;SET MAXIMUM HEIGHT TO MAKE SQUARE PLOT
MAPSIZE	EQU	47232D		;TOTAL SIZE OF MAP
CWIDTH	EQU	6		;RASTER WIDTH OF CHARACTER
NO8BIT	EQU	FALSE		;SHOULD BE FALSE EVEN IF 7 BIT INTERFACE
MSBTOP	EQU	FALSE		;LEAST SIG. BIT IS TOP DOT OF STROKE
;	SET UP GRAPHIC OUTPUT BUFFER AREA
GBUFF:	DS	MAXX+1
NGRAPH	DW	0000H
	ENDIF			;(OKI)
;
;
;========================= DATA STORAGE SECTION ============================
;
COLOR	DB	0
XPOS	DW	0
YPOS	DW	0
X	DW	0
Y	DW	0
YFILL	DW	0
NCHAR	DW	0
ACHAR	DB	40H
POINTER	DB	128D			;POINTER IN FILE BUFFER
POINTR2	DB	00H			;POINTER IN OUTPUT FILE BUFFER
OLDSTK	DW	0000H
STACK	DS	80H			;SET ASIDE 128 LEVEL STACK
XDOT	DW	0000H			;POSITION OF DOT TO BE PLOTTED
YDOT	DW	0000H			;POSITION OF DOT TO BE PLOTTED
XYADDR	DW	ORIGIN			;ADDRESS OF X,Y LOCATION
XYBIT	DB	00H			;BIT IN BYTE @ XYADDR FOR X,Y
DIVDND	DW	0000H			;2 BYTE DIVIDEND IN DIVIDE
DIVSOR	DB	00H			;1 BYTE DIVISOR IN DIVIDE
QOTENT	DB	00H			;1 BYTE QUOTIENT FROM DIVIDE
RMANDR	DB	00H			;1 BYTE REMAINDER FROM DIVIDE
BLANK	EQU	' '
NOSPEC	DB	'No File Specified',0DH,0AH,'$'	;ERROR MESSAGES
NOFILE	DB	'File Not Found',0DH,0AH,'$'
EOFMSG	DB	'End of File',0DH,0AH,'$'
NODIR	DB	'No Directory Space Available',0DH,0AH,'$'
NOROOM	DB	'Disk is Full',0DH,0AH,'$' 
UNKNCH	DB	'Undefined Command Character Encountered',0DH,0AH,'$'
STAT1	DB	'	       Working ...              ',0DH,'$'
STAT2	DB	'	               ... Working      ',0DH,'$'
STAT3	DB	'	       Printing Picture         ',07H,0DH,'$'
STATNO	DB	00H
DELTAX	DW	0000H			;LOCAL VARIABLES FOR INCPLT
DELTAY	DW	0000H			;LOCAL VARIABLES FOR INCPLT
EPSLNX	DW	0000H			;LOCAL VARIABLES FOR INCPLT
EPSLNY	DW	0000H			;LOCAL VARIABLES FOR INCPLT
SX	DW	0000H			;LOCAL VARIABLES FOR INCPLT
SY	DW	0000H			;LOCAL VARIABLES FOR INCPLT
DELTA3	DW	0000H			;LOCAL VARIABLES FOR INCPLT
NI	DW	0000H			;LOCAL VARIABLES FOR INCPLT
;
CMASK	DB	0FFH			;COLOR MASK
PATRN	DS	8			;CELL STORAGE FOR CLRMAP (ERASE)
PLAIDS	DB	00H,01H,71H,13H,05H,0FH,35H,11H	; CROSS HATCHED PATTERNS
;
CIFPAT	DB	 00H, 03H, 48H, 03H, 00H, 30H, 84H, 30H	;ND
	DB	 00H,0CCH, 00H,0CCH, 00H, 00H, 00H, 00H	;NI  S
	DB	 08H, 04H, 02H, 01H, 80H, 40H, 20H, 10H	;NT   P
	DB	 11H, 30H, 71H, 30H, 11H, 03H, 17H, 03H	;NC    E
	DB	 22H, 00H, 88H, 00H, 22H, 00H, 88H, 00H	;NM     C
	DB	0C0H, 81H, 03H, 06H, 03H, 81H,0C0H, 60H	;NB  P   I
	DB	 1CH, 3EH, 36H, 3EH, 1CH, 00H, 00H, 00H	;NG   A   A
	DB	 00H, 00H, 00H, 00H, 00H, 00H, 00H, 01H	;CW    T   L
	DB	 04H, 11H, 04H, 00H, 40H, 11H, 40H, 00H	;CD     T
	DB	 02H, 04H, 08H, 10H, 20H, 40H, 80H, 01H	;CP      E
	DB	 00H, 00H, 10H, 38H, 10H, 00H, 00H, 00H	;CS       R
	DB	 66H, 99H, 99H, 66H, 66H, 99H, 99H, 66H	;CC        N
	DB	 00H, 00H, 80H, 10H, 00H, 00H, 10H, 80H	;CM         S
	DB	 81H,0C3H, 66H, 66H,0C3H, 81H, 00H, 00H	;CG
	DB	 0FH, 0EH, 0CH, 08H, 00H, 00H, 00H, 00H	;CE
;
DITHARR	DB	 63,  95,  71, 103,  65,  97,  73, 105	;     ORDERED
	DB	111,  79, 119,  87, 113,  81, 121,  89	; 
	DB	 75, 107,  67,  99,  77, 109,  69, 101	;     DITHER
	DB	123,  91, 115,  83, 125,  93, 117,  85	; 
	DB	 66,  98,  74, 106,  64,  96,  72, 104	;     MATRIX
	DB	114,  82, 122,  90, 112,  80, 120,  88	; 
	DB	 78, 110,  70, 102,  76, 108,  68, 100	; 
	DB	126,  94, 118,  86, 124,  92, 116,  84	; 
;
;
;
;
BOOT	EQU	0000H			;CP/M SYSTEM ENTRY POINT
FCB	EQU	BOOT+005CH		;LOCATION OF FILE CONTROL BLOCK
DMA	EQU	BOOT+0080H		;FILE BUFFER ADDRESS
FDOS	EQU	BOOT+0005H		;ENTRY POINT FOR CPM FUNCTIONS
FCB2	DS	33D			;OUTPUT FILE CONTROL BLOCK
DMA2	DS	128D			;OUTPUT FILE BUFFER
OPDISK	DB	00H			;OUTPUT TO DISK FLAG
;
;-----------------------------------------------------------------------
;
ENTRY	LXI	SP,STACK+80H	;SET NEW 128 LEVEL STACK
	LDA	FCB+9		;GET FIRST CHARACTER OF FILE TYPE
	CPI	BLANK		;IS TYPE BLANK?
	JNZ	NAME			;NO- TYPE HAS BEEN SPECIFIED
	MVI	A,'V'		;MAKE DEFAULT TYPE "VEC"
	STA	FCB+9		;STORE DEFAULT IN FILE TYPE AREA
	MVI	A,'E'
	STA	FCB+10		;STORE DEFAULT IN FILE TYPE AREA
	MVI	A,'C'
	STA	FCB+11		;DONE- DEFAULT IS SET
NAME	LDA	FCB+1			;GET FIRST CHAR FROM FCB
	CPI	BLANK			;IS NAME BLANK?
	JNZ	OPENOP			;JUMP IF A FILE NAME EXISTS
	MVI	C,09H			;SELECT PRINT STRING FUNCTION
	LXI	D,NOSPEC		;PASS ERROR MESSAGE
	CALL	FDOS			;PRINT IT
	JMP	BOOT			;RETURN TO CPM SYSTEM LEVEL
OPENOP	LDA	FCB+17D			;GET 1ST CHAR OF O/P FILE
	CPI	BLANK			;IS NAME BLANK?
	JZ	OPENFIL			;BLANK= NORMAL PRINT OUTPUT
	MVI	A,01H			;SET O/P FILE FLAG=1 (DISK O/P)
	STA	OPDISK			;STORE FLAG
;
;	MOVE O/P FILE NAME TO NEW FCB
;
	MVI	C,16D			;HALF OF FCB#1 IS O/P INFO
	LXI	D,006CH			;START OF O/P FILE NAME
	LXI	H,FCB2			;SET DESTINATION ADDRESS
MOVFCB	LDAX	D			;GET NAME CHARACTER
	MOV	M,A			;STORE NAME CHARACTER
	INX	D			;INCREMENT OLD NAME ADDRESS
	INX	H			;INCREMENT NEW NAME ADDRESS
	DCR	C			;DECREMENT COUNTER
	JNZ	MOVFCB			;LOOP BACK IF NOT DONE
;
	MVI	A,0			;CLEAR ACCUMULATOR
	STA	FCB2+32D		;ZERO CR FIELD IN O/P FCB
;
	LDA	FCB2+9			;GET 1ST CHAR IN O/P FILE TYPE
	CPI	BLANK			;IS FILE TYPE BLANK?
	JNZ	DELETE			;NOT BLANK- GO TO DELELTE OLD
	MVI	A,'P'			;MAKE DEFAULT 'PLT'
	STA	FCB2+9			;STORE DEFAULT 'P'
	MVI	A,'L'
	STA	FCB2+10			;STORE DEFAULT 'L'
	MVI	A,'T'
	STA	FCB2+11			;STORE DEFAULT 'T'
;
DELETE	LXI	D,FCB2			;PASS O/P FILE FCB
	MVI	C,19D			;SELECT DELETE FUNCTION
	CALL	FDOS			;DELETE OLD FILE
;
;	MAKE NEW O/P FILE
;
	MVI	C,26D			;SELECT SET DMA FUNCTION
	LXI	D,DMA2			;PASS O/P FILE BUFFER ADDRESS
	CALL	FDOS			;SET DMA ADDRESS
;
	MVI	C,22D			;SELECT MAKE FILE FUNCTION
	LXI	D,FCB2			;PASS FCB FOR O/P
	CALL	FDOS			;MAKE NEW FILE
	CPI	0FFH			;IS DIRECTORY FULL?
	JNZ	OPENFIL			;NO- GO ON WITH PROGRAM
;
	MVI	C,09H			;SELECT PRINT FUNCTION
	LXI	D,NODIR			;PASS NO DIRECTORY SPACE MSG
	CALL	FDOS			;PRINT ERROR MESSAGE
	JMP	BOOT			;FATAL ERROR- QUIT
;
;OPEN DISK FILE OF PLOT COMMANDS
;
OPENFIL	MVI	C,26D			;SELECT SET DMA FUNCTION
	LXI	D,DMA			;PASS I/P BUFFER LOCATION
	CALL	FDOS			;SET DMA TO I/P BUFFER
;
	MVI	C,0FH			;SELECT OPEN FILE FUNCION
	MVI	A,00H			;CLEAR ACCUMULATOR
	STA	FCB+12			;CLEAR EXTENT COUNTER
	STA	FCB+14			;CLEAR S2 PARAMETER IN FCB
	LXI	D,FCB			;PASS FCB
	CALL	FDOS			;OPEN FILE
	CPI	0FFH			;WAS FILE FOUND?
	JNZ	REWIND			;IF FILE EXITS, REWIND IT
	MVI	C,09H			;SELECT PRINT FUNCTION
	LXI	D,NOFILE		;PASS MESSAGE
	CALL	FDOS			;PRINT IT
	JMP	BOOT			;RETURN TO CPM COMMAND LEVEL
;
REWIND	MVI	A,00H			;CLEAR ACCUMULATOR
	STA	FCB+32D			;REWIND BY SETTING RECORD#=0
;
PARSE	CALL	BYTE		;GET COMMAND CHARACTER
	CPI	60H		;IS IT LOWER CASE?
	JC	PARSE0		;NO, SO SKIP SHIFTING IT
	XRI	00100000B	;SHIFT CHARACTER TO UPPER CASE
;
PARSE0	CPI	'P'		;IS IT A "P"?
	PUSH	PSW		;SAVE COMMAND CHARACTER
	CZ	POINT		;P COMMANDS PLOT POINT
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CALL	STAT		;DISPLAY STATUS MESSAGE
;
;
	CPI	'C'
	PUSH	PSW
	CZ	COLOUR		;C COMMANDS SET COLOR
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'D'		;IS IT A "D"?
	PUSH	PSW		;SAVE COMMAND CHARACTER
	CZ	PLOTSEG		;D COMMANDS PLOT SEGMENT
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'E'
	PUSH	PSW
	CZ	CLRMAP		;E COMMANDS CLEAR MEMORY MAP TO COLOR
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'F'
	PUSH	PSW
	CZ	FILL		;F COMMANDS FILL AREA TO COLOR
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHARACTER
;
	CPI	'I'
	PUSH	PSW
	CZ	INCPLT		;I COMMANDS PLOT INCREMENTAL SEGMENT
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'M'		;M COMMANDS MOVE TO COORD W/O PLOTTING
	PUSH	PSW
	CZ	MOVE
	POP	PSW
	JZ	PARSE
;
	CPI	'N'
	JZ	PARSE		;N COMMANDS A NO OPERATION LOOP
;
	CPI	'O'
	PUSH	PSW
	CZ	MAPOUT		;O COMMANDS PRINTING OF PLOT
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'Q'
	PUSH	PSW
	CZ	QUIT		;Q COMMANDS TERMINATION OF PROGRAM
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'S'
	PUSH	PSW
	CZ	STRING		;S COMMANDS CHARACTER STRING PLOTTING
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'T'
	PUSH	PSW
	CZ	TEXT		;T COMMANDS RAW TEXT OUTPUT
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'U'
	PUSH	PSW
	CZ	UPLOAD		;U COMMANDS UPLOAD OF COLOR PATERNS
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	'X'
	PUSH	PSW
	CZ	XTEND		;PROVISION FOR NON-STANDARD COMMANDS
	POP	PSW
	JZ	PARSE			;LOOP BACK FOR NEW CHAR
;
	CPI	0DH			;IGNORE CARRIAGE RETURNS
	JZ	PARSE
;
	CPI	0AH
	JZ	PARSE			;IGNORE LINE FEEDS
;
;	COMMAND CHARACTER DOES NOT MATCH ANY DEFINED COMMAND
;
	MVI	C,09H		;SELECT PRINT STRING FUNCTION
	LXI	D,UNKNCH	;PASS UNDEFINED CHARACTER MESSAGE
	CALL	FDOS		;PRINT IT
	JMP	PARSE		;LOOP UP TO TOP TO GET NEW CHARACTER
;
;-----------------------------------------------------------------------
;                 DEFINE SUBROUTINES
;-----------------------------------------------------------------------
;
;	CONVERT BINARY INTEGER TO DECIMAL ASCII NUMBER
;
;	INPUTS:
;		N (BINARY NUMBER) IN [DE]
;		ADDRESS TO STORE LOW DIGIT IN [HL]
;	OUTPUTS:
;		ASCII NUMBER STORED IN MEMORY, HIGH BYTE FIRST.
;		     NOTE: THE ADDRESS IS DECREMENTED FOR EACH CHAR.
;	REGISTER STATUS:
;		ALL REGISTER VALUES PRESERVED
;	ERROR CONDITIONS:
;		NONE
;
	IF	CITOH
BINDEC:	PUSH	H		;SAVE REGISTERS
	PUSH	D
	PUSH	B
	PUSH	PSW
;
	MVI	A,10D		;GET A TEN
	STA	DIVSOR		;DIVISIONS WILL BE BY BASE 10
;
BDECLP:	PUSH	H		;SAVE ADDRESS FOR FUTURE USE
	MOV	A,D
	STA	DIVDND		;FIRST DIVIDE HIGH BYTE
	MVI	A,00H
	STA	DIVDND+1	;16 BIT DIVIDEND NOW = 8 BIT N HIGH BYTE
	CALL	DIVIDE		;DIVIDE BY 10
	LDA	QOTENT
	MOV	D,A		;RESULT IS HIGH BYTE OF NEW N
	LXI	H,RMANDR
	MOV	H,M		;DIVIDE REMAINDER WITH LOW BYTE OF N
	MOV	L,E		;ADD LOW BYTE OF N TO REMAINDER
	SHLD	DIVDND
	CALL	DIVIDE		;DIVIDE LOW BYTES BY 10
	POP	H		;RETRIEVE ADDRESS TO RECEIVE CHARACTER
	LDA	RMANDR		;REMAINDER IS DIGIT
	ADI	30H		;CONVERT DIGIT TO ASCII
	MOV	M,A		;STORE CHARACTER
	DCX	H		;MOVE POINTER LEFT
	LDA	QOTENT		;GET RESULT OF DIVISION
	MOV	E,A		;RESULT IS LOW BYTE OF NEW N
	ORA	D		;IS NEW END = 0?
	JNZ	BDECLP		;LOOP BACK UP IF > 0
;
	POP	PSW
	POP	B
	POP	D
	POP	H		;REGISTERS RESTORED
	RET
	ENDIF			;(CITOH)
;----------------------------------------------------------------------
;
;	BMULT PERFORMS A 1-BYTE BY 2-BYTE MULTIPLY
;
;	THIS ROUTINE IS FROM ELECTRONICS MAGAZINE, FEB 24, 1982.
;	BY JERRY L. GOODRICH, PENN. STATE U.
;
;	INPUTS:
;		8-BIT NUMBER IN [A]
;		16-BIT NUMBER IN [BC]
;	OUTPUTS:
;		PRODUCT IN [A],[HL] (HIGH BYTE IN [A])
;	REGISTER STATUS:
;		SEE INPUTS AND OUTPUTS
;	ERROR CONDITIONS:
;		NONE
;
BMULT	LXI	H,0		;ZERO PARTIAL PRODUCT
	LXI	D,7		;D=0,E=BIT COUNTER
	ADD	A		;GET FIRST MULTIPLIER BIT
LOOP1:	JNC	ZERO		;ZERO SKIP
	DAD	B		;ONE-ADD MULTIPLICAND
	ADC	D		;ADD CARRY TO THIRD BYTE OF PRODUCT
ZERO:	DAD	H		;SHIFT PRODUCT LEFT
	ADC	A
	DCR	E		;DECREMENT BIT COUNTER
	JNZ	LOOP1		;LOOP UNTIL DONE
	RNC			;DONE IF NO CARRY
	DAD	B		;OTHERWISE DO LAST ADD
	ADC	D
	RET			;AND RETURN
;-----------------------------------------------------------------------
;	BYTE GETS NEXT BYTE IN BUFFER
;	NEXT RECORD IS READ IF NEED BE
;	INPUTS:
;		128 CHARACTER BUFFER @ DMA
;		CHARACTER POINTER @ POINTER WHICH IS SET @ LAST POSITION
;	OUTPUTS:
;		NEW BYTE IN ACCUMULATOR
;	REGISTER STATUS:
;		[BC],[DE],[HL] REGISTERS PRESERVED
;	ERROR CONDITIONS:
;		NONE- IF POINTER EXCEEDS 128, NEW RECORD IS READ
;
BYTE	PUSH	B		;SAVE REGISTERS
	PUSH	D
	PUSH	H
;
	LDA	POINTER			;GET POINTER VALUE
	CPI	128D			;IS POINTER=128?
	CZ	READ			;GET RECORD IF LAST ONE WAS #128
	LDA	POINTER			;GET NEW POINTER VALUE
	INR	A			;INCREMENT POINTER VALUE
	STA	POINTER			;STORE NEW POINTER VALUE
	MOV	C,A			;SAVE POINTER VALUE IN C
	MVI	B,0			;MAKE BC=C
	LXI	H,DMA-1			;LOAD HL WITH BYTE BEFORE DMA 
	DAD	B			;CALCULATE ADDR OF DESIRED BYTE
	MOV	A,M			;GET BYTE
;
	POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	RET				;DONE-- BYTE IS IN ACCUM.
;-----------------------------------------------------------------------
;
;	PRINTED CHARACTER OUTPUT
;
;	INPUTS:
;		CHARACTER IN REGISTER [A]
;
;	OUTPUTS:
;		GRAPHIC BUFFER IS FLUSHED
;		CHARACTER IS PUT OUT TO PRINTER
;		ADDRESS IN [HL] IS INCREMENTED BY (CWIDTH - 1)
;		DOT COUNTER INCREMENTED BY (CWIDTH - 1)
;		THE ABOVE ARE TO ACCOUNT FOR THE SIZE OF A CHARACTER
;		AS OPPOSED TO A SINGLE DOT
;	REGISTER STATUS:
;		[A,PSW],[BC] PRESERVED
;		[DE] DECREMENTED BY (CWIDTH -1)
;		[HL] INCREMENTED BY (CWIDTH -1)
;	ERROR CONDITIONS:
;		NONE
;
CHAROUT: PUSH	PSW			;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
;
	XRI	10000000B		;CLEAR HIGH BIT OF CHARACTER
	CALL	GBUFOUT			;FLUSH GRAPHIC BUFFER
	MVI	C,05H			;SELECT LIST OUTPUT
	MOV	E,A			;PASS CHARACTER
	CALL	PDOS			;SEND CHARACTER TO PRINTER
;
	POP	H			;RECALL REGISTERS
	POP	D
	MVI	A,CWIDTH-1
CHARO1:	INX	H			;INCREMENT ADDRESS
	DCX	D			;DECREMENT DOT COUNTER
	SUI	1			;DECREMENT LOOP COUNTER
	JNZ	CHARO1
;
	POP	B
	POP	PSW
	RET
;
;-----------------------------------------------------------------------
;
;	CLEAR MEMORY SUBROUTINE
;
;	INPUTS:
;		BITMAP OF SIZE MAPSIZE LOCATED AT ORIGIN
;		MAP COLOR STORED IN COLOR
;		(POS = PATTERNED, 0 = WHITE, - = COMPLEMENTARY)
;	OUTPUTS:
;		ENTIRE MAP AREA SET TO DESIRED COLOR OR PATTERN
;	REGISTERS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE
;
CLRMAP:	LDA	COLOR			;GET COLOR
	ORA	A			;SET FLAGE ACCORDING TO COLOR
	JNZ	CLRNZ			;IS COLOR NON-WHITE?
	LXI	D,MAPSIZE		;PUT MAPSIZE IN [DE] AS COUNTER
	LXI	H,ORIGIN		;PUT START OF MAP IN [HL]
	MVI	C,00H			;C CONTAINS IMAGE OF WHITE BYTE
CLRLP1:	MOV	M,C			;TOP OF LOOP, STORE BYTE
	INX	H			;INCREMENT ADDRESS IN MAP
	DCX	D			;DECREMENT LOOP COUNTER
	MOV	A,D			;MOVE HIGH BYTE OF COUNT. TO [A]
	ORA	E			;CHECK FOR 0 COUNTER
	JNZ	CLRLP1			;LOOP UNTIL DONE
	RET				;FINISHED WITH WHITE ERASE
;
CLRNZ:	PUSH	PSW		;SAVE FLAG VALUES
;	NOW FORM 8 BYTE COLOR PATTERN
	LXI	H,PATRN+7	;POINT TO LAST IN PATTERN SEQUENCE
	MVI	C,07H		;INITIALIZE X COUNTER
CLRLP2:	MVI	D,80H		;SET UP Y BIT SELECT
	MVI	E,07H		;INITIALIZE Y COUNTER
	MVI	B,00H		;INITIALIZE PATTERN
CLRLP3:	CALL	CLRMSK		;FORM COLOR MASK BASED ON X,Y
	LDA	CMASK		;GET MASK
	ANA	D		;SELECT ONE BIT
	ORA	B		;ADD BIT TO PATTERN
	MOV	B,A		;SAVE NEW PATTERN
	MOV	A,D		;MODIFY BIT SELECT MASK
	RRC			;MOVE SELECT BIT DOWN ONE NOTCH
	MOV	D,A		;SAVE NEW BIT SELECT
	DCR	E		;DECREMENT Y COUNTER
	JP	CLRLP3		;JUMP BACK IF NOT NEGATIVE (NEED 0 PASS)
	POP	PSW		;RETRIEVE COLOR CODE FLAG SETTINGS
	PUSH	PSW		;RE-SAVE FLAGS SETTINGS
	JP	CLRL31		;POSITIVE FLAG MEANS PATTERN IS OK
	MOV	A,B		;GET PATTERN
	CMA			;COMPLEMENT PATTERN FOR NEGATIVE COLORS
	MOV	B,A		;STORE PATTERN BYTE
CLRL31:	MOV	M,B		;SAVE PATTERN FOR THIS X LOCATION
	DCX	H		;MOVE MEMORY POINTER OVER
	DCR	C		;DECREMENT X COORDINATE/COUNTER
	JP	CLRLP2		;ONLY DONE WHEN NEGATIVE (NEED 0 PASS)
;
;	SET UP FOR CLEARING MEMORY
;	ROTATE ARRAY OF PATTENRX DOWN TO MATCH
;
	LXI	B,(MAXY+1) MOD 8+1;COUNTER FOR ROTATIONS DUE TO MISMATCH
CLRLP4:	CALL	ROTPAT		;ROTATE PATTERN ARRAY 1 POSITION
	DCR	C		;DECREMENT COUNTER
	JNZ	CLRLP4		;LOOP BACK IF NOT DONE
;
	LXI	H,ORIGIN	;SET MAP POINTER TO START OF MAP
	LXI	B,(MAXY+1)/7	;INITIALIZE LINE COUNTER
CLRLP5:	LXI	D,(MAXX+1)/8	;INITALIZE DOT COUNTER
CLRL51:	LDA	PATRN		;GET FIRST BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+1		;GET SECOND BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+2
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+3
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+4
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+5
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+6
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	LDA	PATRN+7
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT X COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER ZERO?
	JNZ	CLRL51		;LOOP BACK UNTIL DONE
;
	LXI	D,(MAXX+1)MOD 8	;SET COUNTER FOR REST OF LINE
	MOV	A,D		;CHECK TO SEE IF LINESIZE ID MULT OF 8
	ORA	E		;WAS MOD 8 =0?
	JZ	CLRLP6		;JUMP TO BOTTOM OF LOOP IF FINISHED
	LDA	PATRN		;APPLY PATTERN TO REMANING 1-7 BYTES
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT LINE LENGTH COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER = 0?
	JZ	CLRLP6		;IF FINISHED, SKIP TO BOTTOM OF OUTER LP
	LDA	PATRN+1		;CONTINUE WITH NEXT PATTERN BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT LINE LENGTH COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER = 0?
	JZ	CLRLP6		;IF FINISHED, SKIP TO BOTTOM OF OUTER LP
	LDA	PATRN+2		;CONTINUE WITH NEXT PATTERN BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT LINE LENGTH COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER = 0?
	JZ	CLRLP6		;IF FINISHED, SKIP TO BOTTOM OF OUTER LP
	LDA	PATRN+3		;CONTINUE WITH NEXT PATTERN BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT LINE LENGTH COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER = 0?
	JZ	CLRLP6		;IF FINISHED, SKIP TO BOTTOM OF OUTER LP
	LDA	PATRN+4		;CONTINUE WITH NEXT PATTERN BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT LINE LENGTH COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER = 0?
	JZ	CLRLP6		;IF FINISHED, SKIP TO BOTTOM OF OUTER LP
	LDA	PATRN+5		;CONTINUE WITH NEXT PATTERN BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
	DCX	D		;DECREMENT LINE LENGTH COUNTER
	MOV	A,E
	ORA	D		;IS COUNTER = 0?
	JZ	CLRLP6		;IF FINISHED, SKIP TO BOTTOM OF OUTER LP
	LDA	PATRN+6		;CONTINUE WITH NEXT PATTERN BYTE
	ANI	7FH		;CLEAR HI BIT
	MOV	M,A		;STORE PATTERN IN MEMORY MAP
	INX	H		;MOVE MEMORY POINTER
;
CLRLP6:	CALL	ROTPAT		;ROTATE PATTERN DOWN TO MATCH CELLS
	DCX	B		;BOTTOM OF OUTER LOOP. DEC LINE COUNTER
	MOV	A,C
	ORA	B		;IS COUNTER = 0?
	JNZ	CLRLP5		;LOOP BACK UP FOR ANOTHER IF REQ'D
;
	POP	PSW		;CLEAN UP STACK
	RET
;
;-----------------------------------------------------------------------
;
;	COLOR MASK
;
;	THIS SUBROUTINE FORMS THE COLOR MASK USED IN PLOTTING POINTS
;
;	METHOD:
;		THE PLOT IS DIVIDED UP INTO 8 X 8 RASTER CELLS.
;		FOR COLOR VALUES BETWEEN 1 AND 63, THE CELL IS COMPOSED
;		OF AN X PATTERN AND A Y PATTERN WHICH ARE XOR'ED WITH
;		EACH OTHER TO FORM A "PLAID" PATTERN
;		FOR COLOR VALUES 64 AND ABOVE, ORDERED DITHERING IS USED
;		ORDERED DITHERING IS A TECHNIQUE IN WHICH THE DOTS IN 
;		THE CELL ARE ADDED IN IN A PRE-ARRANGED POSITION BASED
;		UPON THE "INTENSITIY" OF THE CELL.  THE INTERSECTION OF
;		THE POINT AND THE PATTERN (STORED IN THE ARRAY "DITHARR"
;		DETERMINES WHETHER OR NOT THE POINT IS PLOTTED
;
;		FOR BOTH METHODS, A COLOR MASK IS CREATED, WHICH IS 
;		ALL 1'S IF THE POINT IN THE PATTERN PLANE IS ON, OR 
;		ALL 0'S IF THE POINT IN THE PATTERN PLANE IS OFF.
;	INPUTS:
;		X COORDINATE IN BC
;		Y COORDINATE IN DE
;	OUTPUTS:
;		COLOR MASK STORED IN CMASK
;	REGISTER STATUS:
;		ALL REGISTERS PRESERVED
;	ERROR CONDITIONS:
;		NONE
;
CLRMSK	PUSH	PSW		;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
;
	MOV	A,C		;FORM X CELL COORDINATE
	ANI	00000111B
	MOV	B,A
;
	MOV	A,E		;FORM Y CELL COORDINATE
	ANI	00000111B
	MOV	C,A
;
	LDA	COLOR		;GET COLOR CODE
	ORA	A		;SET FLAGS BASED ON BASIC CODE
	JZ	WHTMSK		;ZERO COLOR => WHITE MASK
	JP	POSCLR		;COLOR CODE IS POSITIVE
	CMA			;COMPLEMENT COLOR
	ADI	01H		;COLOR CODE IS NOW POSITIVE
POSCLR	CPI	64D		;IS COLOR CODE < 64
	JNC	DITHER		;CODE >=64 --> DITHERED
	CPI	49D		;IS COLOR CODE < 49
	JNC	SPECIAL		;CODE FROM 49 TO 63 --> CIFPAT'S ELSE PLAID
;
	PUSH	PSW		;SAVE COLOR CODE
	ANI	07H		;SELECT LOWER 3 BITS OF COLOR CODE
	LXI	H,PLAIDS	;GET BASE ADDRESS OF BASIC PATTERN
	ADD	L		;ADD X CODE TO BASE ADDR TO FIND PATTERN
	MOV	L,A
	MOV	A,H
	ACI	00H		;ADD CARRY TO HIGH BYTE OF ADDRESS
	MOV	H,A
	MOV	A,M		;GET X PATTERN FOR CELL
	INR	B		;INCREMENT X COORDINATE TO BE COUNTER
XCELLP	RAR			;ROTATE PATTERN BIT INTO CARRY
	DCR	B		;DECREMENT COUNTER
	JNZ	XCELLP		;LOOP BACK IF NOT DONE
	MVI	A,0FFH		;CARRY --> PATTERN BIT SAYS PLOT POINT
	JC	SAVXMSK		
	MVI	A,00H
SAVXMSK	MOV	B,A		;REPLACE X CELL COORD WITH X COLOR MASK
;
	POP	PSW		;RETRIEVE COLOR CODE
	ANI	38H		;SELECT 2ND 3 BITS FOR Y CODE
	RRC			;ROTATE BITS TO LOW ORDER POSITION
	RRC
	RRC
	LXI	H,PLAIDS	;GET BASE ADDRESS OF BASIC PATTERN
	ADD	L		;ADD X CODE TO BASE ADDR TO FIND PATTERN
	MOV	L,A
	MOV	A,H
	ACI	00H		;ADD CARRY TO HIGH BYTE OF ADDRESS
	MOV	H,A
	MOV	A,M		;GET Y PATTERN FOR CELL
	INR	C		;INCREMENT Y COORDINATE TO BE COUNTER
YCELLP	RAR			;ROTATE PATTERN BIT INTO CARRY
	DCR	C		;DECREMENT COUNTER
	JNZ	YCELLP		;LOOP BACK IF NOT DONE
	MVI	A,0FFH		;DOT WILL BE PLOTTED IF CARRY SET
	JC	SAVYMSK		
	MVI	A,00H
SAVYMSK	XRA	B		;FINAL COLOR MASK-- X PATRN XOR Y PATRN
	STA	CMASK		;SAVE COLOR MASK
;
	POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	RET			;FINISHED   -END OF PLAID BRANCH
;
DITHER	PUSH	PSW		;SAVE COLOR CODE FOR FUTURE USE
	MOV	A,C		;MULTIPLY Y CELL COORDINATE BY 8
	RLC
	RLC
	RLC
	ADD	B		;OFFSET INTO DITHER TABLE = Y*8 + X
	LXI	H,DITHARR	;GET BASE ADDRESS OF TABLE
	ADD	L		;ADD OFFSET TO BASE ADDRESS
	MOV	L,A
	MOV	A,H
	ACI	00H		;ADD CARRY TO HIGH BYTE
	MOV	H,A
	MOV	A,M		;GET DITHER TABLE VALUE
	POP	D		;RETRIEVE COLOR CODE (FORMERLY IN [A])
	CMP	D		;IS DITHER VALUE > COLOR CODE?
	MVI	A,0FFH		;CARRY--> PLOT POINT
	JC	SAVMSK
	MVI	A,00H		;CARRY NOT SET--> DON'T PLOT POINT
SAVMSK	STA	CMASK		;STORE MASK FOR FUTURE USE
;
	POP	H
	POP	D
	POP	B
	POP	PSW		;REGISTERS RESTORED, STACK CLEANED UP
	RET
;
;
SPECIAL:SUI	49D		;CODE IS NOW RELATIVE TO 49
	RLC			;CODE * 8
	RLC
	RLC
	ADD	B		;ADD X COORD TO FORM OFFSET INTO ARRAY
	LXI	H,CIFPAT	;GET FWA OF PATTERN ARRAY
	ADD	L		;ADD OFFSET TO FWA
	MOV	L,A
	MOV	A,H
	ACI	00H		;ADD CARRY TO HI BYTE
	MOV	H,A		;ADDITION COMPLETE
	MOV	A,M		;GET PATTERN BYTE FOR THIS X COORD.
	INR	C		;INCREMENT Y COORD TO FORM COUNTER 
SPCLP:	RAR			;ROTATE PATTERN BIT INTO CARRY
	DCR	C		;DECREMENT COUNTER
	JNZ	SPCLP		;LOOP BACK UNTIL DONE
	MVI	A,0FFH		;DOT WILL BE PLOTTED IF CARRY SET
	JC	SAVMSK
	MVI	A,00H		;CARRY NOT SET- DON'T PLOT POINT
	JMP	SAVMSK
;
;
WHTMSK	MVI	A,0FFH		;FOR WHITE, ALWAYS MODIFY DOT
	JMP	SAVMSK		;SAVE MASK AND RETURN
;
;-----------------------------------------------------------------------
;
;	DEFINE COLOR SUBROUTINE
;
;	INPUTS:
;		BUFFER @ DMA
;	OUTPUTS:
;		COLOR VALUE SAVED FOR FUTURE REFERENCE
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDTIONS:
;		NONE
;
COLOUR:	CALL	BYTE		;GET COLOR VALUE
	STA	COLOR		;SAVE IT
	RET
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE COMPUTES THE NEXT POINT IN A LINE SEGMENT
;	MUST BE USED WITH SEGINIT TO INITIALIZE ALL VARIABLES FIRST.
;
;	INPUTS:
;		NI	COUNTER USED BY CALLING SUB. TO KNOW WHEN DONE.
;		XPOS,YPOS	PRESENT POSITION
;		DX,DY	SIZE OF LINE SEGMENT ALONG X,Y AXIS
;		EPSLNX,EPSLNY,SX,SY,DELTA3	LOCAL VARIABLES
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED.
;	ERROR CONDITIONS:
;		NONE PECULIAR TO THIS ROUTINE
;
COMPSEG	LHLD	NI		;GET COUNTER VALUE
	INX	H		;NI<DX- CONTINUE (FIRST INCR. NI)
	SHLD	NI		;STORE NEW NI VALUE
	LHLD	XPOS		;GET XPOS & PUT IN (BC)
	MOV	B,H		;HI BYTE TO (B)
	MOV	C,L		;LOW BYTE TO (C)
	LHLD	YPOS		;FETCH YPOS
	XCHG			;PUT YPOS IN (DE)
	LHLD	EPSLNX		;FETCH EPSILON X
	DAD	B		;ADD EPSILON X TO X POSITION
	SHLD	XPOS		;STORE NEW VALUE
	LHLD	EPSLNY		;FETCH EPSILON Y
	DAD	D		;ADD EPSILON Y TO Y POSITION
	SHLD	YPOS		;STORE NEW VALUE OF Y POSITION
	LHLD	DELTAY		;FETCH DELTA Y
	XCHG			;PUT DELTAY IN (DE)
	LHLD	DELTA3		;FETCH DELTA 3
	DAD	D		;ADD DELTA Y TO DELTA 3
	SHLD	DELTA3		;STORE NEW VALUE OF DELTA3
	XCHG			;PUT NEW VALUE OF DELTA 3 IN (DE)
	LHLD	DELTAX		;FETCH DELTA X
	MOV	A,H		;CONTINUE IF DELTA X < DELTA 3 
	CMP	D		;OTHERWISE PLOT POINT AND LOOP
	JC	CONT2		;HI BYTES FIRST- DELTA3 DEFINITELY >
	JNZ	DOPT		;DX > D3- PLOT POINT
	MOV	A,L		;HIGH BYTES =: LOOK @ LOW BYTES
	CMP	E		;NOW LOW BYTES
	JNC	DOPT		;D3<=DX: PLOT POINT
CONT2	MOV	A,E		;COMPUTE D3=D3-DX 
	SUB	L		;SUBTRACT LOW BYTE FIRST
	MOV	L,A		;PUT LOW BYTE IN POSITION FOR STORE
	MOV	A,D		;NOW HIGH BYTE OF D3
	SBB	H		;SUBTRACT HIGH BYTE
	MOV	H,A		;PUT HI BYTE IN POSITION FOR STORE
	SHLD	DELTA3		;STORE RESULT
	LHLD	SX		;COMPUTE XPOS=XPOS+SX
	XCHG			;PUT SX IN (DE)
	LHLD	XPOS		;FETCH X POSITION
	DAD	D		;ADD SX TO XPOS
	SHLD	XPOS		;STORE RESULT
	LHLD	SY		;COMPUTE YPOS=YPOS+SY
	XCHG			;PUT SY IN (DE)
	LHLD	YPOS		;FETCH Y POSITION
	DAD	D		;ADD SY
	SHLD	YPOS		;STORE NEW Y POSITION
DOPT	RET			;RETURN SO CALLING SUB CAN USE POSITION.
;
;-----------------------------------------------------------------------
;		CARRIAGE RETURN ROUTINE
;
;	INPUTS:
;		NONE
;
;	OUTPUTS:
;		PRINTER CARRIAGE IS RETURNED AND PAPER ADVANCED
;
;	REGISTER STATUS:
;		ALL VALUES PRESERVED
;
;	ERROR CONDITIONS:
;		NONE
;
CRLF	PUSH	PSW		;SAVE ALL REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,0DH		;PASS CARRIAGE RETURN CHARACTER
	CALL	PDOS
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,0AH		;PASS LINE FEED CHARACTER
	CALL	PDOS		;SEND IT OUT
	POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	RET
;
;-----------------------------------------------------------------------
;	THIS SUBROUTINE FORMS THE MASK FOR THE PLOTTING OF A POINT
;	DIGIT= YCOORD MOD 7
;	INPUTS:
;		XCOORD IN BC
;		YCOORD IN DE
;		XYADDR IN HL
;	OUTPUTS:
;		CONTENTS OF XYADDR IN B
;		MASK (1 BIT ON) IN C
;		YCOORD IN DE
;		XYADDR IN HL
;	REGISTER STATUS:
;		SEE OUTPUTS
;	ERROR CONDITIONS:
;		OVERFLOW IN DIVIDE CALLS WOOPS
;
DIGIT	PUSH	H			;SAVE XYADDRESS
	PUSH	D			;SAVE YCOORD
	CALL	CLRMSK		;PREPARE COLOR MASK FOR FUTURE USE
	XCHG				;PUT YCOORD IN HL
	SHLD	DIVDND			;CALCULATE YCOORD MOD 7
	MVI	A,07H
	STA	DIVSOR
	CALL	DIVIDE			;MOD IS DIVIDE W/O QUOTIENT
	LDA	RMANDR			;GET RESULT
	ORA	A			;SET FLAGS
	CM	WOOPS			;RMANDR= -1 ON OVERFLOW
	MOV	B,A			;MOVE # OF DIGIT TO B
	MVI	A,00H
	INR	B			;INCREMENT B TO INIT FOR 1ST DEC
	IF	MSBTOP
	STC				;CLEAR ACCUM, PUT 1 IN CARRY
ROTMASK	RAL				;MOVE MASK BIT 1 LEFT
	ENDIF			;(MSBTOP)
;
	IF	NOT MSBTOP
	MVI	A,10000000B	;SET HIGH BIT AND ROTATE IT RIGHT
ROTMASK RRC			;MOVE MASK BIT 1 RIGHT
	ENDIF			;(NOT MSBTOP)
;
	DCR	B			;DECREMENT # OF DIGIT
	JNZ	ROTMASK			;LOOP BACK
	MOV	C,A		;STORE MASK TEMPORARILY
	LDA	CMASK		;GET COLOR MASK
	ANA	C		;AND BIT MASK WITH COLOR MASK- BOTH RQD
	MOV	C,A			;PUT MASK IN C
	POP	D			;BRING BACK YCOORD
	POP	H			;BRING BACK (XYADDR)
	MOV	B,M			;GET BYTE @ (XYADDR)
	RET
;
;-----------------------------------------------------------------------
;	DIVISION SUBROUTINE
;	INPUTS:
;		DIVDND  TWO BYTE POSITIVE NUMBER
;		DIVSOR	ONE BYTE POSITIVE NUMBER
;	OUTPUTS:
;		QOTENT	ONE BYTE POSITIVE QUOTIENT
;		RMANDR	ONE BYTE POSITIVE REMAINDER OR FLAG
;	REGISTER STATUS:
;		BC,DE,HL,PSW REGISTERS RETURNED TO ORIGINAL VALUES
;	ERROR CONDITIONS:
;		RMANDR=-1 IF OVERFLOW OCCURS
;
DIVIDE	PUSH	PSW			;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
	LHLD	DIVDND		;FETCH DIVIDEND
	XCHG				;PUT DIVIDEND INTO THE DE PAIR
	LDA	DIVSOR			;FETCH DIVSOR
	MOV	C,A			;SAVE IN REGISTER C
	MVI	B,8			;LOOP COUNTER IN REGISTER B
DIVLOOP	MOV	A,E			;SHIFT LOW ORDER BYTE TO LEFT
	ANA	A			;CLEAR CARRY
	RAL				;SHIFT
	MOV	E,A			;REPLACE VALUE
	MOV	A,D			;FETCH HIGH ORDER BYTE
	RAL				;ROTATE BRINGING IN HIGH BIT
	SUB	C			;SUBTRACT DIVISOR
	JP	SETBIT			;IF RESULT WAS POSITIVE, JUMP
	ADD	C			;OTHERWISE ADD BACK DIVISOR
	MOV	D,A			;REPLACE HIGH ORDER BYTE
	JMP	NEXT			;GO TO INCREMENT PHASE
SETBIT	MOV	D,A			;REPLACE HIGH ORDER BYTE
	MOV	A,E			;FETCH LOW ORDER BYTE
	ORI	1			;SET LOW ORDER BIT
	MOV	E,A			;REPLACE LOW ORDER BYTE
NEXT	DCR	B			;DECREMENT LOOP COUNTER
	JNZ	DIVLOOP			;REPEAT UNTIL DONE
	MOV	A,E			;QUOTIENT
	ANA	A			;TEST SIGN OF RESULT
	JP	OK			;IF POSITIVE RESULT IS ACCURATE
	MVI	A,0FFH			;SET OVERFLOW VALUE
	STA	RMANDR
	JMP	DONE
OK	STA	QOTENT			;SAVE QUOTIENT
	MOV	A,D			;REMAINDER
	STA	RMANDR			;SAVE REMAINDER
DONE	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE PLOTS THE VERTICAL LINE USED TO FILL IN AREAS
;
;	INPUTS:
;		XPOS,YPOS	CURRENT POSITION ON SEGMENT
;		YFILL		HORIZONTAL LEVEL TO FILL TO
;	OUTPUTS:
;		VERTICAL LINE FROM (XPOS,YPOS) TO (XPOS,YFILL)
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE PECULIAR TO THIS ROUTINE.
;		NOTE: ALL COORDINATE VALUES ASSUMED TO BE POSITIVE
;
FILINE	CALL	STAT		;UPDATE STATUS MESSAGE
	LHLD	XPOS		;GET STARTING COORDINATES OF LINE
	SHLD	XDOT		;XPOS WILL BE X COORD OF ALL DOTS
	LHLD	YPOS		;GET Y COORDINATE
	PUSH	H		;SAVE Y POSITION- PLOTDOT WILL RESET IT
	XCHG			;PUT Y COORDINATE IN [DE]
	LHLD	YFILL		;GET Y FILL VALUE
;
	MOV	A,D		;COMPARE Y COORDINATES FOR TOP AND BOT.
	CMP	H		;COMPARE HIGH BYTES
	JC	YFXCH		;CARRY INDICATES THAT YFILL IS > YPOS
	JNZ	CONTFIL		;YFILL DEFINITELY LESS THAN YPOS
	MOV	A,E		;HIGH BYTES EQUAL- COMPARE LOW BYTES
	CMP	L		;IS YFILL ABOVE OR BELOW YPOS?
	JNC	CONTFIL		;YFILL IS NOT ABOVE YPOS- CONTINUE
YFXCH	XCHG			;SWITCH YPOS AND YFILL- LARGER VAL IN DE
CONTFIL	SHLD	YDOT		;PASS Y COORDINATE TO PLOTDOT
	PUSH	D		;SAVE REGISTERS
	PUSH	H
	CALL	PLOTDOT		;PLOT POINT
	POP	H		;RETRIEVE REGISTERS
	POP	D
	INX	H		;INCREMENT Y POSITION
;
	MOV	A,D		;CHECK TO SEE IF LINE IS DONE
	CMP	H		;COMPARE HIGH BYTES
	JC	DONEFIL		;CARRY INDICATES THAT NEW Y IS ABOVE END
	JNZ	CONTFIL		;NEW COORDINATE DEFINITELY BELOW END
	MOV	A,E		;HIGH BYTES EQUAL- COMPARE LOW BYTES
	CMP	L		;IS IT THERE YET?
	JC	DONEFIL		;CARRY INDICATES THAT NEW Y IS ABOVE END
	JMP	CONTFIL		;LOOP BACK AND DO NEXT POINT
DONEFIL	POP	H		;RETRIEVE LINE Y POSITION
	SHLD	YPOS		;RESTORE VALUE
	RET			;ALL FINISHED!
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE WILL FILL AN AREA BETWEEN A LINE SEGMENT AND
;	A HORIZONTAL LINE
;
;	INPUTS:
;		BUFFER CONTAINING COORDINATE PAIRS AND Y COORDINATE OF 
;		FILL LEVEL.  ALL FIVE ARE REAL VALUES
;	OUTPUTS:
;		XPOS,YPOS UPDATED TO END OF LINE SEGMENT
;		AREA BETWEEN SEGMENT AND YFILL IS FILLED WITH CURRENT 
;		COLOR VALUE
;	REGISTER STATUS:
;		ALL REGISTERS DESTROYED
;	ERROR CONDITIONS:
;		NONE PECULIAR TO THIS ROUTINE
;
FILL	CALL	READXY		;GET STARTING COORDINATES
	LHLD	X
	SHLD	XPOS		;UPDATE X POSITION TO START OF SEGMENT
	LHLD	Y
	SHLD	YPOS		;UPDATE Y POSITION TO START OF SEGMENT
	CALL	READXY		;GET END COORDINATES
	CALL BYTE		;GET FIRST BYTE OF FIXED PT. Y FILL
	PUSH	PSW		;STORE FIRST BYTE
	CALL	BYTE		;GET SECOND BYTE
	MOV	B,A		;PUT HIGH BYTE IN [B]
	POP	PSW		;GET LOW BYTE
	MOV	C,A		;[BC] NOW CONTAINS FIXED POINT Y COORD.
	LXI	D,MAXY*2	;PASS MAXIMUM RASTER ADDRESS
	CALL	MULT		;MULTIPLY Y COORD BY NO. OF Y RASTERS
	XCHG			;PUT HIGH BYTES IN [HL]
	SHLD	YFILL		;SAVE INTEGER VALUE OF Y FILL LEVEL
;
	CALL	SEGINIT		;INITIALIZE VARIABLES FOR SEG. INTERP.
	CALL	FILINE		;FILL AREA BETWEEN FIRST PT. & YFILL
STRTFIL	CALL	COMPSEG		;COMPUTE NEXT POINT IN SEGMENT
	LHLD	DELTAX		;TOP OF LOOP- END WHEN NI>DX
	XCHG			;DELTAX IS NOW IN (DE)
	LHLD	NI		;GET COUNTER
	MOV	A,D		;COMPARE COUNTER W/DX HI BYTE FIRST
	CMP	H		;COMPARE HI BYTES
	RC			;CARRY INDICATES NI HI BYTE>DX HI BYTE
	JNZ	CHKFIL		;CONTINUE IF NI DEFINITELY < DX
	MOV	A,E		;HIGH BYTES EQUAL- LOOK @ LOW BYTE
	CMP	L		;NOW LOW BYTE
	RC			;NI LOW BYTE>DX LOW BYTE- DONE W/SEGMENT
CHKFIL	LHLD	XDOT		;COMPARE XDOT AND XPOS
	XCHG
	LHLD	XPOS		;XPOS=XDOT=> THIS WILL DUPLICATE FILL
	MOV	A,D
	CMP	H		;ARE HIGH BYTES THE SAME?
	JNZ	LOOPFIL		;GO ON IF HIGH BYTES ARE NOT EQUAL
	MOV	A,E		;HIGH BYTES EQUAL- LOOK AT LOW BYTES
	CMP	L		;ARE THE TWO EXACTLY THE SAME?
	JZ	STRTFIL		;YES- SKIP THIS POSITION
LOOPFIL	CALL	FILINE		;FILL AREA BETWEEN SEGMENT & YFILL
	JMP	STRTFIL		;LOOP BACK TO TOP
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE WILL SEND A STRING OF CHARACTERS TO THE PRINTER
;
;	INPUTS:
;		NUMBER-1 OF CHARACTERS TO SEND IN [DE]
;		ADDRESS-1 OF FIRST CHARACTER IN [HL]
;	OUTPUTS:
;		0 THROUGH [DE] CHARACTERS SENT TO PRINTER
;	REGISTER STATUS:
;		ALL REGISTERS DESTROYED
;	ERROR CONDITIONS:
;		NONE DETECTED BY THIS ROUTINE
;
GBOLOOP	NOP
	IF	OKI
	PUSH	D
	PUSH	H
	MVI	C,05H		;SEND ETX TO START INTO GRAPHIC MODE
	MVI	E,03H
	CALL	PDOS
	POP	H
	POP	D
	ENDIF			;(OKI)
;
KIRKLOP	DCX	D		;DECREMENT COUNTER
	INX	H		;INCREMENT ADDRESS
	PUSH	D		;SAVE COUNTER
	PUSH	H
	MOV	E,M		;GET CHARACTER
;
	IF	OKI		;IF GRAPHIC BYTE IS <ETX>, A SECOND
;<ETX> IS REQUIRED FOR THE OKI PRINTER
	MOV	A,E
	CPI	03H		;IS BYTE <ETX>?
	JNZ	GBOLP1
	PUSH	D		;SAVE BYTE
	MVI	C,05H		;SELECT CP/M LIST FUNCTION
	CALL	PDOS
	MVI	E,03H		;REPLACE <ETX> CHARACTER SENT
	POP	D		;SAVE BYTE
	ENDIF			;(OKI)
;
GBOLP1	MVI	C,05		;SELECT CP/M LIST OUTPUT FUNCTION
	CALL	PDOS		;SEND CHARACTER OUT
	POP	H		;RETRIEVE ADDRESS
	POP	D		;RETRIEVE COUNTER
	MOV	A,E		;IS COUNTER =0?
	ORA	D		;TEST COUNTER
	JNZ	KIRKLOP		;NOT DONE: LOOP BACK
	IF	OKI		;SEND ETX-SO TO CANCEL GRAPHICS MODE
	PUSH	D		;SAVE COUNTER
	PUSH	H		;SAVE ADDRESS
	MVI	C,05H
	MVI	E,03H
	CALL	PDOS
	MVI	C,05H
	MVI	E,02H
	CALL	PDOS
	POP	H		;RETRIEVE ADDRESS
	POP	D		;RETRIEVE COUNTER
	ENDIF			;(OKI)
;
	RET
;
;-----------------------------------------------------------------------
;	THIS ROUTINE SAVES A BYTE FROM BIT MAP IN GRAPHIC BUFFER
;
;	INPUTS:
;		BYTE IN (B)
;		2 BYTE COUNTER @ NGRAPH
;
;	OUTPUTS:
;		NGRAPH INCREMENTED
;		BYTE STORED IN BUFFER @ GBUFF
;		BUFFER FLUSHED IF FULL
;
;	REGISTER STATUS:
;		ALL REGISTERS PRESERVED
;
;	ERROR CONDITIONS:
;		NONE
;
GBUFIN	PUSH	PSW		;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
;
	LHLD	NGRAPH		;GET NO. OF BYTES IN BUFFER
	INX	H		;INCREMENT NGRAPH
	SHLD	NGRAPH		;STORE NEW VALUE
	XCHG			;PUT NGRAPH IN [DE]
;
	LXI	H,GBUFF-1	;GET BUFFER BASE ADDRESS
	DAD	D		;ADD COUNTER TO BASE ADDRESS
	MOV	M,B		;STORE BYTE
;
;
	XCHG			;PUT NGRAPH IN [HL]
	LXI	D,0-(MAXX+1)	;PUT -MAX NO. OF BYTES IN [DE]
	DAD	D		;[HL]=NGRAPH-(MAX NO. OF BYTES)
	MOV	A,H		;IF [HL]=0 THEN BUFFER IS FULL
	ORA	L		;SET FLAGS
	CZ	GBUFOUT
		;BUFFER IS FULL- FLUSH IT TO PRINTER
;
	POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	RET
;
;-----------------------------------------------------------------------
;		THIS SUBROUTINE FLUSHES THE GRAPHIC BUFFER
;
;	INPUTS:
;		GRAPHIC BUFFER @ GBUFF
;		NUMBER OF VALID BYTES IN BUFFER @ NGRAPH
;		"ESC K" SEQUENCE STORED AHEAD OF NGRAPH
;
;	OUTPUTS:
;		PRINTER IS PLACED IN DOT GRAPHIC MODE 
;		GRAPHIC STRING TRANSMITTED BYTE BY BYTE TO PRINTER
;
;	REGISTER STATUS:
;		ALL REGISTERS PRESERVED
;
;	ERROR CONDITIONS:
;		NONE
;
GBUFOUT	PUSH	PSW		;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
;
GBOTOP	LHLD	NGRAPH		;FETCH BUFFER COUNTER
	XCHG			;PUT BUFFER COUNTER IN [DE]
	MOV	A,E		;LOOK AT LOW BYTE
	ORA	D		;IS COUNTER=0?
	JZ	GBUFRET		;IF BUFFER IS EMPTY, DON'T O/P ANYTHING
;
;	SKIP TOTALLY BLANK LINES
;
	LXI	B,MAXX+1	;GET LENGTH OF BUFFER
	MOV	A,B		;COMPARE HIGH BYTES FIRST
	CMP	D
	JNZ	GBO2		;NO MATCH INDICATES SOMETHING ON THIS LINE
	MOV	A,C		;COMPARE LOW BYTES NEXT
	CMP	E
	JNZ	GBO2		;NO MATCH INDICATES SOMETHING ON THIS LINE
;
	LXI	H,GBUFF		;SET POINTER TO START OF BUFFER
GBO1	MOV	A,M		;GET BYTE FROM BUFFER
	ORA	A		;IS IT A BLANK STROKE?
	JNZ	GBO2		;GO TO OUTPUT SECTION IF NOT BLANK
	INX	H		;POINT TO NEW BYTE
	DCX	B		;DECREMENT COUNTER
	MOV	A,B		;CHECK FOR ZERO
	ORA	C
	JNZ	GBO1		;REPEAT UNTIL LAST BYTE HAS BEEN CHECKED
;
	JMP	GBUFRET		;RETURN W/O PLOTTING SINCE ALL WERE BLANK
;
GBO2	NOP			;HEAD OF OUTPUT SECTION
;
	IF	NO8BIT
	MOV	A,E		;LOOK AT LOW BYTE OF COUNTER
	ORA	A		;SET FLAGS- IS HIGH BIT SET?
	JP	GBO7		;LOW BYTE HAS 7 BITS-O/P WHOLE THING.
;
;	THE PARALLEL INTERFACE WILL ONLY TRANSMIT 7 BITS.  THE LOW BYTE
;	OF THE BUFFER COUNTER HAS ITS HIGH BIT SET, THEREFORE, THE 
;	BUFFER MUST BE OUTPUT IN SMALLER CHUNKS
;
	PUSH	D		;SAVE NGRAPH ON STACK
	ENDIF			;(NO8BIT)
	IF	EPSON AND NO8BIT
	LXI	D,126+4		;COUNTER=>126 BYTES + 4 FOR ESCK,NGRAPH
	LXI	H,126D		;SET NGRAPH TO 126
	SHLD	NGRAPH		;PUT NEW NO. IN PRINTER SEQUENCE
	LXI	H,ESCK-1	;START WITH ESCAPE SEQUENCE
	ENDIF			;(EPSON AND NO8BIT)
;
	IF	CITOH AND NO8BIT
	LXI	D,126+6		;COUNTER=>126 BYTES + 6 FOR ESC S N3210
	LXI	H,ESCK+3	;ADDRESS OF N1 BYTE
	LXI	B,126D		;SET NO. OF BYTES
	MOV	M,B		;STORE HIGH BYTE IN N1
	INX	H		;ADDRESS OF N0
	MOV	M,C		;STORE LOW BYTE IN N0
	LXI	H,ESCK-1	;START WITH ESCAPE SEQUENCE
	ENDIF			;(CITOH AND NO8BIT)
;
	IF	NO8BIT
	CALL	GBOLOOP		;SEND OUT FIRST 126 CHARACTERS
;
;	MOVE CHARACTERS IN BUFFER UP TO REPLACE THOSE SENT OUT
;
	POP	H		;RETRIEVE OLD VALUE OF NGRAPH
	LXI	D,0FF82H	;[DE]=-126D
	DAD	D		;[HL]NOW=NGRAPH-126
	SHLD	NGRAPH		;STORE NEW VALUE
	XCHG			;PUT NGRAPH IN [DE] TO ACT AS COUNTER
	LXI	H,GBUFF-1		;GET BASE ADDRESS OF BUFFER
	PUSH	H		;SAVE POINTER FOR SAVING DATA
	LXI	B,007EH		;PUT 126D IN [BC]
	DAD	B		;[HL] NOW POINTS TO NEW BYTES
;
GBOMOV	INX	H		;INCRMENT NEW DATA POINTER
	MOV	A,M		;GET BYTE FROM BUFFER
	XTHL			;EXCHANGE POINTERS
	INX	H		;INCREMENT SAVE DATA POINTER
	MOV	M,A		;MOVE BYTE UP IN BUFFER
	XTHL			;EXCHANGE POINTERS BACK AGAIN
	DCX	D		;DECREMENT COUNTER
	MOV	A,E		;CHECK TO SEE IF LOOP IS DONE
	ORA	D		;IS [DE]=0?
	JNZ	GBOMOV		;LOOP BACK UP IF NOT DONE
	POP	H		;RETRIEVE POINTER TO CLEAN UP STACK
;
;	NGRAPH HAS NOW BEEN UPDATED AND DATA IN BUFFER HAS BEEN MOVED
;	TO REPLACE THAT WHICH HAS BEEN SENT OUT.  NOW READY TO TRY ALL
;	OVER AGAIN WITH NEW SEGMENT OF DATA IN BUFFER.
;
	JMP	GBOTOP
	ENDIF			;(NO8BIT)
;
	IF	EPSON
GBO7	INX	D
	INX	D
	INX	D
	INX	D
	LXI	H,ESCK-1	;START WITH ESCAPE SEQUENCE
	ENDIF			;(EPSON)
;
	IF	CITOH
GBO7	LXI	H,ESCK+2	;ADDRESS OF N3 BYTE FOR GRAPHICS SELECT
	MVI	A,30H		;INITIALIZE NUMBER OF BYES TO "0000"
	MOV	M,A		;"0"
	INX	H
	MOV	M,A		;"00"
	INX	H
	MOV	M,A		;"000"
	INX	H
	MOV	M,A		;"0000"
;
	CALL BINDEC		;CONVERT N TO ASCII DECIMAL AND STORE
;
	INX	D		;INCREMENT COUNTER FOR ESC S N3-N0
	INX	D
	INX	D
	INX	D
	INX	D
	INX	D
	LXI	H,ESCK-1	;START WITH ESCAPE SEQUENCE
	ENDIF			;(CITOH)
;
	IF	OKI
GBO7	LXI	H,GBUFF-1
	ENDIF			;(OKI)
;
	CALL	GBOLOOP		;SEND OUT STRING OF GRAPHIC CHARACTERS
;
GBUFRET	MVI	A,00H		;CLEAR ACCUMULATOR
	STA	NGRAPH		;SET NGRAPH=0
	STA	NGRAPH+1
POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	RET
;
;-----------------------------------------------------------------------
;	THIS SUBROUTINE PLOTS AN INCREMENTAL LINE SEGMENT FROM THE
;	PRESENT POSITION
;	INPUTS:
;		FILE BUFFER @ DMA
;		PRESENT POSITION @ XPOS,YPOS
;	OUTPUTS:
;		XPOS, YPOS UPDATED TO X,Y
;		VISIBLE PORTION OF LINE SEGMENT DRAWN
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE PECULIAR TO THIS ROUTINE
;
INCPLT	CALL	READXY			;GET END POINT VALUES
	CALL	SEGINIT		;INITIALIZE SEGMENT INTERPOLATION SUB.
;
STRTPLT	LHLD	DELTAX		;TOP OF LOOP- END WHEN NI>DX
	XCHG			;DELTAX IS NOW IN (DE)
	LHLD	NI		;GET COUNTER
	MOV	A,D		;COMPARE COUNTER W/DX HI BYTE FIRST
	CMP	H		;COMPARE HI BYTES
	RC			;CARRY INDICATES NI HI BYTE>DX HI BYTE
	JNZ	CONTPLT		;CONTINUE IF NI DEFINITELY < DX
	MOV	A,E		;HIGH BYTES EQUAL- LOOK @ LOW BYTE
	CMP	L		;NOW LOW BYTE
	RC			;NI LOW BYTE>DX LOW BYTE- DONE W/SEGMENT
CONTPLT	CALL	COMPSEG		;COMPUTE XPOS AND YPOS AT NEXT POINT
	LHLD	XPOS		;FETCH X POSITION
	SHLD	XDOT		;PASS IN XDOT
	LHLD	YPOS		;FETCH Y POSITION
	SHLD	YDOT		;PASS IN YDOT
	CALL	PLOTDOT		;PLOT IT (FINALLY)
	JMP	STRTPLT		;BOUNCE UP TO THE TOP OF THE LOOP
;
;-----------------------------------------------------------------------
;			LINE SPACING SUBROUTINE
;
;	INPUTS:
;		NONE
;	OUTPUTS:
;		FORM FEED SENT
;		ESC A 7  SENT TO SET THE PRINTER TO 7/72" LINE SPACING
;	REGISTER STATUS:
;		ALL VALUES CHANGED
;	ERROR CONDITIONS:
;		NONE
;
	IF	EPSON
LN772	MVI	C,05H		;SELECT LIST OUTPUT
;	MVI	E,0CH		;PASS FORMFEED
;	CALL	PDOS		;SEND IT OUT
;
;	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,1BH		;PASS ESC CHARACTER
	CALL	PDOS		;SEND IT OUT
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,'A'		;PASS "A"
	CALL	PDOS		;SEND IT OUT
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,07H		;PASS 7 FOR 7/72"
	CALL	PDOS
;
	RET
	ENDIF			;(EPSON)
;
	IF	CITOH
LN772	MVI	C,05H		;SELECT LIST OUTPUT
;	MVI	E,0CH		;PASS FORMFEED
;	CALL	PDOS		;SEND IT OUT
;
;	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,1BH		;PASS ESC CHARACTER
	CALL	PDOS		;SEND IT OUT
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,'>'		;ESC >  SETS UNIDIRECTIONAL PRINTING
	CALL	PDOS		;SEND IT OUT
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,1BH		;PASS ESC CHARACTER
	CALL	PDOS		;SEND IT OUT
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,'T'		;PASS "T"
	CALL	PDOS		;SEND IT OUT
;
	MVI	C,05H
	MVI	E,'1'
	CALL	PDOS		;SEND OUT 1 AS HIGH BYTE
;
	MVI	C,05H		;SELECT LIST OUTPUT
	MVI	E,'4'		;PASS 14 FOR 14/144"
	CALL	PDOS
;
	RET
	ENDIF			;(CITOH)
;
	IF	OKI
LN772	MVI	C,05H
	MVI	E,18H		;CLEAR PRINTER
	CALL	PDOS
	MVI	C,05H
	MVI	E,1CH		;SET 12 CPI
	CALL	PDOS
	MVI	C,05H
	MVI	E,1BH		;ESC % "9" 14 TO SET LINE SPACING
	CALL	PDOS
	MVI	C,05H
	MVI	E,25H
	CALL	PDOS
	MVI	C,05H
	MVI	E,39H
	CALL	PDOS
	MVI	C,05H
	MVI	E,14D		;14/144 "/LINE
	CALL	PDOS
	RET
	ENDIF			;(OKI)
;
;-----------------------------------------------------------------------
;	THIS SUBROUTINE CALCULATES THE ADDRESS FOR AN XY COORDINATE PAIR
;	XYADDR= ORIGIN + XCOORD + (MAXY-YCOORD)/7 * (MAXX+1)
;	INPUTS:
;		XCOORDINATE IN REGISTERS BC
;		YCOORDINATE IN REGISTERS DE
;		MAXIMUM Y RASTER COUNT IN HL
;	OUTPUTS:
;		XCOORDINATE IN REGISTERS BC
;		YCOORDINATE IN REGISTERS DE
;		ADDRESS OF X,Y COORDINATES IN HL
;		ADDRESS STORED @ XYADDR
;	REGISTER STATUS:
;		PSW VALUES CHANGED
;	ERROR CONDITIONS:
;		OVERFLOW OF ARITHMETIC CALLS WOOPS
;
LOCDOT	PUSH	D		;STORE Y COORD ON STACK
	PUSH	B		;STORE X COORD ON STACK
	MOV	A,L
	SUB	E		;SUBTRACT YCOORD FROM MAXY
	MOV	L,A
	MOV	A,H
	SBB	D
	MOV	H,A		;[HL] NOW CONTAINS (MAXY - Y)
	SHLD	DIVDND		;PASS (MAXY - Y) TO DIVISION ROUTINE
	MVI	A,07H		;PASS 7 TO DIVISION ROUTINE
	STA	DIVSOR
	CALL	DIVIDE		;(MAXY - Y)/7
	LDA	RMANDR		;RMANDR IS NEGATIVE IF OVERFLOW
	ORA	A		;SET FLAGS
	CM	WOOPS		;OVERFLOW IN DIVISION
	LDA	QOTENT		;GET RESULT OF DIVISION
	LXI	B,MAXX+1	;[BC] NOW CONTAINS THE MAX. NO. OF X'S
	CALL 	BMULT		;[HL] HAS LOW ORDER BYTES, [A] THE HIGH
;			[HL] NOW CONTAINS (MAX-YCOORD)/7*(MAX+1)
	POP	B			;PUT XCOORD IN [BC]
	DAD	B			;ADD TO X PREVIOUS TERM
	LXI	D,ORIGIN		;LAST TERM
	DAD	D			;FINAL SUM IS IN [HL]
	SHLD	XYADDR			;STORE RESULT
	POP	D		;RETRIEVE Y COORDINATE
	RET
;
;-----------------------------------------------------------------------
;	OUTPUT ROUTINE
;
;	INPUTS:
;		MEMORY MAP STARTING @ ORIGIN
;
;	OUTPUTS:
;		MAP IS DUMPED TO PRINTER 1 BYTE AT A TIME
;		MIXED GRAPHICS AND TEXT ARE OUTPUT
;
;	REGISTER STATUS:
;		ALL VALUES DESTROYED
;
;	ERROR CONDITIONS:
;		NONE. PRINTER WILL HANG IF IT DOESN'T GET PROPER INPUT
;
MAPOUT	MVI	A,00H		;RESET STATUS COUNTER
	STA	STATNO
	MVI	C,09H		;PRINT PRINTING STATUS MESSAGE
	LXI	D,STAT3		
	CALL	FDOS
;
	CALL	LN772		;SET PRINTER TO 7/72" LINE SPACING
	LXI	H,ORIGIN	;INITIAIZE START ADDRESS
	MVI	A,00H		;CLEAR ACCUMULATOR
	STA	NGRAPH		;INITIALIZE GRAPHICS COUNTER
	STA	NGRAPH+1
	MVI	C,(MAXY+1)/7	;INITIALIZE LINE COUNTER
LINLOOP	LXI	D,MAXX+1	;INITIALIZE DOT COUNTER
;
BYTLOOP	MOV	B,M		;GET BYTE
	MOV	A,B		;PUT BYTE IN (A)
	ORA	A		;SET FLAGS - IS IT A GRAPHIC BYTE?
	CM	CHAROUT		;NO- HI BIT SET THEREFORE CHARACTER
	CP	GBUFIN		;YES- SAVE IT IN GRAPHIC BUFFER
;
	INX	H		;INCREMENT ADDRESS TO NEXT X LOCATION
	DCX	D		;DECREMENT DOT COUNTER
	MOV	A,D
	ORA	E		;IS DOT COUNTER = 0?
	JNZ	BYTLOOP		;NO- SO LOOP TO TOP AGAIN
;
	CALL	GBUFOUT		;AT END OF LINE- FLUSH BUFFER
	CALL	CRLF		;SEND A LINE FEED TO PRINTER
	DCR	C		;DECREMENT LINE COUNTER
	MOV	A,C		;GET READY TO TEST LINE COUNTER
	ORA	A		;SET FLAGS ON LINE COUNTER
	JNZ	LINLOOP		;NOT DONE- REPEAT OUTER LOOP
;
	CALL	PRESET		;RESET PRINTER TO NORMAL MODE
;
	RET			;LAST LINE FINISHED
;
;-----------------------------------------------------------------------
;	THIS SUBROUTINE MOVES THE PRESENT POSITION TO NEW COORDINATES
;	WITHOUT DOING ANYTHING ELSE
;
;	INPUTS:
;		COORDINATE PAIR IN BUFFER
;	OUTPUTS:
;		XPOS AND YPOS UPDATED TO NEW COORDINATES
;	REGISTER STATUS:
;		ALL VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE PECULIAR TO THIS ROUTINE
;
MOVE	CALL	READXY		;GET COORDINATE PAIR
	LHLD	X		;GET X COORDINATE
	SHLD	XPOS		;UPDATE X AXIS POSITION
	LHLD	Y		;GET Y COORDINATE
	SHLD	YPOS		;UPDATE	Y AXIS POSITION
	RET			;POSITION NOW UPDATED.
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE MULTIPLIES TWO 16 BIT INTEGERS
;
;	THIS ROUTINE FROM ELECTRONICS MAGAZINE, FEB. 24, 1982.
;	WRITTEN BY JERRY L. GOODRICH, PENN. STATE U.
;
;
;	INPUTS:
;		MULTIPLICAND IN [BC]
;		MULTIPLIER IN [DE]
;	OUTPUTS:
;		32 BIT PRODUCT IN [DE],[HL] (MOST SIG. BITS IN [DE])
;	REGISTER STATUS:
;		SEE INPUTS AND OUTPUTS
;	ERROR CONDITIONS:
;		NONE
;
MULT	MOV	A,E		;LOAD LOWEST ORDER BYTE OF MULTIPLIER
	PUSH	D		;SAVE HIGHEST ORDER BYTE OF MULTIPLIER
	CALL	BMULT		;DO 1-BYTE MULTIPLY
	XTHL		;SAVE LOWEST ORDER BYTES PRODUCT, GET MULTIPLIER
	PUSH	PSW		;STORE HIGHEST ORDER BYTE OF FIRST PROD.
	MOV	A,H		;LOAD HIGHEST ORDER BYTE OF MULTIPLIER
	CALL	BMULT		;DO SECOND 1-BYTE MULTIPLY
	MOV	D,A		;POSITION HIGHEST-ORDER BYTE OF PRODUCT
	POP	PSW		;GET HIGHEST ORDER BYTE OF FIRST PRODUCT
	ADD	H		;UPDATE THIRD BYTE OF PRODUCT
	MOV	E,A		;AND PUT IT IN E
	JNC	NC1		;DONT'T INCREMENT D IF NO CARRY
	INR	D		;INCREMENT D IF CARRY
NC1:	MOV	H,L		;RELOCATE LOWEST ORDER BYTES OF 2ND PROD
	MVI	L,0
	POP	B		;GET LOWEST ORDER 2 BYTES OF FIRST PROD.
	DAD	B		;GET FINAL PRODUCT LOWEST ORDER 2 BYTES
	RNC			;DONE IF NO CARRY
	INX	D		;OTHERWISE UPDATE HIGHEST ORDER 2 BYTES
	RET
;
;-----------------------------------------------------------------------
;	PRINT OR DISK O/P SUBROUTINE
;
;	INPUTS:
;		05H IN (C)
;		CHARACTER IN (E)
;		BUFFER POINTER SET TO LAST CHARACTER (POINTR2)
;		O/P FLAG IN OPDISK
;	OUTPUTS:
;		CHARACTER PRINTED IF O/P FLAG SET
;		CHARACTER WRITTEN TO DISK IF FLAG IS SET
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE IN THIS ROUTINE.
;
PDOS	LDA	OPDISK			;GET DISK O/P FLAG
	CPI	00H			;IS FLAG SET?
	PUSH	PSW			;SAVE FLAG
	CZ	FDOS			;PRINT CHARACTER IF IT IS
	POP	PSW			;RETRIEVE FLAGS
	RZ				;RETURN IF CHARACTER WAS PRINTED
;
	LDA	POINTR2			;GET BUFFER POINTER
	INR	A			;INCREMENT POINTER FOR NEW CHAR.
	STA	POINTR2			;SAVE NEW VALUE
	MOV	C,A			;SAVE POINTER VALUE IN (C)
	MVI	B,0			;CLEAR HIGH BYTE OF (BC)
	LXI	H,DMA2-1		;GET LAST ADDR. BEFORE DMA2
	DAD	B			;CALCULATE ADDRESS OF BYTE
	MOV	M,E			;PUT CHARACTER IN BUFFER
	CPI	128D			;IS BUFFER FULL?
	CZ	WRITE			;WRITE IT OUT IF IT IS.
	RET				;DONE
;
;-----------------------------------------------------------------------
;	THIS SUBROUTINE PLOTS A POINT @ XDOT,YDOT
;	METHOD:
;		FIND BYTE CONTAINING XDOT,YDOT
;		FORM MASK EG: IF XDOT,YDOT IS IN #4 BIT,
;		MASK = 00010000
;		DIGIT= 76543210
;		MODIFY BYTE ACCORDING TO COLOR & STORE IT BACK
;	INPUTS:
;		2 BYTE X LOCATION STORED @ XDOT
;		2 BYTE Y LOCATION STORED @ YDOT
;	OUTPUTS:
;		XPOS, YPOS RESET TO VALUES GIVEN IN XDOT, YDOT
;		APPROPRIATE DOT TURNED ON OR OFF IN MEMORY MAP
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		IF XDOT OR YDOT ARE OUTSIDE OF WINDOW, NO POINT PLOTTED
;		XPOS AND YPOS WILL STILL POINT OUTSIDE WINDOW
;
PLOTDOT	LHLD	XDOT			;GET X POSITION
	SHLD	XPOS			;UPDATE CURRENT POSITION
	MOV	B,H			;MOVING XDOT TO BC
	MOV	C,L			;XDOT NOW IN BC
	LHLD	YDOT			;GET Y POSITION
	SHLD	YPOS			;UPDATE CURRENT POSITION
	MOV	D,H			;MOVING YDOT TO DE
	MOV	E,L			;YDOT NOW IN DE
;XPOS AND YPOS NOW CONTAIN LAST POS. ATTEMPTED- MAY NOT BE IN WINDOW
	LXI	H,MAXX		;PUT LIMITS OF X IN HL
XCHECK	MOV 	A,B				;CHECK FOR NEG X-SIGN IN HI BYTE
	ORA	A			;IS XDOT NEGATIVE?
	RM				;XDOT NEG- RETURN W/O PLOTTING
	MOV	A,H			;WORK WITH HIGH BYTE FIRST
	CMP	B			;COMPARE MAX & X HIGH BYTES
	RC				;X>MAX- THEREFORE RETURN
	JNZ	YCHECK			;X IS OK- CHECK Y
	MOV	A,L			;HIGH BYTES ARE= LOOK @ LOW BYTE
	CMP	C			;COMPARE X & MAX LOW BYTES
	RC				;X>MAX- RETURN W/O PLOTTING
YCHECK	LXI	H,MAXY		;PUT LIMIT OF Y IN HL
	MOV	A,D			;YDOT HI BYTE CONTAINS SIGN
	ORA	A			;IS YDOT NEGATIVE?
	RM				;YDOT NEG- RETURN W/O PLOTTING
	MOV	A,H			;HIGH BYTES FIRST
	CMP	D			;COMPARE MAX & Y HIGH BYTES
	RC				;Y>MAX- RETURN W/O PLOTTING
	JNZ	XYOK			;Y IS OK- PLOT DOT
	MOV	A,L			;HIGH BYTES= LOOK @ LOW BYTES
	CMP	E			;COMPARE LOW BYTES
	RC				;Y IS > MAX- RETURN W/O PLOTTING
XYOK	CALL	LOCDOT			;GET ADDRESS OF BYTE FOR X,YDOT
	CALL	DIGIT			;FORM MASK FOR PLOTTING
	MOV	A,B		;DETERMINE IF BYTE IS GRAPHIC
	ORA	A		;GRAPHIC?
	RM			;MINUS= CHARACTER: RETURN W/O PLOTTING
	LDA	COLOR			;GET COLOR VALUE
	ORA	A			;SET FLAGS
	JZ	WHITE			;0 = WHITE
	JM	COMPL			;-1 = COMPLEMENTARY COLOR
	MOV	A,B			;COLOR IS BLACK
	ORA	C			;MODIFY BYTE BY TURNING BIT ON
	MOV	M,A			;STORE BACK IN MEMORY
	RET				;DONE- ( AT LAST)
;
WHITE	MOV	A,B			;WORK W/ BYTE CONTAINING X,Y
	CMA				;COMPLEMENT BYTE
	ORA	C			;MODIFY BYTE BY TURNING ON BIT
	CMA				;COMPLEMENT BYTE BACK- BIT 0FF
	MOV	M,A			;STORE BYTE BACK IN MEMORY
	RET				;DONE- (FINALY)
;
COMPL	MOV	A,B			;WORK W/ BYTE CONTAINING X,Y
	XRA	C			;COMPLEMENT BIT
	MOV	M,A			;STORE IT
	RET				;DONE-
;
;-----------------------------------------------------------------------
;		PLOT POINT ROUTINE
;
;	INPUTS:
;		BUFFER @ DMA
;	OUTPUTS:
;		POINT PLOTTED IN MEMORY
;	REGISTER STATUS:
;		ALL VALUES CHANGED
;	ERROR CONDITIONS:
;		NONE
;
POINT	CALL	READXY		;READ COORDINATES FOR POINT
	LHLD	X		;FETCH X LOCATION
	SHLD	XDOT		;PASS X TO DOT ROUTINE
	LHLD	Y		;FETCH Y LOCATION
	SHLD	YDOT		;PSSS Y TO DOT ROUTINE
	CALL	PLOTDOT
	RET
;
;-----------------------------------------------------------------------
;			QUIT
;	CLOSES OUTPUT FILE, TERMINATES PROGRAM
;	INPUTS:
;		FCB FOR OUTPUT FILE @ FCB2
;		DISK OUTPUT FLAG @ OPDISK
;	OUTPUTS:
;		REMAINDER OF RECORD SET TO 0, DISK CLOSED.
;	REGISTER STATUS:
;		ALL VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE
;
QUIT:	LDA	OPDISK			;GET DISK OUTPUT FLAG
	CPI	00H			;IS IT SET?
	JZ	BOOT			;NO, SO ALL DONE
;
	LDA	POINTR2			;LOOK @ O/P POINTER
	CPI	0			;IS O/P BUFFER EMPTY?
	JZ	BOOT			;YES- DONE
;
;	FILL REMAINDER OF O/P BUFFER WITH NULLS
;
	MOV	E,A			;SAVE POINTER VALUE IN (E)
	MVI	D,00H			;CLEAR HIGH BYTE OF (DE)
	MVI	A,128			;SET MAX VALUE OF POINTER
	SUB	E			;(A)= 128- POINTR2
	MOV	C,A			;(C) NOW IS COUNT OF EXTRA BUFF.
;
CLRBUF	PUSH	B			;SAVE COUNTER
	MVI	E,00H			;PASS A <NULL>
	CALL	PDOS			;PUT IT IN BUFFER
	POP	B			;RETRIEVE COUNTER
	DCR	C			;COUNTER=COUNTER-1
	JNZ	CLRBUF			;LOOP BACK UNTIL BUFFER IS FULL
;
	MVI	C,10H			;SELECT CLOSE FILE FUNCTION
	LXI	D,FCB2			;PASS O/P FCB
	CALL	FDOS			;CLOSE FILE
;
	JMP	BOOT			;DO WARM BOOT ON EXIT
;
;-----------------------------------------------------------------------
;			LINE SEGMENT ROUTINE
;	INPUTS:	FILE BUFFER @ DMA
;
;	OUTPUTS:
;		XPOS, YPOS UPDATED TO X2,Y2
;		VISIBLE PORTION OF LINE SEGMENT PLOTTED
;
;	REGISTERS:
;		ALL REGISTERS VALUES DESTROYED
;	ERROR CONDITIONS:
;		NO CHECKS MADE IN THIS ROUTINE
;
PLOTSEG	CALL	READXY		;GET STARTING COORDINATES
	LHLD	X		;FETCH STARTING X
	SHLD	XDOT		;PASS TO DOT ROUTINE
	LHLD	Y		;FETCH STARTING Y
	SHLD	YDOT		;PASS TO DOT ROUTINE
	CALL	PLOTDOT		;PLOT STARTING POINT
	CALL	INCPLT		;PLOT REST OF SEGMENT
	RET			;RETURN TO MAIN PROGRAM
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE RESETS THE PRINTER TO ITS NORMAL MODE 
;
;	INPUTS:
;		NONE
;	OUTPUTS:
;		NONE RETURNED
;	REGISTER STATUS:
;		ALL REGISTERS CHANGED
;	ERROR CONDITIONS:
;		NONE
;
	IF	EPSON
PRESET:	MVI	C,05H
	MVI	E,1BH		;PASS ESC CHARACTER
	CALL	PDOS		;SEND ESC
	MVI	C,05H
	MVI	E,'2'
	CALL	PDOS		;ESC 2 SETS LINE SPACING TO 6 LINES/IN.
	MVI	C,05H
	MVI	E,CR		;SEND CARRIAGE RETURN TO RESET HEAD
	CALL	PDOS
	RET
	ENDIF			;(EPSON)
;
	IF	CITOH
PRESET:	MVI	C,05H
	MVI	E,1BH		;SEND ESC
	CALL	PDOS
	MVI	C,05H
	MVI	E,'A'		;ESC A SETS LINE SPACING TO 6 LINES/IN.
	CALL	PDOS
	MVI	E,CR
	MVI	C,05H
	CALL	PDOS		;SEND CARRIAGE RETURN TO RESET HEAD
	RET
	ENDIF			;(CITOH)
;
	IF	OKI
PRESET:	MVI	C,05H
	MVI	E,1BH		;ESC % "9" 24 TO SET LINE SPACING
	CALL	PDOS
	MVI	C,05H
	MVI	E,25H		; "%"
	CALL	PDOS
	MVI	C,05H
	MVI	E,39H		; "9"
	CALL	PDOS
	MVI	C,05H
	MVI	E,24D		;RESET TO NORMAL LINE SPACING
	CALL	PDOS
	RET
;
	ENDIF			;(OKI)
;
;-----------------------------------------------------------------------
;	READ RECORD SUBROUTINE
;	INPUTS:
;		OPENED FILE
;		FILE CONTROL BLOCK @ FCB
;		128 CHAR FILE BUFFER @ DMA
;		1 BYTE CHARACTER POINTER @ POINTER
;	OUTPUTS:
;		CHARACTER POINTER RESET TO 0
;		NEW RECORD IN FILE BUFFER
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		EOF: JUMP TO EOFEXIT INSTEAD OF NORMAL RETURN
;
READ	MVI	C,26D			;SELECT SET DMA FUNCTION
	LXI	D,DMA			;PASS BUFFER ADDRESS
	CALL	FDOS			;SET DMA ADDRESS TO I/P BUFFER
;
	MVI	C,14H			;SELECT SEQUENTIAL READ FUNCTION
	LXI	D,FCB			;PASS FCB
	CALL	FDOS			;READ RECORD INTO BUFFER @ DMA
	CPI	00H			;READ OK?
	JZ	SETPNTR			;RESET POINTER IF NOT EOF
	POP	B			;POP RETURN ADDR OFF STACK
	JMP	EOFEXIT			;GOTO EXIT INSTEAD OF NORMAL RTN
SETPNTR	MVI	A,0			;CLEAR ACCUM.
	STA	POINTER			;RESET POINTER TO 0
	RET				;RETURN-NEW RECORD & POINTER POS
;
EOFEXIT	MVI	C,09H		;SELECT PRINT STRING FUNCTION
	LXI	D,EOFMSG		;PASS MESSAGE
	CALL	FDOS		;PRINT EOF MESSAGE
	JMP	BOOT		;RETURN TO CP/M COMMAND LEVEL
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE GETS AN XY PAIR
;AND CONVERTS IT TO RASTER VALUES.  THE GENERAL ALGORITHM IS:
;
;	INTEGER = (FIXED POINT) * (NUMBER OF RASTERS) * 2/ 2^16
; 
; THE FIXED POINT NUMBER IS A 15 BIT VALUE IN THE RANGE 0 TO 1.  
; WHEN VIEWED AS AN INTEGER, THE FIXED POINT COORDINATES RANGE FROM
; 0 TO 32767.  WHEN MULTIPLIED BY THE RANGE OF THE RASTER COORDINATES,
; THEY MUST BE DIVIDED BY 32767 TO REPRESENT THE TRUE VALUE.  THIS IS 
; APPROXIMATED BY MULTIPLYING BY 2 / 65536   (2/64K).  DIVIDING BY 64K
; IS ACCOMPLISHED BY SIMPLY DISREGARDING THE LOWER 2 BYTES OF THE RESULT
;
;	INPUTS:
;		128 CHARACTER BUFFER @ DMA
;		CHARACTER POINTER @ POINTER
;	OUTPUTS:
;		TWO BYTE VALUE STORED @ X
;		TWO BYTE VALUE STORED @ Y
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE- BYTE WILL TERMINATE PROGRAM ON EOF IF NECESSARY
;
READXY	CALL	BYTE			;GET FIRST BYTE OF X
	PUSH	PSW		;STORE FIRST BYTE
	CALL	BYTE		;GET SECOND BYTE
	MOV	B,A		;PUT HIGH BYTE IN [B]
	POP	PSW		;GET LOW BYTE
	MOV	C,A		;[BC] NOW CONTAINS FIXED POINT X COORD.
	LXI	D,MAXX*2	;PASS MAXIMUM RASTER ADDRESS
	CALL	MULT		;MULTIPLY X COORD BY NO. OF X RASTERS
	XCHG			;PUT HIGH BYTES IN [HL]
	SHLD	X		;STORE CORRESPONDING RASTER X COORDINATE
;
	CALL BYTE		;GET FIRST BYTE OF Y
	PUSH	PSW		;STORE FIRST BYTE
	CALL	BYTE		;GET SECOND BYTE
	MOV	B,A		;PUT HIGH BYTE IN [B]
	POP	PSW		;GET LOW BYTE
	MOV	C,A		;[BC] NOW CONTAINS FIXED POINT Y COORD.
	LXI	D,MAXY*2	;PASS MAXIMUM RASTER ADDRESS
	CALL	MULT		;MULTIPLY Y COORD BY NO. OF Y RASTERS
	XCHG			;PUT HIGH BYTES IN [HL]
	SHLD	Y		;STORE CORRESPONDING RASTER Y COORDINATE
	RET
;
;---------------------------------------
;
;	THIS SUBROUTINE ROTATES THE PATTERNS USED FOR ERASING TO A COLOR
;
;	INPUTS:
;		ARRAY OF 8 PATTERN BYTES STORED AT PATRN
;	OUTPUTS:
;		ARRAY IS ROTATED ONE BIT DOWN
;	REGISTER STATUS:
;		[BC],[HL] PRESERVED, ALL OTHERS DESTROYED
;	ERROR CONDITIONS:
;		NONE
;
ROTPAT:	PUSH	B		;SAVE COUNTER IN [BC]
	PUSH	H		;SAVE POINTER IN [HL]
	MVI	B,8D		;INITIALIZE COUNTER
	LXI	H,PATRN		;INITIALIZE ADDRESS OF HEAD OF ARRAY
ROTPT1:	MOV	A,M		;GET BYTE
	IF	MSBTOP
	RRC			;ROTATE BYTE
	ENDIF			;( MSBTOP )
	IF	NOT MSBTOP
	RLC
	ENDIF			;( NOT MSBTOP )
	MOV	M,A		;STORE ROTATED BYTE
;
	INX	H		;MOVE POINTER TO NEXT BYTE
	DCR	B		;DECREMENT COUNTER
	JNZ	ROTPT1		;LOOP BACK UNTIL DONE
	POP	H		;RETRIEVE SAVED REGISTERS
	POP	B
	RET
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE INITIALIZES THE VARIABLES USED IN COMPUTING A 
;	LINE SEGMENT
;
;	INPUTS:
;		XPOS,YPOS	PRESENT POSITION
;		X,Y		END POINTS OF SEGMENT
;	OUTPUTS:
;		DX,DY	X,Y SIZES OF LINE SEGMENT
;		EPSLNX,EPSLNY,SX,SY,DELTA3	INTERNAL VARIABLES 
;						INITIALIZED
;		NI	COUNTER USED TO DETERMINE WHEN DONE
;	REGISTER SATUS:
;		ALL REGISTER VALUES DESTROYED.
;	ERROR CONDITIONS:
;		NONE
;
SEGINIT	LHLD	X			;GET X
	XCHG				;PUT X IN DE
	LHLD	XPOS			;PUT PRESENT POS IN HL
	MOV	A,E			;CALCULATE DELTA X
	SUB	L
	MOV	C,A
	MOV	A,D
	SBB	H
	MOV	B,A			;BC NOW CONTAINS DELTA X (DX)
	LHLD	Y			;GET Y END POINT VALUE
	XCHG				;PUT Y IN DE
	LHLD	YPOS			;GET PRESENT Y POSITION
	MOV	A,E			;CALCULATE DELTA Y (DY)
	SUB	L
	MOV	E,A
	MOV	A,D
	SBB	H
	MOV	D,A			;DE NOW CONTAINS DY
	XCHG				;PUT DY IN HL, YPOS IN DE
	SHLD	DELTAY			;STORE DY
	MOV	H,B
	MOV	L,C
;
	SHLD	DELTAX			;STORE DELTA X
	LXI	H,0000H			;INITIALIZE VARIABLES
	SHLD	SX
	SHLD	EPSLNY
	LXI	H,0001H
	SHLD	SY
	SHLD	EPSLNX
	LDA	DELTAX+1		;GET DX HIGH BYTE
	ORA	A		;SET FLAGS ACCORDING TO DX HI BYTE
	JP	CHKDY
	LXI	H,0FFFFH		;CHANGE INITIALIZATION FOR -DX
	SHLD	EPSLNX
	LHLD	DELTAX			;CHANGE SIGN ON DX
	MOV	A,H
	CMA				;COMPLEMENT HIGH BYTE
	MOV	H,A
	MOV	A,L
	CMA				;COMPLEMENT LOW BYTE
	ADI	01H			;ADD 1 TO MAKE IT TWO'S COMP.
	MOV	L,A
	MOV	A,H
	ACI	00H			;ADD CARRY TO HIGH BYTE
	MOV	H,A
	SHLD	DELTAX			;STORE NOW POSITIVE DX
CHKDY	LDA	DELTAY+1		;GET DY HIGH BYTE- CONTAINS SIGN
	ORA	A		;SET FLAGS ON DY HI BYTE
	JP	CHDXDY			;DY IS POS- GOTO TRANSPOSE AXES
	LHLD	DELTAY			;DY IS NEGATIVE- CHANGE SIGN
	MOV	A,H
	CMA				;COMPLEMENT HI BYTE
	MOV	H,A
	MOV	A,L
	CMA
	ADI	01H			;COMPLEMENT AND ADD 1
	MOV	L,A
	MOV	A,H
	ACI	00H			;ADD CARRY FROM LOW BYTE
	MOV	H,A
	SHLD	DELTAY			;STORE THE NOW POS. DY
	LXI	H,0FFFFH		;LOAD -1 IN (HL)
	SHLD	SY			;SY= -1
CHDXDY	LHLD	DELTAX			;TRANSPOSE AXES IF DX<DY
	XCHG				;PUT DX IN DE
	LHLD	DELTAY		;GET DELTA Y
	MOV	A,D			;PUT HIGH BYTE OF DX IN A
	CMP	H			;DX < DY ? (HIGH BYTES FIRST)
	JC	TNSPOS			;DX DEFINITELY < DY
	JNZ	LSTINIT			; DX DEFINITELY > DY
	MOV	A,E			;HIGH BYTES =, CHECK LOW BYTES
	CMP	L
	JNC	LSTINIT			;IF NO CARRY, DX>= DY- START PLOTTING
TNSPOS	SHLD	DELTAX			;DY WAS IN HL- STORE AS DX
	XCHG				;DX NOW IN HL, DY NOW IN DE
	SHLD	DELTAY			;STORE OLD DX AS NEW DY
	LHLD	EPSLNX
	SHLD	SX			;REINITIALIZE: SX= EPSILON X

	LHLD	SY
	SHLD	EPSLNY		;EPSILON Y = SY
	LXI	H,0000H
	SHLD	EPSLNX		;EPSILON X = 0
	SHLD	SY		;SY = 0
;
LSTINIT	STC			;CLEAR CARRY -SET=1, THEN COMPLEMENT
	CMC
	MOV	A,D		;CALCULATE DELTAX/2 BY SHIFTING 1 RIGHT
	RAR			;SHIFT
	MOV	D,A		;STORE HIGH BYTE DELTAX/2 IN D
	MOV	A,E		;NOW THE LOW BYTE
	RAR			;SHIFT  (DIVIDE BY 2)
	MOV	E,A		;PUT LOW BYTE BACK.
	XCHG			;PUT DX/2 IN (HL)
	SHLD	DELTA3		;STORE IN DELTA3
;
	LXI	H,0001H		;SET NI=1
	SHLD	NI		;SAVE COUNTER VALUE
	RET			;DONE WITH INITIALIZATION
;
;------------------------------------------------------------------------
;			STATUS MESSAGE ROUTINE
;
;	THIS ROUTINE DISPLAYS A MESSAGE TO INDICATE THAT THE PROGRAM
;	IS WORKING.
;
;	INPUTS:
;		CURRENT COUNT STORED IN STATNO
;	OUTPUTS:
;		MESSAGE DISPLAYED
;	REGISTER STATUS:
;		ALL REGISTER VALUES PRESERVED
;	ERROR CONDITIONS:
;		NONE
;
STAT	PUSH	PSW		;SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
;
	LDA	STATNO		;GET COUNTER
	INR	A		;UPDATE COUNTER
	STA	STATNO
	MVI	C,09H		;SELECT WRITE FUNCTION
	CPI	01H		;SELECT MESSAGE
	JNZ	STATM2
	LXI	D,STAT1
	CALL	FDOS		;PRINT MESSAGE
	JMP	STATX		;EXIT SUBROUTINE
;
STATM2	CPI	128		;CHECK FOR OTHER MESSAGE
	JNZ	STATX		;NOT TIME FOR EITHER MESSAGE
	LXI	D,STAT2
	CALL	FDOS		;PRINT OTHER MESSAGE
;
STATX	POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	RET
;
;------------------------------------------------------------------------
;			STRING PLOTTING SUBROUTINE
;	METHOD:
;		ASCII CODE IS STORED REPEATEDLY IN THE AREA OCCUPIED BY
;		THE CHARACTER (CWIDTH RASTERS).  HI BIT IS SET TO  
;		INDICATE THAT THE BYTE IS ASCII AND NOT DOT IMAGE.
;
;	INPUT:
;		X,Y IN FILE BUFFER
;		BYTES READ SEQUENTIALLY FROM BUFFER UNTIL CARRIAGE RTN
;		IS ENCOUNTERED.
;
;	OUTPUTS:
;		EACH CHARACTER IS STORED IN THE BYTE CONTAINING THE BIT
;		MAP COORDINATE INDICATED FOR THE CHARACTER
;
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;
;	ERROR CONDITIONS:
;		X,Y LOCATIONS < 0 ARE RESET TO 0
;		X,Y LOCATIONS > MAX ARE RESET TO 0
;
CR	EQU	0DH		;CR = CARRIAGE RETURN
STRING	CALL	READXY		;GET STARTING COORDINATES
STRNG0	CALL	BYTE		;GET FIRST CHARACTER
	CPI	CR		;IS CHARACTER A CARRIAGE RETURN?
	RZ			;YES- SO RETURN (ALL DONE)
	ORI	10000000B	;SET HIGH BIT
	MOV	B,A		;SAVE BYTE IN (B)
	LHLD	X		;GET X LOCATION
	MOV	A,H		;LOOK AT HIGH BYTE
	ORA	A		;SET FLAGS
	JM	RESETX		;X IS NEGATIVE- RESET TO 0
	LXI	D,MAXX-CWIDTH	;GET MAXIMUM X VALUE 
	CMP	D		;COMPARE MAX AND X HIGH BYTES
	JC	STRNG1		;MAX DEFINITELY > X (X IS OK)
	JNZ	RESETX		;X DEFINITELY > MAX -RESET X
	MOV	A,L		;HI BYTES ARE =: LOOK AT LOW BYTES
	CMP	E		;IS MAX LOW BYTE > X LOW BYTE?
	JC	STRNG1		;YES IS IS - X IS OK
	JZ	STRNG1		;LOW BYTES ARE =: X IS BARELY OK
RESETX	LXI	H,0000H		;CLEAR HL
	SHLD	X		;STORE 0 IN X
STRNG1	LHLD	Y		;FETCH Y STARTING LOCATION
	MOV	A,H		;LOOK AT Y HIGH BYTE
	ORA	A		;SET FLAGS
	JM	RESETY		;NEGATIVE - RESET TO 0
	LXI	D,MAXY	;USE ENTIRE COORDINATE RANGE FOR Y
	CMP	D		;COMPARE MAX AND Y HIGH BYTES
	JC	STRNG2		;Y DEFINITELY OK
	JNZ	RESETY		;Y DEFINITELY > MAX - RESET Y
	MOV	A,L		;HI BYTES ARE =: LOOK @ LOW BYTES
	CMP	E		;COMPARE MAX AND Y LOW BYTES
	JC	STRNG2		;MAX > Y - Y IS OK
	JZ	STRNG2		;Y = MAX
RESETY	LXI	H,0000H		;CLEAR OLD VALUE OF Y
	SHLD	Y		;Y = 0
STRNG2	XCHG			;PUT Y IN (DE)
	LHLD	X		;FETCH X
	PUSH	B		;SAVE BYTE TEMPORARILY
	PUSH	D		;SAVE Y COORD TEMPORARILY
;	MAKE X COORD. A MULTIPLE OF CWIDTH FOR PROPER PRINTER OUTPUT
	SHLD	DIVDND		;COMPUTE X=(X/CWIDTH)*CWIDTH
	MVI	A,CWIDTH	;GET CWIDTH FOR DIVISOR
	STA	DIVSOR
	CALL	DIVIDE		;DIVIDE X BY CWIDTH
	LDA	QOTENT		;GET RESULTS (NO OVERFLOW AS 0<=X<1530)
	LXI	B,CWIDTH	;PASS CHARACTER WIDTH
	CALL	BMULT		;[HL] NOW CONTAINS (X/CWIDTH)*CWIDTH
;
	MOV	B,H		;PUT X IN (BC)
	MOV	C,L
	POP	D		;RETRIEVE Y COORDINATE
	LXI	H,MAXY	;PUT MAX Y IN (HL)
	CALL	LOCDOT	;GET LOCATION OF BYTE
	POP	B		;RETRIEVE BYTE
	MOV	M,B		;PUT BYTE IN ADDRESS CONTAINING X,Y
;	STORE BYTE REPEATEDLY TO BLANK OUT ENTIRE AREA OCCUPIED BY IT
	MVI	A,CWIDTH-1	;INITIALIZE LOOP COUNTER
STRNG3:	INX	H		;INCREMENT ADDRESS
	MOV	M,B		;STORE BYTE
	SUI	1		;DECREMENT LOOP COUNTER
	JNZ	STRNG3		;LOOP BACK UP UNTIL FINISHED
	MVI	C,CWIDTH		;PUT CWIDTH IN (C)
	LHLD	X		;FETCH X LOCATION
	MVI	B,00H		;CLEAR (B)
	DAD	B		;INCREMENT X LOCATION FOR  NEXT CHARACTER
	SHLD	X		;STORE NEW X LOCATION
	JMP	STRNG0		;LOOP UP TO TOP
;
;-----------------------------------------------------------------------
;	TEXT
;
;	THIS SUBROUTINE OUTPUTS TEXT IMMEDIATELY TO THE PRINTER
;	NOTE: TEXT IS NOT PUT INTO MEMORY MAP
;
;	INPUTS:
;		TEXT STRING IN FILE (ENDS WITH 0 BYTE)
;	OUTPUTS:
;		TEXT STRING PRINTED
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE PECULIAR TO THIS ROUTINE
;
TEXT	CALL	BYTE		;GET NEXT CHARACTER
	CPI	0		;CHECK FOR END OF STRING
	RZ			;RETURN IF FINISHED
;
	MOV	E,A		;PASS CHARACTER
	MVI	C,05		;SELECT CP/M LST: OUTPUT
	CALL	PDOS		;PRINT IT
;
	JMP	TEXT		;LOOP BACK UNTIL DONE
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE UPLOADS THE ARRAY DEFINING COLOR PALLET
;
;	INPUTS:
;		16 BIT INTEGER SPECIFYING # OF DATA BYTES TO COME
;		DATA BYTES IN INPUT FILE
;	OUTPUTS:
;		NEW COLOR VALUES STORED IN APPROPRIATE ARRAYS
;	REGISTER STATUS:
;		ALL REGISTER VALUES DESTROYED
;	ERROR CONDITIONS:
;		NONE
;
UPLOAD:	CALL	BYTE		;GET LOW BYTE OF INTEGER
	MOV	C,A		;SAVE INTEGER IN [BC]
	CALL	BYTE		;GET HIGH BYTE
;
	ORA	A		;CHECK VALUE OF HIGH BYTE
	JNZ	UPBAD		;FOR THIS PROGRAM, HI BYTE MUST BE 0
	MOV	A,C		;LOOK AT LOW BYTE
	CPI	7D		;7 INDICATES UPLOAD PLAID PATTERNS
	JZ	UPLAID		;PROCEED TO UPLOAD PLAID VALUES
	CPI	64D		;64 INDICATES UPLOAD DITHER MATRIX
	JZ	UPDITH		;PROCEED TO UPLOAD DITHER MATRIX
	CPI	120D		;124 INDICATES UPLOAD SPECIAL PATTERNS
	JZ	UPCIF		;PROCEED TO UPLOAD SPECIAL PATTERNS
;
UPBAD:	CALL	BYTE		;# HAS UNEXPECTED VALUE- SKIP BYTES
	DCX	B		;DECREMENT LOOP COUNTER
	MOV	A,C
	ORA	B		;IS COUNTER = 0 ?
	JNZ	UPBAD		;LOOP BACK UNTIL FINISHED
	RET
;
UPLAID:	LXI	H,PLAIDS+1	;POINT TO PLAID ARRAY (LEAVE "0" ALONE)
	JMP	UPLP1		;PROCEED TO READ-STORE LOOP
UPCIF:	LXI	H,CIFPAT	;SET POINTER AT START OF SPECIAL PATTERNS
	JMP	UPLP1
UPDITH:	LXI	H,DITHARR	;POINT TO DITHER ARRAY
UPLP1:	CALL	BYTE		;GET COLOR PATTERN
	MOV	M,A		;STORE PATTERN
	INX	H		;POINT TO NEXT PATTERN SLOT
	DCR	C		;DECREMENT COUNTER
	JNZ	UPLP1		;LOOP BACK UNTIL FINISHED
	RET
;
;-----------------------------------------------------------------------
;	THIS SUBROUTINE IS EXECUTED WHEN OVERFLOW OCCURS IN MULT. OR DIV
;	INPUTS:
;		NONE
;	OUTPUTS:
;		MESSAGE "OVERFLOW"
;		ALL REGISTERS PUSHED ON STACK
;		IN ORDER: PSW, H, D, B
;		FINAL POSITION OF STACK POINTER SAVED IN OLDSTK
;	REGISTER STATUS:
;		ALL INPUT REGISTERS STORED ON STACK, C, DE, HL REG CHANGED
;	ERROR CONDITIONS:
;		NONE
;
WOOPS	PUSH	PSW			;SAVE ALL REGISTERS
	PUSH	H
	PUSH	D
	PUSH	B
	LXI	H,0000H		;CLEAR (HL)
	DAD	SP		;GET STACK POINTER
	SHLD	OLDSTK		;SAVE STACK POINTER FOR DEBUG
	MVI	C,09H			;SELECT PRINT FUNCTION
	LXI	D,OVFLMSG
	CALL	FDOS			; PRINT 'OVERFLOW'
	JMP	BOOT			;RETURN TO CP/M COMMAND LEVEL
OVFLMSG	DB	'OVERFLOW$'
;
;-----------------------------------------------------------------------
;	WRITE RECORD SUBROUTINE
;
;	INPUTS:
;		OPENED FILE
;		FILE CONTROL BLOCK @ FCB2
;		BUFFER @ DMA2
;		BUFFER POINTER @ POINTR2
;	OUTPUTS:
;		BUFFER WRITTEN TO FILE
;		BUFFER POINTER RESET TO 0
;	REGISTER STATUS:
;		ALL REGISTER VALUES CHANGED
;	ERROR CONDITIONS:
;		IF NO SPACE LEFT ON DISK, ERROR MESSAGE WRITTEN
;		AND PROGRAM TERMINATES.
;
WRITE	MVI	C,26D			;SELECT SET DMA FUNCTION
	LXI	D,DMA2			;PASS O/P BUFFER
	CALL	FDOS			;SET DMA ADDRESS
;
	MVI	C,21D			;SELECT WRITE SEQUENTIAL
	LXI	D,FCB2			;PASS O/P FCB
	CALL	FDOS			;WRITE RECORD
;
	CPI	00H			;WAS WRITE OK?
	JNZ	FULLXIT			;JUMP TO ERROR SECTION IF NOT
	MVI	A,00H			;CLEAR (A)
	STA	POINTR2			;POINTR2=0
	RET				;DONE WITH SUCCESSFUL WRITE
FULLXIT	MVI	C,09D			;SELECT PRINT FUNCTION
	LXI	D,NOROOM		;PASS ERROR MESSAGE
	CALL	FDOS			;PRINT IT
;
	JMP	BOOT			;TERMINATE WITH WARM START
;
;-----------------------------------------------------------------------
;
;	THIS SUBROUTINE IS USED FOR NON-STANDARD EXTENSIONS TO PLOT
;
;	INPUTS:
;		NONE
;	OUTPUTS:
;		NONE
;	REGSISTER STATUS:
;		ALL VALUES PRESERVED
;	ERROR CONDITIONS:
;		NONE
;
XTEND:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
;
	CALL	BYTE		;GET LOW BYTE OF NUMBER OF DATA BYTES
	MOV	A,C
	CALL	BYTE		;GET HIGH BYTE OF NUMBER OF BYTES
	MOV	A,B		;[BC] IS NOW 16 BIT INTEGER
	ORA	C		;IS NUMBER = 0?
	JZ	XTND2		;FINISHED IF N = 0
XTND1:	CALL	BYTE		;GET DATA BYTE
	DCX	B		;DECREMENT COUNTER
	MOV	A,C
	ORA	B		;IS COUNTER = 0 ?
	JNZ	XTND1		;LOOP BACK IF MORE TO COME
XTND2:	POP	H		;RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	RET			;FINISHED
;
;-----------------------------------------------------------------------
;
ORIGIN					;START OF PICTURE MAP
;
;-----------------------------------------------------------------------
