        Name msgap3
; File MSGAP3.ASM
; Tektronix emulator for use with MS Kermit/IBM.
; Edit history:
; Last edit 18 March 1988
; 18 Mar 1988 V2.30 adapted for the NEC APCIII -- RFGoeke
;	The NEC version uses only a single VRAM page which cannot be saved
; (because a mode select call clears the VRAM!) in your choice of green.
; The gbcol variable is used to indicate normal (0) or reverse (1) video.
; For readability, a linefeed was set to 10 pixels.
;	NEC also does not respond well to DOS keyboard calls; use BIOS
; 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
; Converted to IBM PCs by Brian Holley, Cambridge Univ.
; 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-Z turns on the crosshairs (not on 4006 or 4025)
; 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.
; 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.
; =============================================================================
;
; - ctrl-g (BEL) from line gives beep in tek mode
; - characters better placed in relation to current beam position
;       in EGA and Hercules modes
;   characters OR-ed into place rather than overwriting
; - add SET TERMINAL GRAPHICS NONE -    this ignores the start-up ESC-FF
;                                       for Tektronix
; - add MonoEGA mode for monochrome graphics on an EGA
;
; version 2.29/t3
;  changes - stop control characters from echoing to screen in TEKEMU
;          - show version on name in MSSDEF.H
; version 2.29b
; changes with this version:  - faster line drawing, using direct write to
;                               memory rather than BIOS calls
;                             - support for Hercules, Olivetti, EGA
;                             - minor bug fixes

; adapted to IBM PC June 1987 by        Brian Holley,
;                                       Faculty of Economics and Politics
;                                       University of Cambridge, England
;                                       Email: BJH6@UK.AC.CAM.PHX

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

        include mssdef.h

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

screen  equ     19h                     ; bios screen call -- NEC
kbint	equ	18H			; bios keyboard call -- NEC

uparr   equ     39h                     ; DOS scan codes for arrow keys -- NEC
dnarr   equ     3Ch                     ; these are also the "extended" codes
lftarr  equ     3Ah
rgtarr  equ     3Bh
homscn  equ     3Dh                     ; DOS home screen scan code -- NEC
shuparr equ     0B4h                    ; "extended" codes for CTRL-Arrows
shdnarr equ     0B7h
shlftarr equ    0B5h
shrgtarr equ    0B6h

; Graph_mode for different systems:
; NEC resolution = Olivetti (640 x 400)
; Though we set mode for color, BIOS will go to B&W if adaptor board absent
olivetti equ    9                       ; Olivetti's Hi-res - 50 lines text

segcga  equ     0A800h                  ; CGA, AT&T/Olivetti -- NEC !!!

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

att_low_mask    equ     1fH             ; Various NEC attribute-related equates
att_overline    equ     01H             ; this is all NEC version stuff RFG
att_blink       equ     02H
att_rev_video   equ     04H
att_underline   equ     08H
att_intensity   equ     04H             ; same as reverse video

col_high_mask   equ     0E0H
nec_black       equ     00H             ; This table gives colors       RFG
nec_blue        equ     20H             ; (only bits 8,7,6 count)
nec_red         equ     40H
nec_magenta     equ     60H
nec_green       equ     80H
nec_cyan        equ     0A0H
nec_yellow      equ     0C0H
nec_white       equ     0E0H

datas   segment public 'datas'
        extrn   flags:byte, portval:word, rxtable:byte, vtemu:byte
;        extrn   tv_mode:byte		; NEC omits

scrsave dw	?	; segment addr of memory for screen save (NEC)

xmult   dw      ?                       ; scaling factor for x is
xdiv    dw      ?                       ;     xmult/xdiv
ymult   dw      ?                       ; scaling factor for y is
ydiv    dw      ?                       ;     ymult/ydiv
xmax    dw      ?                       ;
ybot    dw      ?                       ;

; required for Hercules screen handling

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      'NEC_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
                                ; local variables for LINE plotting routine
