Back to the index of Compute II

COMPUTE II ISSUE 1 / APRIL/MAY 1980 / PAGE 43

Hard Copy Graphics For the Kim

Keith Sproul
1368 Noah Road
North Brunswick, New Jersey 08902

There are many different video boards out these days, each with its own advantages and each designed for a different system. Some video boards are 'Byte Mapped', that is they display an ASCII character for every byte in memory. The other type of video board is a 'Bit Mapped' screen, this type displays one 'pixel', a dot on the television screen, for each bit in memory. Both of these types have advantages. The byte mapped screens display a character at a time and are good for high speed text applications and sometimes rough graphics. The bit mapped screens by definition give you higher resolution graphics. With a bit mapped video board you can do professional quality graphics. Characters are still possible on a bit mapped screen, but they have to be 'drawn'.

Figure 1

Micro Technology Unlimited of Manchester, New Hampshire makes a 'VISIBLE MEMORY' video board that is of the second type. This video board displays 200 rows of 40 bytes across. At 8 bits to the byte, this produces a graphic display of 320 by 200 pixels. That is fairly high resolution, even higher than 'High Res' on the APPLE. Besides being a good graphics board, this 'Visible Memory' doubles as 8K of memory when the graphics is not needed.

Hal Chamberlin, who is well known in the microcomputer industry and also works for M.T.U., wrote a 'V.M. Support Package' for this board. This package does everything from plotting points to drawing characters on the screen. This 'software character generator' enables the user to display text in any format, including sub-scripted and super-scripted characters. The user can also redefine his own characters or the entire character set. This enables the use of languages other than English to be displayed on the screen, a feature that is very rarely seen.

All of this is fine and pretty on the screen, but what if hard copy is needed? Plotters can be used to produce hard copy, but they are extremely expensive and are dedicated to plotting. Plotters also require extensive software to run properly. A different alternative is to use a DIABLO HyTerm II terminal. This terminal produces about the best print quality available and has built-in graphics capabilities. By using the graphics mode, the image from a bit mapped screen can be 'plotted' on the terminal, bit for bit, producing the exact image that was on the screen. The program at the end of this article is a 6502 assembler routine to print the entire contents of the 'Visible Memory' screen onto a DIABLO HyTerm II. The ideas involved can be adapted to other graphics boards as well, but will only work with 'bit mapped' video boards such as the M.T.U. 'Visible Memory'. Figure 1 was drawn on a M.T.U. 'Visible Memory' video board and then 'plotted' on a DIABLO using this program.

This program has been somewhat optimized for speed because of the length of time that is required for printing the images. Further optimization is possible such as adding reverse printing, and using other specialized features of the DIABLO. This was omitted to keep the program small and simple.

The screen is processed in four steps, the Page, the Line, the Byte, and the Bit. The program prints a Page by calling the Line subroutine 200 times. This routine prints a Line by calling the Byte routine 40 times, which in turn prints a byte by calling the Bit or Dot routine 8 times. The Line routine checks for the end of the line, only printing up to the last non-zero byte. It also skips any completely blank line, immediately going onto the next line to decrease printing time. The Byte routine shifts the byte to the left to determine if each bit is a 'one' or a 'zero'. The program can take up to an hour to print a complicated design. The average picture takes approximately 25 minutes. The reason for the big difference in time is that to print a 'one', a 'period' and a 'space' have to be printed, and to print a 'zero', just a space has to be printed, so a 'one' takes twice as long as a 'zero'.

This same set of ideas can be used to digitize pictures using a light sensitive diode fastened to the printing mechanism of the DIABLO. Instead of reading from the Visible Memory and writing to the plotter, the process is reversed, reading from the DIABLO and writing to the Visible Memory. This method was discussed in October 1979 issue of 'Dr. Dobb's Journal'. I hope to experiment with this idea in the future but have not had time to do it yet.

Of course this is not the cheapest way to go, but a DIABLO can be used for a lot more than just plotting. It can also be used as a normal hardcopy device for text processing or just listings whereas a plotter can only be used for one thing, plotting.


For reference only:

This is the list of escape sequences understood by the Diablo HyTerm II printer. The one(s) with '*' are used in this program.

