Name ccgibm ; File CCGIBM.ASM ; Tektronix emulator for use with MS Kermit/IBM. ;CHINESE ifdef MSDOS include msgibm.dat else include ccgibm.dat endif code segment public 'code' extrn outchr:near, beep:near, scrseg:near, cmblnk:near extrn clrmod:near, savescr:near, cptchr:near, pcwait:near extrn restscr:near, getflgs:near, clrbuf:near, vtans52:near extrn iseof:near, beep:near assume cs:code, ds:datas, es:nothing ; Initialise TEK mode by setting high resolution screen, etc tekini PROC NEAR push ax ; do presence tests push bx push cx push dx push si push di push es mov bx,portval ; get port flow control chars: mov bx,[bx].flowc ; bh=xon, bl=xoff or both are nulls mov flow,bx ; save here mov ax,bx ; get flow control word cmp al,0 ; able to do xoff? je tekin0 ; e = no call outmodem ; tell host xoff while we change modes tekin0: mov bx,vtemu.att_ptr ; emulator screen color ptr mov al,[bx] mov gfcol,al ; save foreground color and gfcol,0fh ; save just foreground bits and al,70h ; select background color, no bold mov cl,4 shr al,cl ; get background colors mov gbcol,al ; set graphics background color mov ah,15 ; get current screen mode int screen cmp al,3 ; in a mono/color text mode (2/3)? jbe tekin1 ; be = yes cmp al,mono ; mono text mode (7)? je tekin1 ; e = yes cmp tekflg,0 ; are we active as Tek device now? je tekin1 ; e = no jmp tekin13 ; yes, don't redo graphics setup tekin1: mov curmode,al ; save mode here mov ah,3 ; get cursor position xor bh,bh ; page 0 int screen mov cursor,dx ; save position call savescr ; save text screen ; Presence tests. tekin2: mov graph_mode,cga ; Color. Assume CGA mov segscn,segcga ; assume cga screen segment mov gpage,0 ; graphics page 0 but no page 1 mov putc,offset gputc ; CGA character display routine mov gcplot,offset gcgen ; General character plot routine mov psetup,offset psetupc ; CGA plot setup routine mov plotptr,offset pltcga ; CGA dot plot routine mov pincy,offset pincyc ; CGA inc y routine mov xmult,5 ; CGA. Scale TEK to PC by 640/1024 mov xdiv,8 ; so that 0-1023 converts to 0-639 mov xmax,640-8 ; x-coord of rightmost character mov ymult,10 ; vertical scale for IBM is 200/780 mov ydiv,39 ; mov ybot,199 ; Bottom of screen is Y=199 mov al,tekgraf ; user video board specification cmp al,0 ; auto-sensing? je tekin2c ; e = yes (default) cmp al,1 ; user wants CGA? jne tekin2a ; ne = no jmp tekin13 ; do CGA tekin2a:cmp al,4 ; user wants Hercules? jne tekin2b ; ne = no jmp tekin8 ; do Hercules tekin2b:cmp al,5 ; user wants AT&T style? jne tekin2c ; ne = no jmp tekin7 ; do AT&T kind ; do auto-sensing of display board ; test for EGA tekin2c:mov ax,1200H ; EGA: Bios alternate select mov bl,10H ; Ask for EGA info mov bh,0ffH ; Bad info, for testing mov cl,0fH ; Reserved switch settings int screen ; EGA, are you there? and cl,0fh ; four lower switches cmp cl,0cH ; Test reserved switch settings jb tekin3 ; b = ega present jmp tekin7 ; else no EGA, check other adapters tekin3: mov ax,40h ; check Bios 40:87h for ega being mov es,ax ; the active display adapter test byte ptr es:[87h],8 ; is ega active? jz tekin3a ; z = yes jmp tekin7 ; ega is inactive, check others tekin3a:cmp bl,1 ; is there 128KB on ega board? jb tekin4 ; b = less, so no screen saves mov gpage,1 ; >=128 KB, use two graphics pages tekin4: mov graph_mode,ega ; assume high resolution color cmp cl,3 ; high resolution color? je tekin5 ; e = yes cmp cl,9 ; high resolution color? je tekin5 ; e = yes mov graph_mode,monoega ; assume mono monitor on ega board test bh,1 ; ega mono mode in effect? jnz tekin5 ; nz = yes mov graph_mode,colorega ; say ordinary cga on ega board, 64KB mov gpage,1 ; is enough memory with 200 scan lines jmp short tekin5a ; use current cga parameters tekin5: mov ybot,349 ; text screen bottom is 349 on EGA mov ymult,35 ; mov ydiv,78 ; scale y by 350/780 tekin5a:mov segscn,segega ; use ega screen segment mov psetup,offset psetupe ; plot setup routine mov plotptr,offset pltega ; ega dot plot routine mov pincy,offset pincye ; inc y routine mov putc,offset gputc ; character display routine mov gcplot,offset gcega ; EGA character plot routine call fixcolor ; correct color mapping for some bds jmp tekin13 ; end of EGA part, do VGA tests below tekin7: mov ax,0fc00h ; Olivetti/AT&T 6300, check rom id mov es,ax mov di,0 ; start here mov graph_mode,olivetti ; Olivetti mov cx,attlen ; length of logo mov si,offset ATTLOGO ; master string repe cmpsb ; do a match je tekin7c ; e = a match mov di,0050h ; look here too mov si,offset ATTLOGO mov cx,attlen repe cmpsb je tekin7c ; e = a match mov di,2014h ; and look here mov si,offset ATTLOGO mov cx,attlen repe cmpsb ; do a match je tekin7c ; e = a match, else try other types tekin7a:mov graph_mode,toshiba mov ax,0f000h ; Check for Toshiba T3100, rom scan mov es,ax mov di,0014h ; start here mov si,offset TOSHLOGO ; master string mov cx,toshlen ; length repe cmpsb ; do a match je tekin7c ; e = a match, else try other types tekin7b:mov graph_mode,vaxmate ; DEC VAXmate II mov ax,0f000h ; Check for VAXmate II rom signature mov es,ax mov di,0e000h ; start here mov si,offset DECLOGO ; master string mov cx,declen ; length repe cmpsb ; do a match jne tekin7d ; ne = mismatch, try other types ; Olivetti/AT&T, Toshiba, VAXmate tekin7c:mov gpage,0 ; only page 0 with 640 by 400 mode mov segscn,segcga ; use cga screen segment (0b800h) mov psetup,offset psetupo ; plot setup routine mov plotptr,offset pltcga ; cga dot plot routine mov pincy,offset pincyh ; inc y routine (Herc style addresses) mov putc,offset gputc ; character display routine mov gcplot,offset gcgen ; General character plot routine mov ybot,399 ; bottom of screen is y = 399 mov ymult,20 ; vertical scale = 400/780 mov ydiv,39 ; same as cga setup jmp tekin13 tekin7d:cmp curmode,mono ; mono text mode? je tekin8 ; e = yes jmp tekin11 ; ne = no, try cga ; test for Hercules tekin8: call scrseg ; get screen segment, test Environment cmp tv_mode,0 ; Environment active? je tekin8a ; e = no, ok to test for Hercules jmp tekin10 ; don't do Herc mode, do Mono tekin8a:mov dx,hstatus ; Herc status port in al,dx ; read it mov bl,al ; save here and bl,80h ; remember retrace bit mov cx,0ffffh ; do many times (for fast machines) tekin8b:mov dx,hstatus ; check status port in al,dx and al,80h ; select bit jmp $+2 ; use a little time cmp bl,al ; did it change? loope tekin8b ; test again if not je tekin10 ; e = no change in bit, not Herc mov graph_mode,hercules ; say have Herc board mov segscn,seghga ; assume hga screen segment mov putc,offset gputc ; character display routine mov gcplot,offset gcgen ; General character plot routine mov psetup,offset psetuph ; plot setup routine to use mov plotptr,offset pltcga ; use cga dot plot routine for Herc mov pincy,offset pincyh ; inc y routine mov xmult,45 ; Scale TEK to Hercules by 720/1024 mov xdiv,64 ; so that 0-1023 converts to 0-719 mov xmax,720-8 ; x-coord of rightmost character mov ymult,87 ; vertical scale for Hercules is mov ydiv,195 ; 348/780 mov ybot,347 ; bottom of screen is y = 347 mov ax,seghga ; segment of Herc video display mov es,ax mov al,es:[8000h] ; read original contents, page 1 not byte ptr es:[8000h] ; write new pattern mov ah,es:[8000h] ; read back not byte ptr es:[8000h] ; restore original contents not ah ; invert this too cmp ah,al ; same (memory present?) jne tekin9 ; ne = not same, no memory there mov gpage,1 ; say two pages of display memory tekin9: jmp tekin13 ; set to MONO tekin10:mov graph_mode,mono ; force monochrome adapter text mov segscn,segmono ; assume mono screen segment call scrseg ; Environments: get virtual screen mov segscn,ax ; seg returned in ax and es:di mov gpage,0 mov putc,offset mputc ; character display routine mov psetup,offset psetupm ; plot setup routine to use mov plotptr,offset pltmon ; use hga dot plot routine mov pincy,offset pincym ; inc y routine mov xmult,5 ; Scale TEK to mono by 640/1024 mov xdiv,8 ; so that 0-1023 converts to 0-639 mov xmax,640-8 ; x-coord of rightmost character mov ymult,10 ; vertical scale for mono is 200/780 mov ydiv,39 mov ybot,200 ; bottom of screen is y = 200 for Bios jmp tekin13 ; Uses TEXT mode, for safety ; test for CGA tekin11:mov graph_mode,cga ; set CGA high resolution graphics mov segscn,segcga ; CGA screen segment jmp tekin13 ; Set Graphics mode tekin13:cmp graph_mode,hercules ; Hercules? jne tekin14 ; ne = no call hgraf ; set Herc graphics mode, clear regen jmp short tekin16 ; restore screen tekin14:mov ah,0 ; set screen mode mov al,graph_mode ; to this screen mode cmp tekgraf,3 ; user wants "VGA" modes (640x480)? jne tekin14a ; ne = no cmp al,monoega ; yes, allow high resolution stuff? jb tekin14a ; b = no cmp al,ega ; ditto ja tekin14a ; a = no add al,2 ; use modes 17(b/w) and 18(10)(color) mov ybot,479 ; text screen bottom is 479 on VGA mov ymult,48 tekin14a:cmp gpage,0 ; only page 0 available? je tekin15 ; e = yes, and watch for Bios errors cmp inited,0 ; first time through? je tekin15 ; e = yes, clear the page of old junk or al,80h ; save regen buffer (save area too) tekin15:int screen ; Bios Set Mode. tekin16:mov tekflg,1 ; starting Tek sub mode cmp inited,0 ; inited yet? jne tekin19 ; ne = yes, restore screen mov ttstate,offset tektxt ; do displayable text mov prestate,offset tektxt ; set a previous state of text mov inited,1 ; say we have initialized mov al,gfcol mov tfcol,al ; remember current coloring mov al,gbcol mov tbcol,al call tekcls ; clear screen, for ega coloring jmp short tekin20 tekin19:call tekrest ; restore old graphics screen mov al,tfcol ; and coloring mov gfcol,al mov al,tbcol mov gbcol,al tekin20:mov ax,flow ; get flow control word xchg ah,al ; get xon into al cmp al,0 ; able to send xon? je tekin21 ; e = no call outmodem ; tell host xon tekin21:clc ; clear carry for success jmp short tekin23 tekin22:stc ; set carry for failure tekin23:pop es pop di pop si pop dx pop cx pop bx pop ax ret tekini ENDP TEKRINT proc near ; Tek reinitialization entry point mov inited,0 ; do complete reinitialization jmp tekini TEKRINT endp ;Terminal emulation. Enter with received character in AL. TEKEMU PROC NEAR ; main emulator cmp tekflg,0 ; Tek mode active yet? (msz call) jne tektt1 ; ne = yes call tekini ; init now mov ttstate,offset tektxt ; initial state mov prestate,offset tektxt ; set a previous state of text jnc tektt1 ; nc = succeeded ret ; else failed to init, just return tektt1: and al,7fh ; force Tek chars to be 7 bits cmp al,0 ; NUL char? je tekign ; e = yes, ignore it before logging push ax call getflgs ; get msy yflags into al mov yflags,al test al,capt ; capturing output? pop ax jz tektt4 ; z = no, forget this part push ax ; save char call cptchr ; give it captured character pop ax ; restore character and keep going tektt4: test yflags,trnctl ; debug? if so use tty mode jz tektt5 ; z = no cmp al,DEL ; DEL char? jne tektt4a ; ne = no mov al,5eh ; make DEL a caret query mark call outscrn mov al,3fh ; the query mark call outscrn jmp short tekign tektt4a:cmp al,' ' ; control char? jae tektt4b ; ne = no push ax mov al,5eh ; caret call outscrn pop ax add al,'A'-1 ; make char printable tektt4b:call outscrn tekign: ret ; Ignore this character tektt5: call tkscan ; scan for "ESC [ ? 3 8 l" exit code tektt5a:cmp al,0 ; null char response? je tekign ; e = yes, ignore the character cmp al,' ' ; control code? jb tektt6 ; b = yes, decode jmp ttstate ; no, do current state ; Control characters: tektt6: cmp al,GS ; Line plot command? jne tektt7 ; ne = no mov visible,0 ; Next move is invisible and status,not txtmode ; set status report byte mov ttstate,offset tekline ; expect coordinates next jmp tektt12 tektt7: cmp al,RS ; Incremental dot command? jne tektt8 ; ne = no and status,not txtmode ; set status report mov ttstate,offset tekrlin ; expect pen command next jmp tektt12 tektt8: cmp al,FS ; Point plot command? jne tektt9 ; ne = no mov visible,0 ; next move is invisible and status,not txtmode ; set status report byte mov ttstate,offset tekpnt jmp tektt12 tektt9: cmp al,US ; assert text mode? [bjh] jne tektt10 ; ne = no or status,txtmode ; set status report byte mov ttstate,offset tektxt ; Go to TEKTXT next time mov bypass,0 ; reset bypass condition jmp tektt12 tektt10:cmp al,ESCAPE ; Escape? jne tektt11 ; ne = no or status,txtmode ; set status report byte cmp ttstate,offset tekesc ; already in escape state? je tektt14 ; e = yes, nest no further push ttstate ; current state pop prestate ; save here as previous state mov ttstate,offset tekesc ; next state parses escapes ret tektt11:cmp al,CAN ; Control X? (exits Tek sub mode) jne tektt13 ; ne = no, stay in current state cmp ttstate,offset tekesc ; ESC Control-X? je tektt13 ; yes, parse it in tekesc code mov ttstate,offset tektxt ; back to text mode test flags.vtflg,tttek ; main Tek emulator? jnz tektt12 ; nz = yes, ignore the ^X call tekend ; else exit sub mode mov tekflg,0 ; clear Tek sub mode flag tektt12:mov prestate,offset tektxt ; make previous state text tektt14:ret tektt13:jmp ttstate ; let someone else worry about this TEKEMU ENDP ; End TEK emulation, recover previous screen TEKEND PROC NEAR cmp tekflg,0 ; Tek sub mode active? jne teknd0 ; ne = yes ret ; else return as is. teknd0: call teksave ; save graphics screen to page 1 cmp graph_mode,hercules ; Hercules? jne teknd1 ; ne = no call htext ; yes then set up Hercules text mode teknd1: mov ah,0 ; set video mode mov al,curmode ; restore previous screen mode int screen ; revert to text screen call restscr ; restore text screen mov dx,cursor ; saved cursor position mov bh,0 ; page 0 mov ah,2 ; set cursor int screen ret TEKEND ENDP ; State machine active while Tek is active. Senses ESC [ ? 3 8 l to exit ; Tek mode and return to either non-sub mode terminal or to a VT102. ; Plays back unmatched escape sequences. Enter with character in al. tkscan proc near and al,7fh ; strip high bit cmp al,byte ptr tkoff ; start of Tek Off sequence? jne tkscn1 ; ne = no call tkscn4 ; playback previously matched chars mov tkcnt,1 ; count matched chars (one now) mov tkoffs,al ; save full character, with high bit mov al,0 ; our temporary response jmp short tkscnx ; and exit tkscn1: push bx ; check for char in Tek Off sequence mov bx,tkcnt ; number of chars matched in Tek Off mov tkoffs[bx],al ; save this char cmp al,byte ptr tkoff[bx] ; match expected char in sequence? pop bx jne tkscn3 ; ne = no, play back partial match inc tkcnt ; count new match mov al,0 ; our temporary response cmp tkcnt,tkofflen ; matched all char in sequence? jne tkscnx ; ne = not yet, wait for more mov tkcnt,0 ; clear counter cmp flags.vtflg,tttek ; are we a full Tek terminal now? jne tkscn2 ; ne = no, a submode call vtans52 ; toggle terminal type, in msyibm tkscn2: mov al,CAN ; simulate arrival of Control-X jmp short tkscnx ; all done tkscn3: call tkscn4 ; playback previously matched chars mov tkcnt,0 ; reset to no match and exit tkscnx: ret ; common exit ; local worker procedure tkscn4: push ax ; save break char (in al) push cx ; playback partial sequence to screen mov cx,tkcnt ; number of chars matched before break jcxz tkscn4b ; z = none push si mov si,offset tkoffs ; string to be played back tkscn4a:cld lodsb ; get a char into al push cx push si ; save these around tektt5a work call tektt5a ; use it pop si pop cx loop tkscn4a ; do all that came in previously pop si tkscn4b:pop cx pop ax ; recover break char ret tkscan endp TEKTXT proc near ; Dispatch on text characters cmp al,DEL ; RUBOUT? jne tektx1 ; ne = no mov al,bs ; make BS jmp short tektx7 tektx1: cmp al,CR ; carriage return (^M)? je tektx9 ; e = yes tektx2: cmp al,LF ; line feed (^J)? je tektx9 ; e = yes tektx3: cmp al,FF ; form feed (^L)? jne tektx4 ; ne = no call tekcls ; clear the screen jmp short tektx8 tektx4: cmp al,VT ; vertical tab (^K)? je tektx7 cmp al,bell ; bell (^G)? jne tektx5 ; ne = no call beep mov bypass,0 ; clear GIN mode bypass condition jmp short tektx8 tektx5: cmp al,tab ; horizontal tab (^I)? je tektx7 ; e = yes tektx6: cmp al,BS ; backspace (^H)? je tektx7 ; e = yes cmp al,' ' ; control char? jb tektx8 ; b = yes, ignore it tektx7: cmp bypass,0 ; bypass mode off? jne tektx8 ; ne = no, it's on so skip display call OUTSCRN ; output character to the screen tektx8: ret tektx9: mov bypass,0 ; clear GIN mode bypass condition jmp short tektx7 TEKTXT endp ; Process escape sequences. Callable from msz terminal emulator. ; Enter with received character in AL. Escape sequences are generally ; treated as interruptions to the current plotting/text command. Screen ; clearing is the exception by causing a general emulator reset. TEKESC PROC NEAR mov bypass,0 ; clear GIN mode bypass condition mov ttstate,offset tekesc ; in case get here from msz file cmp tekflg,0 ; Tek mode active yet? (msz call) jne tekesc1 ; ne = yes call tekini ; init now mov prestate,offset tektxt ; set a previous state of text jnc tekesc1 ; nc = succeeded ret ; else failed to init, just return tekesc1:cmp al,'Z' ; ESC-Z Identify? jne tekesc2 ; ne = no call SENDID ; Send terminal identification jmp tekescx tekesc2:cmp al,FF ; ESC-FF Clear screen? jne tekesc3 ; ne = no call tekcls ; Clear screen mov prestate,offset tektxt ; make previous state text mode jmp tekescx ; Return to text mode after ESC-FF tekesc3:cmp al,ESCZ ; ESC-^Z Enter GIN mode? jne tekesc4 ; ne = no cmp graph_mode,mono ; Monochrome text mode? je tekesc3a ; e = yes, no crosshairs in text mode mov bypass,1 ; turn on GIN mode bypass conditon call CROSHAIR ; Activate the cross-hairs jmp tekescx tekesc3a:call beep ; tell the user we are unhappy jmp tekescx ; and ignore the command tekesc4:cmp al,ENQ ; ESC-^E Enquiry for cursor position? jne tekesc5 ; ne = no mov bypass,1 ; set bypass mode call SENDSTAT ; send status jmp tekescx tekesc5:cmp al,CAN ; ESC Control-X? jne tekesc6 ; ne = no mov bypass,1 ; set bypass condition jmp tekescx tekesc6:cmp al,3fh ; query mark? (ESC ? means DEL) jne tekesc7 ; ne = no mov al,DEL ; replace with DEL code jmp tekescx ; and process it as if received. tekesc7:cmp al,accent ; accent grave, line pattern series? jb tekesc8 ; b = no cmp al,65h ; lowercase e? ja tekescx ; a = beyond line pattern series push bx mov bl,al sub bl,accent ; remove bias and bl,7 ; eight patterns, roll over excess mov bh,0 shl bx,1 ; make this a word index mov bx,linetab[bx] ; get line pattern word mov linepat,bx ; save in active word pop bx ; return to previous mode tekesc8:cmp al,5bh ; right square bracket? jne tekescx ; ne = no jmp tekcol ; start coloring scan tekescx:push ax mov ax,prestate ; get previous state mov ttstate,ax ; restore it or ax,ax ; test for none pop ax jz go2text ; z = none, use text mode clc ret ; resume previous state go2text:mov ttstate,offset tektxt ; Go to TEKTXT next time mov lastc,0 ; clear last drawing coordinate flag or status,txtmode ; set text mode in status byte clc ret TEKESC ENDP ; Parse ESC [ Pn ; Pn m ; where Pn = 30-37 foreground color, 40-47 background color, ANSI standard TEKCOL proc near mov word ptr lastd,0 ; clear parsing flags used below mov ttstate,offset tekco1 ; resume parsing below clc ret tekco1: cmp lastd,'3' ; units digit in 30 series? jne tekco2 ; ne = no inc lastd+1 ; count argument sub al,'0' ; ascii to binary cmp al,7 ; numeric? jbe tekco1a ; be = yes jmp tekco10 ; a = no, error tekco1a:push bx mov bl,al mov bh,0 mov al,byte ptr colortb[bx] ; reverse coloring pop bx and tfcol,not (7) ; retain intensity bit or tfcol,al ; remember foreground color mov lastd,0 ; clear parsing flag ret tekco2: cmp lastd,'4' ; units digit in 40 series? jne tekco4 ; ne = no inc lastd+1 ; count argument sub al,'0' cmp al,7 ; numeric? ja tekco10 ; a = no, error push bx mov bl,al mov bh,0 mov al,byte ptr colortb[bx] ; reverse coloring pop bx mov tbcol,al ; remember background color mov lastd,0 ; clear parsing flag ret tekco4: cmp lastd,0 ; looking for tens digit? jne tekco10 ; ne = yes, error cmp al,';' ; separator? jne tekco5 ; ne = no ret ; ignore it tekco5: cmp al,'0' ; remove intensity, set b/w? jne tekco6 ; ne = no mov tfcol,7 ; regular white mov tbcol,0 ; on black inc lastd+1 ; count argument ret tekco6: cmp al,'1' ; intensity bit? jne tekco7 ; ne = no and tfcol,not (8) or tfcol,8 ; set foreground intensity inc lastd+1 ; count argument ret tekco7: cmp al,'m' ; end of sequence je tekco8 ; e = yes cmp al,'3' jb tekco10 ; b = not allowed tens digit cmp al,'4' ja tekco10 ; a = not allowed tens digit mov lastd,al ; remember tens digit inc lastd+1 ; count argument ret tekco8: cmp lastd+1,0 ; number of ansi arguments, zero? ja tekco9 ; a = no, got some mov tbcol,0 ; none is same as 0, set b/w mov tfcol,7 tekco9: mov al,tbcol ; success, store coloring mov gbcol,al ; set background color mov al,tfcol mov gfcol,al ; set foreground color tekco10:mov word ptr lastd,0 ; clear argument and number of args call fixcolor ; do special ega corrections mov al,gfcol ; update these in case error mov tfcol,al mov al,gbcol mov tbcol,al jmp tekescx ; finish escape state TEKCOL endp ; Revise screen color codes for ega boards with mono displays and limited ; memory. fixcolor proc near cmp graph_mode,ega ; one of these ega modes? je fixcol0 ; e = yes cmp graph_mode,colorega je fixcol0 cmp graph_mode,monoega je fixcol0 ret ; else ignore color corrections fixcol0:mov ah,gfcol mov al,gbcol cmp graph_mode,monoega ; monochrome display? jne fixcol3 ; ne = no test al,7 ; bright backgound? jnz fixcol1 ; nz = yes mov ah,1 ; normal foreground test gfcol,8 ; intensity on? jz fixcol1 ; z = no mov ah,5 ; say bright foreground fixcol1:test al,7 ; black backgound? jz fixcol2 ; z = yes mov al,1 ; regular video fixcol2:cmp ah,al ; same color in both? jne fixcol3 ; ne = no mov ah,1 ; make foreground regular mov al,0 ; and background black fixcol3:mov gfcol,ah mov gbcol,al cmp gpage,0 ; minimal memory (64KB mono and ega)? ja fixcol4 ; a = no, enough, else strange mapping mov al,gfcol ; fix coloring to map planes C0 to C1 and al,5 ; and C2 to C3 (as 0, 3, 0Ch, or 0Fh) mov ah,al ; make a copy shl ah,1 ; duplicate planes C0, C2 in C1, C3 or al,ah ; merge the bits mov gfcol,al ; store proper foreground color mov al,gbcol ; repeat for background color and al,5 mov ah,al shl ah,1 or al,ah mov gbcol,al fixcol4:ret fixcolor endp TEKLINE proc near ; GS line drawing call tekxyc ; parse coordinates from input bytes jnc teklin1 ; nc = not done yet mov cl,visible ; get moveto or drawto variable call tekdraw ; move that point mov visible,1 ; say next time we draw teklin1:ret TEKLINE endp TEKPNT proc near ; FS plot single point call tekxyc ; parse coordinates jnc tekpnt1 ; nc = not done yet mov cl,0 ; do not draw call tekdraw ; move to the point mov ax,si ; copy starting point to end point mov bx,di ; ax,bx,si,di are in PC coordinates mov cl,1 ; make plot visible call line ; draw the dot mov visible,0 ; return to invisibility tekpnt1:ret TEKPNT endp ; Decode graphics x,y components. Returns carry set to say have all ; components for a line, else carry clear. Understands 4014 lsb extensions. ; Permits embedded escape sequences. TEKXYC proc near cmp al,CR ; Exit drawing on CR,LF,RS,US,FS,CAN je tekghx ; e = yes, a cr cmp al,LF ; these terminate line drawing cmds je tekghx cmp al,FS ; je tekghx cmp al,RS ; je tekghx cmp al,US ; je tekghx cmp al,CAN ; and je tekghx ; BUT ignore other control chars cmp al,20h ; Control char? jb tekgh0 ; b = yes, ignore it cmp al,40h jb tekgh2 ; 20-3F are HIX or HIY cmp al,60h ; 40-5F are LOX (causes beam movement) jb tekgh4 ; 60-7F are LOY ; Extract low-order 5 bits of Y coord mov ah,tek_loy ; Copy previous LOY to MSB (4014) mov tek_lsb,ah and al,1Fh ; LOY is 5 bits mov tek_loy,al cmp lastc,loy ; 2nd LOY in a row? je tekgh1 ; Yes, then LSB is valid mov tek_lsb,0 ; 1st one, clear LSB tekgh1: mov lastc,loy ; LOY seen, expect HIX (instead of HIY) tekgh0: clc ; c clear = not completed yet ret tekghx: jmp go2text ; Extract high-order 5 bits (X or Y, depending on lastc) tekgh2: and ax,1Fh ; Just 5 bits mov cl,5 shl ax,cl ; Shift over 5 bits cmp lastc,loy ; was last coordinate a low-y? je tekgh3 ; e = yes, parse hix mov tek_hiy,ax ; this byte has HIY mov lastc,hiy clc ret tekgh3: mov tek_hix,ax ; This byte has HIX mov lastc,hix clc ret tekgh4: and al,1Fh ; Just 5 bits mov tek_lox,al mov lastc,lox mov ax,tek_hix ; Combine HIX*32 or al,tek_lox ; with LOX mov bx,tek_hiy ; Same for Y or bl,tek_loy stc ; set c to say completed operation ret TEKXYC endp TEKRLIN proc near ; RS relative line drawing cmp al,' ' ; Pen up command? jne tekrli1 ; ne = no, try pen down mov visible,0 ; do invisible movements jmp short tekrli2 ; do the command tekrli1:cmp al,'P' ; pen down command? jne tekrli3 ; ne = no, return to text mode mov visible,1 ; set visible moves tekrli2:mov ax,x_coord ; PC x coordinate of pen mov bx,y_coord ; y coordinate call pctotek ; get current pen position in Tek coor mov cl,0 ; invisible, moveto call tekdraw ; move that point, set oldx and oldy mov ttstate,offset tekinc ; next get incremental movement cmds ret tekrli3:mov visible,0 ; bad char, reset visibility push prestate pop ttstate ; restore previous state jmp tektt5 ; deal with the break char TEKRLIN endp ; interpret RS inc plot command byte TEKINC proc near ; get movement character and do cmd cmp al,'A' ; move right? jne tekinc1 ; ne = no inc oldx ; adjust beam position jmp short tekinc9 tekinc1:cmp al,'E' ; move right and up? jne tekinc2 ; ne = no inc oldx inc oldy jmp short tekinc9 tekinc2:cmp al,'D' ; move up? jne tekinc3 ; ne = no inc oldy jmp short tekinc9 tekinc3:cmp al,'F' ; move left and up? jne tekinc4 ; ne = no dec oldx inc oldy jmp short tekinc9 tekinc4:cmp al,'B' ; move left? jne tekinc5 ; ne = no dec oldx jmp short tekinc9 tekinc5:cmp al,'J' ; move left and down? jne tekinc6 ; ne = no dec oldx dec oldy jmp short tekinc9 tekinc6:cmp al,'H' ; move down? jne tekinc7 ; ne = no dec oldy jmp short tekinc9 tekinc7:cmp al,'I' ; move right and down? jne tekincb ; ne = no, bad command inc oldx dec oldy tekinc9:cmp oldx,0 ; too far left? jge tekinc10 ; ge = no mov oldx,0 ; else stop at the left margin tekinc10:cmp oldx,maxtekx-1 ; too far left? jle tekinc11 ; le = no mov oldx,maxtekx-1 ; else stop that the left margin tekinc11:cmp oldy,maxteky-1 ; above the top? jle tekinc12 ; le = no mov oldy,maxteky-1 ; else stop at the top tekinc12:cmp oldy,0 ; below the bottom? jge tekinc13 ; ge = no mov oldy,0 ; else stop at the bottom tekinc13:mov ax,oldx ; ax is vector x end point mov bx,oldy ; bx is vector y end point mov cl,visible call tekdraw ; move/draw to that point ret tekincb:push prestate ; bad character, exit inc plot mode pop ttstate ; new state is previous state mov visible,0 jmp tektt5 ; reparse the bad char TEKINC endp ; Routine to trigger the crosshairs, wait for a key to be struck, and send ; the typed char (if printable ascii) plus four Tek encoded x,y position ; coordinates and then a carriage return. ; ax, cx, xcross, ycross operate in PC coordinates. CROSHAIR PROC NEAR push linepat ; save line drawing pattern mov linepat,0ffffh ; reset line type to solid mov ax,xmax ; right margin minus 7 dots add ax,7 mov temp,ax ; right margin dot crosha1:call crosdraw ; draw the cross-hairs call iseof ; is stdin at EOF? jc crosha2 ; c = yes, exit this mode now mov ah,coninq ; DOS, quiet read char int dos push ax ; save char for later call crosdraw ; erase cross hairs pop ax or al,al ; ascii or scan code returned jnz arrow5 ; nz = ascii char returned call iseof ; is stdin at EOF? jc crosha2 ; c = yes, exit this mode now mov ah,coninq ; read scan code int dos cmp al,0 ; Control-Break? jne crosha3 ; ne = no, something else crosha2:pop linepat ; restore line pattern ret ; exit crosshairs mode crosha3:cmp al,homscn ; is it 'home'? jne arrow1 ; ne = no, try other keys mov ax,temp ; right margin shr ax,1 ; central position mov xcross,ax ; save PC coord for crosshair mov ax,ybot ; last scan line shr ax,1 mov ycross,ax ; this is the center of the screen jmp crosha1 ; home the crosshairs arrow1: cmp al,lftarr ; left arrow? jne arrow2 ; ne = no mov cx,-1 ; left shift jmp short xkeys arrow2: cmp al,rgtarr ; right arrow? jne arrow3 ; ne = no mov cx,1 ; right shift jmp short xkeys arrow3: cmp al,uparr ; up arrow? jne arrow4 ; ne = no mov cx,-1 ; up shift jmp short vertkey arrow4: cmp al,dnarr ; down arrow? jne badkey ; ne = no, ignore it mov cx,1 ; down shift jmp short vertkey badkey: call beep ; tell user we don't understand jmp crosha1 ; keep going ; Shifted keys yield ascii keycodes arrow5: cmp al,'C' and 1fh ; Control-C? je crosha2 ; e = yes, exit crosshairs mode now cmp al,shlftarr ; shifted left arrow? jne arrow6 ; ne = no mov cx,-10 ; big left shift jmp short xkeys arrow6: cmp al,shrgtarr ; shifted right arrow? jne arrow7 ; ne = no mov cx,10 ; big right shift jmp short xkeys arrow7: cmp al,shuparr ; shifted up arrow? jne arrow8 ; ne = no mov cx,-10 ; big up shift jmp short vertkey arrow8: cmp al,shdnarr ; shifted down arrow? jne charkey ; ne = no, send this key as is mov cx,10 ; big down shift jmp short vertkey xkeys: add cx,xcross ; add increment jns noxc ; gone too far negative? mov cx,0 ; yes - then make it 0 noxc: cmp cx,temp ; too far right? jb xdraw9 ; b = no mov cx,temp ; yes - then make it the right xdraw9: mov xcross,cx ; new x value for cross hairs jmp crosha1 ; and redraw vertkey:add cx,ycross ; adjust cx jns noyc ; gone negative? mov cx,0 ; yes then make 0 noyc: cmp cx,ybot ; too high? jb yok mov cx,ybot ; make it maximum yok: mov ycross,cx ; save new y crosshair jmp crosha1 ; and redraw charkey:call clrbuf ; purge received data to date call outmodem ; send the break character mov ax,xcross ; set beam to xcross,ycross mov bx,ycross ; must convert to Tek coordinates call pctotek ; scale from PC screen coord to Tek push ax ; save around drawing push bx mov cx,0 ; just a move call tekdraw ; moveto ax,bx in Tek coord pop bx ; recover Tek y pop ax ; recover Tek x call sendpos ; send position report to host pop linepat ; recover current line drawing pattern mov ttstate,offset tektxt ; Go to TEKTXT next time mov lastc,0 ; clear last drawing coordinate flag or status,txtmode ; set text mode in status byte ret CROSHAIR ENDP ; CROSDRAW draws cross-hairs by XORing cross with picture. ; xcross and ycross are in PC coordinates. CROSDRAW PROC NEAR mov si,xcross ; move to (xcross, ycross-10) mov di,ycross sub di,10 ; half the size of the cross jns crosd1 ; no sign bit means ok mov di,0 ; else limit to start of screen crosd1: mov ax,si ; next, draw to (xcross, ycross+10) mov bx,ycross ; make bottom stroke add bx,10 cmp bx,ybot ; too large? jbe crosd2 ; be = no mov bx,ybot ; vertical line to (xcross,ybot) crosd2: mov cx,0ffh ; invert pixels call line ; and draw vertical sub si,12 ; move to (xcross-12, ycross) jns crosd3 ; no sign means ok mov si,0 ; else limit to start of line crosd3: mov di,ycross mov bx,di mov ax,xcross ; draw to (xcross+12, ycross) add ax,12 cmp ax,temp ; temp is right margin, too large? jbe crosd4 ; be = no, ok mov ax,temp ; max x value crosd4: mov cx,0ffh ; set XOR code call line ; draw to (xcross+12, ycross) ret CROSDRAW ENDP ; SENDPOS sends position of cross-hairs to the host. ; ax has Tek X and bx has Tek Y coord of center of crosshair SENDPOS PROC NEAR push bx ; preserve register call sendxy ; send x coord pop ax call sendxy ; send y coord mov al,cr ; follow up with cr call outmodem ret SENDPOS ENDP ; SENDXY sends value of ax as Tek encoded bytes ; ax is in Tek coordinates SENDXY PROC NEAR shl ax,1 shl ax,1 ; move all but lower 5 bits to ah shl ax,1 shr al,1 shr al,1 ; move low five bits to low 5 bits shr al,1 or ah,20h ; make it a printing char as per TEK xchg al,ah ; send high 5 bits first call outmodem xchg al,ah ; then low five bits or al,20h call outmodem xchg ah,al ; al is first sent byte ret SENDXY ENDP SENDID PROC NEAR ; Pretend VT100 with graphics option mov bx,IDSEQ ; Get addr of string sndid1: mov al,[bx] ; Get char from sequence cmp al,0 ; End of sequence? jz sndid0 ; Yes, return call OUTMODEM ; Send it out the port inc bx jmp sndid1 sndid0: ret SENDID ENDP ; SENDSTAT - send status and cursor position to host SENDSTAT PROC NEAR mov al,STATUS ; get tek status or al,20h ; make it printable call OUTMODEM ; and send it mov ax,oldx ; now send x coordinate (oldx is Tek) call SENDXY mov ax,oldy ; and y coordinate (oldy is Tek coord) call SENDXY mov al,cr ; end with a cr call OUTMODEM ret SENDSTAT ENDP ; routine to send al to the modem port OUTMODEM PROC NEAR push ax mov ah,al call outchr ; outchr reads from ah nop ; ignore errors nop nop pop ax ret OUTMODEM ENDP ; Convert X and Y from PC coordinates to Tek coordinates. AX = X, BX = Y ; for both input and output. pctotek proc near mul xdiv ; scale from PC screen coord to Tek div xmult xchg bx,ax ; save Tek x coord in bx neg ax ; y axis. Turn upside down for Tek add ax,ybot mul ydiv ; scale y from PC screen coord to Tek div ymult xchg ax,bx ; ax has X, bx has Y in Tek coords ret pctotek endp ; Routine to output character in AL to the screen. OUTSCRN PROC NEAR ; Output one character to the screen cmp bypass,0 ; GIN mode bypass off? je outscp ; e = yes ret ; else ignore characters outscp: ; Set Translation Input filter cmp rxtable+256,0 ; translation turned off? je outsct ; e = yes, no translation push bx mov bx,offset rxtable ; address of translate table xlatb ; new char is in al and al,7fh ; retain only lower seven bits pop bx outsct: mov si,ybot ; get last scan line inc si ; number of scan lines sub si,y_coord ; minus where char bottom needs to go jnc outscc ; nc = enough space for char ; else give "More >" message push ax ; save current char push cx mov cx,mormsglen ; characters in More message mov ax,cx shl ax,1 shl ax,1 shl ax,1 ; times 8 bits/character neg ax ; (note: leave last char cell empty) add ax,xmax ; right justify mov x_coord,ax ; set starting x dot mov ax,ybot mov y_coord,ax ; set starting y line mov ccode,1 ; write in foreground colors push cx mov al,DEL ; fill all pixels outscm1:call putc ; write loop outscm1 pop cx push cx mov al,BS ; backup to overwrite with More text outscm2:call putc loop outscm2 pop cx mov ccode,0 ; main text in background colors mov si,offset moremsg ; give More message outsclf:cld lodsb ; read a byte from string call putc ; display the string loop outsclf ; repeat for all string chars pop cx mov ccode,1 ; restore normal foreground coloring call iseof ; EOF on redirected stdin? jc outscl3 ; c = yes, proceed anyway mov ah,coninq ; read keyboad via DOS int dos ; wait for keystroke or al,al ; scan code being returned? jne outscl3 ; ne = no mov ah,coninq ; clear away scan code too int dos outscl3:call tekcls ; clear the screen pop ax ; recover current character cmp al,lf ; just a line feed? jne outscc ; ne = no, display it ret ; else ignore the line feed outscc: push ax mov ax,xmax cmp x_coord,ax ; beyond right margin? jbe outsc3 ; be = no mov al,cr ; else simulate cr/lf call putc ; before displaying current char mov al,lf call putc outsc3: pop ax call putc ; routine to draw characters ret OUTSCRN ENDP ; TEKCLS routine to clear the screen. ; Entry point tekcls1 clears screen without resetting current point. TEKCLS PROC NEAR cmp tekflg,0 ; Tek sub mode active yet? jne tekcls0 ; ne = yes ret ; else ignore this call tekcls0:mov x_coord,0 ; starting text coordinates mov y_coord,8 mov oldx,0 ; assumed cursor starting location mov oldy,maxteky ; top right corner (Tek coord) mov scalex,0 ; clear last plotted point (PC coord) mov scaley,0 mov lastc,0 ; last parsed x,y coordinate mov visible,0 ; make lines invisible mov linepat,0ffffh ; reset line pattern to solid mov ccode,1 ; reset to ordinary writing mov bypass,0 ; clear bypass condition mov ttstate,offset tektxt ; do displayable text push ax mov ax,xmax ; right margin minus 7 dots add ax,7 ; right most dot shr ax,1 ; central position mov xcross,ax ; save PC coord for crosshair mov ax,ybot ; last scan line shr ax,1 mov ycross,ax ; this is the center of the screen pop ax tekcls1:push ax ; save registers push cx cmp graph_mode,hercules ; Hercules? jne tekcls2 ; ne = no call hgraf ; set Hercules board to Graphics mode jmp tekcls7 tekcls2:mov di,0 ; point to start of screen, di=row call psetup ; setup graphics routine and es:di mov cx,4000h ; CGA, 200 lines times 80 bytes worth cmp graph_mode,cga ; cga? je tekcls3 ; e = yes mov cx,8000h ; Olivetti, 400 lines times 80 bytes cmp graph_mode,olivetti ; AT&T-Olivetti? je tekcls3 ; e = yes cmp graph_mode,toshiba ; Toshiba? je tekcls3 ; e = yes cmp graph_mode,vaxmate ; VAXmate? jne tekcls4 ; ne = no tekcls3:cld ; clear screen directly of text stuff mov al,0 ; color is black rep stosb ; clear the bytes jmp short tekcls7 tekcls4:cmp graph_mode,ega ; EGA? je tekcls5 ; e = yes cmp graph_mode,monoega ; EGA with mono display? je tekcls5 ; e = yes cmp graph_mode,colorega ; EGA with medium resolution monitor? je tekcls5 ; e = yes jmp short tekcls6 ; else use Bios tekcls5: ; EGA clear screen quickly mov ax,0ff08h ; set all 8 bits to be changed call ega_gc ; set bit mask register accordingly mov cx,ybot ; last scan line inc cx ; number of scan lines mov ax,80 ; bytes per scan line mul cx mov cx,ax ; cx = number of bytes to clear mov al,gbcol ; select background colour cld rep stosb ; write backgound color jmp short tekcls7 tekcls6:push es ; clear screen by scrolling up call cmblnk ; clear screen, for Environments pop es tekcls7:mov si,0 ; starting x (in case screen is mov di,0 ; starting y cleared by user) pop cx pop ax ret TEKCLS ENDP ; Routine to draw a line on the screen, using TEKTRONIX coordinates. ; X coordinate in AX, 0=left edge of screen, 1023=right edge of screen. ; Y coordinate in BX, 0=bottom of screen, 779=top of screen. ; CL=0 - invisible move, CL=1 - draw a line, CL=0FFh - invert pixels on line TEKDRAW PROC NEAR mov si,scalex ; get old x already scaled mov di,scaley ; get old y already scaled call scale ; scale new end point to PC coords cmp cl,0 ; invisible drawing? je moveto ; z = just move, skip draw part call LINE ; draw the line moveto: mov x_coord,ax ; update text coordinates to match mov y_coord,bx ; last drawn point ret TEKDRAW ENDP ; Scale TEKTRONIX coordinates to the currently defined screen coordinates ; AX holds X axis, BX holds Y axis. Both are changed from Tektronix coord ; to PC coordinates by this procedure. SCALE PROC NEAR push dx push si mov oldx,ax ; save current Tek x for next draw mov oldy,bx ; save current Tek y for next draw mul xmult ; scale x-coord mov si,xdiv ; get the divisor shr si,1 ; halve it add ax,si ; add in - to round to nearest integer adc dx,0 div xdiv push ax mov ax,bx mul ymult ; scale y-coord mov si,ydiv ; get divisor shr si,1 ; halve it add ax,si ; add in - to round to nearest integer adc dx,0 div ydiv mov bx,ybot sub bx,ax ; Put new Y in right reg jns scale3 ; ns = not too far mov bx,0 scale3: pop ax ; Put new X in right reg mov scalex,ax ; save scaled values mov scaley,bx pop si pop dx ret SCALE ENDP ; LINE Subroutine to plot a line with endpoints in AX,BX and SI,DI. ; fast line drawing routine for the IBM PC ; ; Registers at CALL ; ----------------- ; SI=Start X coord, all in PC coordinates ; DI=Start Y coord ; AX=End X coord ; BX=End Y coord ; CL=Color code: 1=draw foreground, 0=draw background, 0ffh=invert ; BP= line drawing pattern (is changed here by rotation) ; registers are all unchanged LINE PROC NEAR push ax push bx push cx push dx push si push di push es mov bp,linepat ; store active line pattern word in BP mov ccode,cl ; save color code in ccode for use by plot() ; first get coord to achieve increasing x; deltax >= 0 sub ax,si ; deltax = x2 - x1 jge line1 ; ge = going to the right, as desired neg ax ; make deltax non-negative sub si,ax ; swap the x coordinates xchg bx,di ; swap the y coordinates too ; second, compute deltay. ax = deltax, si = x1 line1: sub bx,di ; deltay = y2 - y1 call psetup ; setup display adapter for plotting ; and setup es:di to screen memory ; Choose algorithm based on |deltay| < |deltax| (use shallow) else steep. ; We arrange matters such that both deltas are non-negative. cmp bx,0 ; deltay jge line2 ; ge = non-negative neg linelen neg bx ; make non-negative line2: cmp bx,ax ; |deltay| versus |deltax| jbe shallow ; be = do shallow algorithm jmp steep ; else do steep algorithm ; shallow algorithm, move along x, di=y1, bx=deltay, si=x1, ax=deltax shallow:add bx,bx ; bx = 2*deltay mov cx,ax ; cx = number of steps (deltax here) inc cx ; loop dec's cx before testing mov dx,bx ; dx holds error sub dx,ax ; error = 2*deltay - deltax add ax,ax ; ax = 2*|deltax| shal1: call plotptr ; Plot(x,y) cmp dx,0 jle shal2 ; le = error <= 0 call pincy ; increment y by one scan line sub dx,ax ; error = error - 2*deltax shal2: add dx,bx ; error = error + 2*deltay inc si ; x = next dot right loop shal1 shal3: jmp short plotex ; steep algorithm, move along y, di=y1, bx=deltay, si=x1, ax=deltax steep: add ax,ax ; ax = 2*deltax mov dx,ax ; dx holds error sub dx,bx ; error = 2*deltax(bx) - deltay (bx) mov cx,bx ; cx = number of steps (deltay here) inc cx ; loop dec's cx before testing add bx,bx ; bx = 2*|deltay| stee1: call plotptr ; Plot(x,y) x = ax, y = di cmp dx,0 jle stee2 ; le error <= 0 inc si ; x = next dot right sub dx,bx ; error = error - 2*deltay stee2: add dx,ax ; error = error + 2*deltax call pincy ; increment y loop stee1 stee3:;;;jmp plotex plotex: mov ccode,1 ; reset to do foreground coloring pop es pop di pop si pop dx ; restore the world pop cx pop bx pop ax ret LINE ENDP ;;;;;;; EGA plot support routines psetupe proc near ; EGA setup for plotting push ax mov linelen,80 ; for y going down screen by pincy mov ax,segscn ; set es to screen memory segment mov es,ax mov ax,0205h ; mode: write mode 2 call ega_gc mov ax,0003h ; assume writing bits directly cmp ccode,0ffh ; inverting bits? jne psete2 ; ne = no mov ax,1803h ; then say XOR the bits psete2: call ega_gc ; set controller mov ax,80 ; compute starting point in regen buff mul di mov di,ax ; di = di * 80 pop ax ret psetupe endp pincye proc near ; EGA inc y add di,linelen ; includes sign of deltay ret pincye endp pltega proc near ; EGA plot(x,y). x is in si, y is in di rol bp,1 ; rotate line pattern jnc pltega1 ; nc = no bit to be plotted push bx push si push di mov bx,si ; want si/8 for bytes along line shr si,1 shr si,1 shr si,1 add di,si ; starting point in regen buffer and bx,0007h ; leave lower 3 bits for bit in byte mov bh,masktab[bx] ; 0-7 into bit mask in byte, x pos mov bl,ccode ; get line type code call ega_plt pop di pop si pop bx pltega1:ret pltega endp ;;;;;;;; CGA plot support routines ; The CGA graphics memory mapping in mode 6 (640 by 200) is 8 dots per byte, ; left most dot in the high bit, 80 bytes per scan line, scan line segments ; alternating between 0b800h (even lines 0, 2, ...) and 0ba00h (odd lines). psetupc proc near ; CGA setup for plotting push ax push cx mov linelen,80 ; 80 bytes per scan line mov cx,segscn mov es,cx mov cx,di ; save copy of di, start y line ; compute starting point in regen buff shr di,1 ; half the lines in each bank mov ax,80 ; 80 bytes per line mul di mov di,ax ; di = di * 80 / 2 test cx,1 ; even or odd line jz psetc1 ; z = even add di,2000h ; offset to odd bank (seg 0ba00h) psetc1: and di,3fffh pop cx pop ax ret psetupc endp pincyc proc near ; CGA inc y cmp linelen,0 ; increasing or decreasing y? jl pinyc2 ; l = decreasing cmp di,2000h ; in upper bank now? jb pinyc1 ; b = no, in lower bank add di,linelen ; add a line pinyc1: add di,2000h ; switch banks and di,3fffh ; roll over address ret pinyc2: cmp di,2000h ; in upper bank now? jae pinyc4 ; ae = yes add di,linelen ; subtract a line pinyc4: add di,2000h ; switch banks and di,3fffh ; roll over address ret pincyc endp pltcga proc near ; CGA plot(x,y). x is in si, y is in di push bx ; used for HGA plot also. push si push di rol bp,1 ; rotate line pattern jnc pltcg3 ; nc = no bit to be plotted mov bx,si ; want si/8 for bytes along line shr si,1 shr si,1 shr si,1 add di,si ; starting point in regen buffer and bx,0007h ; leave lower 3 bits for bit in byte ; di = offset in regen buffer mov bh,masktab[bx] ; 0-7 into bit mask in byte. x position mov bl,ccode ; get line type code cmp bl,1 ; draw the bit? jne pltcg1 ; ne = no or es:[di],bh ; drawn jmp short pltcg3 pltcg1: cmp bl,0 ; draw in background (erase)? jne pltcg2 ; ne = no not bh and es:[di],bh ; erase the dots jmp short pltcg3 pltcg2: xor es:[di],bh ; xor in this color pltcg3: pop di pop si pop bx ret pltcga endp ;;;;;;; HGA plot support routines ; The HGA graphics memory mapping in mode 255 (720 by 348) is 8 dots per byte, ; left most dot in the high bit, 90 bytes per scan line, scan line segments ; sequence as 0b000h, 0b200h, 0b400h, 0b800h for lines 0-3 and repeat 90 bytes ; higher for the rest. psetuph proc near ; HGA setup for plotting push ax push cx mov linelen,90 ; for y going down screen by incy mov ax,segscn ; base segment of display memory mov es,ax mov cx,di ; save copy of di, start y line ; compute starting point in regen buff shr di,1 ; quarter the lines in each bank shr di,1 mov ax,90 mul di mov di,ax ; di = di * 90 / 4 and cx,3 ; compute bank from 2 lsb of line num jcxz pseth2 ; z means it is in bank 0 (0b000h) pseth1: add di,2000h ; add offset for each bank loop pseth1 ; do cx times pseth2: pop cx pop ax ret psetuph endp pincyh proc near ; HGA inc y, step offset of line cmp linelen,0 ; increasing y? jg pinyh2 ; g = yes cmp di,2000h ; in lowest for four banks? ja pinyh1 ; a = no add di,linelen ; yes, add a line pinyh1: add di,6000h ; move back by adding a lot and di,7fffh ; roll over address ret pinyh2: cmp di,6000h ; in top most bank? jb pinyh4 ; b = no add di,linelen ; yes, first add a line pinyh4: add di,2000h ; switch to next bank and di,7fffh ; roll over address ret pincyh endp ;;;;;;; AT&T-Olivetti, Toshiba, VAXmate Graphics Adapter plot support routines ; The graphics memory mapping in 640 by 400 mode is 8 dots per byte, ; left most dot in the high bit, 80 bytes per scan line, scan line segments ; sequence as 0b800h, 0ba00h, 0bc00h, 0be00h for lines 0-3 and repeat 80 bytes ; higher for the rest. Use Hercules line incrementing (inc y) and CGA dot ; writing. This is a monographic display. psetupo proc near ; setup for plotting push ax push cx mov linelen,80 ; for y going down screen by incy mov ax,segscn ; base segment of display memory mov es,ax mov cx,di ; save copy of di, start y line ; compute starting point in regen buff shr di,1 ; quarter the lines in each bank shr di,1 mov ax,80 mul di mov di,ax ; di = di * 80 / 4 and cx,3 ; compute bank from 2 lsb of line num jcxz pseto2 ; z means it is in bank 0 (0b800h) pseto1: add di,2000h ; add offset for each bank loop pseto1 ; do cx times pseto2: pop cx pop ax ret psetupo endp ;;;;;;;; Monochrome, simulate dots with text char psetupm proc near mov linelen,1 ; 80 characters but one line ret psetupm endp pltmon proc near ; Monochrome dot plot mov x_coord,si ; put dot at row=di, col=si, PC Coord mov y_coord,di push ax mov al,'+' ; our dot character call mputc ; display text char pop ax ret pltmon endp pincym proc near ; Monochrome inc y add di,linelen ; includes sign ret pincym endp ; GPUTC - a routine to send text characters from font to true graphics boards ; such as EGA, Hercules or CGA. Char is in al. Drawing routine ptr is gcplot. gputc proc near cmp al,' ' ; control character? jae gputc1 ; ae = no, display the char jmp putctrl ; else handle controls at putctrl gputc1: push ax ; first save some registers push bx push cx push es push di mov bl,al ; now BL has char to be displayed and bl,7fh ; no high bits allowed here ; set board mode mov di,y_coord ; get current y coord (char bottom) sub di,8 ; start 8 lines higher jnc gputc2 ; nc = ok mov di,0 ; move up to first line mov y_coord,8 ; and reset scan line indicator gputc2: call psetup ; enter with di=line number, sets es:di to ; start of line in display buf and ; sets byte-wide plot mode mov ax,x_coord ; compute regen buffer byte shr ax,1 ; want x_coord/8 for bytes along line shr ax,1 shr ax,1 add di,ax ; byte in regen buffer xor bh,bh sub bx,32 ; characters in font start at 32 shl bx,1 shl bx,1 ; 8 bytes per char - hence * 8 shl bx,1 mov cx,8 ; 8 bytes (scan lines) to transfer call gcplot ; call character plot routine call incx ; move to next char position pop di pop es pop cx pop bx pop ax ret gputc endp putctrl proc near ; CONTROL CHARS = cursor movement push ax ; save character cmp al,FF ; formfeed? jne putct0 ; ne = no call TEKCLS ; FF clears the screen jmp putctx putct0: cmp al,BS ; BS? sends (logical) cursor back one jne putct2 ; ne = no, try next mov ax,x_coord sub ax,8 ; so delete 8 dots (move left) jns putct1 ; ns = non-negative mov ax,0 ; but not less than 0 putct1: mov x_coord,ax ; and replace x coordinate mov al,' ' ; send a space call putc sub x_coord,8 ; restore cursor jmp putctx putct2: cmp al,tab ; tabs move forward one char position jne putct4 ; ne = not a tab call incx ; let incx move cursor right one col jmp putctx putct3: mov x_coord,ax jmp putctx putct4: cmp al,cr ; 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 putctx sub y_coord,8 ; subtract one line (8 pixels) jnc putctx ; nc = space left mov y_coord,8 ; else set to top of screen putctx: pop ax ret putctrl endp mputc proc near ; MONO put char in AL via Bios push ax ; updates x_coord,y_coord with push bx ; new cursor position push cx push dx mov ah,0 ; marker for cursor setting not needed cmp al,' ' ; control code? jae mputc1 ; ae = no, printable call putctrl ; do cursor arithmetic mov ah,1 ; marker to set cursor but no display mputc1: push ax ; save char and marker mov cl,3 ; char cell is 8 x 8 dots mov ax,x_coord ; get resulting cursor PC positions shr ax,cl mov dl,al ; column mov ax,y_coord sub ax,8 ; minus 8 dots, like other modes jnc mputc2 ; nc = non-negative mov ax,0 ; else start at the top mov y_coord,8 ; here too mputc2: shr ax,cl mov dh,al ; row mov ah,2 ; set cursor to x_coord,y_coord mov bh,0 ; page 0 int screen pop ax cmp ah,0 ; write a char in al? jne mputcx ; ne = no mov ah,09h ; write char at cursor postion mov cx,1 ; just one char mov bh,0 ; page 0 mov bl,gfcol ; foreground coloring int screen inc dl ; next column mov ah,2 ; set real cursor ahead of last char int screen call incx ; move logical cursor mputcx: pop dx pop cx pop bx pop ax ret mputc endp incx proc near ; move the logical cursor right mov ax,x_coord ; shift the (logical) cursor right add ax,8 ; one character cell mov x_coord,ax cmp ax,xmax ; at end of the line? jbe incx1 ; b = no mov x_coord,0 ; wrap to next line add y_coord,8 ; next row mov ax,ybot ; last scan line cmp ax,y_coord ; below bottom line? jge incx1 ; ge = no mov y_coord,ax ; set to bottom row mov al,lf ; simulate a line feed operation call outscrn ; invoke More message incx1: ret incx endp ; EGA Character plot routine. Enter with bx pointing at font array for char ; cx = number of bytes in char font, es:di = screen memory. Worker for gputc. ; ccode: 0=plot in background colors, 1=foreground, 0ffh=xor with screen gcega proc near gcega1: mov al,font[bx] ; EGA byte plot: get bits from font push bx ;;;;; mov bh,0ffh ; write these bits to clear field ;;;;; mov bl,0 ; in background coloring ;;;;; call ega_plt ; plot a byte mov bh,al ; set bit pattern of character mov bl,ccode ; plot in back/fore/xor (ccode) colors call ega_plt ; byte plot routine for EGA systems pop bx inc bx ; next byte of char pattern call pincy ; next scan line (linelen is preset) loop gcega1 ret gcega endp ; General Character plot routine. Enter with bx pointing at font array for ; char, cx = number of bytes in char font, es:di = screen memory. ; Worker for gputc. gcgen proc near gcgen1: mov al,font[bx] ; Non-EGA systems: get bits from font cmp ccode,1 ; write in foreground? je gcgen2 ; e = yes xor es:[di],al ; background or xor (same) jmp short gcgen3 ;;;; mov es:[di],al ; write desired pattern (no overwrite) gcgen2: OR es:[di],al ; write desired pattern (no overwrite) gcgen3: inc bx ; point to next byte of char pattern call pincy ; next scan line (linelen is preset) loop gcgen1 ; and repeat until complete ret gcgen endp ; routines to manipulate ega graphics controller and mode register ; command code in al, value in ah - destroys al and dx ega_gc proc near ; ega graphics controller mov dx,3ceh out dx,al ; output command code inc dx ; dx is now data port mov al,ah ; get value to al out dx,al ; output value ret ega_gc endp ega_md proc near ; ega mode controller mov dx,3c4h out dx,al ; output command code inc dx ; dx is now data port mov al,ah ; get value to al out dx,al ; output value ret ega_md endp ; Plot eight pixels using an EGA board ; Enter with ES:[DI] pointing to screen address of byte, ; bh has pattern of bits to be set, bl has attributes: ; 0 = draw in background color, 1 = draw in foreground color, ; 0ffh = XOR with current dot colors. ; registers preserved ega_plt proc near push ax push dx mov al,8 ; command to set bit mask register mov ah,bh ; get bits to be modified (1) call ega_gc ; unprotect those bit positions mov ah,gfcol ; get foreground colour cmp bl,1 ; draw in foreground? je ega2 ; ne = no mov ah,gbcol ; get grahics background colour cmp bl,0ffh ; do an XOR? jne ega2 ; ne = no mov ah,0ffh ; XOR, touch all color bits ega2: mov al,es:[di] ; latch byte mov es:[di],ah ; set the byte pop dx pop ax ret ega_plt endp ; routine to set Hercules card to graphics mode - both pages are enabled HGRAF PROC NEAR push ax push bx ; save used registers push cx push si mov al,grph ; graph mode lea si,gtable ; requires graphics table mov bx,0 mov cx,4000h ; clear 4000h words call setmd ; and set the mode pop si pop cx pop bx pop ax ret HGRAF ENDP ; set Hercules card to text mode HTEXT PROC NEAR push ax push bx push cx push si mov al,text ; text mode lea si,ttable ; requires text table mov bx,0720h ; blank value (space, white on black) mov cx,2000 ; whole screen to clear (80*25) call setmd ; set the mode pop si pop cx pop bx pop ax ret HTEXT ENDP ; Hercules mode set - called from HTEXT and HGRAF SETMD PROC NEAR push dx push ax mov dx,config ; configuration port mov al,genable ; allow graphics mode to be set out dx,al pop ax push ax push cx ; save count mov dx,cntrl ; control port out dx,al ; set to text or graphics mov dx,index ; send 12 bytes from table to 6845 mov cx,12 ; number of registers to load xor ah,ah ; start with register 0 of 6845 cld setmd1: jmp $+2 ; small pause for hardware mov al,ah ; ah is counter out dx,al ; set register inc dx ; point to data port lodsb ; get next byte in table jmp $+2 ; small pause for hardware out dx,al ; and send to 6845 inc ah ; next register dec dx ; point to register port loop setmd1 ; and continue 'til cx=0 pop cx ; recover count cld push di push es mov ax,segscn ; start of screen mov es,ax xor di,di mov ax,bx ; get blanking character rep stosw ; store blanking char in whole screen pop es pop di mov dx,cntrl ; now to re-enable screen pop ax ; get mode or al,scrn_on ; enable screen out dx,al pop dx ret SETMD ENDP teksave proc near ; saves graphics screen from page 0 to page 1 push si push di cmp gpage,0 ; only graphics page 0 on display board? je teksavx ; e = yes, no saving possible here mov si,segscn ; segment (!) of current screen cmp graph_mode,ega je teksav1 cmp graph_mode,monoega je teksav1 cmp graph_mode,colorega je teksav1 cmp graph_mode,hercules je teksav2 jmp short teksavx ; else nothing teksav1:mov di,segega+800h ; EGA page 1 screen segment call egasr ; call common save/restore code jmp short teksavx teksav2:mov di,seghga+800h ; Hercules page 1 screen segment call hgasr ; call common save/restore code teksavx:pop di pop si ret teksave endp tekrest proc near ; saves graphics screen of page 0 in page 1 push si push di cmp gpage,0 ; only graphics page 0 on display board? jne tekres0 ; ne = no, more so work to do here call tekcls1 ; else clear the screen to color it jmp short tekresx ; and exit tekres0:mov di,segscn ; segment (!) of new graphics screen cmp graph_mode,ega je tekres1 cmp graph_mode,monoega je tekres1 cmp graph_mode,colorega je tekres1 cmp graph_mode,hercules je tekres2 jmp short tekresx ; else nothing tekres1:mov si,segega+800h ; segment of EGA page 1 call egasr ; call common save/restore code jmp short tekresx tekres2:mov si,seghga+800h ; segment of Hercules page 1 call hgasr ; call common save/restore code tekresx:pop di pop si ret tekrest endp egasr proc near ; common code for Tek ega save/restore ops push ax push cx push dx mov ax,0f00h ; enable 4 plane set/resets call ega_gc ; set controller mov ax,0f01h ; enable Set/Reset register call ega_gc mov ax,0f02h ; set color compare register for 4 planes call ega_gc mov ax,0905h ; set mode reg: write latches, read mode call ega_gc mov ax,0ff02h ; enable all planes call ega_md mov cx,ybot ; last scan line inc cx ; number of scan lines mov ax,80 ; bytes per scan line mul cx mov cx,ax push es ; save es push ds ; save ds mov es,di ; destination, set es to video memory mov ds,si ; source, set ds to video memory xor si,si ; clear offset fields xor di,di cld rep movsb ; copy from page [si] to page [di] pop ds ; recover ds pop es ; and other registers mov ax,0000h ; disable 4 plane set/resets call ega_gc ; set controller mov ax,0001h ; disable Set/Reset register call ega_gc ; set controller mov ax,0002h ; disable color compare register call ega_gc mov ax,1005h ; set mode reg: write latches, odd/even call ega_gc pop dx pop cx pop ax ret egasr endp hgasr proc near ; Hercules save restore screen push cx mov cx,4000h ; number of words to move push es ; save es push ds ; save ds mov es,di ; destination, set es to video memory mov ds,si ; source, set ds to video memory xor si,si ; clear offset fields xor di,di cld rep movsw ; copy from page [si] to page [di] pop ds ; recover ds pop es ; and other registers pop cx ret hgasr endp code ends end