REVLVL  equ     5               ;Revision level 6-25-85

;=============================================================================
;
; MSYTIPRO.ASM This file contains system dependent terminal emulation routines
;              for the H19 and Tektronix 4010 terminals.
;
; NOTE: ESC Z and ANSI mode don't work.
;
; Credits:      Dan Smith       Computing Center        (303) 273-3396
;                               Colorado School of Mines
;                               Golden, Colorado 80241
;               Joe Smith, now at TYMSHARE, 39100 Liberty St, Fremont CA 94538
;
;
; The following H19 escape codes are supported:
;
; Esc H    Cursor home                      Esc L    Insert line
; Esc C    Cursor forward                   Esc M    Delete line
; Esc D    Cursor backward                  Esc N    Delete character
; Esc B    Cursor down                      Esc O    Exit insert mode
; Esc A    Cursor up                        Esc @    Enter insert mode
; Esc I    Reverse index                    Esc p    Enter reverse video mode
; Esc Y    Direct cursor addressing         Esc q    Exit reverse video mode
; Esc E    Clear display                    Esc j    Save cursor position
; Esc J    Erase to end of page             Esc k    Restore cursor position
; Esc K    Erase to end of line
; Esc x4   Set block cursor                 Esc Z    Identify as VT52
; Esc y4   Set underscore cursor
;
; The following H19 codes are not supported:
;
; Esc n     Cursor position report          Esc <    Enter ANSI mode
; Esc b     Erase beginning of display      Esc [    Enter hold screen mode
; Esc l     Erase entire line               Esc \    Exit hold screen mode
; Esc o     Erase beginning of line         Esc F    Enter graphics mode
; Esc z     Reset to power up config.       Esc G    Exit graphics mode
; Esc r ?   Modify baud rate                Esc t    Enter keypad shifted mode
; Esc x 1-3 Set modes 1 through 3           Esc u    Exit keypad shifted mode
; Esc x 5-9 Set modes 5 through 9           Esc =    Enter alt keypad mode
; Esc y 1-3 Reset modes 1 through 3         Esc >    Exit alt keypad mode
; Esc y 5-9 Reset modes 5 through 9         Esc }    Keyboard disable
; Esc v     Wrap around at end of line      Esc {    Keyboard enable
; Esc w     Discard at end of line          Esc ]    Transmit 25th line
; Esc Z     Identify as H-19                Esc #    transmit page
;
;=============================================================================

        include mssdef.h

datas   segment public 'datas'
        extrn   flags:byte

tekflag db      0               ;Flag for ESCape sequences
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
tek_lox db      0
tek_lsb db      0               ; Low-order 2 bits of X + low Y (4014 mode)

arrtab  db      48h,'A'                 ;Up arrow
        db      50h,'B'                 ;Down arrow
        db      4bh,'D'                 ;Left arrow
        db      4dh,'C'                 ;Right arrow
arrtabl equ     ($-arrtab) / 2          ;Number of keys in arrtab

spctab  db      27,13,10,08,09,07,29,12
lspctab equ     $-spctab
spcjmp  dw      outesc,outcr,outlf,outbs,outtab,beep,tekini,ffeed

esctab  db      'YABCDEHIJKLMNO@pqjkxy'         ;Recognized escape codes
        db      'Z',12,1ah
lesctab equ     $-esctab
escjmp  dw      movcur,curup,curdwn,currt       ;Escape code routines. This
        dw      outbs,clrscr,curhom,revind      ;array must parallel the codes
        dw      clreow,clreol,inslin,dellin     ;listed above.
        dw      delchr,noins,entins,invvid
        dw      nrmvid,savecur,restcur,setm,resetm
        dw      sendid,escff,xhair

argadr  dw      0
escchar db      0
videobuf        dw      0de00h
ttstate dw      0
wcoord  db      0
savrow  db      0
insmod  db      0
cursor  dw      0
oldcur  dw      0

