Name msgap3 ; File MSGAP3.ASM ; Tektronix emulator for use with MS Kermit/IBM. ; Edit history: ; Last edit 18 March 1988 ; 18 Mar 1988 V2.30 adapted for the NEC APCIII -- RFGoeke ; The NEC version uses only a single VRAM page which cannot be saved ; (because a mode select call clears the VRAM!) in your choice of green. ; The gbcol variable is used to indicate normal (0) or reverse (1) video. ; For readability, a linefeed was set to 10 pixels. ; NEC also does not respond well to DOS keyboard calls; use BIOS ; 1 Jan 1988 version 2.30 ; 31 Dec 1987 change name from msvibm to msgibm for final release. [jrd] ; 29 Dec 1987 Add ESC [ ? 3 8 l as exit Tek mode command, from VT340's.[jrd] ; 26 Dec 1987 Add test to absorb echo of crosshairs report. [jrd] ; 22 Dec 1987 Revise parsing rules to make an escape sequence be a temporary ; interruption to the current command (except Clear Screen seq). [jrd] ; Add Control-C and Control-Break as non-reporting exits from GIN mode. [jrd] ; 21 Dec 1987 Add AT&T 6300, Olivetti M24 presence tests and run code. [jrd] ; 16 Dec 1987 Correct screen coloring for 64KB mono/med res color egas. [jrd] ; 4 Dec 1987 Add quirks for Environments, such as TopView, Windows. [jrd] ; 3 Dec 1987 Let 128KB EGA boards save screens. [jrd] ; 30 Nov 1987 Add relative plotting, thanks to help from Bob Parks. [jrd] ; 24 Nov 1987 Add dashed line patterns. [jrd] ; 21 Nov 1987 Add full color background. [jrd] ; 15 Nov 1987 Do screen clears manually because a Bios mode-set keeps ; interrupts off long enough to miss serial port characters. Make crosshairs ; smaller. [jrd] ; 8 Nov 1987 Modularize line drawing using Bresneham's algorithm, use pointers ; to action routines for different board types. Add screen save/restore. ; Do display board presence tests. Add FS as point plot introducer. Allow ; for virtual screens when operating under Environments (Windows, etc). [jrd] ; 1 Nov 1987 Heavy rewrite to integrate code into regular MS Kermit/IBM ; material. [jrd] ;============================================================================== ; Original version for TI Pro computers by ; 12-Dec-84 Joe Smith, CSM Computing Center, Golden CO 80401 ; Converted to IBM PCs by Brian Holley, Cambridge Univ. ; Upgraded and integrated into MS Kermit 2.30 by Joe Doupnik, Utah State Univ. ; ; Description of Tektronix commands ; ; ESCAPE-CONTROL-E (ENQ) requests a status report ; ESCAPE-FORMFEED erases the screen. ; ESCAPE-CONTROL-Z turns on the crosshairs (not on 4006 or 4025) ; ESCAPE [ ? 3 8 l exits Tek mode and returns to host text terminal type ; (VT102 if none defined yet). This is an extension from DEC VT340's. ; CONTROL-] (GS) turns on plot mode, the first move will be with beam off. ; CONTROL-^ (RS) turns on incremental plot mode. RS space means move pen up ; RS P means move pen down, following letters:A, E, D, F, B, J, H, I mean ; move right, right and up, up, left and up, left, left and down, down, and ; right and down, respectively. Ex: RS J J J means move three Tek ; positions left and down with the pen up (invisibly). ; CONTROL-UNDERLINE (US) turns off plot mode, as does CR (for all but 4025). ; CONTROL-X switches from TEKTRONIX sub mode to NORMAL alpha mode but is ; ignored if we are emulating a full Tek terminal rather than a sub mode ; of DEC or Heath. ; FF erases screen. ; ESCAPE letter, where letter is accent grave (`), a-e sets the line drawing ; pattern until reset to solid lines (same as escape accent) by command or ; a terminal reset. ; where ; ENQ = Control E ; ESC = Control [ (left square bracket) ; FF = Control L ; FS = Control \ (backslash) ; GS = Control ] (right square bracket) ; RS = Control ^ (caret) ; US = Control _ (underscore) ; ; The plot commands are characters which specify the absolute position to move ; the beam. All moves except the one immediately after the GS character ; (Control-]) are with a visible trace. ; ; For 4010-like devices - The positions are from 0 to 1023 for both X and Y, ; although only 0 to 780 are visible for Y due to screen geometry. The screen ; is 10.23 by 7.80 inches, and coordinates are sent as 1 to 4 characters. ; ; For 4014-like devices - The positions are from 0 to 4096, but each movement ; is a multiple of 4 positions unless the high-resolution LSBXY are sent. This ; makes it compatible with the 4010 in that a full sized plot fills the screen. ; ; HIX,HIY = High-order 5 bits of position ; LOX,LOY = Middle-order 5 bits of position ; LSBXY = Low-order 2 bits of X + low-order 2 bits of Y (4014 mode) ; ; Hi Y Lo Y Hi X LSBXY Characters sent (Lo-X always sent) ; ---- ---- ---- ----- ---------------------------------- ; Same Same Same Same Lo-X ; Same Same Same Diff LSB, Lo-Y, Lo-X 4014 ; Same Same Diff Same Lo-Y, Hi-X, Lo-X ; Same Same Diff Diff LSB, Lo-Y, Hi-X, Lo-X 4014 ; Same Diff Same Same Lo-Y, Lo-X ; Same Diff Same Diff LSB, Lo-Y, Lo-X 4014 ; Same Diff Diff Same Lo-Y, Hi-X, Lo-X ; Same Diff Diff Diff LSB, Lo-Y, Hi-X, Lo-X 4014 ; Diff Same Same Same Hi-Y, Lo-X ; Diff Same Same Diff Hi-Y, LSB, Lo-Y, Lo-X 4014 ; Diff Same Diff Same Hi-Y, Lo-Y, Hi-X, Lo-X ; Diff Same Diff Diff Hi-Y, LSB, Lo-Y, Hi-X, Lo-X 4014 ; Diff Diff Same Same Hi-Y, Lo-Y, Lo-X ; Diff Diff Same Diff Hi-Y, LSB, Lo-Y, Lo-X 4014 ; Diff Diff Diff Same Hi-y, Lo-Y, Hi-X, Lo-X ; Diff Diff Diff Diff Hi-y, LSB, Lo-Y, Hi-X, Lo-X 4014 ; Offset for byte: 20h 60h 60h 20h 40h ; ; Note that LO-Y must be sent if HI-X has changed so that the TEKTRONIX knows ; the HI-X byte (in the range of 20h-3fh) is HI-X and not HI-Y. LO-Y must ; also be sent if LSBXY has changed, so that the 4010 will ignore LSBXY and ; accept LO-Y. The LSBXY byte is 60h + MARGIN*10h + LSBY*4 + LSBX. (MARGIN=0) ; ;============================================================================== ; ; External variable tekflg and calls to tekini, tekemu, tekesc, tekcls: ; Byte TEKFLG is non-zero when the Tek emulator is active; it is set by the ; startup code in tekini and is maintained in this file. Internal variable ; inited remembers if we have a graphics screen saved, etc. ; TEKINI must be called when entering the emulator to establish the graphics ; screen mode and to calculate the screen dimensions. ; TEKESC is called from say mszibm.asm to invoke Tek emulation when the ; external procedures have detected an Escape Control-L sequence. An implicit ; initialization is done if necessary. ; TEKEMU is the normal entry point to pass a received character to the emulator. ; It too will do an implicit initialization, if required. ; TEKCLS clears the graphics screen, but only if the emulator is active. ; The emulator remains active during Connect mode Help, Status, and other ; interrupts which do not change the terminal type. ; ============================================================================= ; ; - ctrl-g (BEL) from line gives beep in tek mode ; - characters better placed in relation to current beam position ; in EGA and Hercules modes ; characters OR-ed into place rather than overwriting ; - add SET TERMINAL GRAPHICS NONE - this ignores the start-up ESC-FF ; for Tektronix ; - add MonoEGA mode for monochrome graphics on an EGA ; ; version 2.29/t3 ; changes - stop control characters from echoing to screen in TEKEMU ; - show version on name in MSSDEF.H ; version 2.29b ; changes with this version: - faster line drawing, using direct write to ; memory rather than BIOS calls ; - support for Hercules, Olivetti, EGA ; - minor bug fixes ; adapted to IBM PC June 1987 by Brian Holley, ; Faculty of Economics and Politics ; University of Cambridge, England ; Email: BJH6@UK.AC.CAM.PHX public tekemu,tekini,tekend ; Terminal emulation routines public tekcls, tekesc, tekflg ; used by msz file include mssdef.h ENQ equ 05h ; ^E ENQ for TEK enquiries CAN equ 18h ; ^X to return to ANSI mode ESCZ equ 1Ah ; SUB, ESC-^Z triggers crosshairs VT equ 0bh ; ^K go up one line FS equ 1ch ; ^\ for point plot mode GS equ 1Dh ; ^] draw line (1st move is invisible) RS equ 1Eh ; ^^ for incremental line plot mode US equ 1Fh ; ^_ (underscore) returns to text mode accent equ 60h ; accent grave txtmode equ 4 ; text mode for TEKTRONIX status maxtekx equ 1024 ; horizontal and maxteky equ 780 ; vertical resolution of TEK 4010 screen equ 19h ; bios screen call -- NEC kbint equ 18H ; bios keyboard call -- NEC uparr equ 39h ; DOS scan codes for arrow keys -- NEC dnarr equ 3Ch ; these are also the "extended" codes lftarr equ 3Ah rgtarr equ 3Bh homscn equ 3Dh ; DOS home screen scan code -- NEC shuparr equ 0B4h ; "extended" codes for CTRL-Arrows shdnarr equ 0B7h shlftarr equ 0B5h shrgtarr equ 0B6h ; Graph_mode for different systems: ; NEC resolution = Olivetti (640 x 400) ; Though we set mode for color, BIOS will go to B&W if adaptor board absent olivetti equ 9 ; Olivetti's Hi-res - 50 lines text segcga equ 0A800h ; CGA, AT&T/Olivetti -- NEC !!! hiy equ 1 ; codes for Tek graphics components loy equ 2 hix equ 4 lox equ 3 att_low_mask equ 1fH ; Various NEC attribute-related equates att_overline equ 01H ; this is all NEC version stuff RFG att_blink equ 02H att_rev_video equ 04H att_underline equ 08H att_intensity equ 04H ; same as reverse video col_high_mask equ 0E0H nec_black equ 00H ; This table gives colors RFG nec_blue equ 20H ; (only bits 8,7,6 count) nec_red equ 40H nec_magenta equ 60H nec_green equ 80H nec_cyan equ 0A0H nec_yellow equ 0C0H nec_white equ 0E0H datas segment public 'datas' extrn flags:byte, portval:word, rxtable:byte, vtemu:byte ; extrn tv_mode:byte ; NEC omits scrsave dw ? ; segment addr of memory for screen save (NEC) xmult dw ? ; scaling factor for x is xdiv dw ? ; xmult/xdiv ymult dw ? ; scaling factor for y is ydiv dw ? ; ymult/ydiv xmax dw ? ; ybot dw ? ; ; required for Hercules screen handling ttstate dw tektxt ; state machine control pointer prestate dw 0 ; previous state, across interruptions visible db 0 ; 0 to move, 1 to draw a line tek_hiy dw 0 ; Y coordinate in Tektronix mode tek_loy db 0 tek_hix dw 0 ; X coordinate in Tektronix mode tek_lox db 0 tek_lsb db 0 ; Low-order 2 bits of X + low Y ; (4014 mode) status db 0 lastc db 0 ; last x/y coord fragment seen masktab db 80h,40h,20h,10h,8,4,2,1 ; quicker than calculations! ; dashed line patterns linetab dw 0ffffh ; ESC accent 11111111 11111111 dw 0aaaah ; ESC a 10101010 10101010 dw 0f0f0h ; ESC b 11110000 11110000 dw 0fafah ; ESC c 11111010 11111010 dw 0ffcch ; ESC d 11111111 11001100 dw 0fc92h ; ESC e 11111100 10010010 linepat dw 0ffffh ; active line pattern, from above ;End of init data IDSEQ dw tekem ; address of response to terminal CTLTAB dw 0 ; .. inquiry tekem db 'NEC_TEK' ; .. and the response db escape,'/Z',0 x_coord dw 0 ; Tek text char X coordinate y_coord dw 8 ; Tek text char Y coordinate xcross dw 0 ; cross hairs to start at centre ycross dw 0 oldx dw 0 ; Tek coordinates of last point oldy dw 767 ; initially top left scalex dw 0 ; PC coord for scaled x value scaley dw 0 ; for scaled y value curmode db 0 ; screen mode before graphics ; local variables for LINE plotting routine graph_mode db 0 ; graphics video mode, default is none cursor dw 0 ; saved text cursor inited db 0 ; non-zero if inited (retains page) tekflg db 0 ; Tek mode active flag yflags db 0 ; flags byte from msy flow dw 0 ; flow control word gpage db 0 ; display adapter graphics page ;gfcol db 15 ; graphics foreground colour (NEC omit) gbcol db 0 ; graphics background color moremsg db ' More >' mormsglen equ $-moremsg ; length of message ccode db 0 ; temp for holding plot color code linelen dw 0 ; offset increment between scan lines putc dw ? ; ptr to plot a character routine psetup dw ? ; ptr to plot setup routine pfin dw ? ; ptr to plot cleanup routine pincy dw ? ; ptr to inc y routine plotptr dw ? ; ptr to dot plot routine segscn dw ? ; actual screen segment to use ; ANSI Escape sequence to turn off Media Copy (Print Controller Off) tkoff db escape,'[?38l' ; Exit Tek mode escape sequence tkofflen equ $-tkoff ; length of sequence tkoffs db 6 dup (0) ; received chars in rcv'd sequence tkcnt dw 0 ; counter of matched char in tkoffs repbuf db 6 dup (0) ; crosshairs report buf repcnt db 0 ; number of untouched chars in repbuf temp dw 0 ; 8*8 font for Hercules, CGA, and EGA TEK mode ; - allows 43 lines, and 80 (90 for Hercules) chars per line. ; all printing (?) characters from to - two characters per line ; 8 bits per scan line, given top line first, 8 scan lines. font db 0,0,0,0,0,0,0,0, 18h,18h,18h,18h,18h,0,18h,0 db 6ch,6ch,6ch,0,0,0,0,0, 36h,36h,7fh,36h,7fh,36h,36h,0 db 0ch,3fh,68h,3eh,0bh,7eh,18h,0, 60h,66h,0ch,18h,30h,66h,06h,0 db 38h,6ch,6ch,38h,6dh,66h,3bh,0, 0ch,18h,30h,0,0,0,0,0 db 0ch,18h,30h,30h,30h,18h,0ch,0, 30h,18h,0ch,0ch,0ch,18h,30h,0 db 0,18h,7eh,3ch,7eh,18h,0,0, 0,18h,18h,7eh,18h,18h,0,0 db 0,0,0,0,0,18h,18h,30h, 0,0,0,7eh,0,0,0,0 db 0,0,0,0,0,18h,18h,0, 0,06h,0ch,18h,30h,60h,0,0 db 3ch,66h,6eh,7eh,76h,66h,3ch,0, 18h,38h,18h,18h,18h,18h,7eh,0 db 3ch,66h,06h,0ch,18h,30h,7eh,0, 3ch,66h,06h,1ch,06h,66h,3ch,0 db 0ch,1ch,3ch,6ch,7eh,0ch,0ch,0, 7eh,60h,7ch,06h,06h,66h,3ch,0 db 1ch,30h,60h,7ch,66h,66h,3ch,0, 7eh,06h,0ch,18h,30h,30h,30h,0 db 3ch,66h,66h,3ch,66h,66h,3ch,0, 3ch,66h,66h,3eh,06h,0ch,38h,0 db 0,0,18h,18h,0,18h,18h,0, 0,0,18h,18h,0,18h,18h,30h db 0ch,18h,30h,60h,30h,18h,0ch, 0,0,0,7eh,0,7eh,0,0,0 db 30h,18h,0ch,06h,0ch,18h,30h, 0,3ch,66h,0ch,18h,18h,0,18h,0 db 3ch,66h,6eh,6ah,6eh,60h,3ch, 0,3ch,66h,66h,7eh,66h,66h,66h,0 db 7ch,66h,66h,7ch,66h,66h,7ch, 0,3ch,66h,60h,60h,60h,66h,3ch,0 db 78h,6ch,66h,66h,66h,6ch,78h, 0,7eh,60h,60h,7ch,60h,60h,7eh,0 db 7eh,60h,60h,7ch,60h,60h,60h, 0,3ch,66h,60h,6eh,66h,66h,3ch,0 db 66h,66h,66h,7eh,66h,66h,66h, 0,7eh,18h,18h,18h,18h,18h,7eh,0 db 3eh,0ch,0ch,0ch,0ch,6ch,38h, 0,66h,6ch,78h,70h,78h,6ch,66h,0 db 60h,60h,60h,60h,60h,60h,7eh, 0,63h,77h,7fh,6bh,6bh,63h,63h,0 db 66h,66h,76h,7eh,6eh,66h,66h, 0,3ch,66h,66h,66h,66h,66h,3ch,0 db 7ch,66h,66h,7ch,60h,60h,60h, 0,3ch,66h,66h,66h,6ah,6ch,36h,0 db 7ch,66h,66h,7ch,6ch,66h,66h, 0,3ch,66h,60h,3ch,06h,66h,3ch,0 db 7eh,18h,18h,18h,18h,18h,18h, 0,66h,66h,66h,66h,66h,66h,3ch,0 db 66h,66h,66h,66h,66h,3ch,18h, 0,63h,63h,6bh,6bh,7fh,77h,63h,0 db 66h,66h,3ch,18h,3ch,66h,66h, 0,66h,66h,66h,3ch,18h,18h,18h,0 db 7eh,06h,0ch,18h,30h,60h,7eh, 0,7ch,60h,60h,60h,60h,60h,7ch,0 db 0,60h,30h,18h,0ch,06h,0,0, 3eh,06h,06h,06h,06h,06h,3eh,0 db 18h,3ch,66h,42h,0,0,0,0, 0,0,0,0,0,0,0,0ffh db 30h,18h,0ch,0,0,0,0,0, 0,0,3ch,06h,3eh,66h,3eh,0 db 60h,60h,7ch,66h,66h,66h,7ch,0, 0,0,3ch,66h,60h,66h,3ch,0 db 06h,06h,3eh,66h,66h,66h,3eh,0, 0,0,3ch,66h,7eh,60h,3ch,0 db 0eh,18h,18h,3ch,18h,18h,18h,0, 0,0,3eh,66h,66h,3eh,06h,3ch db 60h,60h,7ch,66h,66h,66h,66h,0, 18h,0,38h,18h,18h,18h,3ch,0 db 18h,0,38h,18h,18h,18h,18h,70h, 60h,60h,66h,6ch,78h,6ch,66h,0 db 38h,18h,18h,18h,18h,18h,3ch,0, 0,0,76h,7fh,6bh,6bh,63h,0 db 0,0,7ch,66h,66h,66h,66h,0, 0,0,3ch,66h,66h,66h,3ch,0 db 0,0,7ch,66h,66h,7ch,60h,60h,0, 0,3eh,66h,66h,3eh,06h,07h db 0,0,6ch,76h,60h,60h,60h,0, 0,0,3eh,60h,3ch,06h,7ch,0 db 30h,30h,7ch,30h,30h,30h,1ch,0, 0,0,66h,66h,66h,66h,3eh,0 db 0,0,66h,66h,66h,3ch,18h,0, 0,0,63h,6bh,6bh,7fh,36h,0 db 0,0,66h,3ch,18h,3ch,66h,0, 0,0,66h,66h,66h,3eh,06h,3ch db 0,0,7eh,0ch,18h,30h,7eh,0, 0ch,18h,18h,70h,18h,18h,0ch,0 db 18h,18h,18h,0,18h,18h,18h,0, 30h,18h,18h,0eh,18h,18h,30h,0 db 31h,6bh,46h,0,0,0,0,0, 8 dup (0ffh) datas ends code segment public 'code' extrn outchr:near, beep:near, scrseg:near, cmblnk:near extrn clrmod:near, savescr:near, cptchr:near, pcwait:near extrn restscr:near, getflgs:near, clrbuf:near, vtans52:near assume cs:code, ds:datas, es:nothing ; Initialise TEK mode by setting high resolution screen, etc ;The Olivetti has (639,399) as the coordinate of the lower-right corner. ;Calculate endpoint X=(5/8)*(HIX*32+LOX), Y=399-(20/39)*(HIY*32+LOY) tekini PROC NEAR push ax ; do presence tests. [jrd] push bx push cx push dx push si push di push es ; NEC handles flow control in hardware; see SERINIT in msxap3 ; NEC uses green graphic plane (only) mov gbcol,0 ; NEC: this is normal video push si ; NEC mov ah,15 ; get current screen mode int screen pop si ; NEC cmp al,3 ; in a mono/color text mode (2/3)? jbe tekin1 ; be = yes ; cmp al,mono ; mono text mode (7)? ; je tekin1 ; e = yes cmp tekflg,0 ; are we active as Tek device now? je tekin1 ; e = no jmp tekin13 ; yes, don't redo graphics setup tekin1: mov curmode,al ; save mode here mov ah,3 ; get cursor position xor bh,bh ; page 0 int screen mov cursor,dx ; save position call savescr ; save text screen ; Presence tests. tekin2: mov xmult,5 ; CGA. Scale TEK to PC by 640/1024 mov xdiv,8 ; so that 0-1023 converts to 0-639 mov xmax,640-8 ; x-coord of rightmost character tekin7: mov graph_mode,olivetti ; Olivetti mov gpage,0 ; only page 0 with 640 by 400 mode mov segscn,segcga ; use cga screen segment (0b800h) mov psetup,offset psetupn ; plot setup routine for NEC mov plotptr,offset pltcga ; cga dot plot routine mov pfin,offset pfinc ; cleanup routine mov pincy,offset pincym ; inc y routine (NEC is straight) mov putc,offset gputc ; character display routine mov ybot,399 ; bottom of screen is y = 399 mov ymult,20 ; Olivetti vertical scale = 400/780 mov ydiv,39 ; same as cga setup ; Set Graphics mode ;tekin13: tekin14:mov ah,0 ; set screen mode mov al,graph_mode ; to this screen mode tekin15:int screen ; Bios Set Mode. mov ax,100 ; wait 100 millisec call pcwait ; NEC requires >65 millisec pause here mov ah,1 ; and kill cursor while we wait tekin13: mov ch,80h int screen tekin16:mov tekflg,1 ; starting Tek sub mode ; cmp inited,0 ; inited yet? NEC didn't save ; jne tekin19 ; ne = yes, restore screen mov ttstate,offset tektxt ; do displayable text mov prestate,offset tektxt ; set a previous state of text mov inited,1 ; say we have initialized call tekcls ; clear screen, for ega coloring ; jmp short tekin20 ; flow control in hardware on NEC ;tekin19:call tekrest ; not saved on NEC ;tekin20:mov ax,flow ; get flow control word ; xchg ah,al ; get xon into al ; cmp al,0 ; able to send xon? ; je tekin21 ; e = no ; call outmodem ; tell host xon ;tekin21:clc ; clear carry for success ; jmp short tekin23 ;tekin22:stc ; set carry for failure tekin23:pop es pop di pop si pop dx pop cx pop bx pop ax ret tekini ENDP ;Terminal emulation. Enter with received character in AL. TEKEMU PROC NEAR ; main emulator cmp tekflg,0 ; Tek mode active yet? (msz call) jne tektt1 ; ne = yes call tekini ; init now mov ttstate,offset tektxt ; initial state mov prestate,offset tektxt ; set a previous state of text jnc tektt1 ; nc = succeeded ret ; else failed to init, just return tektt1: and al,7fh ; force Tek chars to be 7 bits. cmp al,0 ; NUL char? je tekign ; e = yes, ignore it before logging push ax call getflgs ; get msy yflags into al mov yflags,al test al,capt ; capturing output? pop ax jz tektt4 ; z = no, forget this part push ax ; save char call cptchr ; give it captured character pop ax ; restore character and keep going tektt4: test yflags,trnctl ; debug? if so use tty mode jz tektt5 ; z = no cmp al,DEL ; DEL char? jne tektt4a ; ne = no mov al,5eh ; make DEL a caret query mark call outscrn mov al,3fh ; the query mark call outscrn jmp short tekign tektt4a:cmp al,' ' ; control char? jae tektt4b ; ne = no push ax mov al,5eh ; caret call outscrn pop ax add al,'A'-1 ; make char printable tektt4b:call outscrn tekign: ret ; Ignore this character tektt5: call tkscan ; scan for "ESC [ ? 3 8 l" exit code cmp al,0 ; null char response? je tekign ; e = yes, ignore the character ; check for echo of crosshair report cmp repcnt,0 ; any chars need matching in report? je tektt5a ; e = no push bx ; yes mov bx,6 ; number of bytes in crosshairs rpt sub bl,repcnt ; number of chars needing matching cmp al,repbuf[bx] ; received same as current rpt char? pop bx jne tektt5a ; ne = mismatch, stop echo test dec repcnt ; say one more matched clc ; absorb without comment ret ; stay in this state tektt5a:mov repcnt,0 ; clear report count cmp al,' ' ; control code? jb tektt6 ; b = yes, decode jmp ttstate ; no, do current state ; Control characters: tektt6: cmp al,GS ; Line plot command? jne tektt7 ; ne = no mov visible,0 ; Next move is invisible and status,not txtmode ; set status report byte mov ttstate,offset tekline ; expect coordinates next jmp tektt12 tektt7: cmp al,RS ; Incremental dot command? jne tektt8 ; ne = no and status,not txtmode ; set status report mov ttstate,offset tekrlin ; expect pen command next jmp tektt12 tektt8: cmp al,FS ; Point plot command? jne tektt9 ; ne = no mov visible,0 ; next move is invisible and status,not txtmode ; set status report byte mov ttstate,offset tekpnt jmp tektt12 tektt9: cmp al,US ; assert text mode? [bjh] jne tektt10 ; ne = no or status,txtmode ; set status report byte mov ttstate,offset tektxt ; Go to TEKTXT next time jmp tektt12 tektt10:cmp al,ESCAPE ; Escape? jne tektt11 ; ne = no or status,txtmode ; set status report byte cmp ttstate,offset tekesc ; already in escape state? je tektt14 ; e = yes, nest no further push ttstate ; current state pop prestate ; save here as previous state mov ttstate,offset tekesc ; next state parses escapes ret tektt11:cmp al,CAN ; Control X? (exits Tek sub mode) jne tektt13 ; ne = no, stay in current state mov ttstate,offset tektxt ; back to text mode test flags.vtflg,tttek ; main Tek emulator? jnz tektt12 ; nz = yes, ignore the ^X call tekend ; else exit sub mode mov tekflg,0 ; clear Tek sub mode flag tektt12:mov prestate,offset tektxt ; make previous state text tektt14:ret tektt13:jmp ttstate ; let someone else worry about this TEKEMU ENDP ; End TEK emulation, recover previous screen TEKEND PROC NEAR cmp tekflg,0 ; Tek sub mode active? jne teknd0 ; ne = yes ret ; else return as is. teknd0: ; NEC can't save (VRAM is destroyed by mode switch) call tekcls ; clear screen to avoid flash teknd1: mov ah,0 ; set video mode mov al,curmode ; restore previous screen mode int screen ; revert to text screen mov ax,100 ; wait 100 millisec call pcwait ; NEC requires >65 millisec pause here call restscr ; restore text screen mov dx,cursor ; saved cursor position mov bh,0 ; page 0 mov ah,2 ; set cursor int screen ret TEKEND ENDP ; State machine active while Tek is active. Senses ESC [ ? 3 8 l to exit ; Tek mode and return to either non-sub mode terminal or to a VT102. ; Plays back unmatched escape sequences. Enter with character in al. tkscan proc near and al,7fh ; strip high bit cmp al,byte ptr tkoff ; start of Tek Off sequence? jne tkscn1 ; ne = no call tkscn4 ; playback previously matched chars mov tkcnt,1 ; count matched chars (one now) mov tkoffs,al ; save full character, with high bit mov al,0 ; our temporary response jmp short tkscnx ; and exit tkscn1: push bx ; check for char in Tek Off sequence mov bx,tkcnt ; number of chars matched in Tek Off mov tkoffs[bx],al ; save this char cmp al,byte ptr tkoff[bx] ; match expected char in sequence? pop bx jne tkscn3 ; ne = no, play back partial match inc tkcnt ; count new match mov al,0 ; our temporary response cmp tkcnt,tkofflen ; matched all char in sequence? jne tkscnx ; ne = not yet, wait for more mov tkcnt,0 ; clear counter cmp flags.vtflg,tttek ; are we a full Tek terminal now? jne tkscn2 ; ne = no, a submode call vtans52 ; toggle terminal type, in msyibm tkscn2: mov al,CAN ; simulate arrival of Control-X jmp short tkscnx ; all done tkscn3: call tkscn4 ; playback previously matched chars mov tkcnt,0 ; reset to no match and exit tkscnx: ret ; common exit ; local worker procedure tkscn4: push ax ; save break char (in al) push cx ; playback partial sequence to printer mov cx,tkcnt ; number of chars matched before break jcxz tkscn4b ; z = none push si mov si,offset tkoffs ; string to be played back tkscn4a:cld lodsb ; get a char into al push cx push si ; save these around tektt5a work call tektt5a ; use it pop si pop cx loop tkscn4a ; do all that came in previously pop si tkscn4b:pop cx pop ax ; recover break char ret tkscan endp TEKTXT proc near ; Dispatch on text characters cmp al,DEL ; RUBOUT? jne tektx1 ; ne = no mov al,bs ; make tektx1: cmp al,CR ; ^M Carriage return? je tektx7 ; e = yes tektx2: cmp al,LF ; ^J LineFeed? je tektx7 ; e = yes tektx3: cmp al,FF ; ^L Formfeed? jne tektx4 ; ne = no call tekcls ; clear the screen jmp short tektx8 tektx4: cmp al,VT ; ^K vertical tab? je tektx7 cmp al,bell ; ^G bell on line? jne tektx5 ; ne = no call beep jmp short tektx8 tektx5: cmp al,Tab ; Tab? jne tektx6 ; ne = no mov al,' ' ; make it a space tektx6: cmp al,BS ; ^H backspace? je tektx7 ; e = yes cmp al,' ' ; control char? jb tektx8 ; b = yes, ignore it tektx7: call OUTSCRN ; output character to the screen tektx8: ret TEKTXT endp ; Process escape sequences. Callable from msz terminal emulator. ; Enter with received character in AL. Escape sequences are generally ; treated as interruptions to the current plotting/text command. Screen ; clearing is the exception by causing a general emulator reset. TEKESC PROC NEAR mov ttstate,offset tekesc ; in case get here from msz file cmp tekflg,0 ; Tek mode active yet? (msz call) jne tekesc1 ; ne = yes call tekini ; init now mov prestate,offset tektxt ; set a previous state of text jnc tekesc1 ; nc = succeeded ret ; else failed to init, just return tekesc1:cmp al,'Z' ; ESC-Z Identify? jne tekesc2 ; ne = no call SENDID ; Send terminal identification jmp tekescx tekesc2:cmp al,FF ; ESC-FF Clear screen? jne tekesc3 ; ne = no call tekcls ; Clear screen mov prestate,offset tektxt ; make previous state text mode jmp tekescx ; Return to text mode after ESC-FF tekesc3:cmp al,ESCZ ; ESC-^Z Enter GIN mode? jne tekesc4 ; ne = no ; cmp graph_mode,mono ; Monochrome text mode? ; je tekesc3a ; e = yes, no crosshairs in text mode call CROSHAIR ; Activate the cross-hairs jmp tekescx tekesc3a:call beep ; tell the user we are unhappy jmp tekescx ; and ignore the command tekesc4:cmp al,ENQ ; ESC-^E Enquiry for cursor position? jne tekesc5 ; ne = no call SENDSTAT ; send status jmp tekescx tekesc5:cmp al,accent ; accent grave, line pattern series? jb tekescx ; b = no cmp al,65h ; lowercase e? ja tekescx ; a = beyond line pattern series push bx mov bl,al sub bl,accent ; remove bias mov bh,0 shl bx,1 ; make this a word index mov bx,linetab[bx] ; get line pattern word mov linepat,bx ; save in active word pop bx ; return to previous mode tekescx:push ax mov ax,prestate ; get previous state mov ttstate,ax ; restore it or ax,ax ; test for none pop ax jz go2text ; z = none, use text mode clc ret ; resume previous state go2text:mov ttstate,offset tektxt ; Go to TEKTXT next time mov lastc,0 ; clear last drawing coordinate flag or status,txtmode ; set text mode in status byte clc ret TEKESC ENDP TEKLINE proc near ; GS line drawing call tekxyc ; parse coordinates from input bytes jnc teklin1 ; nc = not done yet mov cl,visible ; get moveto or drawto variable call tekdraw ; move that point mov visible,1 ; say next time we draw teklin1:ret TEKLINE endp TEKPNT proc near ; FS plot single point call tekxyc ; parse coordinates jnc tekpnt1 ; nc = not done yet mov cl,0 ; do not draw call tekdraw ; move to the point mov ax,si ; copy starting point to end point mov bx,di ; ax,bx,si,di are in PC coordinates mov cl,1 ; make plot visible call line ; draw the dot mov visible,0 ; return to invisibility tekpnt1:ret TEKPNT endp ; Decode graphics x,y components. Returns carry set to say have all ; components for a line, else carry clear. Understands 4014 lsb extensions. ; Permits embedded escape sequences. TEKXYC proc near cmp al,CR ; Exit drawing on CR,LF,RS,US,FS,CAN je go2text ; e = yes, a cr cmp al,LF ; these terminate line drawing cmds je go2text cmp al,FS ; je go2text cmp al,RS ; je go2text cmp al,US ; je go2text cmp al,CAN ; and je go2text ; BUT ignore other control chars cmp al,20h ; Control char? jb tekgh0 ; b = yes, ignore it cmp al,40h jb tekgh2 ; 20-3F are HIX or HIY cmp al,60h ; 40-5F are LOX (causes beam movement) jb tekgh4 ; 60-7F are LOY ; Extract low-order 5 bits of Y coord mov ah,tek_loy ; Copy previous LOY to MSB (4014) mov tek_lsb,ah and al,1Fh ; LOY is 5 bits mov tek_loy,al cmp lastc,loy ; 2nd LOY in a row? je tekgh1 ; Yes, then LSB is valid mov tek_lsb,0 ; 1st one, clear LSB tekgh1: mov lastc,loy ; LOY seen, expect HIX (instead of HIY) tekgh0: clc ; c clear = not completed yet ret ; Extract high-order 5 bits (X or Y, depending on lastc) tekgh2: and ax,1Fh ; Just 5 bits mov cl,5 shl ax,cl ; Shift over 5 bits cmp lastc,loy ; was last coordinate a low-y? je tekgh3 ; e = yes, parse hix mov tek_hiy,ax ; this byte has HIY mov lastc,hiy clc ret tekgh3: mov tek_hix,ax ; This byte has HIX mov lastc,hix clc ret tekgh4: and al,1Fh ; Just 5 bits mov tek_lox,al mov lastc,lox mov ax,tek_hix ; Combine HIX*32 or al,tek_lox ; with LOX mov bx,tek_hiy ; Same for Y or bl,tek_loy stc ; set c to say completed operation ret TEKXYC endp TEKRLIN proc near ; RS relative line drawing cmp al,' ' ; Pen up command? jne tekrli1 ; ne = no, try pen down mov visible,0 ; do invisible movements jmp short tekrli2 ; do the command tekrli1:cmp al,'P' ; pen down command? jne tekrli3 ; ne = no, return to text mode mov visible,1 ; set visible moves tekrli2:mov ax,x_coord ; PC x coordinate of pen mov bx,y_coord ; y coordinate call pctotek ; get current pen position in Tek coor mov cl,0 ; invisible, moveto call tekdraw ; move that point, set oldx and oldy mov ttstate,offset tekinc ; next get incremental movement cmds ret tekrli3:mov visible,0 ; bad char, reset visibility push prestate pop ttstate ; restore previous state jmp tektt5 ; deal with the break char TEKRLIN endp ; interpret RS inc plot command byte TEKINC proc near ; get movement character and do cmd cmp al,'A' ; move right? jne tekinc1 ; ne = no inc oldx ; adjust beam position jmp short tekinc9 tekinc1:cmp al,'E' ; move right and up? jne tekinc2 ; ne = no inc oldx inc oldy jmp short tekinc9 tekinc2:cmp al,'D' ; move up? jne tekinc3 ; ne = no inc oldy jmp short tekinc9 tekinc3:cmp al,'F' ; move left and up? jne tekinc4 ; ne = no dec oldx inc oldy jmp short tekinc9 tekinc4:cmp al,'B' ; move left? jne tekinc5 ; ne = no dec oldx jmp short tekinc9 tekinc5:cmp al,'J' ; move left and down? jne tekinc6 ; ne = no dec oldx dec oldy jmp short tekinc9 tekinc6:cmp al,'H' ; move down? jne tekinc7 ; ne = no dec oldy jmp short tekinc9 tekinc7:cmp al,'I' ; move right and down? jne tekincb ; ne = no, bad command inc oldx dec oldy tekinc9:cmp oldx,0 ; too far left? jge tekinc10 ; ge = no mov oldx,0 ; else stop at the left margin tekinc10:cmp oldx,maxtekx-1 ; too far left? jle tekinc11 ; le = no mov oldx,maxtekx-1 ; else stop that the left margin tekinc11:cmp oldy,maxteky-1 ; above the top? jle tekinc12 ; le = no mov oldy,maxteky-1 ; else stop at the top tekinc12:cmp oldy,0 ; below the bottom? jge tekinc13 ; ge = no mov oldy,0 ; else stop at the bottom tekinc13:mov ax,oldx ; ax is vector x end point mov bx,oldy ; bx is vector y end point mov cl,visible call tekdraw ; move/draw to that point ret tekincb:push prestate ; bad character, exit inc plot mode pop ttstate ; new state is previous state mov visible,0 jmp tektt5 ; reparse the bad char TEKINC endp ; Routine to trigger the crosshairs, wait for a key to be struck, and send ; the typed char (if printable ascii) plus four Tek encoded x,y position ; coordinates and then a carriage return. ; ax, by, xcross, ycross operate in PC coordinates. ; NEC mods to use BIOS key fetch and key translations; since shift-arrow ; is not a unique code, use CTRL-arrow instead CROSHAIR PROC NEAR push linepat ; save line drawing pattern mov linepat,0ffffh ; reset line type to solid crosha0:mov ax,xmax ; right margin minus 7 dots add ax,7 mov temp,ax ; right margin dot shr ax,1 ; central position mov xcross,ax ; save PC coord for crosshair mov ax,ybot ; last scan line shr ax,1 mov ycross,ax ; this is the center of the screen crosha1:call crosdraw ; draw the cross-hairs ; mov ah,coninq ; DOS, quiet read char ; int dos mov ah,0 ; NEC call, returns int kbint ; ah = scan code, al = ASCII ; if al = 0, ah = "extended code" push ax ; save char for later call crosdraw ; erase cross hairs pop ax ; or al,al ; ascii or scan code returned ; jnz arrow5 ; nz = ascii char returned ; mov ah,coninq ; read scan code ; int dos ; cmp al,0 ; Control-Break? ; jne crosha3 ; ne = no, something else ;crosha2:pop linepat ; restore line pattern ; ret ; exit crosshairs mode cmp al,0 je crosha3 ; e = extended code keys cmp al,3 ; Control-C? jne charkey pop linepat ; restore line pattern ret ; exit crosshairs mode charkey:call clrbuf ; purge received data to date mov repcnt,6 ; set length of report string mov repbuf,al ; store first report character call outmodem ; send the break character mov ax,xcross ; set beam to xcross,ycross mov bx,ycross ; must convert to Tek coordinates call pctotek ; scale from PC screen coord to Tek push ax ; save around drawing push bx mov cx,0 ; just a move call tekdraw ; moveto ax,bx in Tek coord pop bx ; recover Tek y pop ax ; recover Tek x call sendpos ; send position report to host pop linepat ; recover current line drawing pattern ret crosha3: xchg ah,al cmp al,homscn ; is it 'home'? je crosha0 ; e = yes jmp short arrow1 ; else try the arrow keys arrow1: cmp al,lftarr ; left arrow? jne arrow2 ; ne = no mov cx,-1 ; left shift jmp short xkeys arrow2: cmp al,rgtarr ; right arrow? jne arrow3 ; ne = no mov cx,1 ; right shift jmp short xkeys arrow3: cmp al,uparr ; up arrow? jne arrow4 ; ne = no mov cx,-1 ; up shift jmp short vertkey arrow4: cmp al,dnarr ; down arrow? jne arrow5 ; ne = no, ignore it mov cx,1 ; down shift jmp short vertkey arrow5: cmp al,shlftarr ; shifted left arrow? jne arrow6 ; ne = no mov cx,-64 ; big left shift jmp short xkeys arrow6: cmp al,shrgtarr ; shifted right arrow? jne arrow7 ; ne = no mov cx,64 ; big right shift jmp short xkeys arrow7: cmp al,shuparr ; shifted up arrow? jne arrow8 ; ne = no mov cx,-32 ; big up shift jmp short vertkey arrow8: cmp al,shdnarr ; shifted down arrow? jne badkey mov cx,32 ; big down shift jmp short vertkey badkey: call beep ; tell user we don't understand jmp crosha1 ; keep going xkeys: add cx,xcross ; add increment jns noxc ; gone too far negative? mov cx,0 ; yes - then make it 0 noxc: cmp cx,temp ; too far right? jb xdraw9 ; b = no mov cx,temp ; yes - then make it the right xdraw9: mov xcross,cx ; new x value for cross hairs jmp crosha1 ; and redraw vertkey:add cx,ycross ; adjust cx jns noyc ; gone negative? mov cx,0 ; yes then make 0 noyc: cmp cx,ybot ; too high? jb yok mov cx,ybot ; make it maximum yok: mov ycross,cx ; save new y crosshair jmp crosha1 ; and redraw CROSHAIR ENDP ; CROSDRAW draws cross-hairs by XORing cross with picture. ; xcross and ycross are in PC coordinates. CROSDRAW PROC NEAR mov si,xcross ; move to (xcross, ycross-12) mov di,ycross sub di,12 ; half the size of the cross jns crosd1 ; no sign bit means ok mov di,0 ; else limit to start of screen crosd1: mov ax,si ; next, draw to (xcross, ycross+12) mov bx,ycross ; make bottom stroke add bx,12 cmp bx,ybot ; too large? jbe crosd2 ; be = no mov bx,ybot ; vertical line to (xcross,ybot) crosd2: mov cx,0ffh ; invert pixels call line ; and draw vertical sub si,12 ; move to (xcross-12, ycross) jns crosd3 ; no sign means ok mov si,0 ; else limit to start of line crosd3: mov di,ycross mov bx,di mov ax,xcross ; draw to (xcross+12, ycross) add ax,12 cmp ax,temp ; temp is right margin, too large? jbe crosd4 ; be = no, ok mov ax,temp ; max x value crosd4: mov cx,0ffh ; set XOR code call line ; draw to (xcross+12, ycross) ret CROSDRAW ENDP ; SENDPOS sends position of cross-hairs to the host. ; ax has Tek X and bx has Tek Y coord of center of crosshair SENDPOS PROC NEAR push bx ; preserve register call sendxy ; send x coord mov word ptr repbuf+1,ax ; first word pop ax call sendxy ; send y coord mov word ptr repbuf+3,ax ; second word mov al,cr ; follow up with cr mov repbuf+5,al ; last report character call outmodem ret SENDPOS ENDP ; SENDXY sends value of ax as Tek encoded bytes ; ax is in Tek coordinates SENDXY PROC NEAR shl ax,1 shl ax,1 ; move all but lower 5 bits to ah shl ax,1 shr al,1 shr al,1 ; move low five bits to low 5 bits shr al,1 or ah,20h ; make it a printing char as per TEK xchg al,ah ; send high 5 bits first call outmodem xchg al,ah ; then low five bits or al,20h call outmodem xchg ah,al ; al is first sent byte ret SENDXY ENDP SENDID PROC NEAR ; Pretend VT100 with graphics option mov bx,IDSEQ ; Get addr of string sndid1: mov al,[bx] ; Get char from sequence cmp al,0 ; End of sequence? jz sndid0 ; Yes, return call OUTMODEM ; Send it out the port inc bx jmp sndid1 sndid0: ret SENDID ENDP ; SENDSTAT - send status and cursor position to host SENDSTAT PROC NEAR mov al,STATUS ; get tek status or al,20h ; make it printable call OUTMODEM ; and send it mov ax,oldx ; now send x coordinate (oldx is Tek) call SENDXY mov ax,oldy ; and y coordinate (oldy is Tek coord) call SENDXY mov al,cr ; end with a cr call OUTMODEM ret SENDSTAT ENDP ; routine to send al to the modem port OUTMODEM PROC NEAR push ax mov ah,al call outchr ; outchr reads from ah nop ; ignore errors nop nop pop ax ret OUTMODEM ENDP ; Convert X and Y from PC coordinates to Tek coordinates. AX = X, BX = Y ; for both input and output. pctotek proc near mul xdiv ; scale from PC screen coord to Tek div xmult xchg bx,ax ; save Tek x coord in bx neg ax ; y axis. Turn upside down for Tek add ax,ybot mul ydiv ; scale y from PC screen coord to Tek div ymult xchg ax,bx ; ax has X, bx has Y in Tek coords ret pctotek endp ; Routine to output character in AL to the screen. OUTSCRN PROC NEAR ; Output one character to the screen ; Set Translation Input filter cmp rxtable+256,0 ; translation turned off? je outsct ; e = yes, no translation push bx mov bx,offset rxtable ; address of translate table xlatb ; new char is in al and al,7fh ; retain only lower seven bits pop bx outsct: mov si,ybot ; get last scan line inc si ; number of scan lines sub si,y_coord ; minus where char bottom needs to go jnc outscc ; nc = enough space for char ; else give "More >" message push ax ; save current char mov ax,mormsglen ; characters in More message shl ax,1 shl ax,1 shl ax,1 ; times 8 bits/character neg ax ; (note: leave last char cell empty) add ax,xmax ; right justify mov x_coord,ax ; set starting x dot mov ax,ybot mov y_coord,ax ; set starting y line ; mov ah,gfcol ; get screen coloring ; mov al,gbcol ; push ax ; save it xchg ah,al ; interchange colors for message ; mov gfcol,ah mov gbcol,1 ; NEC: set reverse video mov si,offset moremsg ; give More message push cx mov cx,mormsglen outsclf:cld lodsb ; read a byte from string call putc ; display the string loop outsclf ; repeat for all string chars pop cx ; pop ax ; restore normal video ; mov gfcol,ah mov gbcol,0 ; NEC: set nromal video mov ah,coninq ; read keyboad via DOS int dos ; wait for keystroke or al,al ; scan code being returned? jne outscl3 ; ne = no mov ah,coninq ; clear away scan code too int dos outscl3:call tekcls ; clear the screen pop ax ; recover current character cmp al,lf ; just a line feed? jne outscc ; ne = no, display it ret ; else ignore the line feed outscc: push ax mov ax,xmax cmp x_coord,ax ; beyond right margin? jbe outsc3 ; be = no mov al,cr ; else simulate cr/lf call putc ; before displaying current char mov al,lf call putc outsc3: pop ax call putc ; routine to draw characters ret OUTSCRN ENDP ; TEKCLS routine to clear the screen. ; Entry point tekcls1 clears screen without resetting current point. TEKCLS PROC NEAR cmp tekflg,0 ; Tek sub mode active yet? jne tekcls0 ; ne = yes ret ; else ignore this call tekcls0:mov x_coord,0 ; starting text coordinates mov y_coord,8 mov oldx,0 ; assumed cursor starting location mov oldy,maxteky ; top right corner (Tek coord) mov scalex,0 ; clear last plotted point (PC coord) mov scaley,0 mov lastc,0 ; last parsed x,y coordinate mov visible,0 ; make lines invisible mov linepat,0ffffh ; reset line pattern to solid mov ccode,1 ; reset to ordinary writing mov ttstate,offset tektxt ; do displayable text tekcls1:push ax ; save registers push cx tekcls2:mov di,0 ; point to start of screen, di=row call psetup ; setup graphics routine and es:di mov cx,8000h ; Olivetti, 400 lines times 80 bytes tekcls3:cld ; clear screen directly of text stuff mov al,0 ; color is black rep stosb ; clear the bytes jmp short tekcls7 tekcls7:mov si,0 ; starting x (in case screen is mov di,0 ; starting y cleared by user) pop cx pop ax ret TEKCLS ENDP ; Routine to draw a line on the screen, using TEKTRONIX coordinates. ; X coordinate in AX, 0=left edge of screen, 1023=right edge of screen. ; Y coordinate in BX, 0=bottom of screen, 779=top of screen. ; CL=0 - invisible move, CL=1 - draw a line, CL=0FFh - invert pixels on line TEKDRAW PROC NEAR mov si,scalex ; get old x already scaled mov di,scaley ; get old y already scaled call scale ; scale new end point to PC coords cmp cl,0 ; invisible drawing? je moveto ; z = just move, skip draw part call LINE ; draw the line moveto: mov x_coord,ax ; update text coordinates to match mov y_coord,bx ; last drawn point ret TEKDRAW ENDP ; scale TEKTRONIX coordinates to the currently defined screen coordinates ; AX holds X axis, BX holds Y axis. Both are changed from Tektronix coord ; to PC coordinates by this procedure. SCALE PROC NEAR push dx push si mov oldx,ax ; save current Tek x for next draw mov oldy,bx ; save current Tek y for next draw mul xmult ; scale x-coord mov si,xdiv ; get the divisor shr si,1 ; halve it add ax,si ; add in - to round to nearest integer adc dx,0 div xdiv push ax mov ax,bx mul ymult ; scale y-coord mov si,ydiv ; get divisor shr si,1 ; halve it add ax,si ; add in - to round to nearest integer adc dx,0 div ydiv mov bx,ybot sub bx,ax ; Put new Y in right reg jns scale3 ; ns = not too far mov bx,0 scale3: pop ax ; Put new X in right reg mov scalex,ax ; save scaled values mov scaley,bx pop si pop dx ret SCALE ENDP ; LINE Subroutine to plot a line with endpoints in AX,BX and SI,DI. ; fast line drawing routine for the IBM PC ; ; Registers at CALL ; ----------------- ; SI=Start X coord, all in PC coordinates ; DI=Start Y coord ; AX=End X coord ; BX=End Y coord ; CL=Color code: 1=draw foreground, 0=draw background, 0ffh=invert ; BP= line drawing pattern (is changed here by rotation) ; registers are all unchanged LINE PROC NEAR push ax push bx push cx push dx push si push di push es mov bp,linepat ; store active line pattern word in BP mov ccode,cl ; save color code in ccode for use by plot() ; first get coord to achieve increasing x; deltax >= 0 sub ax,si ; deltax = x2 - x1 jge line1 ; ge = going to the right, as desired neg ax ; make deltax non-negative sub si,ax ; swap the x coordinates xchg bx,di ; swap the y coordinates too ; second, compute deltay. ax = deltax, si = x1 line1: sub bx,di ; deltay = y2 - y1 call psetup ; setup display adapter for plotting ; and setup es:di to screen memory ; Choose algorithm based on |deltay| < |deltax| (use shallow) else steep. ; We arrange matters such that both deltas are non-negative. cmp bx,0 ; deltay jge line2 ; ge = non-negative neg linelen neg bx ; make non-negative line2: cmp bx,ax ; |deltay| versus |deltax| jbe shallow ; be = do shallow algorithm jmp steep ; else do steep algorithm ; shallow algorithm, move along x, di=y1, bx=deltay, si=x1, ax=deltax shallow:add bx,bx ; bx = 2*deltay mov cx,ax ; cx = number of steps (deltax here) inc cx ; loop dec's cx before testing mov dx,bx ; dx holds error sub dx,ax ; error = 2*deltay - deltax add ax,ax ; ax = 2*|deltax| shal1: call plotptr ; Plot(x,y) cmp dx,0 jle shal2 ; le = error <= 0 call pincy ; increment y by one scan line sub dx,ax ; error = error - 2*deltax shal2: add dx,bx ; error = error + 2*deltay inc si ; x = next dot right loop shal1 shal3: jmp plotex ; steep algorithm, move along y, di=y1, bx=deltay, si=x1, ax=deltax steep: add ax,ax ; ax = 2*deltax mov dx,ax ; dx holds error sub dx,bx ; error = 2*deltax(bx) - deltay (bx) mov cx,bx ; cx = number of steps (deltay here) inc cx ; loop dec's cx before testing add bx,bx ; bx = 2*|deltay| stee1: call plotptr ; Plot(x,y) x = ax, y = di cmp dx,0 jle stee2 ; le error <= 0 inc si ; x = next dot right sub dx,bx ; error = error - 2*deltay stee2: add dx,ax ; error = error + 2*deltax call pincy ; increment y loop stee1 stee3: jmp plotex plotex: call pfin ; cleanup boards after plotting mov ccode,1 ; reset to do foreground coloring pop es pop di pop si pop dx ; restore the world pop cx pop bx pop ax ret LINE ENDP pfinc proc near ; CGA end of plot board cleanup ret pfinc endp pltcga proc near ; CGA plot(x,y). x is in si, y is in di push bx ; used for HGA plot also. push si push di rol bp,1 ; rotate line pattern jnc pltcg3 ; nc = no bit to be plotted mov bx,si ; want si/8 for bytes along line shr si,1 shr si,1 shr si,1 add di,si ; starting point in regen buffer and bx,0007h ; leave lower 3 bits for bit in byte ; di = offset in regen buffer mov bh,masktab[bx] ; 0-7 into bit mask in byte. x position mov bl,ccode ; get line type code cmp bl,1 ; draw the bit? jne pltcg1 ; ne = no or es:[di],bh ; drawn jmp short pltcg3 pltcg1: cmp bl,0 ; draw in background (erase)? jne pltcg2 ; ne = no not bh and es:[di],bh ; erase the dots jmp short pltcg3 pltcg2: xor es:[di],bh ; xor in this color pltcg3: pop di pop si pop bx ret pltcga endp pincym proc near ; Monochrome inc y add di,linelen ; includes sign ret pincym endp ;;;;;;;;;;;;;;; NEC plot support routines ; In modes 8 and 9 (640 by 400) we have 8 dots per byte, ; left most dot in the high bit, 80 bytes per scan line, scan line segments ; are totally sequential. psetupn proc near push ax mov linelen,80 ; for y going down screen by incy mov ax,segscn ; base segment of display memory mov es,ax mov ax,80 mul di mov di,ax ; di = di * 80 pop ax ret psetupn endp ; GPUTC - a routine to send text characters from font to true graphics boards ; such as EGA, Hercules or CGA. Char is in al. gputc proc near cmp al,' ' ; control character? jae gputc1 ; ae = no, display the char jmp putctrl ; else handle controls at putctrl gputc1: push bx ; first save some registers push cx push es push di mov bl,al ; now BL has char to be displayed and bl,7fh ; no high bits allowed here ; set board mode mov di,y_coord ; get current y coord (char bottom) sub di,8 ; start 8 lines higher jnc gputc2 ; nc = ok mov di,0 ; move up to first line mov y_coord,8 ; and reset scan line indicator gputc2: call psetup ; enter with di=line number, sets es:di to ; start of line in display buf and ; sets byte-wide plot mode mov ax,x_coord ; compute regen buffer byte shr ax,1 ; want x_coord/8 for bytes along line shr ax,1 shr ax,1 add di,ax ; byte in regen buffer xor bh,bh sub bx,32 ; characters in font start at 32 shl bx,1 shl bx,1 ; 8 bytes per char - hence * 8 shl bx,1 mov cx,8 ; 8 bytes (scan lines) to transfer gputc4: mov al,font[bx] ; Non-EGA systems: get bits from font cmp gbcol,0 je gputc5 xor al,0FFh gputc5: mov es:[di],al ; write desired pattern (no overwrite) inc bx ; point to next byte of char pattern call pincy ; inc to next line (linelen is preset) loop gputc4 ; and repeat 'til complete gputx: call incx ; move to next char position pop di pop es pop cx pop bx ret gputc endp putctrl proc near ; CONTROL CHARS = cursor movement cmp al,FF ; formfeed? jne putct0 ; ne = no call TEKCLS ; FF clears the screen ret putct0: cmp al,BS ; BS? sends (logical) cursor back one jne putct2 ; ne = no, try next mov ax,x_coord sub ax,8 ; so delete 8 dots (move left) jns putct1 ; ns = non-negative mov ax,0 ; but not less than 0 putct1: mov x_coord,ax ; and replace x coordinate mov al,' ' ; send a space call putc sub x_coord,8 ; restore cursor ret putct2: cmp al,tab ; tabs move forward one char position jne putct4 ; ne = not a tab mov ax,x_coord add ax,8 ; so add 8 cmp ax,xmax ; zero if off edge of screen jbe putct3 mov x_coord,0 mov al,lf jmp short putct5 ; process our new line feed putct3: mov x_coord,ax ret putct4: cmp al,cr ; means go to beginning of line jne putct5 mov x_coord,0 ; zero the x coordinate ret putct5: cmp al,lf ; means go down 8 pixels (1 line) jne putct7 ; ne = not LF add y_coord,10 ; NEC version has 2 pixel space ret putct7: cmp al,vt ; move up screen 1 line (8 pixels) jne putctx sub y_coord,10 ; NEC uses 10 jnc putctx ; nc = space left mov y_coord,10 ; NEC uses 10 putctx: ret putctrl endp incx proc near ; move the logical cursor right mov ax,x_coord ; shift the (logical) cursor right add ax,8 ; one character cell mov x_coord,ax cmp ax,xmax ; at end of the line? jbe incx1 ; b = no mov x_coord,0 ; wrap to next line add y_coord,8 ; next row mov ax,ybot ; last scan line cmp ax,y_coord ; below bottom line? jge incx1 ; ge = no mov y_coord,ax ; set to bottom row mov al,lf ; simulate a line feed operation call outscrn ; invoke More message incx1: ret incx endp code ends end