graph_mode db   0                       ; graphics video mode, default is none
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 (NEC omit)
gbcol   db      0                       ; graphics background color
moremsg db      ' More >'
mormsglen equ   $-moremsg               ; length of message
ccode   db      0                       ; temp for holding plot color code
linelen dw      0                       ; offset increment between scan lines
putc    dw      ?                 ; ptr to plot a character routine
psetup  dw      ?                 ; ptr to plot setup routine
pfin    dw      ?                 ; ptr to plot cleanup routine
pincy   dw      ?                 ; ptr to inc y routine
plotptr dw      ?                 ; ptr to dot plot routine
segscn  dw      ?                 ; actual screen segment to use
; ANSI Escape sequence to turn off Media Copy (Print Controller Off)
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
repbuf  db      6 dup (0)               ; crosshairs report buf
repcnt  db      0                       ; number of untouched chars in repbuf
temp    dw      0

; 8*8 font for Hercules, CGA, and EGA TEK mode
; - 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)
datas   ends

code    segment public 'code'
        extrn   outchr:near, beep:near, scrseg:near, cmblnk:near
        extrn   clrmod:near, savescr:near, cptchr:near, pcwait:near
        extrn   restscr:near, getflgs:near, clrbuf:near, vtans52:near

        assume  cs:code, ds:datas, es:nothing

; Initialise TEK mode by setting high resolution screen, etc

;The Olivetti has (639,399) as the coordinate of the lower-right corner.
;Calculate endpoint X=(5/8)*(HIX*32+LOX), Y=399-(20/39)*(HIY*32+LOY)

tekini  PROC NEAR
        push    ax                      ; do presence tests. [jrd]
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    es

; NEC handles flow control in hardware; see SERINIT in msxap3

; NEC uses green graphic plane (only)

        mov     gbcol,0			; NEC: this is normal video

        push    si                      ; NEC
        mov     ah,15                   ; get current screen mode
        int     screen
        pop     si                      ; NEC
        cmp     al,3                    ; in a mono/color text mode (2/3)?
        jbe     tekin1                  ; be = yes
;        cmp     al,mono                 ; mono text mode (7)?
;        je      tekin1                  ; e = yes
        cmp     tekflg,0                ; are we active as Tek device now?
        je      tekin1                  ; e = no
        jmp     tekin13                 ; yes, don't redo graphics setup
tekin1: mov     curmode,al              ; save mode here
        mov     ah,3                    ; get cursor position
        xor     bh,bh                   ; page 0
        int     screen
        mov     cursor,dx               ; save position
        call    savescr                 ; save text screen
                                        ; Presence tests.
tekin2: 
        mov     xmult,5                 ; CGA. Scale TEK to PC by 640/1024
        mov     xdiv,8                  ;  so that 0-1023 converts to 0-639
        mov     xmax,640-8              ; x-coord of rightmost character
tekin7:
        mov     graph_mode,olivetti     ; Olivetti
        mov     gpage,0                 ; only page 0 with 640 by 400 mode
        mov     segscn,segcga           ; use cga screen segment (0b800h)
        mov     psetup,offset psetupn   ; plot setup routine for NEC
        mov     plotptr,offset pltcga   ; cga dot plot routine
        mov     pfin,offset pfinc       ; cleanup routine
        mov     pincy,offset pincym     ; inc y routine (NEC is straight)
        mov     putc,offset gputc       ; character display routine
        mov     ybot,399                ; bottom of screen is y = 399
        mov     ymult,20                ; Olivetti vertical scale = 400/780
        mov     ydiv,39                 ; same as cga setup

                                        ; Set Graphics mode
;tekin13:
tekin14:mov     ah,0                    ; set screen mode
        mov     al,graph_mode           ;  to this screen mode
tekin15:int     screen                  ; Bios Set Mode.
        mov     ax,100                  ; wait 100 millisec
        call    pcwait                  ; NEC requires >65 millisec pause here
	mov	ah,1			; and kill cursor while we wait
