NAME msy55x ; File MSY55X.ASM ; edit history: ; Edit msyibm to produce Sanyo version 8 July 1986 [rwb] ; [2.29] code frozen on 6 May 1986 [jrd] ; Add VT100 terminal emulation from James Harvey at I.U. Purdue ; Move Heath-19 code into that emulation (in module mszibm). ; Revise dynamic memory allocation to obey DOS's rules; use sbrk in mssker. ; Incorporate (limited) support for TopView and Windows in screen handling. ; Revise screen scrolling routines. ; Add functionality for "Del" key to produce ascii Delete code. ; Improve display under debug mode. ; Communicate with emulator module mszibm through global sturcture vtemu.xxx, ; data variables mar_top, mar_bot (screen line numbers for scrolling), ; jwait (wait for screen retrace), scbattr (screen background attributes), ; and several global procedures. Module mszibm is initialized by calling ; vsinit at the completion of initializing this module. ; Do much (but never enough) general cleanup of code. ; Add test for IBM EGA, from C. Kim. If present then don't wait for display ; retrace. ; Add test for running under IBM PC Netbios. If so we lose some info on ; keyboard scan codes (no mode line toggle, Backspace key = backspace). ; Global byte pcnet is non-zero if Netbios is in use. MSXIBM needs pcnet. ; Add dump-screen-to-disk routine for connect mode. Uses Control End. ; Add global entry point TELMSY to get yflags of terminal emulator passed ; in register AL; this is for mode line manipulation. ; Add control of screen refresh via Set Term Color 0 for regular IBM CGA, ; waits for retrace before updating screen, and Set Term Color 10 for ; no waiting. Default is to wait. Controlling variable is refresh defined ; here and set in msxibm under Set Term Color. ; Change names of atscru and atscrd to vtscru and vtscrd, resp. ; Revise memory allocation for screen roll back buffers from fixed size to ; dynamic size of one line per buffer to npgs*slen (5*24=120) per buffer ; to accomodate limited free memory systems. Leave space for Command.com ; before allocating buffer space. 12 April 1986 [jrd] ; Make Dumpscr, the screen dump procedure, available from connect mode drop ; down menu. This makes Dumpscr a global procedure for all MS Kermits. ; 13 April 1986 [jrd] ; Revise mode (status) line again to show full VT102 name, 5 digit speeds, ; and so forth. 19 April 1986. [jrd] ; Revise slightly the keypad function key code to accomodate Heath-19. ; 3 May 1986 [jrd] ; ; [2.28 jrd] ; Correct reported bug of Heath emulation ignores CR/LF when cursor is at ; column 80. Done by commenting out parts of outcr and outlf. [jrd] ; ; [v2.28] ; Don't scroll in inverse video lines (again). ; Backspace in column 0 backs up a line in wrap mode (from Greg Small, ; UC Berkeley) ; Ansi set graphics rendition support (suggested by Greg Small, UC Berkeley) ; escape sequences of the form esc [ p1;p2;...;pn m where pi is ; one of 0,1,4,5,7 for normal, high-intensity, underline, blink, ; and reverse, respectively. ; JD May 1985 ; [v2.27] ; Fixed destructive tab problem (received from many people) ; Fixed insert/delete line problem when at bottom/top of screen. ; Newlines never scroll in inverse video lines ; Implemented cursor save/restore (from Univ. Md.) ; "Echo" status on mode corrected. ; JD, 6 December 1984 public term, gss, lclyini ; entry points public prtbout, prtnout, csrtype, scrmod, scrseg, scrsync public scroff, scron, atsclr, vtscru, vtscrd, scrloc, trnmod, dumpscr public modlin, telmsy, scrloc public vtemu, crt_mode, scbattr, pcnet, refresh ; data [jrd] include mssdef.h ; some definitions ; hardware ;;timer equ 40h ; timer port [not in Sanyo, rwb] ;;bel_prt equ 61h ; speaker control [not in Sanyo, rwb] crt_status equ 3dah ; crt status port disp_enb equ 8 ; display enable bit crtmset equ 3D8H ; CRT mode set port. crtstat equ 3DAH ; CRT status port. screen equ 10h ; bios screen call kb equ 16h ; keyboard interrupt ;;;setblk equ 4ah ; DOS Setblock function ;;;(above definition commented out because already supplied in MSSDEF.H) chesc equ 27 bel equ 7 print_out equ 05h ; dos function to print to printer pbout equ 02h ; dos function to print a character dostty equ 0eh ; dos screen mode write tty [jrd] ; Keyboard scan codes: prscan equ 19h ; Alt-P for print-screen [rwb] upscan equ 49h ; up page dnscan equ 51h ; down page ctlup equ 74h ; ctl-rt arrow, would like to [rwb] ; use ctl-up page, but Sanyo [rwb] ; sends same code as pg-up [rwb] ctldn equ 76h ; ctl-down page homscn equ 47h ; home screen modscn equ 32h ; Alt-M [rwb] endscn equ 4fh ; end of screen delscan equ 53h ; Del key cendscn equ 75h ; ctl-end (dump screen to disk) [jrd] ; no shift state sensing for Sanyo [rwb] ;;alt_shift equ 8H ; alt shift key down ;;ctl_shift equ 4H ; ctl key down ;;left_shift equ 2H ; left shift key down ;;right_shift equ 1H ; right shift key down uparr equ 48h ; scan codes for arrow keys dnarr equ 50h lftarr equ 4bh rgtarr equ 4dh altmns equ 130D ;[IU2] Alt-"-". ; Toggles between terminal types altequ equ 131D ;[IU2] Alt-"=". Reset emualtor kpf1 equ 59D ;[IU2] PF1 - PF4 for VT100 & VT52 kspf1 equ 68h ; PF5 - PF10 ctl/PF1 - ctl/PF8 [rwb] ; for VT100 keypad application 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 '? ' 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 [jrd] modfrm ends datas segment public 'datas' extrn flags:byte, mar_top:byte, mar_bot:byte, jwait:byte extrn filtst:byte, dmpname:byte waste db 100h dup (?) ;*** need this junk because assembler ;*** generates non-relocatable offsets ;*** for things like ;*** "sub di,offset foo" ;*** if offset foo < 100H ; stuff for screen routines yflags db ? ; status flags... flags1 db 0 ; internal flags. prtscr equ 80h ; print screen pressed inited equ 08h ; been here before... wrapped equ 04h ; on if wrapped on last char... vtinited db 0 ; flag for emulator having been inited cursor dw ? esc_ch db ? argadr dw ? ; address of arg blk ega_mode db 0 ; non-zero if IBM EGA is in use. [jrd] 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. pcnet db 0 ; flag, 0 = no PC Network adapter[jrd] netbios equ 5ch ; interrupt for Netbios ; 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 [jrd] ansflgs db 0 ;[IU2] ANSI flags trmtyp db 0 ; most recent terminal type mtty db 7 dup (' ') ; no terminal type (mode line) ; ordered tables of keycodes and corresponding action routine addresses. ckeys db 0,prscan,dnscan,upscan,endscn,homscn,ctlup,ctldn db altmns ; Alt- toggle terminal types db altequ ; Alt= Reset the terminal lcarr equ $-ckeys ;[IU2] define base index of arrow keys db uparr,dnarr,rgtarr,lftarr lcpfk equ $-ckeys ;[IU2] define base index of pf keys db kpf1,kpf1+1,kpf1+2,kpf1+3 lcxpfk equ $-ckeys ;[IU2] define base index of num key pad db kpf1+4,kpf1+5,kpf1+6,kpf1+7,kpf1+8,kpf1+9 ;[IU2] PF5-PF10 db kspf1,kspf1+1,kspf1+2,kspf1+3 ;[rwb] ctl/PF1-ctl/PF4 db kspf1+4,kspf1+5,kspf1+6,kspf1+7 ;[rwb] ctl/PF5-ctl/PF8 lckeys equ $-ckeys ; ckacts must parallel ckeys above... ckacts dw trnbrk,trnprs,dnwpg,upwpg,endwnd,homwnd,upone,dnone dw vtans52 ; VT100/VT52/H19 toggle. dw vtinit ;[IU2] VT100 "RESET" dw trnarr,trnarr,trnarr,trnarr ;[IU2] common arrow keys rtn. dw trnpfk,trnpfk,trnpfk,trnpfk ;[IU2] common pf keys routine dw 14 dup (trxpfk) ;[IU2] common appl. keys rtn. arrtab db 'A','B','C','D' ; arrows: up, down, right, left pfktab db 'P','Q','R','S' ; PF1, PF2, PF3, PF4 xpfktb db 'w' ;[IU2] PF5 = "7" padkey db 'x' ;[IU2] PF6 = "8" padkey db 'y' ;[IU2] PF7 = "9" padkey db 'm' ;[IU2] PF8 = "-" padkey db 't' ;[IU2] PF9 = "4" padkey db 'u' ;[IU2] PF10 = "5" padkey db 'v' ;[rwb] ctl/PF1 = "6" padkey db 'l' ;[rwb] ctl/PF2 = "," padkey db 'q' ;[rwb] ctl/PF3 = "1" padkey db 'r' ;[rwb] ctl/PF4 = "2" padkey db 's' ;[rwb] ctl/PF5 = "3" padkey db 'M' ;[rwb] ctl/PF6 = ENTER padkey db 'p' ;[rwb] ctl/PF7 = "0" padkey db 'n' ;[rwb] ctl/PF8 = "." padkey ; key redefinitions ktrntab dw ? ; address of translation table krpltab dw ? ; address of replacement table ktlen dw ? lincur dw ? ; cursor type save area scbattr db ? ; Screen background attribute oldattr db ? ; screen attributes at init time curattr db ? ; current attribute modesw dw ? beldiv dw 2dch ; 550 hz? captrtn dw ? ; routine to call for captured output dmphand dw ? ; screen dump file handle [jrd] dumpbuf db 80 dup (?), cr, lf ; 82 byte dump work buffer dumpsep db FF,cr,lf ; screen image separators dmperr db ' Cannot open file to save screen to disk $' ; 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' baudnsiz equ 16 ; # 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 crt_mode db ? crt_cols db ? crt_lins db ? low_rgt dw ? ; lower right corner of window swidth equ 80 ; max screen width slen equ 24 ; and length npgs equ 5 ; # of pages of scrolling on each side scrsav dw ? ; segment address of save area refresh db 0 ; screen refresh (0=wait for retrace) ; circular buffer. To work properly, the buffer size should be an exact ; multiple of swidth*2 (assured by mem mngmnt code in lclyini, [jrd]). 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. [jrd] cbuf ends tlbuf dw ? ; temp to hold top line of screen blbuf dw ? ; temp to hold bottom line of screen twnd cbuf <> ; top screen spill-buffer struct bwnd cbuf <> ; bottom screen spill buffer struct topline dw swidth dup (?) ; top line screen spill buffer botline dw swidth dup (?) ; bottom line screen spill buffer datas ends code segment public 'code' ; code segment extrn beep:near,prtchr:near,outchr:near,sendbr:near,sbrk:near extrn isfile:near, strlen:near ; in mssfil extrn anstty:near,ansini:near,ansrei:near ; in mszibm extrn anstat:near,anskbi:near,ansdsl:near ; in mszibm extrn ans52t:near, vclick:near, vsinit:near ; in mszibm 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 mov ax,swidth*(slen+1)*2 ; (80 char + 80 attr) * 25 lines [jrd] call sbrk ; memory allocation routine (mssker) mov scrsav,ax ; memory segment for save screens mov tlbuf,offset topline ; a new buffer in 'datas' space mov blbuf,offset botline ; ditto [jrd] mov ax,swidth*2*2 ; ask for two lines (1 per buffer) call sbrk ; allocate mem. Exit Kermit on failure ;if we get here them we have the lines mov bwnd.orig,ax ; memory segment, bottom window area push es ; save this register. mov es,ax ; seg pointer to new memory block mov bx,(swidth*2*slen*2*npgs+24015)/16 ; what we want initially mov ah,setblk ; DOS Setblock. Ask for that space. int dos ; bx has # paragraphs available sub bx,24000D/16 ; deduct space for DOS 3.1 Command.com cmp bx,(swidth*4+15)/16 ; any room left for buffers? jge lclyin2 ; some space is available for buffers mov bx,(swidth*4+15)/16 ; else use our sbrk allocation lclyin2:mov ah,setblk ; ask for that many paragraphs int dos ; Errors here == DOS deceived us. pop es ; restore reg. mov ax,bx ; bx = # paragraphs allocated by DOS shr ax,1 ; divide by two (two buffers) mov cx,bwnd.orig ; segment where allocation begins add cx,ax ; segment where next buffer begins mov twnd.orig,cx ; and store it. mov cl,4 ; paragraphs to bytes. shl ax,cl ; number of bytes per buffer mov cx,swidth*2 ; number of bytes per line in buffer mov dx,0 ; clear extended numerator div cx ; ax = number of lines per buffer mov bwnd.lmax,ax ; max lines per buffer mov twnd.lmax,ax ; max lines per buffer mov cx,swidth*2 ; bytes per line (char + attribute) 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 scrmod ; read video state, get crt_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 ; test for IBM PC Network adapter, formula in IBM PC Network Tech Ref mov pcnet,0 ; assume PC Net is inactive ; push es ; save es around PC Network call ; mov ax,netbios ; interrupt 5cH (Lock/Unlock file) ; mov es,ax ; cmp word ptr es:[0],0 ; anything there? ; je lclyin1 ; e = no, so no Network ; mov ah,0ffh ; check further, DOS reserved funct. ; int dos ; cmp al,03H ; adapter present? (3 = magic #) ; jne lclyin1 ; ne = no (not exhaustive test here) ; mov pcnet,1 ; else say Netbios is active. ;lclyin1:pop es ; recover es from network test. call vsinit ; init terminal emulator module MSZ ret lclyini endp scrini proc near ; init screen stuff mov ah,15 ; read video state... int screen mov crt_mode,al ; save crt mode cmp ah,crt_cols ; is real # of cols < passed? jge scrin1 ; no mov crt_cols,ah ; yes, save # of cols scrin1: mov dl,crt_cols ; # of cols again mov dh,crt_lins ; and # of rows dec dl dec dh mov low_rgt,dx ; save away window address 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 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. mov ega_mode,1 ; yes, set flag to say so. scrin6: test flags1,inited ; have we been here before? jnz scrin4 ; 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 mov lincur,cx ; save cursor type (line #'s) cmp dh,crt_lins ; past logical end of screen? jb scrin2 ; no, keep going mov dh,byte ptr low_rgt+1 ; yes, just use lower right corner scrin2: cmp dl,crt_cols ; maybe past right margin jb scrin3 ; no, use the way it is mov dl,byte ptr low_rgt scrin3: mov cursor,dx ; init cursor scrin4: cmp flags.vtflg,0 ; doing terminal emulation? ;;; jne scrin5 ; ne = yes mov ah,2 ; set cursor position xor bh,bh int screen ; set cursor in case it moved scrin5: ret scrini endp ; Routine to initialize terminal emulator. Call once. vtinit proc near ;[IU2] cmp flags.vtflg,0 ; doing emulation? je vtinix ; e = no or vtinited,inited call ansflg ; update ansi flags mov al,yflags ;[IU2] Pass the flags. mov bx,argadr ;[IU2] Get address of argument block mov dl,[bx].baudb ;[IU2] Baud rate code in dl mov dh,[bx].parity ;[IU2] Parity code in bits mov cl,4 ;[IU2] 0-3 of dh shl dh,cl or dh,07H ;[IU2] Just say 7 data bits. mov bx,low_rgt ;[IU2] Pass screen size in bx. call ansini ; call startup routine in mszibm. vtinix: ret vtinit endp ;[IU2] Routine to toggle VT100/VT52/Heath-19 modes in VT100 emulator. vtans52 proc near ;[IU2] cmp flags.vtflg,0 ; emulating? [jrd] je vtans5 ; e = no call ans52t ;[IU2] Call MSZ toggle-it routine. call ansflg ;[IU2] Update flags. vtans5: ret vtans52 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 and flags1,not (prtscr) ; these are allowable (others remain). mov al,[bx].prt ;;; cmp al,portno ; using same port? ;;; je argin1 ; yes, go on ;;; and flags1,not inited ; else re-init stuff argin1: mov portno,al ; update port number mov al,[bx].cols mov crt_cols,al mov al,[bx].rows mov crt_lins,al ; init # of rows and cols ;; mov al,flags.vtflg ; Terminal type [jrd] ;; cmp al,trmtyp ;[IU2] Same type? ;; je argin2 ;[IU2] Yes, just continue ;; and vtinited,not inited ; No, re-init stuff. ;; mov trmtyp,al ;[IU2] And save new terminal type. argin2: mov ax,[bx].captr mov captrtn,ax ; buffer capture routine mov ax,[bx].belld mov beldiv,ax ; bell divisor mov ax,[bx].klen mov ktlen,ax ; length of key redef tbl mov ax,[bx].ktab mov ktrntab,ax ; save key translation table mov ax,[bx].krpl mov krpltab,ax mov al,[bx].escc mov esc_ch,al 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 ; 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 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,'1' cmp portno,1 ; port 1? je modl5 ; yes, keep going mov al,'2' 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 [jrd] mov modbuf.m_prn+1,' ' mov modbuf.m_prn+2,' ' test flags1,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 ; alternate entry to write an alternate mode line modwrt: cmp flags.vtflg,0 ;;;trmtyp,0 ; emulating? jne modwr1 ; ne = yes, so having mode line is OK. ret ; else DOS scrolls 25th line. modwr1: 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 ;[IU2] Get terminal attributes mov bh,ah ; get video attribute mov cx,1800h ; line 25... mov dx,184fh mov ax,600h ; scroll to clear the line int screen mov dx,24 * 100h mov bh,0 mov ah,2 ; set cursor position int screen pop si pop cx ; restore these modl6: 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 ;;;trmtyp,0 ; emulating? je modl7 ; e = no mov al,yflags ;[IU2] Yes - update flags also call ansdsl ; get extras from emulator ;;; ret ;[IU2] ansdsl repositions cursor 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 ;[IU2] Get terminal screen attributes mov bh,al ;[IU2] Use screen background attribute mov ax,600h ; blank window mov cx,24 * 100h ; beginning of window mov dx,24 * 100h + 79 ; end of window int screen ; clear mode line ret ; and return clrmod endp ; Fetch screen attributes from emulator (if emulating). It exists mainly ;[IU2] so that the reverse video will work. Returns the current mode ;[IU1] line background attribute in ah, the current screen background in al, ;[IU2] and the current "cursor" (foreground) attribute in bl. (Note: anstat ;[IU2] returns status yflags in bh). trmatt proc near ;[IU2] Get attributes cmp flags.vtflg,0 ; emulating? [jrd] je trmat1 ;[IU2] No, just do simple stuff. mov al,yflags ;[IU2] anstat expects flags byte in al. call anstat ; Fetch emulator status/attributes ret trmat1: mov al,scbattr ; Background attributes. [jrd] mov bl,curattr ;[IU2] And cursor attribute. 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 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 ;[IU2] Save acs over call push bx mov al,yflags call anstat ;[IU2] Get status and attributes mov ansflgs,bh ;[IU2] Save. ;;; mov ah,flags.vtflg ;;; mov trmtyp,ah pop bx ;[IU2] Restore acs and return. pop ax ret ansflg endp term proc near ; terminal mode entry point mov argadr,ax ; save argument ptr push es ; save caller's extra segment address mov ax,seg datas mov es,ax call argini ; init options from arg address call scrini ; init screen stuff test flags1,inited ; have we run yet? jz term1 ; no, forget this part call restscr ; restore screen term1: or flags1,inited ; remember we've run already. cmp flags.vtflg,0 ; emulating a terminal? [jrd] jne term1a ; ne = yes, can have mode line [jrd] ;;; mov flags.modflg,0 ; disable mode line. [jrd] or yflags,modoff ; and say want it done. [jrd] cmp trmtyp,0 ; previous terminal type = none? jne term2 ; ne = no. need to clear mode line. term1a: cmp flags.modflg,0 ; is mode line disabled? [jrd] jne term1b ; ne = no. test yflags,modoff ; so, is the mode line really off? jnz term2a ; nz = yes, nothing to do or yflags,modoff ; say want it off and fall thru. [jrd] term1b: test yflags,modoff ; is mode line to be off? [jrd] jnz term2 ; nz = yes, clear the line. [jrd] 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 or al,al ; terminal type none? jz lp ; z = yes, nothing to init. mov al,yflags ; tell emulator we are back cmp vtinited,inited ; inited emulator yet? je term3 ; e - yes call vtinit ; init it now jmp lp term3: call ansrei ; reinit the emulator call ansflg ; and get its flags lp: call portchr ; char at port? jnc chkinp ; nc = no, keep going call outtty ; print on terminal chkinp: cmp pcnet,0 ; IBM PC Netbios active? je chkin2 ; e = no mov dl,0ffh ; Network. keyboard input, via DOS mov ah,dconio ; get a char into al int dos jz lp ; nothing available xor ah,ah ; assume no scan code cmp al,0 ; special char? jne chkin3 ; ne = no. mov ah,dconio ; read second byte int dos ; get pseudo-scan-code into al mov ah,al ; p-scan-code here for following code xor al,al ; say special char xor bl,bl ; say shift state is none jmp chkin3 ; and carry on regardless. chkin2: mov ah,1 ; Non-Network. Bios keyboard input. int kb ; is anything at keyboard? jz lp ; z = no xor ah,ah ; yes. int kb ; get the char from the buffer push ax ; save character temporarily call gss ; get shift state into al mov bl,al ; save shift state pop ax chkin3: cmp flags.vtflg,0 ; emulating? (0 = no) [jrd] je chkin1 ; extra clicks not available [jrd] test vtemu.vtflgst,vskeyclick ; flags from SET. [jrd] jz chkin1 ; extra clicks not wanted [jrd] call vclick ; click, what else? [jrd] chkin1: cmp al,esc_ch ; Kermit's escape character? je quit ; yes, stop here call trnout ; translate if nec., output to prt jmp chkinp ; and keep going quit: 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 call clrmod ; erase mode line quit1: mov ah,oldattr ; attributes at init time mov scbattr,ah ; background = original state [jrd] mov cx,lincur ; cursor type at startup mov ah,1 int screen ; restore cursor type mov ah,2 ; Position cursor mov bh,0 ;[IU3] Page 0 mov dx,24 * 100H ; bottom left int screen ;[IU3] Do it. mov al,yflags mov bx,argadr mov [bx].flgs,al ; update flags in arg block pop es ; restore segment register ret ; and return to caller term endp ; put the character in al to the screen outtty proc near 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: test flags1,prtscr ; should we be printing? jz outnop ; no, keep going push ax mov ah,print_out mov dl,al ; put character here for dos... int dos pop ax outnop: cmp flags.vtflg,0 ; emulating a terminal? jnz outnop1 ; nz = yup, go do something smart test yflags,trnctl ; debug? if so use dos tty mode jz outnp4 ; z = no mov ah,dostty ; dostty screen mode cmp al,7fh ; Ascii Del char or greater? jb outnp1 ; b = no and al,3fH ; strip high 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)? [jrd] jne outnp5 ; ne = no jmp beep ; use short beep, avoid char loss. outnp5: mov dl,al ; write without intervention. mov ah,pbout int dos ; else let dos display char ret ; and return outnop1:jmp anstty ;call terminal emulator routine & ret outtty endp ; get shift state into al. We only care about shift, ctl, and alt keys. ; right shift is collapsed into left shift. ; For Sanyo, indicate no shift keys depressed [rwb] gss proc near xor al,al ; [rwb] ret gss 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 ;[IU2] Global routine now. mov ah,al ; This is where outchr expects it prtbou1:call outchr nop ;[IU2] 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 ;[IU2] Output in base 10. jmp prtno2 ;[IU2] Ensure at least a zero. prtno1: cmp al,0 jne prtno2 ;[IU2] Yes - do more digits ret ;[IU2] No - return from recursive call. prtno2: mov ah,0 ;[IU2] Clear previous remainder. div bl ;[IU2] Divide off a digit push ax ;[IU2] Push remainder (in ah) on stack call prtno1 ;[IU2] Recur. pop ax ;[IU2] Pop off a digit add ah,'0' ;[IU2] Make it ASCII call prtbou1 ;[IU2] Output to port ret ;[IU2] Unwind. prtnout endp ; send the character in al out to the serial port ; handle echoing also... outprt proc near test yflags,lclecho ; echoing? jz outpr1 ; 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,7fh ; we don't worry about parity here stc ; have a character ret ; and return portchr endp ; translate the scan code in ah according to the translate table ; given in ktrntab/krpltab, output to port. If no translation, ; use ascii char in al. (should probably include shift state ; somewhere). Shift state is in bl. trnout proc near test yflags,havtt ; translate table given? jz trnou3 ; no, just output character push ax ; save original value mov al,ah ; put scan code into ah mov ah,bl ; shift state into top half. mov di,ktrntab ; pick up translate tbl mov cx,ktlen ; length of tbl repne scasw ; look for our key pop ax ; recover character jne trnou3 ; not found, forget it sub di,ktrntab ; get index into tbl sub di,2 ; (minus 2 for pre-increment) mov bx,krpltab ; get replacement table mov si,[bx][di] ; and addr of replacement mov cl,[si] ; get first byte (length) xor ch,ch ; clear high-order byte inc si ; point to translation string trnou2: lodsb ; get a byte push si push cx ; save important registers call outprt ; send to port pop cx pop si loop trnou2 ; send all chars cmp flags.vtflg,0 ; emulating? je trno2a ; e = no call anskbi ;[IU2] Yes - say we had keyboard input trno2a: ret trnou3: cmp al,0 ; is it a special code? [rwb] jne trnou4 ; no, don't do this cmp ah,modscn ; Alt-M, mode line toggle? [rwb] je trnmod ; e = yes, go toggle mode line [rwb] cmp ah,cendscn ; Ctrl-End, dump screen to disk? [rwb] jne trno3a ; ne = no [rwb] call savescr ; save the screen in buffer, [rwb] jmp dumpscr ; go do it and return [rwb] trno3a: cmp ah,delscan ; Del key? [jrd] jne trno3b ; ne = no [jrd] mov al,7fH ; send ascii Del code [jrd] jmp trnou4 ; [jrd] trno3b: mov al,ah ; get scan code mov cx,lckeys ; length of table mov di,offset ckeys ; table address repne scasb mov al,0 ; ascii code was 0... jne trnou4 ; not found, keep going sub di,offset ckeys+1 ; get table offset shl di,1 ; shift for word offset jmp ckacts[di] ; jump to appropriate routine trnou4: cmp flags.vtflg,0 ; emulating? je trnou5 ; e = no call anskbi ;[IU2] Yes, say we had keyboard input. cmp al,cr ;[IU2] A CR? jne trnou5 ;[IU2] No - just output it and return call ansflg ;[IU2] Yes - update VT100 flags test ansflgs,anslnm ;[IU2] ANSI new-line mode set? jz trnou5 ;[IU2] No - just send the cr call outprt ;[IU2] Yes - output a carriage-return mov al,lf ;[IU2] Followed by a line feed. trnou5: call outprt ret trnmod: cmp flags.modflg,1 ; is mode line enabled? [jrd] jne trnm2 ; ne = no, don't touch it 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 ;[IU2] Update flags all around. ret ; and return trnm1: and yflags,not modoff ;[IU2] Clear flag first. call modlin ;[IU2] Then turn on mode line. call ansflg ;[IU2] Update flags all around. trnm2: ret trnbrk: ; send a Break signal [rwb] call sendbr ret ; toggle ^ PrtSC screen to printer trnprs: xor flags1,prtscr ; flip the flag test yflags,modoff ; mode line disabled? jnz trnpr1 ; nz = yes call modlin ; else rewrite mode line trnpr1: ret ; and return ;[IU2] Common cursor keys translation. trnarr: shr di,1 ;[IU2] Make offset a byte offset sub di,lcarr ;[IU2] Make offset into char table mov al,arrtab[di] ;[IU2] Fetch the character push ax ;[IU2] Save it. mov al,chesc ;[IU2] Output an escape. call outprt ; Output, echo permitted cmp flags.vtflg,ttvt100 ; VT100 terminal emulation? jne trnar2 ;[IU2] No, do VT52/HEATH-19 sequence. call ansflg ;[IU2] Update flags all around. mov al,'[' ;[IU2] Maybe this next? test ansflgs,decckm ;[IU2] Cursor key mode reset? je trnar1 ;[IU2] Yes, output the "[" mov al,'O' ;[IU2] No, set, use the "O". trnar1: call outprt ; Output it (echo permitted). trnar2: pop ax ;[IU2] Get the saved char back call outprt ; Output to port (echo permitted) ret ;[IU2] Common PF key translation: F1-F4 gives VT100 sequences for PF1-PF4 ;[IU2] (or VT52 sequences for GOLD, RED and BLUE keys for HEATH-19). trnpfk: shr di,1 ;[IU2] Make offset a byte offset sub di,lcpfk ;[IU2] Make offset into char table mov al,pfktab[di] ;[IU2] Fetch the character push ax ;[IU2] Save it. mov al,chesc ;[IU2] Output an escape. call prtbout call ansflg ; get emulator flags test ansflgs,decanm ; ansi mode? je trnpf1 ; e = no mov al,'O' ;[IU2] send an "O". call prtbout ;[IU2] Output it. trnpf1: pop ax ;[IU2] Get the saved char back call prtbout ;[IU2] Output to port ret ;[rwb] Routine for "application keypad" (F5-F10 and ctl/F1-ctl/F8). ; These translate to 7,8,9,4,5,6,1,2,3,0, period, minus, comma, and ENTER. trxpfk: call ansflg ;[IU2] Update emulator flags test ansflgs,deckpam ;[IU2] Application keypad mode? jz trxpfx ;[IU2] No, forget this trxpf0: shr di,1 ;[IU2] Make offset a byte offset sub di,lcxpfk ;[IU2] Make offset into char table mov al,xpfktb[di] ;[IU2] Fetch the character push ax ;[IU2] Save it. mov al,chesc ;[IU2] Output an escape. call prtbout mov al,'O' ;[IU2] Output the "O" cmp flags.vtflg,ttvt100 ; VT100 mode? je trxpf1 ; e = yes, use "O" code test ansflgs,decanm ; ANSI (alt application keypad) mode? jnz trxpf1 ; nz = yes, use "O" trxpf2: mov al,'?' ; else use "?" instead of "O". trxpf1: call prtbout pop ax ;[IU2] Retrieve the character call prtbout ;[IU2] Output it also trxpfx: ret trnout endp ;;;;; General screen management routines for IBM PC ; computes screen location to ax, given row and col in dx. ; trashes ax scrloc proc near push bx mov al,dh ; get row mov bl,swidth ;** row size mul bl ; multiply by row size xor dh,dh ; clear col add ax,dx ; this is current position sal ax,1 ; double for attributes pop bx ret scrloc endp ; wait for retrace so can write to screen memory. Several test conditions ; permit us to skip waiting for all but IBM CGA. scrwait proc near cmp refresh,0 ; slow refresh? jne scrwa3 ; ne = no waiting. cmp tv_mode,0 ; Topview mode? jne scrwa3 ; ne = yes, no waiting cmp ega_mode,0 ; Extended Graphics Adapter in use? jne scrwa3 ; ne = yes, no waiting. cmp crt_mode,7 ; bw mode? je scrwa3 ; e = yes, no waiting push dx mov dx,crt_status scrwa1: in al,dx test al,disp_enb ; display enabled? jnz scrwa1 ; yes, keep waiting scrwa2: in al,dx test al,disp_enb ; now wait for it to go off jz scrwa2 ; so can have whole cycle pop dx scrwa3: ret ; that was easy... scrwait 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. 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: int screen ; Set it. 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 screen so we can restore it. Saves all 25 lines. [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 mov es,di ; segment of save area mov di,0 ; no offset mov cx,swidth*(slen+1) ; # of words on screen call scrwait ; wait for screen to be ready pop ds ; address screen rep movsw ; save the screen pop di pop si pop cx pop ax pop ds ; restore this pop es ret savescr endp ; restore screen from scrsav buffer. Restores all 25 lines. [jrd] restscr proc near push es mov cx,swidth*(slen+1) ; the entire screen [jrd] call scrseg ; get address of screen data in es:di call scrwait ; wait for retrace push ds ; save original data segment mov si,scrsav ; source buffer segment address [jrd] mov ds,si ; set buffer segment in ds for si mov si,0 ; no offset from this rep movsw ; restore data to screen pop ds ; recover original data segment mov cx,swidth*(slen+1) ; number of words on the screen 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 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: 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 dx,24*100H ; go to status line 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 ret dmp1: push di ; read screen buffer, write lines push si push es mov cx,slen+1 ; 25 lines mov si,0 ; offset in memory segment dmp2: push cx ; save outer loop counter mov es,scrsav ; get memory segment mov di,offset dumpbuf ; data segement memory mov cx,swidth ; 80 columns 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 cx,swidth ; 80 columns push es mov ax,ds mov es,ax ; set es to data segment for es:di mov di,offset dumpbuf+swidth-1 ; 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 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 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 ret dumpscr endp ; Get CRT mode - returns mode in variable crt_mode. scrmod proc near mov ah,15 ; Get current video state. int screen mov crt_mode,al ; Store CRT mode value. 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 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. 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 call scrwait ; Wait for retrace. cmp jwait,0 ; Just wait only? jne scrof1 ; Right - don't disable screen. 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.. scrof1: 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. cmp jwait,0 ; No - ever turned off? jne scronx ; No - 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 scrloc 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 cmp cx,swidth ; Blanking a line or less?? jg atscl1 ; No - make scroff disable display mov jwait,0FFH ; Yes - wait for retrace only. atscl1: call scroff ; Turn screen off if color card. push cx ; save word count for Topview 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. mov jwait,0 ; Reset wait-only flag. 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 ret ; worker routine for vtscru/d atsprep:push es ; upgraded from older version [jrd] mov jwait,0 ; wait only for retrace call scroff ; turn off color screen call scrseg ; get display address in es:di mov si,di ; si will be source mov di,tlbuf ; storage for top display line dest mov cx,swidth ; length of line push ds ; swap ds and es for move push es pop ds pop es rep movsw ; copy top line from screen to buffer push ds ; swap back to normal push es pop ds pop es pop es ; and that call scron ; turn on screen again mov ax,tlbuf mov bx,offset twnd ; this is where it goes call putcirc ; put into buffer 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 ret ; And return ;screen roll up, version for manual scrolling only mscru: push bx ; Upgraded by [jrd] push cx push dx push si push di call atsprep ; save top line mscru1: mov ax,601H ; scroll up one line mov dx,low_rgt ; lower rignt corner xor cx,cx ; top row of scrolling region mov bh,scbattr ; background attributes int screen ; scroll up that region mov ax,blbuf ; place for an old bottom line mov bx,offset bwnd ; source of lines call getcirc ; try to get a line jc mscru2 ; c = none, just quit cld mov jwait,0 ; wait for retrace only 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 si,blbuf ; source of line mov cx,swidth rep movsw ; copy in the line to the screen mov cx,swidth ; length for Topview call scrsync ; synch Topview 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 ret ; prep for screen scroll down. [jrd] ; copies bottom scroll line from screen to buffer blbuf. ; destroys ax,cx,dx,si,di. getbot proc near ; Upgraded from old version [jrd] push es mov jwait,0 ; wait only for retrace 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 di,blbuf ; destination address mov cx,swidth ; number of words to copy push ds ; swap ds and es for the move push es pop ds ; ds <-- org es pop es rep movsw ; from screen to buffer push ds ; reswap back to normal push es pop ds pop es pop es call scron ; turn on display again ret getbot endp ;screen scroll down, for manual mode only mscrd: push bx ; Upgraded by [jrd] push cx push dx push si push di mscrd1: call getbot ; fetch bottom line from screen mov ax,blbuf mov bx,offset bwnd call putcirc ; save in circular buffer mscrd3: 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 mov ax,tlbuf ; place to put line temporarily mov bx,offset twnd ; where to get lines call getcirc ; read a line jc mscrd2 ; c = ok, just no line. quit mov si,tlbuf ; where to get line mov cx,swidth ; 80 words. mov jwait,0 ; wait only for retrace call scroff ; turn off display cld ; Put direction back to "increment". push es call scrseg ; get segment address of screen rep movsw ; copy line ds:si to es:di mov cx,swidth ; length for Topview call scrsync ; synch Topview pop es call scron ; turn on display again mscrd2: pop di ; Restore the rest of the ACs. pop si pop dx pop cx pop bx ret ; move viewing window down as much as possible (text moves up) endwnd proc near ; go to end of scrolling text mov cx,slen*npgs ; as many pages as possible jmp dnwp0 ; and enter dwnpg endwnd endp dnone proc near ; move text up one line [jrd] mov cx,1 jmp dnwp0 dnone endp ; scroll viewing window down (text moves up) one page (23 lines, to keep track) dnwpg proc near mov cl,byte ptr low_rgt+1 ; number of rows, excl status mov ch,0 dnwp0: push bx mov bx,offset bwnd ; bottom line buffer cmp [bx].lcnt,cx ; enough lines? jge dnwp1 ; ge = we have that many lines stored mov cx,[bx].lcnt ; do as many as we have dnwp1: jcxz dnwp2 ; z = nothing to do call mscru ; scroll up text one line loop dnwp1 dnwp2: pop bx ret dnwpg endp ; home viewing window homwnd proc near mov cx,slen*npgs ; large # of lines jmp upwp0 ; join upwpg homwnd endp upone proc near ; move text down one line [jrd] mov cx,1 jmp upwp0 upone endp ; scroll viewing window up (text moves down) a page (23 lines, to keep track) upwpg proc near mov cl,byte ptr low_rgt+1 ; number of rows, excl status line mov ch,0 upwp0: push bx mov bx,offset twnd ; how many lines are in top line buf? cmp [bx].lcnt,cx jae upwp1 ; ae = at least as many as requested mov cx,[bx].lcnt ; do only as many as are stored. upwp1: jcxz upwp2 ; z = no lines to scroll call mscrd ; roll down text one line loop upwp1 upwp2: pop bx ret upwpg endp ; put a line into the circular buffer. Pass the buffer structure ; in bx, the pointer to the line in ax. Revised by [jrd] putcirc proc near push es push si push di push bx push cx mov es,[bx].orig ; get segment of memory area mov di,[bx].pp ; pick up buffer ptr (offset from es) add di,2*swidth ; increment to next avail slot mov cx,[bx].bend ; compare line end with buffer end sub cx,2*swidth-1 ; address of end of this line cmp di,cx ; would line extend beyond buffer? jbe putci1 ; be = not beyond end mov di,0 ; else start at the beginning putci1: mov [bx].pp,di ; update ptr mov si,ax ; this is source mov cx,swidth rep movsw ; copy into buffer mov cx,[bx].lmax ; line capacity of buffer cmp [bx].lcnt,cx ; can we increment line count? jae putci2 ; ae = no, keep going inc [bx].lcnt ; else count this line putci2: pop cx pop bx pop di pop si ; restore registers 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, the buffer to copy the line into ; in ax. Revised by [jrd] getcirc proc near push es push si push di push bx push cx mov cx,ds mov es,cx ; ensure proper segment cmp [bx].lcnt,0 ; any lines in buffer? jne getci1 ; yes, ok to take one out. stc ; else set carry jmp short getcir3 ; and return getci1: mov cx,swidth ; # of chars to copy mov si,[bx].pp ; this is source mov di,ax ; this is dest push ds ; save original ds mov ds,[bx].orig ; use seg address of buffer for si rep movsw pop ds ; recover original data segment mov si,[bx].pp ; get ptr again sub si,2*swidth ; move back jnc getcir2 ; still in buffer, continue mov si,[bx].bend ; else use end of buffer sub si,2*swidth-1 ; minus length of a piece getcir2:mov [bx].pp,si ; update ptr dec [bx].lcnt ; decrement # of lines in buffer clc ; make sure no carry getcir3:pop cx pop bx pop di pop si pop es ret getcirc endp code ends if1 %out [End of pass 1] else %out [End of assembly] endif end