home *** CD-ROM | disk | FTP | other *** search
- ;_ disp.asm Wed Mar 23 1988 Modified by: Walter Bright */
- ; Copyright (C) 1986-1988 by Northwest Software
- ; All Rights Reserved
- ; Written by Walter Bright
-
- ; Fast screen display package
-
- include macros.asm
-
- video_io macro
- int 10h
- endm
-
- ;ASCII values
- DEL equ 07Fh ;DEL character
-
- begdata
-
- public _disp_numrows,_disp_numcols
- _disp_numrows dw 25 ;# of rows in display
- _disp_numcols dw 0 ;# of columns in display
-
- scrnrowcol label word ;row,col of actual screen cursor
- scrncol db ?
- scrnrow db ?
-
- public _disp_cursorrow,_disp_cursorcol
- _disp_cursorrow dw ? ;row,col of where we want the cursor to be
- _disp_cursorcol dw ?
-
- normatt equ 07h ;white chars on black background
- stndatt equ 070h ;inverse video
- att db normatt ;current attribute
-
- public _disp_mono,_disp_base,_disp_snowycga,_disp_mode,_disp_inited
- public _disp_ega,_disp_activepage
- _disp_mono db 1 ;0 for color, 1 for monochrome
- _disp_snowycga db 1 ;if 1, then the display is an IBM snowy CGA
- _disp_mode db ? ;what is the current display mode?
- _disp_inited db 0 ;1 if display package is opened
- _disp_ega db 0 ;1 if IBM EGA
- _disp_activepage db 0 ;which page to read/write
- _disp_displaypage db 0 ;which page is displayed
- _disp_base dw 0B000h ;segment of base of video screen
- ; (default is mono)
- ;if 0, then not available (use BIOS)
-
- cursortype dw ? ;where we save the cursor type
-
- enddata
-
- begcode disp
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Set things up. That is, determine what display we've got.
-
- c_public disp_open
- func disp_open
- .if _disp_inited e 0, Q4 ;if not already initialized
- ret
-
- Q4: mov _disp_inited,1
- push BP
- .save DI
- pushES
-
- ;Determine number of rows, also if we have an EGA
- clr DX ;default value
- clr BH
- mov AX,01130h ;inquire info from EGA BIOS
- video_io
- tst DL ;Check if DL is still zero
- jz L3 ;if so, no EGA
- mov _disp_ega,1 ;flag that we have an EGA
- mov _disp_snowycga,0 ;EGAs don't snow
- inc DL
- mov _disp_numrows,DX ;number of rows
- L3:
-
- mov AH,15
- video_io
- mov byte ptr _disp_numcols,AH ;set number of columns
- mov _disp_mode,AL ;save display mode
- .if AL ne 7, Q2 ;if not mono mode
- mov _disp_snowycga,0 ;mono displays don't snow
-
- ;Do an equipment check to see if this is really a mono card.
- ;Note that the COMPAQ can be in mode 7, but still be a color card!
- int 11h ;Equipment Determination BIOS call
- and AX, 00110000b ;isolate initial video mode bits
- .if AX e 00110000b, L1 ;yes, it is a real mono card
- mov AL,7 ;mode 7
- jmps L51
-
- Q2: .if AL e 15, L51 ;if EGA monochrome graphics mode
- mov _disp_mono,0 ;else color display
- L51: mov _disp_base,0B800h ;base of color adapter
- .if AL be 3, L1 ;if color text mode
- .if AL e 7, L1 ; or mono text mode
- mov _disp_base,0 ;use BIOS instead of direct access to video ram
- ; for all graphics and other unrecognized modes
- jmps L50
- L1:
- ;Find out if we are running under DESQview.
- ;This section provided by Erik Lindberg.
- mov AX,2B01h ; Get DESQview version (set date)
- mov CX,'DE' ; if CX,DX = 'DESQ', is invalid
- mov DX,'SQ' ; setdate call.
- int 21h ; DOS interrupt.
- cmp AL,0FFh ; check for invalid return.
- jz L2 ; then DESQview is not running.
- mov ES,_disp_base ; get pre-determined buffer address (_disp_base:0)
- clr DI ; into ES:DI
- mov AH,0FEh ; load function code into AH
- video_io ; to request alternate buffer address.
- mov _disp_base,ES ; and save it.
- L2:
-
- ;determine where cursor is
- L50: mov AH,3
- video_io
- mov cursortype,CX ;save original cursor type
- mov scrnrow,DH
- mov scrncol,DL
- mov AL,DH
- cbw
- mov _disp_cursorrow,AX
- clr DH
- mov _disp_cursorcol,DX
-
- popES
- .restore DI
- pop BP
- ret
- c_endp disp_open
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Close things up
-
- c_public disp_close
- func disp_close
- .if _disp_inited e 0, Q3 ;quit if never opened
- push BP
- callm disp_flush ;flush all output
- mov AH,1
- mov CX,cursortype ;restore original cursor type
- video_io
- mov _disp_inited,0
- pop BP
- Q3: ret
- c_endp disp_close
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Be BIOS compatible, instead of poking directly into the screen
- ; memory.
-
- c_public disp_usebios
- func disp_usebios
- mov _disp_base,0
- ret
- c_endp disp_usebios
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Set cursor type.
- ; Use:
- ; disp_setcursortype(startline*256 + endline);
-
- c_public disp_setcursortype
- func disp_setcursortype
- push BP
- mov BP,SP
- mov CX,P[BP]
- mov AH,1
- video_io
- pop BP
- ret
- c_endp disp_setcursortype
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Put a character into the display.
- ; Behave as a dumb terminal.
- ; Returns character passed.
-
- c_public disp_putc
- func disp_putc
- push BP
- mov BP,SP
- mov AL,P[BP] ;char
- .if AL b ' ', docntl ;control char
- .if AL z DEL, zip1 ;ignore rubouts
- doout: call near ptr outchr ;display character
- mov AX,_disp_cursorcol
- inc AX ;next column
- .if AX ae _disp_numcols, L19 ;if on or past right edge
- L20: mov _disp_cursorcol,AX
- zip1: clr AH
- mov AL,P[BP]
- pop BP
- ret
-
-
- L19: clr AX
- mov BX,_disp_cursorrow ;get row and column
- inc BX ;start of next row
- .if BX b _disp_numrows, L18 ;if not past bottom
- call near ptr scrollup ;scroll up 1 line
- clr AX
- mov BX,_disp_numrows ;lower left corner
- dec BX
- L18: mov _disp_cursorrow,BX
- jmp L20
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Handle control characters
-
- docntl: clr AH
- mov BX,AX
- add BX,AX
- jmp CS:word ptr (offset cntltab)[BX]
-
- cntltab:
- if LCODE
- dw doout
- dw doout
- dw doout
- dw doout
- dw doout
- dw doout
- dw doout
- dw beep,dobs,dotab,donl ;BEL,BS,TAB,LF
- dw donl,donl ;VT,FF
- dw docr ;CR
- dw doout,doout,doout,doout ;P,XON,R,XOFF
- dw doout,doout,doout,doout,doout,doout,doout
- dw doout ;escape
- dw doout,doout,doout,doout,doout,doout
- else
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:beep,offset _TEXT:dobs ;BEL,BS
- dw offset _TEXT:dotab,offset _TEXT:donl ;TAB,LF
- dw offset _TEXT:donl,offset _TEXT:donl ;VT,FF
- dw offset _TEXT:docr ;CR
- dw offset _TEXT:doout,offset _TEXT:doout
- dw offset _TEXT:doout,offset _TEXT:doout ;P,XON,R,XOFF
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout ;escape
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- dw offset _TEXT:doout
- endif
-
- ;;;;;;;;;;;;;;;;;;;;;;
- ; Bell
-
- beep: mov DL,7
- bdos 2 ;send a bell to DOS
- mov AX,7
- pop BP
- ret
-
- ;;;;;;;;;;;;;;;;;;;;
- ; Backspace (non-destructive)
-
- dobs: mov BX,_disp_cursorcol
- dec BX ;backup 1 column
- js L140 ;oops! already in column 0
- mov _disp_cursorcol,BX
- L140: pop BP
- ret
-
- ;;;;;;;;;;;;;;;;;;;;
- ; Carriage return
-
- docr: mov _disp_cursorcol,0 ;reset column
- pop BP
- ret
-
- ;;;;;;;;;;;;;;;;;;;
- ; Line feed
-
- donl: mov _disp_cursorcol,0 ;reset column to start of line
-
- dolf: mov DX,_disp_cursorrow
- inc DX
- .if DX b _disp_numrows, L101
- call near ptr scrollup
- mov AX,0Ah
- pop BP
- ret
-
- L101: mov _disp_cursorrow,DX
- pop BP
- ret
-
- ;;;;;;;;;;;;;;;;;;;
- ; Tab (non-destructive)
-
- dotab:
- mov AX,_disp_cursorcol
- or AX,7
- inc AX ;advance to next tab stop
- .if AX b _disp_numcols, D1
- mov AX,_disp_numcols
- dec AX
- D1: mov _disp_cursorcol,AX
- mov AX,9
- pop BP
- ret
-
- c_endp disp_putc
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Scroll a region of the display.
- ; void disp_scroll(lines,ulrow,ulcol,lrrow,lrcol,att);
- ; lines > 0: scroll up
- ; lines == 0: blank window
- ; lines < 0: scroll down
-
- c_public disp_scroll
- func disp_scroll
- push BP
- mov BP,SP
- mov AL,P[BP]
- mov CH,P+2[BP]
- mov CL,P+4[BP]
- mov DH,P+6[BP]
- mov DL,P+8[BP]
- mov BH,P+10[BP]
- mov AH,6
- tst AL
- jns scroll1
- neg AL
- inc AH
- scroll1:
- video_io
- pop BP
- ret
- c_endp disp_scroll
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Poke att/char into display at row,column.
- ; void disp_pokew(row,col,attchr);
-
- c_public disp_pokew
- func disp_pokew
- push BP
- mov BP,SP
-
- mov CX,P+4[BP] ;save att/char
- mov DH,P[BP] ;row
- mov DL,P+2[BP] ;column
- .if _disp_base e 0, W7
-
- pushES
- mov AX,_disp_numcols
- mul DH
- clr DH
- add AX,DX ;add in column
- shl AX,1 ;compute offset into screen
- mov BX,AX
- mov ES,_disp_base
- .if _disp_snowycga e 0, W1 ;if skip snow check
-
- mov DX,03DAh ;color card status port
- mov AH,1
-
- W5: in AL,DX ;wait for retrace low
- test AL,AH
- jnz W5
- cli ;turn off interrupts
- W6: in AL,DX ;wait for retrace high
- test AL,AH
- jz W6
-
- mov ES:[BX],CX ;poke it
- sti ;enable interrupts
- popES
- pop BP
- ret
-
- W1: mov ES:[BX],CX ;poke it
- popES
- pop BP
- ret
-
- W7: mov scrnrow,DH
- mov scrncol,DL
- mov BH,_disp_activepage ;page number
- mov AH,2
- video_io ;set cursor position (BP is destroyed)
- mov AL,CL ;char
- mov BL,CH ;attribute to use
- mov AH,9 ;write att/char at current cursor position
- mov CX,1 ;write one character
- video_io
- pop BP
- ret
-
- c_endp disp_pokew
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Read att/char from display at row,column.
- ; unsigned disp_peekw(row,col);
-
- c_public disp_peekw
- func disp_peekw
- push BP
- mov BP,SP
-
- mov DH,P[BP] ;row
- mov DL,P+2[BP] ;column
- mov scrnrowcol,DX
- mov BH,_disp_activepage ;page number
- mov AH,2
- video_io ;set cursor position (BP is destroyed)
- mov AH,8 ;read att/char at current cursor position
- video_io
- pop BP
- ret
- c_endp disp_peekw
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Display character in AL.
-
- outchr proc near
- .if _disp_base e 0, P7
-
- pushES
- mov CL,AL
- mov CH,att ;attribute to use
- mov AX,_disp_numcols
- mul _disp_cursorrow
- add AX,_disp_cursorcol
- shl AX,1 ;compute offset into screen
- mov BX,AX
- mov ES,_disp_base
- .if _disp_snowycga e 0, P1 ;if skip snow check
-
- mov DX,03DAh ;color card status port
- mov AH,1
- P5: in AL,DX ;wait for retrace low
- test AL,AH
- jnz P5
- cli ;turn off interrupts
- P6: in AL,DX ;wait for retrace high
- test AL,AH
- jz P6
-
- mov ES:[BX],CX ;poke it
- sti ;enable interrupts
- popES
- ret
-
- P1: mov ES:[BX],CX ;poke it
- popES
- ret
-
- P7: push AX
- callm disp_flush ;bring cursor up to date
- pop AX
- mov AH,9 ;write att/char at current cursor position
- mov BH,_disp_activepage ;page number
- mov BL,att ;attribute to use
- mov CX,1 ;write one character
- video_io
- ret
- outchr endp
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Set cursor position
-
- c_public disp_move
- func disp_move
- push BP
- mov BP,SP
- mov AX,P[BP]
- mov _disp_cursorrow,AX
- mov AX,P+2[BP]
- mov _disp_cursorcol,AX
- pop BP
- ret
- c_endp disp_move
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Flush output.
- ; What this does is set the hardware cursor (scrnxxx) to be where
- ; the software cursor (disp_cursorxxx) is. This is only done when
- ; disp_flush() is called because it is a relatively slow operation.
-
- c_public disp_flush
- func disp_flush
- mov DH,byte ptr _disp_cursorrow
- mov DL,byte ptr _disp_cursorcol
- .if DX e scrnrowcol, F1
- mov scrnrowcol,DX
- mov BH,_disp_activepage
- mov AH,2 ;set cursor function
- push BP
- video_io
- pop BP
- F1: ret
- c_endp disp_flush
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Delete to end of line (including cursor position)
-
- c_public disp_eeol
- func disp_eeol
- mov CX,_disp_numcols
- sub CX,_disp_cursorcol ;CX = # of spaces left in line
- mov AX,_disp_numcols
- mul _disp_cursorrow
- add AX,_disp_cursorcol
- jmps clear1
- c_endp disp_eeol
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Delete to end of screen (including cursor position)
-
- c_public disp_eeop
- func disp_eeop
- mov AX,_disp_numcols
- mul _disp_numrows
- mov CX,AX ;CX = # of chars on screen
- mov AX,_disp_numcols
- mul _disp_cursorrow
- add AX,_disp_cursorcol
- sub CX,AX
- clear1:
- .save DI
- shl AX,1
- mov DI,AX
- ; jmps clear
- c_endp disp_eeop
-
- ;;;;;;;;;;;;;;;;;;;;;;;;
- ; Send CX spaces to screen starting at DI.
-
- func clear
- .if _disp_base e 0, C7
-
- pushES
- mov ES,_disp_base
- cld
- mov AL,' '
- mov AH,att
- .if _disp_snowycga ne 0, C1
- rep stosw
- popES
- .restore DI
- ret
-
- C1: mov DX,03DAh ;color card status port
- mov BX,AX
-
- C5: in AL,DX ;wait for retrace low
- test AL,1
- jnz C5
- cli ;turn off interrupts
- C6: in AL,DX ;wait for retrace high
- test AL,1
- jz C6
-
- mov AX,BX
- stosw ;poke it
- sti ;enable interrupts
- loop C5
-
- popES
- .restore DI
- ret
-
- C7: callm disp_flush ;bring cursor up to date
- mov AX,9*256+' ' ;write att/char at current cursor position
- mov BH,_disp_activepage ;page number
- mov BL,att ;attribute to use
- push BP
- video_io
- pop BP
- .restore DI
- ret
- c_endp clear
-
- ;;;;;;;;;;;;;;;;;;;;;;;;
- ; Start/end standout mode.
- ; Set attribute for subsequent writes.
-
- c_public disp_startstand,disp_endstand,disp_setattr
-
- func disp_startstand
- mov att,stndatt
- ret
- c_endp disp_startstand
-
- func disp_endstand
- mov att,normatt
- ret
- c_endp disp_endstand
-
- func disp_setattr
- push BP
- mov BP,SP
- mov AL,P[BP]
- mov att,AL
- pop BP
- ret
- c_endp disp_setattr
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Scroll up 1 line
-
- scrollup proc near
- .if _disp_snowycga ne 0, biosway ;give up and use bios
- .if _disp_base e 0, biosway
- push DS
- pushES
- .save <SI,DI>
- mov AX,_disp_numcols
- mov SI,AX
- mov BX,AX
- mul _disp_numrows
- sub AX,SI
- mov CX,AX ;CX = # of words to scroll
- shl SI,1 ;source is 1 row in
- clr DI
- mov AL,' ' ;char for blank row
- mov AH,att ;attribute for blank row
- mov ES,_disp_base ;point to video segment
- mov DS,_disp_base
- cld ;increment
- rep movsw ;do the scroll
- mov CX,BX ;# of words in bottom row
- rep stosw ;blank bottom row
- .restore <DI,SI>
- popES
- pop DS
- ret
-
- biosway:
- clr CX ;row,col of upper left corner
- mov DX,_disp_numcols ;col of lower right corner
- dec DX
- mov DH,24
- mov BH,att ;att for blank
- mov AX,0601h ;scroll up 1 line
- video_io
- ret
- scrollup endp
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Get and return the current video mode.
-
- c_public disp_getmode
- func disp_getmode
- push BP
- mov AH,15
- video_io
- clr AH
- pop BP
- ret
- c_endp disp_getmode
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Set the video mode.
- ; Do not use while disp package is open.
-
- c_public disp_setmode
- func disp_setmode
- push BP
- mov BP,SP
- clr AH
- mov AL,P[BP]
- video_io
- pop BP
- ret
- c_endp disp_setmode
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Set into 43 line mode.
- ; Do not use while disp package is open.
-
- c_public disp_set43
- func disp_set43
- .if _disp_ega ne 1, S1
- .if _disp_numrows ne 25, S1
- push BP
- mov AX,0003h ;set color mode, 80x43
- .if _disp_mono e 0, S2
- mov AX,0007h ;set monochrome mode, 80x43
- S2: mov _disp_mode,AL ;save display mode
- video_io
- mov AX,01112h ;character generator BIOS routine
- mov BL,0 ;8x8 double dot character font
- video_io
- mov AX,01200h ;alternate screen routine
- mov BL,020h ;alternate print screen routine
- video_io
- ;Must set cursor to be a block else it will disappear
- mov AX,0100h
- mov CX,0007h ;block cursor
- video_io ;set cursor type
-
- S3: mov AX,01130h ;inquire info from EGA BIOS
- video_io
- clr DH
- .if DX ae _disp_cursorrow, S4
- mov _disp_cursorrow,DX ;reset cursor so it's on the screen
- S4: inc DL
- mov _disp_numrows,DX ;set new # of rows
- pop BP
- S1: ret
- c_endp disp_set43
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; Switch from 43 line mode back to 25 line mode.
-
- c_public disp_reset43
- func disp_reset43
- .if _disp_ega ne 1, S1
- .if _disp_numrows be 25, S1
- push BP
- mov AX,0003 ;color, 80x25
- .if _disp_mono e 0, R2
- mov AX,0007 ;mono, 80x25
- R2: mov _disp_mode,AL ;save display mode
- video_io
- mov AX,01101h ;character generator BIOS routine
- mov BL,0
- video_io
- mov AX,01200h
- mov BL,020h
- video_io
- jmp S3 ;determine # of rows
- c_endp disp_reset43
-
- endcode disp
-
- end
-