tekin13: mov	ch,80h
	int	screen

tekin16:mov     tekflg,1                ; starting Tek sub mode
;        cmp     inited,0                ; inited yet?  NEC didn't save
;        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, for ega coloring
;        jmp     short tekin20           ; flow control in hardware on NEC
;tekin19:call    tekrest                 ; not saved on NEC
;tekin20:mov     ax,flow                 ; get flow control word
;        xchg    ah,al                   ; get xon into al
;        cmp     al,0                    ; able to send xon?
;        je      tekin21                 ; e = no
;        call    outmodem                ; tell host xon
;tekin21:clc                             ; clear carry for success
;        jmp     short tekin23
;tekin22:stc                             ; set carry for failure
tekin23:pop     es
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
tekini  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
        cmp     al,0                    ; null char response?
        je      tekign                  ; e = yes, ignore the character
                                        ; check for echo of crosshair report
        cmp     repcnt,0                ; any chars need matching in report?
        je      tektt5a                 ; e = no
        push    bx                      ; yes
        mov     bx,6                    ; number of bytes in crosshairs rpt
        sub     bl,repcnt               ; number of chars needing matching
        cmp     al,repbuf[bx]           ; received same as current rpt char?
        pop     bx
        jne     tektt5a                 ; ne = mismatch, stop echo test
        dec     repcnt                  ; say one more matched
        clc                             ; absorb without comment
        ret                             ; stay in this state
tektt5a:mov     repcnt,0                ; clear report count
        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
        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
        mov     ttstate,offset tektxt   ; back to text mode
        test    flags.vtflg,tttek       ; main Tek emulator?
        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:			; NEC can't save (VRAM is destroyed by mode switch)
	call    tekcls			; clear screen to avoid flash
teknd1: mov     ah,0                    ; set video mode
        mov     al,curmode              ; restore previous screen mode
        int     screen                  ; revert to text screen
        mov     ax,100                  ; wait 100 millisec
        call    pcwait                  ; NEC requires >65 millisec pause here
        call    restscr                 ; restore text screen
        mov     dx,cursor               ; saved cursor position
        mov     bh,0                    ; page 0
        mov     ah,2                    ; set cursor
        int     screen
        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       ; are we a full Tek terminal now?
        jne     tkscn2                  ; ne = no, a submode
        call    vtans52                 ; toggle terminal type, in msyibm
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 printer
        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>
tektx1: cmp     al,CR                   ; ^M Carriage return?
        je      tektx7                  ; e = yes
tektx2: cmp     al,LF                   ; ^J LineFeed?
        je      tektx7                  ; e = yes
tektx3: cmp     al,FF                   ; ^L Formfeed?
        jne     tektx4                  ; ne = no
        call    tekcls                  ; clear the screen
        jmp     short tektx8
tektx4: cmp     al,VT                   ; ^K vertical tab?
        je      tektx7
        cmp     al,bell                 ; ^G bell on line?
        jne     tektx5                  ; ne = no
        call    beep
        jmp     short tektx8
tektx5: cmp     al,Tab                  ; Tab?
        jne     tektx6                  ; ne = no
        mov     al,' '                  ; make it a space
tektx6: cmp     al,BS                   ; ^H backspace?
        je      tektx7                  ; e = yes
        cmp     al,' '                  ; control char?
        jb      tektx8                  ; b = yes, ignore it
tektx7: call    OUTSCRN                 ; output character to the screen
tektx8: ret
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     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
;        cmp     graph_mode,mono         ; Monochrome text mode?
;        je      tekesc3a                ; e = yes, no crosshairs in text mode
        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
        call    SENDSTAT                ; send status
        jmp     tekescx

