	PAGE  60,132
	TITLE	TOSHIBA P1351 Graphics, v 1.0
	
	comment #

 tgraf.COM  7/4/85
Interrupt replacement for print screen function on ibmpc(tm)
	Please send problem reports and suggestions to:
		Marty Smith
		310 Cinnamon Oak Lane
		Houston, Texas	77079
		Compuserve 72155,1214
		(713) 464-6737

    Create tgraf.COM with MASM*, LINK* and EXE2BIN* as follows:

	masm tgraf,tgraf,tgraf;

	link tgraf;    (ignor the error message about no stack segment,
			  that's taken care of in the next step.)
	exe2bin tgraf.exe tgraf.com

  *  MASM is the MicroSoft(tm) Macro Assembler v. 3.0
	or IBM(tm) Macro Assembler v. 1.0
     LINK and EXE2BIN are PC-DOS(tm) utilities.

  This program originally designed for Epson-MX(tm) series printers
  with Graftrax80(tm) and Graftrax+(tm) bit-plot graphic capabilites.
  ======> Now modified with conditional compilation and macros for
  ======> c.itoh(tm) model 8510a and other printers.

	CHANGE HISTORY:
	9/18/82 - Buffer in routine for a line of bit-plot bytes to allow for
  checking for blank lines replaced by pre-scan routine, saving space.
	1/24/83 - Modifications for conditional assembly with other printers
  and C.ITOH 8510a.
	1/24/83 - Improved error checking for out-of-paper and I/O errors
  involving printer.
	1/24/83 - Bug in error check corrected, occuring when routine does
  error exit and is then called again, resulting in bit-plot data sent in
  regular mode.
	3/12/83 - Allow calling as a subroutine. i.e. no shift key depressed.
  Defaults to small print mode. Can be set to LARGE.
	2/4/84	- Allow correct printing of 640x200 mode.
	3/18/84 - Use int 31h for dos 2.+ terminate process.
	3/24/84 - Use BIOS for keyboard scan, in case screen is printed
		from DOS.
	4/21/84 - -OTHER- section complete for changes from 640 mode.
	9/22/84 - Add code to set lines back in 6/inch order, so CR's
		can advance to TOF.
	9/22/84 - Jump to other print screen routine instead of reassigning
		it to int f1h. Only luck has kept this vector from being used
		by someone else.
	10/20/84- Add check for already installed, don't reinstall.
	10/20/84- Compatibility with MASM 1.0 reestablished, FAR call to old
		routine caused 'fixup error' from EXE2BIN. 
	10/20/84- CALLGRAF now points to common address variable for default
		mode, is now the same for all versions of program.  Demo now
		works!
	4/15/84 - Toshiba P1351 added to list.  This is a higher resolution
		printer with a 24 pin dot head, and is another special edition
		of the program, like the Okidata with its 7 dot graphics.

	Features:
  Accepts ESC key exit, prescans to test for blank line
  left shift prtsc = small graphics, right shift prtsc = big
  Runs as a .COM type program under dos
     resident until power down or reset.
   1 = screen sent horiz. 320 bits in 480 mode
   2 = screen sent vert. 400 bits double printed in 480 mode
 **************  1 mode **********************
	DL = masking character
	DH = count of 25 (physical lines)
	CX = counter for each line (80)
	DS = used to index screen at 'b8000'
   These regs must be preserved during routine
	  (increment each line by adding '14' hex to ds: for paragraph
		boundary of 320 bytes 0x'140')
 **************  2 mode *********************
	DH = count of 40 (physical lines)
	CX = counter for each line (100)
	SI = index to screen via ds:
   These regs must be preserved during routine
	all output to printer is done from routine -send2-, which uses
	bios routine int 17h, and provides safe error exit.

  GRAF.COM is designed with the idea that the user's main program is the
  primary function and GRAF.COM should not cause problems of its own.


	#

TRUE	equ	-1	; DON'T CHANGE THESE!
FALSE	equ	0

escape	equ	27	; for printer
CR	equ	13
LF	equ	10

; ===============>  A L L  U S E R S  <===================
; ====> SET ONE AND ONLY ONE OF THE FOLLOWING THREE <=====
; don't set citoh to true! not operable with this version.

TOSHIBA	EQU	TRUE
; citoh and nec are left in here to allow for other 24 pin printers, and
; should NOT be set true at present.
CITOH	EQU	FALSE	; citoh and nec 8023 use similar codes.
NEC	EQU	FALSE

DEBUG	equ	FALSE
	
MAX_LINES equ	25	; lines in a screen

; Each bit of a byte is mapped to the wire head of the printer.
; If the Epson MX is sent 80h (bit 7), the TOP wire makes a dot.
; If the C.ITOH is sent   01h (bit 0), the TOP wire makes a dot.
; ===============>  A L L  U S E R S  <===================
; =====> SET ONE AND ONLY ONE OF THE FOLLOWING TWO <======

BIT7	EQU	TRUE
BIT0	EQU	FALSE

; BIT7 is TRUE for TOSHIBA
; BIT0 is TRUE for CITOH,NEC8023

print	macro	char
	mov	al,char
	call	SEND2
	endm


;  ***************> START OF ACTUAL CODE <*****************

cseg	segment 'code'
	assume cs:cseg
	org	100h		; set up for .com conversion
; publics here for debugging.

	comment #
	public	BCONT,BIT0,BIT7,BREAK?,BUFFER,D6ONE
	public	DEFAULT_ROUTINE
	public	DONE,DONE1,DOS1,DO_OLD,DSTOR,EDONE,ERRET,ESCAPE,EXIT
	public	GOBACK?,GOWAIT,GR1,GR2,GRAPHIC,IND10,INDEND
	public	INDENT,INDENT2,INIT,INITIAL,INITOK,INITR,INL640,INLOP
	public	INLOP2,LAST,LFCR,LOOP_COUNT,M640,M6AIN,M6LOOP,MAIN
	public	MAIN2,MAIN2A,ML10,ML10A,ML10B,ML20,MLOOP,MLOOP2,MODE640
	public	NO0,NO1,NO2,NO3,NO4,NO5,NO6,NO7,NOS10,NOSEND
	public	NOSET,NXTS,NXTS10,OLD_PRINT_ROUTINE,ONEOR2,PTFLAG,S310
	public	S320,S330,S340,S350,S360,S370,S380,S390,SEB10,SEB20,SEB30
	public	SEBLOOP1,SEBLOOP2,SEC10,SEC20,SEC25,SEC30,SECLOOP1
	public	SECLOOP2,SEND,SEND2,SEND3,SENDTWO,SEND_BIG_BW
	public	SEND_BIG_COLOR,SEND_LOOP1,SEND_LOOP2,SEND_LOOP3,SEND_ONE
	public	SEND_THREE,SEND_TWO,START,STWO1,STWO10,STWO2,STWO20
	public	STWO30,STWO40,TO0,TO1,TO2,TO3,TO4,TO5,TO6,TO7
	public	TOF,TOFL,TS0A,TS1A,TS2A,TS3A,TS4A,TS5A
	public	TS6A,TS7A,TST4,TST8,TWO,WEREHERE,WHERESI
	#

init	proc
	jmp	initial 	; so we have to set up first
init	endp
;	debugvar dw	0
gowait	dw	0
wheresi dw	0
ptflag	db	0
oneor2	db	0
dstor	dw	0
mode640 dw	0

; **** the 1 below is the POKE to use in CALLing from another program. ****
;
default_routine dw	1	;  1 for small, 2 for LARGE.		  *
;
; ****   WARNING * add any new variables AFTER this to preserve POKE ******

bigc1	db	001000b,100000b,000010b,001000b,100000b,000010b
bigc2	db	100010b,010101b,101010b,010100b,0,0  ; patterns for big color
bigc3	db	101010b,010101b,101010b,010101b,101010b,010101b

data_byte db	0,0
	
loop_count	db	0,0

old_print_routine  dd	0	; address of former print screen routine.

crt_cols	db	0
video_page	db	0
cursor_pos	dw	0
tmode_flag	db	0

do_old	proc	near
; jump to old routine
	pop	bp
	pop	si
	pop	di
	pop	dx
	pop	cx
	pop	bx
	pop	ds
	pop	es
	pop	ax
	jmp	cs:old_print_routine

do_old	endp

; --->	ACTUAL INTERRUPT ROUTINE STARTS HERE  <---
start	proc	far	; Start of main routine--Shift Prt.Sc hit.
	assume cs:cseg
	sti		; This follows ROM routine real close
	push	ax	;SAVE REGS
	push	es
	push	ds
	push	bx
	push	cx
	push	dx
	push	di
	push	si
	push	bp
	mov	bp,sp		; Save in case of error for reset
	mov	ax,50h		; Check here first to see if
	mov	ds,ax		; routine is already in progress
	mov	si,0		; otherwise it will be a mess.
	mov	al,01h		; if [si]=1 then there is a 
	cmp	[si],al		; print screen already in progress.
	jnz	nxts		; if not we're go for routine
	jmp	exit		; otherwise go back home.
nxts:	mov	[si],al 	; 
	mov	ah,15		; Get the current video state.
	int	10h		; from the ROM routine,
	mov	cs:mode640,FALSE
	cmp	al,4		; AL=4-6 are all graphics so we're OK
	jz	graphic
	cmp	al,5
	jz	graphic
	cmp	al,6
	jnz	nxts10
	mov	cs:mode640,TRUE ; special case
	jmp	short graphic
nxts10:
	jmp	do_text_mode

	mov	al,0	; else reset and go to ROM routine.
	mov	[si],al
	jmp	do_old	; this is where we stored the ROM routine entry.
;	jmp	exit	; Do the ROM routine but come back here to leave.
graphic:
	mov	ax,40h	; Get the keyboard shift flag
	mov	ds,ax	; segment
	mov	si,17h	; and address
	mov	ax,[si] ; pick it up
	and	ax,3	; get rid of other stuff
	or	ax,ax	; Mod. to create default small
	jnz	gr1	; for case where routine is called as a subroutine.
	mov	ax,cs:default_routine
gr1:	mov	cs:oneor2,al	; store for later
	push	ax	; also here
	xor	al,al	; make sure this starts out as NO print.
	mov	cs:ptflag,al
	xor	dl,dl	; These bits indicate whether R or L Shift is down
	mov	dh,19h	; 25 lines of graphic dots at 8 dots per line
	mov	cs:loop_count,dh
	mov	ax,0b800h ; stored in DX
	mov	ds,ax	;SET UP FOR SCREEN PEEK
; Printer setup section to change line spacing to 8/72" for continuous dots

; line spacing routine - All Epson Graftrax and IBM Graphics should
; accept esc 'A' 8  or  esc '3' 24 for line spacing, but IBM Graphics only
; recognizes esc '3' 24
	IF	TOSHIBA
	print	escape
	print	'L'     ; A
	print	'0'	; 8
	print	'7'
	ENDIF

	IF	CITOH	; ESC T 16
	print	escape
	print	'T'     ; T
	print	'1'     ; 1
	print	'6'     ; 6
	print	escape

	IF	NEC
	print	'['     ; Set printer to unidirectional for dot alignment
	ELSE
	print	'>'
	ENDIF

	ENDIF

	pop	ax	; get back which routine
	cmp	al,2	; Left Shift Prt Sc means LARGE graphic print
	jnz	gr2
	jmp	main2	; so hop over there if so.
gr2:
	cmp	cs:mode640,TRUE
	jnz	MAIN
	jmp	m640

; START OF small GRAPHICS PRINT ROUTINE.
; This routine scans across the screen from left to right,
; building an TOSHIBA bit plot byte out of IBM screen dots.
; TOSHIBA wire head		IBM screen color dots
; TOP	 o  128  80h bit 7	| 00 | 01 | 10 | 11 | = 4 dots, one byte
;	 o   64  40h  "  6
; one	 o   32  20h  "  5      ibm dots go one raster line then the next
; bit	 o   16  10h  "  4      EVEN line, ie 0, 2, 4 etc.
; plot	 o    8  08h  "  3
; byte	 o    4  04h  "  2      then you go back and do 1, 3, 5 etc.
;	 o    2  02h  "  1
; BOTTOM o    1  01h  "  0      At loc. 0000h are 4 dots, 0,0|0,1|0,2|0,3
;				At loc. 2000h are 4 dots, 1,0|1,1|1,2|1,3
;
main:	mov	cx,80	; 80 x 4 = 320 dots.
	mov	di,sp	; this is not very structured, but its 11:30pm

	comment #

ok, heres the idea, bp is already set for printer foulup abort.
This printer has much finer resolution than the epson, humble beginning
of this program.  all color modes do color translation here, b+w is yet
another situation, carp, carp. The scan routine is set so that when material
is found to be printed, the print line loop is reset to the top and only 
then is data actually sent. This allows for quicker printing of blank space.
 A cr/lf is much faster than control codes and 2000 bytes.  A more 
complicated translation routine means more call nesting, and so register 
DI is used to allow movement without stack trouble (famous last words).
If you make modifications to the program, please understand that changing
register DI may make for some interesting side effects.

	#

mloop:	mov	dl,0c0h ; 11000000b
	call	tst4	; see if this comes back <> 0
;	mov	al,ah	; we are testing bit patterns for one screen byte
	call	send3	; don't send to printer unless something to send
	mov	dl,30h	; 00110000b
	call	tst4	; each byte is 4 dots
;	mov	al,ah	; so we test for each dot in a byte
	call	send3	; send sets PTFLAG if there is a dot on the line
	mov	dl,0ch	; 00001100b
	call	tst4	; then resets to start of line and starts printing
;	mov	al,ah	; AL is the bit plot byte being built
	call	send3	; This keeps us from printing a line of '0's.
	mov	dl,03h	; 00000011b
	call	tst4	; TST4 scans down 8 screen dot lines each time called
;	mov	al,ah
	call	send3
	loop	mloop	; 80 bytes make 320 dots
	call	lfcr	; this is a good old regular line feed/carriage return
	call	break?	; someone hit ESC key? so take early exit
	mov	dh,cs:loop_count
	dec	dh	; DL is line counter
	or	dh,dh	; when it goes 0 we're through
	jz	done	; reset everything and do an IRET
	mov	cs:loop_count,dh
	mov	ax,ds	; otherwise bump the SEGMENT reg so that location
	add	ax,14h	; 0 is the start of the next line
	mov	ds,ax	; X'140' = 320
	jmp	main	; and do this 80 times (80x4=320)
done:	mov	ax,0
; This is the common exit for both routines, Printer is restored.
done1:	push	ax	; save AX cause it has error exit flag
; TOSHIBA command to reset printer to 6 lines/in. = ESC 2 (1b 32)
	IF	TOSHIBA
	print	escape
	print	'L'
	print	'0'	; add 12/216 to reset line spacing
	print	'8'
	print	CR
	print	LF
	ENDIF
; FOR CITOH MAKE SURE BIDIRECTIONAL PRINTING IS RESTORED
	IF	CITOH
	print	escape
	print	'A'
	print	escape

	IF	NEC
	print	']'
	ELSE
	print	'<'
	ENDIF

	ENDIF

edone:	mov	ax,50h	; Set end of PrtSc indication
	mov	ds,ax	; OK to come back and do again
	mov	si,0
	pop	ax
	mov	[si],al
exit:	pop	bp
	pop	si	; restore regs and return to caller
	pop	di
	pop	dx
	pop	cx
	pop	bx
	pop	ds
	pop	es
	pop	ax
	iret		; were an interrupt routine so we IRET

	comment	#
 START OF LARGE PRINT ROUTINE
+-------------+
| ^ ^ 	      |  This time we scan from 199,0 to 0,0
| ^ ^ 	      |   and go across
| ^ ^ 	      |  These are representations
| | | 	      |   of one color dot.
+-------------+    0	     1	     2	     3	   Palettes
		x x x x x x 	x x x x x x
     all o's	o o o o o o	x x x x x x	all x's
		x x x x x x	x x x x x x
		o o o o o o	o o o o o o	These patterns may be
		x x x x x x	o o o o o o	changed if they don't 
		o o o o o o	o o o o o o	look convincing.
color   00	     01		     10		11
	 0	      1		      2		 3

		for b+w:

     	dot on :  xxxxxx	oooooo  : dot off
		  xxxxxx	oooooo
		  xxxxxx	oooooo			


	#

main2:	mov	dh,80	; we have 80 colunms x 25 lines here
	mov	cs:loop_count,dh
	mov	cs:wheresi,3ef0h ; si is our index
	mov	si,cs:wheresi
	mov	di,sp
main2a: mov	cx,100
mloop2: mov	al,[si] ; idea is to get a byte starting at screen BOTTOM
	cmp	cs:mode640,TRUE
	je	ml10
	  
	call	send_big_color

	jmp	short ml10a
ml10:
	call	send_big_bw
ml10a:
	mov	cs:gowait,si ; store SI for next EVEN raster line
	sub	si,2000h ; subtract 2000h for the next ODD raster line
	mov	al,[si] ; and do the same here
	cmp	cs:mode640,TRUE
	je	ml10b

	call	send_big_color

	jmp	short ml20
ml10b:
	call	send_big_bw
ml20:
	mov	si,cs:gowait ; get back the EVEN line
	sub	si,80	; advance UP the screen one line (say 199,0 to 197,0)
	loop	mloop2	; and do this 100 times
	call	lfcr	; finished with one line we send normal line-end
	call	break?	; check for an ESC if we want to abort
	or	al,al	; clear flags
	dec	cs:loop_count
	mov	dh,cs:loop_count ; DH is our line counter,
	or	dh,dh	; when it goes 0 we're done.
	jz	tof	; so we'll try to reset Top of Form and exit

	inc	cs:wheresi	; else go to the next byte location
	mov	si,cs:wheresi	; store
	jmp	main2a		; and do again

tof:
	print	12	; send a form feed

	jmp	done	; clean up and back to caller.

start	endp

send2	proc	near	; BIOS routine to print the character in AL

IF	DEBUG
	inc	cs:debugvar
	ret
	ELSE
	push	ax
	mov	ah,00h	; 0=print, 1=initialize port, 2=read status to AH
	push	dx
	mov	dx,0	; DX specifies printer 0 (LPT1:)
	int	17h	; BIOS used instead of DOS because DOS sends
	pop	dx	; CR/LF's in the middle of the bit-plots
	test	ah,29h	; check for timeout or errors or out-of-paper
	pop	ax
	jnz	erret
	ret

erret:
	cmp	cs:tmode_flag,TRUE
	jne	erret10
	call	reset_cursor
erret10:
	mov	ax,00ffh ; Flag for printer foulup
	mov	sp,bp
	push	ax
	jmp	edone	; special abort
	ENDIF
send2	endp

; TOSHIBA bit plots operate at 180 dots per inch, or 1440 for an 8 inch line.
; called by ESC ; 'xxxx' where xxxx is an ASCII number like '0010' or '1440'
;  i.e.  300 dots would be ESC ; 0300
;  This is sent to the TOSHIBA as --> 27 ';' '0300'

indent	proc	near
	push	cx	; 13 spaces in to center
	IF	TOSHIBA
	cmp	cs:mode640,TRUE
	jz	ind10
	mov	cx,13	; PICTURE ( we've got 960 dots and 1440 to work with
inlop:	print	' '	; 1440-960=480/18 spaces/char pica = 26.67 extra
			; so indent the picture 13 spaces to center )
	loop	inlop
	print	escape	; SEQUENCE TO SET UP 960
			; BIT PLOTS IN GRAPHIC MODE.
	print	';'	; OF P1351
			; This is the set-up for the small print
	print	'0'	
	print	'9'	; 320*3=960 dots	
	print	'6'
	print	'0'
	jmp	short indend

ind10:		   
	mov	cx,5
inl640:		      	; 640x200 mode, 1440-1280=160/18 per char pica=8.89
			; so indent 5
	print	' '
	loop	inl640
	print	escape
	print	';'     ; 640 dots * 2 = 1280
	print	'1'
	print	'2'
	print	'8'
	print	'0'

indend:
	ENDIF
	IF	CITOH
	print	escape	; ESC N = Pica pitch
	print	'N'
	cmp	cs:mode640,TRUE
	jz	ind10
	mov	cx,20	; PICTURE ( we've got 320 dots and 640 to work with )
inlop:	print	20h	; 640-320=320 / 8 dots per char. = 40 extra
			; so indent the picture 13 spaces to center
	loop	inlop
	jmp	ind20

ind10:
	print	escape
	print	'S'
	print	'0'
	print	'6'
	print	'4'
	print	'0'
	jmp	ind30
ind20:
; ESC S 0320 = 320 bit plot type bytes on the way
	print	escape	; SEQUENCE TO SET UP 320 BIT PLOTS IN 640 MODE
	print	'S'     ; OF CITOH  This is the set-up for the small print
	print	'0'     ; Would love to try to use all 640 bits here
	print	'3'
	print	'2'
	print	'0'

ind30:
	ENDIF
	pop	cx
	ret
indent	endp
; This is indent for LARGE print
; This time we have 200*6=1200 bit plots to send 
; 1440-1200=240/18 =13.33 extra, so indent 6
indent2 proc	near
	push	cx
	IF	TOSHIBA
	mov	cx,6	; so indent 6 character type spaces
inlop2: print	20h
	loop	inlop2
	print	escape	; 200*6=1200
	print	';'
	print	'1'
	print	'2'
	print	'0'
	print	'0'
	ENDIF
; 640-400=240 / 8 = 30 EXTRA characters
	IF	CITOH
	print	escape ; ESC N = Pica pitch
	print	'N'
	mov	cx,15	; PICTURE ( we've got 400 dots and 640 to work with
inlop2: print	20h	; 640-400 / 8 dots per char. = 30 extra so indent
			; the picture 15 spaces to center
	loop	inlop2
; ESC S 0400 = 400 bit plot type bytes on the way
	print	escape	; SEQUENCE TO SET UP 400 BIT PLOTS IN 640 MODE
	print	'S'     ; OF CITOH
	print	'0'
	print	'4'
	print	'0'
	print	'0'
	ENDIF
	pop	cx
	ret
indent2 endp

m640	proc	near
m6ain:	mov	cx,80	; 80 x 4 = 320 dots.
	mov	di,sp
m6loop: mov	dl,80h ; 10000000b
	call	tst8	; see if this comes back <> 0
	mov	al,ah	; we are testing bit patterns for one screen byte
	call	sendtwo	; don't send to printer unless something to send
	mov	dl,40h	; 01000000b
	call	tst8	; each byte is 4 dots
	mov	al,ah	; so we test for each dot in a byte
	call	sendtwo	; send sets PTFLAG if there is a dot on the line
	mov	dl,20h	; 00100000b
	call	tst8	; then resets to start of line and starts printing
	mov	al,ah	; AL is the bit plot byte being built
	call	sendtwo
	mov	dl,10h	; 00010000b
	call	tst8	; TST4 scans down 8 screen dot lines each time called
	mov	al,ah
	call	sendtwo
	mov	dl,08h ; 00001000b
	call	tst8	; see if this comes back <> 0
	mov	al,ah	; we are testing bit patterns for one screen byte
	call	sendtwo	; don't send to printer unless something to send
	mov	dl,04h	; 00000100b
	call	tst8	; each byte is 4 dots
	mov	al,ah	; so we test for each dot in a byte
	call	sendtwo	; send sets PTFLAG if there is a dot on the line
	mov	dl,02h	; 00000010b
	call	tst8	; then resets to start of line and starts printing
	mov	al,ah	; AL is the bit plot byte being built
	call	sendtwo
	mov	dl,01h	; 00000001b
	call	tst8	; TST4 scans down 8 screen dot lines each time called
	mov	al,ah
	call	sendtwo
	loop	m6loop	; 80 bytes make 320 dots
	call	lfcr	; this is a good old regular line feed/carriage return
	call	break?	; see if someone hit ESC key. If so take early exit
	or	al,al
	mov	dh,cs:loop_count
	dec	dh	; DL is line counter
	cmp	dh,0	; when it goes 0 we're through
	jz	d6one	; reset everything and do an IRET
	mov	cs:loop_count,dh
	mov	ax,ds	; otherwise bump the SEGMENT reg so that location
	add	ax,14h	; 0 is the start of the next line
	mov	ds,ax	; X'140' = 320
	jmp	m6ain	; and do this 80 times (80x4=320)
d6one:	mov	ax,0
	jmp	done1

m640	endp

tst4	proc	near	;  This routine builds ONE bit plot byte
	mov	bx,80	;  by testing a dot with the mask sent
	sub	bx,cx	;  from MLOOP.
	mov	si,bx	;  First it does the ODD rows then the EVEN,
	xor	ax,ax	;  alternate lines are offset 2000h
	mov	bl,[si] ;  from each other in memory.
	and	bl,dl	;  DL has the mask
	or	bl,bl	;  SI the location
	jz	no7	;  BL the memory byte
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts7a
	or	ah,80h	; if set, set on data word
ts7a:
	test	bl,dl	; odd bit
	jz	no7
	or	ah,40h
no7:	add	si,80	; +80 gets us from say 0,0 to 2,0
	mov	bl,[si] ; get the memory byte ( 4 dots )
	and	bl,dl	; get rid of dots we aren't testing now
	or	bl,bl	; see if its COLOR 0
	jz	no5	; if yes, go on
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts5a
	or	ah,8	; if set, set on data word
ts5a:
	test	bl,dl	; odd bit
	jz	no5
	or	ah,4
no5:	add	si,80	; continue 7 5 3 1
	mov	bl,[si]	;  xxxxxx
	and	bl,dl	;        
	or	bl,bl	;  xxxxxx
	jz	no3	;  xxxxxx
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts3a
	or	al,80h	; if set, set on data word
ts3a:
	test	bl,dl	; odd bit
	jz	no3
	or	al,40h
no3:	add	si,80	;  xxxxxx
	mov	bl,[si]	;
	and	bl,dl
	or	bl,bl
	jz	no1
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts1a
	or	al,8	; if set, set on data word
ts1a:
	test	bl,dl	; odd bit
	jz	no1
	or	al,4
no1:	push	ax
	mov	ax,80
	sub	ax,cx	; CX counts our screen position
	add	ax,2000h ; add 2000h for the EVEN rows
	mov	si,ax	; with seg set to B800h we can use SI like an
	pop	ax	; array pointer ( AH has our byte so don't lose )
	mov	bl,[si] ; and continue with the same idea for 6 4 2 0
	and	bl,dl
	or	bl,bl
	jz	no6
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts6a
	or	ah,20h	; if set, set on data word
ts6a:
	test	bl,dl	; odd bit
	jz	no6
	or	ah,10h
;	call	set6
no6:	add	si,80
	mov	bl,[si]
	and	bl,dl
	or	bl,bl
	jz	no4
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts4a
	or	ah,2	; if set, set on data word
ts4a:
	test	bl,dl	; odd bit
	jz	no4
	or	ah,1
;	call	set4
no4:	add	si,80
	mov	bl,[si]
	and	bl,dl
	or	bl,bl
	jz	no2
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts2a
	or	al,20h	; if set, set on data word
ts2a:
	test	bl,dl	; odd bit
	jz	no2
	or	al,10h
;	call	set2
no2:	add	si,80
	mov	bl,[si]
	and	bl,dl
	or	bl,bl
	jz	no0
	mov	bh,bl
	and	bx,1010101001010101b ; separate components of two bits/pixel
	test	bh,dl	; even bit
	jz	ts0a
	or	al,2	; if set, set on data word
ts0a:
	test	bl,dl	; odd bit
	jz	no0
	or	al,1
;	call	set0

no0:	ret

	comment #
; hopefully this can be left out, it all depends on the LQ1500
; where's my Z80 now
; reverse this table if your bit plots use bit 0 for the top wire
	IF	BIT7
set15:	or	ah,80h	; top wire - bit 7
	ret
set14:	or	ah,40h	; bit 6
	ret
set13:	or	ah,20h	; bit 5
     	ret
set12:	or	ah,10h	; bit 4
	ret
set11:	or	ah,08h	; bit 3
	ret
set10:	or	ah,04h	; bit 2
	ret
set9:	or	ah,02h	; bit 1
	ret
set8:	or	ah,01h	; bit 0
	ret
set7:	or	al,80h	; top wire - bit 7
	ret
set6:	or	al,40h	; bit 6
	ret
set5:	or	al,20h	; bit 5
	ret
set4:	or	al,10h	; bit 4
	ret
set3:	or	al,08h	; bit 3
	ret
set2:	or	al,04h	; bit 2
	ret
set1:	or	al,02h	; bit 1
	ret
set0:	or	al,01h	; bit 0
	ret
	ENDIF
	IF	BIT0
set7:	or	ah,01h	; top wire - bit 0
	ret
set6:	or	ah,02h	; bit 1
	ret
set5:	or	ah,04h	; bit 2
	ret
set4:	or	ah,08h	; bit 3
	ret
set3:	or	ah,10h	; bit 4
	ret
set2:	or	ah,20h	; bit 5
	ret
set1:	or	ah,40h	; bit 6
	ret
set0:	or	ah,80h	; bit 7
	ret
	ENDIF

	#

tst4	endp

; 640 mode is single bits, no color, so result is in AL.
;
tst8	proc	near	;  This routine builds ONE bit plot byte
	mov	ax,80	;  by testing a dot with the mask sent
	sub	ax,cx	;  from M6LOOP.  Used by 640 mode
	mov	si,ax	;  First it does the ODD row then the EVEN
	mov	ah,0	;  since alternate lines are offset 2000h
	mov	al,[si] ;  from each other in memory.
	and	al,dl	;  DL has the mask
	cmp	al,0	;  SI the location
	jz	to7	;  AL the memory byte
	or	ah,80h	;  AH is the byte being built
to7:	add	si,80	; +80 gets us from say 0,0 to 2,0
	mov	al,[si] ; get the memory byte ( 4 dots )
	and	al,dl	; get rid of dots we aren't testing now
	cmp	al,0	; see if its COLOR 0
	jz	to5	; if yes, go on
	or	ah,20h
;	call	set5	; otherwise set that bit
to5:	add	si,80	; continue 7 5 3 1
	mov	al,[si]
	and	al,dl
	cmp	al,0
	jz	to3
	or	ah,8
;	call	set3
to3:	add	si,80
	mov	al,[si]
	and	al,dl
	cmp	al,0
	jz	to1
	or	ah,2
;	call	set1
to1:	push	ax
	mov	ax,80
	sub	ax,cx	; CX counts our screen position
	add	ax,2000h ; add 2000h for the EVEN rows
	mov	si,ax	; with seg set to B800h we can use SI like an
	pop	ax	; array pointer ( AH has our byte so don't lose )
	mov	al,[si] ; and continue with the same idea for 6 4 2 0
	and	al,dl
	cmp	al,0
	jz	to6
	or	ah,40h
;	call	set6
to6:	add	si,80
	mov	al,[si]
	and	al,dl
	cmp	al,0
	jz	to4
	or	ah,10h
;	call	set4
to4:	add	si,80
	mov	al,[si]
	and	al,dl
	cmp	al,0
	jz	to2
	or	ah,4
;	call	set2
to2:	add	si,80
	mov	al,[si]
	and	al,dl
	cmp	al,0
	jz	to0
	or	ah,1
;	call	set0
to0:	ret

tst8	endp

; This routine pre-scans a line to see if in fact there are any bit
; plots to send. The main routine will keep sending bytes here
; If a whole line of 0's are sent we avoid going through the
; set-up for bit-plot (i.e. slower movement) graphics when a CR/LF
; would take care of everything.
; If there IS something to send, PTFLAG is set, the current line
; position is set to 0, bit-plot is init., and bits are really sent to printer.
send	proc	near
;	push	ax	; save the character
;	push	ds	; DS saved cause it points to lines
;	pop	ax	; points to DS
;	mov	cs:dstor,ax	; save
	cmp	cs:ptflag,TRUE	; check for printing
	jne	nosend	; if PTFLAG isn't TRUE we are still scanning
;	pop	ax	; else get the char. in AL and print it
	call	send2	; this is the real out to printer routine
	ret
;	jmp	short noset ; restore DS and return
nosend:
;	pop	ax	; This is the SCAN routine
	or	al,al	; get the char. > test for 0 > if so reset and go back
	jz	noset
	mov	al,TRUE ; if <> 0
	mov	cs:ptflag,al ; set PTFLAG to go
	mov	sp,di	;DISCARD RETURN
	cmp	cs:oneor2,1 ; check which (small or LARGE)
	jnz	two	; indent 6 or 13 depending on which routine
	cmp	cs:mode640,TRUE
	jz	nos10
	call	indent	; indent also sets up bit-plot mode
;	call	noset	; NOSET will restore DS to right pos.
	jmp	main	; and do the line for real.
nos10:
	call	indent
;	call	noset
	jmp	m6ain
two:	call	indent2 ; init. for LARGE
	mov	si,cs:wheresi	; SI set back to start of line
;	call	noset	; get right DS
	jmp	main2a	; back to beginning
noset:
;	push	ax	; routine to restore DS
;	mov	ax,cs:dstor
;	mov	ds,ax
;	pop	ax
	ret
send	endp
	
send3	proc	near
; takes word length data and sends to printer
;
;  word reads left to right and has actual color values of eight
;  vertical pixels
;
;  these will be sent to the printer as three sets of four bytes each, 
;  each set of four bytes controlling the 24 pins on the print head.
;
;  pixel box is 3x3.  colors represented:
;  
;  color 0:  color 1:  color 2:  color 3:
;   o o o     o	o o	o x o     x o x
;   o o	o     o x o	o x o     o x o
;   o o	o     o o o	o x o     x o x
;    00	       01	 10	   11
;		  
	push	bx
	push	cx
	push	dx
	mov	dx,ax
	mov	bx,ax
	mov	cx,4

send_loop1:			; first pattern

	xor	al,al		; first column
	mov	ah,dh
	and	ah,11110000b	; just top two pixels
	or	ah,ah		; check for zero
	jz	send_one
	test	ah,10000000b	; twos place
	jz	s320
;	or	al,00101000b	; 0-5 significant
s310:
	test	ah,01000000b	; ones place
	jz	s320
	or	al,00101000b
s320:
 	test	ah,00100000b	; twos
 	jz	send_one
; 	or	al,00000101b
s330:
	test	ah,00010000b
	jz	send_one
	or	al,000101b
send_one:
	call	send
	shl	dx,1
	shl	dx,1
	shl	dx,1
	shl	dx,1
	loop	send_loop1

	mov	dx,bx		; restore char for next pattern
	mov	cx,4
send_loop2:
	xor	al,al		; first column
	mov	ah,dh
	and	ah,11110000b	; just top two pixels
	or	ah,ah		; check for zero
	jz	send_two
	test	ah,01000000b	; ones place
	jz	s340
	or	al,00010000b	; 0-5 significant
s340:		   
	test	ah,10000000b
	jz	s350
	or	al,00101000b	; only other
s350:
	test	ah,00010000b
	jz	s360
	or	al,00000010b
s360:
	test	ah,00100000b
	jz	send_two
	or	al,00000101b
send_two:
	call	send
	shl	dx,1
	shl	dx,1
	shl	dx,1
	shl	dx,1
	loop	send_loop2
	
	mov	dx,bx
	mov	cx,4

send_loop3:		; first pattern

	xor	al,al	; first column
	mov	ah,dh
	and	ah,11110000b	; just top two pixels
	or	ah,ah	; check for zero
	jz	send_three
	test	ah,10000000b	; twos place
	jz	s380
;	or	al,00101000b	; 0-5 significant
s370:
	test	ah,01000000b	; ones place
	jz	s380
	or	al,00101000b
s380:
	test	ah,00100000b
	jz	send_three
;	or	al,00000101b
s390:
	test	ah,00010000b
	jz	send_three
	or	al,00000101b
send_three:
	call	send
	shl	dx,1
	shl	dx,1
	shl	dx,1
	shl	dx,1
	loop	send_loop3

	pop	dx
	pop	cx
	pop	bx
	ret

send3	endp

sendtwo	proc	near
; expands 640x200 mode byte in small mode
;  bit is sent twice for 1280  3.56 x 3.33  7.11 x 6.66
;	
;	byte is in AL.
;
;	on =  x o   off = o o
;	      o	x	  o o
;	      x o	  o o

	push	bx		; save some regs
	push	cx
	push	dx
	
	mov	dx,ax		; copy data byte in al to dl,bl
	mov	bx,ax
	
	mov	cx,4		; do it with a loop
	
stwo1:
	xor	al,al		; start out blank
	test	dl,10000000b	; check top bit
	jz	stwo10		; not set, skip to next
	mov	al,00101000b	; if set reflect in data
stwo10:
	test	dl,01000000b	; check next
	jz	stwo20		; do again. 
	or	al,00000101b	; each byte is two verticle screen pixels
stwo20:
	call	send		; out to routine which prints or doesn't
	shl	dl,1		; depending on line.
	shl	dl,1		; now move data left 
	
	loop	stwo1		; and do it four times.
	
	mov	dx,bx		; get back copy
	mov	cx,4		; and send again
stwo2:
	xor	al,al
	test	dl,10000000b
	jz	stwo30
	mov	al,00010000b
stwo30:
	test	dl,01000000b
	jz	stwo40
	or	al,00000010b
stwo40:
	call	send
	shl	dl,1
	shl	dl,1
	
	loop	stwo2
	
	pop	dx
	pop	cx
	pop	bx

	ret

sendtwo	endp

send_big_color	proc	near
; take four pixel byte in al and expand to 24 x 6 to printer

	push	bx
	push	cx
	push	dx
		
	mov	dx,ax		; copy data byte
	mov	cs:data_byte,al
	xor	bx,bx
	mov	cx,6		; basically send for six vertical dot firings

secloop1:
	push	cx		; two loops, save first counter

	mov	dl,cs:data_byte	; get original data
	xor	dh,dh		; blank top half
	mov	cx,4		; set up inner loop 
secloop2:

	xor	al,al		; clear printer byte
	test	dl,11000000b	; see if its zero
	jz	sec25
	
	shl	dx,1		; move bits in question into lower dh
	shl	dx,1
	and	dh,3		; discard others    11 binary
	
	cmp	dh,1 		; is it a one?
	jnz	sec10		; no, try another
	mov	al,cs:bigc1[bx]	; else use pattern 1
	jmp	short sec30	; and go print
	
sec10:
	cmp	dh,2		; is it a two?
	jnz	sec20 		; no, then must be 3
	mov	al,cs:bigc2[bx]	; else use pattern 2
	jmp	short sec30	; off to print.
	
sec20:
	mov	al,cs:bigc3[bx]	; determined to be 3
	jmp	short sec30
sec25:
	shl	dx,1		; keep track of bits for zero case
	shl	dx,1
	
sec30:	
	call	send		; out to send routine
						     
	loop	secloop2	; do for each pixel
	
	pop	cx		; get back other counter
	inc	bx
	
	loop	secloop1	; do six times
	
	pop	dx		; and we are done.
	pop	cx
	pop	bx
	ret

send_big_color	endp
	
	
send_big_bw	proc	near
; take four pixel byte in al and expand to 24 x 6 to printer

	push	bx
	push	cx
	push	dx
		
	mov	dx,ax		; copy data byte
	mov	cs:data_byte,al
	mov	bl,010000b
	mov	bh,000010b	; pattern
	mov	cx,6		; basically send for six vertical dot firings

sebloop1:
	push	cx		; two loops, save first counter
	xor	bx,11100111000b	; reverse pattern

	mov	dl,cs:data_byte	; bl won't be changed
	mov	cx,4		; set up inner loop 
sebloop2:

	xor	al,al		; clear printer byte
	test	dl,10000000b	; check top
	jz	seb10
	
	mov	al,bl		; else use pattern 1
seb10:	
			 
	test	dl,01000000b
	jz	seb20
	or	al,bh
	
seb20:
	shl	dl,1		; set up for next
	shl	dl,1
	
seb30:	
	call	send		; out to send routine
						     
	loop	sebloop2	; do for each pixel
	
	pop	cx		; get back other counter
	
	loop	sebloop1	; do six times
	
	pop	dx		; and we are done.
	pop	cx
	pop	bx
	ret

send_big_bw	endp


lfcr	proc	near	; send a regular CR/LF combo
	print	13
	print	10
	mov	ax,0
	mov	cs:ptflag,al ; reset PTFLAG for next line
;	mov	ax,cs:dstor  ; restore DS
;	mov	ds,ax
	ret		; onward
lfcr	endp

break?	proc	near	; Test for early exit
	push	ax	; don't lose any regs. here
	push	dx
	mov	ah,01h	; call direct keyboard io (constat) by BIOS
	int	16h
	jnz	goback? ; if zero flag clear we have a character
bcont:	pop	dx	; no char. return
	pop	ax
	ret
goback?:
	mov	ah,0
	int	16h
	cmp	al,1bh	; ESC
	jz	back	; so go back, else return
	jmp	short bcont	; no ESC exit
back:	pop	dx	; ESC exit This doesn't check for Ctrl-Break
	pop	ax	; so if it is hit we save it for the caller to handle
	pop	ax	;DISCARD RETURN
	cmp	cs:tmode_flag,TRUE
	jne	GB10
	call	reset_cursor
GB10:
	jmp	done	; and go back to orig. caller
break?	endp

; text_mode
	
; routines for text mode dump
; 7/4/85
; right shift will print with control chars and extended replaced by dots '.'
; left shift will print graphics chars.

	
read_line	proc	near
; read line from screen into buffer, calculate length and put in first pos.
	
	push	bp
	mov	di,80h	; use default dta from original load
	inc	di
	
	mov	dh,loop_count
	xor	dl,dl
	mov	bh,video_page
	mov	bl,crt_cols
	cld		; set auto-increment
	
rloop:
	mov	ah,2	; set cursor
	int	10h

	mov	ah,8	; read att/char
	int	10h
	
	or	al,al	; replace 0 with space
	jz	rtl20
	cmp	al,0ffh ; and 255
	je	rtl20
rtl10:	
	stosb
	
	inc	dl
	cmp	dl,bl
	jne	rloop
	
	jmp	rtl_scan

rtl20:
	mov	al,' '	; replace space type chars with spaces
	jmp	rtl10
	
rtl_scan:
	dec	di	; set to last char
	mov	si,80h	; length store
	mov	cl,bl	; loop for length
	xor	ch,ch
	mov	al,' '	; search for spaces
	std		; set auto_decrement
	
	repe	scasb	; search backwards until 0 or non-space

	je	rtl30

	inc	cl	; adjust for count of characters, else cl is zero
rtl30:	
	mov	[si],cl
	cld

rtlret:		    
	pop	bp
	ret
	
	
read_line	endp

do_extended	proc	near

	mov	al,'.'
	call	send2
	ret
	
do_extended	endp
	
do_control	proc	near
	
	mov	al,'.'
	call	send2
	ret
	
do_control	endp


print_line	proc	near
; use info in buffer to print

	mov	si,80h
	lodsb		; get length
	or	al,al
	jnz	pl10
plret:	
	ret
pl10:
	mov	cl,al
	xor	ch,ch
	cld
ploop:
	lodsb
	cmp	al,127
	ja	pl_extended
	cmp	al,32
	jb	pl_control

	call	send2
plnext:	
	loop	ploop
	
	jmp	plret
       
pl_extended:
	call	do_extended
	jmp	plnext
pl_control:
	call	do_control
	jmp	plnext

print_line	endp
	

do_text_mode	proc	near
; comes in just after test for mode, but before shift key check

	mov	cs:crt_cols,ah
	mov	cs:video_page,bh
	mov	cs:tmode_flag,TRUE

	mov	ax,40h	; Get the keyboard shift flag
	mov	ds,ax	; segment
	mov	si,17h	; and address
	mov	ax,[si] ; pick it up
	and	ax,3	; get rid of other stuff
	or	ax,ax	; Mod. to create default small
	jnz	tr1	; for case where routine is called as a subroutine.
	mov	ax,cs:default_routine
tr1:	mov	cs:oneor2,al	; store for later

	mov	ax,cs
	mov	ds,ax	; set data to here
	mov	es,ax
			 
	mov	ah,3
	int	10h	; read cursor pos.
	mov	cursor_pos,dx ; save

	mov	byte ptr loop_count,0	
tmode_loop:
	
	call	read_line ; read in entire line
	call	print_line ; send to printer
	call	lfcr
	call	break?
			 
	mov	al,loop_count
	inc	al
	mov	loop_count,al
	cmp	al,MAX_LINES
	jnz	tmode_loop

	call	reset_cursor
	jmp	done

reset_cursor:	
	mov	dx,cursor_pos	; restore cursor
	mov	bh,video_page
	mov	ah,2
	int	10h
	
	mov	tmode_flag,FALSE

	ret

do_text_mode	endp


last	dw	0	; this marks end of resident code.
			; DON'T put anything below here you expect to use
			; after initialization.

buffer	db	'        TOSHIBA(tm) P1340, P1351, P351',13,10
	db	'            Screen Printer  v 1.1',13,10,10
	db	' ==>            Graphics Mode:',13,10
	db	'      Right Shift PrtSc = small graphics',13,10
	db	'      Left Shift PrtSc = LARGE GRAPHICS',13,10
	db	' ==>              Text Mode:',13,10
	db	'    Right Shift PrtSc = quick screen print',13,10
	db	'Left Shift PrtSc = extended characters printed',13,10,10
	db	'    ESCape will exit at the end of a line.',13,10,'$'
werehere db	' ** TOSHIBA.COM is already resident **',13,10,10
	db	' There is no need to reinstall.',13,10,'$'
initr	proc	far
initial:
	mov	ax,0	; get addr of
	mov	ds,ax	; print screen routine
	mov	si,14h	; in rom
	mov	ax,[si] ; from interrupt table in ram
	inc	si
	inc	si
	mov	dx,[si]

	mov	word ptr cs:old_print_routine,ax
	mov	word ptr cs:old_print_routine+2,dx
	mov	cx,offset last-offset start
	mov	di,ax
	mov	si,offset start
	cmp	dx,0efffh	; if routine points to ROM, ours is not it.
	ja	initok
	cmp	si,di
	jne	initok		; if start location not same, it can't be ours.

	; otherwise check to see if this routine is

	mov	es,dx		; already in memory, and don't reinstall if so.
	mov	ax,cs
	mov	ds,ax
	repe	cmpsb


	or	cx,cx		; cx=0 means there is a copy of this at the
	jnz	initok		; other address.
	mov	dx,offset werehere
	mov	ah,9		; so we print a message and
	int	21h		; abort.
	int	20h
initok:

;	 mov	 ds,ax
;	 mov	 al,0f1h ; move it to
;	 mov	 ah,25h
;	 int	 21h	 ; int f1h described in tech. manual as unused vector
	mov	ax,cs	; reset int 5
	mov	ds,ax	; to point to
	mov	ax,offset start ; this routine
	mov	dx,ax
	mov	al,5
	mov	ah,25h	; dos routine to reset int. vector
	int	21h
	mov	ax,offset buffer
	mov	dx,ax
	mov	ah,9
	int	21h	; print greeting
	mov	ax,3000h  ; get dos version
	int	21h
	or	al,al
	jz	dos1
	mov	ax,offset last
	mov	cx,16
	xor	dx,dx
	div	cx
	inc	ax	; make number of paragraphs
	mov	dx,ax
	mov	al,0	; exit code
	mov	ah,31h	; terminate process, keep resident
	int	21h

dos1:
	mov	dx,offset last	; last address here
	inc	dx
	int	27h	; terminate but stay resident
initr	endp
cseg	ends
	end	init