xmult   dw      9                       ;Scale TEK to TI by 9/13
xdiv    dw      13                      ;so that 0-1023 converts to 0-708
ymult   dw      5                       ;Scale TEK to TI by 5/13
ydiv    dw      13                      ;so that 0-779 converts to 299-0
ybot    dw      299                     ;Bottom of screen is Y=299
oldx    dw      0                       ;Previous scaled coordinates
oldy    dw      0
grseg   dw      0

datas   ends

code    segment public
        assume  cs:code,ds:datas

        extrn   beep:near, prtchr:near, outchr:near
        public  term

;=============================================================================
; Main entry point for Tektronix 4010 - Heathkit H19 terminal emulation.
;=============================================================================
        db      'term'
term    proc    near
        mov     argadr,ax               ;Save address of argument block
        call    termini
term10: call    inport                  ;Input from modem
        jnc     term20                  ;No input available; Check keyboard
        call    outtty                  ;Print on terminal
term20: mov     ah,1                    ;See if a character has been typed
        int     4ah                     ;  on keyboard
        jz      term10                  ;Jump if not
        xor     ah,ah                   ;Read char from keyboard buffer
        int     4ah
        cmp     al,escchar              ;See if the Esc character (^])
        jz      term30                  ;Jump if it is
        call    outport                 ;Send character out comm port
        jmp     short term20            ;Make sure KB buffer doesnt overrun
term30: call    termend
        ret
term    endp

;=============================================================================
; TERMINI  Subroutine to initialize the terminal before starting emulation
;=============================================================================
termini proc    near
        mov     bx,argadr               ;Save escape char in local storage
        mov     al,[bx].escc
        mov     escchar,al
        mov     grseg,0d000h            ;Assume green on a 3 plane system
        int     4fh                     ;Get system configuration
        test    ax,4000h                ;See if graphics plane 3 exists
        jnz     ti10                    ;Jump if it does
        mov     grseg,0c000h            ;Reset to plane 1 for a 1 plane system
ti10:   mov     ttstate,offset nstate
        mov     insmod,0                ;Turn off insert mode
        mov     ah,13h                  ;Necessary to clear screen in order to
        int     49h                     ;  get CRTC start address in sync with
        mov     word ptr cursor,0       ;    cursor position for direct video
        ret                             ;      buffer access.
termini endp

;=============================================================================
; TERMEND  Subroutine to clean up after terminal emulation.
;=============================================================================
termend proc    near
;*;     mov     ah,13h                  ;Clear text screen
;*;     int     49h
;*;     mov     ah,14h                  ;Clear graphics screen
;*;     int     49h
        ret
termend endp

;=============================================================================
; Routine to input a character from the modem port. If no character available
; this returns with the carry flag cleared. (NC)
;=============================================================================
inport  proc    near                    ;Input from the modem
        call    prtchr
        jmp     short ip10              ;Character available
        nop                             ;Need 3 bytes
        clc                             ;Indicate no character
        ret
ip10:   and     al,7fh                  ;No parity here for terminal emulation
        stc                             ;Indicate character available
        ret
inport  endp

;=============================================================================
; Subroutine to translate and send the character out the communication port
;=============================================================================
outport proc    near
        cmp     flags.vtflg,1
        jne     op2                     ;Jump if no Heath-19 emulation
        or      al,al
        jz      op5                     ;Jump if a special key
op2:    mov     ah,al
        jmp     short op30
op5:    mov     cx,arrtabl              ;Number of entries in translation table
        mov     si,offset arrtab        ;Point to start of translation table
op10:   cmp     ah,[si]
        jz      op20                    ;Jump if found key
        add     si,2                    ;Point to next key scan code
        loop    op10
        ret                             ;Scan code not found; don't send it
op20:   mov     ah,27
        call    outchr                  ;Send a leading escape char
        nop                             ;Waste 3 bytes to ignore error
        nop
        nop
        mov     ah,[si+1]               ;Get translated code value
op30:   call    outchr                  ;Output character in AH
        nop                             ;Waste 3 bytes to ignore error
        nop
        nop
        ret
outport endp