tekesc5:cmp     al,accent               ; accent grave, line pattern series?
        jb      tekescx                 ; b = no
        cmp     al,65h                  ; lowercase e?
        ja      tekescx                 ; a = beyond line pattern series
        push    bx
        mov     bl,al
        sub     bl,accent               ; remove bias
        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

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      go2text                 ; e = yes, a cr
        cmp     al,LF                   ; these terminate line drawing cmds
        je      go2text
        cmp     al,FS                   ; <FS>
        je      go2text
        cmp     al,RS                   ; <RS>
        je      go2text
        cmp     al,US                   ; <US>
        je      go2text
        cmp     al,CAN                  ; and <CAN>
        je      go2text                 ; 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
                      ; 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, by, xcross, ycross operate in PC coordinates.
; NEC mods to use BIOS key fetch and key translations; since shift-arrow
; is not a unique code, use CTRL-arrow instead

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

crosha0:mov     ax,xmax                 ; right margin minus 7 dots
        add     ax,7
        mov     temp,ax                 ; right margin 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
crosha1:call    crosdraw                ; draw the cross-hairs
;        mov     ah,coninq               ; DOS, quiet read char
;        int     dos
	mov	ah,0			; NEC call, returns
	int	kbint			; ah = scan code, al = ASCII
					; if al = 0, ah = "extended code"
        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

;        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

	cmp	al,0
	je	crosha3			; e = extended code keys
	cmp     al,3			; Control-C?
        jne     charkey
	pop	linepat			; restore line pattern
	ret				; exit crosshairs mode

charkey:call    clrbuf                  ; purge received data to date
        mov     repcnt,6                ; set length of report string
        mov     repbuf,al               ; store first report character
        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
        ret

crosha3:
	xchg	ah,al
	cmp     al,homscn               ; is it 'home'?
        je      crosha0                 ; e = yes
        jmp     short arrow1            ; else try the arrow keys

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     arrow5                  ; ne = no, ignore it
        mov     cx,1                    ; down shift
        jmp     short vertkey
arrow5:
        cmp     al,shlftarr             ; shifted left arrow?
        jne     arrow6                  ; ne = no
        mov     cx,-64                  ; big left shift
        jmp     short xkeys
arrow6: cmp     al,shrgtarr             ; shifted right arrow?
        jne     arrow7                  ; ne = no
        mov     cx,64                   ; big right shift
        jmp     short xkeys
arrow7: cmp     al,shuparr              ; shifted up arrow?
        jne     arrow8                  ; ne = no
        mov     cx,-32                  ; big up shift
        jmp     short vertkey
arrow8: cmp     al,shdnarr              ; shifted down arrow?
        jne     badkey
        mov     cx,32                   ; big down shift
        jmp     short vertkey

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

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

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-12)
        mov     di,ycross
        sub     di,12                   ; 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+12)
        mov     bx,ycross               ; make bottom stroke
        add     bx,12
        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
        mov     word ptr repbuf+1,ax    ; first word
        pop     ax
        call    sendxy                  ; send y coord
        mov     word ptr repbuf+3,ax    ; second word
        mov     al,cr                   ; follow up with cr
        mov     repbuf+5,al             ; last report character
        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
                                        ; 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     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
                                        ; else give "More >" message
        push    ax                      ; save current char
        mov     ax,mormsglen            ; characters in More message
        shl     ax,1
        shl     ax,1
        shl     ax,1                    ; times 8 bits/character
        neg     ax                      ; (note: leave last char cell empty)
        add     ax,xmax                 ; right justify
        mov     x_coord,ax              ; set starting x dot
        mov     ax,ybot
        mov     y_coord,ax              ; set starting y line
;        mov     ah,gfcol                ; get screen coloring
;        mov     al,gbcol
;        push    ax                      ; save it
        xchg    ah,al                   ; interchange colors for message
;        mov     gfcol,ah
        mov     gbcol,1			; NEC: set reverse video
        mov     si,offset moremsg       ; give More message
        push    cx
        mov     cx,mormsglen
outsclf:cld
        lodsb                           ; read a byte from string
        call    putc                    ; display the string
        loop    outsclf                 ; repeat for all string chars
        pop     cx
