; DISPLAY.ASM - contains a collection of video-related procedures and
;               functions for use with Microsoft high-level languages.
;
;   Author:     Christy Gemmell
;   For:        Assembly-Language Toolbox for QuickBASIC
;   Version:    4.06
;   Date:       22/9/1990
;
;   Compatible with the QuickBASIC 4.0, 4.5 and BASIC 6 compilers
;   Assembled using Microsoft Macro Assembler, MASM version 5.1
;
;   Global symbols and procedures.
;
                .model  medium

                public  ScreenAddress, ScreenWrite
                public  VideoType, FastPrint

                .code

;   Data Division.
;
;   Video parameters - default to monochrome screen display
;
SnowFlag        db      0               ; Snow prevention flag
VideoRam        dw      0B000h          ; Current video segment
VideoPort       dw      03BAh           ; Current video status port
Param1          label   word
Mode            db      7               ; Current screen mode
Columns         db      80              ; Current screen width
Param2          label   word
Rows            db      25              ; Current screen length
ActivePage      db      0               ; Current video page

;Listing 1.1     Collect video information

;  Collect information about the current video display.
;
;   Returns:    AL =    Current display mode
;               AH =    Screen width in columns
;               BL =    Screen height in rows
;               BH =    Active display page
;
;  The correct video display segment and CRT status port addresses are
;  determined for the current system and, if necessary, the internal
;  'snow' prevention flag is set.
;
VideoType       proc    far
                push    cx                      ; Preserve these
                push    dx                      ;    registers
                push    es                      ;
                push    bp                      ;Added this [DEC]
                mov     ah,0Fh                  ; ROM-BIOS Service 16
                int     10h                     ; - Check video mode
                cmp     al,7                    ; Monochrome display?
                je      Type_02                 ; Yes, use defaults
                mov     cs:VideoRam,0B800h      ; Otherwise set up
                mov     cs:VideoPort,03DAh      ;    for colour
Type_01:
                mov     cs:Param1,ax            ; Save display mode
                                                ;    and width
                push    bx                      ; Save active display
                xor     bh,bh                   ;    page
                mov     dl,24                   ; Default to 25 rows
                mov     ax,1130h                ; ROM-BIOS Service 16
                int     10h                     ;  - get font
                pop     bx                      ;    information
                mov     bl,dl                   ; DL = rows - 1
                inc     bl                      ; Save video page     
                mov     cs:Param2,bx            ;    and height
                mov     bl,10h                  ; Test for presence
                mov     ah,12h                  ;    of an EGA or VGA
                int     10h                     ;      display adaptor
                cmp     bl,10h                  ; Any response?
                jne     Type_02                 ; Yes, can't be a CGA
                mov     cs:SnowFlag,1           ; Set snow prevention
Type_02:                                        ;    flag
                mov     bx,cs:Param2            ; Recover page and
                                                ;    screen height
                mov     ax,cs:Param1            ; Recover screen mode
                                                ;    and width
                pop     bp                      ;added [DEC]
                pop     es                      ; Clean up the stack
                pop     dx
                pop     cx
                ret                             ; Return to caller
VideoType       endp

;Listing 1.2     Convert row/column co-ordinates to an address

;   Calculate address from a pair of row/column co-ordinates.
;
;   Given the row/column column co-ordinate of a character on the
;   screen, this function returns the segment:offset address of that
;   character in video memory. The address is correctly adjusted to
;   the start of the the currently active display page, but no check
;   is made to ensure that the co-ordinates supplied are within the
;   actual screen bounds.
;
;   Input:     AL      = Row co-ordinate of character (base zero).
;              AH      = Column co-ordinate of character (base zero).
;   Output:    ES:DI==>  Address in video display buffer of the
;                         character cell specified.
;              DX      = CRT status register port address.
;
;   It is assumed that a previous call has been made to the VideoType
;   function to determine the screen width, the port address of the
;   CRT status register and the correct video display segment.
;
ScreenAddress  proc    far
               push    ax               ; Save working registers
               push    bx
               mov     bh,ah            ; Column to BH
               mov     bl,cs:Columns    ; Get current screen width
               shl     bl,1             ; Add in attribute bytes
               mul     bl               ; Multiply by row number
               xor     bl,bl            ; Calculate
               xchg    bh,bl            ;    column offset
               shl     bl,1             ;      in BX
               add     ax,bx            ; Add it to the row offset
               mov     di,ax            ;    and copy to DI
               xor     ax,ax            ; Index to ROM-BIOS
               mov     es,ax            ;    data in low memory
               mov     ax,es:[44Eh]     ; Get offset of current page
               add     di,ax            ; Adjust target pointer
               mov     es,cs:VideoRam   ; Return segment of video RAM
               mov     dx,cs:VideoPort  ; Return CRT status port
               pop     bx               ; Clean up the stack
               pop     ax
               ret                      ;    and return to caller
