DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦62d5550b3⟧ TextFile

    Length: 68748 (0x10c8c)
    Types: TextFile
    Names: »msg55x.asm«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦71044c191⟧ »EurOpenD3/misc/kermit.ms-2.32.tar.Z« 
        └─⟦31f2d420d⟧ 
            └─⟦this⟧ »msg55x.asm« 

TextFile

    NAME    msg55x
; File MSG55X.ASM
; Kermit system dependent module for Sanyo MBC-55x
; Sanyo mods by Robert W. Babcock and Joseph H. White
; Tektronix emulator for use with MS Kermit/IBM.
; Edit history:
; Last edit 19 April 1988, strip out code for other than CGA boards
; 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    10h            ; bios screen call

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    '8'            ; ascii codes for shifted arrows
shdnarr equ    '2'
shlftarr equ    '4'
shrgtarr equ    '6'

                    ; Graph_mode for different systems:
cga    equ    6            ; highest resolution mode for CGA
mono    equ    7            ; real monochrome display adapter
colorega equ    14            ; Low-res mode, color EGA
monoega equ    15            ; mono ega needs mode 15
ega    equ    16            ; Hi-res mode - EGA
olivetti equ    72            ; Olivetti's Hi-res - 50 lines text
hercules equ    255            ; pseudo mode for Hercules graphics
; Note: IBM VGA mode 18, 640 by 480, can be used by setting "ega" above
; to 18 and modify ybot to be 479 and ymult to be 48 at label tekin5.
; The code will scale everything appropriately for the new screen size, but
; there will be insufficient memory to retain the entire graphics image.
; Do this at your own risk, please, until PS/2 Tech Refs are available. [jrd]

segega    equ    0a000h            ; segments of display memory, EGA
segcga    equ    0b800h            ; CGA, AT&T/Olivetti
seghga    equ    0b000h            ; HGA
segmono equ    0b000h            ; Monochrome

                    ; Hercules equates:
index    equ    03b4h            ; 6845 index register
cntrl    equ    03b8h            ; Display mode control port
hstatus equ    03bah            ; status port
scrn_on equ    8            ; bit to turn screen on
grph    equ    2            ; graphics mode
text    equ    20h            ; text mode
config    equ    03bfh            ; configuration port
genable equ    1            ; enable graphics, page 0 only

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

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

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    ?            ;

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    'IBM_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
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    mputc            ; ptr to plot a character routine
psetup    dw    psetupc            ; ptr to plot setup routine
pfin    dw    pfinc            ; ptr to plot cleanup routine
pincy    dw    pincyc            ; ptr to inc y routine
plotptr dw    pltcga            ; ptr to dot plot routine
segscn    dw    0b800h            ; 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 IBM PC CGA card has (639,199) as the coordinate of the lower-right corner.
;Calculate endpoint X=(5/8)*(HIX*32+LOX), Y=199-(10/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
    mov    bx,portval        ; get port flow control chars:
    mov    bx,[bx].flowc        ; bh=xon, bl=xoff or both are nulls
    mov    flow,bx            ; save here
    mov    ax,bx            ; get flow control word
    cmp    al,0            ; able to do xoff?
    je    tekin0            ; e = no
    call    outmodem        ; tell host xoff while we change modes
tekin0: mov    bx,vtemu.att_ptr    ; emulator screen color ptr
    mov    al,[bx]
    mov    gfcol,al        ; save foreground color
    and    gfcol,0fh        ; save just foreground bits
    and    al,70h            ; select background color, no bold
    mov    cl,4
    shr    al,cl            ; get background colors
    mov    gbcol,al        ; set graphics background color

    mov    ah,15            ; get current screen mode
    int    screen
    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    graph_mode,cga        ; Color. Assume CGA
    mov    segscn,segcga        ; assume cga screen segment
    mov    gpage,0            ; graphics page 0 but no page 1
    mov    putc,offset gputc    ; CGA character display routine
    mov    psetup,offset psetupc    ; CGA plot setup routine
    mov    plotptr,offset pltcga    ; CGA dot plot routine
    mov    pfin,offset pfinc    ; CGA cleanup routine
    mov    pincy,offset pincyc    ; CGA inc y routine
    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
    mov    ymult,10        ; vertical scale for IBM is 200/780
    mov    ydiv,39            ;
    mov    ybot,199        ; Bottom of screen is Y=199
                    ; test for CGA
tekin11:mov    graph_mode,cga        ; set CGA high resolution graphics
    mov    segscn,segcga        ; CGA screen segment
    jmp    tekin13

                    ; Set Graphics mode
tekin13:
tekin14:mov    ah,0            ; set screen mode
    mov    al,graph_mode        ;  to this screen mode
    cmp    gpage,0            ; only page 0 available?
    je    tekin15            ; e = yes, and watch for Bios errors
    cmp    inited,0        ; first time through?
    je    tekin15            ; e = yes, clear the page of old junk
    or    al,80h            ; save regen buffer (save area too)
tekin15:int    screen            ; Bios Set Mode.

tekin16: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, for ega coloring
    jmp    short tekin20
tekin19:call    tekrest            ; restore old graphics screen
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: call    teksave            ; save graphics screen to page 1
teknd1: mov    ah,0            ; set video mode
    mov    al,curmode        ; restore previous screen mode
    int    screen            ; revert to text screen
    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.

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
    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

crosha3: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    badkey            ; ne = no, ignore it
    mov    cx,1            ; 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,-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    charkey            ; ne = no, send this key as is
    mov    cx,32            ; big down shift
    jmp    short vertkey

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
    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
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,al
    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,al
    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,4000h        ; CGA, 200 lines times 80 bytes worth
tekcls3:cld                ; clear screen directly of text stuff
    mov    al,0            ; color is black
    rep    stosb            ; clear the bytes
    jmp    short tekcls7

tekcls6:push    es            ; clear screen by scrolling up
    call    cmblnk            ; clear screen, for Environments
    pop    es

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

;;;;;;;;;;;;;;;;;;;;;;;;;; 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    linelen,80        ; 80 bytes per scan line
    mov    cx,segscn
    mov    es,cx
    mov    cx,di            ; save copy of di, start y line
                    ; compute starting point in regen buff
    shr    di,1            ; half the lines in each bank
    mov    ax,80            ; 80 bytes per line
    mul    di
    mov    di,ax            ; di = di * 80 / 2
    test    cx,1            ; even or odd line
    jz    psetc1            ; z = even
    add    di,2000h        ; offset to odd bank (seg 0ba00h)
psetc1: and    di,3fffh
    pop    cx
    pop    ax
    ret
psetupc endp

pincyc    proc    near            ; CGA inc y
    cmp    linelen,0        ; increasing or decreasing y?
    jl    pinyc2            ; l = decreasing
    cmp    di,2000h        ; in upper bank now?
    jb    pinyc1            ; b = no, in lower bank
    add    di,linelen        ; add a line
pinyc1: add    di,2000h        ; switch banks
    and    di,3fffh        ; roll over address
    ret
pinyc2: cmp    di,2000h        ; in upper bank now?
    jae    pinyc4            ; ae = yes
    add    di,linelen        ; subtract a line
pinyc4: add    di,2000h        ; switch banks
    and    di,3fffh        ; roll over address
    ret
pincyc    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

; 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
    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,8        ; border managed by outscrn and incx
    ret
putct7: cmp    al,vt            ; <VT> move up screen 1 line (8 pixels)
    jne    putctx
    sub    y_coord,8        ; - so subtract 8
    jnc    putctx            ; nc = space left
    mov    y_coord,8        ; else set to top of screen
putctx: ret
putctrl endp

mputc    proc    near            ; MONO put char in AL via Bios
    push    ax            ; updates x_coord,y_coord with
    push    bx            ; new cursor position
    push    cx
    push    dx
    mov    ah,0            ; marker for cursor setting not needed
    cmp    al,' '            ; control code?
    jae    mputc1            ; ae = no, printable
    call    putctrl            ; do cursor arithmetic
    mov    ah,1            ; marker to set cursor but no display

mputc1: push    ax            ; save char and marker
    mov    cl,3            ; char cell is 8 x 8 dots
    mov    ax,x_coord        ; get resulting cursor PC positions
    shr    ax,cl
    mov    dl,al            ; column
    mov    ax,y_coord
    sub    ax,8            ; minus 8 dots, like other modes
    jnc    mputc2            ; nc = non-negative
    mov    ax,0            ; else start at the top
    mov    y_coord,8        ; here too
mputc2: shr    ax,cl
    mov    dh,al            ; row
    mov    ah,2            ; set cursor to x_coord,y_coord
    mov    bh,0            ; page 0
    int    screen
    pop    ax
    cmp    ah,0            ; write a char in al?
    jne    mputcx            ; ne = no
    mov    ah,09h            ; write char at cursor postion
    mov    cx,1            ; just one char
    mov    bh,0            ; page 0
    mov    bl,gfcol        ; foreground coloring
    int    screen
    inc    dl            ; next column
    mov    ah,2            ; set real cursor ahead of last char
    int    screen
    call    incx            ; move logical cursor
mputcx: pop    dx
    pop    cx
    pop    bx
    pop    ax
    ret
mputc    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


teksave proc    near        ; saves graphics screen from page 0 to page 1
    push    si
    push    di
    cmp    gpage,0        ; only graphics page 0 on display board?
    je    teksavx        ; e = yes, no saving possible here
    mov    si,segscn    ; segment (!) of current screen
teksavx:pop    di
    pop    si
    ret
teksave endp

tekrest proc    near        ; saves graphics screen of page 0 in page 1
    push    si
    push    di
    cmp    gpage,0        ; only graphics page 0 on display board?
    jne    tekres0        ; ne = no, more so work to do here
    call    tekcls1        ;  else clear the screen to color it
    jmp    short tekresx    ;  and exit
tekres0:mov    di,segscn    ; segment (!) of new graphics screen
tekresx:pop    di
    pop    si
    ret
tekrest endp

code    ends
    end