;=============================================================================
; Subroutine to send the character in AL to the screen. If Heath-19 emulation
; is on, the character will be interpreted according to H-19 and Tektronix 4010
; escape codes.
;=============================================================================
outtty  proc    near
        cmp     flags.vtflg,1
        jne     otty10                  ;Jump if no Heath-19 emulation
        mov     dx,cursor               ;These may need cursor...
        cld                             ;Set here so its not required later
        jmp     ttstate                 ;Jump according to current state
otty10: mov     dl,al                   ;Print char in al at cursor position
        mov     ah,2                    ;  using DOS
        int     21h
        ret
outtty  endp

;=============================================================================
; Subroutine to process the character in AL according to the normal state
;=============================================================================
nstate  proc    near
        cmp     al,32                   ;Special character?
        jb      conchar                 ;Yes, perform control char operation
        cmp     insmod,0                ;In insert mode?
        je      ns10                    ;No, output normal
        push    ax                      ;Save character
        call    inschr                  ;Insert a blank in line
        pop     ax                      ;Restore character
ns10:   jmp     pchar                   ;Print char in AL
nstate  endp

;=============================================================================
; Subroutine to handle the ASCII character below 32 in al
;=============================================================================
conchar proc    near
        mov     di,offset spctab        ;See if character is in table
        mov     cx,lspctab
        repne   scasb
        jz      cc10                    ;Go process if it was
        push    ax                      ;Save char
        mov     al,'^'
        call    pchar                   ;Print caret
        pop     ax
        add     al,'A'-1                ;Make control character printable
        jmp     pchar                   ;Print, then return
cc10:   sub     di,offset spctab+1      ;Get index of char
        shl     di,1                    ;Double for word offset
        jmp     spcjmp[di]              ;And go handle
conchar endp

;=============================================================================
; special char routines.  cursor is in dx, char in al
;=============================================================================
outlf   proc    near
        inc     dl                      ;Bump row
        jmp     setcur
outlf   endp

outcr   proc    near
        xor     dh,dh                   ;Set col to 0
        jmp     setcur
outcr   endp

outbs   proc    near
        or      dh,dh
        jle     setcur                  ;Col 0, can't back up
        dec     dh                      ;Back up col
        jmp     setcur                  ;And use if reasonable
outbs   endp

outtab  proc    near
        add     dh,8                    ;Tab is at most 8 columns
        and     dh,not 111b             ;Round down to a multiple of 8
        cmp     dh,80                   ;Out of range?
        jb      outta1                  ;No, go set it
        mov     dh,80-1                 ;Else just move to right margin
outta1: jmp     setcur
outtab  endp

outesc  proc    near
        mov     ttstate,offset estate   ;Expect escape sequence.
        ret
outesc  endp

;=============================================================================
; Escape-char handling routines
;=============================================================================
estate  proc    near
        mov     ttstate,offset nstate   ;Put state back to normal
        mov     di,offset esctab        ;Escape char tbl
        mov     cx,lesctab              ;Length of tbl
        repne   scasb                   ;Look for it in tbl
        jz      es10                    ;Found, go use it
        push    ax
        mov     al,27                   ;Output Esc character
        call    pchar
        pop     ax                      ;Output unrecognized escape code
        jmp     pchar
es10:   sub     di,offset esctab+1      ;Get offset into tbl
        shl     di,1                    ;Convert to word offset
        jmp     escjmp[di]              ;And go dispatch on it
estate  endp

;=============================================================================
; Subroutine to print a character at the current cursor position and advance
; the cursor to the next position.
;=============================================================================
pchar   proc    near
        push    es                      ;Save ES
        push    ax                      ;Save char to print
        mov     dx,cursor               ;Get row and column
        call    scrloc                  ;Map DX to ES:DI
        pop     ax                      ;Restore char to print
        stosb                           ;Put into video buffer
        pop     es                      ;Restore segment
        inc     dh                      ;Bump col
        jmp     setcur                  ;Position cursor
pchar   endp

;=============================================================================
; Subroutine to position the cursor. This routine will wrap lines and scroll
; the screen. The row is in DL, the column is in DH
;=============================================================================
setcur  proc    near
        cmp     dh,80                   ;See if in range
        jae     sc20
        cmp     dl,24                   ;Lines go from 0 to 23
        jbe     sc10                    ;Not off end, keep going
        push    dx                      ;Save row/col
        xor     dx,dx
        call    dellin                  ;Scroll up one line by deleting top line
        pop     dx
        mov     dl,24                   ;Go to bottom line again...