ScreenAddress  endp

;Listing 1.3     Output a character and attribute to the screen.
;
;   Output a character and attribute to the video display.
;
;   If the 'snow prevention' flag is set, this routine waits until the
;   beginning of the next CRT horizontal retrace period before writing
;   data to the display. This is necessary only on computers fitted
;   with Colour Graphics Adaptor (CGA) which may suffer from glitches
;   or screen snow if data is written to the screen while the video
;   buffer is being refreshed.
;
;   Input:      ES:DI==>    Address in the video display buffer where
;                           the data is to be written.
;               DX =        Port address of CRT status register.
;               AL =        Character to output.
;               AH =        Display attribute of character.
;
;   Output:     DI          Updated to point to next output address.
;
ScreenWrite     proc    far
                push    bx              ; Preserve BX
                cmp     cs:SnowFlag,0   ; Snow prevention needed?
                cli                     ; Don't interrupt!
                jz      Write_3         ; No, don't bother
                mov     bx,ax           ; Save byte and attribute
Write_1:
                in      al,dx           ; Read video port
                test    al,1            ; Test bit zero
                jnz     Write_1         ; Wait until it's reset
Write_2:
                in      al,dx           ; Read port again
                test    al,1            ; Test bit zero
                jz      Write_2         ; Wait until it's set
                mov    ax,bx            ; Recover data
Write_3:
                stosw                   ; Write data to screen
                sti                     ; Restore interrupts
                pop     bx              ; Restore BX
                ret
ScreenWrite     endp

;Listing 1.4     Main program module.

;   Fast screen printing.
;
;   This procedure outputs text directly to the video display without
;   going through DOS or ROM-BIOS services.
;
FastPrint       proc    far
                push    bp              ; Save Base pointer
                mov     bp,sp           ; Establish stack frame
                push    es              ; Save Extra Segment
                push    si              ;    and index pointers
                push    di
                call    VideoType       ; Get video parameters
                mov     dh,ah           ; Load screen dimensions
                mov     dl,bl           ;    into DX
                mov     ax,[bp+12]      ; Get row number
                dec     al              ; Convert to base zero
                cmp     al,0            ; Top screen row?
                jae     Fast_01         ; Jump if not below
                xor     al,al           ; Don't go over the top!
Fast_01:
                cmp     al,dl           ; Bottom row?
                jb      Fast_02         ; Go no further
                mov     al,dl
                dec     al
Fast_02:
                mov     bx,[bp+10]      ; Get column number
                mov     ah,bl           ;    into AH
                dec     ah              ; Convert to base zero
                cmp     ah,0            ; Leftmost column?
                jae     Fast_03         ; Jump if not below
                xor     ah,ah           ; Don't go off the screen
Fast_03:
                cmp     ah,dh           ; Rightmost column?
                jb      Fast_04         ; Go no further
                mov     ah,dh           ; Don't go off the screen
                dec     ah              ; Base zero, remember?
Fast_04:
                call    ScreenAddress   ; Calculate target address
                mov     bx,[bp+8]       ; Index to string descriptor
                mov     cx,[bx]         ;    Get string length
                cmp     cx,0            ; Make sure it isn't
                ja      Fast_05         ;    a null string
                mov     ax,1            ; If so set Error code
                jmp     short Fast_07   ;    and abort
Fast_05:
                mov     si,[bx+2]       ; DS:SI==> string data
                mov     ax,[bp+6]       ; Get display attribute
                xchg    ah,al           ;    into AH
                cld                     ; Clear direction flag
Fast_06:
                lodsb                   ; Get a byte from the string
                call    ScreenWrite     ; Write byte and attribute
                loop    Fast_06         ; For length of string
                xor     ax,ax           ; Report success
Fast_07:
                pop     di              ; Clean up the stack
                pop     si
                pop     es
                pop     bp
                ret     8               ; Return to QuickBASIC
FastPrint       endp

end
