Hard Copy Graphics For the Kim
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'.
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