sc10:   mov     cursor,dx               ;Save cursor pos
        mov     ah,2
        int     49h                     ;Set cursor
sc20:   ret
setcur  endp

;=============================================================================
; Subroutine to move the cursor up and possibly scroll the screen down
;=============================================================================
revind  proc    near
        cmp     dl,0
        jle     rev10
        dec     dl                      ;back up a row
        jmp     setcur                  ;and go set cursor
rev10:  xor     dx,dx
        jmp     inslin                  ;Insert a line at top of screen
revind  endp

;=============================================================================
; Subroutine to move the cursor up
;=============================================================================
curup   proc    near
        cmp     dl,0                    ;w/in range?
        jle     curu10                  ;no, skip this
        dec     dl                      ;else back up
curu10: jmp     setcur                  ;and go set position
curup   endp

;=============================================================================
; Subroutine to move the cursor down
;=============================================================================
curdwn  proc    near
        inc     dl
        jmp     setcur                  ;increment row (setcur can scroll!)
curdwn  endp

;=============================================================================
; Subroutine to move the cursor 1 position to the right.
;=============================================================================
currt   proc    near
        inc     dh
        jmp     setcur
currt   endp

;=============================================================================
; Subroutine to home cursor and clear screen
;=============================================================================
clrscr  proc    near
        call    curhom                  ;go home cursor
        mov     dx,cursor
        jmp     clreow                  ;then clear to end of window
clrscr  endp

;=============================================================================
; Subroutine to home the cursor
;=============================================================================
curhom  proc    near
        xor     dx,dx                   ;move to 0,0
        jmp     setcur
curhom  endp

;=============================================================================
; Subroutine to clear the screen from the cursor to the end of the window
;=============================================================================
clreow  proc    near
        push    es
        call    scrloc                  ;Map DX into ES:DI in the video buffer
        mov     cx,80*25                ;Number of chars on screen
        sub     cx,di                   ;Number from the cursor on
        mov     al,' '                  ;Fill with blanks
        rep     stosb                   ;Fill screen
        pop     es
        ret
clreow  endp

;=============================================================================
; Subroutine to clear the screen from the cursor to the end of the line
;=============================================================================
clreol  proc    near
        mov     cx,80                   ;Number of cols across screen
        sub     cl,dh                   ;Number from cursor on
        jle     eol10                   ;Jump if past end
        push    es
        call    scrloc                  ;Map DX to ES:DI
        mov     al,' '                  ;Fill end with blanks
        rep     stosb                   ;Blank end of line
        pop     es
eol10:  ret
clreol  endp

;=============================================================================
; Subroutine to insert a line at the row that the cursor is in.
;=============================================================================
inslin  proc    near
        xor     dh,dh                   ;Move to start of row
        cmp     dl,24
        jae     clreol                  ;Just clear bottom row
        push    ds
        push    es
        call    scrloc                  ;Map DX to ES:DI
        mov     ds,videobuf             ;Set DS to video buffer
        mov     cx,24*80                ;Number of chars on screen
        sub     cx,di                   ;Number of chars past current row
        push    di                      ;Save current row address
        mov     di,25*80-1              ;Point to last char
        mov     si,24*80-1              ;Point 1 line up
        std                             ;Auto decrement
        rep     movsb                   ;Move lines down
        cld                             ;Auto increment
        mov     cx,80                   ;Number of chars on original line
        pop     di                      ;Restore pointer to start of line
        mov     al,' '                  ;Fill with blanks
        rep     stosb                   ;Blank line
        pop     es
        pop     ds
        ret
inslin  endp

