	Name msggri
; File MSGIBM.ASM
	include mssdef.h
;       Copyright (C) 1982,1991, Trustees of Columbia University in the
;       City of New York.  Permission is granted to any individual or
;       institution to use, copy, or redistribute this software as long as
;       it is not sold for profit and this copyright notice is retained.
; Tektronix emulator for use with MS Kermit/IBM.
; Edit history:
; 2 March 1991 version 3.10
; John Nyenhuis	  Purdue University  School of Electrical Engineering
; West Lafayette IN 47907   (317)494-3524     nyenhuis@ee.ecn.purdue.edu
; November 1988
; Modify msgibm.asm to work with the GRiD Compass II
; Functionality is same as for IBM except for the more message in OUTSCRN
;
; Last edit 22 May 1988
; 1 July 1988 Version 2.31
; 22 May 1988 Add support for ESC [ Pn ; Pn m (ANSI) screen coloring.
; 22 March 1988 Add global byte Tekgraf which forces graphics board type
;   0=auto-sensing, 1=cga, 2=ega, 3=VGA, 4=Hercules, 5=ATT. Tekgraf stored
;   here and set in file MSX by Set Term Graphics <board type>. Permit chars
;   to overlap existing pixels. [jrd]
; 27 Feb 1988 Add tests for Toshiba T3100 (tnx for assist from Rob Preuss),
;   for Olivetti M28/AT&T 6300+, and for DEC VAXmate II (tnx to Frank da Cruz)
;   Add pointer based dispatch to character-font drawing routine. Add tests
;   for stdin being a file rather than a device (keyboard). [jrd]
; 27 Jan 1988 Supress GIN and Status echos with Bypass byte. Bypass is reset
;  by receipt of BEL, LF, CR, US, escape sequences, terminal reset.
;  Bypass is set by receipt of ESC Control-E, ESC Control-X, ESC Control-Z.
;  Make GIN mode crosshairs remember last GIN mode postion until the terminal
;  is reset; make major steps smaller. Add ESC query-mark stands for DEL.
;  Make Horizontal Tab (Control-I) a non-printing cursor control character
;  to move right one column (with line wrap). Let real Hercules boards use
;  both pages of memory (clones behave differently), tnx to Daniel Gruner.
; 1 Jan 1988 version 2.30
; 31 Dec 1987 change name from msvibm to msgibm for final release. [jrd]
; 29 Dec 1987 Add ESC [ ? 3 8 l	 as exit Tek mode command, from VT340's.[jrd]
; 26 Dec 1987 Add test to absorb echo of crosshairs report. [jrd]
; 22 Dec 1987 Revise parsing rules to make an escape sequence be a temporary
;  interruption to the current command (except Clear Screen seq). [jrd]
; Add Control-C and Control-Break as non-reporting exits from GIN mode. [jrd]
; 21 Dec 1987 Add AT&T 6300, Olivetti M24 presence tests and run code. [jrd]
; 16 Dec 1987 Correct screen coloring for 64KB mono/med res color egas. [jrd]
; 4 Dec 1987 Add quirks for Environments, such as TopView, Windows. [jrd]
; 3 Dec 1987 Let 128KB EGA boards save screens. [jrd]
; 30 Nov 1987 Add relative plotting, thanks to help from Bob Parks. [jrd]
; 24 Nov 1987 Add dashed line patterns. [jrd]
; 21 Nov 1987 Add full color background. [jrd]
; 15 Nov 1987 Do screen clears manually because a Bios mode-set keeps
;  interrupts off long enough to miss serial port characters. Make crosshairs
;  smaller. [jrd]
; 8 Nov 1987 Modularize line drawing using Bresneham's algorithm, use pointers
;  to action routines for different board types. Add screen save/restore.
;  Do display board presence tests. Add FS as point plot introducer. Allow
;  for virtual screens when operating under Environments (Windows, etc). [jrd]
; 1 Nov 1987 Heavy rewrite to integrate code into regular MS Kermit/IBM
;  material. [jrd]
;==============================================================================
; Original version for TI Pro computers by
; 12-Dec-84  Joe Smith, CSM Computing Center, Golden CO 80401
; adapted to IBM PC June 1987 by	Brian Holley,
;					Faculty of Economics and Politics
;					University of Cambridge, England
;					Email: BJH6@UK.AC.CAM.PHX
; Upgraded and integrated into MS Kermit 2.30 by Joe Doupnik, Utah State Univ.
;
;		   Description of Tektronix commands
;
; ESCAPE-CONTROL-E (ENQ) requests a status report
; ESCAPE-FORMFEED erases the screen.
; ESCAPE-CONTROL-X turns on bypass mode (no screen characters).
; ESCAPE-CONTROL-Z turns on the crosshairs (not on 4006 or 4025)
; ESCAPE-? is replaced by DEL code, to assist line plots with 7 bit systems.
; ESCAPE [ Pn ; Pn m  set screen colors. Pn = 30 + sum of colors for foregnd,
;  40 + sum of colors for background, Pn = 0 sets b/w, Pn = 1 for high
;  intensity. Colors are red = 1, green = 2, blue = 4.
; ESCAPE [ ? 3 8 l  exits Tek mode and returns to host text terminal type
;  (VT102 if none defined yet). This is an extension from DEC VT340's.
; CONTROL-] (GS) turns on plot mode, the first move will be with beam off.
; CONTROL-^ (RS) turns on incremental plot mode. RS space means move pen up
;  RS P means move pen down, following letters:A, E, D, F, B, J, H, I mean
;  move right, right and up, up, left and up, left, left and down, down, and
;  right and down, respectively. Ex: RS <space> J J J  means move three Tek
;  positions left and down with the pen up (invisibly).
; CONTROL-UNDERLINE (US) turns off plot mode, as does CR (for all but 4025).
; CONTROL-X switches from TEKTRONIX sub mode to NORMAL alpha mode but is
;  ignored if we are emulating a full Tek terminal rather than a sub mode
;  of DEC or Heath.
; FF erases screen.
; ESCAPE letter, where letter is accent grave (`), a-e sets the line drawing
;   pattern until reset to solid lines (same as escape accent) by command or
;   a terminal reset.
; where
;	ENQ = Control E
;	ESC = Control [ (left square bracket)
;	FF = Control L
;	FS = Control \ (backslash)
;	GS = Control ] (right square bracket)
;	RS = Control ^ (caret)
;	US = Control _ (underscore)
;
; The plot commands are characters which specify the absolute position to move
; the beam.  All moves except the one immediately after the GS character
; (Control-]) are with a visible trace.
;
; For 4010-like devices - The positions are from 0 to 1023 for both X and Y,
; although only 0 to 780 are visible for Y due to screen geometry.  The screen
; is 10.23 by 7.80 inches, and coordinates are sent as 1 to 4 characters.
;
; For 4014-like devices - The positions are from 0 to 4096, but each movement
; is a multiple of 4 positions unless the high-resolution LSBXY are sent.  This
; makes it compatible with the 4010 in that a full sized plot fills the screen.
;
; HIX,HIY = High-order 5 bits of position
; LOX,LOY = Middle-order 5 bits of position
; LSBXY	  = Low-order 2 bits of X + low-order 2 bits of Y (4014 mode)
;
; Hi Y	  Lo Y	  Hi X	  LSBXY	  Characters sent (Lo-X always sent)
; ----	  ----	  ----	  -----	  ----------------------------------
; Same	  Same	  Same	  Same				 Lo-X
; Same	  Same	  Same	  Diff		LSB, Lo-Y,	 Lo-X	4014
; Same	  Same	  Diff	  Same		     Lo-Y, Hi-X, Lo-X
; Same	  Same	  Diff	  Diff		LSB, Lo-Y, Hi-X, Lo-X	4014
; Same	  Diff	  Same	  Same		     Lo-Y,	 Lo-X
; Same	  Diff	  Same	  Diff		LSB, Lo-Y,	 Lo-X	4014
; Same	  Diff	  Diff	  Same		     Lo-Y, Hi-X, Lo-X
; Same	  Diff	  Diff	  Diff		LSB, Lo-Y, Hi-X, Lo-X	4014
; Diff	  Same	  Same	  Same	  Hi-Y,			 Lo-X
; Diff	  Same	  Same	  Diff	  Hi-Y, LSB, Lo-Y,	 Lo-X	4014
; Diff	  Same	  Diff	  Same	  Hi-Y,	     Lo-Y, Hi-X, Lo-X
; Diff	  Same	  Diff	  Diff	  Hi-Y, LSB, Lo-Y, Hi-X, Lo-X	4014
; Diff	  Diff	  Same	  Same	  Hi-Y,	     Lo-Y,	 Lo-X
; Diff	  Diff	  Same	  Diff	  Hi-Y, LSB, Lo-Y,	 Lo-X	4014
; Diff	  Diff	  Diff	  Same	  Hi-y,	     Lo-Y, Hi-X, Lo-X
; Diff	  Diff	  Diff	  Diff	  Hi-y, LSB, Lo-Y, Hi-X, Lo-X	4014
; Offset for byte:		  20h	60h  60h   20h	 40h
;
; Note that LO-Y must be sent if HI-X has changed so that the TEKTRONIX knows
; the HI-X byte (in the range of 20h-3fh) is HI-X and not HI-Y.	 LO-Y must
; also be sent if LSBXY has changed, so that the 4010 will ignore LSBXY and
; accept LO-Y.	The LSBXY byte is 60h + MARGIN*10h + LSBY*4 + LSBX. (MARGIN=0)
;
;
;
; External variable tekflg and calls to tekini, tekemu, tekesc, tekcls:
; Byte TEKFLG is non-zero when the Tek emulator is active; it is set by the
; startup code in tekini and is maintained in this file. Internal variable
; inited remembers if we have a graphics screen saved, etc.
; TEKINI must be called when entering the emulator to establish the graphics
; screen mode and to calculate the screen dimensions.
; TEKRINT reinitialize complete emulator.
; TEKESC is called from say mszibm.asm to invoke Tek emulation when the
; external procedures have detected an Escape Control-L sequence. An implicit
; initialization is done if necessary.
; TEKEMU is the normal entry point to pass a received character to the emulator.
; It too will do an implicit initialization, if required.
; TEKCLS clears the graphics screen, but only if the emulator is active.
; The emulator remains active during Connect mode Help, Status, and other
; interrupts which do not change the terminal type.

	public	tekemu,tekini,tekrint,tekend,tekgraf	; Terminal emulation
	public	tekcls, tekesc, tekflg			;  used by msz file

ENQ	equ	05h			; ^E ENQ for TEK enquiries
CAN	equ	18h			; ^X to return to ANSI mode
ESCZ	equ	1Ah			; SUB, ESC-^Z triggers crosshairs
VT	equ	0bh			; ^K go up one line
FS	equ	1ch			; ^\ for point plot mode
GS	equ	1Dh			; ^] draw line (1st move is invisible)
RS	equ	1Eh			; ^^ for incremental line plot mode
US	equ	1Fh			; ^_ (underscore) returns to text mode
accent	equ	60h			; accent grave

txtmode equ	4			; text mode for TEKTRONIX status
maxtekx equ	1024			; horizontal and
maxteky equ	780			; vertical resolution of TEK 4010


uparr	equ	72			; DOS scan codes for arrow keys
dnarr	equ	80
lftarr	equ	75
rgtarr	equ	77
homscn	equ	71			; DOS home screen scan code
shuparr equ	73	     ;code-arrow keys [jan]
shdnarr equ	81
shlftarr equ	212
shrgtarr equ	213

segcga	equ	0040h		       ; grid display start [jan]


hiy	equ	1			; codes for Tek graphics components
loy	equ	2
hix	equ	4
lox	equ	3

data	segment public 'data'
	extrn	flags:byte, portval:word, rxtable:byte
	extrn	bigscreen:byte, denyflg:word	 ; control tek auto entry/exit


xmult	dw	5			; 320 = (5/16)*1024 small scrn [jan]
xdiv	dw	16			;     xmult/xdiv
ymult	dw	12			; 240=(12/39)*780  small scrn  [jan]
ydiv	dw	39			;     ymult/ydiv
xmax	dw	312			; 320-8 x coord of right most chr [jan]
ybot	dw	239			; 240 lines on small scrn [jan]
linelen dw	40			 ; offset increment between scan lines
linebytes dw	40			;40 bytes/line on small scn [jan]



ttstate dw	tektxt			; state machine control pointer
prestate dw	0			; previous state, across interruptions
visible db	0			; 0 to move, 1 to draw a line
tek_hiy dw	0			; Y coordinate in Tektronix mode
tek_loy db	0
tek_hix dw	0			; X coordinate in Tektronix mode
tek_lox db	0
tek_lsb db	0			; Low-order 2 bits of X + low Y
					;	(4014 mode)
status	db	0
lastc	db	0			; last x/y coord fragment seen
masktab db	80h,40h,20h,10h,8,4,2,1 ; quicker than calculations!
					; dashed line patterns
linetab dw	0ffffh			; ESC accent	11111111 11111111
	dw	0aaaah			; ESC a		10101010 10101010
	dw	0f0f0h			; ESC b		11110000 11110000
	dw	0fafah			; ESC c		11111010 11111010
	dw	0ffcch			; ESC d		11111111 11001100
	dw	0fc92h			; ESC e		11111100 10010010

linepat dw	0ffffh			; active line pattern, from above


;End of init data


IDSEQ	dw	tekem			; address of response to terminal
CTLTAB	dw	0			; .. inquiry
tekem	db	'GRiD_TEK'		 ; .. and the response
	db	escape,'/Z',0
x_coord dw	0			; Tek text char X coordinate
y_coord dw	8			; Tek text char Y coordinate
xcross	dw	0			; cross hairs to start at centre
ycross	dw	0
oldx	dw	0			; Tek coordinates of last point
oldy	dw	767			;  initially top left
scalex	dw	0			; PC coord for scaled x value
scaley	dw	0			;  for scaled y value
curmode db	0			; screen mode before graphics
tekgraf db	1		; Tek graphics board selection (def=cga)[jan]
				; local variables for LINE plotting routine
cursor	dw	0			; saved text cursor
inited	db	0			; non-zero if inited (retains page)
tekflg	db	0			; Tek mode active flag
yflags	db	0			; flags byte from msy
flow	dw	0			; flow control word
gpage	db	0			; display adapter graphics page
gfcol	db	15			; graphics foreground colour
gbcol	db	0			; graphics background color
tfcol	db	0			; temp foreground color
tbcol	db	0			; temp background color
lastd	db	0,0			; worker for ESC [ Pn ; Pn m scanner
ccode	db	0		       ;coloring
moremsg db	' More >'
mormsglen equ	$-moremsg		; length of message
putc	dw	gputc			; ptr to plot a character routine
psetup	dw	psetupc			; ptr to plot setup routine
pincy	dw	pincyc			; ptr to inc y routine
plotptr dw	pltcga			; ptr to dot plot routine
gcplot	dw	gcgen			; ptr to char plot routine
segscn	dw	0040h		       ; actual screen segment to use[jan]
					; ANSI Escape sequence to exit Tek mode
tkoff	db	escape,'[?38l'		; Exit Tek mode escape sequence
tkofflen equ	$-tkoff			; length of sequence
tkoffs	db	6 dup (0)		; received chars in rcv'd sequence
tkcnt	dw	0			; counter of matched char in tkoffs
bypass	db	0			; GIN mode bypass condition (0=off)
temp	dw	0

; 8*8 font for Hercules and such, CGA, and EGA
; - allows 43 lines, and 80 (90 for Hercules) chars per line.
; all printing (?) characters from <space> to <del> - two characters per line
; 8 bits per scan line, given top line first, 8 scan lines.
font	db	0,0,0,0,0,0,0,0,	       18h,18h,18h,18h,18h,0,18h,0
	db	6ch,6ch,6ch,0,0,0,0,0,	       36h,36h,7fh,36h,7fh,36h,36h,0
	db	0ch,3fh,68h,3eh,0bh,7eh,18h,0, 60h,66h,0ch,18h,30h,66h,06h,0
	db	38h,6ch,6ch,38h,6dh,66h,3bh,0, 0ch,18h,30h,0,0,0,0,0
	db	0ch,18h,30h,30h,30h,18h,0ch,0, 30h,18h,0ch,0ch,0ch,18h,30h,0
	db	0,18h,7eh,3ch,7eh,18h,0,0,     0,18h,18h,7eh,18h,18h,0,0
	db	0,0,0,0,0,18h,18h,30h,	       0,0,0,7eh,0,0,0,0
	db	0,0,0,0,0,18h,18h,0,	       0,06h,0ch,18h,30h,60h,0,0
	db	3ch,66h,6eh,7eh,76h,66h,3ch,0, 18h,38h,18h,18h,18h,18h,7eh,0
	db	3ch,66h,06h,0ch,18h,30h,7eh,0, 3ch,66h,06h,1ch,06h,66h,3ch,0
	db	0ch,1ch,3ch,6ch,7eh,0ch,0ch,0, 7eh,60h,7ch,06h,06h,66h,3ch,0
	db	1ch,30h,60h,7ch,66h,66h,3ch,0, 7eh,06h,0ch,18h,30h,30h,30h,0
	db	3ch,66h,66h,3ch,66h,66h,3ch,0, 3ch,66h,66h,3eh,06h,0ch,38h,0
	db	0,0,18h,18h,0,18h,18h,0,       0,0,18h,18h,0,18h,18h,30h
	db	0ch,18h,30h,60h,30h,18h,0ch,   0,0,0,7eh,0,7eh,0,0,0
	db	30h,18h,0ch,06h,0ch,18h,30h,   0,3ch,66h,0ch,18h,18h,0,18h,0
	db	3ch,66h,6eh,6ah,6eh,60h,3ch,   0,3ch,66h,66h,7eh,66h,66h,66h,0
	db	7ch,66h,66h,7ch,66h,66h,7ch,   0,3ch,66h,60h,60h,60h,66h,3ch,0
	db	78h,6ch,66h,66h,66h,6ch,78h,   0,7eh,60h,60h,7ch,60h,60h,7eh,0
	db	7eh,60h,60h,7ch,60h,60h,60h,   0,3ch,66h,60h,6eh,66h,66h,3ch,0
	db	66h,66h,66h,7eh,66h,66h,66h,   0,7eh,18h,18h,18h,18h,18h,7eh,0
	db	3eh,0ch,0ch,0ch,0ch,6ch,38h,   0,66h,6ch,78h,70h,78h,6ch,66h,0
	db	60h,60h,60h,60h,60h,60h,7eh,   0,63h,77h,7fh,6bh,6bh,63h,63h,0
	db	66h,66h,76h,7eh,6eh,66h,66h,   0,3ch,66h,66h,66h,66h,66h,3ch,0
	db	7ch,66h,66h,7ch,60h,60h,60h,   0,3ch,66h,66h,66h,6ah,6ch,36h,0
	db	7ch,66h,66h,7ch,6ch,66h,66h,   0,3ch,66h,60h,3ch,06h,66h,3ch,0
	db	7eh,18h,18h,18h,18h,18h,18h,   0,66h,66h,66h,66h,66h,66h,3ch,0
	db	66h,66h,66h,66h,66h,3ch,18h,   0,63h,63h,6bh,6bh,7fh,77h,63h,0
	db	66h,66h,3ch,18h,3ch,66h,66h,   0,66h,66h,66h,3ch,18h,18h,18h,0
	db	7eh,06h,0ch,18h,30h,60h,7eh,   0,7ch,60h,60h,60h,60h,60h,7ch,0
	db	0,60h,30h,18h,0ch,06h,0,0,     3eh,06h,06h,06h,06h,06h,3eh,0
	db	18h,3ch,66h,42h,0,0,0,0,       0,0,0,0,0,0,0,0ffh
	db	30h,18h,0ch,0,0,0,0,0,	       0,0,3ch,06h,3eh,66h,3eh,0
	db	60h,60h,7ch,66h,66h,66h,7ch,0, 0,0,3ch,66h,60h,66h,3ch,0
	db	06h,06h,3eh,66h,66h,66h,3eh,0, 0,0,3ch,66h,7eh,60h,3ch,0
	db	0eh,18h,18h,3ch,18h,18h,18h,0, 0,0,3eh,66h,66h,3eh,06h,3ch
	db	60h,60h,7ch,66h,66h,66h,66h,0, 18h,0,38h,18h,18h,18h,3ch,0
	db	18h,0,38h,18h,18h,18h,18h,70h, 60h,60h,66h,6ch,78h,6ch,66h,0
	db	38h,18h,18h,18h,18h,18h,3ch,0, 0,0,76h,7fh,6bh,6bh,63h,0
	db	0,0,7ch,66h,66h,66h,66h,0,     0,0,3ch,66h,66h,66h,3ch,0
	db	0,0,7ch,66h,66h,7ch,60h,60h,0, 0,3eh,66h,66h,3eh,06h,07h
	db	0,0,6ch,76h,60h,60h,60h,0,     0,0,3eh,60h,3ch,06h,7ch,0
	db	30h,30h,7ch,30h,30h,30h,1ch,0, 0,0,66h,66h,66h,66h,3eh,0
	db	0,0,66h,66h,66h,3ch,18h,0,     0,0,63h,6bh,6bh,7fh,36h,0
	db	0,0,66h,3ch,18h,3ch,66h,0,     0,0,66h,66h,66h,3eh,06h,3ch
	db	0,0,7eh,0ch,18h,30h,7eh,0,     0ch,18h,18h,70h,18h,18h,0ch,0
	db	18h,18h,18h,0,18h,18h,18h,0,   30h,18h,18h,0eh,18h,18h,30h,0
	db	31h,6bh,46h,0,0,0,0,0,	       8 dup (0ffh)
data   ends

code	segment public 'code'
	extrn	outchr:near, beep:near, cmblnk:near
	extrn	clrmod:near, cptchr:near
	extrn	clrbuf:near, iseof:near, getflgs:near
	extrn  termtog:near		   ; toggle terminal type [jan]
	assume	cs:code, ds:data, es:nothing

; Initialise TEK mode by setting high resolution screen, etc

tekini	PROC NEAR
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	es
	cmp bigscreen,0		       ;1means big
	je tekin1		       ;eq means use defaults
	 mov xmult,1			;512=(1/2) x 1024 big scrn [jan]
	 mov xdiv,2			;512 columns on big screen
	 mov ymult,64			;256=(64/195)*780
	 mov ydiv,195			;256 rows on big screen
	 mov xmax,504			;5-2-8 x coord of right most chr
	 mov ybot,255			;256 lines on big screen
	 mov linelen,64		       ;64 bytes per line
	 mov linebytes,64
	jmp tekin2
tekin1:	 mov xmult,10		;small screen stuff
	 mov xdiv,32		;small is 320 x 240
	 mov ymult,12
	 mov ydiv,39
	 mov xmax,312
	 mov ybot,239
	 mov linelen,40
	 mov linebytes,40


tekin2: mov	tekflg,1		; starting Tek sub mode
;	cmp	inited,0		; inited yet?
;	jne	tekin19			; ne = yes, restore screen
	mov	ttstate,offset tektxt	; do displayable text
	mov	prestate,offset tektxt	; set a previous state of text
	mov	inited,1		; say we have initialized
;	call	tekcls			; clear screen
;	jmp	short tekin20
;tekin19:call	 tekrest		 ; restore old graphics screen
tekin21:clc				; clear carry for success
tekin23:pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
tekini	ENDP

TEKRINT proc	near			; Tek reinitialization entry point
	mov	inited,0		; do complete reinitialization
	jmp	tekini
TEKRINT endp


;Terminal emulation. Enter with received character in AL.

TEKEMU PROC	NEAR			; main emulator
	cmp	tekflg,0		; Tek mode active yet? (msz call)
	jne	tektt1			; ne = yes
	call	tekini			; init now
	mov	ttstate,offset tektxt	; initial state
	mov	prestate,offset tektxt	; set a previous state of text
	jnc	tektt1			; nc = succeeded
	ret				; else failed to init, just return
tektt1: and	al,7fh			; force Tek chars to be 7 bits
	cmp	al,0			; NUL char?
	je	tekign			; e = yes, ignore it before logging
	push	ax
	call	getflgs			; get msy yflags into al
	mov	yflags,al
	test	al,capt			; capturing output?
	pop	ax
	jz	tektt4			; z = no, forget this part
	push	ax			; save char
	call	cptchr			; give it captured character
	pop	ax			; restore character and keep going
tektt4: test	yflags,trnctl		; debug? if so use tty mode
	jz	tektt5			; z = no
	cmp	al,DEL			; DEL char?
	jne	tektt4a			; ne = no
	mov	al,5eh			; make DEL a caret query mark
	call	outscrn
	mov	al,3fh			; the query mark
	call	outscrn
	jmp	short tekign
tektt4a:cmp	al,' '			; control char?
	jae	tektt4b			; ne = no
	push	ax
	mov	al,5eh			; caret
	call	outscrn
	pop	ax
	add	al,'A'-1		; make char printable
tektt4b:call	outscrn

tekign: ret				; Ignore this character

tektt5: call	tkscan			; scan for "ESC [ ? 3 8 l" exit code
tektt5a:cmp	al,0			; null char response?
	je	tekign			; e = yes, ignore the character
	cmp	al,' '			; control code?
	jb	tektt6			; b = yes, decode
	jmp	ttstate			; no, do current state
					; Control characters:
tektt6: cmp	al,GS			; Line plot command?
	jne	tektt7			; ne = no
	mov	visible,0		; Next move is invisible
	and	status,not txtmode	; set status report byte
	mov	ttstate,offset tekline	; expect coordinates next
	jmp	tektt12
tektt7: cmp	al,RS			; Incremental dot command?
	jne	tektt8			; ne = no
	and	status,not txtmode	; set status report
	mov	ttstate,offset tekrlin	; expect pen command next
	jmp	tektt12
tektt8: cmp	al,FS			; Point plot command?
	jne	tektt9			; ne = no
	mov	visible,0		; next move is invisible
	and	status,not txtmode	; set status report byte
	mov	ttstate,offset tekpnt
	jmp	tektt12
tektt9: cmp	al,US			; assert text mode? [bjh]
	jne	tektt10			; ne = no
	or	status,txtmode		; set status report byte
	mov	ttstate,offset tektxt	; Go to TEKTXT next time
	mov	bypass,0		; reset bypass condition
	jmp	tektt12
tektt10:cmp	al,ESCAPE		; Escape?
	jne	tektt11			; ne = no
	or	status,txtmode		; set status report byte
	cmp	ttstate,offset tekesc	; already in escape state?
	je	tektt14			; e = yes, nest no further
	push	ttstate			; current state
	pop	prestate		; save here as previous state
	mov	ttstate,offset tekesc	; next state parses escapes
	ret
tektt11:cmp	al,CAN			; Control X? (exits Tek sub mode)
	jne	tektt13			; ne = no, stay in current state
	cmp	ttstate,offset tekesc	; ESC Control-X?
	je	tektt13			; yes, parse it in tekesc code
	mov	ttstate,offset tektxt	; back to text mode
;	test	flags.vtflg,tttek	; main Tek emulator?
	test	denyflg,tekxflg		;disable auto exit/entry [jan]
	jnz	tektt12			; nz = yes, ignore the ^X
	call	tekend			; else exit sub mode
	mov	tekflg,0		; clear Tek sub mode flag
tektt12:mov	prestate,offset tektxt	; make previous state text
tektt14:ret
tektt13:jmp	ttstate			; let someone else worry about this
TEKEMU	ENDP

; End TEK emulation, recover previous screen
TEKEND	PROC	NEAR
	cmp	tekflg,0		; Tek sub mode active?
	jne	teknd0			; ne = yes
	ret				; else return as is.
teknd0: call termtog			;toggle terminal
	ret
TEKEND	ENDP

; State machine active while Tek is active. Senses ESC [ ? 3 8 l to exit
; Tek mode and return to either non-sub mode terminal or to a VT102.
; Plays back unmatched escape sequences. Enter with character in al.

tkscan	proc	near
	and	al,7fh			; strip high bit
	cmp	al,byte ptr tkoff	; start of Tek Off sequence?
	jne	tkscn1			; ne = no
	call	tkscn4			; playback previously matched chars
	mov	tkcnt,1			; count matched chars (one now)
	mov	tkoffs,al		; save full character, with high bit
	mov	al,0			; our temporary response
	jmp	short tkscnx		;  and exit

tkscn1: push	bx			; check for char in Tek Off sequence
	mov	bx,tkcnt		; number of chars matched in Tek Off
	mov	tkoffs[bx],al		; save this char
	cmp	al,byte ptr tkoff[bx]	; match expected char in sequence?
	pop	bx
	jne	tkscn3			; ne = no, play back partial match
	inc	tkcnt			; count new match
	mov	al,0			; our temporary response
	cmp	tkcnt,tkofflen		; matched all char in sequence?
	jne	tkscnx			; ne = not yet, wait for more
	mov	tkcnt,0			; clear counter
	cmp	flags.vtflg,tttek	;full terminal now?
	jne	tkscn2			; ne = no, a submode
      ;	 call	 termtog		 ; toggle terminal type[jan]
tkscn2: mov	al,CAN			; simulate arrival of Control-X
	jmp	short tkscnx		;  all done

tkscn3: call	tkscn4			; playback previously matched chars
	mov	tkcnt,0			; reset to no match and exit
tkscnx: ret				; common exit

					; local worker procedure
tkscn4: push	ax			; save break char (in al)
	push	cx			; playback partial sequence to screen
	mov	cx,tkcnt		; number of chars matched before break
	jcxz	tkscn4b			; z = none
	push	si
	mov	si,offset tkoffs	; string to be played back
tkscn4a:cld
	lodsb				; get a char into al
	push	cx
	push	si			; save these around tektt5a work
	call	tektt5a			; use it
	pop	si
	pop	cx
	loop	tkscn4a			; do all that came in previously
	pop	si
tkscn4b:pop	cx
	pop	ax			; recover break char
	ret
tkscan	endp


TEKTXT	proc	near			; Dispatch on text characters

	cmp	al,DEL			; RUBOUT?
	jne	tektx1			; ne = no
	mov	al,bs			; make BS
	jmp	short tektx7
tektx1: cmp	al,CR			; carriage return (^M)?
	je	tektx9			; e = yes
tektx2: cmp	al,LF			; line feed (^J)?
	je	tektx9			; e = yes
tektx3: cmp	al,FF			; form feed (^L)?
	jne	tektx4			; ne = no
	call	tekcls			; clear the screen
	jmp	short tektx8
tektx4: cmp	al,VT			; vertical tab (^K)?
	je	tektx7
	cmp	al,bell			; bell (^G)?
	jne	tektx5			; ne = no
	call	beep
	mov	bypass,0		; clear GIN mode bypass condition
	jmp	short tektx8
tektx5: cmp	al,tab			; horizontal tab (^I)?
	je	tektx7			; e = yes
tektx6: cmp	al,BS			; backspace (^H)?
	je	tektx7			; e = yes
	cmp	al,' '			; control char?
	jb	tektx8			; b = yes, ignore it
tektx7: cmp	bypass,0		; bypass mode off?
	jne	tektx8			; ne = no, it's on so skip display
	call	OUTSCRN			;output character to screen

tektx8: ret
tektx9: mov	bypass,0		; clear GIN mode bypass condition
	jmp	short tektx7
TEKTXT	endp

; Process escape sequences. Callable from msz terminal emulator.
; Enter with received character in AL. Escape sequences are generally
; treated as interruptions to the current plotting/text command. Screen
; clearing is the exception by causing a general emulator reset.
TEKESC	PROC	NEAR
	mov	bypass,0		; clear GIN mode bypass condition
	mov	ttstate,offset tekesc	; in case get here from msz file
	cmp	tekflg,0		; Tek mode active yet? (msz call)
	jne	tekesc1			; ne = yes
	call	tekini			; init now
	mov	prestate,offset tektxt	; set a previous state of text
	jnc	tekesc1			; nc = succeeded
	ret				; else failed to init, just return

tekesc1:cmp	al,'Z'			; ESC-Z Identify?
	jne	tekesc2			; ne = no
;	call	SENDID			; Send terminal identification
	jmp	tekescx

tekesc2:cmp	al,FF			; ESC-FF Clear screen?
	jne	tekesc3			; ne = no
	call	tekcls			; Clear screen
	mov	prestate,offset tektxt	; make previous state text mode
	jmp	tekescx			; Return to text mode after ESC-FF

tekesc3:cmp	al,ESCZ			; ESC-^Z Enter GIN mode?
	jne	tekesc4			; ne = no
	mov	bypass,1
	call	CROSHAIR		; Activate the cross-hairs
	jmp	tekescx
tekesc3a:call	beep			; tell the user we are unhappy
	jmp	tekescx			; and ignore the command

tekesc4:cmp	al,ENQ			; ESC-^E Enquiry for cursor position?
	jne	tekesc5			; ne = no
	mov	bypass,1		; set bypass mode
	call	SENDSTAT		; send status
	jmp	tekescx

tekesc5:cmp	al,CAN			; ESC Control-X?
	jne	tekesc6			; ne = no
	mov	bypass,1		; set bypass condition
	jmp	tekescx

tekesc6:cmp	al,3fh			; query mark? (ESC ? means DEL)
	jne	tekesc7			; ne = no
	mov	al,DEL			; replace with DEL code
	jmp	tekescx			; and process it as if received.

tekesc7:cmp	al,accent		; accent grave, line pattern series?
	jb	tekesc8			; b = no
	cmp	al,65h			; lowercase e?
	ja	tekescx			; a = beyond line pattern series
	push	bx
	mov	bl,al
	sub	bl,accent		; remove bias
	and	bl,7			; eight patterns, roll over excess
	mov	bh,0
	shl	bx,1			; make this a word index
	mov	bx,linetab[bx]		; get line pattern word
	mov	linepat,bx		; save in active word
	pop	bx			; return to previous mode

tekesc8:cmp	al,5bh			; right square bracket?
	jne	tekescx			; ne = no
;	jmp	tekcol			; no color on GRiD [jan]

tekescx:push	ax
	mov	ax,prestate		; get previous state
	mov	ttstate,ax		; restore it
	or	ax,ax			; test for none
	pop	ax
	jz	go2text			; z = none, use text mode
	clc
	ret				; resume previous state

go2text:mov	ttstate,offset tektxt	; Go to TEKTXT next time
	mov	lastc,0			; clear last drawing coordinate flag
	or	status,txtmode		; set text mode in status byte
	clc
	ret
TEKESC	ENDP



TEKLINE proc	near			; GS line drawing
	call	tekxyc			; parse coordinates from input bytes
	jnc	teklin1			; nc = not done yet
	mov	cl,visible		; get moveto or drawto variable
	call	tekdraw			; move that point
	mov	visible,1		; say next time we draw
teklin1:ret
TEKLINE endp

TEKPNT	proc	near			; FS plot single point
	call	tekxyc			; parse coordinates
	jnc	tekpnt1			; nc = not done yet
	mov	cl,0			; do not draw
	call	tekdraw			; move to the point
	mov	ax,si			; copy starting point to end point
	mov	bx,di			; ax,bx,si,di are in PC coordinates
	mov	cl,1			; make plot visible
	call	line			; draw the dot
	mov	visible,0		; return to invisibility
tekpnt1:ret
TEKPNT	endp

; Decode graphics x,y components. Returns carry set to say have all
; components for a line, else carry clear. Understands 4014 lsb extensions.
; Permits embedded escape sequences.
TEKXYC	proc	near
	cmp	al,CR			; Exit drawing on CR,LF,RS,US,FS,CAN
	je	tekghx			; e = yes, a cr
	cmp	al,LF			; these terminate line drawing cmds
	je	tekghx
	cmp	al,FS			; <FS>
	je	tekghx
	cmp	al,RS			; <RS>
	je	tekghx
	cmp	al,US			; <US>
	je	tekghx
	cmp	al,CAN			; and <CAN>
	je	tekghx			; BUT ignore other control chars
	cmp	al,20h			; Control char?
	jb	tekgh0			; b = yes, ignore it
	cmp	al,40h
	jb	tekgh2			; 20-3F are HIX or HIY
	cmp	al,60h			; 40-5F are LOX (causes beam movement)
	jb	tekgh4			; 60-7F are LOY
					; Extract low-order 5 bits of Y coord
	mov	ah,tek_loy		; Copy previous LOY to MSB (4014)
	mov	tek_lsb,ah
	and	al,1Fh			; LOY is 5 bits
	mov	tek_loy,al
	cmp	lastc,loy		; 2nd LOY in a row?
	je	tekgh1			; Yes, then LSB is valid
	mov	tek_lsb,0		; 1st one, clear LSB
tekgh1: mov	lastc,loy		; LOY seen, expect HIX (instead of HIY)
tekgh0: clc				; c clear = not completed yet
	ret
tekghx: jmp	go2text

			; Extract high-order 5 bits (X or Y, depending on lastc)
tekgh2: and	ax,1Fh			; Just 5 bits
	mov	cl,5
	shl	ax,cl			; Shift over 5 bits
	cmp	lastc,loy		; was last coordinate a low-y?
	je	tekgh3			; e = yes, parse hix
	mov	tek_hiy,ax		; this byte has HIY
	mov	lastc,hiy
	clc
	ret
tekgh3: mov	tek_hix,ax		; This byte has HIX
	mov	lastc,hix
	clc
	ret
tekgh4: and	al,1Fh			; Just 5 bits
	mov	tek_lox,al
	mov	lastc,lox
	mov	ax,tek_hix		; Combine HIX*32
	or	al,tek_lox		;  with LOX
	mov	bx,tek_hiy		; Same for Y
	or	bl,tek_loy
	stc				; set c to say completed operation
	ret
TEKXYC	endp

TEKRLIN proc	near			; RS relative line drawing
	cmp	al,' '			; Pen up command?
	jne	tekrli1			; ne = no, try pen down
	mov	visible,0		; do invisible movements
	jmp	short tekrli2		; do the command
tekrli1:cmp	al,'P'			; pen down command?
	jne	tekrli3			; ne = no, return to text mode
	mov	visible,1		; set visible moves

tekrli2:mov	ax,x_coord		; PC x coordinate of pen
	mov	bx,y_coord		;    y coordinate
	call	pctotek			; get current pen position in Tek coor
	mov	cl,0			; invisible, moveto
	call	tekdraw			; move that point, set oldx and oldy
	mov	ttstate,offset tekinc	; next get incremental movement cmds
	ret

tekrli3:mov	visible,0		; bad char, reset visibility
	push	prestate
	pop	ttstate			; restore previous state
	jmp	tektt5			; deal with the break char
TEKRLIN endp
					; interpret RS inc plot command byte
TEKINC	proc	near			; get movement character and do cmd
	cmp	al,'A'			; move right?
	jne	tekinc1			; ne = no
	inc	oldx			; adjust beam position
	jmp	short tekinc9
tekinc1:cmp	al,'E'			; move right and up?
	jne	tekinc2			; ne = no
	inc	oldx
	inc	oldy
	jmp	short tekinc9
tekinc2:cmp	al,'D'			; move up?
	jne	tekinc3			; ne = no
	inc	oldy
	jmp	short tekinc9
tekinc3:cmp	al,'F'			; move left and up?
	jne	tekinc4			; ne = no
	dec	oldx
	inc	oldy
	jmp	short tekinc9
tekinc4:cmp	al,'B'			; move left?
	jne	tekinc5			; ne = no
	dec	oldx
	jmp	short tekinc9
tekinc5:cmp	al,'J'			; move left and down?
	jne	tekinc6			; ne = no
	dec	oldx
	dec	oldy
	jmp	short tekinc9
tekinc6:cmp	al,'H'			; move down?
	jne	tekinc7			; ne = no
	dec	oldy
	jmp	short tekinc9
tekinc7:cmp	al,'I'			; move right and down?
	jne	tekincb			; ne = no, bad command
	inc	oldx
	dec	oldy
tekinc9:cmp	oldx,0			; too far left?
	jge	tekinc10		; ge = no
	mov	oldx,0			; else stop at the left margin
tekinc10:cmp	oldx,maxtekx-1		; too far left?
	jle	tekinc11		; le = no
	mov	oldx,maxtekx-1		; else stop that the left margin
tekinc11:cmp	oldy,maxteky-1		; above the top?
	jle	tekinc12		; le = no
	mov	oldy,maxteky-1		; else stop at the top
tekinc12:cmp	oldy,0			; below the bottom?
	jge	tekinc13		; ge = no
	mov	oldy,0			; else stop at the bottom
tekinc13:mov	ax,oldx			; ax is vector x end point
	mov	bx,oldy			; bx is vector y end point
	mov	cl,visible
	call	tekdraw			; move/draw to that point
	ret
tekincb:push	prestate		; bad character, exit inc plot mode
	pop	ttstate			; new state is previous state
	mov	visible,0
	jmp	tektt5			; reparse the bad char
TEKINC	endp


; Routine to trigger the crosshairs, wait for a key to be struck, and send
; the typed char (if printable ascii) plus four Tek encoded x,y position
; coordinates and then a carriage return.
; ax, cx, xcross, ycross operate in PC coordinates.

CROSHAIR PROC NEAR
	push	linepat			; save line drawing pattern
	mov	linepat,0ffffh		; reset line type to solid

	mov	ax,xmax			; right margin minus 7 dots
	add	ax,7
	mov	temp,ax			; right margin dot
crosha1:call	crosdraw		; draw the cross-hairs
	call	iseof			; is stdin at EOF?
	jc	crosha2			; c = yes, exit this mode now
	mov	ah,coninq		; DOS, quiet read char
	int	dos
	push	ax			; save char for later
	call	crosdraw		; erase cross hairs
	pop	ax
	or	al,al			; ascii or scan code returned
	jnz	arrow5			; nz = ascii char returned

	call	iseof			; is stdin at EOF?
	jc	crosha2			; c = yes, exit this mode now
	mov	ah,coninq		; read scan code
	int	dos
	cmp	al,0			; Control-Break?
	jne	crosha3			; ne = no, something else
crosha2:pop	linepat			; restore line pattern
	ret				; exit crosshairs mode

crosha3:cmp	al,homscn		; is it 'home'?
	jne	arrow1			; ne = no, try other keys
	mov	ax,temp			; right margin
	shr	ax,1			; central position
	mov	xcross,ax		; save PC coord for crosshair
	mov	ax,ybot			; last scan line
	shr	ax,1
	mov	ycross,ax		; this is the center of the screen
	jmp	crosha1			; home the crosshairs

arrow1: cmp	al,lftarr		; left arrow?
	jne	arrow2			; ne = no
	mov	cx,-1			; left shift
	jmp	short xkeys
arrow2: cmp	al,rgtarr		; right arrow?
	jne	arrow3			; ne = no
	mov	cx,1			; right shift
	jmp	short xkeys
arrow3: cmp	al,uparr		; up arrow?
	jne	arrow4			; ne = no
	mov	cx,-1			; up shift
	jmp	short vertkey
arrow4: cmp	al,dnarr		; down arrow?
	jne	arrow7			; ne = no, ignore it
	mov	cx,1			; down shift
	jmp	short vertkey

arrow7: cmp	al,shuparr		; shifted up arrow?
	jne	arrow8			; ne = no
	mov	cx,-10			; big up shift
	jmp	short vertkey
arrow8: cmp	al,shdnarr		; shifted down arrow?
	jne	badkey		       ; ne = no, send this key as is
	mov	cx,10			; big down shift
	jmp	short vertkey


badkey: call	beep			; tell user we don't understand
	jmp	crosha1			; keep going

					; Shifted keys yield ascii keycodes
arrow5: cmp	al,'C' and 1fh		; Control-C?
	je	crosha2			; e = yes, exit crosshairs mode now
	cmp	al,shlftarr		; shifted left arrow?
	jne	arrow6			; ne = no
	mov	cx,-10			; big left shift
	jmp	short xkeys
arrow6: cmp	al,shrgtarr		; shifted right arrow?
	jne	charkey			 ; ne = no
	mov	cx,10			; big right shift
	jmp	short xkeys

xkeys:	add	cx,xcross		; add increment
	jns	noxc			; gone too far negative?
	mov	cx,0			; yes - then make it 0
noxc:	cmp	cx,temp			; too far right?
	jb	xdraw9			; b = no
	mov	cx,temp			; yes - then make it the right
xdraw9: mov	xcross,cx		; new x value for cross hairs
	jmp	crosha1			; and redraw

vertkey:add	cx,ycross		; adjust cx
	jns	noyc			; gone negative?
	mov	cx,0			; yes then make 0
noyc:	cmp	cx,ybot			; too high?
	jb	yok
	mov	cx,ybot			; make it maximum
yok:	mov	ycross,cx		; save new y crosshair
	jmp	crosha1			; and redraw

charkey:call	clrbuf			; purge received data to date
	call	outmodem		; send the break character
	mov	ax,xcross		; set beam to xcross,ycross
	mov	bx,ycross		; must convert to Tek coordinates
	call	pctotek			; scale from PC screen coord to Tek
	push	ax			; save around drawing
	push	bx
	mov	cx,0			; just a move
	call	tekdraw			; moveto ax,bx in Tek coord
	pop	bx			; recover Tek y
	pop	ax			; recover Tek x
	call	sendpos			; send position report to host
	pop	linepat			; recover current line drawing pattern
	mov	ttstate,offset tektxt	; Go to TEKTXT next time
	mov	lastc,0			; clear last drawing coordinate flag
	or	status,txtmode		; set text mode in status byte
	ret
CROSHAIR ENDP

; CROSDRAW draws cross-hairs by XORing cross with picture.
; xcross and ycross are in PC coordinates.
CROSDRAW PROC	NEAR
	mov	si,xcross		; move to (xcross, ycross-10)
	mov	di,ycross
	sub	di,10			; half the size of the cross
	jns	crosd1			; no sign bit means ok
	mov	di,0			; else limit to start of screen
crosd1: mov	ax,si			; next, draw to (xcross, ycross+10)
	mov	bx,ycross		; make bottom stroke
	add	bx,10
	cmp	bx,ybot			; too large?
	jbe	crosd2			; be = no
	mov	bx,ybot			; vertical line to (xcross,ybot)
crosd2: mov	cx,0ffh			; invert pixels
	call	line			; and draw vertical
	sub	si,12			; move to (xcross-12, ycross)
	jns	crosd3			; no sign means ok
	mov	si,0			; else limit to start of line
crosd3: mov	di,ycross
	mov	bx,di
	mov	ax,xcross		; draw to (xcross+12, ycross)
	add	ax,12
	cmp	ax,temp			; temp is right margin, too large?
	jbe	crosd4			; be = no, ok
	mov	ax,temp			; max x value
crosd4: mov	cx,0ffh			; set XOR code
	call	line			; draw to (xcross+12, ycross)
	ret
CROSDRAW ENDP

; SENDPOS sends position of cross-hairs to the host.
; ax has Tek X and bx has Tek Y coord of center of crosshair
SENDPOS PROC NEAR
	push	bx			; preserve register
	call	sendxy			; send x coord
	pop	ax
	call	sendxy			; send y coord
	mov	al,cr			; follow up with cr
	call	outmodem
	ret
SENDPOS ENDP

; SENDXY sends value of ax as Tek encoded bytes
; ax is in Tek coordinates
SENDXY	PROC	NEAR
	shl	ax,1
	shl	ax,1			; move all but lower 5 bits to ah
	shl	ax,1
	shr	al,1
	shr	al,1			; move low five bits to low 5 bits
	shr	al,1
	or	ah,20h			; make it a printing char as per TEK
	xchg	al,ah			; send high 5 bits first
	call	outmodem
	xchg	al,ah			; then low five bits
	or	al,20h
	call	outmodem
	xchg	ah,al			; al is first sent byte
	ret
SENDXY	ENDP


SENDID	PROC NEAR			; Pretend VT100 with graphics option
	mov	bx,IDSEQ		; Get addr of string
sndid1: mov	al,[bx]			; Get char from sequence
	cmp	al,0			; End of sequence?
	jz	sndid0			; Yes, return
	call	OUTMODEM		; Send it out the port
	inc	bx
	jmp	sndid1
sndid0: ret
SENDID	ENDP

; SENDSTAT - send status and cursor position to host

SENDSTAT PROC NEAR
	mov	al,STATUS		; get tek status
	or	al,20h			; make it printable
	call	OUTMODEM		; and send it
	mov	ax,oldx			; now send x coordinate (oldx is Tek)
	call	SENDXY
	mov	ax,oldy			; and y coordinate (oldy is Tek coord)
	call	SENDXY
	mov	al,cr			; end with a cr
	call	OUTMODEM
	ret
SENDSTAT ENDP

; routine to send al to the modem port

OUTMODEM PROC	NEAR
	push	ax
	mov	ah,al
	call	outchr			; outchr reads from ah
	 nop				; ignore errors
	 nop
	 nop
	pop	ax
	ret
OUTMODEM ENDP

; Convert X and Y from PC coordinates to Tek coordinates. AX = X, BX = Y
; for both input and output.
pctotek proc	near
	mul	xdiv			; scale from PC screen coord to Tek
	div	xmult
	xchg	bx,ax			; save Tek x coord in bx
	neg	ax			; y axis. Turn upside down for Tek
	add	ax,ybot
	mul	ydiv			; scale y from PC screen coord to Tek
	div	ymult
	xchg	ax,bx			; ax has X, bx has Y in Tek coords
	ret
pctotek endp

; Routine to output character in AL to the screen.

OUTSCRN PROC NEAR			; Output one character to the screen
	cmp	bypass,0		; GIN mode bypass off?
	je	outscp			; e = yes
	ret				;  else ignore characters
outscp:					; Set Translation Input filter
	cmp	rxtable+256,0		; translation turned off?
	je	outsct			; e = yes, no translation
	push	bx
	mov	bx,offset rxtable	; address of translate table
	xlatb				; new char is in al
	and	al,7fh			; retain only lower seven bits
	pop	bx
outsct: mov	ccode,1			; normal text [jan]
	mov	si,ybot			; get last scan line
	inc	si			; number of scan lines
	sub	si,y_coord		; minus where char bottom needs to go
	jnc	outscc			; nc = enough space for char
					; took out more stuff [jan]
	mov	y_coord,0		; back to top of screen [jan]

outscc: push	ax
	mov	ax,xmax
	cmp	x_coord,ax		; beyond right margin?
	jbe	outsc3			; be = no
	mov	al,cr			; else simulate cr/lf
	call	putc			; before displaying current char
	mov	al,lf
	call	putc
outsc3: pop	ax
	call	putc			; routine to draw characters
	ret
OUTSCRN ENDP




; TEKCLS routine to clear the screen.
; Entry point tekcls1 clears screen without resetting current point.
TEKCLS	PROC	NEAR
	cmp	tekflg,0		; Tek sub mode active yet?
	jne	tekcls0			; ne = yes
	ret				; else ignore this call
tekcls0:mov	x_coord,0		; starting text coordinates
	mov	y_coord,8
	mov	oldx,0			; assumed cursor starting location
	mov	oldy,maxteky		;  top right corner (Tek coord)
	mov	scalex,0		; clear last plotted point (PC coord)
	mov	scaley,0
	mov	lastc,0			; last parsed x,y coordinate
	mov	visible,0		; make lines invisible
	mov	linepat,0ffffh		; reset line pattern to solid
	mov	ccode,1			; reset to ordinary writing
	mov	bypass,0		; clear bypass condition
	mov	ttstate,offset tektxt	; do displayable text
	push	ax
	mov	ax,xmax			; right margin minus 7 dots
	add	ax,7			; right most dot
	shr	ax,1			; central position
	mov	xcross,ax		; save PC coord for crosshair
	mov	ax,ybot			; last scan line
	shr	ax,1
	mov	ycross,ax		; this is the center of the screen
	pop	ax

tekcls1:push	ax			; save registers
	push	cx
	call	cmblnk			; clear the screen
tekcls7:mov	si,0			; starting x  (in case screen is
	mov	di,0			; starting y	cleared by user)
	pop	cx
	pop	ax
	ret
TEKCLS	ENDP



; Routine to draw a line on the screen, using TEKTRONIX coordinates.
; X coordinate in AX, 0=left edge of screen, 1023=right edge of screen.
; Y coordinate in BX, 0=bottom of screen, 779=top of screen.
; CL=0 - invisible move, CL=1 - draw a line, CL=0FFh - invert pixels on line

TEKDRAW PROC NEAR
	mov	si,scalex		; get old x already scaled
	mov	di,scaley		; get old y already scaled
	call	scale			; scale new end point to PC coords
	cmp	cl,0			; invisible drawing?
	je	moveto			; z = just move, skip draw part
	call	LINE			; draw the line
moveto: mov	x_coord,ax		; update text coordinates to match
	mov	y_coord,bx		;  last drawn point
	ret
TEKDRAW ENDP

; Scale TEKTRONIX coordinates to the currently defined screen coordinates
; AX holds X axis, BX holds Y axis. Both are changed from Tektronix coord
; to PC coordinates by this procedure.
SCALE	PROC	NEAR
	push	dx
	push	si
	mov	oldx,ax			; save current Tek x for next draw
	mov	oldy,bx			; save current Tek y for next draw
	mul	xmult			; scale x-coord
	mov	si,xdiv			; get the divisor
	shr	si,1			; halve it
	add	ax,si			; add in - to round to nearest integer
	adc	dx,0
	div	xdiv
	cmp	oldx,maxtekx-1		;at right of screen? [jan]
	jne	scale2		       ;ne means not at edge [jan]
	mov	ax,xmax		     ;right of display on PC [jan]
	add	ax,7		     ;[jan]
scale2: push	ax
	mov	ax,bx
	mul	ymult			; scale y-coord
	mov	si,ydiv			; get divisor
	shr	si,1			; halve it
	add	ax,si			; add in - to round to nearest integer
	adc	dx,0
	div	ydiv
	mov	bx,ybot
	sub	bx,ax			; Put new Y in right reg
	jns	scale3			; ns = not too far
	mov	bx,0
scale3: pop	ax			; Put new X in right reg
	mov	scalex,ax		; save scaled values
	mov	scaley,bx
	pop	si
	pop	dx
	ret
SCALE	ENDP

; LINE	Subroutine to plot a line with endpoints in AX,BX and SI,DI.
;	fast line drawing routine for the IBM PC
;
; Registers at CALL
; -----------------
; SI=Start X coord, all in PC coordinates
; DI=Start Y coord
; AX=End X coord
; BX=End Y coord
; CL=Color code: 1=draw foreground, 0=draw background, 0ffh=invert
; BP= line drawing pattern (is changed here by rotation)
; registers are all unchanged

LINE	PROC	NEAR
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	es
	mov	bp,linepat		; store active line pattern word in BP
	mov	ccode,cl	; save color code in ccode for use by plot()
			; first get coord to achieve increasing x; deltax >= 0
	sub	ax,si			; deltax = x2 - x1
	jge	line1			; ge = going to the right, as desired
	neg	ax			; make deltax non-negative
	sub	si,ax			; swap the x coordinates
	xchg	bx,di			; swap the y coordinates too
				; second, compute deltay. ax = deltax, si = x1
line1:	sub	bx,di			; deltay = y2 - y1
	call	psetup			; setup display adapter for plotting
					;  and setup es:di to screen memory
  ; Choose algorithm based on |deltay| < |deltax| (use shallow) else steep.
  ; We arrange matters such that both deltas are non-negative.
	cmp	bx,0			; deltay
	jge	line2			; ge = non-negative
	neg	linelen
	neg	bx			; make non-negative
line2:	cmp	bx,ax			; |deltay| versus |deltax|
	jbe	shallow			; be = do shallow algorithm
	jmp	steep			; else do steep algorithm

	; shallow algorithm, move along x, di=y1, bx=deltay, si=x1, ax=deltax
shallow:add	bx,bx			; bx = 2*deltay
	mov	cx,ax			; cx = number of steps (deltax here)
	inc	cx			; loop dec's cx before testing
	mov	dx,bx			; dx holds error
	sub	dx,ax			; error = 2*deltay - deltax
	add	ax,ax			; ax = 2*|deltax|
shal1:	call	plotptr			; Plot(x,y)
	cmp	dx,0
	jle	shal2			; le =	 error <= 0
	call	pincy			; increment y by one scan line
	sub	dx,ax			; error = error - 2*deltax
shal2:	add	dx,bx			; error = error + 2*deltay
	inc	si			; x = next dot right
	loop	shal1
shal3:	jmp	short plotex

	; steep algorithm, move along y, di=y1, bx=deltay, si=x1, ax=deltax
steep:	add	ax,ax			; ax = 2*deltax
	mov	dx,ax			; dx holds error
	sub	dx,bx			; error = 2*deltax(bx) - deltay (bx)
	mov	cx,bx			; cx = number of steps (deltay here)
	inc	cx			; loop dec's cx before testing
	add	bx,bx			; bx = 2*|deltay|
stee1:	call	plotptr			; Plot(x,y) x = ax, y = di
	cmp	dx,0
	jle	stee2			; le  error <= 0
	inc	si			; x = next dot right
	sub	dx,bx			; error = error - 2*deltay
stee2:	add	dx,ax			; error = error + 2*deltax
	call	pincy			; increment y
	loop	stee1
stee3:;;;jmp	plotex

plotex: mov	ccode,1			; reset to do foreground coloring
	pop	es
	pop	di
	pop	si
	pop	dx			; restore the world
	pop	cx
	pop	bx
	pop	ax
	ret
LINE	ENDP



;;;;;;;; CGA plot support routines
; The CGA graphics memory mapping in mode 6 (640 by 200) is 8 dots per byte,
; left most dot in the high bit, 80 bytes per scan line, scan line segments
; alternating between 0b800h (even lines 0, 2, ...) and 0ba00h (odd lines).
psetupc proc	near			; CGA setup for plotting
	push	ax
	push	cx
	mov	ax,linebytes
	mov	linelen,ax	 	; 40 bytes per scan line
	mov	cx,segscn		; small grid scn [jan]
	mov	es,cx
	mov	cx,di			; save copy of di, start y line
					; compute starting point in regen buff
	mov	ax,linebytes		;  bytes per line [jan]
	mul	di
	mov	di,ax			; di = di * linebytes
	pop	cx
	pop	ax
	ret
psetupc endp

pincyc	proc	near			; CGA inc y
	add	di,linelen		; add a line
	ret
pincyc	endp

pltcga	proc	near		; CGA plot(x,y). x is in si, y is in di
	push	bx		; used for HGA plot also.
	push	si
	push	di
	rol	bp,1			; rotate line pattern
	jnc	pltcg3			; nc = no bit to be plotted
	mov	bx,si			; want si/8 for bytes along line
	shr	si,1
	shr	si,1
	shr	si,1
	xor	si,1			;bytes in hl order on GRiD [jan]
	add	di,si			; starting point in regen buffer
	and	bx,0007h		; leave lower 3 bits for bit in byte
					; di = offset in regen buffer
	mov	bh,masktab[bx]		; 0-7 into bit mask in byte. x position
	mov	bl,ccode		; get line type code
	cmp	bl,1			; draw the bit?
	jne	pltcg1			; ne = no
	or	es:[di],bh		; drawn
	jmp	short pltcg3
pltcg1: cmp	bl,0			; draw in background (erase)?
	jne	pltcg2			; ne = no
	not	bh
	and	es:[di],bh		; erase the dots
	jmp	short pltcg3
pltcg2: xor	es:[di],bh		; xor in this color
pltcg3: pop	di
	pop	si
	pop	bx
	ret
pltcga	endp


; GPUTC - a routine to send text characters from font to true graphics boards
; such as EGA, Hercules or CGA. Char is in al. Drawing routine ptr is gcplot.

gputc	proc	near

	cmp	al,' '			; control character?
	jae	gputc1			; ae = no, display the char
	jmp	putctrl			; else handle controls at putctrl
gputc1: push	ax			; first save some registers
	push	bx
	push	cx
	push	es
	push	di
	mov	bl,al			; now BL has char to be displayed
	and	bl,7fh			; no high bits allowed here
					; set board mode
	mov	di,y_coord		; get current y coord (char bottom)
	sub	di,8			; start 8 lines higher
	jnc	gputc2			; nc = ok
	mov	di,0			; move up to first line
	mov	y_coord,8		; and reset scan line indicator
gputc2: call	psetup		; enter with di=line number, sets es:di to
				; start of line in display buf and
				; sets byte-wide plot mode
	mov	ax,x_coord		; compute regen buffer byte
	shr	ax,1			; want x_coord/8 for bytes along line
	shr	ax,1
	shr	ax,1
	xor	ax,1		   ;bytes in hl order on grid [jan]
	add	di,ax			; byte in regen buffer
	xor	bh,bh
	sub	bx,32			; characters in font start at 32
	shl	bx,1
	shl	bx,1			; 8 bytes per char - hence * 8
	shl	bx,1
	mov	cx,8			; 8 bytes (scan lines) to transfer
	call	gcplot			; call character plot routine
	call	incx			; move to next char position
	pop	di
	pop	es
	pop	cx
	pop	bx
	pop	ax
	ret
gputc	endp

putctrl proc	near			; CONTROL CHARS = cursor movement
	push	ax			; save character
	cmp	al,FF			; formfeed?
	jne	putct0			; ne = no
	call	TEKCLS			; FF clears the screen
	jmp	putctx
putct0: cmp	al,BS			; BS? sends (logical) cursor back one
	jne	putct2			; ne = no, try next
	mov	ax,x_coord
	sub	ax,8			; so delete 8 dots (move left)
	jns	putct1			; ns = non-negative
	mov	ax,0			; but not less than 0
putct1: mov	x_coord,ax		; and replace x coordinate
	mov	al,' '			; send a space
	call	putc
	sub	x_coord,8		; restore cursor
	jmp	putctx
putct2: cmp	al,tab			; tabs move forward one char position
	jne	putct4			; ne = not a tab
	call	incx			; let incx move cursor right one col
	jmp	putctx
putct3: mov	x_coord,ax
	jmp	putctx
putct4: cmp	al,cr			; <CR> means go to beginning of line
	jne	putct5
	mov	x_coord,0		; zero the x coordinate
	jmp	putctx
putct5: cmp	al,lf			; <LF> means go down 8 pixels (1 line)
	jne	putct7			; ne = not LF
	add	y_coord,8		; border managed by outscrn and incx
	jmp	putctx
putct7: cmp	al,vt			; <VT> move up screen 1 line (8 pixels)
	jne	putctx
	sub	y_coord,8		; subtract one line (8 pixels)
	jnc	putctx			; nc = space left
	mov	y_coord,8		; else set to top of screen
putctx: pop	ax
	ret
putctrl endp


incx	proc	near			; move the logical cursor right
	mov	ax,x_coord		; shift the (logical) cursor right
	add	ax,8			;  one character cell
	mov	x_coord,ax
	cmp	ax,xmax			; at end of the line?
	jbe	incx1			; b = no
	mov	x_coord,0		; wrap to next line
	add	y_coord,8		; next row
	mov	ax,ybot			; last scan line
	cmp	ax,y_coord		; below bottom line?
	jge	incx1			; ge = no
	mov	y_coord,ax		; set to bottom row
	mov	al,lf			; simulate a line feed operation
	call	outscrn			; invoke More message
incx1:	ret
incx	endp


; General Character plot routine. Enter with bx pointing at font array for
; char, cx = number of bytes in char font, es:di = screen memory.
; Worker for gputc.

gcgen	proc	near
gcgen1: mov	al,font[bx]		; Non-EGA systems: get bits from font
	cmp	ccode,1			; write in foreground?
	je	gcgen2			; e = yes
	xor	es:[di],al		; background or xor (same)
	jmp	short gcgen3
;;;;	mov	es:[di],al		; write desired pattern (no overwrite)
gcgen2: OR	es:[di],al		; write desired pattern (no overwrite)
gcgen3: inc	bx			; point to next byte of char pattern
	call	pincy			; next scan line (linelen is preset)
	loop	gcgen1			; and repeat until complete
	ret
gcgen	endp


teksave proc	near		; saves graphics screen
				; mimic procedure in msxgri.asm [jan]
	ret
teksave endp

tekrest proc	near		; saves graphics screen of page 0 in page 1
	push	si
	push	di
; need to mimic the procedure in msxgri.asm for restoring a screen
tekresx:pop	di
	pop	si
	ret
tekrest endp

code	ends
	end

