home *** CD-ROM | disk | FTP | other *** search
- page 58,132
- ;--- zavt.asm ----------------------------------------------------------
- ; Zephyr Avatar terminal driver.
- ; Copyright (C) 1989-1990, Luns Tee, Toronto Ontario
- ; Based on original code for ZANSI by Thomas Hanlin III, Alexandria VA.
- ; and original code for NANSI by Daniel Kegel, Pasadena CA.
- ;
- ; Revision History:
- ;------------------------------------------------------------------------
- ; Luns Tee, Toronto Ontario
- ; 19 Dec 1988: Replaced code to set 43 lines with code to check
- ; number of lines on screen through bios and then
- ; set internal paramaters accordingly
- ;
- ; 8 Mar 1989: Removed forementioned code completely and placed it
- ; with the code that determines screen size and video
- ; mode at each write. Also added routines for automatic
- ; support of different video pages and tidied up the
- ; TTY scroll
- ;
- ; 24 Mar 1989: Added code to enable/disable pseudocursor. Similar to
- ; enabling/disabling end of line wrap but with 45 instead
- ; i.e. esc[45l disables pseudocursor, esc[45h reenables
- ;
- ; 15 Apr 1989: Removed all the JMP $+2 from the cursor set routines as
- ; nobody could give a reason for their being there aside
- ; from them being artifacts from compiling a higher level
- ; language
- ;
- ; 17 Aug 1989; Added code to allow backspace across left margin as
- ; is required for upcoming (?) command line editor
- ; enhancement TSR
- ;
- ; 23 Aug 1989; Put in faster *10 code in parsing, fixed bug involving
- ; backspace after wraparound on screens of width >128
- ; and general maniacal cleaning up
- ;
- ; 26 Aug 1989; Fixed minor bug in beep routine as addressed in NANSI 22c
- ; and made the darned bell shorter
- ;
- ; 20 Sep 1989; added restriction that DSR paramater must be 6 (as
- ; mentioned inconsistently between sources) and centralized
- ; graphics mode checking to balance Mono and Color system
- ; speeds
- ;
- ; 29 Sep 1989; made max_x one based and saved 10 bytes, reversed
- ; strategy for HVP_SET and changed BYTEOUT to support
- ; screens up to 255x255 in size
- ;
- ; 16 Nov 1989; removed redundant code between getchar/peekchar as well as
- ; the interrupt functions, word aligned everything relevant,
- ; made check for non EGA screens part of init rather than
- ; part of normally resident interrupt routine, tightened
- ; backspace, reordered code to make for more jmp short rather
- ; than jmp near, rewrote parse routines so a colon not
- ; preceeded by a number acts as predicted, removed all KKR and
- ; kb remapping artifacts, fixed bug involving tabs over the
- ; right margin on screens of widths not a multiple of 8,
- ; referred byte requests for 0 to dh instead of a constant,
- ; put everything not needed as a word variable into equates,
- ; put register saving and compilation paramaters into macros
- ; in an include file ZANSI_D.ASM and rewrote SM/RM
- ;
- ; 26 Nov 1989; Modified scroll routine to better handle situations
- ; where screen lengths change leaving cursor off screen
- ; - formerly scrolled screen while writing outside of it - now
- ; scrolls region from start of screen to cursor bringing
- ; active screen area into view
- ;
- ; 27 Dec 1989; Added support for AVATAR/0 except for ^Y RLE (being planned)
- ; and added switches in ZANSI_D for AVATAR, direct scroll
- ; override (for back-scroll users), and left margin wrap
- ;
- ; 4 Feb 1990; Finished off RLE support, commented all code not in ZANSI12
- ; and renamed to ZAVT.
- ;
- ; 21 Feb 1990; Put 'hold's into cursor set routine for driver compiled for
- ; 286 as it is on the faster machines (wish I had one) that
- ; they are needed to give the system time to catch up
- ;
- ; 28 Feb 1990; Took code from PC-Mag's DOS-EDIT as grounds for a full-screen
- ; editor for DOS input. Effect is the similar, but code is now
- ; where it belongs saving some TSR conflicts
- ;
- ; 23 May 1990; Dug up NANSI code and replace keyboard remapping. Also
- ; reversed keybuf logic - strings are no longer stored
- ; inverted - to simplify code
- ;------------------------------------------------------------------------
-
- include zavt_d.asm ; get equates
-
- ; from zavt_p.asm
- extrn f_escape:near, f_in_escape:near
-
- if avatar
- extrn avt_cls:near, f_avatar:near
- extrn dle:near, rle:near
- endif
-
- ; from zavt_i.asm
- extrn dosfn0:near
- if fullscreen
- extrn linebufend:word
- endif
-
- ; to zavt_p.asm
- public f_loopdone
- public f_control
- public f_looploop
- public cur_parm_ptr
- public escvector, string_term
-
- if avatar
- public f_nctl
- public f_loop_nocheck
- public gmode_flag
- public putchar
- endif
-
- ; to both zavt_p.asm and zavt_f.asm
- public cur_x, cur_y, max_x, max_y, cur_attrib,string_attrib
-
- ; to zavt_f.asm
- public pseudo_flag
- public wrap_flag
- public gmode_flag
- public xy_to_regs, get_blank_attrib
- public port_6845
- public cur_coords, saved_coords
- public max_coords
- public cpr_esc, cpr_buf, cprseq
- public video_mode
- public screen_len
- public cur_page
- public video_off
-
- ; to zavt_i.asm
- public hdrseg
- public req_ptr, break_handler
- public int_29
-
-
- ; from zavt_k.asm
- extrn screenedit:near
- extrn getchar:near, peekchar:near
-
- ; to zavt_k.asm
- if fullscreen
- public scrnbuf, pseudocursor
- endif
-
- if xlate
- public xlatseq
- endif
- public fnkey, fnkeybuf
-
-
- CODE segment byte public 'CODE'
- assume cs:code, ds:code
-
- ; Device Driver Header
-
- org 0
-
- if two_handlers
- dw header2
- else
- dw -1
- endif
- hdrseg dw -1 ; next device
- dw 8013h ; attributes
- dw strategy ; request header pointer entry
- dw interrupt ; request entry point
- db 'CON', 5 dup(' ') ; device name (8 char)
- header2:
- if two_handlers
- dd -1 ; next device
- dw 8013h ; attributes
- dw strategy ; request header pointer entry
- dw interrupt ; request entry point
- db 'KEYB', 4 dup(' ') ; device name (8 char)
- endif
-
- ; following three keybufs hold information about input
- ; Storage order determines priority- since the characters making up a function
- ; key code must never be separated (say, by a Control-Break), they have the
- ; highest priority, and so on. Keyboard keys (except ctrl-break) have the
- ; lowest priority.
-
- fnkey keybuf <0, fnkeybuf> ; fn key string (0 followed by scan code)
- cprseq keybuf <0> ; CPR string (ESC [ y;x R)
- brkkey keybuf <0, brkkeybuf> ; ^C
- if fullscreen
- scrnbuf keybuf <0> ; line from full-screen editor
- endif
- if xlate
- xlatseq keybuf <0> ; keyboard reassignment string
- endif
-
-
- ;------- dos_fn_tab -------------
- ; This table is used in "interrupt" to call the routine that handles
- ; the requested function.
-
- max_cmd equ 12
- dos_fn_tab:
- dw dosfn0, nopcmd, nopcmd, badcmd, dosfn4, dosfn5, dosfn6
- dw dosfn7, dosfn8, dosfn8, nopcmd, nopcmd
-
- ;----- variable area --------------------
- req_ptr label dword
- req_off dw ?
- req_seg dw ?
-
- escvector dw 0 ; state vector of ESCape sequencer
- pseudo_flag db 1 ; 1 = simulate cursor in graphics modes
- wrap_flag db 1 ; 0 = no wrap past line end
- video_mode db 3 ; ROM BIOS video mode (2=BW, 3=color)
- gmode_flag db 0 ; 0 = text mode
- max_coords label word
- max_y db 24
- max_cur_x label word ; used to get both max & cur at once
- max_x db 80 ; line width (80 for 80x25 modes)
- cur_coords label word
- cur_x db 0 ; cursor position (0 = left edge)
- cur_y db 0 ; (0 = top edge)
- saved_coords dw ? ; holds XY after a SCP escape sequence
- video_off dw 0 ; offset of current page into video buffer
- screen_len dw ? ; bytes on screen (w attributes)
- f_cptr_seg dw ? ; part of fastout write buffer pointer
- cur_parm_ptr dw ? ; last byte of parm area now used
- port_6845 dw ? ; port address of 6845 card
- string_attrib label word ; to get the attribute pronto
- string_term db 0 ; either escape or double quote
- cur_attrib db 7 ; current char attributes
- cur_page db 0 ; current display page
-
-
- brkkeybuf db 3 ; control C
- fnkeybuf db ? ; holds second byte of fn key codes
- cpr_esc db 27,'[' ; descending buffer for cpr function
- cpr_buf db 9 dup (?)
-
- ;------ xy_to_regs --------------------------------------------
- ; on entry: x in cur_x, y in cur_y
- ; on exit: dx = chars left on line, di = address
- ; Alters ax, bx.
- xy_to_regs proc near
- ; Find number of chars til end of line, keep in DX
- mov ax,max_cur_x
- xor bx,bx ; BX = cur_x
- xchg bl,ah ; AX = max_x
- mov dx,ax
- sub dx,bx ; DX is # of chars till EOL
- ; Calculate DI = current address in text buffer
- mul cur_y
- add ax,bx ; AX is # of chars into buffer
- shl ax,1
- add ax,[video_off]
- mov di,ax ; DI is now offset of cursor.
- ret
- xy_to_regs endp
-
-
- ;------- strategy ----------------------------------------------------
- ; DOS calls strategy with a request which is to be executed later.
- ; Strategy just saves the request.
-
- strategy proc far
- mov cs:req_off,BX
- mov cs:req_seg,ES
- ret
- strategy endp
-
- ;------ interrupt -----------------------------------------------------
- ; This is where the request handed us during "strategy" is
- ; actually carried out.
- ; Calls one of 12 subroutines depending on the function requested.
- ; Each subroutine returns with exit status in AX.
-
- interrupt proc far
- sti
- push_all
-
- ; Read requested function information into registers
- lds bx,cs:req_ptr
- mov al,2[BX] ; al = function code
- les si,14[BX] ; ES:SI = input/output buffer addr
- mov cx,18[BX] ; cx = input/output byte count
-
- cmp al,max_cmd
- ja unk_command ; too big, exit with error code
-
- mov bx,ax
- shl bx,1 ; form index to table of words
- mov ax,cs
- mov ds,ax
- call word ptr dos_fn_tab[bx]
- int_done:
- lds bx,cs:req_ptr ; report status
- or ax,100h ; (always set done bit upon exit)
- mov 3[bx],ax
-
- pop_all ; restore caller's registers
- ret ; return to DOS.
-
- unk_command:
- call badcmd
- jmp int_done
-
- interrupt endp
-
- ;----- BIOS break handler -----------------------------------------
- ; Called by BIOS when Control-Break is hit (vector was set up in Init).
- ; Simply notes that a break was hit. Flag is checked during input calls.
-
- break_handler proc
- mov cs:brkkey.len, 1
- iret
- break_handler endp
-
-
- ;------ badcmd -------------------------------------------------------
- ; Invalid function request by DOS.
- badcmd proc near
- mov ax, 813h ; return "Error: invalid cmd"
- ret
- badcmd endp
-
-
- ;------- dos function #4 -----------------------------------------------
- ; Reads CX characters from the keyboard, places them in buffer at ES:SI.
- dosfn4 proc near
- jcxz nopcmd
- mov di,si
- dos4lp: push cx
- call getchar
- pop cx
- stosb
- loop dos4lp
- dosfn4 endp
-
- ;------ nopcmd -------------------------------------------------------
- ; Unimplemented or dummy function request by DOS.
- ; also used as a central not-busy exit for othere functions
- nopcmd proc near
- xor ax, ax ; No error, not busy.
- ret
- nopcmd endp
-
- ;-------- dos function #5: non-destructive input, no wait ------
- ; One-character lookahead into the keyboard buffer.
- ; If no characters in buffer, return BUSY; otherwise, get value of first
- ; character of buffer, stuff into request header, return DONE.
- dosfn5 proc near
- call peekchar
- jz busy
- lds bx,req_ptr
- mov [bx+0Dh], al
- jmp nopcmd ; No error, not busy.
- dosfn5 endp
-
- ;-------- dos function #6: input status --------------------------
- ; Returns "busy" if no characters waiting to be read.
- dosfn6 proc near
- call peekchar
- jnz nopcmd ; No error, not busy.
- dosfn6 endp
-
- ;------ busy --------------------------------------------------------
- ; corollary to nopcmd
- busy proc near
- mov ax, 200h ; No error, busy.
- ret
- busy endp
-
- ;-------- dos function #7: flush input buffer --------------------
- ; Clears the IBM keyboard input buffer. Since it is a circular
- ; queue, we can do this without knowing the beginning and end
- ; of the buffer; all we need to do is set the tail of the queue
- ; equal to the head (as if we had read the entire queue contents).
- ; Also resets all the device driver's stuffahead buffers.
- dosfn7 proc near
- mov ax, abs40
- mov es, ax
- mov ax, es:buffer_head ; clear queue by making the tail
- mov es:buffer_tail, ax ; equal to the head
- xor ax, ax ; No error, not busy
- mov fnkey.len, ax ; Reset the stuffahead buffers.
- mov cprseq.len, ax
- mov brkkey.len, ax
- if fullscreen
- mov scrnbuf.len, ax
- endif
-
- ret
- dosfn7 endp
-
-
- ;------ int_29 ----------------------------------------------
- ; Int 29 handles DOS quick-access putchar.
- ; Last device loaded with attribute bit 4 set gets accessed for
- ; single-character writes via int 29h instead of via interrupt.
- ; Must preserve all registers.
- ; Installed as int 29h by dosfn0 (init).
- int_29_buf db ?
-
- int_29 proc near
- sti
- push_all
- mov cx,1
- mov bx,cs
- mov es,bx
- mov ds,bx
- mov si,offset int_29_buf
- mov [si],al
- call dosfn8
- pop_all
- iret
- int_29 endp
-
- ;------ dosfn8 -------------------------------------------------------
- ; Handles writes to the device (with or without verify).
- ; Called with
- ; CX = number of bytes to write
- ; ES:SI = transfer buffer
- ; DS = CS, so we can access local variables.
-
- dosfn8 proc near
-
- mov f_cptr_seg, es ; save segment of char ptr
-
- ; Read the BIOS buffer address/cursor position variables.
- mov ax,abs40
- mov ds,ax
- assume ds:abs40
-
- ; Find current video mode and screen size.
- mov ax, crt_len
- mov cs:screen_len, ax
-
- mov ax,word ptr crt_mode ; al = crt mode; ah = # of columns
- mov cs:video_mode, al
- mov al, crt_rows
- mov cs:max_coords,ax ; one based
-
- ; Find current cursor coordinates.
- mov al,active_page
- mov cs:cur_page,al
- cbw
- shl ax,1
- mov bx,ax
- mov ax,cursor_posn[bx]
- mov cs:cur_coords,ax
-
- ; Find video buffer segment address; adjust so ofs is 0; return in AX.
- mov ax,crt_start
- mov cs:video_off,ax
- mov ax,addr_6845 ; 6845 address
-
- mov dx,cs
- mov ds,dx
- assume ds:code
-
- mov port_6845,ax
- call xy_to_regs ; Set DX, DI according to cur_coords.
-
- ; | If in graphics mode, clear old pseudocursor
- ; and set graphics mode flag
- mov bx,0B800h ; segment for colour text
- mov al,video_mode
- cbw
- cmp al, 4
- jb d8_no_cp
- mov bh,0B0h ; if text, it's a monochrome card..
- cmp al, 7
- jz d8_no_cp
- call pseudocursor ; write block in xor, make al nonzero
- d8_no_cp:
- mov es,bx
- mov word ptr video_mode,ax ; store zero if text mode
- mov ax, string_attrib
- mov ds, f_cptr_seg ; get segment of char ptr
- assume ds:nothing
- cld ; make sure we'll increment
-
- ; Get a character, put it on the screen, repeat 'til end of line
- ; or no more characters.
- jcxz f_loopdone ; if count = 0, we're already done.
-
- cmp cs:escvector, 0 ; If in middle of an escape sequence,
- jnz f_in_escapex ; jump to escape sequence handler.
-
- f_tloop:
-
- ; If not in graphics mode, jump to alternate loop
- ; What a massive kludge! A better approach would have been
- ; to collect characters for a "write n chars" routine
- ; which would handle both text and graphics modes.
- cmp cs:gmode_flag,dh
- jnz f_g_cloop
-
- f_t_cloop:
- lodsb ; get char! (al = ds:[si++])
- cmp al,28 ; is it a control char?
- jb f_control ; maybe...
- f_t_nctl:
- stosw ; Put Char! (es:[di++] = ax)
- dec dx ; count down to end of line
- loopnz f_t_cloop ; and go back for more.
- jnz f_loopdone
-
- f_at_eol: ; at end of line; maybe do a crlf.
- ;----- Handle overrunning right end of screen -------
- ; cx++; compensate for double loop
- ; if (!wrap_flag) { dx++; di-=2; }
- ; else do_crlf;
- inc cx
- cmp cs:wrap_flag, dh
- jz reverse
- feol_wrap:
- ; dx=max_x; set bx= chars left in line
- ; di -= 2*(max_x);
- ; do_lf
- mov dl, cs:max_x
- sub di, dx
- sub di, dx
- jmp f_lf
-
- f_g_cloop:
- lodsb ; get char! (al = ds:[si++])
- cmp al,28 ; is it a control char?
- jb f_control ; maybe...
- f_g_nctl:
- call putchar
- dec dx ; count down to end of line
- loopnz f_g_cloop ; and go back for more.
- jmp short f_t_at_eol
-
- f_looploop:
- or dx,dx
- f_loop_nocheck: ; in case we switched into
- loopnz f_tloop ; a graphics mode
- f_t_at_eol:
- jz f_at_eol
- f_loopdone:
-
- ;--------- All done with write request -----------
- ; DI is cursor address; cursor position in cur_y, dl.
- mov ax, cs
- mov ds, ax ; get our segment back
- assume ds:code
-
- ; Restore cur_x = max_x - dx
- mov al, max_x
- sub al, dl
- mov cur_x, al
- ; Set cursor position; cursor adr in DI; cursor pos in cur_x,cur_y
- call set_pseudocursor
- ; Return to DOS.
- xor ax, ax ; No error, not busy.
- ret
-
- f_in_escapex:
- jmp f_in_escape
-
-
- f_bs: ;----- Handle backspace -----------------
- ; Moves cursor back one space without erasing. No wraparound.
- cmp dl, cs:max_x ; wrap around to previous line?
- jb reverse ; if not, back up
-
- if wrap_left
- fbs_wrap: ; else do some checks
- cmp cs:wrap_flag,dh ; do we want a wrap?
- jz f_looploop ; no; leave
- cmp cs:cur_y,dh ; top left corner?
- jz f_looploop ; if so, ditto
- dec cs:cur_y
- mov dl,dh ; else 0 char left on line
- else
- jmp f_looploop
- endif
- reverse:
- dec di ; back up one char & attrib
- dec di
- inc dx ; and note one more char left on line.
- jmp f_loop_nocheck
-
- assume ds:nothing
- ;---- handle control characters ----
- ; Note: cur_x is not kept updated in memory, but can be
- ; computed from max_x and dx.
- ; Cur_y is kept updated in memory.
- f_control:
- cmp al,13 ; carriage return?
- jz f_cr
- cmp al,10 ; line feed?
- jz f_lf
- cmp al,27 ; Is it an escape?
- jz f_escapex
- cmp al,8 ; backspace?
- jz f_bs
- cmp al,9 ; tab?
- jz f_tabx
- cmp al,7 ; bell?
- jz f_bell
-
- if avatar
- cmp al,12 ; AVT clearscreen?
- jz avt_clsx
- cmp al,22 ; AVT escape?
- jz f_avatarx
- cmp al,16 ; DLE?
- jz dlex
- cmp al,25 ; RLE?
- jz rlex
- f_nctl:
- endif
- ; not a control char
- cmp cs:gmode_flag,dh
- jnz f_g_nctl
- jmp f_t_nctl
-
- f_escapex:
- jmp f_escape
-
- if avatar
- avt_clsx:
- jmp avt_cls
- f_avatarx:
- jmp f_avatar
- dlex:
- jmp dle
- rlex:
- jmp rle
-
- endif
-
- f_bell: ;----- Handle bell ----------------------
- call beep ; >DING<
- jmp f_looploop ; Let main loop decrement cx.
-
- f_cr: ;----- Handle carriage return -----------
- ; di -= cur_x<<1; set di= address of start of line
- ; dx=max_x; set bx= chars left in line
- mov al, cs:max_x
- mov ah,dh
- sub ax,dx ; Get cur_x into ax.
- sub di,ax
- sub di,ax
- add dx,ax
- mov ax,cs:string_attrib ; restore current attribute
- jmp f_loop_nocheck ; and let main loop decrement cx
-
- f_tabx: jmp f_tab
-
-
- f_lf: ;----- Handle line feed -----------------
- ; if (cur_y >= max_y) scroll; scroll screen up if needed
- ; else { cur_y++; di += max_x; else increment Y
-
- mov al,cs:Cur_y
- sub al,cs:Max_y ; do we need to scroll screen?
- jb flf_noscroll ; yes, do it
-
- sub cs:cur_y,al
- inc ax
- push cx
- push dx
- call get_blank_attrib ; ah is attribute to use
- mov bh,ah ; color to use on new blank areas
- xor cx,cx
-
- if direct_scroll
- cmp cs:gmode_flag,dh
- jnz flf_scrollit
-
- mov ah,dh ; ax has count of lines to scroll
- mov cl,cs:max_x ; cx
- shl cx,1 ; counted in bytes
- mul cx ; multiply it by the overflow
- mov dx,cx ; save our screen width
- sub di,ax ; bring back pointer scrolled distance
- add di,dx ; then add one blank line
- xchg bx,ax ; and save it for later
-
- push ds
- push si
- push di
- mov cx,es
- mov ds,cx ; set DS to video segment
- mov di,cs:[video_off] ; and SI and DI to start of screen
- mov si,di
- add si,bx
- mov cx,cs:[screen_len] ; get the length of the screen
- sub cx,dx ; less however many lines
- shr cx,1 ; in words
- rep movsw ; scroll it
- mov cx,bx ; CX is chars per line
- shr cx,1
- mov al," " ; AH still blank attribute
- rep stosw ; clear the bottom line
- pop di
- pop si
- pop ds
- else
- jmp short flf_scrollit
- endif
-
- flf_scroll_done:
- pop dx
- pop cx
- mov ax,cs:string_attrib ; restore current attribute
- jmp f_looploop ; and let main loop decrement cx
-
- flf_scrollit:
- mov dl,al
- add dx,cs:max_coords
- dec dx
- xchg dl,dh
- dec dx
- mov ah,06 ; BIOS scroll al lines.
- int 10h ; call BIOS to scroll a rectangle.
- jmp short flf_scroll_done
-
- flf_noscroll:
- inc cs:cur_y
- mov al,cs:Max_x
- mov ah,dh
- shl ax,1
- add di,ax
- mov ax,cs:string_attrib ; restore current attribute
- jmp f_looploop ; and let main loop decrement cx
-
-
- f_tab: ;----- Handle tab expansion -------------
- push cx ; save cx
- ; Calculate number of spaces to output.
- mov cx,dx
- sub cl,cs:max_x ; cx=0-cur_x
- dec cx ; raise floor and ceiling
- and cx,7 ; 0-7
- inc cx ; 1-8
-
- ; ah is still current attribute. Move CX spaces to the screen.
- mov al, ' '
- cmp cs:gmode_flag,dh
- jnz f_tp_lp
- sub dx, cx ; update chars-to-eol, maybe set z
- jae nochop ; in case width is not a multiple of 8
- add cx,dx ; chop the tab so we don't get a neg DX
- xor dx,dx
- nochop: rep stosw
- pop cx ; restore cx
- jmp f_loop_nocheck ; Let main loop decrement cx.
-
- ;--------------- graphics mode support -----------------------
-
- f_tp_lp: ; graphics mode- call putc to put the char
- call putchar
- dec dx ; go to next cursor position
- loopnz f_tp_lp
- pop cx
- jmp f_loop_nocheck
-
-
- ;---- set_pseudocursor ------------
- ; If in graphics mode, set pseudocursor, else set real cursor.
- ; Destroys DS!!!!
- assume ds:code
-
- set_pseudocursor proc near
- cmp gmode_flag,dh
- jnz pseudocursor
-
- SET_CURS: ; Write directly to 6845 cursor address register.
- mov bx,di
- shr bx,1 ; convert word index to byte index
-
- mov dx,Port_6845
- mov al,0Eh
- out dx,al
- hold
-
- inc dx
- mov al, bh
- out dx, al
- hold
-
- dec dx
- mov al, 0fh
- out dx, al
- hold
-
- inc dx
- mov al, bl
- out dx, al
-
- mov al,cur_page
- cbw
- shl ax,1
- mov bx,ax
- mov ax,cur_coords
-
- ; Set cursor position in low memory.
- mov dx, abs40
- mov ds, dx
- assume ds:abs40
-
- mov cursor_posn[bx],ax
- ret
-
- set_pseudocursor endp
-
- assume ds:code
-
- ;---- pseudocursor --------------------------------------------------
- ; If pseudo_flag is true, writes a color 15 block in XOR at the
- ; current cursor location, and sets cursor position.
- ; Otherwise, just sets cursor position.
-
- pseudocursor proc near
- cmp pseudo_flag, 0
- jnz psc_pseudo
- push dx ; flag off - don't draw
- mov dx, cur_coords ; get X & Y into DX
- mov bh, cur_page ; supposed to be zero in graph modes?
- mov ah, 2 ; chose "Set Cursor Position"
- int 10h ; call ROM BIOS
- pop dx
- ret
-
- psc_pseudo:
- mov ax, 8F16h ; xor, color 15, ^V (small block)
- ; fall through to putchar
- pseudocursor endp
-
-
- ;---- putchar ------------------------------------------------
- ; Writes char AL, attribute AH to screen at (max_x+1-dl), cur_y.
- ; On entry, registers set up as per xy_to_regs.
- ; Preserves all registers.
- assume ds:nothing
-
- putchar proc near
- push ax
- push bx
- push cx
- push dx
- ; 1. Set cursor position.
-
- sub dl, cs:max_x
- neg dx
-
- mov dh, cs:cur_y ; get X & Y into DX
- mov bh, cs:cur_page ; choose page
- mov bl,ah ; attribute in BL for part 2.
- mov ah, 2 ; chose "Set Cursor Position"
- int 10h ; call ROM BIOS
- ; 2. Write char & attribute.
- mov cx,1
- mov ah,9
- int 10h
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- putchar endp
-
- ;--------------- end of graphics mode support --------------------
-
- dosfn8 endp
-
- ;--- get_blank_attrib ------------------------------------------------
- ; Determine new attribute and character for a new blank region.
- ; Use current attribute, just disallow blink and underline.
- ; (Pretty strange way to do it. Might want to disallow rev vid, too.)
- ; Returns result in AH, preserves all other registers.
- get_blank_attrib proc near
- xor ah,ah
- cmp cs:gmode_flag,ah
- jnz gb_aok ; if graphics mode, 0 is bkgnd
- mov ah, cs:cur_attrib
- and ah,7fh ; disallow blink
- cmp cs:video_mode,7 ; monochrome?
- jne gb_aok
- cmp ah,1 ; underline?
- jne gb_aok
- mov ah,7 ; yep- set it to normal.
- gb_aok: ret
- get_blank_attrib endp
-
- ;---- beep ------------------------------------------------------
- ; Beep speaker; period given by beep_div, duration by beep_len.
- ; Preserves CX and DX
-
- beep_div equ 1300 ; fairly close to IBM beep
- beep_len equ 2 ; 2/18 sec- shorter than IBM
-
- beep proc near
- push cx
- push dx
-
- mov al,10110110b ; select 8253
- mov dx,43h ; control port address
- out dx,al
- dec dx ; timer 2 address
- mov ax, beep_div
- out dx,al ; low byte of divisor
- mov al,ah
- out dx,al ; high byte of divisor
- mov dx,61h
- in al,dx ; get current value of control bits
- push ax
- or al, 3
- out dx,al ; turn speaker on
-
- ; Wait for desired duration by monitoring time-of-day 18 Hz clock
- push ds
- mov ax,abs40
- mov ds,ax
- assume ds:abs40
-
- mov bx, timer_low
- mov cx, -1 ; emergency, in case clock dead
-
- beeplp: mov ax, timer_low
- sub ax,bx
- cmp ax, beep_len
- jg beepover
- loop beeplp
- beepover:
-
- pop ds
- assume ds:nothing
- pop ax
- and al, not 3 ; turn speaker off
- out dx,al
- pop dx
- pop cx
- ret
- beep endp
-
- CODE ends
- end