;=============================================================================
; Subroutine to scroll the screen up over the current line
;=============================================================================
dellin  proc    near
        xor     dh,dh                   ;Move to start of row
        cmp     dl,24
        jae     clreol                  ;Just clear bottom row
        push    ds
        push    es
        call    scrloc                  ;Map DX to ES:DI
        mov     ds,videobuf             ;Set DS to video buffer
        mov     cx,24*80                ;First char of last row
        sub     cx,di                   ;Number of chars past current row
        mov     si,di
        add     si,80                   ;Source is one line down
        rep     movsb                   ;Move chars up
        mov     cx,80                   ;Number of chars on last line
        mov     al,' '                  ;Fill with blanks
        rep     stosb                   ;Blank line
        pop     es
        pop     ds
        ret
dellin  endp

;=============================================================================
; Subroutine to delete the current character by scrolling to the left
;=============================================================================
delchr  proc    near
        push    ds
        push    es
        call    scrloc                  ;Map dx to es:di
        mov     ds,videobuf
        mov     cx,79                   ;Last char on line
        sub     cl,dh
        jz      dch20                   ;Jump if on last char
        mov     si,di
        inc     si                      ;Source is 1 char to right
        rep     movsb                   ;Move chars to left
dch20:  mov     byte ptr [di],' '
        pop     es
        pop     ds
        ret
delchr  endp

;=============================================================================
; Subroutine to insert a character at the cursor position
;=============================================================================
inschr  proc    near
        push    ds
        push    es
        mov     cx,79           ;This is last col to move, +1 for length
        sub     cl,dh           ;Compute distance to end
        jle     ichr20          ;Nothing to move...
        mov     dh,78           ;This is address of last col to move
        call    scrloc          ;Compute pos
        mov     ds,videobuf
        mov     si,di
        inc     di              ;Destination is one byte over...
        std                     ;Remember to move us backwards
        rep     movsb           ;Move chars to right
        cld
ichr20: pop     es
        pop     ds
        ret
inschr  endp

;=============================================================================
; Subroutine to turn off insert mode.
;=============================================================================
noins   proc    near
        mov     insmod,0                ;Turn off insert mode
        ret
noins   endp

;=============================================================================
; Subroutine to process ESC Y  (The direct cursor addressing command)
;=============================================================================
movcur  proc    near
        mov     wcoord,0                ;Want two coordinates...
        mov     ttstate,offset cstate
        ret
movcur  endp

;=============================================================================
; Subroutine to get a coordinate
;=============================================================================
cstate  proc    near
        sub     al,32                   ;Coordinates offset by 32
        cmp     wcoord,0                ;See if first coord already received
        jnz     cs10                    ;Jump if it was
        inc     wcoord                  ;Indicate first was received
        mov     savrow,al               ;Save first coordinate  (row)
        ret
cs10:   mov     ttstate,offset nstate   ;Reset state
        mov     dh,al                   ;Put column in DH
        mov     dl,savrow               ;Get saved row
        jmp     setcur                  ;Position cursor
cstate  endp

;=============================================================================
; Subroutine to enter insert mode.
;=============================================================================
entins  proc    near
        mov     insmod,0ffh             ;enter insert mode...
        ret                             ;and return
entins  endp

;=============================================================================
; Subroutine to enter inverse video mode
;=============================================================================
invvid  proc    near
        ret
invvid  endp

;=============================================================================
; Subroutine to exit inverse video mode
;=============================================================================
nrmvid  proc    near
        ret
nrmvid  endp

;=============================================================================
; Subroutine to handle the set mode command. Sequence = ESC x (1,2,3,4,5...)
;=============================================================================
setm    proc    near                    ;Here if ESC x entered
        mov     ttstate,offset mstate   ;Wait for value
        ret
mstate: mov     ttstate,offset nstate   ;Put state back to normal
        cmp     al,'4'
        jz      uscurs                  ;Set underscore cursor
        push    ax
        mov     al,27                   ;Output Esc character
        call    pchar
        mov     al,'x'                  ;Output set mode character
        call    pchar
        pop     ax                      ;Output unrecognized mode code
        jmp     pchar
setm    endp

;=============================================================================
; Subroutine to handle the reset mode command. Sequence = ESC y (1,2,3,4,5...)
;=============================================================================
resetm  proc    near                    ;Here if ESC y entered
        mov     ttstate,offset rstate   ;Wait for value
        ret
