Metropoli BBS
VIEWER: _svgasdk.asm MODE: TEXT (ASCII)
;****************************************************************************
;*
;*          The SuperVGA Kit - UniVBE Software Development Kit
;*
;*                  Copyright (C) 1996 SciTech Software
;*                          All rights reserved.
;*
;* Filename:    $Workfile:   _svgasdk.asm  $
;* Version:     $Revision:   1.16  $
;*
;* Language:    80386 Assembler
;* Environment: IBM PC Real Mode and 16/32 bit Protected Mode.
;*
;* Description: Assembly language support routines for the UVBELib Software
;*              Development Kit. This code is intended to be used as a guide
;*              for developing software with the UVBELib SuperVGA library.
;*              All the code here assumes that the video memory selector
;*              has been cached in the GS selector before the code is
;*              called.
;*
;* $Date:   05 Sep 1996 14:21:12  $ $Author:   KendallB  $
;*
;****************************************************************************

        IDEAL

include "model.mac"             ; Memory model macros
include "vbeaf.inc"             ; VBE/AF Accelerator Functions
include "svga.inc"              ; SuperVGA Kit structures

header  _svgasdk                ; Set up memory model

CRTC    EQU 3D4h                ; Port of CRTC registers

begdataseg  _svgasdk

DC      EQU     __SV_devCtx     ; Macro to access global structure

        $EXTRN  __SV_devCtx,SV_devCtx_s
        $EXTRN  __SV_pagesize,ULONG
        $EXTRN  __SV_bankShift,UINT
        $EXTRN  __SV_setBankRM,DPTR
        $EXTRN  __SV_setBankPtr,DPTR

if pmode
        $EXTRN  __SV_setBank20,DPTR
        $EXTRN  __SV_setCRT20,DPTR
        $EXTRN  __SV_setPal20,DPTR
        $EXTRN  _VBE_MMIOSel,WORD
endif

enddataseg  _svgasdk

begcodeseg  _svgasdk

ifdef   __WINDOWS32_386__
        EXTRN   _PM_setBankA:FPTR
        EXTRN   _PM_setBankAB:FPTR
        EXTRN   _PM_setCRTStart:FPTR
endif

;----------------------------------------------------------------------------
; loadVidMem    - Macro to load video memory address into es:reg
;----------------------------------------------------------------------------
; This macro loads the video memory address in to ES:REG. For 16 bit code
; this simply loads the 32 bit far pointer into ES:REG. For 32 bit protected
; mode code this simply loads EREG with the offset of the video memory.
;
; For Watcom C++ Win386 mode this function loads EREG with the offset within
; video memory and loads the selector to the video memory into ES. Currently
; we are not able to map linear pointers to video memory in Win386 mode, so
; we need to load a selector to the video memory.
;----------------------------------------------------------------------------
MACRO   lVidMem reg
ifdef   __WIN386__
        movzx   reg,[WORD DC.videoMem]
        mov     es,[WORD (DC.videoMem)+2]
else
        _les    reg,[DC.videoMem]
endif
ENDM

; All banked access to video memory goes via the ES selector for Watcom
; Win386 mode. We also must save/restore the value of ES across functions
; that use it.

ifdef   __WIN386__
_ES     EQU ES:
endif

MACRO   save_es
ifdef   __WIN386__
        push    es
endif
ENDM

MACRO   restore_es
ifdef   __WIN386__
        pop     es
endif
ENDM

;----------------------------------------------------------------------------
; SV_pixelAddr16 - Determine address of pixel in 16 color banked modes
;----------------------------------------------------------------------------
;
; Entry:        _AX -   y-coordinate
;               _BX -   x-coordinate
;
; Exit:         AH  -   bit mask
;               ES:_BX  -   byte offset in buffer
;               CL  -   number of bits to shift left
;               _SI -   64k bank number of the address
;
; Registers:    none.
;
;----------------------------------------------------------------------------
PROC    SV_pixelAddr16 near

        push    _dx                 ; Save DX
        mul     [USHORT DC.bytesperline]    ; DX:AX := y * BytesPerLine
        mov     cl,bl               ; CL := low-order byte of x

        shr     _bx,3               ; _BX := x/8
        add     ax,bx
        adc     dl,0                ; DL:_BX := y*BytesPerLine + x/8
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        adc     dl,[BYTE DC.bankOffset]; DL := bank number
        add     bx,[USHORT DC.originOffset] ; _BX := byte offset in video buffer
        adc     dl,0
        mov     _si,_dx             ; _SI := bank number

        mov     ah,1                ; AH := unshifted bit mask
        and     cl,7                ; CL := x & 7
        xor     cl,7                ; CL := # bits to shift left

        pop     _dx
        ret

ENDP    SV_pixelAddr16

;----------------------------------------------------------------------------
; SV_pixelAddr256 - Determine address of pixel in 256 color banked modes
;----------------------------------------------------------------------------
;
; Entry:        _AX     -   y-coordinate
;               _BX     -   x-coordinate
;
; Exit:         ES:_BX  -   byte offset in buffer
;               _DX     -   64k bank number of the address
;
; Registers:    None.
;
;----------------------------------------------------------------------------
PROC    SV_pixelAddr256 near

        mul     [USHORT DC.bytesperline]        ; DX:AX := y * bytesperline
        add     ax,bx
        adc     dx,0                ; DX:_BX := y * BytesPerLine + x
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        adc     dl,[BYTE DC.bankOffset]; DL := bank number
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        ret

ENDP    SV_pixelAddr256

;----------------------------------------------------------------------------
; SV_pixelAddr32k - Determine address of pixel in 32k color banked modes
;----------------------------------------------------------------------------
;
; Entry:        _AX -   y-coordinate
;               _BX -   x-coordinate
;
; Exit:         _BX -   byte offset in buffer
;               _DX -   64k bank number of the address
;
; Registers:    None.
;
;----------------------------------------------------------------------------
PROC    SV_pixelAddr32k near

        mul     [USHORT DC.bytesperline]        ; DX:AX := y * bytesperline
        shl     _bx,1
        add     ax,bx
        adc     dx,0                ; DX:BX := y * BytesPerLine + x * 2
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        adc     dl,[BYTE DC.bankOffset]; DL := bank number
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        ret

ENDP    SV_pixelAddr32k

;----------------------------------------------------------------------------
; SV_pixelAddr16m - Determine address of pixel in 16m color banked modes
;----------------------------------------------------------------------------
;
; Entry:        _AX -   y-coordinate
;               _BX -   x-coordinate
;
; Exit:         _BX -   byte offset in buffer
;               _DX -   64k bank number of the address
;
; Registers:    None.
;
;----------------------------------------------------------------------------
PROC    SV_pixelAddr16m near

        mul     [USHORT DC.bytesperline]        ; DX:AX := y * bytesperline
        add     ax,bx
        shl     _bx,1
        add     ax,bx
        adc     dx,0                ; DX:BX := y * BytesPerLine + x * 3
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        adc     dl,[BYTE DC.bankOffset]; DL := bank number
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        ret

ENDP    SV_pixelAddr16m

;----------------------------------------------------------------------------
; SV_pixelAddr4G - Determine address of pixel in 4G color banked modes
;----------------------------------------------------------------------------
;
; Entry:        _AX -   y-coordinate
;               _BX -   x-coordinate
;
; Exit:         _BX -   byte offset in buffer
;               _DX -   64k bank number of the address
;
; Registers:    None.
;
;----------------------------------------------------------------------------
PROC    SV_pixelAddr4G  near

        mul     [USHORT DC.bytesperline]        ; DX:AX := y * bytesperline
        shl     _bx,2
        add     ax,bx
        adc     dx,0                ; DX:BX := y * BytesPerLine + x * 2
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        adc     dl,[BYTE DC.bankOffset]; DL := bank number
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        ret

ENDP    SV_pixelAddr4G

;----------------------------------------------------------------------------
; clearBanked   - Clear all banks in the video page
;----------------------------------------------------------------------------
; Entry:        EAX - Value to clear with
;
; Registers:    All.
;----------------------------------------------------------------------------
PROC    clearBanked

        LOCAL   color:ULONG = LocalSize

        enter_c LocalSize
        mov     [color],eax

        mov     _ax,[DC.maxy]
        inc     _ax
        mul     [USHORT DC.bytesperline]     ; DX:AX := number of bytes to fill
        mov     bx,ax
        add     bx,[USHORT DC.originOffset] ; BX := bytes in last bank to fill
        adc     dl,0
        mov     dh,dl               ; DH := number of full banks to fill

        lVidMem _di                 ; ES:_DI -> video memory
        add     di,[USHORT DC.originOffset]
        mov     dl,[BYTE DC.bankOffset]; DL := starting bank number
        cld                         ; Moves go up in memory

		or      dh,dh               ; More than one bank to fill?
        jz      @@SingleBank        ; No, only fill a single bank

; Fill the first partial bank

		call    _SV_setBankASMDL
        mov     eax,[color]
        mov     ecx,0FFFFh
        sub     cx,[USHORT DC.originOffset]
        inc     ecx
        shr     ecx,2
    rep stosd
        lVidMem _di                 ; ES:_DI -> video memory
        inc     dl
        dec     dh
        jz      @@SingleBank        ; Only two banks to fill