<esc> 	1       SET HORIZONTAL TAB
<esc> 	2       CLEAR ALL TABS
<esc> 	3  *    SETS GRAPHICS MODE
<esc> 	4       CLEARS GRAPHICS MODE
<esc> 	5       FORWARD PRINTING
<esc> 	6       SETS REVERSE PRINTING
<esc> 	7       not used
<esc> 	8       CLEAR INDIVIDUAL TAB
<esc> 	9       SET LEFT MARGIN
<esc> 	0       SET RIGHT MARGIN
<esc> 	A       PRINT IN RED
<esc> 	B       PRINT IN BLACK
<esc> 	D       NEGATIVE 1/2 LINE FEED
<esc> 	U       1/2 LINE FEED
<esc> 	<ht>(n)	ABSOLUTE HORIZONTAL TAB
<esc> 	<vt>(n)	ABSOLUTE VERTICAL TAB
<esc> 	<lf>	NEGATIVE LINE FEED

DIABLO Plot Routine

This program takes the image on an M.T.U. Visible Memory Board and plots that image on a DIABLO HyTerm II printer. The routine has some intelligence in that it checks for the end of each line and only plots up to the end of the line, going on with the next line when finished. If the entire line is blank, it skips that line and advances to the next line.

The program waits for a character to be typed at the keyboard of the Diablo so that you can straighten the paper before it starts printing, be sure to type a character that does not print on the terminal (i.e. a space).

NOTE: graphics mode (and some of the other modes) are cleared when the Diablo receives a (cr) (hex $0D), so graphics mode is reset at the beginning of every line.