rstate: mov     ttstate,offset nstate   ;Put state back to normal
        cmp     al,'4'
        jz      blcurs                  ;Set block cursor
        push    ax
        mov     al,27                   ;Output Esc character
        call    pchar
        mov     al,'x'                  ;Output set mode character
        call    pchar
        pop     ax                      ;Output unrecognized mode code
        jmp     pchar
resetm  endp

;=============================================================================
; Subroutine to set the underscore cursor
;=============================================================================
uscurs  proc    near
        mov     cx,4a0bh
        mov     ah,1
        int     49h
        ret
uscurs  endp

;=============================================================================
; Subroutine to set a block cursor
;=============================================================================
blcurs  proc    near
        mov     cx,400bh
        mov     ah,1
        int     49h
        ret
blcurs  endp

;=============================================================================
; save cursor in DX
;=============================================================================
savecur proc    near
        mov     oldcur,dx
        ret
savecur endp

;=============================================================================
; restore cursor onto screen
;=============================================================================
restcur proc    near
        mov     dx,oldcur
        jmp     setcur
restcur endp

;=============================================================================
; Computes screen location to es:di, given col and row in dx.
; Trashes ax,bx
;=============================================================================
scrloc  proc    near
        mov     al,dl           ;Get row
        xor     ah,ah
        shl     ax,1            ;Row * 2
        mov     bx,ax
        shl     ax,1            ;Row * 4
        shl     ax,1            ;Row * 8
        add     ax,bx           ;Row * 10
        shl     ax,1            ;Row * 20
        shl     ax,1            ;Row * 40
        shl     ax,1            ;Row * 80
        add     al,dh
        adc     ah,0
        mov     di,ax
        mov     es,videobuf
        ret
scrloc  endp

;=============================================================================
;
; 12-Dec-84  Joe Smith, CSM Computing Center, Golden CO 80401
;
;                  Description of Tektronix commands
;
; ESCAPE-CONTROL-E (ENQ) requests a status report
; ESCAPE-FORMFEED erases the screen.
; ESCAPE-CONTROL-Z turns on the crosshairs (not on 4006 or 4025)
; ESCAPE-A-E enables the interactive plotter
; ESCAPE-A-F turns off the interactive plotter
; ESCAPE-M-L-2 Selects color 2 for drawing lines on 4113
; ESCAPE-M-T-: Selects color 10 for drawing text on 4113
; CONTROL-] (GS) turns on plot mode, the first move will be with beam off.
; CONTROL-UNDERLINE (US) turns off plot mode.  (CR also works for all but 4025.)
; CONTROL-X switches HDSGVT from TEKTRONIX mode to NORMAL alpha mode.
;
; 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,
; altho 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 w/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:                  40  140   140    40   100
;
; Note that LO-Y must be sent if HI-X has changed so the TEKTRONIX knows that
; the HI-X byte (in the range of 40-77 octal) 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 140 + MARGIN*20 + LSBY*4 + LSBX.  (MARGIN=0)
;
;============================================================================

;============================================================================
; Subroutine to initialize tektronix emulation. Called when GS char received
;============================================================================
tekini  proc    near
        mov     visible,0               ;Next move is invisible
        mov     tekflag,1
        mov     ttstate,offset xystate  ;Go to ystate next
        ret
tekini  endp

;============================================================================
; Subroutine to clear the graphics screen. Called when a Form feed is received
;============================================================================
ffeed   proc    near
        mov     ah,14h                  ;Clear only graphics (not text)
        int     49h
        ret
ffeed   endp

;============================================================================
; Subroutine to clear the graphics and the text screen. Called if Esc FF rec.
;============================================================================
escff   proc    near
        mov     ah,13h                  ;Erase both text and graphics screen
        int     49h
        mov     ah,14h
        int     49h
        mov     ttstate,offset nstate
        ret
escff   endp

;=============================================================================
; Subroutine to send an identification code back. (Esc Z)
;=============================================================================
sendid  proc    near
        mov     al,esc
        call    outport
        mov     al,'\'
        call    outport
        mov     al,'K'
        call    outport
        mov     ttstate,offset nstate
        ret
sendid  endp

