A.N.A.L.O.G. ISSUE 35 / OCTOBER 1985 / PAGE 81
One of the first things you find out about your printer is that it can’t print out many of the “special” characters in the Atari character set (e.g., the cursor characters, clear screen, all the CTRL graphics characters, all inverse characters, and so forth). If you send any of these to your printer, all kinds of odd things start happening.
Many of the special characters are interpreted as control codes by the printer, causing line feeds, form feeds, different fonts, etc. Unfortunately, a lot of Atari BASIC programs use these characters quite liberally, so if you type a simple LIST “P:” command, you might see your listing unexpectedly shift into Japanese katakana in the middle of a program line. Printing pictures from graphics mode 8 or 7 + (15 on XL computers) can be a fairly complicated procedure, as well. Translating the screen data to printer format is not an easy task for a beginning or intermediate programmer.
There’s a way to print any character your Atari can display on-screen; you must use your printer’s graphics mode and convert every character in the text you are sending into the graphics data that will draw that character on the printer. There are several programs on the market that will do this (Printwiz, Megafont II, Lister-Plus), but all of these require that the program (or text) to be printed be stored on disk in an ATASCII file.
These lister programs all read text from this disk file one line at a time, convert it to printer graphics and print it. This disk-based method is rather slow and necessitates an intermediate step in the listing process — making the disk file. Most of these utilities also have some provision for printing pictures.
This program represents another approach to the problem. The G: device is loaded into memory at boot-up time as an AUTORUN.SYS file. It will work with BASIC, the Assembler/Editor cartridge, BASIC XL and MAC/65.
You can LOAD, SAVE, ENTER and LIST files to and from disk, edit programs and perform any function in the usual manner with G: present. The difference is that, any time you want to produce a graphics listing of a BASIC or assembly language program, you just type:
LIST "G:" (BASIC) LIST #G: (MAC/65, ASSEMBLER/EDITOR)
This will list whatever you have in memory to the printer, but with all inverse and graphics characters exactly as they appear on-screen. You can list only certain line numbers, in the same way you would to any other device, with a statement such as:
LIST "G:",19,290 or LIST #G:,1220
The G: device will automatically set the left margin five spaces in and set the skip-over-perforation feature. I recommend positioning the printhead approximately two line feeds below the perforation line to start your listing.
Now, what would you pay? But wait . . .there’s still more! G: comes in four flavors — G1: (the default), G2:, G3: and G4:. Here’s what the different device numbers do.
Now, what would you pay? But wait… G: also prints custom character sets! When you’re printing text, G: will use whatever character set memory location 756 (hex $2F4) is pointing to.
Character set modification has been covered in many places, so I won’t go into the whole subject here. There are many public domain and commercial character editors for the Atari, to help in creating any font you can imagine. Create-A-Font by Vince Erceg in ANALOG Computing’s issue 16 is a good one.
G: also has a very flexible XIO frmction, which will print an exact copy of a graphics mode 0, 8 or 7 + (mode E) screen display. A mode screen can be printed with either single- or double-width characters. Mode 8 or 7 + screens can be printed in normal or inverse, three different widths and two different heights!
To print a graphics mode screen, type:
XIO 16,#1,0,0,"G:"
This is probably most useful in the program mode, where you can set up the screen in whatever way you like, then execute the XIO command (say, with a press of the START button). When using XIO with graphics 0, the G: device numbers (G1:, G2:, G3:, and G4:) control only the print size, not the line length. Therefore, G1: and G2: will produce the same printout, as will G3: and G4:.
If the first number after XIO (the command number) is 16, the entire screen will be printed. To print just part of the screen, add the number of lines you want to print to 16 and use that as the XIO command number. For example, if you want to print the first five lines using double-width characters, add 5 to 16 (21), and the XIO command might look like:
XIO 21,#1,0,0,"G4:"
To print a graphics 8 or 7+ screen, first set up your hi-res display, then execute the command:
XIO 64,#1,0,0,"G:"
This will print a single-width, single-height picture. To print your screen in inverse (like a photographic negative), set the auxiliary byte (the second number past the channel number) to 255. The XIO command would be:
XIO 64,#1,0,255,"G:"
When you’re printing a hi-res screen, the G: device numbers control the height of the picture. Here’s how they work:
G1: or G2: Single height. G3: or G4: Double height.
The width of the picture is controlled by the value of the first byte past the channel number in the XIO statement. In the first two examples above, this byte is 0. Here are the width values:
0 or 1 Single width. 2 Double width. 3 Triple width.
I’ll give several examples to illustrate the use of the XIO 64 command.
XIO 64,#1,0,255,"G4" -- Single width, inverse, double height. XIO 64,#1,2,0,"G2:" --- Double width, normal, single height. XIO 64,#2,3,255,"G3:" - Triple width, inverse, double height. XIO 64,#1,1,0,"G:" ---- Single width, normal, single height.
As you can see, there are quite a few ways to print a hi-res picture with the G: device. Some experimentation will probably be necessary to find the best way to print each picture.
And, by the way, the G: device automatically centers your picture on the page (on 80-column printers). Now, how much would you pay?
If you use MAC/65 or the Assembler/Editor cartridge, you can also send assembly listings to G: with the ASM command, or print to G: (no line numbers) with the PRINT command. The syntax would be:
ASM,#G: or PRINT #G:
In BASIC or BASIC XL, you can open a channel to G: with a statement like:
OPEN #1,8,0,"G:"
and then treat it exactly as any other output device — print strings, numbers, etc. with PUT # or PRINT # commands. This enables you to set up special title pages for documents with mixed print modes and mixed character fonts, draw borders, graph lines. . .or whatever you wish!
You can open more than one channel to G: at a time (e.g., G1: and G4:) and print alternate lines in different character widths. Unfortunately, at this point there’s no way to change print modes on the same line. The channel numbers that you use must be between one and seven, as with any other device.
G: even provides a way for you to control your printer’s line spacing. There are three preset line feed values, and you may also set the line feed to n/72 inches, n being a number between 3 and 127. The preset values are:
0 (default) 8/72 (1/9) inch line feed. 1 9/72 (1/8) inch line feed. 2 12/72 (1/G) inch line feed.
In addition to these three presets, any number (n) greater than 2 is taken to mean a line feed of n/72 inches. We use the OPEN auxiliary byte to pass the line feed value to the G: driver, like this:
OPEN #1,8,2,"G4:" or XIO 16,#1,0,10,"G:"
The auxiliary byte is the second number past the channel number in both examples (the same one we use for inverse with the XIO function). In the first example, it’s 2. This will set the printer to 1/6 inch line feeds. In the second example, we’re telling the printer we want line feeds of 10/72 inch.
The G: device uses the serial bus to send data to the printer, through SIOV at $E459. This means that if you have some kind of printer interface utilizing the joystick ports (as I used to), you can’t use this version of G:.
It’s possible to modify G: to use an IOCB channel to access the printer, but then the G: device will actually use two IOCB channels while it’s open, and you could no longer have more than one channel open to G: simultaneously.
G: is protected from SYSTEM RESET; it will remain available to you until you turn your computer off (or type DOS). You can go to DOS in the usual manner, but, if you do, G: will no longer work when you return to the cartridge.
G: doesn’t touch the much-abused page 6. Instead, G: reserves about 10 pages (2560 bytes) of low memory and sets the MEMLO pointer past itself, so that it can’t be overwritten. The reason G: uses so much memory is that, for every 1 character byte we want to print, we must send 8 bytes of graphics data. This means a large buffer to hold the converted graphics string. (The program itself is a little over 4 pages long, while the buffer is 5 pages — 1280 bytes!)
If you have any very large programs, it’s possible that there may no longer be enough free RAM to load them. This should be a rare occurrence; if it happens, you can always break your program into two parts and list them separately.
The version of G: presented here should work with any DOS, including Happy Warp DOS. It is assembled at an origin of $25D0. If you want to change this (perhaps to free up some more memory), you must enter in the source code with MAC/65 and reassemble with the different origin.
One last word … In the text mode, G: is a line-oriented device; in other words, it expects to be sent a line of text terminated by a RETURN (ATASCII 155). This means that you shouldn’t use PRINT # statements that end in a semi-colon, because G: won’t send anything to the printer until it sees a RETURN. Similarly, if you use PUT # commands to send data to G:, nothing will be printed until you send a 155 ($9B).
The BASIC program, with all those DATA statements that accompany this article, creates an AUTORUN.SYS file on disk that will automatically load and initialize the G: driver.
Type in the BASIC listing and SAVE it to disk before you RUN it. Then RUN the program, and your AUTORUN.SYS file will be created. When this is done, the G: device will be automatically installed whenever you boot up with this disk.
If you have MAC/65, you can type in the assembly listing and create the AUTORUN.SYS file with the command ASM, #-,#D: AUTORUN.SYS.
Charles F. Johnson is a musician by trade, currently working for Al Jarreau. A self-taught guitarist and programmer, he grew up in Hawaii and has been programming for three and a half years. This is his first published program.
10 REM *** G: GRAPHICS PRINTER *** 20 DATA 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15 30 DIM DAT$(91),HEX(22):FOR X=0 TO 22: READ N:HEX(X)=N:NEXT X:LINE=990:RESTOR E 1000:TRAP 110:? "CHECKING DATA" 40 LINE=LINE+10:? "LINE:";LINE:READ DA T$:IF LEN(DAT$)<>90 THEN 150 50 DATLIN=PEEK(183)+PEEK(184)*256:IF D ATLIN<>LINE THEN ? "LINE ";LINE;" MISS ING!":END 60 FOR X=1 TO 89 STEP 2:D1=ASC(DAT$(X) )−48:D2=ASC(DAT$(X+1))−48:BYTE=HEX(D1) *16+HEX(D2) 70 IF PASS=2 THEN PUT #1,BYTE:NEXT X:R EAD CHKSUM:GOTO 40 80 TOTAL=TOTAL+BYTE:IF TOTAL>999 THEN TOTAL=TOTAL−1000 90 NEXT X:READ CHKSUM:IF TOTAL=CHKSUM THEN 40 100 GOTO 150 110 IF PEEK(195)<>6 THEN 150 120 IF PASS=2 THEN END 130 ? "INSERT DISK WITH DOS, PRESS RET URN";:DIM IN$(1):INPUT IN$:OPEN #1,8,0 ,"D:AUTORUN.SYS" 140 ? :? "WRITING FILE":PASS=2:LINE=99 0:RESTORE 1000:TRAP 110:GOTO 40 150 ? "BAD DATA: LINE ";LINE:END 1000 DATA FFFFD025F52520FFFFA50A8D8B29 A50B8D8C29A50C8DD1258D8D29A50D8DD2258D 8E29A9D0850CA925850D60E2,546 1010 DATA 02E302D325D3258A29A200BD1A03 F005E8E8E8D0F6A9479D1A03A9019D1B03A926 9D1C03A910850AA926850BA9,253 1020 DATA FC8DE702A92E8DE802601C268726 9E269F269C26CD274C9D26A203BD8B29950ACA 10F86C0A00088A4A4A4A4AA8,793 1030 DATA 883004C0079004A086D057A621CA 8EA929BDDF2999D829A52BC9FFD002A900C903 B004AABDE3298DF729A522C9,416 1040 DATA 40D017A52AC902B004A91CD00AC9 03B004A90ED002A9018DF4292036298DAB29A2 0ABDED299DC003CA10F72041,122 1050 DATA 293005201029A0012860203629A9 1B8DC003A9408DC103A99B8DC203204129A001 60088EA52948A207B5D49D9B,190 1060 DATA 29CA10F8ADA32985D4ADA42985D5 68ACAB29F013C040D016A52B8DA829A9B885D6 A92985D7D038C99BD0034C5D,192 1070 DATA 27A0008CA82984D70A6EA8294AAC AB29D00FC920B00469409007C960B00338E920 A0030A26D788D0FA85D6ADF4,411 1080 DATA 0205D785D7A0078CA629B1D6ACA8 29F00249FFA0074A48B1D46A91D4688810F5CE A629ACA62910E2A007B1D4C9,294 1090 DATA 9BD004A99791D48810F318A5D469 088DA32985D49005EEA429E6D4EEFA29AEA929 F06BADFA29DDE629D063A000,654 1100 DATA A99B91D48CAA29A2030EFA292EFB 29CAD0F7ADAB29C940D004A94CD00CADA5294A 4A4A4AAACABDD8298DF929A9,571 1110 DATA F885DAA92985DB203629A8B1DA99 C003C99BD0058DAA29F010C8C028D0ED18A5DA 692885DA9002E6DB204129AD,633 1120 DATA AA29F0D6201029A207BD9B2995D4 CA10F828A001608EA529201D26C001D051A904 8DA929A55885D88DB2298DB0,797 1130 DATA 29A55985D98DB3298DB129A5228D AB29C940F032C911B004A918D002E9108DAD29 A9008DAC29ACAC29B1D8AEA5,314 1140 DATA 2920A026EEAC29ADAC29C928D0EB 204F29CEAD29D0DE4C8826A52AC902900DC903 B004A905D002A9068DA929A5,384 1150 DATA 21C903900B8DB729A2A0A000A930 D00BA9008DB729A240A001A9188EB4298CB529 8DB629A9008DAE29A9008DAF,272 1160 DATA 29ADB22985D8ADB32985D9A200A0 00B1D89DB829ACB729F0039DB929204F29E8C0 039001E8E008D0E4A52AC902,950 1170 DATA 9030205B29A207BDC0299DB829CA 10F720A026A207BDC8299DB829CA10F720A026 A52AC903D00EA207BDD0299D,47 1180 DATA B829CA10F720A026EEB229D003EE B329EEAF29ADAF29C928D08D18ADB0296DB429 8DB0298DB229ADB1296DB529,710 1190 DATA 8DB1298DB329EEAE29ADAE29CDB6 29F0034C6928A9058DF4294C8826A900AA9DFC 299DFC2A9DFC2B9DFC2C9DFC,567 1200 DATA 2DE8D0EE8DFA298DFB29A9FC8DA3 29A9298DA42960A227A9009DC003CA10FA60A2 0BBD8F299D0003CA10F74C59,195 1210 DATA E418A5D8692885D89002E6D960A2 17A9009DC029CA10FAA207A9078DA729BDB829 4A48A42A087EC0297EC8297E,543 1220 DATA D0292888D0F268CEA72910E8CA10 DD608F29FB2940015780C003050028004E0000 000000000000000000000000,793 1230 DATA 0000000000000000000000000000 00000000000000000000000000000000000000 000000000000000000000000,793 1240 DATA 000000000000000000004C4C4B4B 08090C0026263C2850781B401B4E051B4D051B 41081B000000E002E102D325,638
; ================================== ; ; A GRAPHICS PRINTING DEVICE ; G: FOR EPSON OR GEMINI PRINTERS ; ; ================================== ; ; ; (c) 1985 by CHARLES JOHNSON ; and Little Green Footballs ; ; G1: --- 80 Column Normal ; G2: --- 40 Column Normal ; G3: --- 40 Column Double-Width ; G4: --- 60 Column Double-Width ; ; XIO 16,#1,0,0,"G:" --- ; print a GRAPHICS 0 screen. ; Any XIO command # larger than ; 16 will be used as the # of ; screen lines to print +16. ; ; XIO 64,#1,0,0,"G:" --- ; print a GRAPHICS 8 or 7+ (E) ; screen. ; ; Auxiliary byte 2 values: ; (These go in ICAX2) ; ; 0 - 8/72 in. line feed ; 1 - 9/72 in. LF ; 2 - 12/72 in. LF ; 255 - INVERSE PRINT (XIO 64) ; ; Any number (n) larger than 2 ; will be used as n/72 in. LF ; ; ; -------------- ; System equates ; -------------- ; DOSVEC = $0A DOSINI = $0C ICDNOZ = $21 ICCOMZ = $22 ICAX1Z = $2A ICAX2Z = $2B SAVMSC = $58 ZPOUTP = $D4 FNTPTR = $D6 SCRPTR = $D8 POINTR = $DA ; RUNAD = $02E0 INITAD = $02E2 MEMLO = $02E7 CHBAS = $02F4 ; DDEVIC = $0300 HATABS = $031A PRNBUF = $03C0 SIOV = $E459 ; ; ----------------------------- ; Make this routine RESET-proof ; ----------------------------- ; *= $25D0 ; START JSR $FFFF PILFER LDA DOSVEC STA DVSAVE LDA DOSVEC+1 STA DVSAVE+1 LDA DOSINI ;Steal the DOS STA START+1 ;init vectors STA DVSAVE+2 ;and put them LDA DOSINI+1 ;in my code STA START+2 STA DVSAVE+3 LDA #<START ;Put address STA DOSINI ;of G: init code LDA #>START ;in DOSINI STA DOSINI+1 RTS ; *= INITAD ; .WORD PILFER ; ; --------------------- ; Install the G: device ; --------------------- ; *= PILFER ; INSTAL LDX #0 SEARCH LDA HATABS,X ;Look for the BEQ ADDG ;end of the INX ;handler table INX INX BNE SEARCH ; ADDG LDA #'G ;Add G: to the STA HATABS,X ;device table LDA #<GDRIVER STA HATABS+1,X LDA #>GDRIVER STA HATABS+2,X LDA #<GDVEC ;Reset DOS STA DOSVEC ;vectors LDA #>GDVEC STA DOSVEC+1 LDA #<PND ;Reset the MEMLO STA MEMLO ;pointer LDA #>PND STA MEMLO+1 RTS ; ; ---------------------- ; The table of addresses ; ---------------------- ; GDRIVER .WORD GOPEN-1 .WORD GCLOSE-1 .WORD GGETB-1 .WORD GPUTB-1 .WORD GSTAT-1 .WORD GXIO-1 JMP GINIT ; ; DOS commands go through here ; GDVEC LDX #3 GDV2 LDA DVSAVE,X ;Restore DOS STA DOSVEC,X ;vectors DEX BPL GDV2 JMP (DOSVEC) ;Go to DOS! ; ; ======================= ; THE G: HANDLER ROUTINES ; ======================= ; ; ---------------- ; The OPEN routine ; ---------------- ; GOPEN PHP TXA ;Calling IOCB # LSR A ;Divide by 16 LSR A ;to use as index LSR A LSR A TAY ;Move to Y DEY ;-1 BMI SETERR ;<0 = error CPY #7 ;>6 = error BCC GO2 SETERR LDY #$86 ;Bad IOCB # BNE GORTS ; GO2 LDX ICDNOZ ;Get device # DEX ;Subtract 1 STX SPLIT ;Store it LDA GRNUM,X ;Put gr mode in STA GRTBL,Y ;table LDA ICAX2Z ;Get LF value CMP #$FF ;Inverse pic? BNE GO3 ;No, skip LDA #0 ;Reset for LF GO3 CMP #3 ;>=3? BCS SETLFT ;Yes, skip TAX ;Move index to X LDA LFNUM,X ;Get preset LF SETLFT STA LNFEED ;Put LF in init LDA ICCOMZ ;Get command # CMP #64 ;Picture dump? BNE CLP1 ;No, skip LDA ICAX1Z ;Get width CMP #2 ;Single width? BCS NOTSNG ;No, skip LDA #28 ;Margin at 28 BNE SETMGN ; NOTSNG CMP #3 ;Double width? BCS NOTDBL ;No, skip LDA #14 ;Margin at 14 BNE SETMGN ; NOTDBL LDA #1 ;Margin at 1 SETMGN STA MARGN ;Set margin CLP1 JSR CLPBUF ;Clear buffer STA XIO? ;Clear XIO flag LDX #ICLEN-1 CCODES LDA ICODES,X ;Copy init STA PRNBUF,X ;codes to SIO DEX ;buffer BPL CCODES JSR DOSIO ;Send init codes BMI GORTS ;Error, skip JSR INIT LDY #1 GORTS PLP RTS ; ; ----------------- ; The CLOSE routine ; ----------------- ; GCLOSE JSR CLPBUF LDA #27 ;Reset printer STA PRNBUF ;and send one LDA #64 ;line feed STA PRNBUF+1 LDA #155 STA PRNBUF+2 JSR DOSIO GSTAT GINIT LDY #1 GGETB RTS ; ; ---------------- ; PUT BYTE routine ; ---------------- ; GPUTB PHP STX XSAVE PHA LDX #7 GP1 LDA ZPOUTP,X ;Save zero page STA ZPSAVE,X ;locations DEX BPL GP1 LDA OUTPTR ;Set zero page STA ZPOUTP ;pointer to LDA OUTPTR+1 ;gr buffer STA ZPOUTP+1 PLA LDY XIO? ;Is this XIO? BEQ GP1.2 ;No, skip CPY #64 ;Gr 8 dump? BNE GP2 ;No, skip LDA ICAX2Z ;Set inverse STA INVERS ;flag LDA #<GRBUF ;Set pointer to STA FNTPTR ;graphics buffer LDA #>GRBUF STA FNTPTR+1 BNE BYTE1 ; GP1.2 CMP #$9B ;End of line? BNE GP2 ;No, skip JMP DOPRINT ;Go print it! ; GP2 LDY #0 STY INVERS STY FNTPTR+1 ASL A ;Clear inverse ROR INVERS ;bit and save LSR A LDY XIO? BNE CONVERT CMP #$20 ;Convert from BCS CK2 ;ATASCII to ADC #$40 ;internal code BCC CONVERT CK2 CMP #$60 BCS CONVERT SEC SBC #$20 ; CONVERT LDY #3 GETINDEX ASL A ;Get index into ROL FNTPTR+1 ;char set table DEY BNE GETINDEX ; STA FNTPTR ;Set pointer to LDA CHBAS ;char storage ORA FNTPTR+1 STA FNTPTR+1 ; BYTE1 LDY #7 ;Eight bytes STY BYTCNT ;per character BYTELOOP LDA (FNTPTR),Y ;Get a byte LDY INVERS ;Inverse char? BEQ B2 ;No, skip EOR #$FF ;Reverse bits B2 LDY #7 ;8 bits per byte BITLOOP LSR A ;Bit to carry PHA ;Save byte LDA (ZPOUTP),Y ;Roll bit ROR A ;sideways into STA (ZPOUTP),Y ;each byte PLA ;Restore byte DEY ;Next bit BPL BITLOOP ; DEC BYTCNT ;Count bytes LDY BYTCNT ;More? BPL BYTELOOP ;Yes, go back ; LDY #7 CKRET LDA (ZPOUTP),Y CMP #$9B ;Check for EOLs BNE NOTRET ;in output LDA #$97 ;Replace STA (ZPOUTP),Y NOTRET DEY BPL CKRET ; CLC LDA ZPOUTP ;Increment ptr ADC #8 ;to print buffer STA OUTPTR ;by 8 bytes STA ZPOUTP BCC SKIP INC OUTPTR+1 INC ZPOUTP SKIP INC OUTCNT ;Count chars LDX SPLIT ;Is this 80-col? BEQ EXIT ;Yes, exit LDA OUTCNT ;Have we done CMP SPVAL,X ;one line? BNE EXIT ;No, more bytes ; DOPRINT LDY #0 ;Put EOL at end LDA #$9B ;of print buffer STA (ZPOUTP),Y STY DONE ;Clear done flag LDX #3 MULT8 ASL OUTCNT ;Multiply the # ROL OUTCNT+1 ;of characters DEX ;by 8 to get the BNE MULT8 ;# of gr bytes LDA XIO? CMP #64 BNE NOTPIC LDA #76 BNE SETM ; NOTPIC LDA XSAVE ;Get IOCB # LSR A ;Divide by 16 LSR A LSR A LSR A TAX ;Move to X DEX ;-1 LDA GRTBL,X ;Get gr mode SETM STA GRMODE ;Put in header LDA #<HEADER ;Set pointer STA POINTR ;to start of LDA #>HEADER ;header and STA POINTR+1 ;print buffer SENDEM JSR CLPBUF ;Clear SIO buf TAY SEND2 LDA (POINTR),Y ;Move chars STA PRNBUF,Y ;40 at a time CMP #$9B ;to SIO buffer BNE SEND3 ;(or until EOL) STA DONE ;Set done flag BEQ PRNT ;Skip ; SEND3 INY CPY #40 BNE SEND2 CLC ;Increment zero LDA POINTR ;page pointer by ADC #40 ;40 STA POINTR BCC PRNT INC POINTR+1 PRNT JSR DOSIO ;Send 40 bytes LDA DONE ;Done? BEQ SENDEM ;No, do the rest JSR INIT ;Re-init EXIT LDX #7 EX1 LDA ZPSAVE,X ;Restore zero STA ZPOUTP,X ;page locations DEX BPL EX1 PLP LDY #1 ;=Successful RTS ; ; --------------------------- ; The XIO screen dump routine ; --------------------------- ; GXIO STX XSAVE ;Save IOCB # JSR GOPEN ;Open G: CPY #1 ;Open OK? BNE GXXIT ;No, exit LDA #4 ;Set line length STA SPLIT LDA SAVMSC ;Set pointers STA SCRPTR ;to start of STA COLPTR ;screen memory STA ROWPTR LDA SAVMSC+1 STA SCRPTR+1 STA COLPTR+1 STA ROWPTR+1 LDA ICCOMZ ;Get command # STA XIO? ;Store it CMP #64 ;Gr 8 dump? BEQ GR8 ;Yes, go to it CMP #17 ;Full screen? BCS SHORT ;No, skip LDA #24 ;Set 24 lines BNE SETLIN ;Skip ; SHORT SBC #16 ;Subtract 16 SETLIN STA LINNUM ;Set # of lines ; STLINE LDA #0 ;Clear byte STA LINIX ;index PRSCRN LDY LINIX ;Get byte from LDA (SCRPTR),Y ;screen mem LDX XSAVE JSR GPUTB ;Send to G: INC LINIX ;Inc index LDA LINIX CMP #40 ;Done one line? BNE PRSCRN ;No, go back JSR NEXTLN ;Inc pointer DEC LINNUM ;Count lines BNE STLINE ;Not done yet GXXIT JMP GCLOSE ; GR8 LDA ICAX1Z ;Get width CMP #2 ;Single? BCC CKHT ;Yes, skip CMP #3 ;Double width? BCS CKW2 ;No, skip LDA #5 ;Length index BNE CKW3 ;Skip ; CKW2 LDA #6 ;Length index CKW3 STA SPLIT CKHT LDA ICDNOZ CMP #3 ;>2=Dbl height BCC NOT4 ;Not dbl, skip STA DBLHT ;Set flag LDX #<4*40 ;Set offset to LDY #>4*40 ;next row LDA #48 ;Set # of rows BNE SETG8 ; NOT4 LDA #0 ;Not dbl height STA DBLHT ;Clear flag LDX #<8*40 ;Offset LDY #>8*40 LDA #24 ;# of rows SETG8 STX ROWADD STY ROWADD+1 STA ENDROW LDA #0 ;Clear row count STA ROWCNT GR8.1 LDA #0 ;Set column to 0 STA COLCNT GR8.2 LDA COLPTR ;Set pointer to STA SCRPTR ;screen LDA COLPTR+1 STA SCRPTR+1 LDX #0 GET8B LDY #0 LDA (SCRPTR),Y ;Move bytes STA GRBUF,X ;to buffer LDY DBLHT ;Double height? BEQ GET8.1 ;No, skip STA GRBUF+1,X ;Double it! GET8.1 JSR NEXTLN ;Inc pointer INX CPY #3 ;Double height? BCC GET8.2 ;No, skip INX GET8.2 CPX #8 ;Done 8 bytes? BNE GET8B ;No, do the rest LDA ICAX1Z ;Get width CMP #2 ;>1? BCC NOTDBW ;No, skip JSR EXPAND ;Expand 'em LDX #7 DBW1 LDA WIDBUF,X ;These sections STA GRBUF,X ;copy the wide DEX ;buffer to the BPL DBW1 ;gr print buffer JSR GPUTB ;& send it to G: LDX #7 DBW2 LDA WIDBUF+8,X STA GRBUF,X DEX BPL DBW2 JSR GPUTB LDA ICAX1Z CMP #3 BNE NOTDB2 LDX #7 DBW3 LDA WIDBUF+16,X STA GRBUF,X DEX BPL DBW3 NOTDBW JSR GPUTB ;Send to G: NOTDB2 INC COLPTR ;Move pointer to BNE GR8.3 ;next column INC COLPTR+1 GR8.3 INC COLCNT ;Count columns LDA COLCNT CMP #40 ;Done 40? BNE GR8.2 ;No. Do the rest CLC LDA ROWPTR ;Set row pointer ADC ROWADD ;to the next row STA ROWPTR STA COLPTR ;Also store here LDA ROWPTR+1 ADC ROWADD+1 STA ROWPTR+1 STA COLPTR+1 INC ROWCNT ;Count rows LDA ROWCNT CMP ENDROW ;Done all? BEQ GR8XIT ;Yes, skip JMP GR8.1 ; GR8XIT LDA #5 ;Reset margin STA MARGN JMP GCLOSE ; ; ----------- ; Subroutines ; ----------- ; INIT LDA #0 ;Clear the TAX ;output buffer CLRBUF STA OUTBUF,X STA OUTBUF+$0100,X STA OUTBUF+$0200,X STA OUTBUF+$0300,X STA OUTBUF+$0400,X INX BNE CLRBUF STA OUTCNT ;Clear character STA OUTCNT+1 ;counter LDA #<OUTBUF ;Set pointer STA OUTPTR ;to buffer start LDA #>OUTBUF STA OUTPTR+1 RTS ; CLPBUF LDX #39 ;Clear the SIO LDA #0 ;print buffer CLP2 STA PRNBUF,X DEX BPL CLP2 RTS ; DOSIO LDX #$0B COPY LDA PRNCOM,X ;Copy print STA DDEVIC,X ;commands to DEX ;the DCB BPL COPY JMP SIOV ; NEXTLN CLC ;Increment scrn LDA SCRPTR ;pointer by one ADC #40 ;line; 40 bytes STA SCRPTR BCC NLN2 INC SCRPTR+1 NLN2 RTS ; EXPAND LDX #23 ;Clear the wide LDA #0 ;buffer CLWBUF STA WIDBUF,X DEX BPL CLWBUF LDX #7 ;Expand 8 bytes EXP1 LDA #7 ;7 bits per byte STA BITCNT LDA GRBUF,X ;Get byte EXP2 LSR A ;Shift bit PHA ;Save byte LDY ICAX1Z ;Get width EXP3 PHP ;Save status reg ROR WIDBUF,X ;Roll carry ROR WIDBUF+8,X ;thru 3 bytes ROR WIDBUF+16,X PLP ;Restore status DEY ;Width count BNE EXP3 ;Not done PLA ;Restore byte DEC BITCNT ;Count bits BPL EXP2 ;Not done yet DEX ;Count bytes BPL EXP1 ;Not done yet! RTS ;DONE!!! ; ; ------------------ ; Miscellaneous data ; ------------------ ; DVSAVE .DS 4 ;DOS vectors PRNCOM .BYTE $40 ;Printer .BYTE 1 ;Device number .BYTE $57 ;Write .BYTE $80 ;Output .WORD PRNBUF ;Buffer address .WORD 5 ;Timeout .WORD $28 ;Buffer length .BYTE $4E ;Normal print .BYTE 0 ;Unused ZPSAVE .WORD 0,0,0,0 OUTPTR .WORD 0 ;Ptr to buffer XSAVE .BYTE 0 ;Calling IOCB # BYTCNT .BYTE 0 ;Byte counter BITCNT .BYTE 0 ;Bit counter INVERS .BYTE 0 ;Inverse flag SPLIT .BYTE 0 ;Length index DONE .BYTE 0 ;Line done flag XIO? .BYTE 0 ;XIO flag LINIX .BYTE 0 ;Screen index LINNUM .BYTE 0 ;# of lines ROWCNT .BYTE 0 ;Row counter COLCNT .BYTE 0 ;Column counter ROWPTR .WORD 0 ;Row pointer COLPTR .WORD 0 ;Column pointer ROWADD .WORD 0 ;Offset to row ENDROW .BYTE 0 ;# of rows DBLHT .BYTE 0 ;Dbl height flag GRBUF .BYTE 0,0,0,0,0,0,0,0 WIDBUF .WORD 0,0,0,0,0,0,0,0 .WORD 0,0,0,0 GRTBL .BYTE 0,0,0,0,0,0,0 GRNUM .BYTE 76,76,75,75 LFNUM .BYTE 8,9,12 SPVAL .BYTE 0,38,38,60,40,80,120 ICODES .BYTE 27,64 ;Init printer .BYTE 27,78,5 ;Skip perf .BYTE 27,77 MARGN .BYTE 5 ;Left margin .BYTE 27,65 LNFEED .BYTE 8 ;LF (n/72 in.) ; ICLEN = *-ICODES ; HEADER .BYTE 27 GRMODE .BYTE 0 OUTCNT .WORD 0 ; OUTBUF .DS $0500 ;Print buffer ; PND = * ; *= RUNAD .WORD INSTAL .END