; Fill all of the full 64k banks

@@InnerLoop:
		call    _SV_setBankASMDL
        mov     eax,[color]
        mov     _cx,4000h           ; Need to set 4000h double USHORTs per bank
        push    _di
    rep stosd
        pop     _di
        inc     dl
        dec     dh
        jnz     @@InnerLoop

; Now fill the last partial bank

@@SingleBank:
		call    _SV_setBankASMDL
        mov     eax,[color]
        xor     _cx,_cx
        mov     cx,bx
        shr     _cx,2               ; _CX := number of double words to set
    rep stosd

        leave_c
        ret

ENDP    clearBanked

;----------------------------------------------------------------------------
; void clear16(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Works even if the display contains more than
; one bank, so will work for 1024x768 and 1280x1024 video modes.
;----------------------------------------------------------------------------
procstartdll   __SV_clear16

        ARG     color:ULONG

        enter_c 0
        save_es

; Setup graphics controller

        mov     dx,3CEh             ; DX := Graphics Controller I/O port

        mov     ah,[BYTE color]     ; AH := Background color
        xor     al,al               ; AL := 0 (Set/Reset register number)
        out     dx,ax               ; load set/reset register

        mov     ax,0F01h            ; AH := 1111b (mask for Enable set/reset)
                                    ; AL := 1 (enable Set/reset reg number)
        out     dx,ax               ; load enable set/reset reg

        call    clearBanked         ; Clear the video memory page

; Restore graphics controller

        mov     dx,3CEh             ; DX := Graphics Controller I/O port
        xor     ax,ax               ; AH := 0, AL := 0
        out     dx,ax               ; Restore default Set/Reset register

        inc     ax                  ; AH := 0, AL := 1
        out     dx,ax               ; Restore enable Set/Reset register

        restore_es
        leave_c_nolocal
        ret

procend     __SV_clear16

;----------------------------------------------------------------------------
; void clear256(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstartdll   __SV_clear256

        ARG     color:ULONG

        enter_c 0
        save_es

        xor     eax,eax
        mov     al,[BYTE color]
        mov     ebx,eax
        shl     ebx,8
        or      eax,ebx
        mov     ebx,eax
        shl     ebx,16
        or      eax,ebx             ; EAX = 32 bit color value

        call    clearBanked

        restore_es
        leave_c_nolocal
        ret

procend     __SV_clear256

;----------------------------------------------------------------------------
; void clear32k(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstartdll   __SV_clear32k

        ARG     color:ULONG

        enter_c 0
        save_es

        xor     eax,eax
        mov     ax,[WORD color]
        mov     ebx,eax
        shl     ebx,16
        or      eax,ebx             ; EAX = 32 bit color value
        call    clearBanked         ; Clear the video memory page

        restore_es
        leave_c_nolocal
        ret

procend     __SV_clear32k

;----------------------------------------------------------------------------
; void clear16m(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstartdll   __SV_clear16m

        ARG     color:ULONG

        enter_c 0
        save_es

        mov     eax,[color]
        or      eax,eax
        jnz     @@SlowClear
        call    clearBanked         ; Clear the video memory page to black
        jmp     @@Exit

@@SlowClear:
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,[USHORT DC.originOffset]
        mov     dl,[BYTE DC.bankOffset]; DL := starting bank number
		call    _SV_setBankASMDL    ; Change to starting bank number

        mov     _di,[DC.maxx]
        inc     _di                 ; _DI := number of pixels to draw
        mov     _si,[DC.maxy]
        inc     _si                 ; _SI := number of lines to process
        mov     ax,[WORD color]     ; AX := pixel color
        mov     dh,[BYTE color+2]   ; DH := top byte of pixel color
        mov     bp,di
        shl     bp,1
        add     bp,di               ; BP := bytes per physical scanline
        sub     bp,[USHORT DC.bytesperline]
        neg     bp                  ; BP := scanline adjust factor

@@NextScanLine:
        mov     _cx,_di

@@LoopSolid:
        cmp     bx,0FFFDh
        jae     @@BankSwitch        ; Bank switch occurs!

        mov     [WORD _ES _bx],ax   ; Set pixel value in buffer
        mov     [BYTE _ES _bx+2],dh
        add     _bx,3               ; Increment to next pixel
        loop    @@LoopSolid         ; Loop across line

@@AfterPlot:
        add     bx,bp
        jc      @@BankSwitch2
        dec     _si
        jnz     @@NextScanLine
        jmp     @@Exit

@@BankSwitch:
        call    DrawPixelAFSLOW16m
        inc     dl
        loop    @@LoopSolid         ; Loop across line
        jmp     @@AfterPlot

@@BankSwitch2:
        inc     dl
		call    _SV_setBankASMDL
		dec     _si
        jnz     @@NextScanLine

@@Exit:
        restore_es
        leave_c_nolocal
        ret

procend     __SV_clear16m

;----------------------------------------------------------------------------
; void clear4G(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstartdll   __SV_clear4G

        ARG     color:ULONG

        enter_c 0
        save_es

        mov     eax,[color]
        call    clearBanked         ; Clear the video memory page

        restore_es
        leave_c_nolocal
        ret

procend     __SV_clear4G

;----------------------------------------------------------------------------
; void putPixel16(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry:        x       -   X coordinate of pixel to draw
;               y       -   Y coordinate of pixel to draw
;               color   -   Color of pixel to draw
;
;----------------------------------------------------------------------------
procstartdll   __SV_putPixel16

        ARG     x:UINT, y:UINT, color:ULONG

        enter_c 0
        save_es

; Compute the pixel's address in video buffer

        mov     _ax,[y]
        mov     _bx,[x]
        mul     [USHORT DC.bytesperline]     ; DX:AX := y * BytesPerLine

        mov     cl,bl               ; CL := low-order byte of x

        shr     _bx,3               ; _BX := x/8
        add     ax,bx
        adc     dx,0                ; DX:BX := y*BytesPerLine + x/8
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        add     bx,[USHORT DC.originOffset]   ; DX:BX := byte offset in video buffer
        adc     dx,[DC.bankOffset]

        cmp     dl,[BYTE DC.curBank]
        je      @@NoChange

		call    _SV_setBankASMDL

@@NoChange:
        mov     ah,1                ; AH := unshifted bit mask
        and     cl,7                ; CL := x & 7
        xor     cl,7                ; CL := # bits to shift left

; set Graphics Controller Bit Mask register

        shl     ah,cl               ; AH := bit mask in proper postion
        mov     dx,3CEh             ; GC address register port
        mov     al,8                ; AL := Bit Mask Register number
        out     dx,ax

; set Graphics Controller Mode register

        mov     ax,0205h            ; AL := Mode register number
                                    ; AH := Write mode 2 (bits 0,1)
                                    ;   Read mode 0 (bit 3)
        out     dx,ax

; set data rotate/Function Select register

        mov     ax,3                ; AL := Data Rotate/Func select reg #
        out     dx,ax

; set the pixel value

        mov     al,[_ES _bx]        ; latch one byte from each bit plane
        mov     al,[BYTE color]     ; AL := pixel value
        mov     [_ES _bx],al        ; update all bit planes

; restore default Graphics Controller registers

        mov     ax,0FF08h           ; default bit mask
        out     dx,ax

        mov     ax,0005h            ; default mode register
        out     dx,ax

        mov     ax,0003h            ; default function select
        out     dx,ax

        restore_es
        leave_c_nolocal
        ret

procend     __SV_putPixel16

;----------------------------------------------------------------------------
; void putPixel256(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry:        x       -   X coordinate of pixel to draw
;               y       -   Y coordinate of pixel to draw
;               color   -   Color of pixel to draw
;
;----------------------------------------------------------------------------
procstartdll   __SV_putPixel256

        ARG     x:UINT, y:UINT, color:ULONG

        enter_c 0
        save_es

        mov     _ax,[y]
        mul     [USHORT DC.bytesperline]
        mov     _bx,[x]
        add     ax,bx
        adc     dl,[BYTE DC.bankOffset]; DL:_BX := y * BytesPerLine + x
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        cmp     dl,[BYTE DC.curBank]
        je      @@NoChange

		call    _SV_setBankASMDL

@@NoChange:
        mov     al,[BYTE color]
        mov     [_ES _bx],al        ; Replace the pixel

        restore_es
        leave_c_nolocal
        ret

procend     __SV_putPixel256

;----------------------------------------------------------------------------
; void putPixel32k(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry:        x       -   X coordinate of pixel to draw
;               y       -   Y coordinate of pixel to draw
;               color   -   Color of pixel to draw
;
;----------------------------------------------------------------------------
procstartdll   __SV_putPixel32k

        ARG     x:UINT, y:UINT, color:ULONG

        enter_c 0
        save_es

        mov     _ax,[y]
        mul     [USHORT DC.bytesperline]
        mov     _bx,[x]
        shl     _bx,1
        add     ax,bx
        adc     dl,[BYTE DC.bankOffset]; DL:_BX := y * BytesPerLine + x
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        cmp     dl,[BYTE DC.curBank]
        je      @@NoChange

		call    _SV_setBankASMDL

@@NoChange:
        mov     ax,[USHORT color]
        mov     [_ES _bx],ax        ; Replace the pixel

        restore_es
        leave_c_nolocal
        ret

procend     __SV_putPixel32k

;----------------------------------------------------------------------------
; void putPixel16m(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry:        x       -   X coordinate of pixel to draw
;               y       -   Y coordinate of pixel to draw
;               color   -   Color of pixel to draw
;
;----------------------------------------------------------------------------
procstartdll   __SV_putPixel16m

        ARG     x:UINT, y:UINT, color:ULONG

        enter_c 0
        save_es

        mov     _ax,[y]
        mul     [USHORT DC.bytesperline]
        mov     _bx,[x]
        add     ax,bx
        adc     dx,0
        shl     bx,1
        add     ax,bx
        adc     dl,[BYTE DC.bankOffset]; DX:AX := y * BytesPerLine + x * 3
        add     ax,[USHORT DC.originOffset]
        adc     dl,0
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax               ; BX := Offset in buffer
        cmp     dl,[BYTE DC.curBank]
        je      @@NoChange

		call    _SV_setBankASMDL

@@NoChange:
        mov     ax,[WORD color]
        mov     dh,[BYTE color+2]
        cmp     bx,0FFFEh
        jae     @@SlowVersion       ; Bank switch occurs in pixel!

        mov     [_ES _bx],ax        ; Replace the first byte
        mov     [_ES _bx+2],dh

@@Exit: restore_es
        leave_c_nolocal
        ret

@@SlowVersion:
        call    DrawPixelAFSLOW16m  ; Draw the pixel slowly
        jmp     @@Exit

procend     __SV_putPixel16m

;----------------------------------------------------------------------------
; IncBXDL   Increment the BX/DL offset bank number combination
;----------------------------------------------------------------------------
;
; This routine is called in place to increment the value of DL:BX where
; DL is the current bank offset, and BX is the current frame buffer offset.
; The routine also ensures that the bank boundary is correctly crossed. It
; is slow, but only gets called for about less than 10 pixels on the entire
; display page.
;
; Entry:        BX  - Video buffer offset
;               DL  - Video bank number
;
; Exit:         BX  - New buffer offset (+1)
;               DL  - New bank bumber (carried over from BX)
;
; Registers:    None.
;
;----------------------------------------------------------------------------
PROC    IncBXDL near

        add     bx,1
        adc     dl,0
		call    _SV_setBankASMDL
		ret

ENDP    IncBXDL

;----------------------------------------------------------------------------
; DrawPixelAFSLOW16m    Draws a pixel split across a bank boundary correctly
;----------------------------------------------------------------------------
;
; Draws the pixel taking into account that a bank boundary occurs in the
; middle of the pixel.
;
; Entry:        DH:AX       - Color of the pixel to plot
;               GS:_BX      - Address of pixel to plot
;               DC.curBank  - Current bank number
;
; Exit:         DH:AX       - Color of pixel to plot
;               GS:_BX      - Address of pixel to plot + 3
;               DC.curBank  - Current bank number + 1
;
; Registers:    All preserved.
;
;----------------------------------------------------------------------------
PROC    DrawPixelAFSLOW16m  near

        push    _dx

        mov     dl,[BYTE DC.curBank]
        mov     [_ES _bx],al        ; Replace the pixel
        call    IncBXDL
        mov     [_ES _bx],ah
        call    IncBXDL
        mov     [_ES _bx],dh
        call    IncBXDL
        pop     _dx
        ret

ENDP    DrawPixelAFSLOW16m

;----------------------------------------------------------------------------
; void putPixel4G(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry:        x       -   X coordinate of pixel to draw
;               y       -   Y coordinate of pixel to draw
;               color   -   Color of pixel to draw
;
;----------------------------------------------------------------------------
procstartdll   __SV_putPixel4G

        ARG     x:UINT, y:UINT, color:ULONG

        enter_c 0
        save_es

        mov     _ax,[y]
        mul     [USHORT DC.bytesperline]
        mov     _bx,[x]
        shl     _bx,2
        add     ax,bx
        adc     dl,[BYTE DC.bankOffset]; DL:_BX := y * BytesPerLine + x
        lVidMem _bx                 ; ES:_BX -> video memory
        add     bx,ax
        add     bx,[USHORT DC.originOffset]
        adc     dl,0
        cmp     dl,[BYTE DC.curBank]
        je      @@NoChange

		call    _SV_setBankASMDL

@@NoChange:
        mov     eax,[color]
        mov     [_ES _BX],eax       ; Replace the pixel

        restore_es
        leave_c_nolocal
        ret

procend     __SV_putPixel4G

;----------------------------------------------------------------------------
; void _SV_line16(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry:        x1      - X1 coordinate of line to draw
;               y1      - Y1 coordinate of line to draw
;               x2      - X2 coordinate of line to draw
;               y2      - Y2 coordinate of line to draw
;               color   - color to draw the line in
;
;----------------------------------------------------------------------------
procstartdll    __SV_line16

        ARG     x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
        LOCAL   Routine:NCPTR, VertInc:ULONG, EIncr:UINT,           \
                NEIncr:UINT = LocalSize

        enter_c LocalSize
        save_es
        cld

; Configure the graphics controller (write mode 3)

        mov     dx,3CEh             ; DX := Graphics Controller port addr

        mov     ax,0B05h            ; AL := Mode register number
                                    ; AH := Write mode 3 (bits 0,1)
                                    ;   Read mode 1 (bit 3)
        out     dx,ax

        xor     ah,ah               ; AH := replace mode
        mov     al,3                ; AL := Data Rotate/Func select reg #
        out     dx,ax

        mov     ax,0007h            ; AH := 0 (don't care for all maps;
                                    ;   CPU reads always return 0FFH)
                                    ; AL := 7 (Color Don't care reg number)
        out     dx,ax               ; Set up Color Don't care reg

        mov     ax,0F01h            ; AH := 1111b (bit plane mask for
                                    ;  enable Set/Reset)
        out     dx,ax               ; AL := Enable Set/Reset Register #

        mov     ax,0FF08h           ; AH := 11111111b, AL := 8
        out     dx,ax               ; restore bit mask register

; Load the current color

        mov     dx,3CEh             ; DX := Graphics Controller port addr
        mov     ah,[BYTE color]     ; Get color value into ah
        xor     al,al               ; AL := Set/Reset Register number
        out     dx,ax

        mov     si,[USHORT DC.bytesperline] ; Increment for video buffer
        mov     [USHORT VertInc+2],0    ; Zero out sign for vertical increment
        mov     _ax,[x2]
        sub     _ax,[x1]            ; _AX := X2 - X1

; Force X1 < X2

        jns     @@X2Greater         ; Jump if X2 > X1
        neg     _ax                 ; _AX := X1 - X2

        mov     _bx,[x2]            ; Exchange X1 and X2
        xchg    _bx,[x1]
        mov     [x2],_bx

        mov     _bx,[y2]            ; Exchange Y1 and Y2
        xchg    _bx,[y1]
        mov     [y2],_bx

; calcluate dy = ABS(Y2-Y1)

@@X2Greater:
        mov     _bx,[y2]
        sub     _bx,[y1]            ; _BX := Y2 - Y1
        jns     @@Y2Greater         ; Jump if slope is positive

        neg     _bx                 ; _BX := Y1 - Y2
        neg     si                  ; negative increment for buffer
        mov     [USHORT VertInc+2],0FFFFh   ; ensure vert increment is negative

; select appropriate routine for slope of line

@@Y2Greater:
        mov     [USHORT VertInc],si ; save increment
        mov     [Routine],offset @@LoSlopeLine
        cmp     _bx,_ax
        jle     @@LoSlope           ; Jump if dy <= dx (Slope <= 1)
        mov     [Routine],offset @@HiSlopeLine
        xchg    _bx,_ax             ; exchange dy and dx

; calculate initial decision variable and increments

@@LoSlope:
        shl     _bx,1               ; _BX := 2 * dy
        mov     [EIncr],_bx         ; EIncr := 2 * dy
        sub     _bx,_ax             ; d = 2 * dy - dx
        mov     _di,_bx             ; DI := initial decision variable
        sub     _bx,_ax
        mov     [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)

; calculate first pixel address

        push    _ax                 ; preserve dx
        mov     _ax,[y1]
        mov     _bx,[x1]
        call    SV_pixelAddr16      ; AH := Bit mask
                                    ; ES:_BX -> buffer
                                    ; CL := # bits to shift left
                                    ; _SI := bank number
        shl     ah,cl               ; AH := bit mask in proper position
        mov     al,ah               ; AL := bit Mask
        pop     _cx                 ; Restore dx
        inc     _cx                 ; _CX := # pixels to draw

        jmp     [Routine]           ; jump to appropriate routine

;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
;                       ES:_BX -> video buffer
;                       AL = bit mask for 1st pixel
;                       AH = bit mask for 1st pixel
;                       _CX = # pixels to draw
;                       DX = Graphics Controller data register port addr
;                       _SI = bank number
;                       _DI = Initial decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
; The Graphics Controller index register should be set to point to the
; Bit Mask register.
;
;****************************************************************************

@@LoSlopeLine:

@@StartLo:
        mov     al,ah               ; AL := bit mask for next pixel
        cmp     si,[USHORT DC.curBank]
        je      @@BitMaskIn

        push    _ax                 ; Preserve AX
        mov     _ax,_si             ; AX := new bank number
		call    _SV_setBankASM      ; Program this bank
        pop     _ax

@@BitMaskIn:
        or      al,ah               ; mask current pixel position

        ror     ah,1                ; Rotate pixel value
        jc      @@BitMaskOut        ; Jump if mask rotated to leftmost pixel

; bit mask not shifted out

        or      _di,_di             ; test sign of d
        jns     @@InPosDi           ; jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@BitMaskIn

        and     [_ES _bx],al        ; set remaining pixel(s)
        jmp     @@Exit

@@InPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr

        and     [_ES _bx],al        ; Update bit planes

        add     bx,[USHORT VertInc] ; increment y
        adc     si,[USHORT VertInc+2]   ; Adjust bank number
        loop    @@StartLo
        jmp     @@Exit

; bit mask shifted out

@@BitMaskOut:
        and     [_ES _bx],al        ; Update bit planes
        add     bx,1                ; increment x
        adc     si,0                ; Adjust bank value

        or      _di,_di             ; test sign of d
        jns     @@OutPosDi          ; jump if non-negative

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@StartLo
        jmp     @@Exit

@@OutPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,[USHORT VertInc] ; vertical increment
        adc     si,[USHORT VertInc+2]   ; Adjust bank number
        loop    @@StartLo
        jmp     @@Exit

;****************************************************************************
;
; Routine for dy > dx (slope > 1)
;                       ES:_BX -> video buffer
;                       AL = bit mask for 1st pixel
;                       _CX = # pixels to draw
;                       DX = Graphics Controller data register port addr
;                       _SI = bank number
;                       _DI = Initial decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
; The Graphics Controller index register should be set to point to the
; Bit Mask register.
;
;****************************************************************************

@@HiSlopeLine:

@@StartHi:
        cmp     si,[USHORT DC.curBank]
        je      @@SetHi

        push    _ax                 ; Preserve AX
        mov     _ax,_si             ; AX := new bank number
		call    _SV_setBankASM      ; Program this bank
        pop     _ax

@@SetHi:
        and     [_ES _bx],al        ; update bit planes

        add     bx,[USHORT VertInc] ; increment y
        adc     si,[USHORT VertInc+2]   ; Adjust bank number

        or      _di,_di             ; test sign of d
        jns     @@HiPosDi           ; jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@StartHi
        jmp     @@Exit

@@HiPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr

        ror     al,1                ; rotate bit mask
        adc     bx,0                ; Increment BX when mask rotated to
                                    ;  leftmost pixel position
        adc     si,0                ; Adjust bank number
        loop    @@StartHi

; Restore graphics controller and return to caller

@@Exit:
        mov     dx,3CEh             ; DX := Graphics Controller port addr
        xor     ax,ax               ; AH := 0, AL := 0
        out     dx,ax               ; Restore Set/Reset Register

        inc     ax                  ; AH := 0, AL := 1
        out     dx,ax               ; Restore Enable Set/Reset register

        mov     al,3                ; AH := 0, AL := 3
        out     dx,ax               ; Restore Data Rotate/Func select reg

        mov     al,5                ; AH := 0, AL := 5
        out     dx,ax               ; default mode register

        mov     ax,0F07h            ; default color compare value
        out     dx,ax

        mov     ax,0FF08h           ; AH := 11111111b, AL := 8
        out     dx,ax               ; restore bit mask register

        restore_es
        leave_c
        ret

procend     __SV_line16

;----------------------------------------------------------------------------
; void _SV_line256(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry:        x1      - X1 coordinate of line to draw
;               y1      - Y1 coordinate of line to draw
;               x2      - X2 coordinate of line to draw
;               y2      - Y2 coordinate of line to draw
;               color   - color to draw the line in
;
;----------------------------------------------------------------------------
procstartdll    __SV_line256

        ARG     x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
        LOCAL   Routine:NCPTR, VertInc:ULONG, EIncr:UINT,           \
                NEIncr:UINT = LocalSize

        enter_c LocalSize
        save_es

        mov     si,[USHORT DC.bytesperline] ; Increment for video buffer
        mov     [USHORT VertInc+2],0    ; Zero out sign for vertical increment

        mov     _ax,[x2]
        sub     _ax,[x1]            ; _AX := X2 - X1

; Force X1 < X2

        jns     @@X2Greater         ; Jump if X2 > X1
        neg     _ax                 ; _AX := X1 - X2

        mov     _bx,[x2]            ; Exchange X1 and X2
        xchg    _bx,[x1]
        mov     [x2],_bx

        mov     _bx,[y2]            ; Exchange Y1 and Y2
        xchg    _bx,[y1]
        mov     [y2],_bx

; calcluate dy = ABS(Y2-Y1)

@@X2Greater:
        mov     _bx,[y2]
        sub     _bx,[y1]            ; _BX := Y2 - Y1
        jns     @@Y2Greater         ; Jump if slope is positive

        neg     _bx                 ; _BX := Y1 - Y2
        neg     si                  ; negative increment for buffer
        mov     [USHORT VertInc+2],0FFFFh   ; ensure vert increment is negative

; select appropriate routine for slope of line

@@Y2Greater:
        mov     [USHORT VertInc],si ; save increment
        mov     [Routine],offset @@LoSlopeLine
        cmp     _bx,_ax
        jle     @@LoSlope           ; Jump if dy <= dx (Slope <= 1)
        mov     [Routine],offset @@HiSlopeLine
        xchg    _bx,_ax             ; exchange dy and dx

; calculate initial decision variable and increments

@@LoSlope:
        shl     _bx,1               ; _BX := 2 * dy
        mov     [EIncr],_bx         ; EIncr := 2 * dy
        sub     _bx,_ax             ; d = 2 * dy - dx
        mov     _di,_bx             ; _DI := initial decision variable
        sub     _bx,_ax
        mov     [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)

; calculate first pixel address

        push    _ax                 ; preserve dx
        mov     _ax,[y1]
        mov     _bx,[x1]
        call    SV_pixelAddr256     ; ES:_BX -> buffer

        pop     _cx                 ; Restore dx
        inc     _cx                 ; CX := # pixels to draw

        jmp     [Routine]           ; jump to appropriate routine

;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@LoSlopeLine:
        mov     al,[BYTE color]     ; AL := pixel value to fill
        mov     dh,[BYTE DC.curBank]    ; DH := current bank number

@@LoopLo:
        cmp     dl,dh
        je      @@SetLo

        mov     dh,al               ; DH := color value
		call    _SV_setBankASMDL    ; Program this bank
        mov     al,dh               ; AL := color value
        mov     dh,dl               ; DH := current bank number

@@SetLo:
        mov     [_ES _bx],al        ; Set pixel value in buffer
        add     bx,1                ; Increment x coordinate
        adc     dl,0                ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@LoPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@LoPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; adjust page number
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

;****************************************************************************
;
; Routine for dy > dx (slope > 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@HiSlopeLine:
        mov     al,[BYTE color]     ; AL := pixel value to fill
        mov     dh,[BYTE DC.curBank]    ; DH := current bank number

@@LoopHi:
        cmp     dh,dl
        je      @@SetHi

        mov     dh,al               ; DH := color value
		call    _SV_setBankASMDL    ; Program this bank
        mov     al,dh               ; AL := color value
        mov     dh,dl               ; DH := current bank number

@@SetHi:
        mov     [_ES _bx],al        ; Set pixel value in buffer
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@HiPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopHi            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@HiPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,1                ; Increment x
        adc     dl,0                ; Adjust bank number
        loop    @@LoopHi            ; Loop for remaining pixels

@@Exit: restore_es
        leave_c
        ret

procend     __SV_line256

;----------------------------------------------------------------------------
; void _SV_line32k(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry:        x1      - X1 coordinate of line to draw
;               y1      - Y1 coordinate of line to draw
;               x2      - X2 coordinate of line to draw
;               y2      - Y2 coordinate of line to draw
;               color   - color to draw the line in
;
;----------------------------------------------------------------------------
procstartdll    __SV_line32k

        ARG     x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
        LOCAL   Routine:NCPTR, VertInc:ULONG, EIncr:UINT,           \
                NEIncr:UINT = LocalSize

        enter_c LocalSize
        save_es
        cld

        mov     si,[USHORT DC.bytesperline] ; Increment for video buffer
        mov     [USHORT VertInc+2],0    ; Zero out sign for vertical increment

        mov     _ax,[x2]
        sub     _ax,[x1]            ; _AX := X2 - X1

; Force X1 < X2

        jns     @@X2Greater         ; Jump if X2 > X1
        neg     _ax                 ; _AX := X1 - X2

        mov     _bx,[x2]            ; Exchange X1 and X2
        xchg    _bx,[x1]
        mov     [x2],_bx

        mov     _bx,[y2]            ; Exchange Y1 and Y2
        xchg    _bx,[y1]
        mov     [y2],_bx

; calcluate dy = ABS(Y2-Y1)

@@X2Greater:
        mov     _bx,[y2]
        sub     _bx,[y1]            ; _BX := Y2 - Y1
        jns     @@Y2Greater         ; Jump if slope is positive

        neg     _bx                 ; _BX := Y1 - Y2
        neg     si                  ; negative increment for buffer
        mov     [USHORT VertInc+2],0FFFFh   ; ensure vert increment is negative

; select appropriate routine for slope of line

@@Y2Greater:
        mov     [USHORT VertInc],si ; save increment
        mov     [Routine],offset @@LoSlopeLine
        cmp     _bx,_ax
        jle     @@LoSlope           ; Jump if dy <= dx (Slope <= 1)
        mov     [Routine],offset @@HiSlopeLine
        xchg    _bx,_ax             ; exchange dy and dx

; calculate initial decision variable and increments

@@LoSlope:
        shl     _bx,1               ; _BX := 2 * dy
        mov     [EIncr],_bx         ; EIncr := 2 * dy
        sub     _bx,_ax             ; d = 2 * dy - dx
        mov     _di,_bx             ; _DI := initial decision variable
        sub     _bx,_ax
        mov     [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)

; calculate first pixel address

        push    _ax                 ; preserve dx
        mov     _ax,[y1]
        mov     _bx,[x1]
        call    SV_pixelAddr32k     ; ES:_BX -> buffer

        pop     _cx                 ; Restore dx
        inc     _cx                 ; _CX := # pixels to draw

        jmp     [Routine]           ; jump to appropriate routine

;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@LoSlopeLine:
        mov     ax,[USHORT color]       ; AX := pixel value to fill
        mov     dh,[BYTE DC.curBank]    ; DH := current bank number

@@LoopLo:
        cmp     dl,dh
        je      @@SetLo

        push    _ax                 ; Save color value
		call    _SV_setBankASMDL    ; Program this bank
        mov     dh,dl               ; DH := current bank number
        pop     _ax                 ; Restore color value

@@SetLo:
        mov     [_ES _bx],ax        ; Set pixel value in buffer
        add     bx,2                ; Increment x coordinate
        adc     dl,0                ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@LoPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@LoPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; adjust page number
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

;****************************************************************************
;
; Routine for dy > dx (slope > 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@HiSlopeLine:
        mov     ax,[USHORT color]       ; AL := pixel value to fill
        mov     dh,[BYTE DC.curBank]    ; DH := current bank number

@@LoopHi:
        cmp     dh,dl
        je      @@SetHi

        push    _ax                 ; Save color value
		call    _SV_setBankASMDL    ; Program this bank
        mov     dh,dl               ; DH := current bank number
        pop     _ax                 ; Restore color value

@@SetHi:
        mov     [_ES _bx],ax        ; Set pixel value in buffer
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@HiPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopHi            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@HiPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,2                ; Increment x
        adc     dl,0                ; Adjust bank number
        loop    @@LoopHi            ; Loop for remaining pixels

@@Exit: restore_es
        leave_c
        ret

procend     __SV_line32k

;----------------------------------------------------------------------------
; void _SV_line16m(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry:        x1      - X1 coordinate of line to draw
;               y1      - Y1 coordinate of line to draw
;               x2      - X2 coordinate of line to draw
;               y2      - Y2 coordinate of line to draw
;               color   - color to draw the line in
;
;----------------------------------------------------------------------------
procstartdll    __SV_line16m

        ARG     x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
        LOCAL   Routine:NCPTR, VertInc:ULONG, EIncr:UINT,           \
                NEIncr:UINT = LocalSize

        enter_c LocalSize
        save_es
        cld

        mov     si,[USHORT DC.bytesperline] ; Increment for video buffer
        mov     [USHORT VertInc+2],0    ; Zero out sign for vertical increment

        mov     _ax,[x2]
        sub     _ax,[x1]            ; _AX := X2 - X1

; Force X1 < X2

        jns     @@X2Greater         ; Jump if X2 > X1
        neg     _ax                 ; _AX := X1 - X2

        mov     _bx,[x2]            ; Exchange X1 and X2
        xchg    _bx,[x1]
        mov     [x2],_bx

        mov     _bx,[y2]            ; Exchange Y1 and Y2
        xchg    _bx,[y1]
        mov     [y2],_bx

; calcluate dy = ABS(Y2-Y1)

@@X2Greater:
        mov     _bx,[y2]
        sub     _bx,[y1]            ; _BX := Y2 - Y1
        jns     @@Y2Greater         ; Jump if slope is positive

        neg     _bx                 ; _BX := Y1 - Y2
        neg     si                  ; negative increment for buffer
        mov     [USHORT VertInc+2],0FFFFh   ; ensure vert increment is negative

; select appropriate routine for slope of line

@@Y2Greater:
        mov     [USHORT VertInc],si ; save increment
        mov     [Routine],offset @@LoSlopeLine
        cmp     _bx,_ax
        jle     @@LoSlope           ; Jump if dy <= dx (Slope <= 1)
        mov     [Routine],offset @@HiSlopeLine
        xchg    _bx,_ax             ; exchange dy and dx

; calculate initial decision variable and increments

@@LoSlope:
        shl     _bx,1               ; _BX := 2 * dy
        mov     [EIncr],_bx         ; EIncr := 2 * dy
        sub     _bx,_ax             ; d = 2 * dy - dx
        mov     _di,_bx             ; _DI := initial decision variable
        sub     _bx,_ax
        mov     [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)

; calculate first pixel address

        push    _ax                 ; preserve dx
        mov     _ax,[y1]
        mov     _bx,[x1]
        call    SV_pixelAddr16m     ; ES:_BX -> buffer

        pop     _cx                 ; Restore dx
        inc     _cx                 ; CX := # pixels to draw

        jmp     [Routine]           ; jump to appropriate routine

;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@LoSlopeLine:
        mov     ax,[USHORT color]       ; AX := pixel value to fill
        mov     dh,[BYTE color+2]   ; DH := top byte of pixel value

@@LoopLo:
        cmp     dl,[BYTE DC.curBank]
        je      @@SetPixelLo

        push    _ax                 ; Save color value
		call    _SV_setBankASMDL    ; Program this bank
        pop     _ax                 ; Restore color value

@@SetPixelLo:
        cmp     bx,0FFFEh
        jae     @@BankSwitchLo

@@SetLo:
        mov     [_ES _bx],ax        ; Set pixel value in buffer
        mov     [_ES _bx+2],dh
        add     bx,3                ; Increment x coordinate
        adc     dl,0                ; Adjust bank number

@@DonePixelLo:
        or      _di,_di             ; Test sign of d
        jns     @@LoPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@LoPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; adjust page number
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@BankSwitchLo:
        call    DrawPixelAFSLOW16m
        inc     dl
        jmp     @@DonePixelLo

;****************************************************************************
;
; Routine for dy > dx (slope > 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@HiSlopeLine:
        mov     ax,[USHORT color]       ; AL := pixel value to fill
        mov     dh,[BYTE color+2]   ; DH := current bank number

@@LoopHi:
        cmp     dl,[BYTE DC.curBank]
        je      @@SetPixelHi

        push    _ax                 ; Save color value
		call    _SV_setBankASMDL    ; Program this bank
        pop     _ax                 ; Restore color value

@@SetPixelHi:
        cmp     bx,0FFFEh
        jae     @@BankSwitchHi

@@SetHi:
        mov     [_ES _bx],ax        ; Set pixel value in buffer
        mov     [_ES _bx+2],dh

@@DonePixelHi:
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@HiPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopHi            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@HiPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,3                ; Increment x
        adc     dl,0                ; Adjust bank number
        loop    @@LoopHi            ; Loop for remaining pixels
        jmp     @@Exit

@@BankSwitchHi:
        call    DrawPixelAFSLOW16m
        sub     bx,3
        jmp     @@DonePixelHi

@@Exit: restore_es
        leave_c
        ret

procend     __SV_line16m

;----------------------------------------------------------------------------
; void _SV_line4G(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry:        x1      - X1 coordinate of line to draw
;               y1      - Y1 coordinate of line to draw
;               x2      - X2 coordinate of line to draw
;               y2      - Y2 coordinate of line to draw
;               color   - color to draw the line in
;
;----------------------------------------------------------------------------
procstartdll    __SV_line4G

        ARG     x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
        LOCAL   Routine:NCPTR, VertInc:ULONG, EIncr:UINT,           \
                NEIncr:UINT = LocalSize

        enter_c LocalSize
        save_es
        push    eax
        cld

        mov     si,[USHORT DC.bytesperline] ; Increment for video buffer
        mov     [USHORT VertInc+2],0    ; Zero out sign for vertical increment

        mov     _ax,[x2]
        sub     _ax,[x1]            ; _AX := X2 - X1

; Force X1 < X2

        jns     @@X2Greater         ; Jump if X2 > X1
        neg     _ax                 ; _AX := X1 - X2

        mov     _bx,[x2]            ; Exchange X1 and X2
        xchg    _bx,[x1]
        mov     [x2],_bx

        mov     _bx,[y2]            ; Exchange Y1 and Y2
        xchg    _bx,[y1]
        mov     [y2],_bx

; calcluate dy = ABS(Y2-Y1)

@@X2Greater:
        mov     _bx,[y2]
        sub     _bx,[y1]            ; _BX := Y2 - Y1
        jns     @@Y2Greater         ; Jump if slope is positive

        neg     _bx                 ; _BX := Y1 - Y2
        neg     si                  ; negative increment for buffer
        mov     [USHORT VertInc+2],0FFFFh   ; ensure vert increment is negative

; select appropriate routine for slope of line

@@Y2Greater:
        mov     [USHORT VertInc],si ; save increment
        mov     [Routine],offset @@LoSlopeLine
        cmp     _bx,_ax
        jle     @@LoSlope           ; Jump if dy <= dx (Slope <= 1)
        mov     [Routine],offset @@HiSlopeLine
        xchg    _bx,_ax             ; exchange dy and dx

; calculate initial decision variable and increments

@@LoSlope:
        shl     _bx,1               ; _BX := 2 * dy
        mov     [EIncr],_bx         ; EIncr := 2 * dy
        sub     _bx,_ax             ; d = 2 * dy - dx
        mov     _di,_bx             ; _DI := initial decision variable
        sub     _bx,_ax
        mov     [NEIncr],_bx        ; NEIncr := 2 * (dy - dx)

; calculate first pixel address

        push    _ax                 ; preserve dx
        mov     _ax,[y1]
        mov     _bx,[x1]
        call    SV_pixelAddr4G      ; ES:_BX -> buffer

        pop     _cx                 ; Restore dx
        inc     _cx                 ; _CX := # pixels to draw

        jmp     [Routine]           ; jump to appropriate routine

;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@LoSlopeLine:
        mov     eax,[color]         ; EAX := pixel value to fill
        mov     dh,[BYTE DC.curBank]    ; DH := current bank number

@@LoopLo:
        cmp     dl,dh
        je      @@SetLo

        push    _ax                 ; Save color value
		call    _SV_setBankASMDL    ; Program this bank
        mov     dh,dl               ; DH := current bank number
        pop     _ax                 ; Restore color value

@@SetLo:
        mov     [_ES _bx],eax       ; Set pixel value in buffer
        add     bx,4                ; Increment x coordinate
        adc     dl,0                ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@LoPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@LoPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; adjust page number
        loop    @@LoopLo            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

;****************************************************************************
;
; Routine for dy > dx (slope > 1)
;                       ES:_BX -> video buffer
;                       _CX = # pixels to draw
;                       _DX = Bank number for first pixel
;                       _DI = decision variable
;                       EIncr   - East pixel increment
;                       NEIncr  - North East pixel increment
;
;****************************************************************************

@@HiSlopeLine:
        mov     eax,[color]         ; EAX := pixel value to fill
        mov     dh,[BYTE DC.curBank]    ; DH := current bank number

@@LoopHi:
        cmp     dh,dl
        je      @@SetHi

        push    _ax                 ; Save color value
		call    _SV_setBankASMDL    ; Program this bank
        mov     dh,dl               ; DH := current bank number
        pop     _ax                 ; Restore color value

@@SetHi:
        mov     [_ES _bx],eax       ; Set pixel value in buffer
        add     bx,[USHORT VertInc] ; increment y
        adc     dl,[BYTE VertInc+2] ; Adjust bank number
        or      _di,_di             ; Test sign of d
        jns     @@HiPosDi           ; Jump if d >= 0

        add     _di,[EIncr]         ; d := d + EIncr
        loop    @@LoopHi            ; Loop for remaining pixels
        jmp     @@Exit              ; We are all done

@@HiPosDi:
        add     _di,[NEIncr]        ; d := d + NEIncr
        add     bx,4                ; Increment x
        adc     dl,0                ; Adjust bank number
        loop    @@LoopHi            ; Loop for remaining pixels

@@Exit: pop     eax
        restore_es
        leave_c
        ret

procend     __SV_line4G

;----------------------------------------------------------------------------
; void _SV_setActivePage(int which)
;----------------------------------------------------------------------------
; Routine to set the video page for active output.
;
; Entry:        page    - Page number of page to use
;
;----------------------------------------------------------------------------
procstartdll   __SV_setActivePage

        ARG     which:UINT

        enter_c 0

; Calculate 18 bit address of page in video memory

        xor     eax,eax
        mov     _ax,[which]         ; EAX := page number
        mul     [__SV_pagesize]         ; EDX:EAX := result
        mov     [USHORT DC.originOffset],ax  ; Save video buffer offset
        shr     eax,16
        mov     [DC.bankOffset],ax    ; Save video bank offset
        call    _SV_setBankASM

        leave_c_nolocal
        ret

procend     __SV_setActivePage

;----------------------------------------------------------------------------
; void _SV_setVisualPage(int which,bool waitVRT)
;----------------------------------------------------------------------------
; Routine to set the visible video page.
;
; Entry:        page    - Page number of page to use
;
;----------------------------------------------------------------------------
procstartdll       __SV_setVisualPage

        ARG     which:UINT, waitVRT:S_BOOL

        enter_c 0
        push    es

        cmp     [DC.maxpage],0      ; No flipping if only one page
        je      @@Exit

; Calculate 18 bit address of page in video memory

        xor     eax,eax
        mov     _ax,[which]         ; EAX := page number
        mul     [__SV_pagesize]         ; EAX := starting address in memory

if pmode
        cmp     [__SV_setCRT20],0
        je      @@NoSetCRT20

; Directly call the 32 bit protected mode CRTC setting routine. The
; interface to the 32 bit routine is different, as it takes the CRTC
; starting address in DX:CX in the same format used for standard VGA modes.

        cmp     [DC.bitsperpixel],4
        je      @@1
        shr     eax,2               ; Adj to plane boundary for 8 bit+ modes
@@1:    mov     cx,ax
        shr     eax,16
        mov     dx,ax               ; DX:CX := CRTC start address
        xor     _bx,_bx             ; BX := 0 - set display start
        cmp     [waitVRT],0
        je      @@2
        mov     _bx,80h             ; BX := 80h - set display start with VRT
@@2:    mov     es,[_VBE_MMIOSel]   ; Load selector to MMIO registers
        call    [__SV_setCRT20]     ; Call the relocated code
        jmp     @@Exit
endif

@@NoSetCRT20:
        mov     edx,eax
        shr     edx,16              ; DX:AX := starting address in memory

        div     [USHORT DC.bytesperline]    ; AX := starting scanline,
                                    ; DX := starting byte
        mov     cx,dx
        cmp     [DC.bitsperpixel],4
        je      @@16Color
        cmp     [DC.bitsperpixel],8
        je      @@SetIt
        cmp     [DC.bitsperpixel],24
        je      @@24BitColor
        cmp     [DC.bitsperpixel],32
        je      @@32BitColor

        shr     cx,1                ; CX := starting pixel in buffer
        jmp     @@SetIt

@@16Color:
        shl     cx,3                ; CX := starting pixel in buffer
        jmp     @@SetIt

@@24BitColor:
        mov     bx,ax               ; Preserve AX
        xor     dx,dx
        mov     ax,cx
        mov     cx,3
        div     cx
        mov     cx,ax               ; CX := starting pixel in buffer
        mov     ax,bx               ; Restore AX
        jmp     @@Setit

@@32BitColor:
        shr     cx,2                ; CX := starting pixel in buffer

@@SetIt:
        mov     bx,ax               ; BX := starting scanline in buffer

        mov     _ax,04F07h
        mov     _dx,_bx             ; DX := starting scanline number
        xor     _bx,_bx             ; BX := 0 - set display start
        cmp     [DC.VBEVersion],200h
        jl      @@NotVBE20
        cmp     [waitVRT],0
        je      @@3
        mov     _bx,80h             ; BX := 80h - set display start with VRT
@@3:
ifdef   __WINDOWS32_386__
        push    edx
        push    ecx
        call    _PM_setCRTStart
        add     esp,8
else
        int     10h                 ; Set the start address
endif
        jmp     @@Exit

; For Non VBE 2.0 implementations we cannot guarantee that the
; implementation will wait for a retrace when setting the display start
; address, so we need to wait for the retrace here just to be sure. Note
; that this _assumes_ the controller is VGA compatible, so will hang in
; an infinite loop on controllers that are not VGA compatible.

@@NotVBE20:
        push    _ax
        push    _dx
        cmp     [waitVRT],0
        je      @@NoWaitDE
        mov     dx,03DAh            ; DX := video status port
@@WaitDE:
        in      al,dx
        test    al,1
        jnz     @@WaitDE            ; Wait for Display Enable
@@NoWaitDE:
        mov     dx,03DAh            ; DX := video status port
        pop     _dx
        pop     _ax

ifdef   __WINDOWS32_386__
        push    edx
        push    ecx
        call    _PM_setCRTStart
        add     esp,8
else
        int     10h                 ; Set the start address
endif

        cmp     [waitVRT],0
        je      @@Exit
        mov     dx,03DAh            ; DX := video status port
@@WaitV:
        in      al,dx               ; Wait for start of vertical retrace
        test    al,8
        jz      @@WaitV

@@Exit: pop     es
        leave_c_nolocal
        ret

procend     __SV_setVisualPage

;----------------------------------------------------------------------------
; void _VGA_setPalette(int start,int num,VBE_palette *pal,bool waitVRT);
;----------------------------------------------------------------------------
; Programs the VGA palette. To avoid the onset of snow, we program values
; only during a vertical retrace interval if BL bit 7 is set. This is a
; compatability routine for VBE 1.2 implemenations, and we will use the
; normal VBE 2.0 routines otherwise.
;----------------------------------------------------------------------------
procstartdll    __VGA_setPalette

        ARG     start:UINT, num:UINT, pal:DPTR, waitVRT:S_BOOL

        enter_c 0
        push    ds

; Wait for the start of the vertical retrace if specified

        cmp     [waitVRT],0
        je      @@NoWaitVRT

        mov     dx,3DAh             ; DX := Input Status register
@@WaitNotVsync:
        in      al,dx
        test    al,8
        jnz     @@WaitNotVsync
@@WaitVsync:
        in      al,dx
        test    al,8
        jz      @@WaitVsync

@@NoWaitVRT:
        _lds    _di,[pal]           ; DS:_DI -> palette to program
        mov     _cx,[num]           ; _CX := registers to program
        mov     _ax,[start]         ; AX := first color register to program
        mov     dx,3C8h             ; DX := DAC Write Index register
        out     dx,al               ; Index the first color register
        inc     _dx                 ; DX := DAC data register
        cld

@@NextEntry:
        mov     al,[_di+2]
        out     dx,al
        mov     al,[_di+1]
        out     dx,al
        mov     al,[_di+0]
        out     dx,al
        add     _di,4
        loop    @@NextEntry

@@Exit: pop     ds
        leave_c_nolocal
        ret

procend     __VGA_setPalette

;----------------------------------------------------------------------------
; _VBE_setBankA Sets the read/write bank directly via window A
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value, by making a single call to the VBE to set Window A since it has
; both read & write attributes set.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;
;----------------------------------------------------------------------------
procstartdll    __VBE_setBankA

        push    _ax
        push    _bx
        push    _cx
        mov     _ax,04F05h
        xor     _bx,_bx             ; BX := select window A
        mov     cl,[BYTE __SV_bankShift]; Adjust to VBE granularity
        shl     dl,cl               ; DX := VBE bank number
        cmp     [__SV_setBankRM],0
        je      @@UseInt10h
        call    [__SV_setBankRM]        ; Call the VBE directly in real mode
        jmp     @@Exit

@@UseInt10h:
ifdef   __WINDOWS32_386__
        push    esi
        push    edi
        push    edx
        call    _PM_setBankA        ; Special routine to thunk to 16 bit code
        pop     edx
        pop     edi
        pop     esi
else
        int     10h
endif

@@Exit: pop     _cx
        pop     _bx
        pop     _ax
        ret

procend     __VBE_setBankA

;----------------------------------------------------------------------------
; _VBE_setBankAB    Sets the read/write bank directly via Window's A & B
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value, by calling the VBE twice to set both Window A and Window B, as
; the VBE reports that they have separate read/write attributes.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;
;----------------------------------------------------------------------------
procstartdll    __VBE_setBankAB

        push    _ax
        push    _bx
        push    _cx
        mov     _ax,04F05h
        xor     _bx,_bx             ; BX := select window A
        mov     cl,[BYTE __SV_bankShift]; Adjust to VBE granularity
        shl     dl,cl               ; DX := VBE bank number
        push    _dx                 ; Save bank value
        cmp     [__SV_setBankRM],0
        je      @@UseInt10h
        call    [__SV_setBankRM]        ; Call the VBE directly in real mode
        pop     _dx
        mov     _ax,04F05h
        mov     _bx,1               ; BX := select window B
        call    [__SV_setBankRM]
        jmp     @@Exit

@@UseInt10h:
ifdef   __WINDOWS32_386__
        pop     _dx
        push    esi
        push    edi
        push    edx
        call    _PM_setBankAB       ; Special routine to thunk to 16 bit code
        pop     edx
        pop     edi
        pop     esi
else
        int     10h
        pop     _dx
        mov     _ax,04F05h
        mov     _bx,1               ; BX := select window B
        int     10h
endif

@@Exit: pop     _cx
        pop     _bx
        pop     _ax
        ret

procend     __VBE_setBankAB

if pmode

;----------------------------------------------------------------------------
; _VBE20_setBankA   Sets the read/write bank directly via window A
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value, by making a single call to the VBE to set Window A since it has
; both read & write attributes set.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    __VBE20_setBankA

        push    _bx
        push    _cx
        xor     _bx,_bx             ; BX := select window A
        mov     cl,[BYTE __SV_bankShift]; Adjust to VBE granularity
        shl     dl,cl               ; DX := VBE bank number
        call    [__SV_setBank20]        ; Call VBE 2.0 protected mode routine
        pop     _cx
        pop     _bx
        ret

procend     __VBE20_setBankA

;----------------------------------------------------------------------------
; _VBE20_setBankAB  Sets the read/write bank directly via Window's A & B
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value, by calling the VBE twice to set both Window A and Window B, as
; the VBE reports that they have separate read/write attributes.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    __VBE20_setBankAB

        push    _bx
        push    _cx
        xor     _bx,_bx             ; BX := select window A
        mov     cl,[BYTE __SV_bankShift]; Adjust to VBE granularity
        shl     dl,cl               ; DX := VBE bank number
        push    _dx                 ; Save bank value
        call    [__SV_setBank20]        ; Call VBE 2.0 protected mode routine
        pop     _dx
        mov     _bx,1               ; BX := select window B
        call    [__SV_setBank20]        ; Call VBE 2.0 protected mode routine
        pop     _cx
        pop     _bx
        ret

procend     __VBE20_setBankAB

;----------------------------------------------------------------------------
; _VBE20_setBankA_ES    Sets the read/write bank directly via window A
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value, by making a single call to the VBE to set Window A since it has
; both read & write attributes set. This routine is different in the
; respect that the bank switching code uses MMIO registers and requires the
; ES register to be loaded with the selector to its MMIO registers.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    __VBE20_setBankA_ES

        push    es
        push    _bx
        push    _cx
        mov     es,[_VBE_MMIOSel]   ; Load selector to MMIO registers
        xor     _bx,_bx             ; BX := select window A
        mov     cl,[BYTE __SV_bankShift]; Adjust to VBE granularity
        shl     dl,cl               ; DX := VBE bank number
        call    [__SV_setBank20]        ; Call VBE 2.0 protected mode routine
        pop     _cx
        pop     _bx
        pop     es
        ret

procend     __VBE20_setBankA_ES

;----------------------------------------------------------------------------
; _VBE20_setBankAB_ES   Sets the read/write bank directly via Window's A & B
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value, by calling the VBE twice to set both Window A and Window B, as
; the VBE reports that they have separate read/write attributes. This
; routine is different in the respect that the bank switching code uses
; MMIO registers and requires the ES register to be loaded with the selector
; to its MMIO registers.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    __VBE20_setBankAB_ES

        push    es
        push    _bx
        push    _cx
        mov     es,[_VBE_MMIOSel]   ; Load selector to MMIO registers
        xor     _bx,_bx             ; BX := select window A
        mov     cl,[BYTE __SV_bankShift]; Adjust to VBE granularity
        shl     dl,cl               ; DX := VBE bank number
        push    _dx                 ; Save bank value
        call    [__SV_setBank20]    ; Call VBE 2.0 protected mode routine
        pop     _dx
        mov     _bx,1               ; BX := select window B
        call    [__SV_setBank20]    ; Call VBE 2.0 protected mode routine
        pop     _cx
        pop     _bx
        pop     es
        ret

procend     __VBE20_setBankAB_ES

;----------------------------------------------------------------------------
; _VBEAF_setBank    Sets the read/write bank directly via VBE/AF
;----------------------------------------------------------------------------
; This function sets the read/write bank by calling the VBE/AF device driver
; bank switching function.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    __VBEAF_setBank

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.setBank]
        pop     ebx
        ret

procend     __VBEAF_setBank

;----------------------------------------------------------------------------
; void _VBE20_setPalette(int start,int num,VBE_palette *pal,bool waitFlag)
;----------------------------------------------------------------------------
; Sets the palette by directly calling the relocated VBE 2.0 palette
; setting routine in 32 bit protected mode.
;----------------------------------------------------------------------------
procstartdll    __VBE20_setPalette

        ARG     start:UINT, num:UINT, pal:DPTR, waitFlag:S_USHORT

        enter_c 0

        mov     bx,[waitFlag]       ; BL := wait for retrace flag
        mov     _cx,[num]           ; _CX := number of entries
        mov     _dx,[start]         ; _DX := starting palette entry
if flatmodel
        mov     edi,[pal]           ; ES:EDI -> palette data
        mov     eax,[__SV_setPal20]
        push    ds
        mov     ds,[_VBE_MMIOSel]   ; Load selector to MMIO registers
        call    eax                 ; Call the VBE 2.0 palette code
        pop     ds
else
		les     di,[pal]
        movzx   edi,di              ; ES:EDI -> palette data
        push    ds                  ; Save DS
        push    fs                  ; Save FS
        push    ds
        pop     fs                  ; FS = DS
        mov     ds,[_VBE_MMIOSel]   ; Load selector to MMIO registers
        call    [fs:__SV_setPal20]  ; Call the VBE 2.0 palette code
        pop     fs
        pop     ds
endif

        leave_c_nolocal
        ret

procend     __VBE20_setPalette

endif

;----------------------------------------------------------------------------
; _SV_setBankASM    Sets the read/write bank directly via the VBE
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value.
;
; Entry:        AL  - New read/write bank number
;
; Exit:         AL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    _SV_setBankASM

		push    _dx
ife flatmodel
		push    ds
		mov     dx,DGROUP           ; Re-load out data segment
		mov     ds,dx
endif
		mov     dx,ax               ; DX := bank number
		mov     [WORD DC.curBank],ax    ; Save current write bank number
		call    [__SV_setBankPtr]       ; Call card specific bank routine
ife flatmodel
		pop     ds
endif
		pop     _dx
		ret

procend         _SV_setBankASM

;----------------------------------------------------------------------------
; _SV_setBankASMDL    Sets the read/write bank directly via the VBE
;----------------------------------------------------------------------------
; This routine sets both the read and write bank numbers to the same
; value.
;
; Entry:        DL  - New read/write bank number
;
; Exit:         DL  - New read/write bank number
;
; Registers:    All preserved!
;----------------------------------------------------------------------------
procstartdll    _SV_setBankASMDL

		push	_dx
ife flatmodel
		push    ds
		push	ax
		mov     ax,DGROUP           ; Re-load out data segment
		mov     ds,ax
		pop		ax
endif
		mov     [BYTE DC.curBank],dl    ; Save current write bank number
		call    [__SV_setBankPtr]       ; Call card specific bank routine
ife flatmodel
		pop     ds
endif
		pop		_dx
		ret

procend         _SV_setBankASMDL

ifdef   __WINDOWS16__
procstart   SV_SETBANKASM
		jmp     _SV_setBankASM
procend     SV_SETBANKASM
endif

;----------------------------------------------------------------------------
; void SV_setBank(int bank)
;----------------------------------------------------------------------------
; Calls the current bank switching routine to change video banks.
;----------------------------------------------------------------------------
procstartdll16  _SV_setBank

        ARG     bank:UINT

        push    _bp
        mov     _bp,_sp
        mov     _ax,[bank]          ; AX := 64k bank value
        call    _SV_setBankASM
        pop     _bp
        ret

procenddll16    _SV_setBank

ifndef  __WINDOWS16__

procstartdll    _SV_beginPixel
        jmp     [DC.beginPixel]
procend         _SV_beginPixel

procstartdll    _SV_putPixel
        jmp     [DC.putPixel]
procend         _SV_putPixel

procstartdll    _SV_putPixelFast
        jmp     [DC.putPixelFast]
procend         _SV_putPixelFast

procstartdll    _SV_endPixel
        jmp     [DC.endPixel]
procend         _SV_endPixel

procstartdll    _SV_clear
        jmp     [DC.clear]
procend         _SV_clear

procstartdll    _SV_beginLine
        jmp     [DC.beginLine]
procend         _SV_beginLine

procstartdll    _SV_line
        jmp     [DC.line]
procend         _SV_line

procstartdll    _SV_lineFast
        jmp     [DC.lineFast]
procend         _SV_lineFast

procstartdll    _SV_endLine
        jmp     [DC.endLine]
procend         _SV_endLine

procstartdll    _SV_setActivePage
        jmp     [DC.setActivePage]
procend         _SV_setActivePage

procstartdll    _SV_setVisualPage
        jmp     [DC.setVisualPage]
procend         _SV_setVisualPage

procstartdll    _SV_beginDirectAccess
        jmp     [DC.beginDirectAccess]
procend         _SV_beginDirectAccess

procstartdll    _SV_endDirectAccess
        jmp     [DC.endDirectAccess]
procend         _SV_endDirectAccess

endif

if flatmodel

;----------------------------------------------------------------------------
; void _SV_beginDirectAccessAFSLOW(void)
;----------------------------------------------------------------------------
procstartdll    __SV_beginDirectAccessAFSLOW

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.EnableDirectAccess]
        pop     ebx
        ret

procend     __SV_beginDirectAccessAFSLOW

;----------------------------------------------------------------------------
; void _SV_endDirectAccessAFSLOW(void)
;----------------------------------------------------------------------------
procstartdll    __SV_endDirectAccessAFSLOW

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.DisableDirectAccess]
        pop     ebx
        ret

procend     __SV_endDirectAccessAFSLOW

;----------------------------------------------------------------------------
; void _SV_beginPixelAFSLOW(void)
;----------------------------------------------------------------------------
procstartdll    __SV_beginPixelAFSLOW

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.EnableDirectAccess]
        pop     ebx
        ret

procend     __SV_beginPixelAFSLOW

;----------------------------------------------------------------------------
; void _SV_endPixelAFSLOW(void)
;----------------------------------------------------------------------------
procstartdll    __SV_endPixelAFSLOW

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.DisableDirectAccess]
        pop     ebx
        ret

procend     __SV_endPixelAFSLOW

;----------------------------------------------------------------------------
; void _SV_beginLineAFSLOW(void)
;----------------------------------------------------------------------------
procstartdll    __SV_beginLineAFSLOW

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.EnableDirectAccess]
        pop     ebx
        ret

procend     __SV_beginLineAFSLOW

;----------------------------------------------------------------------------
; void _SV_endLineAFSLOW(void)
;----------------------------------------------------------------------------
procstartdll    __SV_endLineAFSLOW

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.DisableDirectAccess]
        pop     ebx
        ret

procend     __SV_endLineAFSLOW

;----------------------------------------------------------------------------
; void _SV_beginDirectAccessAF(void)
;----------------------------------------------------------------------------
procstartdll    __SV_beginDirectAccessAF

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.WaitTillIdle]
        pop     ebx
        ret

procend     __SV_beginDirectAccessAF

;----------------------------------------------------------------------------
; void _SV_endDirectAccessAF(void)
;----------------------------------------------------------------------------
procstartdll    __SV_endDirectAccessAF
        ret
procend     __SV_endDirectAccessAF

;----------------------------------------------------------------------------
; void _SV_beginPixelAF()
;----------------------------------------------------------------------------
procstartdll    __SV_beginPixelAF

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.WaitTillIdle]
        pop     ebx
        ret

procend     __SV_beginPixelAF

;----------------------------------------------------------------------------
; void _SV_endPixelAF()
;----------------------------------------------------------------------------
procstartdll    __SV_endPixelAF
        ret
procend     __SV_endPixelAF

;----------------------------------------------------------------------------
; void _SV_beginLineAF()
;----------------------------------------------------------------------------
procstartdll    __SV_beginLineAF

        push    ebx
        mov     ebx,[DC.AFDC]
        call    [AF_devCtx.WaitTillIdle]
        pop     ebx
        ret

procend     __SV_beginLineAF

;----------------------------------------------------------------------------
; void _SV_endLineAF()
;----------------------------------------------------------------------------
procstartdll    __SV_endLineAF
        ret
procend     __SV_endLineAF

;----------------------------------------------------------------------------
; void _SV_lineFastAF(int x1,int y1,int x2,int y2,ulong color)
;----------------------------------------------------------------------------
; Routine draws a solid, single pixel wide line on accelerated devices.
; Assumes that the hardware has already been set up with the correct write
; mode operation.
;
; Entry:        x1      - X1 coordinate of line to draw (fixed point)
;               y1      - Y1 coordinate of line to draw (fixed point)
;               x2      - X2 coordinate of line to draw (fixed point)
;               y2      - Y2 coordinate of line to draw (fixed point)
;               color   - Color to draw the line in
;----------------------------------------------------------------------------
procstartdll    __SV_lineFastAF

        ARG     x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG

        push    ebp
        mov     ebp,esp
        push    ebx
        push    esi

        mov     eax,[color]
        mov     ebx,[DC.AFDC]
        shl     [x1],16                 ; Convert to 16.16 fixed point
        shl     [y1],16
        shl     [x2],16
        shl     [y2],16
        lea     esi,[x1]
        call    [AF_devCtx.DrawLine]

        pop     esi
        pop     ebx
        pop     ebp
        ret

procend     __SV_lineFastAF

endif

;----------------------------------------------------------------------------
; VGA_vSyncPresent	Checks if the vSync pulse is active
;----------------------------------------------------------------------------
; Checks if the vSync pulse is active, but looping around 64000 times
; checking for the sync pulse. If we dont get a sync pulse then we return
; a condition of false (the high level code will make multiple calls to
; this function and time out over a large period of time).
;
; Exit:		_AX	- 1 if vSync present, 0 if not found this time round
;----------------------------------------------------------------------------
procstart    _VGA_vSyncPresent

		push	_bx
		push	_cx
		push	_dx

		mov     dx,03DAh            ; DX := video status port
		mov		_cx,64000			; Loop 64000 times

		in      al,dx               ; Read current status of retrace bit
		and		al,8
		mov		bl,al

@@Wait:	in      al,dx               ; Wait for start of vertical retrace
		and		al,8
		cmp     al,bl
		jne    	@@Found
		loop	@@Wait

		xor		_ax,_ax				; Loop timed out
		jmp		@@Exit

@@Found:mov		_ax,1
@@Exit:	pop		_dx
		pop		_cx
		pop		_bx
		ret

procend      _VGA_vSyncPresent

endcodeseg  _svgasdk

        END
[ RETURN TO DIRECTORY ]