;=============================================================================
; Subroutine to turn on the crosshairs. (Esc ^Z)
;=============================================================================
xhair   proc    near
        mov     ttstate,offset nstate
        ret
xhair   endp

;=============================================================================
; Subroutine to extract the X,Y coordinates for Tektronix emulation.
; Expecting HIY because LOX was seen   tekflag = 1
; Expecting HIX because LOY was seen   tekflag = 0
; Written by Joe Smith, CSM
;=============================================================================
xystate proc    near
        cmp     al,29                   ;Process Pen up command
        jz      tekini
        cmp     al,13                   ;Exit graphics mode on CR,LF,US
        je      go2text
        cmp     al,10
        je      go2text
        cmp     al,1fh
        je      go2text
        cmp     al,18h
        je      go2text
        cmp     al,20h                  ;Control char?
        jl      tek20                   ;Ignore it
        cmp     al,40h
        jl      tek30                   ;20-3F are HIX or HIY
        cmp     al,60h                  ;40-5F are LOX (causes beam movement)
        jl      tek50                   ;60-7F are LOY

;Extract low-order 5 bits of Y coordinate, set ESCFLAG=6

        mov     ah,tek_loy              ;Copy previous LOY to MSB (in case 4014)
        mov     tek_lsb,ah
        and     al,1Fh                  ;LOY is 5 bits
        mov     tek_loy,al
        cmp     tekflag,0               ;2nd LOY in a row?
        je      tek20                   ;Yes, then LSB is valid
        mov     tek_lsb,0               ;1st one, clear LSB
        mov     tekflag,0               ;LOY seen, expect HIX (instead of HIY)
tek20:  ret

;Extract high-order 5 bits (X or Y, depending on ESCFLAG)

tek30:  and     ax,1Fh                  ;Just 5 bits
        mov     cl,5
        shl     ax,cl                   ;Shift over 5 bits
        cmp     tekflag,1               ;Looking for HIY?
        jne     tek40                   ;No, HIX
        mov     tek_hiy,ax              ;Yes, this byte has HIY
        ret                             ;Keep ESCFLAG=4
tek40:  mov     tek_hix,ax              ;This byte has HIX (because ESCFLAG=6)
        mov     tekflag,1               ;Reset to look for HIY next time
        ret

;Extract low-order X, do beam movement

tek50:  and     al,1Fh                  ;Just 5 bits
        mov     tek_lox,al
        mov     ax,tek_hix              ;Combine HIX*32
        or      al,tek_lox              ;with LOX
        mov     bx,tek_hiy              ;Same for Y
        or      bl,tek_loy
        mov     cl,visible              ;0=move, 1=draw
        call    tekdraw
go2visi:mov     visible,1               ;Next movement is with a visible trace
        mov     tekflag,1               ;Reset to look for HIY next time
        ret

go2text:mov     ttstate,offset nstate
        ret
xystate 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.
; Visiblity flag in CL, 0=move invisible, 1=draw a line.
;
; The TI-PRO has (719,299) as the coordinate of the lower-right corner.
; Calculate endpoint X=(9/13)*(HIX*32+LOX), Y=299-(5/13)*(HIY*32+LOY)
;
; The IBM-PC has (639,199) as the coordinate of the lower-right corner.
; Calculate endpoint X=(12/20)*(HIX*32+LOX), Y=199-(5/20)*(HIY*32+LOY)
;
;=============================================================================
tekdraw proc    near
        imul    xmult                   ;Multiply by 9
        idiv    xdiv                    ;Divide by 13
        push    ax                      ;X is now between 0 and 708
        mov     ax,bx
        imul    ymult                   ;Multiply by 5
        idiv    ydiv                    ;Divide by 13
        mov     bx,ybot                 ;Y is now between 0 and 299
        sub     bx,ax                   ;Put new Y in right reg
        pop     ax                      ;Put new X in right reg
        or      cl,cl
        jnz     td10                    ;Jump if line is visible
        mov     oldx,ax                 ;Update last coordinates
        mov     oldy,bx
        ret