;        pop     ax                      ; restore normal video
;        mov     gfcol,ah
        mov     gbcol,0			; NEC: set nromal video
        mov     ah,coninq               ; read keyboad via DOS
        int     dos                     ; wait for keystroke
        or      al,al                   ; scan code being returned?
        jne     outscl3                 ; ne = no
        mov     ah,coninq               ; clear away scan code too
        int     dos
outscl3:call    tekcls                  ; clear the screen
        pop     ax                      ; recover current character
        cmp     al,lf                   ; just a line feed?
        jne     outscc                  ; ne = no, display it
        ret                             ;  else ignore the line feed

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     ttstate,offset tektxt   ; do displayable text
tekcls1:push    ax                      ; save registers
        push    cx
tekcls2:mov     di,0                    ; point to start of screen, di=row
        call    psetup                  ; setup graphics routine and es:di
        mov     cx,8000h                ; Olivetti, 400 lines times 80 bytes
tekcls3:cld                             ; clear screen directly of text stuff
        mov     al,0                    ; color is black
        rep     stosb                   ; clear the bytes
        jmp     short tekcls7
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
        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     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: call    pfin                    ; cleanup boards after plotting
        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

pfinc   proc    near                    ; CGA end of plot board cleanup
        ret
pfinc   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
        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

pincym  proc    near                    ; Monochrome inc y
        add     di,linelen              ; includes sign
        ret
pincym  endp

;;;;;;;;;;;;;;; NEC plot support routines
; In modes 8 and 9 (640 by 400) we have 8 dots per byte,
; left most dot in the high bit, 80 bytes per scan line, scan line segments
; are totally sequential.
psetupn proc    near
        push    ax
        mov     linelen,80              ; for y going down screen by incy
        mov     ax,segscn               ; base segment of display memory
        mov     es,ax
        mov     ax,80
        mul     di
        mov     di,ax                   ; di = di * 80
        pop     ax
        ret
psetupn endp

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

gputc   proc    near
        cmp     al,' '                  ; control character?
        jae     gputc1                  ; ae = no, display the char
        jmp     putctrl                 ; else handle controls at putctrl
gputc1: push    bx                      ; first save some registers
        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
        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

gputc4: mov     al,font[bx]             ; Non-EGA systems: get bits from font
	cmp	gbcol,0
	je	gputc5
	xor	al,0FFh
gputc5: mov     es:[di],al              ; write desired pattern (no overwrite)
        inc     bx                      ; point to next byte of char pattern
        call    pincy                   ; inc to next line (linelen is preset)
        loop    gputc4                  ; and repeat 'til complete
gputx:  call    incx                    ; move to next char position
        pop     di
        pop     es
        pop     cx
        pop     bx
        ret
gputc   endp

putctrl proc    near                    ; CONTROL CHARS = cursor movement
        cmp     al,FF                   ; formfeed?
        jne     putct0                  ; ne = no
        call    TEKCLS                  ; FF clears the screen
        ret
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
        ret
putct2: cmp     al,tab                  ; tabs move forward one char position
        jne     putct4                  ; ne = not a tab
        mov     ax,x_coord
        add     ax,8                    ; so add 8
        cmp     ax,xmax                 ; zero if off edge of screen
        jbe     putct3
        mov     x_coord,0
        mov     al,lf
        jmp     short putct5            ; process our new line feed
putct3: mov     x_coord,ax
        ret
putct4: cmp     al,cr                   ; <CR> means go to beginning of line
        jne     putct5
        mov     x_coord,0               ; zero the x coordinate
        ret
putct5: cmp     al,lf                   ; <LF> means go down 8 pixels (1 line)
        jne     putct7                  ; ne = not LF
        add     y_coord,10              ; NEC version has 2 pixel space
        ret
putct7: cmp     al,vt                   ; <VT> move up screen 1 line (8 pixels)
        jne     putctx
        sub     y_coord,10              ; NEC uses 10
        jnc     putctx                  ; nc = space left
        mov     y_coord,10              ; NEC uses 10
putctx: 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

code    ends
        end
