NAME msyibm ; File MSYIBM.ASM ; edit history: ; Last edit: 5 Jan 1988 ; 5 Jan 1988 Restore cursor codes broken by Tek code additions. [jrd] ; 1 Jan 1988 version 2.30 ; 24 Dec 1987 Restore startup screen attributes at Kermit prompts. [jrd] ; 21 Dec 1987 Fix memory size sign problem for >640K systems. From Edgar Butt ; 4 Dec 1987 cleanup mode switching, add more Video 7 material. [jrd] ; 8 Nov 1987 Add EGA mode switching, from Terry Kennedy. ; 1 Nov 1987 Add support for Tektronix, based on work by Brian Holley. [jrd] ; 13 Oct 1987 Revise memory allocation sequence to avoid small holes. [jrd] ; 2 Oct 1987 Make log file character width match Set Display but 8 bits when ; debugging. [jrd] ; 12 Sept 1987 clarify sequence of translation and 8 bit display. [jrd] ; 27 Aug 1987 Do Translation before logging. [jrd] ; 18 Aug 1987 Change ESC to escape for MASM 4.5+ [jrd] ; 28 July 1987 Fix scron problem in screen save. [jrd] ; 16 June 1987 Remove global byte jwait (wait for vertical retrace), embedd ; code for proc scrwait in proc scroff. Replace calls for scrwait with ; calls to scron/scroff. Thanks to Dave Tweten (dt). [jrd] ; 11 June 1987 Add control of automatic screen roll back when new characters ; are to be displayed; default is off (no roll back). [jrd] ; 8 June 1987 Add keypad application mode tests to emit single chars. [jrd] ; 10 May 1987 Move input translation into terminal emulator, leave copy ; here for terminal type None, use mszibm byte anspflg to sense print ; screen is active, print translated characters but don't translate if ; debugging is active. [jrd] ; 28 March 1987 Make low_rgt screen coord word a global parameter. ; Add support for variable length screens and cursor size changes with ; EGA boards. Tests ok with 25, 35, 43, 50 lines with &/without MS Windows. ; EGA Memory locations 40:84H and 40:87H are used in this process. ; Use savadr dw as place to save screen: usually screen page 1 if screen ; dimensions are non-standard (80x25), else memory buffer scrsav. [jrd] ; 21 March 1987 Translate arriving Connect mode chars via table rxtable. [jrd] ; Add 132 Column support for Tseng Labs EVA board via procedure chgdsp, ; add restore scrolled screen before writing to it. From David L. Knoell [dlk] ; Modify msy and msz to use variable screen length and widths. [dlk] and [jrd] ; 17 March 1987 Reduce screen roll back buffer to half the memory to do the ; same number of screens. [jrd] ; 12 Jan 1987 Add keyboard translator, remove older code. [jrd] ; 1 Oct 1986 Version 2.29a public term, lclyini ; entry points public prtbout, prtnout, csrtype, scrmod, scrseg, scrsync public scroff, scron, atsclr, vtscru, vtscrd, scrloc, trnmod, telmsy public chgdsp, vtroll, crt_lins, crt_cols, getflgs, tv_mode ; action verb procedures for keyboard translator public uparrw, dnarrw, rtarr, lfarr, pf1, pf2, pf3, pf4 public kp0, kp1, kp2, kp3, kp4, kp5, kp6, kp7, kp8, kp9 public kpminus, kpcoma, kpenter, kpdot, chrout, cstatus, cquit public cquery, dmpscn, vtans52, vtinit, dnwpg, upwpg, endwnd, homwnd public upone, dnone, trnprs, dumpscr, modlin, modwrt, snull public klogon, klogof, cdos, chang public vtemu, crt_mode, scbattr, refresh, low_rgt ; data public savescr, restscr include mssdef.h ; some definitions ; hardware crt_status equ 3dah ; CGA crt status port disp_enb equ 8 ; CGA display enable bit crtmset equ 3D8H ; CGA CRT mode set port. screen equ 10h ; bios screen interrupt biostty equ 0eh ; Bios screen tty write mode modfrm struc ; format of mode (status) line db 'Esc-chr: ' ; do not write in last column. m_echr db 2 dup (?) db ' help: ' m_hlp db 2 dup (?) db '? port:' m_prt db 1 dup (?) db ' speed:' m_baud db 5 dup (?) db ' parity:' m_par db 4 dup (?) db ' echo:' m_echo db 3 dup (?) m_term db 13 dup (' ') ; 13 bytes for term type m_prn db 3 dup (' ') ; show PRN when printer is on modfrm ends datas segment public 'datas' extrn flags:byte, mar_top:byte, mar_bot:byte, portval:word extrn filtst:byte, dmpname:byte, kbdflg:byte, rxtable:byte extrn anspflg:byte, tekflg:byte ; stuff for screen routines yflags db ? ; status flags... flags1 db 0 ; internal flags (but used in mszibm). prtscr equ 1 ; print screen pressed inited equ 08h ; been here before... vtinited db 0 ; flag for emulator having been inited cursor dw ? esc_ch db ? parmsk db ? ; 8/7 bit parity mask, for reception argadr dw ? ; address of arg blk vid7id db 'VEGA BIOS Code, ' ; Video 7 Vega version string subset vid7len equ $-vid7id ; length of string atiwid db 'ATI EGA Wonder Bios,' ; ATI EGA wonder version string subset atilen equ $-atiwid ; length of string, inc terminator tsngid db 'Tseng' ; Tseng Labs EVA board tsnglen equ $-tsngid ega_mode db 0 ; non-zero if IBM EGA is in use. tvhere equ 0feh ; Topview active query tvsynch equ 0ffh ; Topview resynch request tv_segs dw ? ; Topview virtual screen, segment tv_sego dw ? ; and offset tv_mode db 0 ; flag, 0 = no Topview. savadr dw 2 dup (?) ; offset then segment of saved screen savflg dw ? ; low_rgt at time of screen save ; The following are used to turn the display back on (after scrolling etc.) msets db 2CH,28H,2DH,29H,2AH,2EH,1EH,29H vtemu emulst <> ; emulator flags ansflgs db 0 ; ANSI flags trmtyp db 0 ; most recent terminal type mtty db ' TTY ' ; no terminal type (mode line) lincur dw ? ; cursor type save area scbattr db ? ; Screen background attribute oldattr db ? ; screen attributes at init time curattr db ? ; current attribute temp dw ? ; scratch storage modtemp db 0 ; temp to hold Kermit modeline status captrtn dw ? ; routine to call for captured output dmphand dw ? ; screen dump file handle dumpbuf db 132 dup (?), cr, lf ; 134 byte dump work buffer dumpsep db FF,cr,lf ; screen image separators dmperr db ' Cannot open file to save screen to disk $' crlf db cr,lf,'$' ; some static data for mode line modbuf modfrm <> ; mode line buffer unkbaud db 'unkwn' ; must be 5 chars... baudn db ' 45.5',' 50 ',' 75 ',' 110 ','134.5',' 150 ',' 300 ',' 600 ' db ' 1200',' 1800',' 2000',' 2400',' 4800',' 9600','19200','38400' db '57.6K','115 K' baudnsiz equ 18 ; # of baud rates known (tbl size / 4) parnams db 'even','mark','none','odd ','spc ' lclmsg db 'loc' remmsg db 'rem' portno db ? ; storage for multi-window stuff swidth equ 80 ; max screen width slen equ 24 ; and length of text npages equ 10 ; # of pages of scrolling on each side crt_norm db ? ; video mode for normal screen crt_mode db ? ; video mode (typ 3, must be text) crt_cols db ? ; number of screen columns (typ 80) crt_lins db 24 ; number of screen rows - 1 (typ 24) low_rgt dw ? ; lower right corner of text window ; high = row address (typ 23) ; low = column address (typ 79) inipara dw ? ; initial paragraphs of scroll memory scrsav dw ? ; segment address of save area refresh db 0 ; screen refresh (0=wait for retrace) vtroll db 0 ; auto roll back allowed (0 = no). ; circular buffer for screen roll back. cbuf struc pp dw ? ; place ptr in buffer bend dw ? ; end of buffer orig dw ? ; buffer origin lcnt dw 0 ; # of lines in buffer. lmax dw ? ; max lines of buffer. cbuf ends twnd cbuf <> ; top screen spill-buffer struct bwnd cbuf <> ; bottom screen spill buffer struct datas ends code segment public 'code' extrn beep:near, prtchr:near, outchr:near, sbrk:near, pcwait:near extrn isfile:near, strlen:near, strcpy:near ; in mssfil extrn anstty:near,ansini:near,ansrei:near ; in mszibm extrn anstat:near,anskbi:near,ansdsl:near ; in mszibm extrn ans52t:near, vsinit:near ; in mszibm extrn msuinit:near, keybd:near ; in msuibm extrn tekini:near,tekcls:near,tekemu:near,tekend:near ;in msgibm assume cs:code, ds:datas, es:datas ; do initialization local to this module... ; Dynamically allocates 4000 bytes for screen save/restore buffer plus ; 320 to 38400 bytes for screen scroll back buffers. Tries to leave space ; for Command.com before enlarging buffers. [jrd] lclyini proc near call msuinit ; initialize keyboard module msuxxx mov ax,swidth*(slen+1)*2 ; (80 char + 80 attr) * 25 lines call sbrk ; memory allocation routine (mssker) ;if we get here them we have the lines mov scrsav,ax ; memory segment for save screens ; screen roll back buffers mov bx,0ffffh ; ask for all of memory, to get size mov ah,alloc ; allocate all of memory (must fail) int dos ; bx has # free paragraphs mov ax,bx ; ax has copy of number free paragraphs sub ax,24000D/16 ; space for Command.com copy #2 jbe lclyin1 ; be = not enough for it. [ebb] cmp ax,(swidth*slen+15)/16 ; minimum roll back space left over? jbe lclyin1 ; be = not even that much cmp ax,(swidth*slen*npages+7)/8 ; paragraphs wanted for roll back jbe lclyin2 ; be = enough but not more than needed mov ax,(swidth*slen*npages+7)/8 ; limit to our actual needs jmp short lclyin2 ; ask for all we really want lclyin1:mov ax,(4*swidth+15)/16 ; use minimum needed paragraphs lclyin2:mov inipara,ax ; save for later resizing of buffers mov cl,4 ; convert paragraphs to bytes shl ax,cl ; for sbrk call sbrk ; ask for that many bytes ;if we get here them we have the space mov bwnd.orig,ax ; memory segment, bottom window area mov twnd.orig,ax ; top. same place for both buffers! mov ax,inipara ; # paragraphs allocated by DOS mov cl,3 ; 2**3 = 8 shl ax,cl ; paragraphs to words (char + attrib) xor dx,dx ; clear extended size mov cx,swidth ; number of chars per line in buffer div cx ; ax = number of lines in buffer mov bwnd.lmax,ax ; max lines per buffer (quotient) mov twnd.lmax,ax ; max lines per buffer add cx,cx ; count char and attribute per item xor dx,dx ; clear extended numerator mul cx ; ax = effective # bytes per buffer dec ax ; adjust for counting from zero mov bwnd.bend,ax ; offset of last byte in buffer mov twnd.bend,ax ; offset of last byte in buffer mov bwnd.pp,0 ; offset of first byte in buffer mov twnd.pp,0 ; offset of first byte in buffer mov bwnd.lcnt,0 ; number of lines occupied in buffer mov twnd.lcnt,0 ; number of lines occupied in buffer call scrseg ; test running in an Environment call scrmod ; read video state, get crt_mode. mov al,crt_mode mov crt_norm,al ; save as normal mode mov ah,8 ; read current attributes xor bh,bh ; page 0 int screen mov scbattr,ah ; save video attributes mov oldattr,ah ; and here too call vsinit ; init terminal emulator module MSZ ret lclyini endp scrini proc near ; init screen stuff call scrmod ; get screen mode, low_rgt mov ah,3 ; get cursor position and char. xor bh,bh ; page 0 int screen mov lincur,cx ; save cursor type (scan line #'s) mov ax,low_rgt ; present screen text size cmp ax,savflg ; vs size of saved screen je scrin7 ; e = same and flags1,not(inited) ; different, reinit screen (no restore) and vtinited,not(inited) ; re-init emulator and clear rollback mov ax,inipara ; paragraphs allotted to roll back mov cl,3 ; 2**3 = 8 shl ax,cl ; paragraphs to words (char + attrib) xor dx,dx ; clear extended size mov cl,byte ptr low_rgt ; number of chars per line in buffer inc cl ; chars per line xor ch,ch ; clear high byte div cx ; ax = number of lines in buffer mov bwnd.lmax,ax ; max lines per buffer (quotient) mov twnd.lmax,ax ; max lines per buffer add cx,cx ; count char and attribute per item xor dx,dx ; clear extended numerator mul cx ; ax = effective # bytes per buffer dec ax ; adjust for counting from zero mov bwnd.bend,ax ; offset of last byte in buffer mov twnd.bend,ax ; offset of last byte in buffer mov bwnd.pp,0 ; offset of first byte in buffer mov twnd.pp,0 ; offset of first byte in buffer mov bwnd.lcnt,0 ; number of lines occupied in buffer mov twnd.lcnt,0 ; number of lines occupied in buffer scrin7: mov dx,cursor ; assume old cursor mov ega_mode,0 ; assume no EGA. 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? cmp cl,0cH ; Test reserved switch settings jge scrin6 ; ge = no EGA in use. push es 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? pop es jnz scrin6 ; nz = no mov ega_mode,1 ; yes, set flag to say so. mov crt_norm,3 ; assume color monitor is attached cmp bh,0 ; is color mode in effect? je scrin6 ; e = yes mov crt_norm,7 ; else use mode 7 for mono scrin6: test flags1,inited ; have we been here before? jnz scrin4 ; nz = yes, use old cursor mov ah,oldattr ; get init time attributes mov curattr,ah ; and set nice screen attribute mov scbattr,ah mov ah,3 ; figure out where cursor is xor bh,bh ; page 0 int screen ; read cursor position, in dx scrin4: cmp dh,byte ptr low_rgt+1 ; past logical end of screen? jb scrin2 ; b = no, keep going mov dh,byte ptr low_rgt+1 ; yes, just use lower right corner scrin2: cmp dl,byte ptr low_rgt ; maybe past right margin jb scrin3 ; b = no, use the way it is mov dl,byte ptr low_rgt scrin3: mov cursor,dx ; init cursor mov ah,2 ; set cursor position xor bh,bh ; page zero int screen ; set cursor in case it moved ret scrini endp ; Routine to initialize VT102/52/Heath-19 terminal emulator. vtinit proc near cmp flags.vtflg,0 ; doing emulation? je vtinix ; e = no cmp tekflg,0 ; Tek mode active? jne vtini2 ; ne = yes, do it's reinit or vtinited,inited call ansflg ; update ansi flags mov al,yflags ; Pass the flags. mov bx,argadr ; Get address of argument block mov dl,[bx].baudb ; Baud rate code in dl mov dh,[bx].parity ; Parity code in bits mov cl,4 ; 0-3 of dh shl dh,cl test flags.remflg,d8bit ; eight bit display? jnz vtini1 ; nz = yes or dh,07H ; Just say 7 data bits. call ansini ; call startup routine in mszibm. ret vtini1: or dh,8 ; say 8 bits call ansini vtinix: clc ret vtini2: call tekcls ; clear Tek screen clc ret vtinit endp argini proc near ; read passed arguments mov bx,argadr ; base of argument block mov al,[bx].flgs ; get flags and al,capt+emheath+havtt+trnctl+lclecho+modoff+lnwrap mov yflags,al ; mask for allowable and save mov al,[bx].prt mov portno,al ; update port number mov al,[bx].rows mov crt_lins,al ; init # of rows and cols mov ax,[bx].captr mov captrtn,ax ; buffer capture routine mov al,[bx].escc mov esc_ch,al mov parmsk,0ffh ; parity mask, assume parity = None cmp [bx].parity,parnon ; is parity None? je argini1 ; e = yes, keep all 8 bits mov parmsk,07fh ; else keep lower 7 bits argini1:ret ; that's it argini endp modlin proc near ; turn on mode line mov al,esc_ch mov modbuf.m_echr,' ' ; first char is initial space mov modbuf.m_hlp,' ' ; goes here too. cmp al,32 ; printable? jnb modl1 ; yes, keep going add al,40h ; made printable mov modbuf.m_echr,5eh ; caret, note control char mov modbuf.m_hlp,5eh modl1: mov modbuf.m_echr+1,al ; fill in character mov modbuf.m_hlp+1,al mov bx,argadr ; get argument block mov al,[bx].baudb ; get baud bits mov si,offset unkbaud ; assume unknown baud cmp al,baudnsiz ; too big? jnb modl2 ; nb = yes, use default mov cl,size m_baud ; each is 5 bytes long mul cl mov ah,0 add ax,offset baudn mov si,ax modl2: mov cx,size m_baud ; length of baud space mov di,offset modbuf.m_baud push es ; save es push ds pop es ; set es to datas segment cld rep movsb ; copy in baud rate mov al,[bx].parity ; get parity code mov cl,2 ; each is 4 bytes long... shl al,cl mov ah,0 add ax,offset parnams ; names of parity settings mov si,ax mov cx,4 ; each is 4 long mov di,offset modbuf.m_par rep movsb mov si,offset remmsg ; Assume remote echoing. test yflags,lclecho ; Is remote side echoing? jz modl4 ; Yes, keep going mov si,offset lclmsg ; Else it's local echoing. modl4: mov cx,3 ; size of on/off mov di,offset modbuf.m_echo rep movsb mov al,portno ; communications port cmp al,' ' ; binary (non-printable)? jae modl5 ; ae = no, ascii add al,'0' ; convert to ascii modl5: mov modbuf.m_prt,al ; fill in port number mov cx,8 ; blank out terminal id field mov si,offset mtty ; assume no terminal emulation. mov di,offset modbuf.m_term ; destination rep movsb ; copy it in. mov modbuf.m_prn,' ' ; assume not printing the screen mov modbuf.m_prn+1,' ' mov modbuf.m_prn+2,' ' test anspflg,prtscr ; doing a print the screen? jz modl5a ; z = no. mov modbuf.m_prn,'P' ; yes. display PRN at end of line mov modbuf.m_prn+1,'R' mov modbuf.m_prn+2,'N' modl5a: mov cx,size modfrm ; this is size of mode line mov si,offset modbuf ; mode line image pop es ; alternate entry to write an alternate mode line modwrt: push cx push si ; save mode line and size mov ah,3 ; read cursor position xor bx,bx ; screen page 0 int screen mov cursor,dx ; save cursor position call trmatt ; Get terminal attributes and ah,77h ; omit blinking/bold attributes mov bh,ah ; get video attribute mov dx,low_rgt ; right most column inc dh ; refer to status line mov ch,dh ; bottom line [dlk] mov cl,0 ; left col = 0 (first) [dlk] mov ax,600h ; scroll to clear the line int screen mov dh,byte ptr low_rgt+1 ; refer to status line inc dh xor dl,dl ; left most column mov bh,0 mov ah,2 ; set cursor position int screen pop si pop cx ; restore these cmp cl,crt_cols ; mode line longer than screen? jbe modl6 ; le = no mov cl,crt_cols ; else do just one line's worth dec cx ; don't let screen scroll modl6: cld lodsb ; get a byte mov ah,14 ; write to terminal mov bh,0 ; page 0 int screen loop modl6 ; write out entire mode line cmp flags.vtflg,0 ; emulating? je modl7 ; e = no and yflags,not modoff ; update local flags (mode line on) mov al,yflags ; Yes - update flags also call ansdsl ; get extras from emulator modl7: mov dx,cursor mov ah,2 mov bh,0 int screen ; put cursor back where it belongs ret ; and return modlin endp clrmod proc near ; clear mode line call trmatt ; Get terminal screen attributes mov bh,al ; Use screen background attribute mov ax,600h ; blank window mov dx,low_rgt ; right most column inc dh ; refer to status line mov cx,dx ; bottom line [dlk] xor cl,cl ; left most column int screen ; clear mode line ret ; and return clrmod endp ; Fetch screen attributes from emulator (if emulating). It exists mainly ; so that the reverse video will work. Returns the current mode ; line background attribute in ah, the current screen background in al, ; and the current "cursor" (foreground) attribute in bl. (Note: anstat ; returns status yflags in bh). trmatt proc near ; Get attributes cmp flags.vtflg,0 ; emulating? je trmat1 ; No, just do simple stuff. mov al,yflags ; anstat expects flags byte in al. call anstat ; Fetch emulator status/attributes ret trmat1: mov al,scbattr ; Background attributes. mov bl,curattr ; And cursor attribute. mov ah,al ; where modlin needs them and ah,77h ; get colors part, no blink/bold rol ah,1 ; reverse them rol ah,1 rol ah,1 rol ah,1 ret trmatt endp ; Get byte yflags of terminal emulator passed in AL. Used in mode line ; handling when 25th line is used by the emulator. [jrd] telmsy proc near mov yflags,al ; get the updated flags call ansflg ; and any other emulator info ret telmsy endp ;[IU2] This routine updates the ANSI status flags from the emulator, ; and passes the "yflags" byte to the VT100 emulator also. ansflg proc near push ax ; Save acs over call push bx mov al,yflags call anstat ; Get status and attributes mov ansflgs,bh ; Save. pop bx pop ax ret ansflg endp getflgs proc near ; supply yflags for terminal emulators mov al,yflags ret getflgs endp term proc near ; terminal mode entry point mov argadr,ax ; save argument ptr call argini ; init options from arg address call scrini ; init screen stuff test flags1,inited ; have we run yet? jz term1 ; z = no, so no saved screen yet call restscr ; restore screen term1: or flags1,inited ; remember we've run already. cmp flags.vtflg,0 ; current terminal type = None? je term3a ; e = yes, nothing to init. mov al,yflags ; tell emulator we are back cmp vtinited,inited ; inited emulator yet? je term3 ; e = yes cmp tekflg,0 ; Tek mode still active? jne term3a ; ne = yes, no re-init here call vtinit ; init it now jmp term3a term3: call ansrei ; reinit the emulator call ansflg ; and get its flags term3a: cmp flags.modflg,0 ; is mode line disabled? je term2a ; e = yes, disabled cmp flags.vtflg,0 ; emulating a terminal? jne term1a ; ne = yes, can have mode line cmp trmtyp,0 ; previous terminal type = none? jne term2 ; ne = no. need to clear mode line. jmp term2a ; yes, let 25th line be intact term1a: test yflags,modoff ; is mode line toggled off? jnz term2 ; nz = yes, clear the line. cmp flags.vtflg,tttek ; going to be a Tek terminal? je term2a ; e = yes, no mode line call modlin ; turn on mode line jmp term2a term2: call clrmod ; ensure its off term2a: mov al,flags.vtflg ; current terminal type mov trmtyp,al ; place to remember it til next time cmp flags.vtflg,tttek ; Tek mode? je term4 ; e = yes cmp tekflg,0 ; Tek mode active within DEC stuff? je lp ; e = no term4: call tekini ; reinit to get graphics screen lp: call portchr ; char at port? jnc chkinp ; nc = no, keep going nop call outtty ; print on terminal chkinp: call keybd ; call keyboard translator in msu jnc lp ; nc = no char or have processed it ; carry set = quit Connect mode. quit: call tekend ; [bjh] mov ah,3 ; get cursor position xor bh,bh ; page 0 int screen mov cursor,dx ; save position call savescr ; save screen cmp flags.vtflg,0 ; emulating? je quit1 ; e = no mov ax,0600h ; clear mode line with old attributes mov bh,oldattr ; attributes mov dx,low_rgt ; right most column inc dh ; refer to status line mov cx,dx ; bottom line [dlk] xor cl,cl ; left most column int screen ; clear the mode line quit1: mov ah,oldattr ; attributes at init time mov scbattr,ah ; background = original state ; for ega in non-standard # lines cmp ega_mode,0 ; ega board active? je quit2 ; e = no cmp byte ptr low_rgt+1,23 ; is screen standard length? je quit2 ; e = yes, so regular cursor set is ok push es ; turn off ega cursor emulation mov ax,40h ; byte 40:87H is ega Info byte mov es,ax push es:[87h] ; save info byte around call or byte ptr es:[87h],1 ; set emulation off (low bit = 1) mov cx,lincur ; cursor shape to set mov ah,1 ; set the shape int screen ; back to starting value pop es:[87h] ; recover original Info byte pop es ; and our work reg jmp short quit3 ; skip regular mode cursor setting quit2: ; for regular sized screen mov cx,lincur ; cursor type at startup mov ah,1 int screen ; restore cursor type quit3: mov ah,2 ; Position cursor mov bh,0 ; Page 0 mov dx,low_rgt ; bottom line inc dh ; status line position xor dl,dl ; left most column int screen ; Do it. mov al,yflags mov bx,argadr mov [bx].flgs,al ; update flags in arg block ret ; and return to caller term endp ; put the character in al to the screen outtty proc near cmp flags.vtflg,0 ; emulating a terminal? jne outnoc ; ne = yes, emulator handles printing test flags.remflg,d8bit ; keep 8 bits for displays? jnz outnp9 ; nz = yes, 8 bits if possible and al,7fh ; remove high bit outnp9: cmp rxtable+256,0 ; translation turned off? je outnp7 ; e = yes, no translation push bx mov bx,offset rxtable ; address of translate table xlatb ; new char is in al pop bx outnp7: test anspflg,prtscr ; should we be printing? jz outnop ; no, keep going push ax mov ah,lstout ; write to system printer device mov dl,al int dos pop ax jnc outnop ; nc = successful print push ax call beep ; else make a noise and call trnprs ; turn off printing pop ax outnop: test yflags,capt ; capturing output? jz outnoc ; no, forget this part push ax ; save char call captrtn ; give it captured character pop ax ; restore character and keep going outnoc: cmp tekflg,0 ; Tek mode active? jne outnp6 ; ne = yes, skip screen rolling cmp vtroll,0 ; auto roll back allowed? jz outnp6 ; z = no, leave screen as is. cmp bwnd.lcnt,0 ; is screen rolled back? [dlk] je outnp6 ; e = no call endwnd ; restore screen before writing [dlk] outnp6: cmp flags.vtflg,0 ; emulating a terminal? jnz outnop1 ; nz = yup, go do something smart test yflags,trnctl ; debug? if so use Bios tty mode jz outnp4 ; z = no mov ah,biostty ; Bios tty screen write cmp al,7fh ; Ascii Del char or greater? jb outnp1 ; b = no je outnp0 ; e = Del char push ax ; save the char mov al,7eh ; output a tilde for 8th bit int screen pop ax ; restore char and al,7fh ; strip high bit outnp0: cmp al,7fh ; is char now a DEL? jne outnp1 ; ne = no and al,3fH ; strip next highest bit (Del --> '?') jmp outnp2 ; send, preceded by caret outnp1: cmp al,' ' ; control char? jae outnp3 ; ae = no add al,'A'-1 ; make visible outnp2: push ax ; save char mov al,5eh ; caret int screen ; display it pop ax ; recover the non-printable char outnp3: int screen ret outnp4: cmp al,bell ; bell (Control G)? jne outnp5 ; ne = no jmp beep ; use short beep, avoid char loss. outnp5: mov dl,al ; write without intervention. mov ah,conout int dos ; else let dos display char ret ; and return outnop1:cmp flags.vtflg,tttek ; doing Tektronix emulation? je outnop2 ; e = yes, use Tek emulator cmp tekflg,0 ; Tek submode active? jne outnop2 ; ne = yes, use Tek emulator jmp anstty ; call terminal emulator routine & ret outnop2:jmp tekemu ; use Tek emulator and return outtty endp ;[IU2] Here to output character to port with no echo (like escape sequences ; sent by PF keys, responses to requests from the host, etc. It is ; wrong thinking to echo these). prtbout proc near ; Global routine now. mov ah,al ; This is where outchr expects it call outchr nop ; Ignore skip return. nop nop ret prtbout endp ;[IU2] Here to output an unsigned 8-bit number (in al) to the port without ; echoing. Used by terminal emulator escape sequence output. prtnout proc near mov bl,10 ; Output in base 10. jmp prtno2 ; Ensure at least a zero. prtno1: cmp al,0 jne prtno2 ; Yes - do more digits ret ; No - return from recursive call. prtno2: mov ah,0 ; Clear previous remainder. div bl ; Divide off a digit push ax ; Push remainder (in ah) on stack call prtno1 ; Recur. pop ax ; Pop off a digit add ah,'0' ; Make it ASCII call outchr ; send to port nop nop nop ret prtnout endp ; send the character in al out to the serial port; handle echoing. ; Can send an 8 bit char while displaying only 7 bits locally. outprt proc near test yflags,lclecho ; echoing? jz outpr1 ; z = no, forget it push ax ; save char call outtty ; print it pop ax ; restore outpr1: mov ah,al ; this is where outchr expects it call outchr ; output to the port nop nop nop ; skip returns... ret outprt endp ; returns with carry on if a character is available portchr proc near call prtchr ; character at port? jmp short portc1 ; yes, go handle nop ; skip return is stupid... clc ; no carry -> no character ret ; and return... portc1: and al,parmsk ; apply 8/7 bit parity mask stc ; have a character ret ; and return portchr endp ;;; Action routines (verbs) for keyboard translator KEYBD in msuibm. ; These are invoked by a jump instruction. Return carry clear for normal ; processing, return carry set for invoking Quit (kbdflg has transfer char). uparrw: mov al,'A' ; cursor keys jmp short comarr dnarrw: mov al,'B' jmp short comarr rtarr: mov al,'C' jmp short comarr lfarr: mov al,'D' comarr: push ax ; save final char mov al,escape ; Output an escape. call outprt ; Output, echo permitted cmp flags.vtflg,tttek ; Tek terminal? je comar0 ; e = yes, use VT100 codes cmp flags.vtflg,ttvt100 ; VT100 terminal emulation? jne comar2 ; No, do VT52/HEATH-19 sequence. comar0: call ansflg ; Update flags all around. mov al,'[' ; Maybe this next? test ansflgs,decckm ; Cursor key mode reset? je comar1 ; Yes, output the "[" mov al,'O' ; No, set, use the "O". comar1: call outprt ; Output it (echo permitted). comar2: pop ax ; recover final char call outprt ; Output to port (echo permitted) clc ret pf1: mov al,'P' ; keypad function keys 1-4 jmp short compf pf2: mov al,'Q' jmp short compf pf3: mov al,'R' jmp short compf pf4: mov al,'S' compf: push ax ; save final char mov al,escape ; Output an escape. call prtbout call ansflg ; get emulator flags test ansflgs,decanm ; ansi mode? jz short compf1 ; z = no mov al,'O' ; send an "O". call prtbout ; Output it. compf1: pop ax ; Get the saved char back call prtbout ; Output to port clc ret kp0: mov al,'p' ; keypad numeric keys jmp short comkp kp1: mov al,'q' jmp short comkp kp2: mov al,'r' jmp short comkp kp3: mov al,'s' jmp short comkp kp4: mov al,'t' jmp short comkp kp5: mov al,'u' jmp short comkp kp6: mov al,'v' jmp short comkp kp7: mov al,'w' jmp short comkp kp8: mov al,'x' jmp short comkp kp9: mov al,'y' jmp short comkp kpminus:mov al,'m' jmp short comkp kpcoma: mov al,'l' jmp short comkp kpenter:mov al,'M' jmp short comkp kpdot: mov al,'n' comkp: test ansflgs,deckpam ; keypad application mode active? jnz comkp3 ; nz = yes, use escape sequences sub al,40h ; deduct offset to numeric symbols jmp comkp0 ; and send that single char comkp3: push ax ; save final char mov al,escape ; Output an escape. call prtbout mov al,'O' ; Output the "O" cmp flags.vtflg,ttvt100 ; VT100 mode? je comkp1 ; e = yes, use "O" code cmp flags.vtflg,tttek ; Tek terminal je comkp1 ; e = yes, use VT100 codes test ansflgs,decanm ; ANSI (alt application keypad) mode? jnz comkp1 ; nz = yes, use "O" comkp2: mov al,'?' ; else use "?" instead of "O". comkp1: call prtbout pop ax ; recover final char comkp0: call prtbout ; send it clc ret klogon proc near ; resume logging (if any) test flags.capflg,logses ; session logging enabled? jz klogn ; z = no, forget it or argadr.flgs,capt ; turn on capture flag or yflags,capt ; set local msy flag as well call ansflg ; tell emulator klogn: clc ret klogon endp klogof proc near ; suspend logging (if any) and argadr.flgs,not capt ; stop capturing and yflags,not capt ; reset local msy flag as well call ansflg ; tell emulator klogo: clc ret klogof endp snull proc near ; send a null byte mov al,0 ; the null call prtbout ; send without logging and local echo clc ret snull endp ; general character out for emulator chrout: cmp flags.vtflg,0 ; emulating? je chrou5 ; e = no call anskbi ; Yes, say we had keyboard input. cmp al,cr ; A CR? jne chrou5 ; No - just output it and return call ansflg ; Yes - update VT100 flags test ansflgs,anslnm ; ANSI new-line mode set? jz chrou5 ; No - just send the cr call outprt ; Yes - output a carriage-return mov al,lf ; Followed by a line feed. chrou5: call outprt clc ret ; these commands invoke Quit cdos: mov al,'P' ; Push to DOS jmp short cmdcom cstatus:mov al,'S' ; Status jmp short cmdcom cquit: mov al,'C' ; Exit Connect mode jmp short cmdcom cquery: mov al,'?' ; Help jmp short cmdcom chang: mov al,'H' ; Hangup, drop DTR & RTS jmp short cmdcom cmdcom: mov kbdflg,al ; pass char to msster.asm via kbdflg stc ; signal that Quit is needed ret dmpscn proc near ; dump screen to file call savescr ; save screen to buffer call dumpscr ; do buffer to file clc ; do not exit Connect mode ret dmpscn endp ;[IU2] Routine to toggle VT100/VT52/Heath-19 modes in VT100 emulator. vtans52 proc near cmp flags.vtflg,0 ; emulating? je vtans5 ; e = no call ans52t ; Call MSZ toggle-it routine. call ansflg ; Update flags. clc ; clear c bit so don't exit Connect. vtans5: ret vtans52 endp ; Toggle Mode Line trnmod: cmp flags.modflg,0 ; is mode line enabled? je trnm2 ; e = no, don't touch it cmp flags.vtflg,tttek ; Tek mode? je trnm2 ; yes cmp tekflg,0 ; Tek submode? jne trnm2 ; ne = yes, no mode line changes test yflags,modoff ; mode line already off? jnz trnm1 ; yes, go turn on call clrmod ; no, clear mode line here or yflags,modoff ; turn on flag call ansflg ; Update flags all around. clc ; clear c bit so don't exit Connect ret ; and return trnm1: and yflags,not modoff ; Clear flag first. call modlin ; Then turn on mode line. call ansflg ; Update flags all around. trnm2: clc ret trnprs: push ax ; toggle ^ PrtSc screen to printer test anspflg,prtscr ; are we currently printing? jnz trnpr2 ; nz = yes, its on and going off mov ah,ioctl mov al,7 ; get output status of printer push bx mov bx,4 ; file handle for system printer int dos pop bx jc trnpr1 ; c = printer not ready cmp al,0ffh ; Ready status? je trnpr2 ; e = Ready trnpr1: call beep ; Not Ready, complain jmp trnpr3 ; and ignore request trnpr2: xor anspflg,prtscr ; flip the flag test yflags,modoff ; mode line off? jnz trnpr3 ; nz = yes call modlin ; else rewrite mode line trnpr3: pop ax clc ; return carry clear (don't quit) ret ;;;;; General screen management routines for IBM PC ; computes screen location to ax, given row and col in [dh,dl], resp. ; trashes dx scrloc proc near mov al,dh ; get row xor ah,ah ; clear ah mul crt_cols ; multiply by number of columns xor dh,dh ; clear row add ax,dx ; this is current position shl ax,1 ; double for attributes ret scrloc endp ; Routine to set cursor type. Pass cursor type in al: 0 = No cursor, ; 1 = Underline cursor, 2 = Block cursor. All cursors blink due to hardware. ; Routine frags any ac that video ints frag. ; For EGA boards running in non-25 line mode the cursor emulation is turned ; off during cursor shape changing and restored afterward. It's another ; ega Feature. [jrd] csrtype proc near push cx ; save the reg mov ah,1 ; Video fxn for set cursor type mov cx,0F00H ; Assume no cursor cmp al,0 ; No cursor? je csrty2 ; Right - set it and be done with it. cmp crt_mode,7 ; B&W card? je csrty3 ; Yes - different sizes mov cx,0607H ; No, use CGA underline cursor cmp al,2 ; Block? jne csrty2 ; No - set it now. csrty1: xor ch,ch ; Yes - make it a block csrty2: cmp ega_mode,0 ; ega board active? je csrty4 ; e = no cmp byte ptr low_rgt+1,23 ; standard screen length? je csrty4 ; e = yes, use regular cursor setting push es ; EGA. turn off cursor emulation mov ax,40h ; 40:87h is ega Info byte mov es,ax push es:[87h] ; save Info byte around call or byte ptr es:[87h],1 ; set emulation off (low bit = 1) mov ah,1 ; Video fxn for set cursor type int screen pop es:[87h] ; restore Info byte pop es ; and our work register pop cx ret csrty4: int screen ; regular cursor shape setting pop cx ret csrty3: mov cx,0B0CH ; Assume B&W underline cursor cmp al,2 ; Block? jne csrty2 ; No - set it now. jmp csrty1 ; Yes - make it a block csrtype endp ; Save the entire screen in a buffer so we can restore and/or dump it. ; Saves regular (80x25) screens to memory buffer scrsav and other sized ; screens to video memory page 1. Resultant save place put into savadr ; (offset then segment) and current low_rgt size info in savflg. Note, ; some Environments (TopView/Windows etc) may not permit use of page 1. [jrd] savescr proc near push es push ds push ax push cx push si push di call scrseg ; get screen segment in ax and es:di push ax ; save screen segment mov si,0 mov di,scrsav ; place to put screen (memory buff) mov savadr+2,di ; working seg address for restore mov savadr,0 ; and no offset for memory buffer call scrmod ; ascertain video mode and screen mov ax,low_rgt ; text screen lower right (typ 23,79) mov savflg,ax ; save it for screen restore inc al ; number of columns add ah,2 ; plus status line = number of rows cmp al,swidth ; same as preset screen space (80)? ja savsc1 ; a = no, use screen video page 1 cmp ah,slen+1 ; same as preset screen length (24)? je savsc3 ; e = yes, use our memory buffer savsc1: mul ah ; times rows = characters on screen shl ax,1 ; times two for attributes = page 1 mov cx,ax ; cx = working copy of screen size and cx,000fh ; get lower four bits for offset part mov savadr,cx ; save offset in this word mov cl,4 shr ax,cl ; compute number of paragraphs pop di ; source screen address push di ; restore again add di,ax ; add paragraphs, point di to page 1 mov savadr+2,di ; and save segment in this word savsc3: mov es,savadr+2 ; segment of storage area mov di,savadr ; offset of same mov ax,low_rgt ; lower right of text screen inc al ; number of columns on screen add ah,2 ; number of rows on screen mul ah ; number of characters on the screen mov cx,ax ; save this in counter cx call scroff ; turn off screen [dt] pop ds ; address screen cld rep movsw ; save the screen pop di pop si pop cx pop ax pop ds ; restore this call scron ; turn on screen [dt] pop es ret savescr endp ; restore screen from buffer (offset and seg in savadr, text coord in savflg). ; Restores all screen lines. [jrd] restscr proc near push es mov ax,savflg ; saved low_rgt text screen coord add ah,2 ; number of screen lines inc al ; number of screen columns mul ah ; columns time lines = # characters mov cx,ax ; save this in counter cx push cx ; save count call scrseg ; get address of screen in es:di call scroff ; turn off screen [dt] push ds ; save original data segment mov si,savadr ; offset of storage area push savadr+2 ; segment of same pop ds ; put storage segment into ds cld rep movsw ; restore data to screen pop ds ; recover original data segment call scron ; turn on screen [dt] pop cx ; recover count call scrsync ; synch Topview with new screen pop es ret restscr endp ; Save the screen to a buffer and then append buffer to a disk file. [jrd] ; Default filename is Kermit.scn; actual file can be a device too. Filename ; is determined by mssset and is passed as pointer dmpname. ; Dumpscr reads the screen image saved by savescr so call savescr call first. dumpscr proc near push ax push bx push cx push dx mov dmphand,-1 ; preset illegal handle mov dx,offset dmpname ; name of disk file, from mssset mov ax,dx ; where isfile wants name ptr call isfile ; what kind of file is this? jc dmp5 ; c = no such file, create it test byte ptr filtst.dta+21,1fh ; file attributes, ok to write? jnz dmp0 ; nz = no. mov al,1 ; writing mov ah,open2 ; open existing file int dos jc dmp0 ; c = failure mov dmphand,ax ; save file handle mov bx,ax ; need handle here mov cx,0ffffh ; setup file pointer mov dx,-1 ; and offset mov al,2 ; move to eof minus one byte mov ah,lseek ; seek the end int dos jmp dmp1 dmp5: test filtst.fstat,80h ; access problem? jnz dmp0 ; nz = yes mov ah,creat2 ; file did not exist mov cx,20h ; attributes, archive bit int dos mov dmphand,ax ; save file handle jnc dmp1 ; nc = ok dmp0: mov ah,3 ; get cursor position xor bx,bx ; page 0 int screen push dx ; save it mov dh,byte ptr low_rgt+1 ; go to status line inc dh xor dl,dl ; left most column mov ah,2 ; position cursor int screen mov dx,offset dmperr ; say no can do mov ah,prstr int dos pop dx ; get original cursor position mov ah,2 ; position cursor xor bx,bx ; page 0 int screen pop dx pop cx pop bx pop ax clc ret dmp1: mov ah,ioctl ; is destination ready for output? mov al,7 ; test output status mov bx,dmphand ; handle int dos jc dmp0 ; c = error cmp al,0ffh ; ready? jne dmp0 ; ne = not ready. push di ; read screen buffer, write lines push si push es mov cl,byte ptr low_rgt+1 ; number of lines - 2 add cl,2 ; number of line on screen xor ch,ch mov si,savadr ; offset in storage area dmp2: push cx ; save outer loop counter mov es,savadr+2 ; get storage segment mov di,offset dumpbuf ; data segment memory mov cl,byte ptr savflg ; number of columns on screen - 1 inc cl ; number of columns on screen xor ch,ch dmp3: mov ax,word ptr es:[si] ; read char + attribute mov byte ptr [di],al ; store just char, don't use es: inc si ; update pointers inc si inc di loop dmp3 ; do for each column std ; set scan backward mov cl,byte ptr savflg ; number of columns on screen - 1 inc cl ; number of columns on screen xor ch,ch push es mov ax,ds mov es,ax ; set es to data segment for es:di mov di,offset dumpbuf ; start of line add di,cx ; plus length of line dec di ; minus 1 equals end of line mov al,' ' ; thing to scan over repe scasb ; scan until non-space cld ; set direction forward pop es jz dmp3a ; z = all spaces inc cx inc di dmp3a: mov word ptr [di+1],0A0Dh ; append cr/lf add cx,2 ; line count + cr/lf mov dx,offset dumpbuf ; array to be written mov bx,dmphand ; need file handle mov ah,write2 ; write the line int dos pop cx ; get line counter again jc dmp3b ; c = error loop dmp2 ; do next line mov dx,offset dumpsep ; put in formfeed/cr/lf mov cx,3 ; three bytes overall mov ah,write2 ; write them dmp3b: mov bx,dmphand ; file handle int dos mov ah,close2 ; close the file now int dos dmp6: pop es pop si pop di pop dx pop cx pop bx pop ax clc ret dumpscr endp ; Get CRT mode - returns mode in variable crt_mode, ; updates crt_cols and low_rgt. ; For EGA active it looks in Bios work memory 40:84H for number of rows. [jrd] scrmod proc near push ax push dx mov ah,15 ; Get current video state. int screen mov crt_mode,al ; Store CRT mode value. mov crt_cols,ah ; store # of cols mov dl,ah ; # of cols again mov dh,crt_lins ; and # of rows (constant from msster) cmp ega_mode,0 ; ega active? je scrmod4 ; e = no push es ; yes, permit different lengths mov ax,40h ; refer to 40:84h for # ega rows mov es,ax mov ah,es:[84h] ; get number of rows - 1 (typ 24) cmp ah,20 ; less than 20 rows? jb scrmod3 ; b = yes, ignore this length cmp ah,80 ; more than 80 rows? ja scrmod3 ; a = yes, ignore this length mov dh,ah ; use this length mov crt_lins,dh ; update our working constant scrmod3:pop es scrmod4: dec dl ; max text column, count from zero dec dh ; max text row, count from zero mov low_rgt,dx ; save away window address pop dx pop ax ret ; And return. scrmod endp ; Get screen segment - returns screen segment in ax, and full address in es:di scrseg proc near xor di,di ; start at beginning of screen (0,0) mov ax,0B000H ; Assume B&W card.. cmp crt_mode,7 ; Is it? je scrse1 ; e = yes mov ax,0B800H ; No - video memory is here on color cmp crt_mode,12 ; graphics set? jb scrse1 ; b = no mov ax,0A000H ; graphics scrse1: mov es,ax ; tell Topview our hardware address needs mov tv_segs,es ; save our hardware screen address mov tv_sego,di ; segment and offset form mov tv_mode,1 ; assume we're running under Topview mov ah,tvhere ; query Topview for its presence int screen mov ax,es ; get its new segment for screen work cmp ax,tv_segs ; same as hardware? jne scrse2 ; ne = no, we are being mapped cmp di,tv_sego ; check this too. jne scrse2 ; ne = no too. Use TV's work buf as screen. mov tv_mode,0 ; else no Topview or no mapping. scrse2: ret scrseg endp ; Synchronize a Topview provided virtual screen buffer with the image ; seen by the user. Requires cx = number of words written to screen ; (char & attribute bytes) and es:di = ENDING address of screen write. ; Changes ax and di. scrsync proc near cmp tv_mode,0 ; Topview mode active? je scrsyn1 ; e = no, skip DOS call below sub di,cx ; backup to start byte (cx = words) sub di,cx ; after storing words to screen mov ah,tvsynch ; tell Topview we have changed screen int screen ; so user sees updated screen scrsyn1:ret scrsync endp ; The following two routines are used to turn off the display while we ; are reading or writing the screen in one of the color card modes. ; Turn screen off for (known) color card modes only. All regs preserved. ; Includes code for old procedure scrwait. 16 June 1987 [jrd] scroff proc near cmp refresh,0 ; slow refresh? jne scrofx ; ne = no wait cmp ega_mode,0 ; Extended Graphics Adapter in use? jne scrofx ; ne = yes, no waiting. cmp tv_mode,0 ; Topview mode? jne scrofx ; ne = yes, no waiting cmp crt_mode,7 ; B&W card? jnb scrofx ; Yes - just return. push ax ; Save ax and dx. push dx mov dx,crt_status ; CGA: Wait for vertical retrace scrof1: in al,dx test al,disp_enb ; display enabled? jnz scrof1 ; yes, keep waiting scrof2: in al,dx test al,disp_enb ; now wait for it to go off jz scrof2 ; so can have whole cycle mov dx,crtmset ; Output to CRT mode set port. mov al,25H ; This shuts down the display out dx,al ; Dumb, but card is too.. pop dx ; Restore acs. pop ax scrofx: ret ; And return. scroff endp ; Turn screen on for (known) color card modes only ; All registers are preserved. scron proc near cmp refresh,0 ; slow refresh? jne scronx ; ne = no wait cmp ega_mode,0 ; Extended Graphics Adapter in use? jne scronx ; ne = yes, no waiting. cmp tv_mode,0 ; Topview mode? jne scronx ; ne = yes, no waiting cmp crt_mode,7 ; B&W card? jnb scronx ; Yes - just return. push ax ; Save ax, dx, and si push dx push si mov al,crt_mode ; Convert crt_mode to a word xor ah,ah mov si,ax ; Get it in a usable register mov al,msets[si] ; Fetch the modeset byte mov dx,crtmset ; This port out dx,al ; Flash it back on pop si ; Restore acs. pop dx pop ax scronx: ret ; And return. scron endp ; Screen clearing routine. [IU] ; ; Call: ax/ coordinates of first screen location to be cleared. ; bx/ coordinates of last location to be cleared. ; Coord: ah = row [0-24], al = column [0-79]. Preserves all registers. [jrd] atsclr: push ax ; Save some acs push cx push dx mov dx,bx ; Compute last screen offset in ax push ax call scrmod ; update column length pop ax ; scrmod zaps ax push ax call scrloc ; get screen start address in ax mov cx,ax ; Save it in cx for a minute pop dx ; Compute first screen offset in ax call scrloc sub cx,ax ; Compute number of locs to clear... add cx,2 sar cx,1 ; Make byte count a word count jle atscl2 ; If nothing to clear, then vamos. push di ; Save some more acs push es ; save es push ax ; save around call call scrseg ; Get address of screen in ax, es:di pop ax ; recover displacement add di,ax ; displacement memory address mov ah,scbattr ; Use current screen background attr. mov al,' ' ; Use space for fill mov dl,byte ptr low_rgt ; line length - 1 inc dl ; line length xor dh,dh cmp cx,dx ; Blanking a line or less?? jg atscl1 ; No - make scroff disable display atscl1: call scroff ; Turn screen off if color card. push cx ; save word count for Topview cld rep stosw ; Blit... (excuse PDP-10ese please) pop cx ; recover word count call scrsync ; synch Topview call scron ; Turn screen back on if color card. pop es ; Restore segment register pop di ; And destination index atscl2: pop dx ; restore regs pop cx pop ax ret ; Scrolling routines. vtscru scrolls up one row, vtscrd scrolls down one ; row. atsprep is called before scrolling up to save the top line in the ; circular buffer. All registers are preserved. ; Screen-roll down. Move text down one line, for terminal emulator only. vtscrd: push ax ; Upgraded by [jrd] push bx push cx push dx mov ax,701H ; scroll down one line mov ch,mar_top ; top margin line mov cl,0 ; left most column mov dh,mar_bot ; bottom margin line mov dl,byte ptr low_rgt ; right most column mov bh,scbattr ; attributes int screen ; scroll it down pop dx pop cx pop bx pop ax clc ret ; worker routine for vtscru/d atsprep:push es ; upgraded from older version [jrd] call scroff ; turn off color screen call scrseg ; get display address in es:di mov si,di ; si will be source mov bx,offset twnd ; this is where it goes call putcirc ; put screen line in circular buffer pop es ; and that call scron ; turn on screen again ret ; and return ; Screen scroll up one line (text moves up) for terminal emulator use. vtscru: push ax ; Upgraded by [jrd] push bx push cx push dx push si push di cmp mar_top,0 ; scrolling the top screen line? ja scru1 ; a = no. don't save anything call atsprep ; save top line scru1: mov ax,601H ; scroll up one line mov dh,mar_bot ; bottom row mov dl,byte ptr low_rgt ; right most column mov ch,mar_top ; top row of scrolling region mov cl,0 ; left most column mov bh,scbattr ; background attributes int screen ; scroll up that region pop di ; Restore the rest of the regs. pop si pop dx pop cx pop bx pop ax clc ret ; And return ;screen text roll up, version for manual scrolling only mscru: push ax ; Upgraded by [jrd] push bx push cx push dx push si push di cmp bwnd.lcnt,0 ; any lines in bottom window? je mscru2 ; e = no, so ignore request call atsprep ; save top line mscru1: mov ax,601H ; scroll up one line mov dx,low_rgt ; lower right corner xor cx,cx ; top row of scrolling region mov bh,scbattr ; background attributes int screen ; scroll up that region call scroff mov dx,low_rgt mov dl,0 ; location is lower left corner call scrloc ; get count from display start push es push ax ; save count call scrseg ; get screen's segment into ax, es:di pop ax ; recover count add di,ax ; destination memory address (es:di) mov bx,offset bwnd ; source of lines call getcirc ; get line from circ buf to screen pop es ; restore es call scron ; turn on the screen mscru2: pop di ; Restore the rest of the regs. pop si pop dx pop cx pop bx pop ax ret ; prep for screen scroll down. ; copies bottom scroll line from screen to bottom window buffer. ; destroys ax,cx,dx,si,di. getbot proc near ; Upgraded from old version [jrd] push es call scroff ; turn off screen mov dx,low_rgt ; from screen location, row mov dl,0 ; starting in col 0 call scrseg ; get adaptor's offset into es:di call scrloc ; get offset in display buffer in ax add di,ax ; source addr in display buffer es:di mov si,di ; screen is source (si) mov bx,offset bwnd ; buffer to use (bottom window) call putcirc ; copy bottom screen line to circ buf pop es call scron ; turn on display again ret getbot endp ;screen text scroll down, for manual mode only mscrd: push ax ; Upgraded by [jrd] push bx push cx push dx push si push di cmp twnd.lcnt,0 ; any lines left in top window? je mscrd1 ; e = no, ingore request call getbot ; fetch bottom line from screen mov ax,701H ; scroll down one line xor cx,cx ; top left corner mov dx,low_rgt ; bottom right corner mov bh,scbattr ; attributes int screen ; scroll it down call scroff ; turn off display push es call scrseg ; get segment address of screen mov bx,offset twnd ; buffer to use (top window) call getcirc ; copy from circ buf to screen pop es call scron ; turn on display again mscrd1: pop di ; Restore the rest of the ACs. pop si pop dx pop cx pop bx pop ax ret ; move viewing window down as much as possible (text moves up) endwnd proc near ; go to end of scrolling text push cx mov cx,bwnd.lcnt ; all bottom window lines [dlk] jmp dnwp0 ; and enter dwnpg endwnd endp dnone proc near ; move text up one line [jrd] push cx mov cx,1 jmp dnwp0 dnone endp ; scroll viewing window down (text moves up) one page (24 lines) dnwpg proc near push cx mov cl,byte ptr low_rgt+1 ; number of rows, excl status inc cl ; count from 1, not 0 mov ch,0 dnwp0: ; additional entry point cmp bwnd.lcnt,cx ; enough lines in bottom line buffer? jge dnwp1 ; ge = we have that many lines stored mov cx,bwnd.lcnt ; do as many as we have dnwp1: jcxz dnwp2 ; z = nothing to do cmp tekflg,0 ; Tek mode active? jne dnwp2 ; ne = yes, no scrolling call mscru ; scroll up text one line loop dnwp1 dnwp2: pop cx clc ret dnwpg endp ; home viewing window homwnd proc near push cx mov cx,twnd.lcnt ; all top window lines [dlk] jmp upwp0 ; join upwpg homwnd endp upone proc near ; move text down one line [jrd] push cx mov cx,1 jmp upwp0 upone endp ; scroll viewing window up (text moves down) a page (24 lines) upwpg proc near push cx mov cl,byte ptr low_rgt+1 ; number of rows, excl status line inc cl ; count from 1, not 0 mov ch,0 upwp0: ; additional entry point cmp twnd.lcnt,cx ; enough lines in top line buffer? jae upwp1 ; ae = at least as many as requested mov cx,twnd.lcnt ; do only as many as are stored. upwp1: jcxz upwp2 ; z = no lines to scroll cmp tekflg,0 ; Tek mode active? jne upwp2 ; ne = yes, no scrolling call mscrd ; roll down text one line loop upwp1 upwp2: pop cx clc ret upwpg endp ; Put a line into the circular buffer. Pass the buffer structure in bx. ; Source is tv_segs:si which is the current screen address. ; Rewritten by [jrd] putcirc proc near push es mov cl,crt_cols ; number of columns xor ch,ch mov es,[bx].orig ; get segment of memory area cmp bx,offset bwnd ; bottom buffer? je putci6 ; e = yes mov di,twnd.pp ; pick up buffer ptr (offset from es) add di,cx ; increment to next available slot add di,cx ; char and attribute cmp di,twnd.bend ; would line extend beyond buffer? jb putci1 ; b = not beyond end mov di,0 ; else start at the beginning putci1: mov twnd.pp,di ; update ptr cld ; set direction to forward push ds ; save regular datas seg reg mov ds,tv_segs ; use screen segment for ds:si rep movsw ; copy into buffer pop ds ; restore regular datas segment mov cx,twnd.lmax ; line capacity of buffer dec cx ; minus one work space line cmp twnd.lcnt,cx ; can we increment line count? jae putci1b ; ae = no, keep going inc twnd.lcnt ; else count this line putci1b:cmp bwnd.lcnt,0 ; any lines in bottom buffer? je putci2 ; e = no mov cx,bwnd.pp ; see if we overlap bot buf cmp cx,twnd.pp ; is this line in bot buf area? jne putci2 ; ne = no add cl,crt_cols ; move bottom pointer one slot earlier adc ch,0 add cl,crt_cols ; words adc ch,0 cmp cx,bwnd.bend ; beyond end of buffer? jb putci1a ; b = no mov cx,0 ; yes, start at beginning of buffer putci1a:mov bwnd.pp,cx ; new bottom pointer dec bwnd.lcnt ; one less line in bottom buffer putci2: pop es ret putci6: ; bottom buffer add cx,cx ; words worth cmp bwnd.lcnt,0 ; any lines in the buffer yet? jne putci7 ; ne = yes mov di,twnd.pp ; get latest used slot of top buff add di,cx ; where first free (?) slot starts cmp di,bwnd.bend ; are we now beyond the buffer? jb putci6a ; b = no mov di,0 ; yes, start at beginning of buffer putci6a:add di,cx ; start of second free (?) slot cmp di,bwnd.bend ; are we now beyond the buffer? jb putci6b ; b = no mov di,0 ; yes, start at beginning of buffer putci6b:mov cx,twnd.lmax ; buffer line capacity sub cx,twnd.lcnt ; minus number used by top buffer sub cx,2 ; minus one work slot and one we need cmp cx,0 ; overused some slots? jge putci8 ; ge = enough to share add twnd.lcnt,cx ; steal these from top window beginning jmp short putci8 putci7: mov es,bwnd.orig ; get segment of memory area mov di,bwnd.pp ; pick up buffer ptr (offset from es) cmp di,0 ; would line start before buffer? jne putci7a ; ne = after start of buffer mov di,bwnd.bend ; else start at the end minus one slot inc di putci7a:sub di,cx putci8: mov bwnd.pp,di ; update ptr (this is latest used slot) mov cl,crt_cols xor ch,ch cld ; set direction to forward push ds ; save regular datas seg reg mov ds,tv_segs ; use screen segment for ds:si rep movsw ; copy into buffer pop ds ; restore regular datas segment mov cx,bwnd.lmax ; line capacity of buffer cmp bwnd.lcnt,cx ; can we increment line count? jae putci8b ; ae = no, keep going inc bwnd.lcnt ; else count this line putci8b:cmp twnd.lcnt,0 ; any lines in top line buf? je putci9 ; e = no mov cx,twnd.pp ; yes, see if we used last top line cmp cx,bwnd.pp ; where we just wrote jne putci9 ; not same place, so all is well dec twnd.lcnt ; one less line in top window cmp cx,0 ; currently at start of buffer? jne putci8a ; ne = no mov cx,twnd.bend ; yes inc cx putci8a:sub cl,crt_cols ; back up top window sbb ch,0 sub cl,crt_cols ; by one line sbb ch,0 mov twnd.pp,cx ; next place to read putci9: pop es ret putcirc endp ; Get a line from the circular buffer, removing it from the buffer. ; returns with carry on if the buffer is empty. ; Pass the buffer structure in bx. ; Destination preset in es:di which is the current screen address. ; Rewritten by [jrd] getcirc proc near cmp [bx].lcnt,0 ; any lines in buffer? jne getci1 ; ne = yes, ok to take one out. stc ; else set carry ret ; and return getci1: ; top and bottom window common code mov cl,crt_cols ; # of chars to copy xor ch,ch push cx ; save around calls mov si,[bx].pp ; this is source cld ; set direction to forward push ds ; save original ds mov ds,[bx].orig ; use seg address of buffer for si rep movsw pop ds ; recover original data segment pop cx ; length for Topview push cx ; save again call scrsync ; synch Topview mov si,[bx].pp ; get ptr again pop cx add cx,cx ; words cmp bx,offset bwnd ; bottom window? je getci6 ; e = yes sub si,cx ; top window, move back jnc getcir2 ; nc = still in buffer, continue mov si,twnd.bend ; else use end of buffer sub si,cx ; minus length of a piece inc si getcir2:mov twnd.pp,si ; update ptr dec twnd.lcnt ; decrement # of lines in buffer clc ; make sure no carry ret getci6: ; bottom window add si,cx ; words, move back (bot buf = reverse) cmp si,bwnd.bend ; still in buffer? jb getci7 ; b = yes mov si,0 ; else use beginning of buffer getci7: mov bwnd.pp,si ; update ptr dec bwnd.lcnt ; decrement # of lines in buffer clc ; make sure no carry ret getcirc endp ; ; CHKDSP - procedure to check for hardware support of 132 cols [dlk] ; ; Supported hardware: EVA board from Tseng Labs w/132-col kit installed ; Video 7 Vega Deluxe w/ 132X25.COM driver installed [tmk] ; ATI EGA Wonder ; ; The routine checks for the presence of a 132-column-capable adapter. If ; one is found, its handler returns the proper vide mode in [CX]. The main- ; line code then moves this to [AX] and issues the video interrupt. ; chgdsp proc near push es ; save all we use push ax push bx push cx push dx push si push di mov temp,ax ; save set/reset flag from msz mov bx,portval ; get flow control around mode sets mov bx,[bx].flowc ; bh=xon, bl=xoff, or both nulls mov byte ptr temp+1,bh ; save xon or null here cmp bl,0 ; no flow control? je chgds0 ; e = none mov ah,bl ; get xoff call outchr ; send it nop nop nop mov ax,100 ; wait 100 millisec for mode to finish call pcwait chgds0: call ckteva ; try for Tseng Labs EVA jnc chgds1 ; nc = found call ckv7vd ; try for Video 7 Vega Deluxe jnc chgds1 ; nc = found call ckatiw ; try for ATI EGA Wonder jnc chgds1 ; nc = found jmp chgdsx ; if not, exit ; chgds1: mov ax,cx ; get returned value in proper reg int screen ; call the bios call scrini ; reset parameters cmp flags.modflg,0 ; is it enabled je chgdsx ; e=not allowed test yflags,modoff ; is mode line toggled off jnz chgdsx ; nz=yes its off so ignore it call modlin ; make mode visible chgdsx: cmp byte ptr temp+1,0 ; no flow control? je chgdsx1 ; e = none mov ah,byte ptr temp+1 ; get xon call outchr ; send it nop nop nop chgdsx1:pop di ; restore what we saved pop si pop dx pop cx pop bx pop ax pop es ret ; return to caller chgdsp endp ; Individual tests for various 132-column boards ; ; Tseng LABS EVA ckteva: mov ax,0c000h ; seg addr for eva mov es,ax ; set into es register mov di,76h ; offset of board's string lea si,tsngid ; validation string mov cx,tsnglen ; length of validiation string cld repe cmpsb ; compare strings jne chnoad ; ne = strings differ ; ; an EVA board - check for 132 col kit cmp byte ptr es:099h,0 ; check 132 col kit installed je chnoad ; e=0=not installed jmp catfnd ; do the mode change chnoad: stc ; indicate adapter not present ret ; and exit ; ; ATI EGA Wonder ckatiw: mov ax,0c000h ; seg addr for EGA Wonder mov es,ax ; set into es register mov di,012fh ; offset of message in ROM lea si,atiwid ; offset of message here mov cx,atilen ; length of validation string cld repe cmpsb ; compare strings jne chnoad ; ne = strings differ ; catfnd: mov cx,0003h ; prepare to reset video mode cmp byte ptr temp,0 ; are we setting or resetting? je ckexit ; e is reset, exit mov cx,0023h ; set to 132 cols (Set Mode 23H) ckexit: clc ; carry clear means found ret ; ; Video 7 Vega Deluxe ckv7vd: mov ax,0c000h ; seg addr for Vega rom bios mov es,ax ; set into es register mov di,002ah ; offset of message in ROM lea si,vid7id ; offset of message here mov cx,vid7len cld repe cmpsb ; compare strings jne chnoad ; ne = strings are different ; test byte ptr es:[03ffeh],1 ; is this a 'Deluxe' Vega? jz chnoad ; z = nope, can't do it mov ah,35h ; DOS Get Vector mov al,10h ; Bios video interrupt int dos ; get it into es:bx mov di,bx ; es:bx is returned int 10h entry pnt sub di,5ah ; back offset to msg in 132X25.COM lea si,vid7id ; offset of validation message mov cx,vid7len ; length of validation string cld cnv7fn1:repe cmpsb ; Look for repeat of msg by 132X25.COM jne cnv7fn2 ; if different mov cl,crt_mode ; prepare to reset video mode mov ch,0 cmp byte ptr temp,0 ; are we setting or resetting? je ckexit ; e is reset, exit mov cx,0000h ; set to 132 cols (old 40x25) jmp short ckexit ; and exit cnv7fn2:mov ax,6f00h ; check for VegaBios driver int screen ; run by ESU.EXE cmp bx,'V7' ; Video 7 Bios presence response jne chnoad ; ne = not there mov ax,6f01h ; al gets monitor type (mono,color,ega) int screen mov bx,51 ; presume mono 132x25, page 0 cmp al,2 ; 1=mono, 2=color, above=ega jb cnv7fn3 ; b = mono mov bx,4fh ; presume med res color 132x25 je cnv7fn3 ; e = med res color mov bx,41h ; ega high res 132x25 cnv7fn3:push bx mov ah,0eh ; get current mode int screen mov ax,6f05h ; set special mode found in bl cmp byte ptr temp,0 ; resetting to 80 column mode? jne cnv7fn4 ; ne = no, setting 132x25 mov al,crt_norm ; get normal mode mov ah,0 ; set mode cnv7fn4:pop bx ; recover special mode int screen mov cx,0f00h ; a nop screen bios command clc ret ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. RSKP PROC NEAR pop bp add bp,3 push bp ret RSKP ENDP ; Jumping here is the same as a ret. R PROC NEAR ret R ENDP code ends if1 %out [End of pass 1] else %out [End of assembly] endif end