48 	 	00E0 	 	 	LINADR 	= 	$00E0 	; ADDR OF CURRENT LINE
49 	 	00E2 	 	 	BCOUNT 	= 	$00E2 	; BYTE POINTER
50		00E4			ACC     =	$00E4
51 	 	 	 	 	 	 	 	
52 	 	2000 	 	 	VM.ORG 	= 	$2000 	; Visible Memory Start Address
55 	 	 	 	 	SBTTL 	Plot Program 	 	
56 	 	 	 	 	 	 	 	
57 	 	0200 	 	 	 	= 	$0200 	
58 	 	 	 	 	 	 	 	
59 	0200 	4C 	09 	02 	START: 	JMP	P.PAGE  ; TAILORING VECTORS
60 	0203 	4C 	A0 	1E 	OUTCHR: JMP 	$1EA0   ; KIM PRINT CHAR ROUTINE (OR YOUR OWN)
61 	0206 	4C 	5A 	1E 	GETCHR: JMP 	$1E5A 	; KIM GET CHAR ROUTINE (OR YOUR OWN)
62 	 	 	 	 	 	 	 	
63 	0209 	 	 	 	P.PAGE:			;PLOT PAGE
64 	0209 	20 	06 	02 	 	JSR 	GETCHAR ; WAIT FOR CHAR TO ALLOW SETTING UP OF PAPER
65 	020C 	20 	B8 	02 	 	JSR 	CRLF	; Put Print Wheel at LEFT Column
66 	020F 	A2 	08 	 	 	LDX 	#8	; 8 Lines down the Page (CHANGE IF DESIRED)
67 	0211 	A9 	0A 	 	LINFD: 	LDA 	#$0A	; <lf>
68 	0213 	20 	A6 	02 	 	JSR 	PRTCHR 	
69 	0216 	CA 	 	 	 	DEX 	 	
70 	0217 	D0 	F8 	 	 	BNE 	LINFD 	
71 	 	 	 	 	 	 	 	
72 	0219 	A9 	00 	 	 	LDA 	#VM.ORG\ 	
73 	021B 	85 	E0 	 	 	STA 	LINADR 	; INIT LINADR TO VM.ORG
74 	021D 	A9 	20 	 	 	LDA 	#VM.ORG^ 	
75 	021F 	85 	E1 	 	 	STA 	LINADR+1 	
76 	 	 	 	 	 	 	 	
77 	0221 	20 	6F 	02 	 	JSR 	INIPLT 	; INIT Printer for PLOTTING
78 	0224 	A2 	C8 	 	 	LDX 	#200	; 200 LINES/PAGE
79 	 	 	 	 	 	 	 	
80 	0226 	 	 	 	PLOT:			; PLOT PAGE
81 	0226 	A0 	27 	 	 	LDY 	#39	; INIT INDEX Pointer
82 	0228 	B1 	E0		CHKBLK: LDA 	(LINADR),Y ; TEST FOR END OF LINE
83 	022A 	D0 	05 	 	 	BNE 	EOL 	
84 	022C 	88 	 	 	 	DEY 	 	
85 	022D 	D0 	F9 	 	 	BNE 	CHKBLK 	; CHECK NEXT BYTE
86 	022F 	F0 	06 	 	 	BEQ 	NXTLIN 	; Advance to next LINE
87								; IF ALL 40 BYTES = $00
88 	0231 	C8 	 	 	EOL: 	INY		; MAKE Y = NUMBER OF BYTES TO PRINT
89 	0232 	84 	E2 	 	 	STY 	BCOUNT 	; SAVE # OF BYTES IN LINE (THAT AREN'T ZERO)
90 	0234 	20 	7A 	02 	 	JSR 	P.LINE 	; PLOT the LINE at (LINADR)
91 	 	 	 	 	 	 	 	
92 	0237 	18 	 	 	NXTLIN: 	CLC 	 	
93 	0238 	A5 	E0 	 	 	LDA 	LINADR 	
94 	023A 	69 	28 	 	 	ADC 	#40	; 40 BYTES/LINE
95 	023C 	85 	E0 	 	 	STA 	LINADR 	
96 	023E 	A5 	E1 	 	 	LDA 	LINADR+1 	
97 	0240 	69 	00 	 	 	ADC 	#0 	
98 	0242 	85 	E1 	 	 	STA 	LINADR+1 	
99 	0244 	CA 	 	 	 	DEX 	 	
100 	0245 	F0 	1A 	 	 	BEQ 	EXIT 	
101								; End of Line
102 	0247 	A9 	0D 	 	 	LDA 	#$0D	; <cr>
103 	0249 	20 	A6 	02 	 	JSR 	PRTCHR 	
104 	024C 	A9 	00 	 	 	LDA 	#$00	; <nul>
105 	024E 	20 	A6 	02 	 	JSR 	PRTCHR 	
106 	0251 	A9 	00 	 	 	LDA 	#$00	; <nul>
107 	0253 	20 	A6 	02 	 	JSR 	PRTCHR 	
108 	0256 	20 	6F 	02 	 	JSR 	INIPLT 	; INITIALIZE TO GRAPHICS MODE
109 	0259 	A9 	0A 	 	 	LDA 	#$0A	; <lf>
110 	025B 	20 	A6 	02 	 	JSR 	PRTCHR 	; Advance Paper 1/48 IN.
111 	025E 	4C 	26 	02 	 	JMP 	PLOT	; Go BACK & Do NEXT LINE
112 	 	 	 	 	 	 	 	 	
115 	0261 	A9 	0D 	 	EXIT: 	LDA 	#$0D	; <cr>
116 	0263 	20 	A6 	02 	 	JSR 	PRTCHR 	; Clear GRAPHICS Mode
117 	0266 	A9 	0C 	 	 	LDA 	#$0C	; <ff>
118 	0268 	20 	A6 	02 	 	JSR 	PRTCHR 	; Advance to top of next page
119 	0263 	60 	 	 	 	RTS		; IF USED AS A SUBROUTINE
120 	026C 	4C 	4F 	1C 	 	JMP 	$1C4F	; OTHERWISE EXIT TO SYSTEM MONITOR
121								; (KIM WARM START)
122 	 	 	 	 	 	 	 	
124 	 	 	 	 	.SBTTL	Plot Subroutines 	 	
127 	 	 	 	 	 	 	 	
128								; INIT the DIABLO to PLOT MODE
129 	026F 	A9 	1B		INIPLT: LDA	#$1B	; <esc> 3
130 	0271 	20 	A6 	02 	 	JSR 	PRTCHR 	; Escape Sequence for PLOT MODE
131 	0274 	A9 	33 	 	 	LDA 	#'3 	
132 	0276 	20 	A6 	02 	 	JSR 	PRTCHR 	
133 	0279 	60 	 	 	 	RTS 	 	
134 	 	 	 	 	 	 	 	
135 	 	 	 	 	 	 	 	
136 	027A 	 	 	 	P.LINE: 	 	; PLOT 1 LINE (320 BITS or 40 BYTES)
137								; (or the # of BYTES in BCOUNT)
138 	027A 	A0 	00 	 	 	LDY 	#0	; INIT Index Pointer
139 	027C 	98 	 	 	PLINE1: 	TYA	; SAVE Y
140 	027D 	48 	 	 	 	PHA 	 	
141 	027E 	B1 	E0 	 	 	LDA 	(LINADR), Y 	
142 	0280 	20 	8B 	02 	 	JSR 	P.BYTE  ; PLOT the BYTE at (LINADR),Y
143 	0283 	68 	 	 	 	PLA		; RESTORE Y
144 	0284 	A8 	 	 	 	TAY 	 	
145 	0285 	C8 	 	 	 	INY		; Advance Pointer to next BYTE
146 	0286 	C6 	E2 	 	 	DEC 	BCOUNT 	
147 	0288 	D0 	F2 	 	 	BNE 	PLINE1
148 	028A 	60 	 	 	 	RTS		; Return when finished
149 	 	 	 	 	 	 	 	
151 	 	 	 	 	 	 	 	
152 	028B 	 	 	 	P.BYTE: 	 	; PLOT 1 BYTE
153 	028B 	48 	 	 	 	PHA		; SAVE ACC
154 	028C 	A0 	08 	 	 	LDY 	#8	; 8 BITS/BYTE
155 	028E 	68 	 	 	PBYTE1: PLA     	; RESTORE ACC
156 	028F 	0A 	 	 	 	ASL 	A	; SHIFT BIT into CARRY
157 	0290 	48 	 	 	 	PHA		; RE-SAVE ACC
158 	0291 	20 	99 	02 	 	JSR 	P.BIT	; PLOT THE BIT
159 	0294 	88 	 	 	 	DEY		; KEEP TRACK OF BITS DONE
160 	0295 	D0 	F7 	 	 	BNE 	PBYTE1 	; Do all 8 BITS
161 	0297 	68 	 	 	 	PLA		; RESTORE STACK
162 	0298 	60 	 	 	 	RTS 	 	
163 	 	 	 	 	 	 	 	
164 	 	 	 	 	 	 	 	
165 	0299 	90 	05 	 	P.BIT: 	BCC 	PBLANK  ; IF BIT = 0
166 	0298 	A9 	2E 	 	 	LDA 	#'. 	
167 	029D 	20 	A6 	02 	 	JSR 	PRTCHR  ; IF BIT = 1
168 	02A0 	20 	A4 	02 	PBLANK: JSR 	OUTSPA	; Advance Print wheel 1/60 IN.
169 	02A3 	60 	 	 	 	RTS 	 	
170 	 	 	 	 	 	 	 	
173 	 	 	 	 	SBTTL 	System Subroutines 	 	
174 	 	 	 	 	 	 	 	
175 	02A4 	A9 	20 	 	OUTSPA: LDA 	#' 	; PRINT A <space>
176								; FALL THROUGHT TO PRTCHR
177 	 	 	 	 	 	 	 	
178								; PRINT ASCII CHAR SAVING A, X, & Y
179 	02A6 	85 	E4 	 	PRTCHR: STA 	ACC 	; SAVE ACC
180 	02A8 	48 	 	 	 	PHA 	 	
181 	02A9 	8A 	 	 	 	TXA		; SAVE X
182 	02AA 	48 	 	 	 	PHA 	 	
183 	02AB 	98 	 	 	 	TYA		; SAVE Y
184 	02AC 	48 	 	 	 	PHA 	 	
185 	02AD 	A5 	E4 	 	 	LDA 	ACC 	
186 	02AF 	20 	03 	02 	 	JSR 	OUTCHR 	; KIM OUTPUT ROUTINE (OR SYSTEM OUTPUT)
187 	02B2 	68 	 	 	 	PLA 	 	
188 	02B3 	A8 	 	 	 	TAY		; RESTORE Y
189 	02B4 	68 	 	 	 	PLA 	 	
190 	02B5 	AA 	 	 	 	TAX		; RESTORE X
191 	02B6 	68 	 	 	 	PLA		; RESTORE ACC
192 	02B7 	60 	 	 	 	RTS 	 	
193 	 	 	 	 	 	 	 	
195 	02B8 	48 	 	 	CRLF: 	PHA		; SAVE ACC
196 	02B9 	8A 	 	 	 	TXA		; SAVE X
197 	02BA 	48 	 	 	 	PHA 	 	
198 	02BB 	A9 	0D 	 	 	LDA 	#$0D	; SUBROUTINE TO
199 	02BD 	20 	03 	02 	 	JSR 	OUTCHR 	; PRINT <cr>,<lf>
200 	02C0 	A9 	0A 	 	 	LDA 	#$0A 	
201 	02C2 	20 	A6 	02 	 	JSR 	PRTCHR 	
202 	02C5 	A2 	04 	 	 	LDX 	#4	; OUTPUT 4
203 	02C7 	A9 	00 	 	NULL: 	LDA 	#$00	; <nul> ($00)
204 	02C9 	20 	03 	02 	 	JSR 	OUTCHR 	
205 	02CC 	CA 	 	 	 	DEX 	 	
206 	02CD 	D0 	F8 	 	 	BNE 	NULL 	
207 	02CF 	68 	 	 	 	PLA		; RESTORE X
208 	02D0 	AA 	 	 	 	TAX 	 	
209 	02D1 	68 	 	 	 	PLA		; RESTORE ACC
210 	02D2 	60 	 	 	 	RTS		; RTS X = X Y = Y A = A
213 	 	0000 	 	 	 	.END