Name msgibm ; File MSGIBM.ASM include mssdef.h ; Tektronix emulator for use with MS Kermit/IBM. ; Edit history: ; Last edit 16 Jan 1990 ; 8 June 1989 Added Wyse-700 support from Mikko Laanti. ; 21 Nov 1988 Version 2.32 ; 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 ; ; ESC CONTROL-E (ENQ) requests a status report ; ESC FORMFEED erases the screen. ; ESC CONTROL-X turns on bypass mode (no screen characters). ; ESC CONTROL-Z turns on the crosshairs (not on 4006 or 4025) ; ESC ? is replaced by DEL code, to assist line plots with 7 bit systems. ; ESC [ 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. ; ESC [ ? 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. ; ESC [ ? 256 n invokes a screen size report, for Word Perfect. Report is ; ESC [ ? 256; height; width; num colors n where num colors is 0, 1 or ; 16; report ESC [ ? 24; 80; 0 n for pure text mono systems. ; ESC @ through ESC M sets default fill pattern as below (1=@...). ; ESC Z report terminal type (as VT320) ; ESC [ 2; 2 $ u host request color palette report. ; ESC / xhome;yhome;xwidth;yheight x draw an empty rectangle ; ESC / xhome;yhome;xwidth;yheight;pattern y fill rectangle with pattern ; ESC / xhome;yhome;xwidth;yheight;pattern z fill rect with pattern+border ; where x/yhome is the lower left Tek corner, xwidth and yheight are the ; Tek width and height. All values are decimal numbers. ; Patterns 0:use default, 1:solid, 2:grey, 3:left to right slant, 4:right to ; left slant, 5:horizontal lines, 6:vertical lines, 7:slanted cross-hatch, ; 8:vertical cross-hatch, 9:checkerboard; 10:dotted, 11:horiz herringbone, ; 12:vertical herringbone,13 and above:border without fill. All are tiling ; 8x8 pixel patterns. ; ESC / param a, ... ESC / param c set user definable line drawing pattern ; to 16 bit value of param; plot as lsb first. ; ESC / 2 h or l, ESC / 9 h or l. h is set, l is reset, 2 is destructive ; space and 9 is destructive backspace. Defaults are reset. ; ESC x ESC y ESC z selects one of these user definable patterns above. ; ESC P P1; P2; P3 q string ESC \ a Sixel Graphics command ; P1 and P3 ignored, P1 = 1 means draw 0 bits in background, else skip them. ; string is ; sixel chars (3fh..7eh, lower 6 bits+3fh, displayed lsb at the top) ; ! Pn sixel char where Pn is a repeat count ; " Pc; Pad; Ph; Pv raster attributes (all ignored for now) ; # Pc; Pu; Px; Py; Pz coloring as follows ; Pc is color palette, 0-15 ; Pu is color units, 1=HLS, 2=RGB ; For Hue Lightness Saturation: ; Px = Hue angle, 0-360 degrees. The colors are mapped around ; the color wheel in 60 degree segments as Hues: ; 0-29 deg = blue, 30-89 = magenta (blue + red), 90-149 = red, ; 150-209 = yellow (red + green), 210-269 = green, ; 270-329 = cyan (green + blue), 330-359 = blue. ; Py = Lightness, 0-100%, Pz = Saturation, 0-100% ; Lightness Sat = 51-100 Sat = 11-50 Sat = 0-10 ; 86-100 bold white bold white bold white ; 71-85 bold hue bold white bold white ; 57-70 bold hue grey (dim white) grey ; 43-56 bold hue dim hue black ; 29-42 dim hue grey grey ; 14-28 dim hue black black ; 0-13 black black black ; Note that Py = Pz = 50 gives the widest spectrum. ; For RGB: Px = red, 0-100%, Py = green, 0-100%, Pz = blue, 0-100% ; If any color exceeds 50% then the bold bit is turned on for ; the ensemble (IBM ega display adapter constraint for RGBi). ; ; Palette registers can be selected by the substring ; # Pc followed by a non-numeric char other than ";" ; and Pc is the palette register, 0-15. ; ; $ (dollar sign ) meaning go to left margin ; - (minus) meaning go to left margin 6 dots down. ; This command yields one or more sets of 6 vertically arranged dots. They ; are placed starting at the top and left side of the current text cell. ; Escape sequences are permitted within string and occur without disruption. ; 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. ; ESC 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. ; ; 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 tekflg, tekdmp, tekinq, tekpal ; used by mszibm file public chcontrol ; used by msyibm file 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 wyse700 equ 0D3h ; Wyse-700 1280 * 400 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. ; ; Note: WYSE-700 mode 1024 * 780 and 1280 * 800 can be set only by ; manual override SET TERMINAL GRAPHICS WYSET or WYSEA, respectively. ; No automatic sensing for Wyse. 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 segwyse equ 0a000h ; wyse-700, both banks start from here ; Wyse equates: wystoff equ 03ddh ; set bank start offset wystseg equ 03deh ; set bank start base wymode equ 03dfh ; register to select mode & bank wybeven equ 0c8h ; mask for R/W even bank wybodd equ 0cbh ; mask for R/W odd bank ; 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) rgbbold equ 80 ; nor/bold threshold for RGB intensity hiy equ 1 ; codes for Tek graphics components loy equ 2 hix equ 4 lox equ 3 ; maxparam and maxinter must agree with the prime equ's in file mszibm.asm maxparam equ 10 ; number of ESC and DCS Parameters maxinter equ 10 ; number of ESC and DCS Intermediates ; Pixel basic operation codes pixor equ 1 ; write as foreground OR current dot pixbak equ 2 ; write as absolute background color pixxor equ 4 ; write as foreground XOR current dot pixfor equ 8 ; write absolute foreground color data segment public 'data' extrn flags:byte, portval:word, rxtable:byte, vtemu:byte extrn tv_mode:byte, yflags:byte, low_rgt:byte extrn param:word, nparam:word, inter:byte, ninter:word, lparam:byte extrn parstate:word, pardone:word, parfail:word extrn dnparam:word, dparam:word, dlparam:byte, dninter:word extrn dinter:byte, dcsstrf:byte, emubufc:word, emubuf:byte extrn emubufl:word ; 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 attllen 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 dumpname db 'TEKPLT.TIF',0 ; dump name dumplen equ $-dumpname tempname db 84 dup (0) ; temp work area dhandle dw -1 ; dump file handle 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 bnkchan db 0 ; a flag so we can select which bank ; to write in Wyse 1280*800 mode colpal db 0,9,0ch,0ah ; VT340 color palette table, IRGB db 0dh,0bh,0eh,7, 8,1,4,2, 5,3,6,0fh ; 16 bytes, active table coldef db 0,9,0ch,0ah, 0dh,0bh,0eh,7, 8,1,4,2, 5,3,6,0fh ; color def mondef db 0,7 dup (0fh), 8 dup (7) ; monochrome default "colors" 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 dw 0 ; ESC x user defined dw 0 ; ESC y user defined dw 0 ; ESC z user defined linepat dw 0ffffh ; active line pattern, from above tekid db escape,'[?63;1;2;4;8;9;15c',0; VT320, level 3, etc ;End of init data even xmult dw 1 ; scaling factor for x is xdiv dw 1 ; xmult/xdiv ymult dw 1 ; scaling factor for y is ydiv dw 1 ; ymult/ydiv xmax dw 1 ; ybot dw 1 ; x_coord dw 0 ; Tek text char X coordinate y_coord dw 0 ; 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 rectx1 dw 0 ; Rectangle PC x lower left corner recty1 dw 0 ; Rectangle PC y lower left corner rectx2 dw 0 ; Rectangle PC x width recty2 dw 0 ; Rectangle PC y height numlines dw 0 ; number of lines to fill ; area fill material fill db 0 ; current fill byte pattern fillptr dw filpat1 ; pointer to current fill pattern fillist dw filpat1,filpat2,filpat3,filpat4,filpat5,filpat6,filpat7 dw filpat8,filpat9,filpat10,filpat11,filpat12,filpat13 dw filpat14 numfil equ ($-fillist)/2 ; number of fill patterns ; fill patterns, 8 bits wide, first byte is at top of PC screen ; 8 bytes per pattern for 8 scan line repetition filpat1 db 8 dup (0ffh) ; solid fill filpat2 db 4 dup (0aah, 55h) ; grey (alternating dots) filpat3 db 80h,01h,02h,04h, 08h,10h,20h,40h ; right to left slant up filpat4 db 80h,40h,20h,10h, 08h,04h,02h,01h ; left to right slant up filpat5 db 2 dup (0,0,0aah,0) ; horizontal lines filpat6 db 8 dup (44h) ; vertical lines filpat7 db 80h,41h,22h,14h, 08h,14h,22h,41h ; slanted crosshatch filpat8 db 2 dup (0aah,80h,80h,80h) ; vertical crosshatch filpat9 db 4 dup (0f0h), 4 dup (0fh) ; checkerboard filpat10 db 4 dup (44h, 11h) ; dots filpat11 db 2 dup (10h,28h,44h,82h) ; horizontal herringbone filpat12 db 80h,40h,20h,10h,08h,10h,20h,40h ; vertical herringbone filpat13 db 8 dup (0) ; first user definable fill filpat14 db 8 dup (0) ; second user definable fill ; end of area fill material 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 ; 1=Tek reads serial port ; 2=VT300 emulator reads serial port tekident db 0 ; Tek ident request flag 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 colortb db 0,4,2,6,1,5,3,7 ; color reversed-bit setting bytes ccode db pixfor ; temp for holding plot color code bypass db 0 ; GIN mode bypass condition (0=off) esctype db 0 bscontrol db 0 ; non-zero for destructive BS spcontrol db 0 ; non-zero for destructive SPACE chcontrol db 0 ; char-writing, 1=opaque,0=transparent even 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 gfplot dw bpltmon ; ptr to area-fill plot routine segscn dw 0b800h ; actual screen segment to use doneptr dw offset xpardone,seg xpardone ; far pointer for tpardone use dumpptr dw offset dump,seg dump ; far pointer for dump use initptr dw offset tekini,seg tekini rptptr dw offset tekrpt,seg tekrpt endptr dw offset tekend,seg tekend linelen dw 0 ; offset increment between scan lines ten dw 10 ; word 10 for multiplying 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 to - two characters per line ; 8 bits per scan line, top line given 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) ; TIFF version 5.0 data fields ; Reference: Aldus/Microsoft Technical Memorandum dated 8/8/88 ; TIFF data item size indicators uchar equ 1 ; unsigned byte ascii equ 2 ; asciiz string byte integer equ 3 ; 16 bit unsigned integer long equ 4 ; 32 bit unsigned integer rational equ 5 ; 32 bit numerator, 32 bit denominator entry struc ; 12 byte image file directory entries dw ? ; tag dw integer ; type, of data item entcnt dd 1 ; length, count of data items entval dw 0 ; long value or long offset to value dw 0 entry ends even ; TIFF 5.0, 8 byte header header dw 4949h ; 'll', low byte stored first dw 42 ; TIFF identification, 42 decimal dw nentry-header,0 ; long offset to image file directory ; Image File Directory nentry dw entrycnt ; number of entries to follow ; 12-byte directory entries newsub entry <0feh,long> ; new subfield type iwidth entry <100h,integer> ; image width, integer for WP 5 ilength entry <101h,integer> ; image length, integer for WP 5 bps entry <102h,,,4> ; bits per sample, 4=iRGB, 1=B/W comp entry <103h,,,1> ; compression, none photo entry <106h,,,3> ; photometric interpret, palette strip entry <111h,long,25,stripoff-header> ; offset to long strip offsets spp entry <115h,,,1> ; samples/pixel, 1 rps entry <116h,long,1,25> ; long rows per strip sbc entry <117h,integer,25,stripbc-header> ; offset to strip byte counts xres entry <11ah,rational,1,xresval-header> ; x axis resolution yres entry <11bh,rational,1,yresval-header> ; y axis resolution resunit entry <128h,integer,1,1> ; resolution unit, no absolute units soft entry <131h,ascii,proglen,prog-header> ; software ident stamp entry <132h,ascii,dtlen,dandt-header> ; date and time stamp cmap entry <140h,integer,3*16,colmap-header> ; palette color map entrycnt equ ($-nentry-2+11)/12 ; compute number of entries for nentry dd 0 ; long offset of next directory (none) ; supporting data pointed at above prog db 'MS Kermit 300',0 ; originating program, asciiz proglen equ $-prog dandt db '1989:12:25 00:00:01',0 ; date and time format dtlen equ $-dandt xresval dw 0,0,1,0 ; two double words (top / bottom) yresval dw 0,0,1,0 ; two double words (top / bottom) stripoff dd 25 dup (0) ; long file offset for each strip stripbc dw 25 dup (0) ; integer byte count for each strip ; color map for red, green, blue; index by IRGB bits from ega sample colmap dw 4 dup (0), 4 dup (007ffh), 4 dup (0), 4 dup (0ffffh) ; red dw 2 dup (0,0,007ffh,007ffh), 2 dup (0,0,0ffffh,0ffffh) ; green dw 2 dup (0,007ffh,0,007ffh), 2 dup (0,0ffffh,0,0ffffh) ; blue tifflen equ $-header ; length of header + directory + info pixdata equ $ ; pixel data start here on disk ; end of TIFF information esctab db 33 ; table of ESC dispatches dw escjmp ; address of table for action routines db ENQ,FF,CAN,CTLZ,'/' ; ^E,^L,^X,^Z,/ db '@ABCD','EFGHI','JKLM' db 3fh,'PZ[\' ; '?PZ[\' db 60h,'abcde','xyz' ; accent, a..e,x,y,z ; Dispatch for esctab table even escjmp dw tekenq, tekcls,tekcan, tekgin,tekeseq ; ^E,^L,^X,^Z,/ dw 14 dup (tekfill) ; '@ABCDEFGHIJKLM' dw tekqury,tekeseq,sendid,tekeseq,tekgotst ; '?PZ[\' dw 9 dup (teklpat) ; accent, a..e,x,y,z ; Final char table for ANSI escape sequences anstab db 21 ; number of entries dw ansjmp ; address of action routines db '@ABCD','EFGHJ','KXade','fhlmn','u' ; Dispatch for anstab table even ansjmp dw ansich, atcuu, atcud, atcuf, atcub ; '@ABCD' dw atcnl, atcpl, atcha, atcup, ated ; 'EFGHJ' dw atel, atech, atcuf, atcva, atcud ; 'KXade' dw atcup, escexit, escexit, tekcol, tekrid ; 'fhlmn' dw tekprpt ; 'u' data ends code segment public 'code' ; main body code segment extrn outchr:near, beep:near, scrseg:near, cmblnk:near extrn savescr:near, restscr:near, cptchr:near, clrbuf:near extrn iseof:near, atparse:near, unique:near extrn chgdsp:near, pcwait:near, vtrmac:near, vtsmac:near assume cs:code, ds:data, es:nothing ; These far routines are called by the Tek emulator; they are here to provide ; a bridge to the main code segment near procedures. ; Procedures for calling to the main body of MS Kermit. Most are FAR and ; must be in in code segment named code, not in code2. outmodem proc far ; send Tek char out serial port push ax mov ah,al call outchr ; outchr reads from ah pop ax ret outmodem ENDP tekbeep proc far ; sound a beep from Tek mode call beep ret tekbeep endp tcmblnk proc far ; blank the screen from Tek mode call cmblnk ret tcmblnk endp tsavescr proc far ; save text screen while in Tek mode call savescr ret tsavescr endp trestscr proc far ;restore text screen while in Tek mode cmp low_rgt,80 ; were we in 80 column mode? jbe trestsc1 ; be = yes mov al,1 ; set to 132 columns call chgdsp ; msyibm routine to change screen trestsc1: call restscr ret trestscr endp tscrseg proc far ; get video segment while in Tek mode call scrseg ret tscrseg endp tclrbuf proc far ; clear serial port buf while in Tek call clrbuf ; mode ret tclrbuf endp tcptchr proc far ; call session logger while in Tek call cptchr ; mode ret tcptchr endp tiseof proc far ; call iseof while in Tek mode call iseof ret tiseof endp tparstart proc far ; start escape sequence parser mov parstate,0 ; set to initialize automatically mov pardone,offset tpardone ; jmp to this when completed mov parfail,0 ; no failure case jump ret tparstart endp tparser proc far call atparse ; reach to real parser ret tparser endp tpardone proc near ; called by real parser call dword ptr doneptr ; far call xpardone, old MASM way ret tpardone endp tunique proc far ; reach to real unique name procedure call unique ; while in Tek mode ret tunique endp tekwait proc far ; call pcwait while in Tek mode call pcwait ret tekwait endp ; Return screen info for Tek screen report: ax=screen height, bx=width, ; cx=number of colors (0=none for pure text, 1=b/w, 16=ega) tekinq proc near mov tekident,1 ; say this is an ident request call dword ptr initptr ; do init steps to get screen sizes mov ax,ybot ; lowest screen line inc ax ; screen height, in lines mov bx,xmax add bx,8 ; screen width, in dots cmp graph_mode,mono ; pure text mono (no graphics at all)? jne tekinq1 ; ne = no mov ax,24 ; bottom screen line mov bx,80 ; screen width xor cx,cx ; pure mono, say 0 colors jmp short tekinq2 tekinq1:mov cx,1 ; say b/w screen cmp plotptr,offset pltcga ; using CGA style graphics? je tekinq2 ; e = yes cmp graph_mode,monoega ; monochrome monitor on ega? je tekinq2 ; e = yes mov cx,16 ; say 16 colors tekinq2:mov tekident,0 ret tekinq endp ; These routines can be called by either the main body or from within Tek ; mode. tekdmp proc near ; Tek screen dump routine call dword ptr dumpptr ; callable from main body clc ret tekdmp endp tekmac proc far ; invoke vtrmac or vtsmac or ax,ax ; which macro? jz tekmacr ; z = the R flavor call vtsmac ; do TerminalS, in msyibm ret tekmacr:call vtrmac ; do TerminalR, in msyibm ret ; only if they fail tekmac endp tekpal proc near ; do palette report tekrpt call dword ptr rptptr ; callable from main body ret tekpal endp code ends ; main body code segment ; Code segment code2 is allocated to Tektronix emulation code2 segment public 'code2' ; supplementary code segment assume cs:code2, ds:data, es:nothing ; Initialise TEK mode by setting high resolution screen, etc tekini proc far 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,mono ; mono text mode (7)? je tekin1 ; e = yes cmp tekident,0 ; doing an ident request? jne tekin2 ; ne = yes, don't mess with screen test tekflg,1 ; are we active as Tek device now? jz tekin1 ; z = 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 tsavescr ; 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 gfplot,offset bpltcga ; CGA area fill 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? jne tekin2d ; ne = no jmp tekin2c ; yes (default) tekin2d:cmp al,1 ; user wants CGA? jne tekin2a ; ne = no call crossini ; preset crosshairs for new screen 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 tekinwy ; ne = no jmp tekin7 ; do AT&T kind ; Wyse-700 tekinwy:cmp al,8 ; user wants Wyse-700 1024*780 ? jne tekinw0 ; ne = no call chkwyse ; presence test jc tekinwf ; c = failed mov xmax,1024-8 ; x-coord of rightmost character mov ybot,779 ; Bottom of screen is Y=780 mov xmult,1 ; Wyse. Scale TEK to PC by 1024/1024 mov xdiv,1 ; so that 0-1023 converts to 0-1023 mov ymult,1 ; vertical scale is 780/780 mov ydiv,1 ; jmp short tekinw2 ; tekinw0:cmp al,7 ; user wants Wyse-700 1280*780 ? jne tekinw1 ; ne = no call chkwyse ; presence test jc tekinwf ; c = failed mov xmax,1280-8 ; x-coord of rightmost character mov ybot,779 ; Bottom of screen is Y=800 mov xmult,10 ; Wyse. Scale TEK to PC by 1280/1024 mov xdiv,8 ; so that 0-1023 converts to 0-1279 mov ymult,1 ; vertical scale is 780/780 mov ydiv,1 ; jmp short tekinw2 ; tekinwf:jmp tekin2c ; failure jump point tekinw1:cmp al,6 ; user wants Wyse-700 1280*800 ? jne tekin2c ; no = no call chkwyse ; presence test jc tekinwf ; c = failed mov xmax,1280-8 ; x-coord of rightmost character mov ybot,799 ; Bottom of screen is Y=800 mov xmult,10 ; Wyse. Scale TEK to PC by 1280/1024 mov xdiv,8 ; so that 0-1023 converts to 0-1279 mov ymult,40 ; vertical scale for IBM is 800/780 mov ydiv,39 ; so scale those 20 pixels more tekinw2:mov graph_mode,wyse700 ; Assume Wyse Graphics mov segscn,segwyse ; assume wyse screen segment mov gpage,0 ; only one graphics page 0 mov putc,offset gputc ; CGA character display routine mov gcplot,offset gcgen ; CGA character plot routine mov psetup,offset psetupw ; Wyse plot setup routine mov plotptr,offset pltcga ; CGA dot plot routine mov pincy,offset pincyw ; Wyse inc y routine jmp tekin13 ; do Wyse ; 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 gfplot,offset bpltega ; ega area fill routine mov pincy,offset pincye ; inc y routine mov putc,offset gputc ; character display routine mov gcplot,offset gcega ; EGA character plot routine call crossini ; preset crosshairs for new screen 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,attllen ; 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,attllen repe cmpsb je tekin7c ; e = a match mov di,2014h ; and look here mov si,offset ATTLOGO mov cx,attllen 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 gfplot,offset bpltcga ; area fill 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 call crossini ; preset crosshairs for new screen jmp tekin13 tekin7d:cmp curmode,mono ; mono text mode? je tekin8 ; e = yes jmp tekin11 ; ne = no, try cga ; test for Hercules tekin8: call tscrseg ; 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 gfplot,offset bpltcga ; area fill 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: call crossini ; preset crosshairs jmp tekin13 ; set to MONO tekin10:mov graph_mode,mono ; force monochrome adapter text mov segscn,segmono ; assume mono screen segment call tscrseg ; 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 gfplot,offset bpltmon ; area fill plot routine 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 call crossini ; preset crosshairs for new screen 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 call crossini ; preset crosshairs for new screen jmp tekin13 ; Set Graphics mode tekin13:cmp graph_mode,wyse700 ; Wyse ? jne tekin13a ; ne = no call wygraf ; set Wyse graphics mode, clear regen jmp short tekin16 ; restore screen tekin13a:cmp graph_mode,hercules ; Hercules? jne tekin14 ; ne = no cmp tekident,0 ; just identifying? jne tekin16 ; ne = yes call hgraf ; set Herc graphics mode, clear regen or tekflg,1 ; say doing Tekmode 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 tekident,0 ; just identifying screen size etc? jne tekin16 ; ne = yes, do not invoke graphics 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. or tekflg,1 ; say doing Tekmode tekin16:cmp tekident,0 ; just identifying? jne tekin16a ; ne = yes 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 tekin16a:mov si,offset mondef ; default monochrome colors cmp plotptr,offset pltcga ; using CGA style graphics? je tekin17 ; e = yes cmp graph_mode,mono ; pure mono text system? je tekin17 ; e = yes cmp graph_mode,monoega ; ega, but monochrome? je tekin17 ; e = no mov si,offset coldef ; use color palette tekin17:mov al,[si+7] ; foreground color = palette 7 mov gfcol,al mov al,[si] ; background color = palette 0 mov gbcol,al mov cx,16 mov di,offset colpal ; VT340 active color palette push es push ds pop es cld rep movsb ; reinit palette entries pop es call fixcolor ; correct color mapping for some bds mov al,gfcol mov tfcol,al ; remember current coloring mov al,gbcol mov tbcol,al cmp tekident,0 ; just identifying? jne tekin20 ; ne = yes 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,250 call tekwait ; 250 ms wait for display adapter 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:mov al,chcontrol ; opaque/transparent char writing mov bscontrol,al ; set destructive BS control mov spcontrol,al ; set destructive SPACE control mov tekident,0 clc ; clear carry for success pop es pop di pop si pop dx pop cx pop bx pop ax ret tekini endp TEKRINT proc far ; Tek reinitialization entry point call dword ptr endptr ; exit cleanly if alread in Tek mode mov inited,0 ; do complete reinitialization mov tekflg,0 call tekini ret TEKRINT endp ; End TEK emulation, recover previous screen TEKEND proc far mov ttstate,offset tektxt ; set an initial state mov prestate,offset tektxt ; and a previous state test tekflg,1 ; running as a Tek terminal now? jnz teknd1 ; nz = yes mov tekflg,0 ; returning to text emulator ret ; else return as is teknd1: call teksave ; save graphics screen to page 1 cmp graph_mode,hercules ; Hercules? jne teknd2 ; ne = no call htext ; yes then set up Hercules text mode teknd2: mov ah,0 ; set video mode mov al,curmode ; restore previous screen mode int screen ; revert to text screen call trestscr ; restore text screen mov dx,cursor ; saved cursor position mov bh,0 ; page 0 mov ah,2 ; set cursor int screen mov tekflg,0 ; returning to text emulator mov lastc,0 mov bypass,0 ; reset bypass condition mov visible,0 ; next move is invisible clc ret TEKEND ENDP ;Terminal emulation. Enter with received character in AL. TEKEMU proc far ; main emulator call tektt ; local emulator routine ret TEKEMU endp tektt proc near test tekflg,1 ; running as a Tek device? jnz tektt1 ; nz = yes push ax call tekini ; init now pop ax 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: test al,80h ; high bit set? jz tektt1a ; z = no cmp al,9fh ; in range for C1 controls? ja tektt1a ; a = no push ax ; save the char mov al,escape ; make 7-bit control version call tektt2 ; act on escape pop ax sub al,40h ; get second char of 7-bit control tektt1a:and al,7fh ; force Tek chars to be 7 bits or al,al ; NUL char? jnz tektt2 ; nz = no ret ; yes, ignore it (before logging) tektt2: test yflags,capt ; capturing output? jz tektt4 ; z = no, forget this part push ax ; save char call tcptchr ; 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 ret 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 ret tektt5: call ttstate ; do current state ret tektt endp TEKTXT proc near ; Dispatch on text characters mov ttstate,offset tektxt ; this is our state 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 cmp al,LF ; line feed (^J)? je tektx9 ; e = yes cmp al,FF ; form feed (^L)? jne tektx4 ; ne = no call tekcls ; clear the screen ret tektx4: cmp al,VT ; vertical tab (^K)? je tektx7 cmp al,bell ; bell (^G)? jne tektx5 ; ne = no call tekbeep mov bypass,0 ; clear GIN mode bypass condition ret tektx5: cmp al,tab ; horizontal tab (^I)? je tektx7 ; e = yes cmp al,BS ; backspace (^H)? je tektx7 ; e = yes cmp al,' ' ; control char? jae tektx7 ; ae = no jmp tekctl ; process control char 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 tekctl proc near ; Control characters: cmp al,GS ; Line plot command? jne tekctl1 ; 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 tekctl7 tekctl1:cmp al,RS ; Incremental dot command? jne tekctl2 ; ne = no and status,not txtmode ; set status report mov ttstate,offset tekrlin ; expect pen command next jmp tekctl7 tekctl2:cmp al,FS ; Point plot command? jne tekctl3 ; ne = no mov visible,0 ; next move is invisible and status,not txtmode ; set status report byte mov ttstate,offset tekpnt jmp tekctl7 tekctl3:cmp al,US ; assert text mode? [bjh] jne tekctl4 ; ne = no or status,txtmode ; set status report byte mov ttstate,offset tektxt ; go to TEKTXT next time mov bypass,0 ; reset bypass condition mov visible,0 ; next move is invisible jmp tekctl7 tekctl4:cmp al,ESCAPE ; Escape? jne tekctl5 ; ne = no or status,txtmode ; set status report byte cmp ttstate,offset tekesc ; already in escape state? je tekctl7 ; 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 tekctl5:cmp al,CAN ; Control X? (exits Tek sub mode) jne tekctl7 ; ne = no, stay in current state mov ttstate,offset tektxt ; back to text mode cmp flags.vtflg,tttek ; main Tek emulator? je tekctl6 ; e = yes, ignore the ^X call tekend ; else exit sub mode mov visible,0 ; next move is invisible tekctl6:mov prestate,offset tektxt ; make previous state text tekctl7:ret tekctl endp TEKESC proc near ; Process ESC mov bypass,0 ; clear GIN mode bypass condition mov ttstate,offset tekesc ; in case get here from msz file cmp inited,0 ; inited 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,20h ; in intermediates, column 2? jb tekesc3 ; b = no cmp al,2fh ja tekesc3 ; a = no mov ttstate,offset tekesc1 ; stay in this state while intermeds mov bx,ninter ; number of intermediates cmp bx,maxinter ; done enough already? jae tekesc2 ; ae = yes, ignore the excess mov inter[bx],al ; store this one inc ninter ; one more cmp inter,'/' ; HDS2000/3000 Final char? je tekesc3 ; e = yes, process specially like '[' tekesc2:ret ; get more input ; Final char is in AL, dispatch on it tekesc3:mov ttstate,offset tektxt ; set new state mov esctype,al ; save kind of escape sequence mov bx,offset esctab ; ESC dispatch table call atdispat ; dispatch on AL ret TEKESC endp tekeseq proc near ; process Escape and Device Contrl seq call tparstart ; init escape sequence parser mov ttstate,offset escparse ; do parsing next ret tekeseq endp ; State for gathering text to feed escape sequence parser escparse proc near cmp al,' ' ; embedded control code? jb escpar2 ; b = yes, process now call tparser ; far call, to call real parser jnc escpar1 ; nc = success push prestate ; recover previous state pop ttstate stc escpar1:ret escpar2:call tekctl ; process embedded control code push prestate ; get previous state pop ttstate ; restore it ret escparse endp ; Escape sequence parser completion routine ; AL has Final character of escape sequence XPARDONE PROC FAR ; called by tpardone when done cmp esctype,'[' ; ansi escape sequence (ESC [)? jne xpardo3 ; ne = no mov bx,offset anstab ; ANSI ESC [ table call atdispat ; dispatch on Final char in AL jmp short xpardo5 xpardo3:cmp esctype,'/' ; HDS escape sequence (ESC /)? jne xpardo4 ; ne = no call hdsesc ; analyze jmp short xpardo5 xpardo4:cmp esctype,'P' ; DCS introducer? jne xpardo5 ; ne = no call tekdcs ; grab parameters etc, prep strings ret xpardo5:push prestate ; recover previous state pop ttstate ret XPARDONE ENDP ; ESC action routines ; exit each by putting prestate into ttstate tekenq proc near ; ESC-^E Enquiry for cursor position mov bypass,1 ; set bypass mode call sendstat ; send status push prestate ; get previous state pop ttstate ; restore it ret tekenq endp tekcan proc near ; ESC ^X push prestate ; get previous state pop ttstate ; restore it jmp tekctl ; process in controls section tekcan endp tekgin proc near ; ESC-^Z Enter GIN mode cmp graph_mode,mono ; Monochrome text mode? je tekgin1 ; e = yes, no crosshairs in text mode mov bypass,1 ; turn on GIN mode bypass conditon call croshair ; activate the cross-hairs jmp short tekgin2 tekgin1:call tekbeep ; tell the user we are unhappy tekgin2:push prestate ; get previous state pop ttstate ; restore it ret tekgin endp tekqury proc near ; query mark (ESC ? means DEL) mov al,DEL ; replace with DEL code push prestate ; get previous state pop ttstate ; restore it ret tekqury endp tekfill proc near ; Fill series ESC @ .. ESC M sub al,'@' ; remove bias mov bl,al xor bh,bh shl bx,1 ; make a word index mov bx,fillist[bx] ; get pointer to the pattern from list mov fillptr,bx ; assign this pattern pointer push prestate ; get previous state pop ttstate ; restore it ret tekfill endp teklpat proc near ; ESC accent grave line pattern series cmp al,'e' ; accent ... lowercase e? jbe teklpa1 ; be = yes sub al,'x'-'f' ; user sets,map x to f, y to g, z to h teklpa1:push bx mov bl,al sub bl,accent ; remove bias cmp bl,8 ; nine patterns, ignore others ja teklpa2 ; a = illegal xor bh,bh shl bx,1 ; make this a word index mov bx,linetab[bx] ; get line pattern word mov linepat,bx ; save in active word teklpa2:pop bx ; return to previous mode push prestate ; get previous state pop ttstate ; restore it ret teklpat endp ; Detect exit Tek submode command ESC [ ? 38 l from VT340's escexit proc near cmp lparam,'?' ; possible "ESC [ ? 38 l"? jne escex2 ; ne = no cmp nparam,1 ; just one numeric parameter? jne escex2 ; ne = no cmp al,'l' ; ESC [ ? Pn l? jne escex4 ; ne = no, try 'h' cmp param,38 ; correct value? jne escex3 ; ne = no cmp flags.vtflg,tttek ; are we a full Tek terminal now? je escex1 ; e = yes, stay that way call dword ptr endptr ; call far tekend ret escex1: mov ttstate,offset tektxt mov al,CAN ; simulate arrival of Control-X jmp tektxt ; process char as text escex2: ret escex3: cmp param,34 ; ESC [ ? 34 l? jne escex2 ; ne = no call tekend ; play save and restore text mode xor ax,ax ; tell tekmac it's a Reset flavor call tekmac ; returns only if successful ret escex4: cmp al,'h' ; ESC ... l? jne escex3 ; ne = no cmp param,34 ; ESC [ ? 34 h? jne escex2 ; ne = no call tekend ; play save and restore text mode mov ax,1 ; tell tekmac it's a Set flavor call tekmac ; returns only if successful ret escexit endp ; Human Data Systems 2000 style escape sequences (ESC / params Final) hdsesc proc near cmp al,'x' ; draw an empty rectangle? jne hdsesc0 ; ne = no call rectdraw jmp short hdsesc2a hdsesc0:cmp al,'y' ; draw a filled rectangle? jne hdsesc1 ; ne = no call rectfil ;do xhome,yhome,xwidth,yheight,pattern jmp short hdsesc2a hdsesc1:cmp al,'z' ; draw and fill rectangle? jne hdsesc2 ; ne = no call rectfil ; do fill before border call rectdraw ; do border jmp short hdsesc2a hdsesc2:cmp ninter,0 ; any intermediates? jne hdsesc2a ; ne = yes, failure cmp lparam,0 ; letter parameter? jne hdsesc2a ; ne = yes, failure cmp nparam,1 ; just zero or one numeric parameter? ja hdsesc9 ; a = no cmp al,'a' ; user defined pattern? jb hdsesc3 ; b = no cmp al,'c' ja hdsesc3 ; a = no sub al,'a' ; 'a' is first of three user patterns xor ah,ah ; store as 'f,g,h' in the series mov bx,ax shl bx,1 ; make a word index mov ax,param[0] ; get the 16-bit pattern mov linetab[bx+12],ax ; store in user defined pattern hdsesc2a:push prestate ; get previous state pop ttstate ; restore it ret hdsesc3:cmp al,'d' ; "Data Level" (pixel ops)? jne hdsesc4 ; ne = no mov cx,param ; get the parameter value mov al,pixfor ; assume foreground only ESC / 0 d cmp cl,1 ; something else? jb hdsesc3a ; b = no mov al,pixbak ; assume background only ESC / 1 d cmp cl,2 ; something else? jb hdsesc3a ; b = no mov al,pixxor ; assume XOR ESC / 2 d cmp cl,3 ; something else? jb hdsesc3a ; b = no ja hdsesc3b ; a = unknown, ignore mov al,pixfor+pixbak ; write both absolute ESC / 3 d hdsesc3a:mov ccode,al ; use as pixel op coding hdsesc3b:push prestate ; get previous state pop ttstate ; restore it ret hdsesc4:cmp al,'h' ; set space, backspace control? je hdsesc4a ; e = yes cmp al,'l' ; reset space, backspace control? jne hdsesc9 ; ne = no xor ah,ah ; say resetting jmp short hdsesc5 hdsesc4a:mov ah,1 ; say setting hdsesc5:cmp param,2 ; space control? jne hdsesc5a ; ne = no mov spcontrol,ah ; reset (0) or set destructive SPACE push prestate ; get previous state pop ttstate ; restore it ret hdsesc5a:cmp param,9 ; destructive backspace? jne hdsesc13 ; ne = no mov bscontrol,ah ; reset (0) or set destructive BS hdsesc9:cmp al,'C' ; user defined fill pattern #1? jne hdsesc10 ; ne = no mov di,offset filpat13 ; storage area for user pattern #1 jmp short hdsesc11 hdsesc10:cmp al,'D' ; user defined fill pattern #2? jne hdsesc11 ; ne = no mov di,offset filpat14 ; storage area for user pattern #2 hdsesc11:mov cx,8 ; do 8 paramters xor bx,bx hdsesc12:mov ax,param[bx] ; copy 8 bit fill pattern mov [di],al ; to array add bx,2 inc di loop hdsesc12 hdsesc13:push prestate ; get previous state pop ttstate ; restore it ret hdsesc endp ; Analyze ESC [ Pn ; Pn m color command ; where Pn = 30-37 foreground color, 40-47 background color, ANSI standard ; Enter with escape sequence already parsed. TEKCOL proc near push si cld mov si,offset param ; parameters from parser mov cx,nparam ; number of parameters tekco1: jcxz tekco5 ; z = none left lodsw ; parameter to ax dec cx or ax,ax ; 0, remove intensity, set b/w? jnz tekco2 ; nz = no mov tfcol,7 ; regular white mov tbcol,0 ; on black jmp short tekco1 tekco2: cmp ax,1 ; intensity bit? jne tekco3 ; ne = no or tfcol,8 ; set foreground intensity jmp short tekco1 tekco3: cmp ax,30 ; foreground series? jb tekco1 ; b = no cmp ax,37 ja tekco4 ; a = no sub ax,30 ; remove bias push bx mov bl,al xor bh,bh mov al,byte ptr colortb[bx] ; reverse coloring pop bx and tfcol,not (7) ; retain intensity bit or tfcol,al ; remember foreground color jmp short tekco1 tekco4: cmp ax,40 jb tekco1 cmp ax,47 ; legal value? ja tekco1 ; a = no sub al,40 push bx mov bl,al xor bh,bh mov al,byte ptr colortb[bx] ; reverse coloring pop bx mov tbcol,al ; remember background color jmp short tekco1 tekco5: cmp ninter,0 ; intermediates? jne tekco7 ; ne = yes, no go cmp lparam,0 ; letter parameter? jne tekco7 ; ne = yes, no go cmp nparam,0 ; number of ansi arguments, zero? ja tekco6 ; a = no, got some mov tbcol,0 ; none is same as 0, set b/w mov tfcol,7 tekco6: mov al,tbcol ; success, store coloring mov gbcol,al ; set background color mov al,tfcol mov gfcol,al ; set foreground color call fixcolor ; do special ega corrections mov al,gfcol ; update these in case error mov tfcol,al mov colpal[7],al ; foreground goes here mov al,gbcol mov tbcol,al mov colpal[0],al ; background goes here tekco7: pop si clc ret 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 fixcol6 ; e = yes cmp graph_mode,colorega je fixcol6 cmp graph_mode,monoega je fixcol6 cmp plotptr,offset pltcga ; using CGA style graphics? jne fixcol5 ; ne = no and gfcol,7 ; strip intensity jmp short fixcol6 ; keep colors different fixcol5:ret ; else ignore color corrections fixcol6:mov ah,gfcol mov al,gbcol cmp graph_mode,monoega ; monochrome ega 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 xor al,al ; 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 tekrid proc near ; report Tek screen parameters cmp lparam,'?' ; possible "ESC [ ? 38 l"? jne tekridx ; ne = no cmp nparam,1 ; just one numeric parameter? jne tekridx ; ne = no cmp param,256 ; correct value? je tekrid ; e = yes tekridx:ret tekrid1:push es ; as ESC [ ? 256; height; len; #col n push ds pop es cld mov di,offset tempname ; a temp buffer mov al,escape ; report stosb mov al,'[' stosb mov al,'?' stosb mov ax,256 call dec2di ; write ascii digits mov al,';' stosb mov ax,ybot ; do height inc ax cmp graph_mode,mono ; pure mono text system? jne tekrid7a ; ne = no mov ax,24 tekrid7a:call dec2di mov al,';' ; separator stosb mov ax,xmax ; width add ax,8 ; in dots cmp graph_mode,mono ; pure mono text system? jne tekrid7b ; ne = no mov ax,80 tekrid7b:call dec2di mov al,';' ; separator stosb mov al,'1' ; screen colors, assume 1 stosb cmp plotptr,offset pltcga ; using CGA style graphics? je tekrid4 ; e = yes cmp graph_mode,monoega ; monochrome monitor on ega? je tekrid4 ; e = yes cmp graph_mode,mono ; pure mono text system? jne tekrid3 mov byte ptr [di-1],'0' ; say zero colors jmp short tekrid4 tekrid3:mov al,'6' stosb ; say 16 tekrid4:mov al,'n' ; end of string stosb call outstrng ; send the string pop es ret tekrid endp tekprpt proc near cmp nparam,1 ; one or more numeric parameters? jb tekrprx ; b = no cmp param,2 ; "CSI 2 $ u"? jne tekrprx ; ne = no cmp inter,'$' ; correct Intermediate? jne tekrprx ; ne = no call dword ptr rptptr ; invoke the palette report generator tekrprx:ret tekprpt endp tekrpt proc FAR ; report VT340 color palette push es ; DECRQTSR(request), DECCTR(response) push ds pop es push di push bx cld mov di,offset tempname ; a temp buffer mov al,escape ; report stosb cmp plotptr,offset pltcga ; using CGA style graphics? je tekrpt9 ; e = yes cmp graph_mode,mono ; pure mono text system? je tekrpt9 ; e = yes cmp graph_mode,monoega ; monochrome monitor on ega? jne tekrpt10 ; ne = no tekrpt9:mov ax,'0P' ; b/w systems report DCS 0 $ s ST stosw mov ax,'s$' stosw call outstrng jmp tekrpt8 tekrpt10:mov ax,'2P' ; color systems report DCS 2 $ s...ST stosw mov ax,'s$' stosw ; "ESC [ 2 $ s" call outstrng ; output this string mov cx,16 ; number of palette registers to do xor bx,bx ; begin with color palette 0 tekrpt1:push bx ; save palette index push cx ; save loop counter mov di,offset tempname ; buffer mov ax,bx ; palette number call dec2di ; palette register, to buffer mov ax,'2;' ; ";2;" means sending RGB values stosw mov al,';' stosb mov ah,colpal[bx] ; get palette iRGB mov al,rgbbold/4 ; assume dark red for bold black cmp ah,8 ; bold black? je tekrpt2 ; e = yes xor al,al test ah,4 ; red? jz tekrpt2 ; z = no mov al,rgbbold/2 ; say red, 40% test ah,8 ; bold? jz tekrpt2 ; z = no mov al,rgbbold ; more if bold tekrpt2:push ax xor ah,ah ; clear high byte call dec2di ; store red pop ax mov al,';' ; separator stosb mov al,rgbbold/4 ; assume dark green for bold black cmp ah,8 ; bold black? je tekrpt4 ; e = yes xor al,al test ah,2 ; green? jz tekrpt4 ; z = no mov al,rgbbold/2 ; say green, 40% test ah,8 ; bold? jz tekrpt4 ; z = no mov al,rgbbold ; more if bold tekrpt4:push ax xor ah,ah ; clear high byte call dec2di ; store green pop ax mov al,';' ; separator stosb mov al,rgbbold/4 ; assume dark blue for bold black cmp ah,8 ; bold black? je tekrpt6 ; e = yes xor al,al test ah,1 ; blue? jz tekrpt6 ; z = no mov al,rgbbold/2 ; say blue, 40% test ah,8 ; bold? jz tekrpt6 ; z = no mov al,rgbbold ; more if bold tekrpt6:xor ah,ah ; clear high byte call dec2di ; store blue pop cx ; recover loop counter cmp cx,1 ; doing last item? je tekrpt7 ; e = yes, do not send another "/" mov al,'/' ; separator stosb tekrpt7:push cx call outstrng ; output this string pop cx pop bx ; recover palette index inc bx ; ready for next palette dec cx jz tekrpt8 ; z = done jmp tekrpt1 ; do all palettes tekrpt8:mov al,escape ; DCS terminator ST call outmodem mov al,'\' call outmodem pop bx pop di pop es ret tekrpt endp ; Output string in tempname. Enter with di pointing at last byte+1. Return ; with di at the same place. outstrng proc near push cx mov cx,di ; compute length mov di,offset tempname ; start of buffer sub cx,di ; start of buffer outstn1:mov al,[di] inc di call outmodem ; send the byte loop outstn1 ; do the string pop cx ret outstrng endp ; Process Device Control Strings (DCS or ESC P lead-in chars, parameters, ; and Final character already read). Prepare to gather strings. tekdcs proc near mov dcsstrf,al ; record Final char mov emubufc,0 ; clear string count mov cx,maxparam ; number of DCS parameters push si ; copy these to the DCS area so that push di ; they are not lost when an ST is push es ; parsed (parser clears ESC items) push ds pop es mov si,offset param ; ESC paramater storage area, numeric mov di,offset dparam ; DCS parameter storage area, numeric cld rep movsw ; copy set to DCS storage area mov cl,lparam ; copy letter Paramter mov dlparam,cl mov cx,maxinter ; number of intermediate characters mov si,offset inter ; source mov di,offset dinter ; destination rep movsb mov si,nparam ; number of parameters mov dnparam,si mov si,ninter mov dninter,si ; number of intermediates pop es pop di pop si cmp dcsstrf,'q' ; Sixel Graphics? jne tekdcs1 ; ne = no mov ttstate,offset tekgets ; get string as next state ret tekdcs1:mov ttstate,offset tekdcsnul ; consume unknown DCS ret tekdcs endp ; Read and discard OSC (ESC ]), PM (ESC ^), APC (ESC _) control sequences ; through final ST (ESC \) terminator. tekdcsnul proc near mov dcsstrf,0 ; simulate a null (dummy) Final char cmp al,20h ; control char? jae tekdcsnu1 ; ae = no, skip jmp tekctl ; do control char tekdcsnu1:ret tekdcsnul endp ; State machine to process DCS strings of type "q" (Sixel Command and Data) ; Enter with new char in AL. tekgets proc near mov ttstate,offset tekgets ; set state to ourselves mov nparam,0 ; say no pending control sequences cmp al,20h ; control character? jae tekgsch ; ae = no, analyze jmp tekctl ; do control char ; single sixel char state tekgsch:cmp al,3fh ; legal sixel data char? jb tekgrpt ; b = no, try repeated char mov cx,1 ; repeat count of 1 jmp sixplt ; plot the six dots tekgrpt:cmp al,'!' ; repeated char? jne tekgera ; ne = no mov ttstate,offset tekgrpt0 ; next state is get repeat parameter mov param,0 mov nparam,0 ret tekgrpt0:cmp al,' ' ; control char? jae tekgrpt1 ; ae = no jmp tekctl ; process control char tekgrpt1:mov cx,param ; first param is used here call getdec ; accumulate repeat count to cx mov param,cx ; retain current count jc tekgrpt2 ; c = ended on non-numeric ret ; get more characters tekgrpt2:cmp al,3fh ; break char, is it a sixel datum? jb tekgrpt3 ; b = no, it is illegal, quit call sixplt ; plot cx versions of the six bits mov ttstate,offset tekgets ; return to sixel idle state ret tekgrpt3:jmp short tekgets ; reprocess break character tekgera:cmp al,22h ; double quote raster attribute? jne tekgco ; ne = no, try color mov param,0 ; clear parameters, Pan mov param[2],0 ; Pad mov param[4],0 ; Ph mov param[6],0 ; Pv mov nparam,0 ; work on initial parameter first mov ttstate,offset tekgra1 ; next state is get parameter ret tekgra1:cmp al,' ' ; control char? jb tekgra2 ; b = yes, finish this work first push bx mov bx,nparam ; parameter number shl bx,1 ; make it a word index mov cx,param[bx] ; accumulated parameter call getdec ; accumulate decimal value into cx mov param[bx],cx ; remember accumulation pop bx jc tekgra2 ; c = failure to get a digit char ret tekgra2:inc nparam ; say have another complete parameter cmp nparam,4 ; got all four params Pan,Pad,Ph,Pv? je tekgra4 ; e = yes cmp al,';' ; break char is separator? jne tekgra3 ; ne = no, quit now ret ; get more characters tekgra3:jmp tekgets ; restart with the break char tekgra4:;;; perform raster attributes work here mov ttstate,offset tekgets ret tekgco: cmp al,'#' ; color introducer? je tekgco0 ; e = yes jmp tekgcr ; ne = no tekgco0:mov ttstate,offset tekgco1 ; next state is get parameter mov param,0 ; clear parameters, Pc mov param[2],0 ; Pu mov param[4],0 ; Px mov param[6],0 ; Py mov param[8],0 ; Pz mov nparam,0 ; work on initial parameter first ret tekgco1:cmp al,' ' ; control char? jb tekgco2 ; b = yes, finish this work first push bx mov bx,nparam ; parameter number shl bx,1 ; make it a word index mov cx,param[bx] ; accumulated parameter call getdec ; accumulate decimal value mov param[bx],cx ; remember accumulation pop bx jc tekgco2 ; c = failure to get a digit char ret tekgco2:inc nparam ; say have another complete parameter cmp al,';' ; break char is separator? jne tekgco3 ; ne = no, decode current sequence cmp nparam,5 ; have 5 params already? jae tekgco3 ; ae = yes, process them now ret ; else get more parameters tekgco3:cmp nparam,1 ; just one parameter? je tekgco3a ; e = yes, select from palette jb tekgco3b ; b = none, reprocess as sixel call tekgco4 ; process parameters mov nparam,0 ; clear parameters jmp tekgets ; reprocess char as sixel tekgco3a:push bx ; select color from palette mov bx,param[0] ; get color number and bx,000fh ; get 0-15 mov bl,colpal[bx] ; get color from palette mov gfcol,bl ; set active foreground color pop bx push ax ; save char in al call fixcolor ; fix color too, if req'd pop ax tekgco3b:mov nparam,0 ; clear parameters jmp tekgets ; reprocess char as sixel ; set IRGB/HLS color to color palette tekgco4:cmp param[2],2 ; Pu (1-2), wanted RBG? je tekgco4b ; e = yes cmp param[2],1 ; Pu, wanted HLS? jne tekgco4a ; ne = no jmp tekgco9 ; do HLS scheme tekgco4a:mov nparam,0 ; clear parameters ret ; return without doing work tekgco4b:push ax ; iRGB, save break char in al mov ax,param[4] ; red mov bx,param[6] ; green mov dx,param[8] ; blue xor cx,cx ; cl has final color index, 0-15 or ch,al or ch,bl or ch,dl ; any color? jcxz tekgco7 ; z = no, use cl = 0 black cmp ax,rgbbold ; setting red bold? jae tekgco4c ; ae = yes cmp bx,rgbbold ; setting green bold? jae tekgco4c ; ae = yes cmp dx,rgbbold ; setting blue bold? jb tekgco4d ; b = no tekgco4c:mov cl,8 ; set the bold bit jmp tekgco4e ; do hues tekgco4d:cmp ax,rgbbold/2 ; all in dim intensities? jae tekgco4e ; ae = no cmp bx,rgbbold/2 ; green? jae tekgco4e ; ae = no cmp dx,rgbbold/2 ; blue jae tekgco4e ; ae = no mov cl,8 ; use bold black (dark grey) jmp tekgco7 tekgco4e:or ax,ax ; Hues, any red? jz tekgco5 ; z = no or cl,4 ; set red bit cmp ax,rgbbold/2 ; dim? jae tekgco5 ; ae = no test cl,8 ; doing bold? jz tekgco5 ; z = no xor cl,4 ; clear dim red tekgco5:or bx,bx ; any green? jz tekgco6 ; z = no or cl,2 ; set green bit cmp bx,rgbbold/2 ; dim? jae tekgco6 ; ae = no test cl,8 ; doing bold? jz tekgco6 ; z = no xor cl,2 ; clear dim green tekgco6:or dx,dx ; any blue? jz tekgco7 ; z = no or cl,1 ; set blue bit cmp dx,rgbbold/2 ; dim? jae tekgco7 ; ae = no test cl,8 ; doing bold? jz tekgco7 ; z = no xor cl,1 ; clear dim blue tekgco7:push bx mov bx,param[0] ; Pc, color palette being defined and bx,000fh ; get 0-15 mov colpal[bx],cl ; store color code in palette pop bx mov nparam,0 ; say done with this sequence pop ax ; recover break char in al ret ; Hue, Lightness, Saturation tekgco9:push ax ; save break char xor cl,cl ; assummed color of black mov ax,param[4] ; Px, Hue, 60 degree slices push cx mov cx,360 ; do modulo 360 xor dx,dx ; clear high order numerator div cx ; dx has remainder pop cx mov ax,dx ; put remainder in ax cmp ax,30 ; blue? jae tekgco10 ; ae = no or cl,1 ; blue jmp short tekgco15 tekgco10:cmp ax,90 ; magenta? jae tekgco11 ; ae = no or cl,1+4 ; magenta = blue + red jmp short tekgco15 tekgco11:cmp ax,150 ; red? jae tekgco12 ; ae = no or cl,4 ; red jmp short tekgco15 tekgco12:cmp ax,210 ; yellow? jae tekgco13 ; ae = no or cl,4+2 ; yellow = reg + green jmp short tekgco15 tekgco13:cmp ax,270 ; cyan? jae tekgco14 ; ae = no or cl,2+1 ; cyan = green+blue jmp short tekgco15 tekgco14:or cl,1 ; blue tekgco15:mov ax,param[6] ; Py, Lightness mov dx,param[8] ; Pz, Saturation cmp ax,86 ; lightness is max? jb tekgco16 ; b = no mov cl,0fh ; greater than 85% means bold white jmp short tekgco22 tekgco16:cmp ax,71 ; high lightness? jb tekgco17 ; b = not that light or cl,8 ; turn on bold bit cmp dx,51 ; saturated? jae tekgco22 ; ae = yes mov cl,0fh ; low saturation yields bold white jmp short tekgco22 tekgco17:cmp ax,57 ; central coloring, upper? jb tekgco18 ; b = no or cl,8 ; turn on bold bit cmp dx,51 ; saturated? jae tekgco22 ; ae = yes, use bold colors mov cl,7 ; s < 50 is dim white cmp dx,11 ; saturated less than 11% jae tekgco22 ; ae = no xor cl,cl ; s < 11 is black here jmp short tekgco22 tekgco18:cmp ax,43 ; dim colors, upper? jb tekgco19 ; b = no or cl,8 ; turn on bold bit cmp dx,51 ; saturated? jae tekgco22 ; ae = yes, use bold colors and cl,not 8 ; use dim colors jmp short tekgco22 tekgco19:cmp ax,29 ; dim colors, lower? jb tekgco20 ; b = no cmp dx,51 ; saturated? jae tekgco22 ; ae = yes mov cl,7 ; use dim white jmp short tekgco22 tekgco20:cmp ax,14 ; dark colors? jb tekgco21 ; b = no cmp dx,51 ; saturated? jae tekgco22 ; ae = yes tekgco21:xor cl,cl ; use black tekgco22:push bx mov bx,param[0] ; Pc, color palette being defined and bx,000fh ; get palette 0-15 mov colpal[bx],cl ; store color code in palette pop bx mov nparam,0 ; say done with this sequence pop ax ; recover break char ret tekgcr: cmp al,'$' ; graphics carriage return? jne tekgnl ; ne = no mov x_coord,0 ; go to left margin, no line feed ret tekgnl: cmp al,'-' ; graphics new line? jne tekgunk ; ne = no mov x_coord,0 ; go to left margin, no line feed mov ax,y_coord ; bottom of char cell add ax,6 ; go down 6 dots cmp ax,ybot ; wrapping below bottom? jbe tekgnl1 ; be = no mov ax,ybot ; stop at bottom (leaves 2 dots free!) tekgnl1:mov y_coord,ax ret tekgunk:mov ttstate,offset tekgets ; unknown char cmp al,' ' ; control char? jae tekgun1 ; ae = no jmp tektxt ; process control char tekgun1:ret ; ignore the unknown char tekgets endp ; Accumulate decimal value in CX using ascii char in al. ; Return with value in CX. Return carry clear if ended on a digit, ; return carry set and ascii char in al if ended on a non-digit. getdec proc near cmp al,'0' ; a number? jb getdecx ; b = no, quit cmp al,'9' ja getdecx ; a = not a number, quit sub al,'0' ; remove ascii bias xchg cx,ax ; put char in cx, decimal value in ax push dx ; save reg mul ten ; times ten for a new digit pop dx ; recover reg, ignore overflow add al,cl ; add current digit adc ah,0 ; 16 bits worth xchg ax,cx ; rpt cnt back to cx clc ; say found a digit ret getdecx:stc ; say non-digit (in al) ret getdec endp ; Display lower six bits of AL in a column, a sixel datum. Do CX times. ; Location is PC text cursor, x_coord, y_coord, with least significant bit ; at the top (at y_coord+8). Increments x_coord by one for each interation ; but stops at right margin and does not change y_coord. If dparam[2], P2, ; is 1 then color pattern 0 bits in current background, else skip them. sixplt proc near cmp cx,0 ; repeat count present? jne sixplt1 ; ne = yes ret sixplt1:push ax push bx push linepat ; save line pattern sub al,3fh ; remove ascii bias from sixel char xor ah,ah mov linepat,ax ; our dot pattern in lower 6 bits mov di,y_coord ; text bottom cell line sub di,8 ; go to top of 8 high char cell jnc sixplt2 ; nc = no wrap over top xor di,di ; limit to screen top sixplt2:mov bx,di ; bx = ending y add bx,5 ; plus our six dots (goes down screen) cmp bx,ybot ; wrapping below bottom? jbe sixplt3 ; be = no mov bx,ybot ; stop at bottom sixplt3:mov ax,x_coord ; left edge of text cell mov si,ax ; si=starting, ax=ending PC x coord add xmax,7 ; refer to right edge, not right char push es ; set up for dot plotting, save regs push si push di push dx push bp mov dl,ccode ; existing pixel op code push dx ; save ccode around line drawing mov ccode,pixor ; set OR pixel op for use by plot() cmp gfcol,0 ; all black dots? jne sixplt3a ; ne = no mov ccode,pixfor ; yes, force overwriting to nulls sixplt3a:push cx call psetup ; setup display and es:di and es:si pop cx ; start sixel repeat loop sixplt4:push cx ; save sixel repeat count push di ; save y starting screen address mov bp,linepat ; store active line pattern word in BP mov cx,6 ; six dots per sixel ; start six dot loop sixplt5:push cx ; save dot count mov cl,pixFor ; assume foreground coloring test bp,1 ; bit to be plotted, is it a 1? jnz sixplt6 ; nz = yes, plot in foreground color cmp dparam[2],1 ; P2 = 1, skip over 0's? je sixplt6 ; e = yes mov cl,pixbak ; use background write pixel op or bp,1 ; set pattern bit so we see a pixel sixplt6:mov ccode,cl ; desired pixel op call plotptr ; plot a dot if it is a 1 call pincy ; next dot down the screen (di) pop cx ; recover dot counter loop sixplt5 ; do each of 6 dots ; pop di ; recover starting y screen coord pop cx ; recover repeat count cmp ax,xmax ; off right edge? jae sixplt8 ; ae = yes inc ax ; move right one pixel inc si ; start and stop x's sixplt8:loop sixplt4 ; repeat sixel cx times pop dx mov ccode,dl ; recover main color code pop bp pop dx pop di pop si pop es mov x_coord,ax ; new text starting x coord sub xmax,7 ; restore to right most char cell pop linepat ; restore normal line pattern pop bx pop ax ret sixplt endp ; Process ST or ESC \ String Terminator. tekgotst proc near mov dcsstrf,0 ; clear DCS Final char mov nparam,0 mov ninter,0 mov al,colpal[7] ; reset foreground to palette 7 mov gfcol,al mov al,colpal[0] ; and background to palette 0 mov gbcol,al call fixcolor ; and fix up coloring, if req'd mov prestate,offset tektxt ; reset state of emulator to normal mov ttstate,offset tektxt ret tekgotst endp TEKLINE proc near ; GS line drawing cmp al,' ' ; control char? jae teklin3 ; ae = no cmp al,CR ; exit drawing on CR,LF,RS,US,FS,CAN je teklin2 ; e = yes, a cr cmp al,LF ; these terminate line drawing cmds je teklin2 cmp al,FS ; je teklin2 cmp al,GS ; je teklin2 cmp al,RS ; je teklin2 cmp al,US ; je teklin2 cmp al,CAN ; and je teklin2 ; BUT ignore other control chars cmp al,escape ; escape? je teklin1 ; e = yes, come back to this state ret ; ignore stray control char teklin1:jmp tekctl ; process control char teklin2:mov lastc,0 ; clear last drawing coordinate flag mov visible,0 ; invisible again jmp tektxt ; process char under text mode teklin3:call tekxyc ; parse coordinates from input bytes jc teklin4 ; c = done, do the plotting ret ; nc = not done yet teklin4:mov cl,visible ; get moveto or drawto variable call tekdraw ; move that point mov visible,1 ; say next time we draw ret TEKLINE endp TEKPNT proc near ; FS plot single point cmp al,' ' ; control char? jae tekpnt3 ; ae = no cmp al,CR ; exit drawing on CR,LF,RS,US,FS,CAN je tekpnt2 ; e = yes, a cr cmp al,LF ; these terminate line drawing cmds je tekpnt2 cmp al,FS ; je tekpnt2 cmp al,GS ; je tekpnt2 cmp al,RS ; je tekpnt2 cmp al,US ; je tekpnt2 cmp al,CAN ; and je tekpnt2 ; BUT ignore other control chars cmp al,escape ; escape? je tekpnt1 ; e = yes clc ret ; ignore stray control char tekpnt1:jmp tekctl ; process control char tekpnt2:mov lastc,0 ; clear last drawing coordinate flag mov visible,0 ; invisible again jmp tektxt ; process char under text mode tekpnt3:call tekxyc ; parse coordinates jc tekpnt4 ; c = done, do the plotting ret ; nc = not done yet tekpnt4:xor cl,cl ; 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 clc 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,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 ; e = 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: 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 ; carry clear means done 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,' ' ; control char? jae tekrli1 ; ae = no jmp tektxt ; process control char tekrli1:cmp al,' ' ; pen up command? jne tekrli2 ; ne = no, try pen down mov visible,0 ; do invisible movements jmp short tekrli3 ; do the command tekrli2:cmp al,'P' ; pen down command? jne tekrli4 ; ne = no, return to text mode mov visible,1 ; set visible moves tekrli3:mov ax,x_coord ; PC x coordinate of pen mov bx,y_coord ; y coordinate call pctotek ; get current pen position in Tek coor xor cl,cl ; invisible, moveto call tekdraw ; move that point, set oldx and oldy mov ttstate,offset tekinc ; next get incremental movement cmds ret tekrli4:mov visible,0 ; bad char, reset visibility mov ttstate,offset tektxt ; assume text tekrli5:jmp ttstate ; deal with bad char TEKRLIN endp ; interpret RS inc plot command byte TEKINC proc near ; get movement character and do cmd cmp al,' ' ; control char? jae tekinc1 ; ae = no jmp tektxt ; process control char tekinc1:mov bx,oldx mov cx,oldy test al,1 ; 'A', 'E', 'I'? Do by bit fields jz tekinc2 ; z = no inc bx ; adjust beam position tekinc2:test al,2 ; 'B', 'F', 'J'? jz tekinc4 dec bx tekinc4:test al,4 ; 'D', 'E', 'F'? jz tekinc8 ; z = no inc cx tekinc8:test al,8 ; 'H', 'I', 'J'? jz tekinc9 dec cx tekinc9:cmp bx,0 ; too far left? jge tekinc10 ; ge = no xor bx,bx ; else stop at the left margin tekinc10:cmp bx,maxtekx-1 ; too far left? jle tekinc11 ; le = no mov bx,maxtekx-1 ; else stop that the left margin tekinc11:cmp cx,maxteky-1 ; above the top? jle tekinc12 ; le = not above the top mov cx,maxteky-1 ; else stop at the top tekinc12:cmp cx,0 ; below bottom? jge tekinc13 ; ge = not below bottom xor cx,cx ; else stop at the bottom tekinc13:mov ax,bx ; ax is vector x end point mov oldx,bx mov bx,cx ; bx is vector y end point mov oldy,cx mov cl,visible jmp tekdraw ; move/draw to that point tekincb:mov visible,0 jmp tektxt ; reparse the bad char TEKINC endp crossini proc near ; set crosshairs for initial screen 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 ret crossini 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 tiseof ; 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 tiseof ; is stdin at EOF? jc crosha2 ; c = yes, exit this mode now mov ah,coninq ; read scan code int dos or al,al ; Control-Break? jnz crosha3 ; nz = 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 tekbeep ; 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 ; s = yes, make it 0 noxc: cmp cx,temp ; too far right? jb xdraw9 ; b = no mov cx,temp ; yes, 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 ; s = yes then make 0 noyc: cmp cx,ybot ; too high? jb yok ; b = no mov cx,ybot ; make it maximum yok: mov ycross,cx ; save new y crosshair jmp crosha1 ; and redraw charkey:push ax ; preserve char in al call tclrbuf ; purge received data to date pop ax 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 xor cx,cx ; 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 al,ccode ; save current pixel op push ax 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 xor di,di ; 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 cl,pixxor ; xor pixels call line ; and draw vertical sub si,12 ; move to (xcross-12, ycross) jns crosd3 ; no sign means ok xor si,si ; 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 cl,pixxor ; set XOR code call line ; draw to (xcross+12, ycross) pop ax ; recover current pixel op mov ccode,al ; restore it 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 ; Write binary number in AX as decimal asciiz to buffer pointer DI. dec2di proc near ; output number in ax using base in cx ; corrupts ax, cx, and dx mov cx,10 dec2di1:xor dx,dx ; clear high word of numerator div cx ; (ax / cx), remainder = dx, quotient = ax push dx ; save remainder for outputting later or ax,ax ; any quotient left? jz dec2di2 ; z = no call dec2di1 ; yes, recurse dec2di2:pop dx ; get remainder add dl,'0' ; make digit printable mov [di],dl ; store char in buffer inc di mov byte ptr[di],0 ; add terminator ret dec2di 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 VT340 mov bx,offset tekid ; VT320 identification string sndid1: mov al,[bx] ; get char from sequence or al,al ; end of sequence? jz sndid0 ; z = 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 ; 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 ; put one character to the screen cmp bypass,0 ; GIN mode bypass off? je outscr1 ; e = yes ret ; else ignore characters ; Set Translation Input filter outscr1:cmp rxtable+256,0 ; translation turned off? je outscr2 ; 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 outscr2:mov ccode,pixor ; assume transparent chars cmp chcontrol,0 ; transparent chars? je outscr3 ; e = yes mov ccode,pixfor ; write in foreground outscr3:cmp al,lf ; this moves down the screen je outscr4 ; e = yes, a lf cmp al,' ' ; printable? jb outscr5 ; b = no outscr4:call testfull ; check for full screen outscr5:call putc ; routine to draw characters ret OUTSCRN ENDP ; Test if screen is full. If full sound beep, wait for any keyboard input ; (skip kbd reading if stdin is redirected). testfull proc near push ax mov ax,x_coord cmp ax,xmax ; at end of the line? jbe testfu1 ; be = no mov x_coord,0 ; wrap to next line add y_coord,8 ; next row testfu1:mov ax,ybot ; get last scan line inc ax ; number of scan lines cmp ax,y_coord ; minus where char bottom needs to go jae testfu3 ; ae = enough space for char call tekbeep ; tell the user we are waiting call tiseof ; EOF on redirected stdin? jc testfu2 ; c = yes, proceed anyway mov ah,coninq ; read keyboad via DOS int dos ; wait for keystroke or al,al ; scan code being returned? jne testfu2 ; ne = no mov ah,coninq ; clear away scan code too int dos testfu2:call tekcls ; clear the screen mov x_coord,0 mov y_coord,0 testfu3:pop ax ; recover current character ret testfull endp ; TEKCLS routine to clear the screen. ; Entry point tekcls1 clears screen without resetting current point. TEKCLS PROC NEAR cmp flags.vtflg,tttek ; regular Tek terminal? je tekcls0 ; e = yes test tekflg,1 ; Tek mode active yet? jnz tekcls0 ; nz = yes ret ; else ignore this call tekcls0:mov x_coord,0 ; starting text coordinates mov y_coord,0 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 bypass,0 ; clear bypass condition mov ttstate,offset tektxt ; do displayable text mov prestate,offset tektxt tekcls1:push ax ; save registers push cx mov bl,ccode ; save pixel op code push bx cmp graph_mode,hercules ; Hercules? jne tekclsw ; ne = no call hgraf ; set Hercules board to Graphics mode jmp tekcls7 tekclsw:cmp graph_mode,wyse700 ; Wyse 700? jne tekcls2 ; ne = no call wygraf ; set board to Graphics mode & cls jmp tekcls7 tekcls2:mov di,0 ; point to start of screen, di=row mov ccode,pixbak ; write in background 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 xor ax,ax test gbcol,7 ; background is dark? jz tekcls3a ; z = yes mov ax,0ffffh ; light, set all pixels tekcls3a:shr cx,1 ; do words rep stosw ; clear the words 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 ax,0003h ; data rotate reg, write unmodified call ega_gc ; mov cx,ybot ; last scan line inc cx ; number of scan lines mov ax,80/2 ; words (2*bytes) per scan line mul cx mov cx,ax ; cx = number of bytes to clear call fixcolor ; fix colors first, if req'd mov al,gbcol ; select background colour mov ah,al ; copy for word stores cld rep stosw ; write backgound color jmp short tekcls7 tekcls6:push es ; clear screen by scrolling up call tcmblnk ; clear screen, for Environments pop es tekcls7:xor si,si ; starting x (in case screen is xor di,di ; starting y cleared by user) pop bx mov ccode,bl ; restore pixel op code 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, else draw in foreground colors 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 mov cl,pixfor ; draw in foreground color 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 cmp ax,1023 ; limit x axis jbe scale1 ; be = not out of bounds mov ax,1023 scale1: cmp bx,779 ; limit y axix jbe scale2 ; be = not out of bounds mov bx,779 scale2: 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 xor bx,bx 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 ; CCODE=pixel operation code ; 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 dl,ccode ; existing pixel op code push dx ; save around line drawing 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 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 ;;; jmp plotex plotex: pop dx ; al has orginal pixel op mov ccode,dl ; restore it pop es pop di pop si pop dx ; restore the world pop cx pop bx pop ax ret LINE ENDP ; Draw a rectangle. ; lower left corner: x = param[0], y = param[2], Tek coordinates ; distance: dx = param[4], dy = param[6], Tek coordinates, all positive rectdraw proc near push x_coord push y_coord mov ax,param[0] ; lower left corner is start, x part mov bx,param[2] ; y part push ax ; x0 push bx ; y0 mov cl,0 ; moveto call tekdraw pop bx pop ax add bx,param[6] ; y0 + dy mov cl,1 ; draw x0,y0 to x0,y0+dy push ax push bx call tekdraw pop bx pop ax add ax,param[4] ; x0+dx mov cl,1 ; draw x0,y0+dy to x0+dx,y0+dy push ax call tekdraw pop ax mov bx,param[2] ; y0 push bx mov cl,1 call tekdraw pop bx mov ax,param[0] ; x0 mov cl,1 call tekdraw ; complete the box pop y_coord pop x_coord ret rectdraw endp ; Fill a rectangle with a given pattern. ; lower left corner: x = param[0], y = param[2], Tek coordinates ; distance: dx = param[4], dy = param[6], Tek coordinates, all positive ; fill pattern = param[8] rectfil proc near push oldx push oldy ; save regular point/line old coords mov ax,param ; get Tek X coord of lower left corner mov bx,param[2] ; get Tek Y coord call scale ; convert to PC in ax,bx, scalex/y mov rectx1,ax ; lower left corner in PC coords mov recty1,bx mov ax,param ; convert ending points, start Tek X add ax,param[4] ; Tek X + DX mov bx,param[2] ; start Tek Y add bx,param[6] ; Tek Y + DY call scale pop oldy pop oldx mov rectx2,ax ; upper right corner PC X coord mov recty2,bx ; upper right corner PC Y coord mov si,rectx1 ; starting x PC coord to si mov di,recty2 ; starting y PC coord to di mov cx,recty1 ; plotting from top down on screen sub cx,bx ; cx = # scan lines - 1 mov numlines,cx ; remember here mov bx,param[8] ; fill pattern number or bx,bx ; zero? jz rectfi1 ; z = yes, use current pointer cmp bx,numfil ; pattern number is too large? ja rectfi1 ; a = yes, use current pointer dec bx ; count internally from 0 shl bx,1 ; make this a word pointer mov bx,fillist[bx] ; get pointer to pattern mov fillptr,bx ; remember it here rectfi1:mov cx,rectx2 ; ending x coord sub cx,rectx1 ; number of horizontal pixels - 1 inc cx ; number of horizontal pixels call psetup ; set up dsp and di to screen offset ; di points to whole byte, do bits in byte in gfplot rectfi2:push bx mov bx,recty1 ; lower screen y (larger value) sub bx,numlines ; alignment: global screen sync and bx,7 ; modulo 8 add bx,fillptr ; offset of fill pattern start mov bl,[bx] ; pattern byte mov fill,bl ; save here for gfplot pop bx call gfplot ; line fill routine call pincy ; next line dec numlines jns rectfi2 ; ns = more to do ret rectfil 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 test ccode,pixfor+pixbak ; direct foreground/background write? jnz psete2 ; nz = yes mov ax,1003h ; assume OR test ccode,pixor ; OR? jnz psete2 ; nz = yes mov ax,1803h ; assume XOR test ccode,pixxor ; inverting bits? jnz psete2 ; nz = yes mov ax,0803h ; then use AND 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 ror bp,1 ; rotate line pattern jc pltega1 ; c = a 1 bit to be plotted cmp ccode,pixfor+pixbak ; plot both 1's and 0's? je pltega1 ; e = yes ret ; else ignore the 0 bit pltega1: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 ret pltega endp ; Plot bit pattern in "fill" as 8 horizontal pixels, starting at x,y (si,di) ; and continuing across the line for cx pixels. psetupe has been called. bpltega proc near ; EGA plot(x,y). x is in si, y is in di push bx push cx 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 byte in regen buffer ; di = offset in regen buffer and bl,7 ; get bit in byte (di = byte aligned) jz bplteg1 ; z = aligned already xchg bl,cl ; get shift to cl, low count to bl mov bh,fill ; 8-bit fill pattern mov al,bh ; get complement of pattern too not al shl bh,cl ; trim cl bits from the left shr bh,cl shl al,cl ; trim them from the right edge shr al,cl ; restore pattern xchg cl,bl ; put count back in cx add cl,bl ; add bits taken care of adc ch,0 jmp short bplteg2 ; do this partial byte now bplteg1:mov bh,fill ; fill pattern mov al,bh ; make inverted pattern not al cmp cx,8 ; do all 8 bits? jae bplteg2 ; ae = yes push cx ; final byte fixup sub cl,8 ; cl = - (number of bits to omit) neg cl ; cl = number of bits to omit mov al,bh ; get complement of pattern too not al shr bh,cl ; trim them from the right edge shl bh,cl ; restore pattern shr al,cl ; trim them from the right edge shl al,cl ; restore pattern pop cx bplteg2:push ax cmp ccode,pixfor+pixbak ; do both fore and background? jne bplteg2a ; ne = no push bx mov bh,al ; get complemented pattern mov bl,pixbak ; write background call ega_plt pop bx bplteg2a:mov bl,ccode ; get line type code call ega_plt bplteg3:pop ax inc di ; next byte right sub cx,8 ; did these cmp cx,0 ; anything left to do? jg bplteg1 ; a = yes, repeat pop di pop si pop cx pop bx ret bpltega 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 and Wyse plots also. push si push di ror bp,1 ; rotate line pattern jc pltcg6 ; c = 1 bit to be plotted cmp ccode,pixfor+pixbak ; plot both 1's and 0's? jne pltcg3 ; ne = no pltcg6: 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 test bl,pixfor+pixor ; draw in foreground color or OR? jz pltcg1 ; z = no test bl,pixor ; OR? jnz pltcg5 ; nz = yes test gfcol,7 ; is foreground dark? jz pltcg4 ; z = yes, punch a hole pltcg5: or es:[di],bh ; drawn jmp short pltcg3 pltcg1: test bl,pixbak ; draw in background (erase)? jz pltcg2 ; z = no test gbcol,7 ; is background light? jnz pltcg5 ; nz = yes pltcg4: not bh ; invert the bit and es:[di],bh ; erase the dot jmp short pltcg3 pltcg2: xor es:[di],bh ; xor in this color pltcg3: pop di pop si pop bx ret pltcga endp ; Plot bit pattern in fill as 8 horizontal pixels, starting at x,y (si,di) ; and continuing across the line for cx pixels. psetupc has been called. bpltcga proc near ; CGA plot(x,y). x is in si, y is in di push bx ; used for HGA and Wyse plots also. push cx 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 byte in regen buffer ; di = offset in regen buffer and bl,7 ; get bit in byte (di = byte aligned) jz bpltcg5 ; z = aligned already xchg bl,cl ; get shift to cl, low count to bl mov bh,fill ; 8-bit fill pattern mov al,bh ; get complement of pattern too not al shl bh,cl ; trim cl bits from the left shr bh,cl shl al,cl ; trim them from the right edge shr al,cl ; restore pattern xchg cl,bl ; put count back in cx add cl,bl ; add bits taken care of adc ch,0 jmp short bpltcg4 ; do this partial byte now bpltcg5:mov bh,fill ; fill pattern mov al,bh ; make inverted pattern not al cmp cx,8 ; do all 8 bits? jae bpltcg4 ; ae = yes push cx ; final byte fixup sub cl,8 ; cl = - (number of bits to omit) neg cl ; cl = number of bits to omit mov al,bh ; get complement of pattern too not al shr bh,cl ; trim them from the right edge shl bh,cl ; restore pattern shr al,cl ; trim them from the right edge shl al,cl ; restore pattern pop cx bpltcg4:mov bl,ccode ; get line type code test bl,pixfor+pixor ; draw in foreground? jz bpltcg1 ; z = no test bl,pixor ; OR? jnz bpltcg7 ; nz = yes test gfcol,7 ; is foreground dark? jz bpltcg6 ; z = yes, punch a hole bpltcg7:or es:[di],bh ; drawn jmp short bpltcg3 bpltcg1:test bl,pixbak ; draw as background (erase)? jz bpltcg2 ; z= do not draw as background (erase) test gbcol,7 ; is background light? jnz bpltcg7 ; nz = yes bpltcg6:not bh and es:[di],bh ; erase the dots jmp short bpltcg3 bpltcg2:xor es:[di],bh ; xor in this color bpltcg3:inc di ; next byte right sub cx,8 ; did these cmp cx,0 ; anything left to do? jg bpltcg5 ; a = yes, repeat pop di pop si pop cx pop bx ret bpltcga endp ;;;;;;; Wyse-700 plot support routines ; The Wyse graphics memory map in mode 0D3h (1280 by 800) is 8 dots per byte, ; left most dot in the high bit, 160 bytes per scan line, scan line segments ; sequence as 0a000h even lines, and same for odd lines psetupw proc near ; Wyse setup for plotting push ax push cx push dx mov linelen,160 ; 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 ; half the lines in each bank mov ax,160 mul di mov di,ax ; di = di * 160 / 2 mov dx,wymode shr cx,1 ; compute bank from 1 lsb of line num jnc psetw2 ; nc = it is in bank 0 (0b000h) mov ax,wybodd ; select odd bank out dx,al jmp short psetw3 psetw2: mov ax,wybeven ; select even bank out dx,al psetw3: mov bnkchan, al ; bank has changed pop dx pop cx pop ax ret psetupw endp ; ; Wyse-700 has two banks. Line 0, 2, 4 ... are in bank 0, and 1, 3, 5 ... are ; in bank 1. Lines 0 and 1 have same addresses, lines 2 and 3 have same ; addresses etc. We have to change bank every time Y changes but we ; have to count new address only after two Y-value changes. Variable ; bnkchan is a flag for us to know into which bank to write. ; pincyw proc near ; Wyse inc y, step offset of line push ax push dx mov dx,wymode ; Wyse conrol register mov al,wybeven ; cmp bnkchan,wybeven ; was last write into even bank ? jne pincywe ; ne = no mov al,wybodd ; yes, set ready for odd bank out dx,al ; mov bnkchan,al ; set to odd jmp short pincywo pincywe:mov al,wybeven ; set ready foe even bank out dx,al ; select it mov bnkchan,al ; set to odd pincywo:cmp linelen,0 ; increasing y? jg pinyw2 ; g = yes cmp al,wybeven ; from high (1) to low (0) bank ? je pinyw4 ; e = yes add di,linelen ; no, add a line jmp short pinyw4 pinyw2: cmp al,wybodd ; from low (0) to high (1) bank ? je pinyw4 ; e = yes add di,linelen ; no, add a line pinyw4: and di,0ffffh ; roll over address pop dx pop ax ret pincyw 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 ; Plot bit pattern in fill as 8 horizontal pixels, starting at x,y (si,di) ; and continuing across the line for cx pixels. Destroys CX. bpltmon proc near ; Mono plot(x,y). x is in si, y is in di jmp pltmon ; a dummy for the present bpltmon 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 or space? ja gputc1 ; a = 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,7 ; start 7 lines higher jnc gputc2 ; nc = ok xor di,di ; move up to first line mov y_coord,7 ; and reset scan line indicator gputc2: call psetup ; enter with di=line number, sets es:di to start of ; line in regen buffer 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 sub x_coord,8 ; delete 8 dots (move left) jnc putct1 ; nc = ok mov x_coord,0 ; limit to left margin putct1: cmp bscontrol,0 ; non-destructive backspace? je putctx ; e = yes push x_coord mov ah,ccode push ax mov ccode,pixbak ; write in background mov al,7fh ; do all dots in background call putc pop ax mov ccode,ah pop x_coord ; restore cursor jmp short 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 putct4: cmp al,CR ; means go to beginning of line jne putct5 mov x_coord,0 ; zero the x coordinate jmp putctx putct5: cmp al,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 ; move up screen 1 line (8 pixels) jne putct8 sub y_coord,8 ; subtract one line (8 pixels) jnc putctx ; nc = space left mov y_coord,8 ; else set to top of screen jmp short putctx putct8: cmp al,' ' ; space? jne putctx ; ne = no cmp spcontrol,0 ; non-destructive space? je putct8a ; e = yes mov ah,ccode push ax mov ccode,pixbak ; write in background mov al,07fh ; do all dots in background call putc pop ax mov ccode,ah jmp short putctx putct8a:call testfull ; check on full screen call incx 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 xor ah,ah ; 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,7 ; minus 7 dots, like other modes jnc mputc2 ; nc = non-negative mov ax,7 ; else start at the top mov y_coord,ax ; here too mputc2: shr ax,cl mov dh,al ; row mov ah,2 ; set cursor to x_coord,y_coord xor bh,bh ; page 0 int screen pop ax or ah,ah ; write a char in al? jnz mputcx ; nz = no mov ah,09h ; write char at cursor postion mov cx,1 ; just one char xor bh,bh ; 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,xmax add ax,8 ; last column+1 cmp ax,x_coord ; beyond right most column? jae incx1 ; ae = no mov x_coord,ax ; set up for wrap ret incx1: add x_coord,8 ; shift the (logical) cursor right ret ; one character cell 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: pixbak=plot in backgrd colors, pixfor=foregrd, pixxor=xor with screen gcega proc near gcega1: mov al,font[bx] ; EGA byte plot: get bits from font push bx cmp chcontrol,0 ; transparent char writing? je gcega2 ; e = yes mov bh,0ffh ; write these bits to clear field mov bl,pixbak ; in background coloring call ega_plt ; plot a byte gcega2: 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,pixfor+pixbak ; write both fore and back? jne gcgen2 ; ne = no cmp gfcol,0 ; is foreground dark? jne gcgen1 ; ne = yes not al ; invert bits gcgen1a:mov es:[di],al ; write bits directly jmp short gcgen5 gcgen2: test ccode,pixfor+pixor ; OR or write in foreground? jz gcgen3 ; z = no not al and es:[di],al ; clear bits to be written cmp gfcol,0 ; is foreground dark? je gcgen5 ; e = yes, done not al or es:[di],al ; insert bits jmp short gcgen5 gcgen3: test ccode,pixxor ; XOR? jz gcgen5 ; z = no xor es:[di],al jmp short gcgen5 gcgen4: not al ; background write and es:[di],al ; clear bits cmp gbcol,0 ; is background dark? je gcgen5 ; e = yes not al or es:[di],al ; write light bits gcgen5: 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: ; pixbak = draw in background color, pixfor = draw in foreground color, ; pixor = OR with foreground color, pixxor = XOR with foreground color. ; registers preserved ; Note: this function operates on 8 pixels. One bits in bh select pixels to ; be changed, bl determines which color planes will be affected for every ; selected pixel. ega_plt proc near push ax push dx mov dx,3ceh ; (ega_gc) unprotect the bit positions mov al,8 ; command to set bit mask register out dx,al ; output command code inc dx ; dx is now data port mov al,bh ; get pixels to be modified (1's) out dx,al ; output value (end of ega_gc) pop dx mov ah,gfcol ; foreground color bit planes ega1: test bl,pixfor+pixor ; write foreground or OR? jnz ega3 ; nz = yes mov ah,gbcol ; background color bit planes test bl,pixbak ; write in background coloring? jnz ega3 ; nz = yes mov ah,0fh ; xor, touch each bit plane ega3: mov al,es:[di] ; latch byte mov es:[di],ah ; merge with untouched bits pop ax ret ega_plt endp ; Presence test for Wyse-700: info in B000h and B800h are supposed to be equal chkwyse proc near push es push ds mov ax,0b800h ; CGA segment mov es,ax mov ax,0b000h ; Mono segment mov ds,ax mov ch,byte ptr es:[0] ; CGA seg mov cl,byte ptr ds:[0] ; Mono seg push cx ; save original contents mov byte ptr ds:[0],ch ; copy CGA to Mono cmp byte ptr ds:[0],ch ; if different then not Wyse jne chkwys1 ; ne = not Wyse not byte ptr es:[0] ; change CGA contents not ch ; and original pattern cmp ch,byte ptr ds:[0] ; if different then not Wyse jne chkwys1 ; ne = not Wyse pop cx mov byte ptr es:[0],ch ; restore CGA mov byte ptr ds:[0],cl ; restore Mono pop ds pop es clc ret chkwys1:pop cx mov byte ptr es:[0],ch ; restore CGA mov byte ptr ds:[0],cl ; restore Mono pop ds pop es stc ret chkwyse endp ; ; routine to set Wyse-700 board to graphics mode - 1280 * 800 & cls ; WYGRAF PROC NEAR push ax push bx ; save used registers push cx push dx push di xor al,al mov dx,wystoff ; map video memory offset to zero out dx,al ; mov dx,wystseg ; map video memory segment to zero out dx,al ; mov ax,segwyse ; set es to Wyse start segment mov es,ax ; mov al,wybeven ; graph mode - even bank mov dx,wymode ; Wyse mode control register out dx,al ; select even bank cld xor ax,ax ; zero ax xor di,di ; start from zero mov cx,0ffffh ; clear 10000h bytes, whole even bank rep stosb ; store blanking char in whole screen mov al,wybodd ; graph mode - odd bank mov dx,wymode ; select it out dx,al ; xor ax,ax ; zero ax xor di,di ; mov cx,0ffffh ; clear 10000h bytes, whole odd bank rep stosb ; store blanking char in whole screen mov bnkchan, 0 ; assume bank 0 pop di ; restore regs pop dx pop cx pop bx pop ax ret WYGRAF 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 xor bx,bx 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 ; byte moves for ega adaptor rep movsb ; copy from page (ds:si) to page (es: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 dump proc far ; Write screen as TIFF v5.0 file push ax push bx push cx push dx push si push di mov si,offset dumpname ; name of dump file mov di,offset tempname ; destination push es push ds pop es mov cx,dumplen ; length of dump name cld repnz movsb ; copy it, asciiz pop es mov ax,offset tempname ; address to ax for unique call tunique ; get unique name into ax mov dx,ax ; ds:dx is asciiz filename xor cx,cx ; normal attributes mov ah,creat2 ; create the file int dos jc dmp2 ; c = failure dmp1: mov dhandle,ax ; file handle call dmpdate ; do time stamp cmp plotptr,offset pltcga ; using CGA style graphics? jne dmp2 ; ne = no call cgadmp ; do CGA style dump routine jmp short dmp3 dmp2: call egadmp dmp3: pop di pop si pop dx pop cx pop bx pop ax ret dump endp ; CGA TIFF 5.0 screen-to-file dump routine cgadmp proc near push es ; do the bookkeeping math first mov bps.entval,1 ; bits/sample, mono mov photo.entval,1 ; mono, one bit after the other mov word ptr cmap.entcnt,0 ; no palette color map entries mov ax,xmax ; image width - 8 pixels add ax,8 ; plus 8, for pixels per line mov iwidth.entval,ax ; store in directory mov xresval,ax ; x resolution mov xresval+2,0 ; high order part mov ax,ybot ; lines per screen - 1 inc ax ; lines per screen mov ilength.entval,ax ; image length, scan lines mov yresval,ax ; y resolution mov yresval+2,0 ; high order part mov cx,25 ; try dividing into this many strips cgadmp5:xor dx,dx ; image pixels mov ax,yresval ; number of scan lines div cx ; try dividing into 25 strips,ax=quo or dx,dx ; did we get null remainder? loopnz cgadmp5 ; nz = no, try again with fewer strips inc cx ; inc for dec by loop, cx = # strips mov word ptr strip.entcnt,cx ; store number of strips mov word ptr sbc.entcnt,cx ; store number of strip byte counts mov rps.entval,ax ; rows per strip mul linelen ; rows/strip * bytes/row = bytes/strip push cx ; save strip count for loop below push ds ; ax = bytes per strip pop es ; es:di to our data segment mov di,offset stripbc ; where to write strip byte counts cld rep stosw ; write ax as bytes/strip, cx times pop cx mov dx,ax ; bytes/strip = increment, put here mov di,offset stripoff ; where we write mov ax,offset pixdata-offset header ; where first strip starts cgadmp4:stosw ; write strip file offset mov word ptr [di],0 ; high order part add di,2 ; next double word add ax,dx ; next file strip offset loop cgadmp4 ; do all strip offsets ; file i/o starts here mov bx,dhandle ; dump's file handle mov dx,offset header ; write TIFF header and directory mov cx,tifflen ; length of header plus directory mov ah,write2 int dos jc cgadmp2 ; c = failure xor di,di ; start at y = top call psetup ; setup cga and di mov cx,ybot ; number of scan lines-1 inc cx ; number of scan lines cgadmp1:push cx mov cx,linelen ; line length, bytes mov dx,di ; offset in screen buffer mov bx,dhandle ; file handle push ds mov ax,segscn ; screen seg mov ds,ax mov ah,write2 ; write directly from screen memory int dos pop ds jc cgadmp2 ; c = failure call pincy ; next line down, y = y + 1 pop cx loop cgadmp1 ; do all scan lines cgadmp2:mov ah,close2 ; close the file int dos mov dhandle,-1 ; set handle to unused pop es ret cgadmp endp ; EGA TIFF 5.0 screen-to-file dump routine egadmp proc near push es ; do the bookkeeping math first mov bps.entval,4 ; bits/sample, iRGB mov photo.entval,3 ; photo interp, palette mov word ptr cmap.entcnt,3*16 ; palette color map entries mov ax,xmax ; image width - 8 pixels add ax,8 ; plus 8, for pixels per line mov iwidth.entval,ax ; store in directory mov xresval,ax ; x resolution mov xresval+2,0 ; high order part mov ax,ybot ; lines per screen - 1 inc ax ; lines per screen mov ilength.entval,ax ; image length, scan lines mov yresval,ax ; y resolution mov yresval+2,0 ; high order part mov cx,25 ; try dividing into this many strips egadmp10:xor dx,dx ; image pixels mov ax,yresval ; number of scan lines div cx ; try dividing into 25 strips, ax=quo or dx,dx ; did we get null remainder? loopnz egadmp10 ; nz = no, try again with fewer strips inc cx ; inc for dec by loop, cx = # strips mov word ptr strip.entcnt,cx ; store number of strips mov word ptr sbc.entcnt,cx ; store number of strip byte counts mov rps.entval,ax ; rows per strip shl ax,1 shl ax,1 ; times 4 bits / pixel mul linelen ; rows/strip * bytes/row = bytes/strip push cx ; save strip count for loop below push ds ; ax = bytes per strip pop es ; es:di to our data segment mov di,offset stripbc ; where to write strip byte counts cld rep stosw ; write ax as bytes/strip, cx times pop cx mov dx,ax ; bytes/strip = increment, put here mov di,offset stripoff ; where we write mov ax,offset pixdata-offset header ; where first strip starts xor bx,bx egadmp11:stosw ; write strip file offset mov es:[di],bx ; high order part add di,2 ; next double word add ax,dx ; next file strip offset adc bx,0 loop egadmp11 ; do all strip offsets ; screen to file i/o starts here mov bx,dhandle ; dump's file handle mov dx,offset header ; write TIFF header and directory mov cx,tifflen ; length of header plus directory mov ah,write2 int dos jnc egadmp12 jmp egadmp9 ; c = failure egadmp12: xor di,di ; start at y = top call psetup ; setup adapter and es:di xor di,di mov bx,offset tempname ; set buffer address mov cx,ybot ; number of scan lines-1 inc cx ; number of scan lines egadmp1:push cx ; save scan line counter mov cx,linelen ; 8*dots across the screen (640) egadmp2:push cx ; save counter of inner loops mov cx,4 ; number of planes to do mov word ptr [bx],0 ; clear the four bytes for this loop mov word ptr [bx+2],0 egadmp3:push cx ; save plane counter push bx ; don't advance buffer pointer here mov dx,3ceh ; (ega_gc) mov al,4 ; command to select read map register out dx,al ; output command code inc dx ; dx is now data port mov al,cl ; do planes 3(I), then 2(R),1(G),0(B) dec al ; cx is one higher than plane out dx,al ; output value (end of ega_gc) mov al,es:[di] ; latch byte ; got 8 bits from a plane mov cx,4 ; do this for four output bytes egadmp4:mov ah,[bx] ; eventually iRGB in each nibble shl al,1 ; get left most pixel bit in plane jnc egadmp5 or ah,8 ; set high nibble least sig bit egadmp5:shl al,1 ; odd numbered pixel rcl ah,1 ; set low nibble least sig bit if c mov [bx],ah inc bx ; next byte loop egadmp4 ; do all four bytes pop bx pop cx ; restore plane counter loop egadmp3 ; do all planes inc di ; next screen memory address add bx,4 ; just did four bytes cmp bx,offset tempname+80 ; at end of 80 bytes? jb egadmp6 ; b = no call egadmpw ; write the buffer mov bx,offset tempname ; reset buffer address jnc egadmp6 ; nc = success pop cx ; clean stack pop cx jmp egadmp9 ; error egadmp6:pop cx ; recover bytes per line counter loop egadmp2 ; next group across scan line pop cx ; recover scan line counter loop egadmp1 ; do next scan line call egadmpw ; flush the buffer for last scan line egadmp9:mov ah,close2 ; close the file mov bx,dhandle int dos mov dhandle,-1 ; set handle to unused xor di,di call psetup pop es ret ; local worker egadmpw:push bx ; write tempbuf from start to [bx-1] push cx mov dx,offset tempname ; work buffer mov cx,bx ; buffer pointer to next free byte sub cx,dx ; buffer size to write cmp cx,0 jle egadmpw1 ; le = nothing to write mov bx,dhandle ; file handle mov ah,write2 ; write cx bytes from tempname int dos jc egadmpw2 ; c = error cmp ax,cx ; wrote all? jne egadmpw2 ; ne = no egadmpw1:clc ; clc pop cx pop bx ret egadmpw2:stc ; carry set for failure pop cx pop bx ret egadmp endp ; Worker. Write Kermit version and current date and time in TIFF header dmpdate proc near mov di,offset prog+10 ; place for version in prog field mov ax,version ; Kermit version call dec2di ; write the version mov ah,getdate ; DOS date (cx= yyyy, dh= mm, dl= dd) int dos mov di,offset dandt ; where to write mov ax,cx ; get yyyy push dx call dec2di ; write to buffer pop dx mov byte ptr [di],':' inc di mov al,dh ; mm cmp al,10 ; leading digit? jae dmpdat1 ; ae = yes mov byte ptr [di],'0' ; make our own inc di dmpdat1:xor ah,ah push dx call dec2di mov byte ptr [di],':' pop dx inc di mov al,dl ; dd cmp al,10 ; leading digit? jae dmpdat2 ; ae = yes mov byte ptr [di],'0' ; make our own inc di dmpdat2:xor ah,ah call dec2di mov byte ptr [di],' ' inc di mov ah,gettim ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s) int dos push dx ; save dx xor ah,ah mov al,ch ; Hours cmp al,10 ; leading digit? jae dmpdat3 ; ae = yes mov byte ptr [di],'0' ; make our own inc di dmpdat3:push cx call dec2di ; write decimal asciiz to buffer pop cx mov byte ptr [di],':' inc di xor ah,ah mov al,cl ; Minutes cmp al,10 ; leading digit? jae dmpdat4 ; ae = yes mov byte ptr [di],'0' ; make our own inc di dmpdat4:call dec2di ; write decimal asciiz to buffer mov byte ptr [di],':' inc di pop dx xor ah,ah mov al,dh ; Seconds cmp al,10 ; leading digit? jae dmpdat5 ; ae = yes mov byte ptr [di],'0' ; make our own inc di dmpdat5:call dec2di ; write decimal asciiz to buffer inc di ret dmpdate endp ; Dispatch table processor. Enter with BX pointing at table of {char count, ; address of action routines, characters}. Jump to matching routine or return. ; Enter with AL holding received Final char. atdispat proc near mov cl,[bx] ; get table length from first byte xor ch,ch mov di,bx ; main table add di,3 ; point di at first char in table push es push ds pop es ; use data segment for es:di below cld ; set direction forward repne scasb ; find matching character pop es je atdisp2 ; e = found a match, get action addr cmp al,' ' ; control char? jb atdisp1 ; b = yes ret ; ignore escape sequence atdisp1:jmp tekctl ; process control char atdisp2:sub di,bx ; distance scanned in table sub di,4 ; skip count byte, address word, inc shl di,1 ; convert to word index inc bx ; point to address of action routines mov bx,[bx] ; get address of action table jmp word ptr [bx+di] ; dispatch to the routine atdispat endp ansich proc near ; insert Pn spaces at and after cursor mov cx,param ; get Pn or cx,cx jnz ansich1 ; got a value inc cx ; zero means one ansich1:push x_coord push y_coord mov al,spcontrol ; preserve space control mov tempname,al ; save here mov spcontrol,1 ; turn on destructive space and x_coord,not 7 ; modulo 8x8 cells mov ax,xmax ; start of last cell sub ax,x_coord ; start of current cell shr ax,1 ; divide by 8 dots per char shr ax,1 shr ax,1 cmp ax,cx ; want more spaces than are on line? jae ansich2 ; ae = no mov cx,ax ; clip to right margin jcxz ansich3 ; z = nothing to do ansich2:push cx mov al,' ' ; a space call outscrn ; write to screen (BYPASS check??) pop cx loop ansich2 ; do them ansich3:mov al,tempname ; space control mov spcontrol,al ; restored pop x_coord pop y_coord ret ansich endp ; scaled by text screen height atcuu proc near ; cursor up Pn lines cmp param,0 ; empty arg? jne atcuu1 ; got a value inc param ; zero means one atcuu1: mov ax,y_coord ; where we are now add ax,4 ; round up a smidge mov cl,byte ptr low_rgt+1 ; highest text line xor ch,ch mul cx ; proportion xor dx,dx mov cx,ybot ; highest scan line div cx ; end, estimate currren text line sub ax,param inc ax ; count lines from 1 again mov param,ax ; new text row jmp atcva ; do as absolute atcuu endp ; scaled by text screen height atcud proc near ; cursor down Pn lines cmp param,0 ; get Pn jne atcud1 ; ne = got a value inc param ; zero means one atcud1: mov ax,y_coord ; where we are now add ax,4 ; round up a smidge mov cl,byte ptr low_rgt+1 ; highest text line xor ch,ch mul cx ; proportion xor dx,dx mov cx,ybot ; highest scan line div cx ; end, estimate currren text line inc ax ; count lines from 1 again add param,ax ; new text row jmp atcva ; do as absolute atcud endp atcuf proc near ; cursor forward Pn columns mov ax,param ; get Pn or ax,ax jnz atcuf1 ; got a value inc ax ; zero means one atcuf1: shl ax,1 ; times 8 dots per char cell shl ax,1 shl ax,1 ; Tek columns worth and x_coord,not 7 ; modulo 8x8 cells add x_coord,ax ; forward to absolute column mov ax,xmax cmp x_coord,ax ; beyond right most cell? jbe atcuf2 ; be = no mov x_coord,ax ; limit to right atcuf2: ret atcuf endp atcub proc near ; cursor left/back Pn columns mov ax,param ; get Pn or ax,ax jnz atcub1 ; got a value inc ax ; zero means one atcub1: shl ax,1 shl ax,1 shl ax,1 ; times 8 dots per cell and x_coord,not 7 ; modulo 8x8 cells mov cx,xmax cmp x_coord,cx ; beyond last col (wrap pending)? jbe atcub3 ; be = no mov x_coord,cx ; set to last col atcub3: sub x_coord,ax ; back up jnc atcub2 ; nc = ok mov x_coord,0 ; stop in column zero atcub2: ret atcub endp atcnl proc near ; do Pn cr/lf's mov x_coord,0 ; to left margin jmp atcud ; do the cursor downs atcnl endp atcpl proc near ; do Pn cursor ups jmp atcuu ; do the cursor ups atcpl endp ; scaled by text screen width atcha proc near ; cursor to absolute column and x_coord,not 7 ; modulo 8x8 cells mov ax,param ; get Pn or ax,ax jz atcha1 ; z = zero already dec param ; count columns from 0 mov ax,xmax ; number of Tek dots/row mul param ; times columns they want mov cl,byte ptr low_rgt ; number of last text column xor ch,ch xor dx,dx div cx ; scale to ~80 column screen cmp ax,xmax ; too far? jbe atcha1 ; be = no mov ax,xmax ; right most column atcha1: mov x_coord,ax ret atcha endp ; scaled by text screen height atcva proc near ; cursor to absolute row dec param ; count from 0 mov ax,param ; desired text row or ax,ax ; zero or now -1? jg atcva1 ; g = no, further down mov ax,7 ; bottom of top text cell jmp short atcva2 atcva1: mov ax,ybot inc ax ; number of scan lines on screen ;;;; and ax,not 7 ; whole 8x8 char cells mul param ; times row they want mov cl,byte ptr low_rgt+1 ; number of last text line (0..23) xor ch,ch xor dx,dx div cx ; scale to ~24 line screen mov cx,ybot ;;;; and cx,not 7 ; whole 8x8 char cells cmp ax,cx ; too far? jbe atcva2 ; be = no mov ax,cx atcva2: mov y_coord,ax ; go to that line ret atcva endp atcup proc near ; cursor to absolute row, column call atcva ; process param[0] as absolute row push param[2] ; column pop param jmp atcha ; process param[2] as absolute column atcup endp ated proc near ; erase display mov al,spcontrol ; preserve space control mov tempname,al ; save here mov spcontrol,1 ; turn on destructive space push x_coord push y_coord ; save cursor cmp param,0 ; cursor to end of screen? je ated1 ; e = yes cmp param,1 ; start of screen to cursor? je ated3 ; e = yes cmp param,2 ; entire screen? je ated5 ; e = yes ret ; else ignore ated1: mov param,0 ; cursor to end of this line call atel ; erase cursor to end of line add y_coord,8 ; look at next line mov ax,ybot cmp y_coord,ax ; are we at the end now? ja ated6 ; a = yes mov x_coord,0 ; start of line is here jmp ated1 ; do through last line ated3: and y_coord,not 7 ; modulo 8x8 char cells mov cx,y_coord ; start of screen to cursor shr cx,1 ; char lines at 8 dots/char shr cx,1 shr cx,1 dec cx ; omit current line= # whole lines or cx,cx ; any whole lines? jle ated3b ; le = no mov y_coord,7 ; start at the top line ated3a: push cx mov param,2 ; entire line call atel ; erase entire line add y_coord,8 ; next line pop cx loop ated3a ated3b: mov param,1 ; start of line to cursor call atel ; erase to cursor on this (last) line jmp short ated6 ated5: call tekcls ; erase whole screen ated6: mov al,tempname ; spacing control mov spcontrol,al pop y_coord pop x_coord ret ated endp atech proc near ; erase Pn chars from cursor to eol mov al,spcontrol ; preserve space control mov tempname,al ; save here mov spcontrol,1 ; turn on destructive space push x_coord push y_coord ; save cursor mov cx,x_coord and cx,not 7 ; modulo 8x8 cells mov ax,xmax sub ax,cx ; number of chars remaining on line shr ax,1 shr ax,1 shr ax,1 inc ax ; count cursor cell mov cx,param ; how many chars to erase or cx,cx jz atech1 ; z = zero, use one inc cx atech1: cmp ax,cx ; want more than line length? jae atech2 ; ae = no mov cx,ax ; clip at right margin or cx,cx jle atech3 ; le = nothing to do atech2: push cx mov al,' ' call outscrn ; write spaces pop cx loop atech2 atech3: mov al,tempname ; spacing control mov spcontrol,al pop y_coord pop x_coord ret atech endp atel proc near ; erase on this line push x_coord push y_coord cmp param,0 ; cursor to end of line? je atel1 ; e = yes cmp param,1 ; start of line to cursor? je atel3 ; e = yes cmp param,2 ; whole line? jne atel5 ; ne = no, fail mov x_coord,0 ; erase entire line atel1: mov cx,xmax ; cursor to end of line mov ax,x_coord and ax,not 7 ; modulo 8x8 cells sub cx,ax shr cx,1 shr cx,1 shr cx,1 ; 8 dots/char inc cx ; count the cursor cell or cx,cx jle atel5 ; le = do nothing mov al,spcontrol ; preserve space control mov tempname,al ; save here mov spcontrol,1 ; turn on destructive space atel2: push cx ; start of line to cursor mov al,' ' call outscrn pop cx loop atel2 mov al,tempname ; space control mov spcontrol,al ; restored atel5: pop y_coord pop x_coord ret atel3: mov cx,x_coord ; start of line to cursor shr cx,1 shr cx,1 shr cx,1 inc cx ; count cursor cell mov x_coord,0 ; go to start of line jmp atel2 ; do the loops atel endp code2 ends end