td10:   mov     si,oldx                 ;Previous position
        mov     di,oldy
        mov     oldx,ax                 ;Update position
        mov     oldy,bx
        jmp     line                    ;Plot line
tekdraw endp

;=============================================================================
; LINE  Subroutine to plot line with endpoints in BX,CX and SI,DI. The method
;       used is an adaptation of octantal dynamic differential analyzer(DDA).
;       SI,DI = Start X,Y coordinates. AX,BX = End X,Y coordinates.
;
;=============================================================================
line    proc    near
        cmp     ax,si                   ;Compare X1 to X2
        jl      plusx                   ;Jump if X1 is to left of X2
        xchg    ax,si                   ;Swap points so point 1 is to left
        xchg    bx,di                   ;  This mirrors quadrants 2,3 to 1,4
plusx:  sub     si,ax                   ;Get delta X into SI
        sub     di,bx                   ;Get delta Y into DI

; Left-hand coordinate in (AX,BX), delta movement in (SI,DI)
; Map X1,Y1 in AX,BX to  offset into the video buffer in BX and bit pos in AX

        shl     bx,1                    ;2*Y
        shl     bx,1                    ;4*Y
        mov     bp,bx                   ;Save 4*Y
        shl     bx,1                    ;8*Y
        shl     bx,1                    ;16*Y
        shl     bx,1                    ;32*Y
        add     bp,bx                   ;DX = 36*Y
        shl     bx,1                    ;64*Y
        shl     bx,1                    ;128*Y
        sub     bx,bp                   ;128Y - 36Y = 92*Y
        mov     cl,al                   ;Low 4 bits of X position
        and     cl,0Fh
        shr     ax,1                    ;Divide by 8 bits per byte
        shr     ax,1
        shr     ax,1
        and     ax,0fffeh               ;Truncate down to word boundary
        add     bx,ax
        mov     ax,8000h                ;Start with set bit on left edge
        shr     ax,cl                   ;Shift it over the correct amount

;AX has bit in position, BX has word address, SI has delta-X, DI has delta-Y

        mov     bp,92                   ;Offset from 1 pixel to one below it
        or      di,di                   ;See if delta y is below zero
        jg      line10                  ;Yes, already on quadrant 3
        neg     di                      ;Get absolute value of delta y
        neg     bp                      ;Move toward top of screen
line10: push    ds
        mov     ds,grseg
        cmp     di,si                   ;Compare delta-Y with delta-X
        jg      line30                  ;Greater than +/- 45 degrees

; Here when slope is less than +/- 45 degrees

line20: mov     cx,si                   ;Number of pixels to plot = delta x
        inc     cx                      ;  + 1
        mov     dx,si                   ;Initialize line error to -(deltax)/2
        shr     dx,1                    ;
        neg     dx                      ;
line2a: or      [bx],ax                 ;Turn on pixel pointed to by BX and Al
        ror     ax,1                    ;Increment X direction
        jnc     line2b                  ;
        add     bx,2                    ;
line2b: add     dx,di                   ;Add delta y to line error
        jl      line2c                  ;Jump for next pixel if error < 0
        add     bx,bp                   ;Go up (or down) one pixel
        sub     dx,si                   ;Subtract delta x from line error
line2c: loop    line2a                  ;Set next pixel
        pop     ds
        ret

; Here when slope is greater than +/- 45 degrees

line30: mov     cx,di                   ;Number of pixels to plot = delta y
        inc     cx                      ;  + 1 (Delta Y was negated above)
        mov     dx,di                   ;Initialize line error to -(deltay)/2
        shr     dx,1                    ;
        neg     dx                      ;
line3a: or      [bx],ax                 ;Turn on pixel pointed to by BX and Al
        add     bx,bp                   ;Move up (or down) 1 pixel
        add     dx,si                   ;Add delta x to line error
        jl      line3c                  ;Jump for next pixel if error < 0
        ror     ax,1                    ;Time to increment X direction
        jnc     line3b                  ;
        add     bx,2                    ;
line3b: sub     dx,di                   ;Subtract delta y from line error
line3c: loop    line3a                  ;Set next pixel
        pop     ds
        ret
line    endp

code    ends
        end
