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

⟦e5265469f⟧ TextFile

    Length: 117611 (0x1cb6b)
    Types: TextFile
    Names: »msgibm.asm«

Derivation

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

TextFile

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


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

        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                     ; IBM 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
toshiba equ     74h                     ; Toshiba T3100, like Olivetti
vaxmate equ     0D0h                    ; DEC VAXmate II, like Olivetti
hercules equ    255                     ; pseudo mode for Hercules graphics
; Note: IBM VGA modes 17 & 18, 640 by 480, can be used by setting "ega" above
; to 17 or 18 and modifying 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.
; Manual override SET TERMINAL GRAPHICS VGA accomplishes these two steps.

segega  equ     0a000h                  ; segments of display memory, EGA,VGA
segcga  equ     0b800h                  ; CGA, AT&T/Olivetti and relatives
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+2                     ; enable graphics (1) on two pages (2)

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

; required for Hercules screen handling

gtable  db      35h,2dh,2eh,7           ; bytes for 6845 controller
        db      5bh,2,57h,57h           ; - graphics mode
        db      2,3,0,0

ttable  db      61h,50h,52h,0fh         ; bytes for 6845 controller
        db      19h,6,19h,19h           ; - text mode
        db      2,0dh,0bh,0ch

attlogo db      'OLIVETTI'              ; Olivetti M24/28, AT&T 6300 rom id
attlen  equ     $-attlogo               ; length
toshlogo db     '  TT33110000  TTOOSSHHIIBBAA' ; Toshiba T3100 logo
toshlen equ     $-toshlogo              ; length
declogo db      'Copyright Digital Equipment Corp' ; DEC VAXmate
declen  equ     $-declogo
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
tekgraf db      0               ; Tek graphics board selection (def=auto)
                                ; 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
tfcol   db      0                       ; temp foreground color
tbcol   db      0                       ; temp background color
lastd   db      0,0                     ; worker for ESC [ Pn ; Pn m scanner
colortb db      0,4,2,6,1,5,3,7         ; color reversed-bit setting bytes
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      psetupm                 ; ptr to plot setup routine
pincy   dw      pincym                  ; ptr to inc y routine
plotptr dw      pltmon                  ; ptr to dot plot routine
gcplot  dw      gcgen                   ; ptr to char plot routine
segscn  dw      0b800h                  ; actual screen segment to use
                                        ; ANSI Escape sequence to exit Tek mode
tkoff   db      escape,'[?38l'          ; Exit Tek mode escape sequence
tkofflen equ    $-tkoff                 ; length of sequence
tkoffs  db      6 dup (0)               ; received chars in rcv'd sequence
tkcnt   dw      0                       ; counter of matched char in tkoffs
bypass  db      0                       ; GIN mode bypass condition (0=off)
temp    dw      0

; 8*8 font for Hercules and such, CGA, and EGA
; - allows 43 lines, and 80 (90 for Hercules) chars per line.
; all printing (?) characters from <space> to <del> - two characters per line
; 8 bits per scan line, given top line first, 8 scan lines.
font    db      0,0,0,0,0,0,0,0,               18h,18h,18h,18h,18h,0,18h,0
        db      6ch,6ch,6ch,0,0,0,0,0,         36h,36h,7fh,36h,7fh,36h,36h,0
        db      0ch,3fh,68h,3eh,0bh,7eh,18h,0, 60h,66h,0ch,18h,30h,66h,06h,0
        db      38h,6ch,6ch,38h,6dh,66h,3bh,0, 0ch,18h,30h,0,0,0,0,0
        db      0ch,18h,30h,30h,30h,18h,0ch,0, 30h,18h,0ch,0ch,0ch,18h,30h,0
        db      0,18h,7eh,3ch,7eh,18h,0,0,     0,18h,18h,7eh,18h,18h,0,0
        db      0,0,0,0,0,18h,18h,30h,         0,0,0,7eh,0,0,0,0
        db      0,0,0,0,0,18h,18h,0,           0,06h,0ch,18h,30h,60h,0,0
        db      3ch,66h,6eh,7eh,76h,66h,3ch,0, 18h,38h,18h,18h,18h,18h,7eh,0
        db      3ch,66h,06h,0ch,18h,30h,7eh,0, 3ch,66h,06h,1ch,06h,66h,3ch,0
        db      0ch,1ch,3ch,6ch,7eh,0ch,0ch,0, 7eh,60h,7ch,06h,06h,66h,3ch,0
        db      1ch,30h,60h,7ch,66h,66h,3ch,0, 7eh,06h,0ch,18h,30h,30h,30h,0
        db      3ch,66h,66h,3ch,66h,66h,3ch,0, 3ch,66h,66h,3eh,06h,0ch,38h,0
        db      0,0,18h,18h,0,18h,18h,0,       0,0,18h,18h,0,18h,18h,30h
        db      0ch,18h,30h,60h,30h,18h,0ch,   0,0,0,7eh,0,7eh,0,0,0
        db      30h,18h,0ch,06h,0ch,18h,30h,   0,3ch,66h,0ch,18h,18h,0,18h,0
        db      3ch,66h,6eh,6ah,6eh,60h,3ch,   0,3ch,66h,66h,7eh,66h,66h,66h,0
        db      7ch,66h,66h,7ch,66h,66h,7ch,   0,3ch,66h,60h,60h,60h,66h,3ch,0
        db      78h,6ch,66h,66h,66h,6ch,78h,   0,7eh,60h,60h,7ch,60h,60h,7eh,0
        db      7eh,60h,60h,7ch,60h,60h,60h,   0,3ch,66h,60h,6eh,66h,66h,3ch,0
        db      66h,66h,66h,7eh,66h,66h,66h,   0,7eh,18h,18h,18h,18h,18h,7eh,0
        db      3eh,0ch,0ch,0ch,0ch,6ch,38h,   0,66h,6ch,78h,70h,78h,6ch,66h,0
        db      60h,60h,60h,60h,60h,60h,7eh,   0,63h,77h,7fh,6bh,6bh,63h,63h,0
        db      66h,66h,76h,7eh,6eh,66h,66h,   0,3ch,66h,66h,66h,66h,66h,3ch,0
        db      7ch,66h,66h,7ch,60h,60h,60h,   0,3ch,66h,66h,66h,6ah,6ch,36h,0
        db      7ch,66h,66h,7ch,6ch,66h,66h,   0,3ch,66h,60h,3ch,06h,66h,3ch,0
        db      7eh,18h,18h,18h,18h,18h,18h,   0,66h,66h,66h,66h,66h,66h,3ch,0
        db      66h,66h,66h,66h,66h,3ch,18h,   0,63h,63h,6bh,6bh,7fh,77h,63h,0
        db      66h,66h,3ch,18h,3ch,66h,66h,   0,66h,66h,66h,3ch,18h,18h,18h,0
        db      7eh,06h,0ch,18h,30h,60h,7eh,   0,7ch,60h,60h,60h,60h,60h,7ch,0
        db      0,60h,30h,18h,0ch,06h,0,0,     3eh,06h,06h,06h,06h,06h,3eh,0
        db      18h,3ch,66h,42h,0,0,0,0,       0,0,0,0,0,0,0,0ffh
        db      30h,18h,0ch,0,0,0,0,0,         0,0,3ch,06h,3eh,66h,3eh,0
        db      60h,60h,7ch,66h,66h,66h,7ch,0, 0,0,3ch,66h,60h,66h,3ch,0
        db      06h,06h,3eh,66h,66h,66h,3eh,0, 0,0,3ch,66h,7eh,60h,3ch,0
        db      0eh,18h,18h,3ch,18h,18h,18h,0, 0,0,3eh,66h,66h,3eh,06h,3ch
        db      60h,60h,7ch,66h,66h,66h,66h,0, 18h,0,38h,18h,18h,18h,3ch,0
        db      18h,0,38h,18h,18h,18h,18h,70h, 60h,60h,66h,6ch,78h,6ch,66h,0
        db      38h,18h,18h,18h,18h,18h,3ch,0, 0,0,76h,7fh,6bh,6bh,63h,0
        db      0,0,7ch,66h,66h,66h,66h,0,     0,0,3ch,66h,66h,66h,3ch,0
        db      0,0,7ch,66h,66h,7ch,60h,60h,0, 0,3eh,66h,66h,3eh,06h,07h
        db      0,0,6ch,76h,60h,60h,60h,0,     0,0,3eh,60h,3ch,06h,7ch,0
        db      30h,30h,7ch,30h,30h,30h,1ch,0, 0,0,66h,66h,66h,66h,3eh,0
        db      0,0,66h,66h,66h,3ch,18h,0,     0,0,63h,6bh,6bh,7fh,36h,0
        db      0,0,66h,3ch,18h,3ch,66h,0,     0,0,66h,66h,66h,3eh,06h,3ch
        db      0,0,7eh,0ch,18h,30h,7eh,0,     0ch,18h,18h,70h,18h,18h,0ch,0
        db      18h,18h,18h,0,18h,18h,18h,0,   30h,18h,18h,0eh,18h,18h,30h,0
        db      31h,6bh,46h,0,0,0,0,0,         8 dup (0ffh)
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
        extrn   iseof:near, beep:near
        assume  cs:code, ds:datas, es:nothing

; Initialise TEK mode by setting high resolution screen, etc

tekini  PROC NEAR
        push    ax                      ; do presence tests
        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     gcplot,offset gcgen     ; General character plot routine
        mov     psetup,offset psetupc   ; CGA plot setup routine
        mov     plotptr,offset pltcga   ; CGA dot plot 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
        mov     al,tekgraf              ; user video board specification
        cmp     al,0                    ; auto-sensing?
        je      tekin2c                 ; e = yes (default)
        cmp     al,1                    ; user wants CGA?
        jne     tekin2a                 ; ne = no
        jmp     tekin13                 ; do CGA
tekin2a:cmp     al,4                    ; user wants Hercules?
        jne     tekin2b                 ; ne = no
        jmp     tekin8                  ; do Hercules
tekin2b:cmp     al,5                    ; user wants AT&T style?
        jne     tekin2c                 ; ne = no
        jmp     tekin7                  ; do AT&T kind
                                        ; do auto-sensing of display board
                                        ; test for EGA
tekin2c:mov     ax,1200H                ; EGA: Bios alternate select
        mov     bl,10H                  ; Ask for EGA info
        mov     bh,0ffH                 ; Bad info, for testing
        mov     cl,0fH                  ; Reserved switch settings
        int     screen                  ; EGA, are you there?
        and     cl,0fh                  ; four lower switches
        cmp     cl,0cH                  ; Test reserved switch settings
        jb      tekin3                  ; b = ega present
        jmp     tekin7                  ; else no EGA, check other adapters

tekin3: mov     ax,40h                  ; check Bios 40:87h for ega being
        mov     es,ax                   ;  the active display adapter
        test    byte ptr es:[87h],8     ; is ega active?
        jz      tekin3a                 ; z = yes
        jmp     tekin7                  ; ega is inactive, check others
tekin3a:cmp     bl,1                    ; is there 128KB on ega board?
        jb      tekin4                  ; b = less, so no screen saves
        mov     gpage,1                 ; >=128 KB, use two graphics pages
tekin4: mov     graph_mode,ega          ; assume high resolution color
        cmp     cl,3                    ; high resolution color?
        je      tekin5                  ; e = yes
        cmp     cl,9                    ; high resolution color?
        je      tekin5                  ; e = yes
        mov     graph_mode,monoega      ; assume mono monitor on ega board
        test    bh,1                    ; ega mono mode in effect?
        jnz     tekin5                  ; nz = yes
        mov     graph_mode,colorega     ; say ordinary cga on ega board, 64KB
        mov     gpage,1                 ; is enough memory with 200 scan lines
        jmp     short tekin5a           ; use current cga parameters
tekin5: mov     ybot,349                ; text screen bottom is 349 on EGA
        mov     ymult,35                ;
        mov     ydiv,78                 ; scale y by 350/780
tekin5a:mov     segscn,segega           ; use ega screen segment
        mov     psetup,offset psetupe   ; plot setup routine
        mov     plotptr,offset pltega   ; ega dot plot routine
        mov     pincy,offset pincye     ; inc y routine
        mov     putc,offset gputc       ; character display routine
        mov     gcplot,offset gcega     ; EGA character plot routine
        call    fixcolor                ; correct color mapping for some bds
        jmp     tekin13                 ; end of EGA part, do VGA tests below

tekin7: mov     ax,0fc00h               ; Olivetti/AT&T 6300, check rom id
        mov     es,ax
        mov     di,0                    ; start here
        mov     graph_mode,olivetti     ; Olivetti
        mov     cx,attlen               ; length of logo
        mov     si,offset ATTLOGO       ; master string
        repe    cmpsb                   ; do a match
        je      tekin7c                 ; e = a match
        mov     di,0050h                ; look here too
        mov     si,offset ATTLOGO
        mov     cx,attlen
        repe    cmpsb
        je      tekin7c                 ; e = a match
        mov     di,2014h                ; and look here
        mov     si,offset ATTLOGO
        mov     cx,attlen
        repe    cmpsb                   ; do a match
        je      tekin7c                 ; e = a match, else try other types
tekin7a:mov     graph_mode,toshiba
        mov     ax,0f000h               ; Check for Toshiba T3100, rom scan
        mov     es,ax
        mov     di,0014h                ; start here
        mov     si,offset TOSHLOGO      ; master string
        mov     cx,toshlen              ; length
        repe    cmpsb                   ; do a match
        je      tekin7c                 ; e = a match, else try other types
tekin7b:mov     graph_mode,vaxmate      ; DEC VAXmate II
        mov     ax,0f000h               ; Check for VAXmate II rom signature
        mov     es,ax
        mov     di,0e000h               ; start here
        mov     si,offset DECLOGO       ; master string
        mov     cx,declen               ; length
        repe    cmpsb                   ; do a match
        jne     tekin7d                 ; ne = mismatch, try other types

                                        ; Olivetti/AT&T, Toshiba, VAXmate
tekin7c:mov     gpage,0                 ; only page 0 with 640 by 400 mode
        mov     segscn,segcga           ; use cga screen segment (0b800h)
        mov     psetup,offset psetupo   ; plot setup routine
        mov     plotptr,offset pltcga   ; cga dot plot routine
        mov     pincy,offset pincyh     ; inc y routine (Herc style addresses)
        mov     putc,offset gputc       ; character display routine
        mov     gcplot,offset gcgen     ; General character plot routine
        mov     ybot,399                ; bottom of screen is y = 399
        mov     ymult,20                ; vertical scale = 400/780
        mov     ydiv,39                 ; same as cga setup
        jmp     tekin13

tekin7d:cmp     curmode,mono            ; mono text mode?
        je      tekin8                  ; e = yes
        jmp     tekin11                 ; ne = no, try cga
                                        ; test for Hercules
tekin8: call    scrseg                  ; get screen segment, test Environment
        cmp     tv_mode,0               ; Environment active?
        je      tekin8a                 ; e = no, ok to test for Hercules
        jmp     tekin10                 ; don't do Herc mode, do Mono
tekin8a:mov     dx,hstatus              ; Herc status port
        in      al,dx                   ; read it
        mov     bl,al                   ; save here
        and     bl,80h                  ; remember retrace bit
        mov     cx,0ffffh               ; do many times (for fast machines)
tekin8b:mov     dx,hstatus              ; check status port
        in      al,dx
        and     al,80h                  ; select bit
        jmp     $+2                     ; use a little time
        cmp     bl,al                   ; did it change?
        loope   tekin8b                 ; test again if not
        je      tekin10                 ; e = no change in bit, not Herc
        mov     graph_mode,hercules     ; say have Herc board
        mov     segscn,seghga           ; assume hga screen segment
        mov     putc,offset gputc       ; character display routine
        mov     gcplot,offset gcgen     ; General character plot routine
        mov     psetup,offset psetuph   ; plot setup routine to use
        mov     plotptr,offset pltcga   ; use cga dot plot routine for Herc
        mov     pincy,offset pincyh     ; inc y routine
        mov     xmult,45                ; Scale TEK to Hercules by 720/1024
        mov     xdiv,64                 ;  so that 0-1023 converts to 0-719
        mov     xmax,720-8              ; x-coord of rightmost character
        mov     ymult,87                ; vertical scale for Hercules is
        mov     ydiv,195                ;  348/780
        mov     ybot,347                ; bottom of screen is y = 347
        mov     ax,seghga               ; segment of Herc video display
        mov     es,ax
        mov     al,es:[8000h]           ; read original contents, page 1
        not     byte ptr es:[8000h]     ; write new pattern
        mov     ah,es:[8000h]           ; read back
        not     byte ptr es:[8000h]     ; restore original contents
        not     ah                      ; invert this too
        cmp     ah,al                   ; same (memory present?)
        jne     tekin9                  ; ne = not same, no memory there
        mov     gpage,1                 ; say two pages of display memory
tekin9: jmp     tekin13
                                        ; set to MONO
tekin10:mov     graph_mode,mono         ; force monochrome adapter text
        mov     segscn,segmono          ; assume mono screen segment
        call    scrseg                  ; Environments: get virtual screen
        mov     segscn,ax               ;  seg returned in ax and es:di
        mov     gpage,0
        mov     putc,offset mputc       ; character display routine
        mov     psetup,offset psetupm   ; plot setup routine to use
        mov     plotptr,offset pltmon   ; use hga dot plot routine
        mov     pincy,offset pincym     ; inc y routine
        mov     xmult,5                 ; Scale TEK to mono 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 mono is 200/780
        mov     ydiv,39
        mov     ybot,200                ; bottom of screen is y = 200 for Bios
        jmp     tekin13                 ; Uses TEXT mode, for safety

                                        ; 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:cmp     graph_mode,hercules     ; Hercules?
        jne     tekin14                 ; ne = no
        call    hgraf                   ; set Herc graphics mode, clear regen
        jmp     short tekin16           ; restore screen
tekin14:mov     ah,0                    ; set screen mode
        mov     al,graph_mode           ;  to this screen mode
        cmp     tekgraf,3               ; user wants "VGA" modes (640x480)?
        jne     tekin14a                ; ne = no
        cmp     al,monoega              ; yes, allow high resolution stuff?
        jb      tekin14a                ; b = no
        cmp     al,ega                  ; ditto
        ja      tekin14a                ; a = no
        add     al,2                    ; use modes 17(b/w) and 18(10)(color)
        mov     ybot,479                ; text screen bottom is 479 on VGA
        mov     ymult,48
tekin14a: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
        mov     al,gfcol
        mov     tfcol,al                ; remember current coloring
        mov     al,gbcol
        mov     tbcol,al
        call    tekcls                  ; clear screen, for ega coloring
        jmp     short tekin20
tekin19:call    tekrest                 ; restore old graphics screen
        mov     al,tfcol                ; and coloring
        mov     gfcol,al
        mov     al,tbcol
        mov     gbcol,al
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

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

;Terminal emulation. Enter with received character in AL.

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

tekign: ret                             ; Ignore this character

tektt5: call    tkscan                  ; scan for "ESC [ ? 3 8 l" exit code
tektt5a:cmp     al,0                    ; null char response?
        je      tekign                  ; e = yes, ignore the character
        cmp     al,' '                  ; control code?
        jb      tektt6                  ; b = yes, decode
        jmp     ttstate                 ; no, do current state
                                        ; Control characters:
tektt6: cmp     al,GS                   ; Line plot command?
        jne     tektt7                  ; ne = no
        mov     visible,0               ; Next move is invisible
        and     status,not txtmode      ; set status report byte
        mov     ttstate,offset tekline  ; expect coordinates next
        jmp     tektt12
tektt7: cmp     al,RS                   ; Incremental dot command?
        jne     tektt8                  ; ne = no
        and     status,not txtmode      ; set status report
        mov     ttstate,offset tekrlin  ; expect pen command next
        jmp     tektt12
tektt8: cmp     al,FS                   ; Point plot command?
        jne     tektt9                  ; ne = no
        mov     visible,0               ; next move is invisible
        and     status,not txtmode      ; set status report byte
        mov     ttstate,offset tekpnt
        jmp     tektt12
tektt9: cmp     al,US                   ; assert text mode? [bjh]
        jne     tektt10                 ; ne = no
        or      status,txtmode          ; set status report byte
        mov     ttstate,offset tektxt   ; Go to TEKTXT next time
        mov     bypass,0                ; reset bypass condition
        jmp     tektt12
tektt10:cmp     al,ESCAPE               ; Escape?
        jne     tektt11                 ; ne = no
        or      status,txtmode          ; set status report byte
        cmp     ttstate,offset tekesc   ; already in escape state?
        je      tektt14                 ; e = yes, nest no further
        push    ttstate                 ; current state
        pop     prestate                ; save here as previous state
        mov     ttstate,offset tekesc   ; next state parses escapes
        ret
tektt11:cmp     al,CAN                  ; Control X? (exits Tek sub mode)
        jne     tektt13                 ; ne = no, stay in current state
        cmp     ttstate,offset tekesc   ; ESC Control-X?
        je      tektt13                 ; yes, parse it in tekesc code
        mov     ttstate,offset tektxt   ; back to text mode
        test    flags.vtflg,tttek       ; main Tek emulator?
        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
        cmp     graph_mode,hercules     ; Hercules?
        jne     teknd1                  ; ne = no
        call    htext                   ; yes then set up Hercules text mode
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 screen
        mov     cx,tkcnt                ; number of chars matched before break
        jcxz    tkscn4b                 ; z = none
        push    si
        mov     si,offset tkoffs        ; string to be played back
tkscn4a:cld
        lodsb                           ; get a char into al
        push    cx
        push    si                      ; save these around tektt5a work
        call    tektt5a                 ; use it
        pop     si
        pop     cx
        loop    tkscn4a                 ; do all that came in previously
        pop     si
tkscn4b:pop     cx
        pop     ax                      ; recover break char
        ret
tkscan  endp


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

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

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

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

tekesc3:cmp     al,ESCZ                 ; ESC-^Z Enter GIN mode?
        jne     tekesc4                 ; ne = no
        cmp     graph_mode,mono         ; Monochrome text mode?
        je      tekesc3a                ; e = yes, no crosshairs in text mode
        mov     bypass,1                ; turn on GIN mode bypass conditon
        call    CROSHAIR                ; Activate the cross-hairs
        jmp     tekescx
tekesc3a:call   beep                    ; tell the user we are unhappy
        jmp     tekescx                 ; and ignore the command

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

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

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

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

tekesc8:cmp     al,5bh                  ; right square bracket?
        jne     tekescx                 ; ne = no
        jmp     tekcol                  ; start coloring scan

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
; Parse ESC [ Pn ; Pn m
; where Pn = 30-37 foreground color, 40-47 background color, ANSI standard
TEKCOL  proc    near
        mov     word ptr lastd,0        ; clear parsing flags used below
        mov     ttstate,offset tekco1   ; resume parsing below
        clc
        ret
tekco1: cmp     lastd,'3'               ; units digit in 30 series?
        jne     tekco2                  ; ne = no
        inc     lastd+1                 ; count argument
        sub     al,'0'                  ; ascii to binary
        cmp     al,7                    ; numeric?
        jbe     tekco1a                 ; be = yes
        jmp     tekco10                 ; a = no, error
tekco1a:push    bx
        mov     bl,al
        mov     bh,0
        mov     al,byte ptr colortb[bx] ; reverse coloring
        pop     bx
        and     tfcol,not (7)           ; retain intensity bit
        or      tfcol,al                ; remember foreground color
        mov     lastd,0                 ; clear parsing flag
        ret

tekco2: cmp     lastd,'4'               ; units digit in 40 series?
        jne     tekco4                  ; ne = no
        inc     lastd+1                 ; count argument
        sub     al,'0'
        cmp     al,7                    ; numeric?
        ja      tekco10                 ; a = no, error
        push    bx
        mov     bl,al
        mov     bh,0
        mov     al,byte ptr colortb[bx] ; reverse coloring
        pop     bx
        mov     tbcol,al                ; remember background color
        mov     lastd,0                 ; clear parsing flag
        ret

tekco4: cmp     lastd,0                 ; looking for tens digit?
        jne     tekco10                 ; ne = yes, error
        cmp     al,';'                  ; separator?
        jne     tekco5                  ; ne = no
        ret                             ; ignore it

tekco5: cmp     al,'0'                  ; remove intensity, set b/w?
        jne     tekco6                  ; ne = no
        mov     tfcol,7                 ; regular white
        mov     tbcol,0                 ;  on black
        inc     lastd+1                 ; count argument
        ret

tekco6: cmp     al,'1'                  ; intensity bit?
        jne     tekco7                  ; ne = no
        and     tfcol,not (8)
        or      tfcol,8                 ; set foreground intensity
        inc     lastd+1                 ; count argument
        ret

tekco7: cmp     al,'m'                  ; end of sequence
        je      tekco8                  ; e = yes
        cmp     al,'3'
        jb      tekco10                 ; b = not allowed tens digit
        cmp     al,'4'
        ja      tekco10                 ; a = not allowed tens digit
        mov     lastd,al                ; remember tens digit
        inc     lastd+1                 ; count argument
        ret

tekco8: cmp     lastd+1,0               ; number of ansi arguments, zero?
        ja      tekco9                  ; a = no, got some
        mov     tbcol,0                 ; none is same as 0, set b/w
        mov     tfcol,7
tekco9: mov     al,tbcol                ; success, store coloring
        mov     gbcol,al                ; set background color
        mov     al,tfcol
        mov     gfcol,al                ; set foreground color
tekco10:mov     word ptr lastd,0        ; clear argument and number of args
        call    fixcolor                ; do special ega corrections
        mov     al,gfcol                ; update these in case error
        mov     tfcol,al
        mov     al,gbcol
        mov     tbcol,al
        jmp     tekescx                 ; finish escape state
TEKCOL  endp

; Revise screen color codes for ega boards with mono displays and limited
; memory.
fixcolor proc   near
        cmp     graph_mode,ega          ; one of these ega modes?
        je      fixcol0                 ; e = yes
        cmp     graph_mode,colorega
        je      fixcol0
        cmp     graph_mode,monoega
        je      fixcol0
        ret                             ; else ignore color corrections
fixcol0:mov     ah,gfcol
        mov     al,gbcol
        cmp     graph_mode,monoega      ; monochrome display?
        jne     fixcol3                 ; ne = no
        test    al,7                    ; bright backgound?
        jnz     fixcol1                 ; nz = yes
        mov     ah,1                    ; normal foreground
        test    gfcol,8                 ; intensity on?
        jz      fixcol1                 ; z = no
        mov     ah,5                    ; say bright foreground
fixcol1:test    al,7                    ; black backgound?
        jz      fixcol2                 ; z = yes
        mov     al,1                    ; regular video
fixcol2:cmp     ah,al                   ; same color in both?
        jne     fixcol3                 ; ne = no
        mov     ah,1                    ; make foreground regular
        mov     al,0                    ;  and background black
fixcol3:mov     gfcol,ah
        mov     gbcol,al
        cmp     gpage,0                 ; minimal memory (64KB mono and ega)?
        ja      fixcol4                 ; a = no, enough, else strange mapping
        mov     al,gfcol                ; fix coloring to map planes C0 to C1
        and     al,5                    ; and C2 to C3 (as 0, 3, 0Ch, or 0Fh)
        mov     ah,al                   ; make a copy
        shl     ah,1                    ; duplicate planes C0, C2 in C1, C3
        or      al,ah                   ; merge the bits
        mov     gfcol,al                ; store proper foreground color
        mov     al,gbcol                ; repeat for background color
        and     al,5
        mov     ah,al
        shl     ah,1
        or      al,ah
        mov     gbcol,al
fixcol4:ret
fixcolor endp

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

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

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

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

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

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

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


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

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

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

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

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

arrow1: cmp     al,lftarr               ; left arrow?
        jne     arrow2                  ; ne = no
        mov     cx,-1                   ; left shift
        jmp     short xkeys
arrow2: cmp     al,rgtarr               ; right arrow?
        jne     arrow3                  ; ne = no
        mov     cx,1                    ; right shift
        jmp     short xkeys
arrow3: cmp     al,uparr                ; up arrow?
        jne     arrow4                  ; ne = no
        mov     cx,-1                   ; up shift
        jmp     short vertkey
arrow4: cmp     al,dnarr                ; down arrow?
        jne     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,-10                  ; big left shift
        jmp     short xkeys
arrow6: cmp     al,shrgtarr             ; shifted right arrow?
        jne     arrow7                  ; ne = no
        mov     cx,10                   ; big right shift
        jmp     short xkeys
arrow7: cmp     al,shuparr              ; shifted up arrow?
        jne     arrow8                  ; ne = no
        mov     cx,-10                  ; big up shift
        jmp     short vertkey
arrow8: cmp     al,shdnarr              ; shifted down arrow?
        jne     charkey                 ; ne = no, send this key as is
        mov     cx,10                   ; 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
        call    outmodem                ; send the break character
        mov     ax,xcross               ; set beam to xcross,ycross
        mov     bx,ycross               ; must convert to Tek coordinates
        call    pctotek                 ; scale from PC screen coord to Tek
        push    ax                      ; save around drawing
        push    bx
        mov     cx,0                    ; just a move
        call    tekdraw                 ; moveto ax,bx in Tek coord
        pop     bx                      ; recover Tek y
        pop     ax                      ; recover Tek x
        call    sendpos                 ; send position report to host
        pop     linepat                 ; recover current line drawing pattern
        mov     ttstate,offset tektxt   ; Go to TEKTXT next time
        mov     lastc,0                 ; clear last drawing coordinate flag
        or      status,txtmode          ; set text mode in status byte
        ret
CROSHAIR ENDP

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

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

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


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

; SENDSTAT - send status and cursor position to host

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

; routine to send al to the modem port

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

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

; Routine to output character in AL to the screen.

OUTSCRN PROC NEAR                       ; Output one character to the screen
        cmp     bypass,0                ; GIN mode bypass off?
        je      outscp                  ; e = yes
        ret                             ;  else ignore characters
outscp:                                 ; Set Translation Input filter
        cmp     rxtable+256,0           ; translation turned off?
        je      outsct                  ; e = yes, no translation
        push    bx
        mov     bx,offset rxtable       ; address of translate table
        xlatb                           ; new char is in al
        and     al,7fh                  ; retain only lower seven bits
        pop     bx
outsct: mov     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
        push    cx
        mov     cx,mormsglen            ; characters in More message
        mov     ax,cx
        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     ccode,1                 ; write in foreground colors
        push    cx
        mov     al,DEL                  ; fill all pixels
outscm1:call    putc                    ; write
        loop    outscm1
        pop     cx
        push    cx
        mov     al,BS                   ; backup to overwrite with More text
outscm2:call    putc
        loop    outscm2
        pop     cx
        mov     ccode,0                 ; main text in background colors
        mov     si,offset moremsg       ; give More message
outsclf:cld
        lodsb                           ; read a byte from string
        call    putc                    ; display the string
        loop    outsclf                 ; repeat for all string chars
        pop     cx
        mov     ccode,1                 ; restore normal foreground coloring
        call    iseof                   ; EOF on redirected stdin?
        jc      outscl3                 ; c = yes, proceed anyway
        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     bypass,0                ; clear bypass condition
        mov     ttstate,offset tektxt   ; do displayable text
        push    ax
        mov     ax,xmax                 ; right margin minus 7 dots
        add     ax,7                    ; right most dot
        shr     ax,1                    ; central position
        mov     xcross,ax               ; save PC coord for crosshair
        mov     ax,ybot                 ; last scan line
        shr     ax,1
        mov     ycross,ax               ; this is the center of the screen
        pop     ax

tekcls1:push    ax                      ; save registers
        push    cx
        cmp     graph_mode,hercules     ; Hercules?
        jne     tekcls2                 ; ne = no
        call    hgraf                   ; set Hercules board to Graphics mode
        jmp     tekcls7

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
        cmp     graph_mode,cga          ; cga?
        je      tekcls3                 ; e = yes
        mov     cx,8000h                ; Olivetti, 400 lines times 80 bytes
        cmp     graph_mode,olivetti     ; AT&T-Olivetti?
        je      tekcls3                 ; e = yes
        cmp     graph_mode,toshiba      ; Toshiba?
        je      tekcls3                 ; e = yes
        cmp     graph_mode,vaxmate      ; VAXmate?
        jne     tekcls4                 ; ne = no
tekcls3:cld                             ; clear screen directly of text stuff
        mov     al,0                    ; color is black
        rep     stosb                   ; clear the bytes
        jmp     short tekcls7

tekcls4:cmp     graph_mode,ega          ; EGA?
        je      tekcls5                 ; e = yes
        cmp     graph_mode,monoega      ; EGA with mono display?
        je      tekcls5                 ; e = yes
        cmp     graph_mode,colorega     ; EGA with medium resolution monitor?
        je      tekcls5                 ; e = yes
        jmp     short tekcls6           ; else use Bios

tekcls5:                                ; EGA clear screen quickly
        mov     ax,0ff08h               ; set all 8 bits to be changed
        call    ega_gc                  ; set bit mask register accordingly
        mov     cx,ybot                 ; last scan line
        inc     cx                      ; number of scan lines
        mov     ax,80                   ; bytes per scan line
        mul     cx
        mov     cx,ax                   ; cx = number of bytes to clear
        mov     al,gbcol                ; select background colour
        cld
        rep     stosb                   ; write backgound color
        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     short plotex

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

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

;;;;;;; EGA plot support routines
psetupe proc    near                    ; EGA setup for plotting
        push    ax
        mov     linelen,80              ; for y going down screen by pincy
        mov     ax,segscn               ; set es to screen memory segment
        mov     es,ax
        mov     ax,0205h                ; mode: write mode 2
        call    ega_gc
        mov     ax,0003h                ; assume writing bits directly
        cmp     ccode,0ffh              ; inverting bits?
        jne     psete2                  ; ne = no
        mov     ax,1803h                ; then say XOR the bits
psete2: call    ega_gc                  ; set controller
        mov     ax,80                   ; compute starting point in regen buff
        mul     di
        mov     di,ax                   ; di = di * 80
        pop     ax
        ret
psetupe endp

pincye  proc    near                    ; EGA inc y
        add     di,linelen              ; includes sign of deltay
        ret
pincye  endp

pltega  proc    near            ; EGA plot(x,y). x is in si, y is in di
        rol     bp,1                    ; rotate line pattern
        jnc     pltega1                 ; nc = no bit to be plotted
        push    bx
        push    si
        push    di
        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
        mov     bh,masktab[bx]          ; 0-7 into bit mask in byte, x pos
        mov     bl,ccode                ; get line type code
        call    ega_plt
        pop     di
        pop     si
        pop     bx
pltega1:ret
pltega  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

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

;;;;;;; HGA plot support routines
; The HGA graphics memory mapping in mode 255 (720 by 348) is 8 dots per byte,
; left most dot in the high bit, 90 bytes per scan line, scan line segments
; sequence as 0b000h, 0b200h, 0b400h, 0b800h for lines 0-3 and repeat 90 bytes
; higher for the rest.
psetuph proc    near                    ; HGA setup for plotting
        push    ax
        push    cx
        mov     linelen,90              ; for y going down screen by incy
        mov     ax,segscn               ; base segment of display memory
        mov     es,ax
        mov     cx,di                   ; save copy of di, start y line
                                        ; compute starting point in regen buff
        shr     di,1                    ; quarter the lines in each bank
        shr     di,1
        mov     ax,90
        mul     di
        mov     di,ax                   ; di = di * 90 / 4
        and     cx,3                    ; compute bank from 2 lsb of line num
        jcxz    pseth2                  ; z means it is in bank 0 (0b000h)
pseth1: add     di,2000h                ; add offset for each bank
        loop    pseth1                  ; do cx times
pseth2: pop     cx
        pop     ax
        ret
psetuph endp

pincyh  proc    near                    ; HGA inc y, step offset of line
        cmp     linelen,0               ; increasing y?
        jg      pinyh2                  ; g = yes
        cmp     di,2000h                ; in lowest for four banks?
        ja      pinyh1                  ; a = no
        add     di,linelen              ; yes, add a line
pinyh1: add     di,6000h                ; move back by adding a lot
        and     di,7fffh                ; roll over address
        ret
pinyh2: cmp     di,6000h                ; in top most bank?
        jb      pinyh4                  ; b = no
        add     di,linelen              ; yes, first add a line
pinyh4: add     di,2000h                ; switch to next bank
        and     di,7fffh                ; roll over address
        ret
pincyh  endp

;;;;;;; AT&T-Olivetti, Toshiba, VAXmate Graphics Adapter plot support routines
; The graphics memory mapping in 640 by 400 mode is 8 dots per byte,
; left most dot in the high bit, 80 bytes per scan line, scan line segments
; sequence as 0b800h, 0ba00h, 0bc00h, 0be00h for lines 0-3 and repeat 80 bytes
; higher for the rest. Use Hercules line incrementing (inc y) and CGA dot
; writing. This is a monographic display.
psetupo proc    near                    ; setup for plotting
        push    ax
        push    cx
        mov     linelen,80              ; for y going down screen by incy
        mov     ax,segscn               ; base segment of display memory
        mov     es,ax
        mov     cx,di                   ; save copy of di, start y line
                                        ; compute starting point in regen buff
        shr     di,1                    ; quarter the lines in each bank
        shr     di,1
        mov     ax,80
        mul     di
        mov     di,ax                   ; di = di * 80 / 4
        and     cx,3                    ; compute bank from 2 lsb of line num
        jcxz    pseto2                  ; z means it is in bank 0 (0b800h)
pseto1: add     di,2000h                ; add offset for each bank
        loop    pseto1                  ; do cx times
pseto2: pop     cx
        pop     ax
        ret
psetupo endp

;;;;;;;; Monochrome, simulate dots with text char
psetupm proc    near
        mov     linelen,1               ; 80 characters but one line
        ret
psetupm endp

pltmon  proc    near                    ; Monochrome dot plot
        mov     x_coord,si              ; put dot at row=di, col=si, PC Coord
        mov     y_coord,di
        push    ax
        mov     al,'+'                  ; our dot character
        call    mputc                   ; display text char
        pop     ax
        ret
pltmon  endp

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

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

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

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

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

; EGA Character plot routine. Enter with bx pointing at font array for char
; cx = number of bytes in char font, es:di = screen memory. Worker for gputc.
; ccode: 0=plot in background colors, 1=foreground, 0ffh=xor with screen
gcega   proc    near
gcega1: mov     al,font[bx]             ; EGA byte plot: get bits from font
        push    bx
;;;;;   mov     bh,0ffh                 ; write these bits to clear field
;;;;;   mov     bl,0                    ; in background coloring
;;;;;   call    ega_plt                 ; plot a byte
        mov     bh,al                   ; set bit pattern of character
        mov     bl,ccode                ; plot in back/fore/xor (ccode) colors
        call    ega_plt                 ; byte plot routine for EGA systems
        pop     bx
        inc     bx                      ; next byte of char pattern
        call    pincy                   ; next scan line (linelen is preset)
        loop    gcega1
        ret
gcega   endp

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

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

; routines to manipulate ega graphics controller and mode register
; command code in al, value in ah - destroys al and dx

ega_gc  proc    near                    ; ega graphics controller
        mov     dx,3ceh
        out     dx,al                   ; output command code
        inc     dx                      ; dx is now data port
        mov     al,ah                   ; get value to al
        out     dx,al                   ; output value
        ret
ega_gc  endp
ega_md  proc    near                    ; ega mode controller
        mov     dx,3c4h
        out     dx,al                   ; output command code
        inc     dx                      ; dx is now data port
        mov     al,ah                   ; get value to al
        out     dx,al                   ; output value
        ret
ega_md endp

; Plot eight pixels using an EGA board
; Enter with ES:[DI] pointing to screen address of byte,
; bh has pattern of bits to be set, bl has attributes:
;  0 = draw in background color, 1 = draw in foreground color,
;  0ffh = XOR with current dot colors.
; registers preserved

ega_plt proc    near
        push    ax
        push    dx
        mov     al,8                    ; command to set bit mask register
        mov     ah,bh                   ; get bits to be modified (1)
        call    ega_gc                  ; unprotect those bit positions
        mov     ah,gfcol                ; get foreground colour
        cmp     bl,1                    ; draw in foreground?
        je      ega2                    ; ne = no
        mov     ah,gbcol                ; get grahics background colour
        cmp     bl,0ffh                 ; do an XOR?
        jne     ega2                    ; ne = no
        mov     ah,0ffh                 ; XOR, touch all color bits
ega2:   mov     al,es:[di]              ; latch byte
        mov     es:[di],ah              ; set the byte
        pop     dx
        pop     ax
        ret
ega_plt endp

; routine to set Hercules card to graphics mode - both pages are enabled

HGRAF   PROC    NEAR
        push    ax
        push    bx                      ; save used registers
        push    cx
        push    si
        mov     al,grph                 ; graph mode
        lea     si,gtable               ;  requires graphics table
        mov     bx,0
        mov     cx,4000h                ; clear 4000h words
        call    setmd                   ; and set the mode
        pop     si
        pop     cx
        pop     bx
        pop     ax
        ret
HGRAF   ENDP

; set Hercules card to text mode

HTEXT   PROC    NEAR
        push    ax
        push    bx
        push    cx
        push    si
        mov     al,text                 ; text mode
        lea     si,ttable               ; requires text table
        mov     bx,0720h                ; blank value (space, white on black)
        mov     cx,2000                 ; whole screen to clear (80*25)
        call    setmd                   ; set the mode
        pop     si
        pop     cx
        pop     bx
        pop     ax
        ret
HTEXT   ENDP

; Hercules mode set - called from HTEXT and HGRAF

SETMD   PROC    NEAR
        push    dx
        push    ax
        mov     dx,config               ; configuration port
        mov     al,genable              ; allow graphics mode to be set
        out     dx,al
        pop     ax
        push    ax
        push    cx                      ; save count
        mov     dx,cntrl                ; control port
        out     dx,al                   ; set to text or graphics
        mov     dx,index                ; send 12 bytes from table to 6845
        mov     cx,12                   ; number of registers to load
        xor     ah,ah                   ; start with register 0 of 6845
        cld
setmd1: jmp     $+2                     ; small pause for hardware
        mov     al,ah                   ; ah is counter
        out     dx,al                   ; set register
        inc     dx                      ; point to data port
        lodsb                           ; get next byte in table
        jmp     $+2                     ; small pause for hardware
        out     dx,al                   ; and send to 6845
        inc     ah                      ; next register
        dec     dx                      ; point to register port
        loop    setmd1                  ; and continue 'til cx=0
        pop     cx                      ; recover count
        cld
        push    di
        push    es
        mov     ax,segscn               ; start of screen
        mov     es,ax
        xor     di,di
        mov     ax,bx                   ; get blanking character
        rep     stosw                   ; store blanking char in whole screen
        pop     es
        pop     di
        mov     dx,cntrl                ; now to re-enable screen
        pop     ax                      ; get mode
        or      al,scrn_on              ; enable screen
        out     dx,al
        pop     dx
        ret
SETMD   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
        cmp     graph_mode,ega
        je      teksav1
        cmp     graph_mode,monoega
        je      teksav1
        cmp     graph_mode,colorega
        je      teksav1
        cmp     graph_mode,hercules
        je      teksav2
        jmp     short teksavx   ; else nothing
teksav1:mov     di,segega+800h  ; EGA page 1 screen segment
        call    egasr           ; call common save/restore code
        jmp     short teksavx
teksav2:mov     di,seghga+800h  ; Hercules page 1 screen segment
        call    hgasr           ; call common save/restore code
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
        cmp     graph_mode,ega
        je      tekres1
        cmp     graph_mode,monoega
        je      tekres1
        cmp     graph_mode,colorega
        je      tekres1
        cmp     graph_mode,hercules
        je      tekres2
        jmp     short tekresx   ; else nothing
tekres1:mov     si,segega+800h  ; segment of EGA page 1
        call    egasr           ; call common save/restore code
        jmp     short tekresx
tekres2:mov     si,seghga+800h  ; segment of Hercules page 1
        call    hgasr           ; call common save/restore code
tekresx:pop     di
        pop     si
        ret
tekrest endp

egasr   proc    near            ; common code for Tek ega save/restore ops
        push    ax
        push    cx
        push    dx
        mov     ax,0f00h        ; enable 4 plane set/resets
        call    ega_gc          ; set controller
        mov     ax,0f01h        ; enable Set/Reset register
        call    ega_gc
        mov     ax,0f02h        ; set color compare register for 4 planes
        call    ega_gc
        mov     ax,0905h        ; set mode reg: write latches, read mode
        call    ega_gc
        mov     ax,0ff02h       ; enable all planes
        call    ega_md
        mov     cx,ybot         ; last scan line
        inc     cx              ; number of scan lines
        mov     ax,80           ; bytes per scan line
        mul     cx
        mov     cx,ax
        push    es              ; save es
        push    ds              ; save ds
        mov     es,di           ; destination, set es to video memory
        mov     ds,si           ; source, set ds to video memory
        xor     si,si           ; clear offset fields
        xor     di,di
        cld
        rep     movsb           ; copy from page [si] to page [di]
        pop     ds              ; recover ds
        pop     es              ; and other registers
        mov     ax,0000h        ; disable 4 plane set/resets
        call    ega_gc          ; set controller
        mov     ax,0001h        ; disable Set/Reset register
        call    ega_gc          ; set controller
        mov     ax,0002h        ; disable color compare register
        call    ega_gc
        mov     ax,1005h        ; set mode reg: write latches, odd/even
        call    ega_gc
        pop     dx
        pop     cx
        pop     ax
        ret
egasr   endp

hgasr   proc    near            ; Hercules save restore screen
        push    cx
        mov     cx,4000h        ; number of words to move
        push    es              ; save es
        push    ds              ; save ds
        mov     es,di           ; destination, set es to video memory
        mov     ds,si           ; source, set ds to video memory
        xor     si,si           ; clear offset fields
        xor     di,di
        cld
        rep     movsw           ; copy from page [si] to page [di]
        pop     ds              ; recover ds
        pop     es              ; and other registers
        pop     cx
        ret
hgasr   endp
code    ends
        end